removed libstdc++ dependency
authorIlya Lavrenov <ilya.lavrenov@itseez.com>
Tue, 12 Feb 2013 10:20:23 +0000 (14:20 +0400)
committerIlya Lavrenov <ilya.lavrenov@itseez.com>
Tue, 12 Feb 2013 10:20:23 +0000 (14:20 +0400)
modules/highgui/src/cap_ffmpeg.cpp
modules/highgui/src/cap_ffmpeg_impl.hpp
modules/highgui/test/test_ffmpeg.cpp

index 0a2f0a3..657502a 100644 (file)
@@ -57,21 +57,42 @@ static CvCreateVideoWriter_Plugin icvCreateVideoWriter_FFMPEG_p = 0;
 static CvReleaseVideoWriter_Plugin icvReleaseVideoWriter_FFMPEG_p = 0;
 static CvWriteFrame_Plugin icvWriteFrame_FFMPEG_p = 0;
 
-static void
-icvInitFFMPEG(void)
+static cv::Mutex _icvInitFFMPEG_mutex;
+
+class icvInitFFMPEG
 {
-    static int ffmpegInitialized = 0;
-    if( !ffmpegInitialized )
+public:
+    static void Init()
+    {
+        cv::AutoLock al(_icvInitFFMPEG_mutex);
+        static icvInitFFMPEG init;
+    }
+
+private:
+    #if defined WIN32 || defined _WIN32
+    HMODULE icvFFOpenCV;
+
+    ~icvInitFFMPEG()
+    {
+        if (icvFFOpenCV)
+        {
+            FreeLibrary(icvFFOpenCV);
+            icvFFOpenCV = 0;
+        }
+    }
+    #endif
+
+    icvInitFFMPEG()
     {
     #if defined WIN32 || defined _WIN32
         const char* module_name = "opencv_ffmpeg"
-            CVAUX_STR(CV_VERSION_EPOCH) CVAUX_STR(CV_VERSION_MAJOR) CVAUX_STR(CV_VERSION_MINOR)
+            CVAUX_STR(CV_MAJOR_VERSION) CVAUX_STR(CV_MINOR_VERSION) CVAUX_STR(CV_SUBMINOR_VERSION)
         #if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__)
             "_64"
         #endif
             ".dll";
 
-        static HMODULE icvFFOpenCV = LoadLibrary( module_name );
+        icvFFOpenCV = LoadLibrary( module_name );
         if( icvFFOpenCV )
         {
             icvCreateFileCapture_FFMPEG_p =
@@ -93,18 +114,24 @@ icvInitFFMPEG(void)
             icvWriteFrame_FFMPEG_p =
                 (CvWriteFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvWriteFrame_FFMPEG");
 
-            if( icvCreateFileCapture_FFMPEG_p == NULL ||
-                icvReleaseCapture_FFMPEG_p == NULL ||
-                icvGrabFrame_FFMPEG_p == NULL  ||
-                icvRetrieveFrame_FFMPEG_p == NULL ||
-                icvSetCaptureProperty_FFMPEG_p == NULL ||
-                icvGetCaptureProperty_FFMPEG_p == NULL ||
-                icvCreateVideoWriter_FFMPEG_p == NULL ||
-                icvReleaseVideoWriter_FFMPEG_p == NULL ||
-                icvWriteFrame_FFMPEG_p == NULL )
+#if 0
+            if( icvCreateFileCapture_FFMPEG_p != 0 &&
+                icvReleaseCapture_FFMPEG_p != 0 &&
+                icvGrabFrame_FFMPEG_p != 0 &&
+                icvRetrieveFrame_FFMPEG_p != 0 &&
+                icvSetCaptureProperty_FFMPEG_p != 0 &&
+                icvGetCaptureProperty_FFMPEG_p != 0 &&
+                icvCreateVideoWriter_FFMPEG_p != 0 &&
+                icvReleaseVideoWriter_FFMPEG_p != 0 &&
+                icvWriteFrame_FFMPEG_p != 0 )
+            {
+                printf("Successfully initialized ffmpeg plugin!\n");
+            }
+            else
             {
-                fprintf(stderr, "Failed to load FFMPEG plugin: module handle=%p\n", icvFFOpenCV);
+                printf("Failed to load FFMPEG plugin: module handle=%p\n", icvFFOpenCV);
             }
+#endif
         }
     #elif defined HAVE_FFMPEG
         icvCreateFileCapture_FFMPEG_p = (CvCreateFileCapture_Plugin)cvCreateFileCapture_FFMPEG;
@@ -117,13 +144,12 @@ icvInitFFMPEG(void)
         icvReleaseVideoWriter_FFMPEG_p = (CvReleaseVideoWriter_Plugin)cvReleaseVideoWriter_FFMPEG;
         icvWriteFrame_FFMPEG_p = (CvWriteFrame_Plugin)cvWriteFrame_FFMPEG;
     #endif
-
-        ffmpegInitialized = 1;
     }
-}
+};
 
 
-class CvCapture_FFMPEG_proxy : public CvCapture
+class CvCapture_FFMPEG_proxy : 
+       public CvCapture
 {
 public:
     CvCapture_FFMPEG_proxy() { ffmpegCapture = 0; }
@@ -146,18 +172,18 @@ public:
         unsigned char* data = 0;
         int step=0, width=0, height=0, cn=0;
 
-        if(!ffmpegCapture ||
-           !icvRetrieveFrame_FFMPEG_p(ffmpegCapture,&data,&step,&width,&height,&cn))
-           return 0;
+        if (!ffmpegCapture ||
+           !icvRetrieveFrame_FFMPEG_p(ffmpegCapture, &data, &step, &width, &height, &cn))
+                       return 0;
         cvInitImageHeader(&frame, cvSize(width, height), 8, cn);
         cvSetData(&frame, data, step);
         return &frame;
     }
     virtual bool open( const char* filename )
     {
+        icvInitFFMPEG::Init();
         close();
 
-        icvInitFFMPEG();
         if( !icvCreateFileCapture_FFMPEG_p )
             return false;
         ffmpegCapture = icvCreateFileCapture_FFMPEG_p( filename );
@@ -190,8 +216,8 @@ CvCapture* cvCreateFileCapture_FFMPEG_proxy(const char * filename)
 #endif
 }
 
