Commit 4dff974e authored by Alexander Reshetnikov's avatar Alexander Reshetnikov

Refactored new ffmpeg wrapper

parent d4fb5027
...@@ -39,24 +39,83 @@ ...@@ -39,24 +39,83 @@
// //
//M*/ //M*/
#include "cap_ffmpeg_api.hpp"
#include <assert.h>
#include <algorithm>
#if defined _MSC_VER && _MSC_VER >= 1200
#pragma warning( disable: 4244 4510 4512 4610 )
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#undef UINT64_C #if !defined(WIN32) || defined(__MINGW32__)
#define UINT64_C(val) val ## LL // some versions of FFMPEG assume a C99 compiler, and don't define INT64_C
#include <libavformat/avformat.h> #if !defined INT64_C || !defined UINT64_C
#include <libavcodec/avcodec.h> #define INT64_C
#include <libswscale/swscale.h> #define UINT64_C
#define __STDC_CONSTANT_MACROS
// force re-inclusion of stdint.h to get INT64_C macro
#undef _STDINT_H
#include <stdint.h>
#endif
#include <errno.h>
#endif
#ifdef WIN32
#define HAVE_FFMPEG_SWSCALE 1
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#else
// if the header path is not specified explicitly, let's deduce it
#if !defined HAVE_FFMPEG_AVCODEC_H && !defined HAVE_LIBAVCODEC_AVCODEC_H
#if defined(HAVE_GENTOO_FFMPEG)
#define HAVE_LIBAVCODEC_AVCODEC_H 1
#define HAVE_LIBAVFORMAT_AVFORMAT_H 1
#if defined(HAVE_FFMPEG_SWSCALE)
#define HAVE_LIBSWSCALE_SWSCALE_H 1
#endif
#elif defined HAVE_FFMPEG
#define HAVE_FFMPEG_AVCODEC_H 1
#define HAVE_FFMPEG_AVFORMAT_H 1
#if defined(HAVE_FFMPEG_SWSCALE)
#define HAVE_FFMPEG_SWSCALE_H 1
#endif
#endif
#endif
#if defined(HAVE_FFMPEG_AVCODEC_H)
#include <ffmpeg/avcodec.h>
#endif
#if defined(HAVE_FFMPEG_AVFORMAT_H)
#include <ffmpeg/avformat.h>
#endif
#if defined(HAVE_FFMPEG_SWSCALE_H)
#include <ffmpeg/swscale.h>
#endif
#if defined(HAVE_LIBAVFORMAT_AVFORMAT_H)
#include <libavformat/avformat.h>
#endif
#if defined(HAVE_LIBAVCODEC_AVCODEC_H)
#include <libavcodec/avcodec.h>
#endif
#if defined(HAVE_LIBSWSCALE_SWSCALE_H)
#include <libswscale/swscale.h>
#endif
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#include "cap_ffmpeg_api.hpp"
#include <assert.h>
#include <algorithm>
#if defined _MSC_VER && _MSC_VER >= 1200 #if defined _MSC_VER && _MSC_VER >= 1200
#pragma warning( default: 4244 4510 4512 4610 ) #pragma warning( default: 4244 4510 4512 4610 )
#endif #endif
...@@ -67,6 +126,7 @@ extern "C" { ...@@ -67,6 +126,7 @@ extern "C" {
#define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__) #define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__)
#endif #endif
#ifndef MKTAG #ifndef MKTAG
#define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24)) #define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
#endif #endif
...@@ -301,6 +361,7 @@ const AVCodecTag codec_bmp_tags[] = { ...@@ -301,6 +361,7 @@ const AVCodecTag codec_bmp_tags[] = {
{ CODEC_ID_NONE, 0 }, { CODEC_ID_NONE, 0 },
}; };
struct Image_FFMPEG struct Image_FFMPEG
{ {
unsigned char* data; unsigned char* data;
...@@ -310,419 +371,488 @@ struct Image_FFMPEG ...@@ -310,419 +371,488 @@ struct Image_FFMPEG
int cn; int cn;
}; };
struct CvCapture_FFMPEG_2
inline void _opencv_ffmpeg_free(void** ptr)
{ {
CvCapture_FFMPEG_2(const char* filename); if(*ptr) free(*ptr);
CvCapture_FFMPEG_2(const CvCapture_FFMPEG_2& mf); *ptr = 0;
CvCapture_FFMPEG_2& operator=(const CvCapture_FFMPEG_2& mf); }
~CvCapture_FFMPEG_2();
bool open( const char* filename );
void close();
bool setProperty(int, double);
double getProperty(int);
bool grabFrame();
bool retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn);
void init();
bool reopen();
cv::Mat read();
void seek(int64_t frame_number);
void seek(double sec);
int64_t get_total_frames();
int64_t get_frame_number();
private:
AVFormatContext * ic;
AVCodecContext * avcodec_context;
AVCodec * avcodec;
AVFrame * picture;
AVFrame * rgb_picture;
AVStream * video_st;
AVPacket packet;
Image_FFMPEG frame;
#if defined(HAVE_FFMPEG_SWSCALE)
struct SwsContext *img_convert_ctx;
#endif
char* filename; struct CvCapture_FFMPEG
{
bool open( const char* filename );
void close();
int video_stream; double getProperty(int);
int64_t picture_pts; bool setProperty(int, double);
bool grabFrame();
bool retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn);
void init();
bool reopen();
size_t width, height; void seek(int64_t frame_number);
int64_t frame_number; void seek(double sec);
bool slowSeek( int framenumber );
double eps_zero; int64_t get_total_frames();
double get_duration_sec();
double get_fps();
int get_bitrate();
double get_duration_sec(); double r2d(AVRational r);
double get_fps(); int64_t dts_to_frame_number(int64_t dts);
int get_bitrate(); double dts_to_sec(int64_t dts);
double r2d(AVRational r); AVFormatContext * ic;
int64_t dts_to_frame_number(int64_t dts); AVCodecContext * avcodec_context;
double dts_to_sec(int64_t dts); AVCodec * avcodec;
int video_stream;
AVStream * video_st;
AVFrame * picture;
AVFrame rgb_picture;
int64_t picture_pts;
AVPacket packet;
Image_FFMPEG frame;
#if defined(HAVE_FFMPEG_SWSCALE)
struct SwsContext *img_convert_ctx;
#endif
int64_t frame_number;
double eps_zero;
/*
'filename' contains the filename of the videosource,
'filename==NULL' indicates that ffmpeg's seek support works
for the particular file.
'filename!=NULL' indicates that the slow fallback function is used for seeking,
and so the filename is needed to reopen the file on backward seeking.
*/
char * filename;
}; };
CvCapture_FFMPEG_2::CvCapture_FFMPEG_2(const char* filename) : void CvCapture_FFMPEG::init()
ic(0), avcodec_context(0), avcodec(0),
picture(0), rgb_picture(0), video_stream(-1),
width(0), height(0), frame_number(0), eps_zero(0.000025)
{ {
av_register_all(); ic = 0;
video_stream = -1;
video_st = 0;
picture = 0;
picture_pts = 0;
memset( &rgb_picture, 0, sizeof(rgb_picture) );
memset( &frame, 0, sizeof(frame) );
filename = 0;
packet.data = NULL;
#if defined(HAVE_FFMPEG_SWSCALE)
img_convert_ctx = 0;
#endif
avcodec_context = 0;
avcodec = 0;
frame_number = 0;
eps_zero = 0.000025;
}
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 13, 0)
avformat_network_init();
#endif
// Open video file void CvCapture_FFMPEG::close()
avformat_open_input(&ic, filename, NULL, NULL); {
if( picture )
av_free(picture);
// Find the first video stream if( video_st )
for(int i = 0; i < static_cast<int>(ic->nb_streams); i++) {
{ #if LIBAVFORMAT_BUILD > 4628
struct AVCodecContext * cc = ic->streams[i]->codec; avcodec_close( video_st->codec );
// set number of threads
cc->thread_count = 2;
if(cc->codec_type == AVMEDIA_TYPE_VIDEO && video_stream == -1) #else
{ avcodec_close( &(video_st->codec) );
AVCodec * codec = avcodec_find_decoder(cc->codec_id);
if (codec == NULL) #endif
CV_Error(0, "Unsupported codec !!!"); video_st = NULL;
}
avcodec_open2(cc, codec, NULL); if ( avcodec_context )
video_stream = i; {
break; #if LIBAVFORMAT_BUILD > 4628
} avcodec_close( avcodec_context );
#else
avcodec_close( &avcodec_context );
#endif
avcodec_context = NULL;
} }
if(video_stream == -1) if( ic )
CV_Error(0, "Didn't find a video stream"); {
#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 24, 2)
av_close_input_file(ic);
#else
avformat_close_input(&ic);
#endif
// Get a pointer to the codec context for the video stream ic = NULL;
avcodec_context = ic->streams[video_stream]->codec; }
// Allocate video frame if( rgb_picture.data[0] )
picture = avcodec_alloc_frame(); {
} free( rgb_picture.data[0] );
rgb_picture.data[0] = 0;
}
CvCapture_FFMPEG_2::CvCapture_FFMPEG_2(const CvCapture_FFMPEG_2& vr) : // free last packet if exist
ic(vr.ic), if (packet.data) {
avcodec_context (vr.avcodec_context), av_free_packet (&packet);
avcodec(0), }
picture(0),
rgb_picture(0), init();
video_stream(-1),
width(0), height(0),
frame_number(0),
eps_zero(0.000001) {}
CvCapture_FFMPEG_2& CvCapture_FFMPEG_2::operator=(const CvCapture_FFMPEG_2& mf)
{
ic = mf.ic;
avcodec_context = mf.avcodec_context;
return *this;
} }
bool CvCapture_FFMPEG_2::open(const char* filename)
/*
Used to reopen a video if the slower fallback function for seeking is used.
*/
bool CvCapture_FFMPEG::reopen()
{ {
CvCapture_FFMPEG_2 cap(filename); if ( filename==NULL ) return false;
*this = cap;
#if LIBAVFORMAT_BUILD > 4628
avcodec_close( video_st->codec );
avcodec_close( avcodec_context );
#else
avcodec_close( &video_st->codec );
avcodec_close( &avcodec_context );
#endif
#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 24, 2)
av_close_input_file(ic);
#else
avformat_close_input(&ic);
#endif
// reopen video
avformat_open_input(&ic, filename, NULL, NULL);
av_find_stream_info(ic);
#if LIBAVFORMAT_BUILD > 4628
AVCodecContext *enc = ic->streams[video_stream]->codec;
#else
AVCodecContext *enc = &ic->streams[video_stream]->codec;
#endif
#ifdef FF_API_THREAD_INIT
avcodec_thread_init(enc, std::min(get_number_of_cpus(), 16));
#endif
AVCodec *codec = avcodec_find_decoder(enc->codec_id);
#if FF_API_AVCODEC_OPEN
avcodec_open(enc, codec);
#else
avcodec_open_2(enc, codec, NULL);
#endif
video_st = ic->streams[video_stream];
// reset framenumber to zero
frame_number = 0;
picture_pts=0;
return true;
} }
void CvCapture_FFMPEG_2::close() #ifndef AVSEEK_FLAG_FRAME
#define AVSEEK_FLAG_FRAME 0
#endif
#ifndef AVSEEK_FLAG_ANY
#define AVSEEK_FLAG_ANY 1
#endif
bool CvCapture_FFMPEG::open( const char* _filename )
{ {
if( picture ) unsigned i;
av_free(picture); bool valid = false;
if( video_st ) close();
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 13, 0)
avformat_network_init();
#endif
/* register all codecs, demux and protocols */
av_register_all();
#ifndef _DEBUG
// av_log_level = AV_LOG_QUIET;
#endif
int err = avformat_open_input(&ic, _filename, NULL, NULL);
if (err < 0) {
CV_WARN("Error opening file");
goto exit_func;
}
err = av_find_stream_info(ic);
if (err < 0) {
CV_WARN("Could not find codec parameters");
goto exit_func;
}
for(i = 0; i < ic->nb_streams; i++)
{ {
#if LIBAVFORMAT_BUILD > 4628 #if LIBAVFORMAT_BUILD > 4628
avcodec_close( video_st->codec ); AVCodecContext *enc = ic->streams[i]->codec;
#else #else
avcodec_close( &video_st->codec ); AVCodecContext *enc = &ic->streams[i]->codec;
#endif #endif
video_st = NULL;
#ifdef FF_API_THREAD_INIT
avcodec_thread_init(enc, get_number_of_cpus());
#else
enc->thread_count = get_number_of_cpus();
#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) {
AVCodec *codec = avcodec_find_decoder(enc->codec_id);
if (!codec ||
#if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0)
avcodec_open2(enc, codec, NULL)
#else
avcodec_open(enc, codec)
#endif
< 0) goto exit_func;
video_stream = i;
video_st = ic->streams[i];
picture = avcodec_alloc_frame();
rgb_picture.data[0] = (uint8_t*)malloc(
avpicture_get_size( PIX_FMT_BGR24,
enc->width, enc->height ));
avpicture_fill( (AVPicture*)&rgb_picture, rgb_picture.data[0],
PIX_FMT_BGR24, enc->width, enc->height );
frame.width = enc->width;
frame.height = enc->height;
frame.cn = 3;
frame.step = rgb_picture.linesize[0];
frame.data = rgb_picture.data[0];
break;
}
} }
if( ic ) if(video_stream >= 0) valid = true;
// perform check if source is seekable via ffmpeg's seek function av_seek_frame(...)
err = av_seek_frame(ic, video_stream, 10, 0);
if (err < 0)
{ {
av_close_input_file(ic); filename=(char*)malloc(strlen(_filename)+1);
ic = NULL; strcpy(filename, _filename);
// reopen videofile to 'seek' back to first frame
reopen();
} }
else
if( rgb_picture->data[0] )
{ {
free( rgb_picture->data[0] ); // seek seems to work, so we don't need the filename,
rgb_picture->data[0] = 0; // but we still need to seek back to filestart
filename=NULL;
int64_t ts = video_st->first_dts;
int flags = AVSEEK_FLAG_FRAME | AVSEEK_FLAG_BACKWARD;
av_seek_frame(ic, video_stream, ts, flags);
} }
exit_func:
// free last packet if exist if( !valid )
if (packet.data) { close();
av_free_packet (&packet);
}
init(); return valid;
} }
bool CvCapture_FFMPEG_2::grabFrame()
bool CvCapture_FFMPEG::grabFrame()
{ {
bool valid = false; bool valid = false;
static bool bFirstTime = true; static bool bFirstTime = true;
int got_picture; int got_picture;
// First time we're called, set packet.data to NULL to indicate it int count_errs = 0;
// doesn't have to be freed const int max_number_of_attempts = 64;
if (bFirstTime) {
if (bFirstTime)
{
bFirstTime = false; bFirstTime = false;
packet.data = NULL; packet.data = NULL;
} }
if( !ic || !video_st ) if( !ic || !video_st ) return false;
return false;
// free last packet if exist if (packet.data != NULL)
if (packet.data != NULL) { {
av_free_packet (&packet); av_free_packet (&packet);
} }
// get the next frame // get the next frame
while (!valid) { while (!valid)
{
int ret = av_read_frame(ic, &packet); int ret = av_read_frame(ic, &packet);
if (ret == AVERROR(EAGAIN))
continue;
if (ret < 0)
break;
if( packet.stream_index != video_stream ) { if (ret == AVERROR(EAGAIN)) continue;
/* else if (ret < 0) break; */
if( packet.stream_index != video_stream )
{
av_free_packet (&packet); av_free_packet (&packet);
count_errs++;
if (count_errs > max_number_of_attempts) break; else
continue; continue;
} }
// Decode video frame
avcodec_decode_video2(video_st->codec, picture, &got_picture, &packet); avcodec_decode_video2(video_st->codec, picture, &got_picture, &packet);
if (got_picture) { // Did we get a video frame?
// we have a new picture, so memorize it if(got_picture)
picture_pts = packet.pts; {
valid = 1; frame_number++;
} picture_pts = packet.pts;
valid = true;
}
else
{
count_errs++;
if (count_errs > max_number_of_attempts)
break;
}
} }
// return if we have a new picture or not // return if we have a new picture or not
return valid; return valid;
} }
bool CvCapture_FFMPEG_2::retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn)
bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn)
{ {
if( !video_st || !picture->data[0] ) if( !video_st || !picture->data[0] )
return false; return false;
#if !defined(HAVE_FFMPEG_SWSCALE) rgb_picture = *avcodec_alloc_frame();
#if LIBAVFORMAT_BUILD > 4628
img_convert( (AVPicture*)&rgb_picture, PIX_FMT_BGR24,
(AVPicture*)picture,
video_st->codec->pix_fmt,
video_st->codec->width,
video_st->codec->height );
#else
img_convert( (AVPicture*)&rgb_picture, PIX_FMT_BGR24,
(AVPicture*)picture,
video_st->codec.pix_fmt,
video_st->codec.width,
video_st->codec.height );
#endif
#else
img_convert_ctx = sws_getContext(video_st->codec->width,
video_st->codec->height,
video_st->codec->pix_fmt,
video_st->codec->width,
video_st->codec->height,
PIX_FMT_BGR24,
SWS_BICUBIC,
NULL, NULL, NULL);
sws_scale(img_convert_ctx, picture->data,
picture->linesize, 0,
video_st->codec->height,
rgb_picture->data, rgb_picture->linesize);
sws_freeContext(img_convert_ctx);
#endif
*data = frame.data;
*step = frame.step;
*width = frame.width;
*height = frame.height;
*cn = frame.cn;
return true; avpicture_fill((AVPicture*)&rgb_picture, rgb_picture.data[0], PIX_FMT_RGB24, video_st->codec->width, video_st->codec->height);
}
void CvCapture_FFMPEG_2::init() #if LIBAVCODEC_VERSION_INT >= ((53<<16)+(6<<8)+0)
{
ic = 0;
video_stream = -1;
video_st = 0;
picture = 0;
picture_pts = 0;
memset( &rgb_picture, 0, sizeof(rgb_picture) );
memset( &frame, 0, sizeof(frame) );
filename = 0;
packet.data = NULL;
#if defined(HAVE_FFMPEG_SWSCALE)
img_convert_ctx = 0;
#endif
}
bool CvCapture_FFMPEG_2::reopen() frame.width = picture->width;
{ frame.height = picture->height;
if ( filename==NULL ) return false;
#if LIBAVFORMAT_BUILD > 4628 #else
avcodec_close( video_st->codec ); frame.width = video_st->codec->width;
#else frame.height = video_st->codec->height;
avcodec_close( &video_st->codec ); #endif
#endif
av_close_input_file(ic);
// reopen video img_convert_ctx = sws_getContext(
#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(52, 111, 0) video_st->codec->width, video_st->codec->height,
av_open_input_file(&ic, filename, NULL, 0, NULL); video_st->codec->pix_fmt,
#else video_st->codec->width, video_st->codec->height,
avformat_open_input(&ic, filename, NULL, NULL); PIX_FMT_BGR24,
#endif SWS_BICUBIC,
NULL, NULL, NULL
);
av_find_stream_info(ic); img_convert_ctx = sws_getCachedContext(
img_convert_ctx,
video_st->codec->width, video_st->codec->height,
video_st->codec->pix_fmt,
video_st->codec->width, video_st->codec->height,
PIX_FMT_BGR24,
SWS_BICUBIC,
NULL, NULL, NULL
);
#if LIBAVFORMAT_BUILD > 4628 if (img_convert_ctx == NULL)
AVCodecContext *enc = ic->streams[video_stream]->codec; CV_Error(0, "Cannot initialize the conversion context!");
#else
AVCodecContext *enc = &ic->streams[video_stream]->codec;
#endif
#if FF_API_THREAD_INIT sws_scale(
avcodec_thread_init(enc, std::min(get_number_of_cpus(), 16)); img_convert_ctx,
#endif picture->data,
picture->linesize,
0, video_st->codec->height,
rgb_picture.data,
rgb_picture.linesize
);
AVCodec *codec = avcodec_find_decoder(enc->codec_id); sws_freeContext(img_convert_ctx);
avcodec_open(enc, codec);
video_st = ic->streams[video_stream];
// reset framenumber to zero
picture_pts=0;
frame_number++;
*data = frame.data;
*step = frame.step;
*width = frame.width;
*height = frame.height;
*cn = frame.cn;
return true; return true;
} }
int64_t CvCapture_FFMPEG_2::get_frame_number() #if defined(__APPLE__)
{ #define AV_NOPTS_VALUE_ ((int64_t)0x8000000000000000LL)
return frame_number; #else
} #define AV_NOPTS_VALUE_ ((int64_t)AV_NOPTS_VALUE)
#endif
cv::Mat CvCapture_FFMPEG_2::read() double CvCapture_FFMPEG::getProperty( int property_id )
{ {
int frame_finished = 0; // if( !capture || !video_st || !picture->data[0] ) return 0;
AVPacket packet; if( !video_st ) return 0;
int count_errs = 0; // double frameScale = av_q2d (video_st->time_base) * av_q2d (video_st->r_frame_rate);
const int max_number_of_attempts = 32; int64_t timestamp;
timestamp = picture_pts;
while(true) switch( property_id )
{ {
av_read_frame(ic, &packet); case CV_FFMPEG_CAP_PROP_POS_MSEC:
return 1000.0*static_cast<int>(frame_number)/static_cast<int>(get_fps());
if(packet.stream_index == video_stream) break;
{ case CV_FFMPEG_CAP_PROP_POS_FRAMES:
// Decode video frame return (double)static_cast<int>(frame_number);
avcodec_decode_video2(avcodec_context, picture, &frame_finished, &packet); break;
case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO:
// Did we get a video frame? return r2d(ic->streams[video_stream]->time_base);
if(frame_finished) break;
{ case CV_FFMPEG_CAP_PROP_FRAME_COUNT:
rgb_picture = avcodec_alloc_frame(); return (double)static_cast<int>(get_total_frames());
break;
cv::Mat img(static_cast<int>(avcodec_context->height), static_cast<int>(avcodec_context->width), CV_8UC3); case CV_FFMPEG_CAP_PROP_FRAME_WIDTH:
return (double)frame.width;
uint8_t * buffer = reinterpret_cast<uint8_t *>(img.ptr(0)); break;
case CV_FFMPEG_CAP_PROP_FRAME_HEIGHT:
avpicture_fill(reinterpret_cast<AVPicture*>(rgb_picture), buffer, PIX_FMT_RGB24, avcodec_context->width, avcodec_context->height); return (double)frame.height;
break;
#if LIBAVCODEC_VERSION_INT >= ((53<<16)+(4<<8)+0) case CV_FFMPEG_CAP_PROP_FPS:
#if LIBAVCODEC_BUILD > 4753
width = picture->width; return av_q2d (video_st->r_frame_rate);
height = picture->height; #else
#else return (double)video_st->codec.frame_rate
width = avcodec_context->width; / (double)video_st->codec.frame_rate_base;
height = avcodec_context->height; #endif
#endif break;
case CV_FFMPEG_CAP_PROP_FOURCC:
struct SwsContext * img_convert_ctx = sws_getContext( #if LIBAVFORMAT_BUILD > 4628
width, height, return (double)video_st->codec->codec_tag;
avcodec_context->pix_fmt, #else
width, height, return (double)video_st->codec.codec_tag;
PIX_FMT_BGR24, #endif
SWS_BICUBIC, break;
NULL, NULL, NULL
);
img_convert_ctx = sws_getCachedContext(
img_convert_ctx,
width, height,
avcodec_context->pix_fmt,
width, height,
PIX_FMT_BGR24,
SWS_BICUBIC,
NULL, NULL, NULL
);
if (img_convert_ctx == NULL)
CV_Error(0, "Cannot initialize the conversion context!");
sws_scale(
img_convert_ctx,
picture->data,
picture->linesize,
0, height,
rgb_picture->data,
rgb_picture->linesize
);
sws_freeContext(img_convert_ctx);
av_free(rgb_picture);
frame_number++;
//std::cout << "cur dts: " << ic->streams[video_stream]->cur_dts << std::endl;
return img;
}
else
{
count_errs ++;
if (count_errs > max_number_of_attempts)
break;
}
}
else
{
count_errs ++;
if (count_errs > max_number_of_attempts)
break;
}
} }
// Free the packet that was allocated by av_read_frame return 0;
av_free_packet(&packet);
return cv::Mat();
} }
double CvCapture_FFMPEG_2::r2d(AVRational r) double CvCapture_FFMPEG::r2d(AVRational r)
{ {
if (r.num == 0 || r.den == 0) if (r.num == 0 || r.den == 0)
{ {
...@@ -734,7 +864,7 @@ double CvCapture_FFMPEG_2::r2d(AVRational r) ...@@ -734,7 +864,7 @@ double CvCapture_FFMPEG_2::r2d(AVRational r)
} }
} }
double CvCapture_FFMPEG_2::get_duration_sec() double CvCapture_FFMPEG::get_duration_sec()
{ {
double sec = static_cast<double>(ic->duration) / static_cast<double>(AV_TIME_BASE); double sec = static_cast<double>(ic->duration) / static_cast<double>(AV_TIME_BASE);
...@@ -747,15 +877,16 @@ double CvCapture_FFMPEG_2::get_duration_sec() ...@@ -747,15 +877,16 @@ double CvCapture_FFMPEG_2::get_duration_sec()
{ {
sec = static_cast<double>(static_cast<int64_t>(ic->streams[video_stream]->duration)) * r2d(ic->streams[video_stream]->time_base); sec = static_cast<double>(static_cast<int64_t>(ic->streams[video_stream]->duration)) * r2d(ic->streams[video_stream]->time_base);
} }
return sec; return sec;
} }
int CvCapture_FFMPEG_2::get_bitrate() int CvCapture_FFMPEG::get_bitrate()
{ {
return ic->bit_rate; return ic->bit_rate;
} }
double CvCapture_FFMPEG_2::get_fps() double CvCapture_FFMPEG::get_fps()
{ {
double fps = r2d(ic->streams[video_stream]->r_frame_rate); double fps = r2d(ic->streams[video_stream]->r_frame_rate);
...@@ -764,7 +895,6 @@ double CvCapture_FFMPEG_2::get_fps() ...@@ -764,7 +895,6 @@ double CvCapture_FFMPEG_2::get_fps()
fps = r2d(ic->streams[video_stream]->avg_frame_rate); fps = r2d(ic->streams[video_stream]->avg_frame_rate);
} }
// may be this is wrong
if (fps < eps_zero) if (fps < eps_zero)
{ {
fps = 1.0 / r2d(ic->streams[video_stream]->codec->time_base); fps = 1.0 / r2d(ic->streams[video_stream]->codec->time_base);
...@@ -773,7 +903,7 @@ double CvCapture_FFMPEG_2::get_fps() ...@@ -773,7 +903,7 @@ double CvCapture_FFMPEG_2::get_fps()
return fps; return fps;
} }
int64_t CvCapture_FFMPEG_2::get_total_frames() int64_t CvCapture_FFMPEG::get_total_frames()
{ {
int64_t nbf = ic->streams[video_stream]->nb_frames; int64_t nbf = ic->streams[video_stream]->nb_frames;
...@@ -784,30 +914,21 @@ int64_t CvCapture_FFMPEG_2::get_total_frames() ...@@ -784,30 +914,21 @@ int64_t CvCapture_FFMPEG_2::get_total_frames()
return nbf; return nbf;
} }
//#include <iostream> int64_t CvCapture_FFMPEG::dts_to_frame_number(int64_t dts)
double round(double d)
{
return std::floor(d + 0.5);
}
int64_t CvCapture_FFMPEG_2::dts_to_frame_number(int64_t dts)
{ {
double sec = dts_to_sec(dts); double sec = dts_to_sec(dts);
return static_cast<int64_t>(get_fps() * sec); return static_cast<int64_t>(get_fps() * sec);
} }
double CvCapture_FFMPEG_2::dts_to_sec(int64_t dts) double CvCapture_FFMPEG::dts_to_sec(int64_t dts)
{ {
return static_cast<double>(dts - ic->streams[video_stream]->start_time) * r2d(ic->streams[video_stream]->time_base); return static_cast<double>(dts - ic->streams[video_stream]->start_time) * r2d(ic->streams[video_stream]->time_base);
} }
void CvCapture_FFMPEG_2::seek(int64_t frame_number) void CvCapture_FFMPEG::seek(int64_t frame_number)
{ {
double sec = static_cast<double>(frame_number) / static_cast<double>(get_fps()); frame_number = std::min(frame_number, get_total_frames());
this->frame_number = std::min<int>(frame_number, get_total_frames()); int64_t dts = dts_to_frame_number(ic->streams[video_stream]->cur_dts);
seek(sec);
/* int64_t dts = dts_to_frame_number(ic->streams[video_stream]->cur_dts);
if (abs(dts - 2 - frame_number) > 16) if (abs(dts - 2 - frame_number) > 16)
{ {
...@@ -820,38 +941,38 @@ void CvCapture_FFMPEG_2::seek(int64_t frame_number) ...@@ -820,38 +941,38 @@ void CvCapture_FFMPEG_2::seek(int64_t frame_number)
while(dts - 2 < frame_number) while(dts - 2 < frame_number)
{ {
cv::Mat i = read(); /* cv::Mat imag = read(); */
if (i.empty()) if (!grabFrame()) break;
break;
dts = dts_to_frame_number(ic->streams[video_stream]->cur_dts); dts = dts_to_frame_number(ic->streams[video_stream]->cur_dts);
}
//std::cout << "cur dts: " << ic->streams[video_stream]->cur_dts << " f: " << dts << std::endl;
} */
} }
void CvCapture_FFMPEG_2::seek(double sec) void CvCapture_FFMPEG::seek(double sec)
{ {
// seek(static_cast<int64_t>(sec * get_fps())); seek(static_cast<int64_t>(sec * get_fps()));
int64_t time_stamp = ic->streams[video_stream]->start_time;
double time_base = av_q2d(ic->streams[video_stream]->time_base);
time_stamp += static_cast<int64_t>(sec / time_base);
av_seek_frame(ic, video_stream, time_stamp, AVSEEK_FLAG_FRAME | AVSEEK_FLAG_BACKWARD);
} }
CvCapture_FFMPEG_2::~CvCapture_FFMPEG_2() // this is a VERY slow fallback function, ONLY used if ffmpeg's av_seek_frame delivers no correct result!
bool CvCapture_FFMPEG::slowSeek( int framenumber )
{ {
#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 24, 2) if ( framenumber>picture_pts )
av_close_input_file(ic); {
#else while ( picture_pts<framenumber )
avformat_close_input(&ic); if ( !grabFrame() ) return false;
#endif }
else if ( framenumber<picture_pts )
{
reopen();
while ( picture_pts<framenumber )
if ( !grabFrame() ) return false;
}
return true;
} }
bool CvCapture_FFMPEG_2::setProperty( int property_id, double value ) bool CvCapture_FFMPEG::setProperty( int property_id, double value )
{ {
if (!video_stream) return false; if( !video_st ) return false;
switch( property_id ) switch( property_id )
{ {
...@@ -859,46 +980,22 @@ bool CvCapture_FFMPEG_2::setProperty( int property_id, double value ) ...@@ -859,46 +980,22 @@ bool CvCapture_FFMPEG_2::setProperty( int property_id, double value )
case CV_FFMPEG_CAP_PROP_POS_FRAMES: case CV_FFMPEG_CAP_PROP_POS_FRAMES:
case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO: case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO:
{ {
switch( property_id ) switch( property_id )
{ {
case CV_FFMPEG_CAP_PROP_POS_FRAMES: case CV_FFMPEG_CAP_PROP_POS_FRAMES:
seek(value/1000.0); break; seek((int64_t)value);
break; break;
case CV_FFMPEG_CAP_PROP_POS_MSEC: case CV_FFMPEG_CAP_PROP_POS_MSEC:
seek(value); seek(value/1000.0);
break; break;
case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO: case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO:
seek(value*this->get_bitrate()); seek((int64_t)(value*ic->duration));
break; break;
} }
/* if ( filename ) picture_pts=(int64_t)value;
{
// ffmpeg's seek doesn't work...
if (!slowSeek((int)timestamp))
{
fprintf(stderr, "HIGHGUI ERROR: AVI: could not (slow) seek to position %0.3f\n",
(double)timestamp / AV_TIME_BASE);
return false;
}
}
else
{
int flags = AVSEEK_FLAG_ANY;
if (timestamp < ic->streams[video_stream]->cur_dts)
flags |= AVSEEK_FLAG_BACKWARD;
int ret = av_seek_frame(ic, video_stream, timestamp, flags);
if (ret < 0)
{
fprintf(stderr, "HIGHGUI ERROR: AVI: could not seek to position %0.3f\n",
(double)timestamp / AV_TIME_BASE);
return false;
}
}
picture_pts=(int64_t)value;*/
} }
break; break;
default: default:
...@@ -906,69 +1003,8 @@ bool CvCapture_FFMPEG_2::setProperty( int property_id, double value ) ...@@ -906,69 +1003,8 @@ bool CvCapture_FFMPEG_2::setProperty( int property_id, double value )
} }
return true; return true;
} }
#if defined(__APPLE__)
#define AV_NOPTS_VALUE_ ((int64_t)0x8000000000000000LL)
#else
#define AV_NOPTS_VALUE_ ((int64_t)AV_NOPTS_VALUE)
#endif
double CvCapture_FFMPEG_2::getProperty( int property_id )
{
// if( !capture || !video_st || !picture->data[0] ) return 0;
if( !video_stream ) return 0;
double frameScale = av_q2d (video_st->time_base) * av_q2d (video_st->r_frame_rate);
int64_t timestamp;
timestamp = picture_pts;
switch( property_id )
{
case CV_FFMPEG_CAP_PROP_POS_MSEC:
return 1000.0*static_cast<double>(dts_to_sec(frame_number));
break;
case CV_FFMPEG_CAP_PROP_POS_FRAMES:
return (double)static_cast<int>(get_frame_number());
break;
case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO:
return static_cast<double>(dts_to_frame_number(frame_number))/static_cast<double>(dts_to_sec(frame_number));
break;
case CV_FFMPEG_CAP_PROP_FRAME_COUNT:
return (double)static_cast<int>(get_total_frames());
break;
case CV_FFMPEG_CAP_PROP_FRAME_WIDTH:
return (double)static_cast<int>(width);
break;
case CV_FFMPEG_CAP_PROP_FRAME_HEIGHT:
return (double)static_cast<int>(height);
break;
case CV_FFMPEG_CAP_PROP_FPS:
#if LIBAVCODEC_BUILD > 4753
return av_q2d (video_st->r_frame_rate);
#else
return (double)video_st->codec.frame_rate
/ (double)video_st->codec.frame_rate_base;
#endif
break;
case CV_FFMPEG_CAP_PROP_FOURCC:
#if LIBAVFORMAT_BUILD > 4628
return (double)video_st->codec->codec_tag;
#else
return (double)video_st->codec.codec_tag;
#endif
break;
}
return 0;
}
///////////////// FFMPEG CvVideoWriter implementation ////////////////////////// ///////////////// FFMPEG CvVideoWriter implementation //////////////////////////
struct CvVideoWriter_FFMPEG struct CvVideoWriter_FFMPEG
...@@ -980,8 +1016,8 @@ struct CvVideoWriter_FFMPEG ...@@ -980,8 +1016,8 @@ struct CvVideoWriter_FFMPEG
void init(); void init();
AVOutputFormat *fmt; AVOutputFormat * fmt;
AVFormatContext *oc; AVFormatContext * oc;
uint8_t * outbuf; uint8_t * outbuf;
uint32_t outbuf_size; uint32_t outbuf_size;
FILE * outfile; FILE * outfile;
...@@ -1067,9 +1103,9 @@ void CvVideoWriter_FFMPEG::init() ...@@ -1067,9 +1103,9 @@ void CvVideoWriter_FFMPEG::init()
video_st = 0; video_st = 0;
input_pix_fmt = 0; input_pix_fmt = 0;
memset(&temp_image, 0, sizeof(temp_image)); memset(&temp_image, 0, sizeof(temp_image));
#if defined(HAVE_FFMPEG_SWSCALE) #if defined(HAVE_FFMPEG_SWSCALE)
img_convert_ctx = 0; img_convert_ctx = 0;
#endif #endif
} }
/** /**
...@@ -1115,21 +1151,21 @@ static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc, ...@@ -1115,21 +1151,21 @@ static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc,
st = av_new_stream(oc, 0); st = av_new_stream(oc, 0);
if (!st) { if (!st) {
/* CV_WARN("Could not allocate stream"); */ CV_WARN("Could not allocate stream");
return NULL; return NULL;
} }
#if LIBAVFORMAT_BUILD > 4628 #if LIBAVFORMAT_BUILD > 4628
c = st->codec; c = st->codec;
#else #else
c = &(st->codec); c = &(st->codec);
#endif #endif
#if LIBAVFORMAT_BUILD > 4621 #if LIBAVFORMAT_BUILD > 4621
c->codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, AVMEDIA_TYPE_VIDEO); c->codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, AVMEDIA_TYPE_VIDEO);
#else #else
c->codec_id = oc->oformat->video_codec; c->codec_id = oc->oformat->video_codec;
#endif #endif
if(codec_id != CODEC_ID_NONE){ if(codec_id != CODEC_ID_NONE){
c->codec_id = codec_id; c->codec_id = codec_id;
...@@ -1157,30 +1193,30 @@ static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc, ...@@ -1157,30 +1193,30 @@ static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc,
frame_rate_base*=10; frame_rate_base*=10;
frame_rate=(int)(fps*frame_rate_base + 0.5); frame_rate=(int)(fps*frame_rate_base + 0.5);
} }
#if LIBAVFORMAT_BUILD > 4752 #if LIBAVFORMAT_BUILD > 4752
c->time_base.den = frame_rate; c->time_base.den = frame_rate;
c->time_base.num = frame_rate_base; c->time_base.num = frame_rate_base;
/* adjust time base for supported framerates */ /* adjust time base for supported framerates */
if(codec && codec->supported_framerates){ if(codec && codec->supported_framerates){
const AVRational *p= codec->supported_framerates; const AVRational *p= codec->supported_framerates;
AVRational req = {frame_rate, frame_rate_base}; AVRational req = {frame_rate, frame_rate_base};
const AVRational *best=NULL; const AVRational *best=NULL;
AVRational best_error= {INT_MAX, 1}; AVRational best_error= {INT_MAX, 1};
for(; p->den!=0; p++){ for(; p->den!=0; p++){
AVRational error= av_sub_q(req, *p); AVRational error= av_sub_q(req, *p);
if(error.num <0) error.num *= -1; if(error.num <0) error.num *= -1;
if(av_cmp_q(error, best_error) < 0){ if(av_cmp_q(error, best_error) < 0){
best_error= error; best_error= error;
best= p; best= p;
} }
} }
c->time_base.den= best->num; c->time_base.den= best->num;
c->time_base.num= best->den; c->time_base.num= best->den;
} }
#else #else
c->frame_rate = frame_rate; c->frame_rate = frame_rate;
c->frame_rate_base = frame_rate_base; c->frame_rate_base = frame_rate_base;
#endif #endif
c->gop_size = 12; /* emit one intra frame every twelve frames at most */ c->gop_size = 12; /* emit one intra frame every twelve frames at most */
c->pix_fmt = (PixelFormat) pixel_format; c->pix_fmt = (PixelFormat) pixel_format;
...@@ -1195,25 +1231,24 @@ static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc, ...@@ -1195,25 +1231,24 @@ static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc,
/* avoid FFMPEG warning 'clipping 1 dct coefficients...' */ /* avoid FFMPEG warning 'clipping 1 dct coefficients...' */
c->mb_decision=2; c->mb_decision=2;
} }
#if LIBAVCODEC_VERSION_INT>0x000409 #if LIBAVCODEC_VERSION_INT>0x000409
// some formats want stream headers to be seperate // some formats want stream headers to be seperate
if(oc->oformat->flags & AVFMT_GLOBALHEADER) if(oc->oformat->flags & AVFMT_GLOBALHEADER)
{ {
c->flags |= CODEC_FLAG_GLOBAL_HEADER; c->flags |= CODEC_FLAG_GLOBAL_HEADER;
} }
#endif #endif
return st; return st;
} }
int icv_av_write_frame_FFMPEG( AVFormatContext * oc, AVStream * video_st, uint8_t * outbuf, uint32_t outbuf_size, AVFrame * picture ) int icv_av_write_frame_FFMPEG( AVFormatContext * oc, AVStream * video_st, uint8_t * outbuf, uint32_t outbuf_size, AVFrame * picture )
{ {
#if LIBAVFORMAT_BUILD > 4628
#if LIBAVFORMAT_BUILD > 4628 AVCodecContext * c = video_st->codec;
AVCodecContext * c = video_st->codec; #else
#else AVCodecContext * c = &(video_st->codec);
AVCodecContext * c = &(video_st->codec); #endif
#endif
int out_size; int out_size;
int ret; int ret;
...@@ -1241,11 +1276,11 @@ int icv_av_write_frame_FFMPEG( AVFormatContext * oc, AVStream * video_st, uint8_ ...@@ -1241,11 +1276,11 @@ int icv_av_write_frame_FFMPEG( AVFormatContext * oc, AVStream * video_st, uint8_
AVPacket pkt; AVPacket pkt;
av_init_packet(&pkt); av_init_packet(&pkt);
#if LIBAVFORMAT_BUILD > 4752 #if LIBAVFORMAT_BUILD > 4752
pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, video_st->time_base); pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, video_st->time_base);
#else #else
pkt.pts = c->coded_frame->pts; pkt.pts = c->coded_frame->pts;
#endif #endif
if(c->coded_frame->key_frame) if(c->coded_frame->key_frame)
pkt.flags |= PKT_FLAG_KEY; pkt.flags |= PKT_FLAG_KEY;
pkt.stream_index= video_st->index; pkt.stream_index= video_st->index;
...@@ -1269,50 +1304,50 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int ...@@ -1269,50 +1304,50 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int
bool ret = false; bool ret = false;
// typecast from opaque data type to implemented struct // typecast from opaque data type to implemented struct
#if LIBAVFORMAT_BUILD > 4628 #if LIBAVFORMAT_BUILD > 4628
AVCodecContext *c = video_st->codec; AVCodecContext *c = video_st->codec;
#else #else
AVCodecContext *c = &(video_st->codec); AVCodecContext *c = &(video_st->codec);
#endif #endif
#if LIBAVFORMAT_BUILD < 5231 #if LIBAVFORMAT_BUILD < 5231
// It is not needed in the latest versions of the ffmpeg // It is not needed in the latest versions of the ffmpeg
if( c->codec_id == CODEC_ID_RAWVIDEO && origin != 1 ) if( c->codec_id == CODEC_ID_RAWVIDEO && origin != 1 )
{ {
if( !temp_image.data ) if( !temp_image.data )
{ {
temp_image.step = (width*cn + 3) & -4; temp_image.step = (width*cn + 3) & -4;
temp_image.width = width; temp_image.width = width;
temp_image.height = height; temp_image.height = height;
temp_image.cn = cn; temp_image.cn = cn;
temp_image.data = (unsigned char*)malloc(temp_image.step*temp_image.height); temp_image.data = (unsigned char*)malloc(temp_image.step*temp_image.height);
} }
for( int y = 0; y < height; y++ ) for( int y = 0; y < height; y++ )
memcpy(temp_image.data + y*temp_image.step, data + (height-1-y)*step, width*cn); memcpy(temp_image.data + y*temp_image.step, data + (height-1-y)*step, width*cn);
data = temp_image.data; data = temp_image.data;
step = temp_image.step; step = temp_image.step;
} }
#else #else
if( width*cn != step ) if( width*cn != step )
{ {
if( !temp_image.data ) if( !temp_image.data )
{ {
temp_image.step = width*cn; temp_image.step = width*cn;
temp_image.width = width; temp_image.width = width;
temp_image.height = height; temp_image.height = height;
temp_image.cn = cn; temp_image.cn = cn;
temp_image.data = (unsigned char*)malloc(temp_image.step*temp_image.height); temp_image.data = (unsigned char*)malloc(temp_image.step*temp_image.height);
} }
if (origin == 1) if (origin == 1)
for( int y = 0; y < height; y++ ) for( int y = 0; y < height; y++ )
memcpy(temp_image.data + y*temp_image.step, data + (height-1-y)*step, temp_image.step); memcpy(temp_image.data + y*temp_image.step, data + (height-1-y)*step, temp_image.step);
else else
for( int y = 0; y < height; y++ ) for( int y = 0; y < height; y++ )
memcpy(temp_image.data + y*temp_image.step, data + y*step, temp_image.step); memcpy(temp_image.data + y*temp_image.step, data + y*step, temp_image.step);
data = temp_image.data; data = temp_image.data;
step = temp_image.step; step = temp_image.step;
} }
#endif #endif
// check parameters // check parameters
if (input_pix_fmt == PIX_FMT_BGR24) { if (input_pix_fmt == PIX_FMT_BGR24) {
...@@ -1329,13 +1364,6 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int ...@@ -1329,13 +1364,6 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int
assert(false); assert(false);
} }
// check if buffer sizes match, i.e. image has expected format (size, channels, bitdepth, alignment)
/*#if LIBAVCODEC_VERSION_INT >= ((52<<16)+(37<<8)+0)
assert (image->imageSize == avpicture_get_size( (PixelFormat)input_pix_fmt, image->width, image->height ));
#else
assert (image->imageSize == avpicture_get_size( input_pix_fmt, image->width, image->height ));
#endif*/
if ( c->pix_fmt != input_pix_fmt ) { if ( c->pix_fmt != input_pix_fmt ) {
assert( input_picture ); assert( input_picture );
// let input_picture point to the raw data buffer of 'image' // let input_picture point to the raw data buffer of 'image'
...@@ -1397,11 +1425,11 @@ void CvVideoWriter_FFMPEG::close() ...@@ -1397,11 +1425,11 @@ void CvVideoWriter_FFMPEG::close()
av_write_trailer(oc); av_write_trailer(oc);
// free pictures // free pictures
#if LIBAVFORMAT_BUILD > 4628 #if LIBAVFORMAT_BUILD > 4628
if( video_st->codec->pix_fmt != input_pix_fmt){ if( video_st->codec->pix_fmt != input_pix_fmt){
#else #else
if( video_st->codec.pix_fmt != input_pix_fmt){ if( video_st->codec.pix_fmt != input_pix_fmt){
#endif #endif
if(picture->data[0]) if(picture->data[0])
free(picture->data[0]); free(picture->data[0]);
picture->data[0] = 0; picture->data[0] = 0;
...@@ -1413,11 +1441,11 @@ void CvVideoWriter_FFMPEG::close() ...@@ -1413,11 +1441,11 @@ void CvVideoWriter_FFMPEG::close()
} }
/* close codec */ /* close codec */
#if LIBAVFORMAT_BUILD > 4628 #if LIBAVFORMAT_BUILD > 4628
avcodec_close(video_st->codec); avcodec_close(video_st->codec);
#else #else
avcodec_close(&(video_st->codec)); avcodec_close(&(video_st->codec));
#endif #endif
av_free(outbuf); av_free(outbuf);
...@@ -1430,13 +1458,15 @@ void CvVideoWriter_FFMPEG::close() ...@@ -1430,13 +1458,15 @@ void CvVideoWriter_FFMPEG::close()
if (!(fmt->flags & AVFMT_NOFILE)) { if (!(fmt->flags & AVFMT_NOFILE)) {
/* close the output file */ /* close the output file */
#if LIBAVCODEC_VERSION_INT >= ((51<<16)+(49<<8)+0) && LIBAVCODEC_VERSION_INT <= ((54<<16)+(5<<8)+0) #if LIBAVCODEC_VERSION_INT < ((52<<16)+(123<<8)+0)
url_fclose(oc->pb); #if LIBAVCODEC_VERSION_INT >= ((51<<16)+(49<<8)+0)
#else url_fclose(oc->pb);
#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0) #else
url_fclose(&oc->pb); url_fclose(&oc->pb);
#endif #endif
#endif #else
avio_close(oc->pb);
#endif
} }
...@@ -1471,11 +1501,11 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, ...@@ -1471,11 +1501,11 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc,
/* 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);
#else #else
fmt = guess_format(NULL, filename, NULL); fmt = guess_format(NULL, filename, NULL);
#endif #endif
if (!fmt) if (!fmt)
return false; return false;
...@@ -1489,21 +1519,21 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, ...@@ -1489,21 +1519,21 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc,
} }
/* Lookup codec_id for given fourcc */ /* Lookup codec_id for given fourcc */
#if LIBAVCODEC_VERSION_INT<((51<<16)+(49<<8)+0) #if LIBAVCODEC_VERSION_INT<((51<<16)+(49<<8)+0)
if( (codec_id = codec_get_bmp_id( fourcc )) == CODEC_ID_NONE ) if( (codec_id = codec_get_bmp_id( fourcc )) == CODEC_ID_NONE )
return false; return false;
#else #else
/* const struct AVCodecTag * tags[] = { codec_bmp_tags, NULL}; const struct AVCodecTag * tags[] = { codec_bmp_tags, NULL};
if( (codec_id = av_codec_get_id(tags, fourcc)) == CODEC_ID_NONE ) if( (codec_id = av_codec_get_id(tags, fourcc)) == CODEC_ID_NONE )
return false; */ return false;
#endif #endif
// alloc memory for context // alloc memory for context
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
oc = avformat_alloc_context(); oc = avformat_alloc_context();
#else #else
oc = av_alloc_format_context(); oc = av_alloc_format_context();
#endif #endif
assert (oc); assert (oc);
/* set file name */ /* set file name */
...@@ -1515,12 +1545,12 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, ...@@ -1515,12 +1545,12 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc,
// set a few optimal pixel formats for lossless codecs of interest.. // set a few optimal pixel formats for lossless codecs of interest..
switch (codec_id) { switch (codec_id) {
#if LIBAVCODEC_VERSION_INT>((50<<16)+(1<<8)+0) #if LIBAVCODEC_VERSION_INT>((50<<16)+(1<<8)+0)
case CODEC_ID_JPEGLS: case CODEC_ID_JPEGLS:
// BGR24 or GRAY8 depending on is_color... // BGR24 or GRAY8 depending on is_color...
codec_pix_fmt = input_pix_fmt; codec_pix_fmt = input_pix_fmt;
break; break;
#endif #endif
case CODEC_ID_HUFFYUV: case CODEC_ID_HUFFYUV:
codec_pix_fmt = PIX_FMT_YUV422P; codec_pix_fmt = PIX_FMT_YUV422P;
break; break;
...@@ -1546,19 +1576,20 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, ...@@ -1546,19 +1576,20 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc,
/* set the output parameters (must be done even if no /* set the output parameters (must be done even if no
parameters). */ parameters). */
#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0) #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
if (av_set_parameters(oc, NULL) < 0)
if (av_set_parameters(oc, NULL) < 0) { #else
if (avformat_write_header(oc, NULL) < 0)
#endif
{
return false; return false;
} }
#endif #if FF_API_DUMP_FORMAT
dump_format(oc, 0, filename, 1);
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) #else
av_dump_format(oc, 0, filename, 1); av_dump_format(oc, 0, filename, 1);
#else #endif
dump_format(oc, 0, filename, 1);
#endif
/* now that all the parameters are set, we can open the audio and /* now that all the parameters are set, we can open the audio and
video codecs and allocate the necessary encode buffers */ video codecs and allocate the necessary encode buffers */
...@@ -1569,11 +1600,11 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, ...@@ -1569,11 +1600,11 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc,
AVCodec *codec; AVCodec *codec;
AVCodecContext *c; AVCodecContext *c;
#if LIBAVFORMAT_BUILD > 4628 #if LIBAVFORMAT_BUILD > 4628
c = (video_st->codec); c = (video_st->codec);
#else #else
c = &(video_st->codec); c = &(video_st->codec);
#endif #endif
c->codec_tag = fourcc; c->codec_tag = fourcc;
/* find the video encoder */ /* find the video encoder */
...@@ -1621,105 +1652,97 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, ...@@ -1621,105 +1652,97 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc,
} }
/* open the output file, if needed */ /* open the output file, if needed */
#ifndef URL_RDONLY if (!(fmt->flags & AVFMT_NOFILE)) {
#define URL_RDONLY 1 #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
#endif if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0)
#ifndef URL_WRONLY #else
#define URL_WRONLY 2 if (avio_open(&oc->pb, filename, 1) < 0)
#endif #endif
#ifndef URL_RWONLY
#define URL_RWONLY (URL_RDONLY|URL_WRONLY)
#endif
if (!(fmt->flags & AVFMT_NOFILE))
{
#if LIBAVCODEC_VERSION_INT <= ((54<<16)+(5<<8)+0)
if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0)
{ {
return false; return false;
} }
#endif
} }
/* write the stream header, if any */ /* write the stream header, if any */
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
avformat_write_header(oc, NULL); avformat_write_header(oc, NULL);
#else
av_write_header( oc );
#endif
return true; return true;
} }
CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG( const char* filename, int fourcc, double fps,
int width, int height, int isColor ) CvCapture_FFMPEG* cvCreateFileCapture_FFMPEG( const char* filename )
{ {
CvVideoWriter_FFMPEG* writer = (CvVideoWriter_FFMPEG*)malloc(sizeof(*writer)); CvCapture_FFMPEG* capture = (CvCapture_FFMPEG*)malloc(sizeof(*capture));
writer->init(); capture->init();
if( writer->open( filename, fourcc, fps, width, height, isColor != 0 )) if( capture->open( filename ))
return writer; return capture;
writer->close(); capture->close();
free(writer); free(capture);
return 0; return 0;
} }
void cvReleaseVideoWriter_FFMPEG( CvVideoWriter_FFMPEG** writer ) void cvReleaseCapture_FFMPEG(CvCapture_FFMPEG** capture)
{ {
if( writer && *writer ) if( capture && *capture )
{ {
(*writer)->close(); (*capture)->close();
free(*writer); free(*capture);
*writer = 0; *capture = 0;
} }
} }
int cvSetCaptureProperty_FFMPEG(CvCapture_FFMPEG* capture, int prop_id, double value)
int cvWriteFrame_FFMPEG( CvVideoWriter_FFMPEG* writer,
const unsigned char* data, int step,
int width, int height, int cn, int origin)
{
return writer->writeFrame(data, step, width, height, cn, origin);
}
int cvSetCaptureProperty_FFMPEG_2(CvCapture_FFMPEG_2* capture, int prop_id, double value)
{ {
return capture->setProperty(prop_id, value); return capture->setProperty(prop_id, value);
} }
double cvGetCaptureProperty_FFMPEG_2(CvCapture_FFMPEG_2* capture, int prop_id) double cvGetCaptureProperty_FFMPEG(CvCapture_FFMPEG* capture, int prop_id)
{ {
return capture->getProperty(prop_id); return capture->getProperty(prop_id);
} }
int cvGrabFrame_FFMPEG_2(CvCapture_FFMPEG_2* capture) int cvGrabFrame_FFMPEG(CvCapture_FFMPEG* capture)
{ {
return capture->grabFrame(); return capture->grabFrame();
} }
int cvRetrieveFrame_FFMPEG_2(CvCapture_FFMPEG_2* capture, unsigned char** data, int* step, int* width, int* height, int* cn) int cvRetrieveFrame_FFMPEG(CvCapture_FFMPEG* capture, unsigned char** data, int* step, int* width, int* height, int* cn)
{ {
return capture->retrieveFrame(0, data, step, width, height, cn); return capture->retrieveFrame(0, data, step, width, height, cn);
} }
CvCapture_FFMPEG_2* cvCreateFileCapture_FFMPEG_2( const char* filename )
CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG( const char* filename, int fourcc, double fps,
int width, int height, int isColor )
{ {
CvCapture_FFMPEG_2* capture = (CvCapture_FFMPEG_2*)malloc(sizeof(*capture)); CvVideoWriter_FFMPEG* writer = (CvVideoWriter_FFMPEG*)malloc(sizeof(*writer));
capture->init(); writer->init();
if( capture->open( filename )) if( writer->open( filename, fourcc, fps, width, height, isColor != 0 ))
return capture; return writer;
capture->close(); writer->close();
free(capture); free(writer);
return 0; return 0;
} }
void cvReleaseCapture_FFMPEG_2(CvCapture_FFMPEG_2** capture)
void cvReleaseVideoWriter_FFMPEG( CvVideoWriter_FFMPEG** writer )
{ {
if( capture && *capture ) if( writer && *writer )
{ {
(*capture)->close(); (*writer)->close();
free(*capture); free(*writer);
*capture = 0; *writer = 0;
} }
} }
int cvWriteFrame_FFMPEG( CvVideoWriter_FFMPEG* writer,
const unsigned char* data, int step,
int width, int height, int cn, int origin)
{
return writer->writeFrame(data, step, width, height, cn, origin);
}
...@@ -74,17 +74,17 @@ icvInitFFMPEG(void) ...@@ -74,17 +74,17 @@ icvInitFFMPEG(void)
if( icvFFOpenCV ) if( icvFFOpenCV )
{ {
icvCreateFileCapture_FFMPEG_p = icvCreateFileCapture_FFMPEG_p =
(CvCreateFileCapture_Plugin)GetProcAddress(icvFFOpenCV, "cvCreateFileCapture_FFMPEG_2"); (CvCreateFileCapture_Plugin)GetProcAddress(icvFFOpenCV, "cvCreateFileCapture_FFMPEG");
icvReleaseCapture_FFMPEG_p = icvReleaseCapture_FFMPEG_p =
(CvReleaseCapture_Plugin)GetProcAddress(icvFFOpenCV, "cvReleaseCapture_FFMPEG_2"); (CvReleaseCapture_Plugin)GetProcAddress(icvFFOpenCV, "cvReleaseCapture_FFMPEG");
icvGrabFrame_FFMPEG_p = icvGrabFrame_FFMPEG_p =
(CvGrabFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvGrabFrame_FFMPEG_2"); (CvGrabFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvGrabFrame_FFMPEG");
icvRetrieveFrame_FFMPEG_p = icvRetrieveFrame_FFMPEG_p =
(CvRetrieveFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvRetrieveFrame_FFMPEG_2"); (CvRetrieveFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvRetrieveFrame_FFMPEG");
icvSetCaptureProperty_FFMPEG_p = icvSetCaptureProperty_FFMPEG_p =
(CvSetCaptureProperty_Plugin)GetProcAddress(icvFFOpenCV, "cvSetCaptureProperty_FFMPEG_2"); (CvSetCaptureProperty_Plugin)GetProcAddress(icvFFOpenCV, "cvSetCaptureProperty_FFMPEG");
icvGetCaptureProperty_FFMPEG_p = icvGetCaptureProperty_FFMPEG_p =
(CvGetCaptureProperty_Plugin)GetProcAddress(icvFFOpenCV, "cvGetCaptureProperty_FFMPEG_2"); (CvGetCaptureProperty_Plugin)GetProcAddress(icvFFOpenCV, "cvGetCaptureProperty_FFMPEG");
icvCreateVideoWriter_FFMPEG_p = icvCreateVideoWriter_FFMPEG_p =
(CvCreateVideoWriter_Plugin)GetProcAddress(icvFFOpenCV, "cvCreateVideoWriter_FFMPEG"); (CvCreateVideoWriter_Plugin)GetProcAddress(icvFFOpenCV, "cvCreateVideoWriter_FFMPEG");
icvReleaseVideoWriter_FFMPEG_p = icvReleaseVideoWriter_FFMPEG_p =
...@@ -112,12 +112,12 @@ icvInitFFMPEG(void) ...@@ -112,12 +112,12 @@ icvInitFFMPEG(void)
#endif #endif
} }
#elif defined HAVE_FFMPEG #elif defined HAVE_FFMPEG
icvCreateFileCapture_FFMPEG_p = (CvCreateFileCapture_Plugin)cvCreateFileCapture_FFMPEG_2; icvCreateFileCapture_FFMPEG_p = (CvCreateFileCapture_Plugin)cvCreateFileCapture_FFMPEG;
icvReleaseCapture_FFMPEG_p = (CvReleaseCapture_Plugin)cvReleaseCapture_FFMPEG_2; icvReleaseCapture_FFMPEG_p = (CvReleaseCapture_Plugin)cvReleaseCapture_FFMPEG;
icvGrabFrame_FFMPEG_p = (CvGrabFrame_Plugin)cvGrabFrame_FFMPEG_2; icvGrabFrame_FFMPEG_p = (CvGrabFrame_Plugin)cvGrabFrame_FFMPEG;
icvRetrieveFrame_FFMPEG_p = (CvRetrieveFrame_Plugin)cvRetrieveFrame_FFMPEG_2; icvRetrieveFrame_FFMPEG_p = (CvRetrieveFrame_Plugin)cvRetrieveFrame_FFMPEG;
icvSetCaptureProperty_FFMPEG_p = (CvSetCaptureProperty_Plugin)cvSetCaptureProperty_FFMPEG_2; icvSetCaptureProperty_FFMPEG_p = (CvSetCaptureProperty_Plugin)cvSetCaptureProperty_FFMPEG;
icvGetCaptureProperty_FFMPEG_p = (CvGetCaptureProperty_Plugin)cvGetCaptureProperty_FFMPEG_2; icvGetCaptureProperty_FFMPEG_p = (CvGetCaptureProperty_Plugin)cvGetCaptureProperty_FFMPEG;
icvCreateVideoWriter_FFMPEG_p = (CvCreateVideoWriter_Plugin)cvCreateVideoWriter_FFMPEG; icvCreateVideoWriter_FFMPEG_p = (CvCreateVideoWriter_Plugin)cvCreateVideoWriter_FFMPEG;
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;
...@@ -152,7 +152,7 @@ public: ...@@ -152,7 +152,7 @@ public:
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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment