Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

If you call your function 2 or more times per second you will have same file name. Check if the file exists and try to use some counter on filename . For example:

VideoWriter writer;
std::string path = "C:/"; //use your basepath
std::string fname = "2015-11-13-15-47-42"; //with the current date and time
std::string output_file_path = path + fname + ".avi";
int cnt = 0;
while (cnt<10)
{
    writer.open(output_file_path, CV_FOURCC('x', '2', '6', '4'), 25, S);
    if (writer.isOpened())
        break;
    cnt++;
    output_file_path = path + fname + "_" + std::to_string(cnt) + ".avi";
}
if (!writer.isOpened())
    logging.WriteLog("Failed to create video file: " + output_file_path);

If EDIT: I've found some interesting behaviour related to codecs and threads in OpenCV. It seems that some codecs requires that multiple object of VideoWriter have to be initialized/opened in the main thread.

After this you call your function 2 can use them in worker threads. My experience:

  • Using uncompressed codecfourcc=0 or more times per second XVID I can open/write VideoWriter in worker threads.
  • Using X264 I have to open one many VideoWriters in the main thread but I can use them in worker threads.

May be some lock occours and could depends on codec/VFW/DSHOW implementation.

The following code works to me with X264 and OCV2.4.10 or OCV 3.0.0. if you will have same file name. Check if comment out the file exists and try to use some counter on filename . For example:line writers[i].open(fname, codec, FPS, image_size); you can test opening in worker thread using XVID.

#define FRAME_W 320
#define FRAME_H 240
#define FPS 25