-
-class CvVideoWriter_FFMPEG_proxy : public CvVideoWriter
+class CvVideoWriter_FFMPEG_proxy : 
+       public CvVideoWriter
 {
 public:
     CvVideoWriter_FFMPEG_proxy() { ffmpegWriter = 0; }
@@ -208,8 +234,8 @@ public:
     }
     virtual bool open( const char* filename, int fourcc, double fps, CvSize frameSize, bool isColor )
     {
+        icvInitFFMPEG::Init();
         close();
-        icvInitFFMPEG();
         if( !icvCreateVideoWriter_FFMPEG_p )
             return false;
         ffmpegWriter = icvCreateVideoWriter_FFMPEG_p( filename, fourcc, fps, frameSize.width, frameSize.height, isColor );
index 445a9e6..b7e1d90 100644 (file)
@@ -328,28 +328,187 @@ void CvCapture_FFMPEG::close()
 #define AVSEEK_FLAG_ANY 1
 #endif
 
-static void icvInitFFMPEG_internal()
+class ImplMutex
 {
-    static volatile bool initialized = false;
-    if( !initialized )
+public:
+       ImplMutex() { init(); }
+       ~ImplMutex() { destroy(); }
+       
+    void init();
+    void destroy();
+
+    void lock();
+    bool trylock();
+    void unlock();
+
+    struct Impl;
+protected:
+    Impl* impl;
+
+private:
+    ImplMutex(const ImplMutex&);
+    ImplMutex& operator = (const ImplMutex& m);
+};
+
+#if defined WIN32 || defined _WIN32 || defined WINCE
+
+struct ImplMutex::Impl
+{
+    void init() { InitializeCriticalSection(&cs); refcount = 1; }
+    void destroy() { DeleteCriticalSection(&cs); }
+
+    void lock() { EnterCriticalSection(&cs); }
+    bool trylock() { return TryEnterCriticalSection(&cs) != 0; }
+    void unlock() { LeaveCriticalSection(&cs); }
+
+    CRITICAL_SECTION cs;
+    int refcount;
+};
+
+#ifndef __GNUC__
+static int _interlockedExchangeAdd(int* addr, int delta)
+{
+#if defined _MSC_VER && _MSC_VER >= 1500
+    return (int)_InterlockedExchangeAdd((long volatile*)addr, delta);
+#else
+    return (int)InterlockedExchangeAdd((long volatile*)addr, delta);
+#endif
+}
+#endif // __GNUC__
+
+#elif defined __APPLE__
+
+#include <libkern/OSAtomic.h>
+
+struct ImplMutex::Impl
+{
+    void init() { sl = OS_SPINLOCK_INIT; refcount = 1; }
+    void destroy() { }
+
+    void lock() { OSSpinLockLock(&sl); }
+    bool trylock() { return OSSpinLockTry(&sl); }
+    void unlock() { OSSpinLockUnlock(&sl); }
+
+    OSSpinLock sl;
+    int refcount;
+};
+
+#elif defined __linux__ && !defined ANDROID
+
+struct ImplMutex::Impl
+{
+    void init() { pthread_spin_init(&sl, 0); refcount = 1; }
+    void destroy() { pthread_spin_destroy(&sl); }
+
+    void lock() { pthread_spin_lock(&sl); }
+    bool trylock() { return pthread_spin_trylock(&sl) == 0; }
+    void unlock() { pthread_spin_unlock(&sl); }
+
+    pthread_spinlock_t sl;
+    int refcount;
+};
+
+#else
+
+struct ImplMutex::Impl
+{
+    void init() { pthread_mutex_init(&sl, 0); refcount = 1; }
+    void destroy() { pthread_mutex_destroy(&sl); }
+
+    void lock() { pthread_mutex_lock(&sl); }
+    bool trylock() { return pthread_mutex_trylock(&sl) == 0; }
+    void unlock() { pthread_mutex_unlock(&sl); }
+
+    pthread_mutex_t sl;
+    int refcount;
+};
+
+#endif
+
+void ImplMutex::init()
+{
+       impl = (Impl*)malloc(sizeof(Impl));
+       impl->init();
+}
+void ImplMutex::destroy() 
+{
+       impl->destroy();
+       free(impl);
+       impl = NULL;
+}
+void ImplMutex::lock() { impl->lock(); }
+void ImplMutex::unlock() { impl->unlock(); }
+bool ImplMutex::trylock() { return impl->trylock(); }
+
+static int LockCallBack(void **mutex, AVLockOp op)
+{
+    ImplMutex* localMutex = reinterpret_cast<ImplMutex*>(*mutex);
+    switch (op)
+    {
+        case AV_LOCK_CREATE:
+            localMutex = reinterpret_cast<ImplMutex*>(malloc(sizeof(ImplMutex)));
+            localMutex->init();
+            *mutex = localMutex;
+            if (!*mutex)
+                return 1;
+        break;
+
+        case AV_LOCK_OBTAIN:
+            localMutex->lock();
+        break;
+
+        case AV_LOCK_RELEASE:
+            localMutex->unlock();
+        break;
+
+        case AV_LOCK_DESTROY:
+            localMutex->destroy();
+            free(localMutex);
+            localMutex = NULL;
+        break;
+    }
+    return 0;
+}
+
+static ImplMutex _mutex;
+static bool _initialized = false;
+
+class InternalFFMpegRegister
+{
+public:
+    InternalFFMpegRegister()
     {
+        _mutex.lock();
+        if (!_initialized)
+        {
     #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 13, 0)
-        avformat_network_init();
+            avformat_network_init();
     #endif
 
-        /* register all codecs, demux and protocols */
-        av_register_all();
+            /* register all codecs, demux and protocols */
+            av_register_all();
+
+            /* register a callback function for synchronization */
+            av_lockmgr_register(&LockCallBack);
+
+            av_log_set_level(AV_LOG_ERROR);
 
-        av_log_set_level(AV_LOG_ERROR);
+            _initialized = true;
+        }
+        _mutex.unlock();
+    }
 
-        initialized = true;
+    ~InternalFFMpegRegister()
+    {
+        _initialized = false;
+        av_lockmgr_register(NULL);
     }
-}
+};
+
+static InternalFFMpegRegister _init;
 
 bool CvCapture_FFMPEG::open( const char* _filename )
 {
-    icvInitFFMPEG_internal();
-
     unsigned i;
     bool valid = false;
 
@@ -361,7 +520,8 @@ bool CvCapture_FFMPEG::open( const char* _filename )
     int err = av_open_input_file(&ic, _filename, NULL, 0, NULL);
 #endif
 
-    if (err < 0) {
+    if (err < 0)
+    {
         CV_WARN("Error opening file");
         goto exit_func;
     }
@@ -371,7 +531,8 @@ bool CvCapture_FFMPEG::open( const char* _filename )
 #else
     av_find_stream_info(ic);
 #endif
-    if (err < 0) {
+    if (err < 0)
+    {
         CV_WARN("Could not find codec parameters");
         goto exit_func;
     }
@@ -383,17 +544,18 @@ bool CvCapture_FFMPEG::open( const char* _filename )
         AVCodecContext *enc = &ic->streams[i]->codec;
 #endif
 
-#ifdef FF_API_THREAD_INIT
-        avcodec_thread_init(enc, get_number_of_cpus());
-#else
+//#ifdef FF_API_THREAD_INIT
+//        avcodec_thread_init(enc, get_number_of_cpus());
+//#else
         enc->thread_count = get_number_of_cpus();
-#endif
+//#endif
 
 #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
 #define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO
 #endif
 
-        if( AVMEDIA_TYPE_VIDEO == enc->codec_type && video_stream < 0) {
+        if( AVMEDIA_TYPE_VIDEO == enc->codec_type && video_stream < 0)
+        {
             AVCodec *codec = avcodec_find_decoder(enc->codec_id);
             if (!codec ||
 #if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0)
@@ -401,7 +563,8 @@ bool CvCapture_FFMPEG::open( const char* _filename )
 #else
                 avcodec_open(enc, codec)
 #endif
-                < 0) goto exit_func;
+                < 0)
+                goto exit_func;
 
             video_stream = i;
             video_st = ic->streams[i];
@@ -1275,8 +1438,6 @@ void CvVideoWriter_FFMPEG::close()
 bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc,
                                  double fps, int width, int height, bool is_color )
 {
-    icvInitFFMPEG_internal();
-
     CodecID codec_id = CODEC_ID_NONE;
     int err, codec_pix_fmt;
     double bitrate_scale = 1;
@@ -1495,6 +1656,7 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc,
     frame_width = width;
     frame_height = height;
     ok = true;
+
     return true;
 }
 
@@ -1506,6 +1668,7 @@ CvCapture_FFMPEG* cvCreateFileCapture_FFMPEG( const char* filename )
     capture->init();
     if( capture->open( filename ))
         return capture;
+
     capture->close();
     free(capture);
     return 0;
@@ -1554,7 +1717,6 @@ CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG( const char* filename, int four
     return 0;
 }
 
-
 void cvReleaseVideoWriter_FFMPEG( CvVideoWriter_FFMPEG** writer )
 {
     if( writer && *writer )
@@ -1745,11 +1907,6 @@ bool OutputMediaStream_FFMPEG::open(const char* fileName, int width, int height,
     oc_ = 0;
     video_st_ = 0;
 
-    // tell FFMPEG to register codecs
-    av_register_all();
-
-    av_log_set_level(AV_LOG_ERROR);
-
     // auto detect the output format from the name and fourcc code
     #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
         fmt_ = av_guess_format(NULL, fileName, NULL);
@@ -1930,11 +2087,6 @@ bool InputMediaStream_FFMPEG::open(const char* fileName, int* codec, int* chroma
         avformat_network_init();
     #endif
 
-    // register all codecs, demux and protocols
-    av_register_all();
-
-    av_log_set_level(AV_LOG_ERROR);
-
     #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 6, 0)
         err = avformat_open_input(&ctx_, fileName, 0, 0);
     #else
@@ -2054,7 +2206,7 @@ bool InputMediaStream_FFMPEG::read(unsigned char** data, int* size, int* endOfFi
 
         if (ret < 0)
         {
-            if (ret == AVERROR_EOF)
+            if (ret == (int)AVERROR_EOF)
                 *endOfFile = true;
             return false;
         }
index 0702cb1..5306546 100644 (file)
@@ -207,7 +207,6 @@ public:
         }
     }
 
-
 private:
     std::vector<VideoWriter*>* writers;
     std::vector<std::string>* files;
@@ -241,18 +240,18 @@ public:
 
     virtual void operator() (const Range& range) const
     {
-        if((range.start + 1) != range.end)
-            return;
-
-        VideoWriter* writer = writers->operator[](range.start);
-        CV_Assert(writer != NULL);
-        CV_Assert(writer->isOpened());
-
-        Mat frame(CreateVideoWriterInvoker::FrameSize, CV_8UC3);
-        for (unsigned int i = 0; i < FrameCount; ++i)
+        for (int j = range.start; j < range.end; ++j)
         {
-            GenerateFrame(frame, i);
-            writer->operator<< (frame);
+            VideoWriter* writer = writers->operator[](j);
+            CV_Assert(writer != NULL);
+            CV_Assert(writer->isOpened());
+
+            Mat frame(CreateVideoWriterInvoker::FrameSize, CV_8UC3);
+            for (unsigned int i = 0; i < FrameCount; ++i)
+            {
+                GenerateFrame(frame, i);
+                writer->operator<< (frame);
+            }
         }
     }
 
@@ -305,47 +304,47 @@ public:
 
     virtual void operator() (const Range& range) const
     {
-        if((range.start + 1) != range.end)
-            return;
-
-        VideoCapture* capture = readers->operator[](range.start);
-        CV_Assert(capture != NULL);
-        CV_Assert(capture->isOpened());
+        for (int j = range.start; j < range.end; ++j)
+        {
+            VideoCapture* capture = readers->operator[](j);
+            CV_Assert(capture != NULL);
+            CV_Assert(capture->isOpened());
 
-        const static double eps = 23.0;
-        unsigned int frameCount = static_cast<unsigned int>(capture->get(CV_CAP_PROP_FRAME_COUNT));
-        CV_Assert(frameCount == WriteVideo_Invoker::FrameCount);
-        Mat reference(CreateVideoWriterInvoker::FrameSize, CV_8UC3);
+            const static double eps = 23.0;
+            unsigned int frameCount = static_cast<unsigned int>(capture->get(CV_CAP_PROP_FRAME_COUNT));
+            CV_Assert(frameCount == WriteVideo_Invoker::FrameCount);
+            Mat reference(CreateVideoWriterInvoker::FrameSize, CV_8UC3);
 
-        for (unsigned int i = 0; i < frameCount && next; ++i)
-        {
-            Mat actual;
-            (*capture) >> actual;
+            for (unsigned int i = 0; i < frameCount && next; ++i)
+            {
+                Mat actual;
+                (*capture) >> actual;
 
-            WriteVideo_Invoker::GenerateFrame(reference, i);
+                WriteVideo_Invoker::GenerateFrame(reference, i);
 
-            EXPECT_EQ(reference.cols, actual.cols);
-            EXPECT_EQ(reference.rows, actual.rows);
-            EXPECT_EQ(reference.depth(), actual.depth());
-            EXPECT_EQ(reference.channels(), actual.channels());
+                EXPECT_EQ(reference.cols, actual.cols);
+                EXPECT_EQ(reference.rows, actual.rows);
+                EXPECT_EQ(reference.depth(), actual.depth());
+                EXPECT_EQ(reference.channels(), actual.channels());
 
-            double psnr = PSNR(actual, reference);
-            if (psnr < eps)
-            {
-#define SUM cvtest::TS::SUMMARY
-                ts->printf(SUM, "\nPSNR: %lf\n", psnr);
-                ts->printf(SUM, "Video #: %d\n", range.start);
-                ts->printf(SUM, "Frame #: %d\n", i);
-#undef SUM
-                ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
-                ts->set_gtest_status();
+                double psnr = PSNR(actual, reference);
+                if (psnr < eps)
+                {
+    #define SUM cvtest::TS::SUMMARY
+                    ts->printf(SUM, "\nPSNR: %lf\n", psnr);
+                    ts->printf(SUM, "Video #: %d\n", range.start);
+                    ts->printf(SUM, "Frame #: %d\n", i);
+    #undef SUM
+                    ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
+                    ts->set_gtest_status();
 
-                Mat diff;
-                absdiff(actual, reference, diff);
+                    Mat diff;
+                    absdiff(actual, reference, diff);
 
-                EXPECT_EQ(countNonZero(diff.reshape(1) > 1), 0);
+                    EXPECT_EQ(countNonZero(diff.reshape(1) > 1), 0);
 
-                next = false;
+                    next = false;
+                }
             }
         }
     }
@@ -359,7 +358,7 @@ private:
 
 bool ReadImageAndTest::next;
 
-TEST(Highgui_Video_parallel_writers_and_readers, DISABLED_accuracy)
+TEST(Highgui_Video_parallel_writers_and_readers, accuracy)
 {
     const unsigned int threadsCount = 4;
     cvtest::TS* ts = cvtest::TS::ptr();