|
|
|
@ -328,10 +328,158 @@ 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(); |
|
|
|
@ -340,16 +488,27 @@ static void icvInitFFMPEG_internal() |
|
|
|
|
/* 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); |
|
|
|
|
|
|
|
|
|
initialized = true; |
|
|
|
|
_initialized = true; |
|
|
|
|
} |
|
|
|
|
_mutex.unlock(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
~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; |
|
|
|
|
} |
|
|
|
|