// This thread uses a VideoWriter writer;
std::string path = "C:/"; //use your basepath
std::string fname = "2015-11-13-15-47-42"; //with object opened in the current date and time
std::string output_file_path = path main thread
void ThreadStd(cv::VideoWriter *writer, const char*fn, int threadNum)
{
    string fname(fn); 
    time_t end_time;
    time_t current_time = time(NULL);
    time_t clip_length = 10;
    end_time = current_time + fname + ".avi";
int cnt = 0;
while (cnt<10)
clip_length;
    Size image_size = Size(FRAME_W, FRAME_H);
    // some codecs don't allow to open Videowriter in multiple tread instance
    if (!writer->isOpened())
    {
    writer.open(output_file_path, CV_FOURCC('x',     //XVID allows open here
        writer->open(fname, CV_FOURCC('X', 'V', 'I', 'D'), FPS, image_size);

        //uncompressed fourcc=0 allows open here
        //writer->open(fname, 0, FPS, image_size);

        // X264 needs Videowriter already opened in the main thread
        //writer->open(fname, CV_FOURCC('X', '2', '6', '4'), 25, S);
FPS, image_size);
    }
    if (writer.isOpened())
        break;
    cnt++;
    output_file_path = path (!writer->isOpened())
    {
        std::cout << "\nThe video file has not been opened: " + std::string(fname) << endl;
    }
    else while (current_time < end_time)
    {
        Mat  webcam_frame = Mat::zeros(image_size, CV_8UC3);
        cv::putText(webcam_frame, "TH#:" + to_string(threadNum), 
                    cv::Point(10, 10), FONT_HERSHEY_PLAIN, 1, Scalar(255,255,255));
        writer->write(webcam_frame);
        current_time = time(NULL);
    }
    cout << "\nTime's up! from thread " << threadNum << std::endl;
    return;
}

int _tmain(int argc, _TCHAR* argv[])
{
    std::cout << "This will test the VideoWriter class's ability to work in threads.\n";
    int numThreads = 5;
    //thread list
    vector<thread> threads(numThreads);
    // we create a VideoWriter object for each thread
    vector<cv::VideoWriter> writers(threads.size());
    for (int i = 0; i < threads.size(); i++)
    {
        std::string fname = "../img/" + "_" + std::to_string(cnt) to_string(i) + ".avi";
        DeleteFileA(fname.c_str()); //delete file if it exist

        Size image_size = Size(FRAME_W, FRAME_H);
        int codec;
        codec = CV_FOURCC('X', '2', '6', '4');
        // open the VideoWriter here but...
        writers[i].open(fname, codec, FPS, image_size);
        // ...we write it in the thread
        threads[i] = thread(ThreadStd, &(writers[i]), fname.c_str(), i);
        cout << "\n\nStarted test thread #" << to_string(i);
    }
if (!writer.isOpened())
    logging.WriteLog("Failed to create video file: " + output_file_path);
    // wait for all treads
    for (int i = 0; i < threads.size(); i++)
        threads[i].join();
    // release all writers
    for (int i = 0; i<writers.size(); i++)
        writers[i].release();
}

EDIT: I've found some interesting behaviour related to codecs and threads in OpenCV. It seems that some codecs requires that multiple object of VideoWriter have to be initialized/opened in the main thread.

After this you can use them in worker threads. My experience:

  • Using uncompressed codecfourcc=0 or XVID I can open/write VideoWriter in worker threads.
  • Using X264 I have to open one many VideoWriters in the main thread but I can use them in worker threads.

May be some lock occours and could depends on codec/VFW/DSHOW implementation.

The following code works to me with X264 and OCV2.4.10 or OCV 3.0.0. if you comment out the line writers[i].open(fname, codec, FPS, image_size); you can test opening in worker thread using XVID.

#define FRAME_W 320
#define FRAME_H 240
#define FPS 25

// This thread uses a VideoWriter object opened in the main thread
void ThreadStd(cv::VideoWriter *writer, const char*fn, int threadNum)
{
    string fname(fn); 
    time_t end_time;
    time_t current_time = time(NULL);
    time_t clip_length = 10;
    end_time = current_time + clip_length;
    Size image_size = Size(FRAME_W, FRAME_H);
    // some codecs don't allow to open Videowriter in multiple tread instance
    if (!writer->isOpened())
    {
        //XVID allows open here
        writer->open(fname, CV_FOURCC('X', 'V', 'I', 'D'), FPS, image_size);

        //uncompressed fourcc=0 allows open here
        //writer->open(fname, 0, FPS, image_size);

        // X264 needs Videowriter already opened in the main thread
        //writer->open(fname, CV_FOURCC('X', '2', '6', '4'), FPS, image_size);
    }
    if (!writer->isOpened())
    {
        std::cout << "\nThe video file has not been opened: " + std::string(fname) << endl;
    }
    else while (current_time < end_time)
    {
        Mat  webcam_frame = Mat::zeros(image_size, CV_8UC3);
        cv::putText(webcam_frame, "TH#:" + to_string(threadNum), 
                    cv::Point(10, 10), FONT_HERSHEY_PLAIN, 1, Scalar(255,255,255));
        writer->write(webcam_frame);
        current_time = time(NULL);
    }
    cout << "\nTime's up! from thread " << threadNum << std::endl;
    return;
}

int _tmain(int argc, _TCHAR* argv[])
{
    std::cout << "This will test the VideoWriter class's ability to work in threads.\n";
    int numThreads = 5;
    //thread list
    vector<thread> threads(numThreads);
    // we create a VideoWriter object for each thread
    vector<cv::VideoWriter> writers(threads.size());
    for (int i = 0; i < threads.size(); i++)
    {
        std::string fname = "../img/" + to_string(i) + ".avi";
        DeleteFileA(fname.c_str()); //delete file if it exist

        Size image_size = Size(FRAME_W, FRAME_H);
        int codec;
        codec = CV_FOURCC('X', '2', '6', '4');
        // open the VideoWriter here but...
        writers[i].open(fname, codec, FPS, image_size);
        // ...we write it in the thread
        threads[i] = thread(ThreadStd, &(writers[i]), fname.c_str(), i);
        cout << "\n\nStarted test thread #" << to_string(i);
    }
    // wait for all treads
    for (int i = 0; i < threads.size(); i++)
        threads[i].join();
    // release all writers
    for (int i = 0; i<writers.size(); i++)
        writers[i].release();
}