removed libstdc++ dependency

pull/479/head
Ilya Lavrenov 12 years ago
parent b6e7aeabe0
commit 5512f91d08
  1. 80
      modules/highgui/src/cap_ffmpeg.cpp
  2. 218
      modules/highgui/src/cap_ffmpeg_impl.hpp
  3. 91
      modules/highgui/test/test_ffmpeg.cpp

@ -57,21 +57,42 @@ static CvCreateVideoWriter_Plugin icvCreateVideoWriter_FFMPEG_p = 0;
static CvReleaseVideoWriter_Plugin icvReleaseVideoWriter_FFMPEG_p = 0; static CvReleaseVideoWriter_Plugin icvReleaseVideoWriter_FFMPEG_p = 0;
static CvWriteFrame_Plugin icvWriteFrame_FFMPEG_p = 0; static CvWriteFrame_Plugin icvWriteFrame_FFMPEG_p = 0;
static void static cv::Mutex _icvInitFFMPEG_mutex;
icvInitFFMPEG(void)
class icvInitFFMPEG
{ {
static int ffmpegInitialized = 0; public:
if( !ffmpegInitialized ) 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 #if defined WIN32 || defined _WIN32
const char* module_name = "opencv_ffmpeg" 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__) #if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__)
"_64" "_64"
#endif #endif
".dll"; ".dll";
static HMODULE icvFFOpenCV = LoadLibrary( module_name ); icvFFOpenCV = LoadLibrary( module_name );
if( icvFFOpenCV ) if( icvFFOpenCV )
{ {
icvCreateFileCapture_FFMPEG_p = icvCreateFileCapture_FFMPEG_p =
@ -93,18 +114,24 @@ icvInitFFMPEG(void)
icvWriteFrame_FFMPEG_p = icvWriteFrame_FFMPEG_p =
(CvWriteFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvWriteFrame_FFMPEG"); (CvWriteFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvWriteFrame_FFMPEG");
if( icvCreateFileCapture_FFMPEG_p == NULL || #if 0
icvReleaseCapture_FFMPEG_p == NULL || if( icvCreateFileCapture_FFMPEG_p != 0 &&
icvGrabFrame_FFMPEG_p == NULL || icvReleaseCapture_FFMPEG_p != 0 &&
icvRetrieveFrame_FFMPEG_p == NULL || icvGrabFrame_FFMPEG_p != 0 &&
icvSetCaptureProperty_FFMPEG_p == NULL || icvRetrieveFrame_FFMPEG_p != 0 &&
icvGetCaptureProperty_FFMPEG_p == NULL || icvSetCaptureProperty_FFMPEG_p != 0 &&
icvCreateVideoWriter_FFMPEG_p == NULL || icvGetCaptureProperty_FFMPEG_p != 0 &&
icvReleaseVideoWriter_FFMPEG_p == NULL || icvCreateVideoWriter_FFMPEG_p != 0 &&
icvWriteFrame_FFMPEG_p == NULL ) 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 #elif defined HAVE_FFMPEG
icvCreateFileCapture_FFMPEG_p = (CvCreateFileCapture_Plugin)cvCreateFileCapture_FFMPEG; icvCreateFileCapture_FFMPEG_p = (CvCreateFileCapture_Plugin)cvCreateFileCapture_FFMPEG;
@ -117,13 +144,12 @@ icvInitFFMPEG(void)
icvReleaseVideoWriter_FFMPEG_p = (CvReleaseVideoWriter_Plugin)cvReleaseVideoWriter_FFMPEG; icvReleaseVideoWriter_FFMPEG_p = (CvReleaseVideoWriter_Plugin)cvReleaseVideoWriter_FFMPEG;
icvWriteFrame_FFMPEG_p = (CvWriteFrame_Plugin)cvWriteFrame_FFMPEG; icvWriteFrame_FFMPEG_p = (CvWriteFrame_Plugin)cvWriteFrame_FFMPEG;
#endif #endif
ffmpegInitialized = 1;
} }
} };
class CvCapture_FFMPEG_proxy : public CvCapture class CvCapture_FFMPEG_proxy :
public CvCapture
{ {
public: public:
CvCapture_FFMPEG_proxy() { ffmpegCapture = 0; } CvCapture_FFMPEG_proxy() { ffmpegCapture = 0; }
@ -146,18 +172,18 @@ public:
unsigned char* data = 0; unsigned char* data = 0;
int step=0, width=0, height=0, cn=0; int step=0, width=0, height=0, cn=0;
if(!ffmpegCapture || if (!ffmpegCapture ||
!icvRetrieveFrame_FFMPEG_p(ffmpegCapture,&data,&step,&width,&height,&cn)) !icvRetrieveFrame_FFMPEG_p(ffmpegCapture, &data, &step, &width, &height, &cn))
return 0; return 0;
cvInitImageHeader(&frame, cvSize(width, height), 8, cn); cvInitImageHeader(&frame, cvSize(width, height), 8, cn);
cvSetData(&frame, data, step); cvSetData(&frame, data, step);
return &frame; return &frame;
} }
virtual bool open( const char* filename ) virtual bool open( const char* filename )
{ {
icvInitFFMPEG::Init();
close(); close();
icvInitFFMPEG();
if( !icvCreateFileCapture_FFMPEG_p ) if( !icvCreateFileCapture_FFMPEG_p )
return false; return false;
ffmpegCapture = icvCreateFileCapture_FFMPEG_p( filename ); ffmpegCapture = icvCreateFileCapture_FFMPEG_p( filename );
@ -190,8 +216,8 @@ CvCapture* cvCreateFileCapture_FFMPEG_proxy(const char * filename)
#endif #endif
} }
class CvVideoWriter_FFMPEG_proxy :
class CvVideoWriter_FFMPEG_proxy : public CvVideoWriter public CvVideoWriter
{ {
public: public:
CvVideoWriter_FFMPEG_proxy() { ffmpegWriter = 0; } CvVideoWriter_FFMPEG_proxy() { ffmpegWriter = 0; }
@ -208,8 +234,8 @@ public:
} }
virtual bool open( const char* filename, int fourcc, double fps, CvSize frameSize, bool isColor ) virtual bool open( const char* filename, int fourcc, double fps, CvSize frameSize, bool isColor )
{ {
icvInitFFMPEG::Init();
close(); close();
icvInitFFMPEG();
if( !icvCreateVideoWriter_FFMPEG_p ) if( !icvCreateVideoWriter_FFMPEG_p )
return false; return false;
ffmpegWriter = icvCreateVideoWriter_FFMPEG_p( filename, fourcc, fps, frameSize.width, frameSize.height, isColor ); ffmpegWriter = icvCreateVideoWriter_FFMPEG_p( filename, fourcc, fps, frameSize.width, frameSize.height, isColor );

@ -328,28 +328,187 @@ void CvCapture_FFMPEG::close()
#define AVSEEK_FLAG_ANY 1 #define AVSEEK_FLAG_ANY 1
#endif #endif
static void icvInitFFMPEG_internal() class ImplMutex
{ {
static volatile bool initialized = false; public:
if( !initialized ) 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) #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 13, 0)
avformat_network_init(); avformat_network_init();
#endif #endif
/* register all codecs, demux and protocols */ /* register all codecs, demux and protocols */
av_register_all(); 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 ) bool CvCapture_FFMPEG::open( const char* _filename )
{ {
icvInitFFMPEG_internal();
unsigned i; unsigned i;
bool valid = false; 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); int err = av_open_input_file(&ic, _filename, NULL, 0, NULL);
#endif #endif
if (err < 0) { if (err < 0)
{
CV_WARN("Error opening file"); CV_WARN("Error opening file");
goto exit_func; goto exit_func;
} }
@ -371,7 +531,8 @@ bool CvCapture_FFMPEG::open( const char* _filename )
#else #else
av_find_stream_info(ic); av_find_stream_info(ic);
#endif #endif
if (err < 0) { if (err < 0)
{
CV_WARN("Could not find codec parameters"); CV_WARN("Could not find codec parameters");
goto exit_func; goto exit_func;
} }
@ -383,17 +544,18 @@ bool CvCapture_FFMPEG::open( const char* _filename )
AVCodecContext *enc = &ic->streams[i]->codec; AVCodecContext *enc = &ic->streams[i]->codec;
#endif #endif
#ifdef FF_API_THREAD_INIT //#ifdef FF_API_THREAD_INIT
avcodec_thread_init(enc, get_number_of_cpus()); // avcodec_thread_init(enc, get_number_of_cpus());
#else //#else
enc->thread_count = get_number_of_cpus(); enc->thread_count = get_number_of_cpus();
#endif //#endif
#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0) #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
#define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO #define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO
#endif #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); AVCodec *codec = avcodec_find_decoder(enc->codec_id);
if (!codec || if (!codec ||
#if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0) #if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0)
@ -401,7 +563,8 @@ bool CvCapture_FFMPEG::open( const char* _filename )
#else #else
avcodec_open(enc, codec) avcodec_open(enc, codec)
#endif #endif
< 0) goto exit_func; < 0)
goto exit_func;
video_stream = i; video_stream = i;
video_st = ic->streams[i]; video_st = ic->streams[i];
@ -1275,8 +1438,6 @@ void CvVideoWriter_FFMPEG::close()
bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc,
double fps, int width, int height, bool is_color ) double fps, int width, int height, bool is_color )
{ {
icvInitFFMPEG_internal();
CodecID codec_id = CODEC_ID_NONE; CodecID codec_id = CODEC_ID_NONE;
int err, codec_pix_fmt; int err, codec_pix_fmt;
double bitrate_scale = 1; double bitrate_scale = 1;
@ -1495,6 +1656,7 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc,
frame_width = width; frame_width = width;
frame_height = height; frame_height = height;
ok = true; ok = true;
return true; return true;
} }
@ -1506,6 +1668,7 @@ CvCapture_FFMPEG* cvCreateFileCapture_FFMPEG( const char* filename )
capture->init(); capture->init();
if( capture->open( filename )) if( capture->open( filename ))
return capture; return capture;
capture->close(); capture->close();
free(capture); free(capture);
return 0; return 0;
@ -1554,7 +1717,6 @@ CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG( const char* filename, int four
return 0; return 0;
} }
void cvReleaseVideoWriter_FFMPEG( CvVideoWriter_FFMPEG** writer ) void cvReleaseVideoWriter_FFMPEG( CvVideoWriter_FFMPEG** writer )
{ {
if( writer && *writer ) if( writer && *writer )
@ -1745,11 +1907,6 @@ bool OutputMediaStream_FFMPEG::open(const char* fileName, int width, int height,
oc_ = 0; oc_ = 0;
video_st_ = 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 // auto detect the output format from the name and fourcc code
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
fmt_ = av_guess_format(NULL, fileName, NULL); 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(); avformat_network_init();
#endif #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) #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 6, 0)
err = avformat_open_input(&ctx_, fileName, 0, 0); err = avformat_open_input(&ctx_, fileName, 0, 0);
#else #else
@ -2054,7 +2206,7 @@ bool InputMediaStream_FFMPEG::read(unsigned char** data, int* size, int* endOfFi
if (ret < 0) if (ret < 0)
{ {
if (ret == AVERROR_EOF) if (ret == (int)AVERROR_EOF)
*endOfFile = true; *endOfFile = true;
return false; return false;
} }

@ -207,7 +207,6 @@ public:
} }
} }
private: private:
std::vector<VideoWriter*>* writers; std::vector<VideoWriter*>* writers;
std::vector<std::string>* files; std::vector<std::string>* files;
@ -241,18 +240,18 @@ public:
virtual void operator() (const Range& range) const virtual void operator() (const Range& range) const
{ {
if((range.start + 1) != range.end) for (int j = range.start; j < range.end; ++j)
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)
{ {
GenerateFrame(frame, i); VideoWriter* writer = writers->operator[](j);
writer->operator<< (frame); 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 virtual void operator() (const Range& range) const
{ {
if((range.start + 1) != range.end) for (int j = range.start; j < range.end; ++j)
return; {
VideoCapture* capture = readers->operator[](j);
VideoCapture* capture = readers->operator[](range.start); CV_Assert(capture != NULL);
CV_Assert(capture != NULL); CV_Assert(capture->isOpened());
CV_Assert(capture->isOpened());
const static double eps = 23.0; const static double eps = 23.0;
unsigned int frameCount = static_cast<unsigned int>(capture->get(CV_CAP_PROP_FRAME_COUNT)); unsigned int frameCount = static_cast<unsigned int>(capture->get(CV_CAP_PROP_FRAME_COUNT));
CV_Assert(frameCount == WriteVideo_Invoker::FrameCount); CV_Assert(frameCount == WriteVideo_Invoker::FrameCount);
Mat reference(CreateVideoWriterInvoker::FrameSize, CV_8UC3); Mat reference(CreateVideoWriterInvoker::FrameSize, CV_8UC3);
for (unsigned int i = 0; i < frameCount && next; ++i) for (unsigned int i = 0; i < frameCount && next; ++i)
{ {
Mat actual; Mat actual;
(*capture) >> actual; (*capture) >> actual;
WriteVideo_Invoker::GenerateFrame(reference, i); WriteVideo_Invoker::GenerateFrame(reference, i);
EXPECT_EQ(reference.cols, actual.cols); EXPECT_EQ(reference.cols, actual.cols);
EXPECT_EQ(reference.rows, actual.rows); EXPECT_EQ(reference.rows, actual.rows);
EXPECT_EQ(reference.depth(), actual.depth()); EXPECT_EQ(reference.depth(), actual.depth());
EXPECT_EQ(reference.channels(), actual.channels()); EXPECT_EQ(reference.channels(), actual.channels());
double psnr = PSNR(actual, reference); double psnr = PSNR(actual, reference);
if (psnr < eps) if (psnr < eps)
{ {
#define SUM cvtest::TS::SUMMARY #define SUM cvtest::TS::SUMMARY
ts->printf(SUM, "\nPSNR: %lf\n", psnr); ts->printf(SUM, "\nPSNR: %lf\n", psnr);
ts->printf(SUM, "Video #: %d\n", range.start); ts->printf(SUM, "Video #: %d\n", range.start);
ts->printf(SUM, "Frame #: %d\n", i); ts->printf(SUM, "Frame #: %d\n", i);
#undef SUM #undef SUM
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
ts->set_gtest_status(); ts->set_gtest_status();
Mat diff; Mat diff;
absdiff(actual, reference, 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; 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; const unsigned int threadsCount = 4;
cvtest::TS* ts = cvtest::TS::ptr(); cvtest::TS* ts = cvtest::TS::ptr();

Loading…
Cancel
Save