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 =
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;
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; }
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 );
#endif
}
-
-class CvVideoWriter_FFMPEG_proxy : public CvVideoWriter
+class CvVideoWriter_FFMPEG_proxy :
+ public CvVideoWriter
{
public:
CvVideoWriter_FFMPEG_proxy() { ffmpegWriter = 0; }
}
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 );
#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;
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;
}
#else
av_find_stream_info(ic);
#endif
- if (err < 0) {
+ if (err < 0)
+ {
CV_WARN("Could not find codec parameters");
goto exit_func;
}
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)
#else
avcodec_open(enc, codec)
#endif
- < 0) goto exit_func;
+ < 0)
+ goto exit_func;
video_stream = i;
video_st = ic->streams[i];
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;
frame_width = width;
frame_height = height;
ok = true;
+
return true;
}
capture->init();
if( capture->open( filename ))
return capture;
+
capture->close();
free(capture);
return 0;
return 0;
}
-
void cvReleaseVideoWriter_FFMPEG( CvVideoWriter_FFMPEG** writer )
{
if( writer && *writer )
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);
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
if (ret < 0)
{
- if (ret == AVERROR_EOF)
+ if (ret == (int)AVERROR_EOF)
*endOfFile = true;
return false;
}
}
}
-
private:
std::vector<VideoWriter*>* writers;
std::vector<std::string>* files;
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);
+ }
}
}
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;
+ }
}
}
}
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();