提交 e0b772a3 编写于 作者: A Alexander Reshetnikov

Added a first version of new ffmpeg wrapper

上级 191e9692
......@@ -385,6 +385,7 @@ if(UNIX)
set(HAVE_FFMPEG 1)
endif()
endif()
# Find the bzip2 library because it is required on some systems
FIND_LIBRARY(BZIP2_LIBRARIES NAMES bz2 bzip2)
if(NOT BZIP2_LIBRARIES)
......@@ -393,6 +394,10 @@ if(UNIX)
endif()
endif()
if(HAVE_FFMPEG)
CHECK_MODULE(libavformat>=53 NEW_FFMPEG)
endif()
if(WITH_1394)
CHECK_MODULE(libdc1394-2 HAVE_DC1394_2)
if(NOT HAVE_DC1394_2)
......
......@@ -53,6 +53,18 @@ set(grfmt_srcs src/bitstrm.cpp ${grfmt_srcs})
source_group("Src\\grfmts" FILES ${grfmt_hdrs} ${grfmt_srcs})
set(highgui_hdrs src/precomp.hpp src/utils.hpp)
if(NEW_FFMPEG)
set(highgui_srcs
src/cap.cpp
src/cap_images.cpp
src/cap_ffmpeg_v2.cpp
src/loadsave.cpp
src/precomp.cpp
src/utils.cpp
src/window.cpp
)
else()
set(highgui_srcs
src/cap.cpp
src/cap_images.cpp
......@@ -62,6 +74,8 @@ set(highgui_srcs
src/utils.cpp
src/window.cpp
)
endif()
file(GLOB highgui_ext_hdrs "include/opencv2/${name}/*.hpp" "include/opencv2/${name}/*.h")
#YV
......
......@@ -26,16 +26,25 @@ enum
OPENCV_FFMPEG_API struct CvCapture_FFMPEG* cvCreateFileCapture_FFMPEG(const char* filename);
OPENCV_FFMPEG_API struct CvCapture_FFMPEG_2* cvCreateFileCapture_FFMPEG_2(const char* filename);
OPENCV_FFMPEG_API int cvSetCaptureProperty_FFMPEG(struct CvCapture_FFMPEG* cap,
int prop, double value);
OPENCV_FFMPEG_API int cvSetCaptureProperty_FFMPEG_2(struct CvCapture_FFMPEG_2* cap,
int prop, double value);
OPENCV_FFMPEG_API double cvGetCaptureProperty_FFMPEG(struct CvCapture_FFMPEG* cap, int prop);
OPENCV_FFMPEG_API double cvGetCaptureProperty_FFMPEG_2(struct CvCapture_FFMPEG_2* cap, int prop);
OPENCV_FFMPEG_API int cvGrabFrame_FFMPEG(struct CvCapture_FFMPEG* cap);
OPENCV_FFMPEG_API int cvRetrieveFrame_FFMPEG(CvCapture_FFMPEG* capture, unsigned char** data,
OPENCV_FFMPEG_API int cvGrabFrame_FFMPEG_2(struct CvCapture_FFMPEG_2* cap);
OPENCV_FFMPEG_API int cvRetrieveFrame_FFMPEG(struct CvCapture_FFMPEG* capture, unsigned char** data,
int* step, int* width, int* height, int* cn);
OPENCV_FFMPEG_API int cvRetrieveFrame_FFMPEG_2(struct CvCapture_FFMPEG_2* capture, unsigned char** data,
int* step, int* width, int* height, int* cn);
OPENCV_FFMPEG_API void cvReleaseCapture_FFMPEG(struct CvCapture_FFMPEG** cap);
OPENCV_FFMPEG_API void cvReleaseCapture_FFMPEG_2(struct CvCapture_FFMPEG_2** cap);
OPENCV_FFMPEG_API struct CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG(const char* filename,
int fourcc, double fps, int width, int height, int isColor );
OPENCV_FFMPEG_API struct CvVideoWriter_FFMPEG_2* cvCreateVideoWriter_FFMPEG_2(const char* filename,
int fourcc, double fps, int width, int height, int isColor );
OPENCV_FFMPEG_API int cvWriteFrame_FFMPEG(struct CvVideoWriter_FFMPEG* writer, const unsigned char* data,
int step, int width, int height, int cn, int origin);
......
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// Intel License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifdef __cplusplus
extern "C" {
#endif
#undef UINT64_C
#define UINT64_C(val) val ## LL
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#ifdef __cplusplus
}
#endif
#include "cap_ffmpeg_api.hpp"
#include "assert.h"
#define CALC_FFMPEG_VERSION(a,b,c) ( a<<16 | b<<8 | c )
struct Image_FFMPEG
{
unsigned char* data;
int step;
int width;
int height;
int cn;
};
struct CvCapture_FFMPEG_2
{
CvCapture_FFMPEG_2(const char* filename);
CvCapture_FFMPEG_2(const CvCapture_FFMPEG_2& mf);
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;
int video_stream;
int64_t picture_pts;
size_t width, height;
int64_t frame_number;
double eps_zero;
double get_duration_sec();
double get_fps();
int get_bitrate();
double r2d(AVRational r);
int64_t dts_to_frame_number(int64_t dts);
double dts_to_sec(int64_t dts);
};
CvCapture_FFMPEG_2::CvCapture_FFMPEG_2(const char* filename) :
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();
avformat_network_init();
// Open video file
avformat_open_input(&ic, filename, NULL, NULL);
// Find the first video stream
for(int i = 0; i < static_cast<int>(ic->nb_streams); i++)
{
struct AVCodecContext * cc = ic->streams[i]->codec;
// set number of threads
cc->thread_count = 2;
if(cc->codec_type == AVMEDIA_TYPE_VIDEO && video_stream == -1)
{
AVCodec * codec = avcodec_find_decoder(cc->codec_id);
if (codec == NULL)
CV_Error(0, "Unsupported codec !!!");
avcodec_open2(cc, codec, NULL);
video_stream = i;
break;
}
}
if(video_stream == -1)
CV_Error(0, "Didn't find a video stream");
// Get a pointer to the codec context for the video stream
avcodec_context = ic->streams[video_stream]->codec;
// Allocate video frame
picture = avcodec_alloc_frame();
}
CvCapture_FFMPEG_2::CvCapture_FFMPEG_2(const CvCapture_FFMPEG_2& vr) :
ic(vr.ic),
avcodec_context (vr.avcodec_context),
avcodec(0),
picture(0),
rgb_picture(0),
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)
{
CvCapture_FFMPEG_2 cap(filename);
*this = cap;
}
void CvCapture_FFMPEG_2::close()
{
if( picture )
av_free(picture);
if( video_st )
{
#if LIBAVFORMAT_BUILD > 4628
avcodec_close( video_st->codec );
#else
avcodec_close( &video_st->codec );
#endif
video_st = NULL;
}
if( ic )
{
av_close_input_file(ic);
ic = NULL;
}
if( rgb_picture->data[0] )
{
free( rgb_picture->data[0] );
rgb_picture->data[0] = 0;
}
// free last packet if exist
if (packet.data) {
av_free_packet (&packet);
}
init();
}
bool CvCapture_FFMPEG_2::grabFrame()
{
bool valid = false;
static bool bFirstTime = true;
int got_picture;
// First time we're called, set packet.data to NULL to indicate it
// doesn't have to be freed
if (bFirstTime) {
bFirstTime = false;
packet.data = NULL;
}
if( !ic || !video_st )
return false;
// free last packet if exist
if (packet.data != NULL) {
av_free_packet (&packet);
}
// get the next frame
while (!valid) {
int ret = av_read_frame(ic, &packet);
if (ret == AVERROR(EAGAIN))
continue;
if (ret < 0)
break;
if( packet.stream_index != video_stream ) {
av_free_packet (&packet);
continue;
}
avcodec_decode_video2(video_st->codec, picture, &got_picture, &packet);
if (got_picture) {
// we have a new picture, so memorize it
picture_pts = packet.pts;
valid = 1;
}
}
// return if we have a new picture or not
return valid;
}
bool CvCapture_FFMPEG_2::retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn)
{
if( !video_st || !picture->data[0] )
return false;
#if !defined(HAVE_FFMPEG_SWSCALE)
#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;
}
void CvCapture_FFMPEG_2::init()
{
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()
{
if ( filename==NULL ) return false;
#if LIBAVFORMAT_BUILD > 4628
avcodec_close( video_st->codec );
#else
avcodec_close( &video_st->codec );
#endif
av_close_input_file(ic);
// reopen video
#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(52, 111, 0)
av_open_input_file(&ic, filename, NULL, 0, NULL);
#else
avformat_open_input(&ic, filename, NULL, NULL);
#endif
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
#if FF_API_THREAD_INIT
avcodec_thread_init(enc, std::min(get_number_of_cpus(), 16));
#endif
AVCodec *codec = avcodec_find_decoder(enc->codec_id);
avcodec_open(enc, codec);
video_st = ic->streams[video_stream];
// reset framenumber to zero
picture_pts=0;
return true;
}
int64_t CvCapture_FFMPEG_2::get_frame_number()
{
return frame_number;
}
cv::Mat CvCapture_FFMPEG_2::read()
{
int frame_finished = 0;
AVPacket packet;
int count_errs = 0;
const int max_number_of_attempts = 32;
while(true)
{
av_read_frame(ic, &packet);
if(packet.stream_index == video_stream)
{
// Decode video frame
avcodec_decode_video2(avcodec_context, picture, &frame_finished, &packet);
// Did we get a video frame?
if(frame_finished)
{
rgb_picture = avcodec_alloc_frame();
cv::Mat img(static_cast<int>(avcodec_context->height), static_cast<int>(avcodec_context->width), CV_8UC3);
uint8_t * buffer = reinterpret_cast<uint8_t *>(img.ptr(0));
avpicture_fill(reinterpret_cast<AVPicture*>(rgb_picture), buffer, PIX_FMT_RGB24, avcodec_context->width, avcodec_context->height);
width = picture->width;
height = picture->height;
struct SwsContext * img_convert_ctx = sws_getContext(
width, height,
avcodec_context->pix_fmt,
width, height,
PIX_FMT_BGR24,
SWS_BICUBIC,
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
av_free_packet(&packet);
return cv::Mat();
}
double CvCapture_FFMPEG_2::r2d(AVRational r)
{
if (r.num == 0 || r.den == 0)
{
return 0.0;
}
else
{
return static_cast<double>(r.num) / static_cast<double>(r.den);
}
}
double CvCapture_FFMPEG_2::get_duration_sec()
{
double sec = static_cast<double>(ic->duration) / static_cast<double>(AV_TIME_BASE);
if (sec < eps_zero)
{
sec = static_cast<double>(ic->streams[video_stream]->duration) * r2d(ic->streams[video_stream]->time_base);
}
if (sec < eps_zero)
{
sec = static_cast<double>(static_cast<int64_t>(ic->streams[video_stream]->duration)) * r2d(ic->streams[video_stream]->time_base);
}
return sec;
}
int CvCapture_FFMPEG_2::get_bitrate()
{
return ic->bit_rate;
}
double CvCapture_FFMPEG_2::get_fps()
{
double fps = r2d(ic->streams[video_stream]->r_frame_rate);
if (fps < eps_zero)
{
fps = r2d(ic->streams[video_stream]->avg_frame_rate);
}
// may be this is wrong
if (fps < eps_zero)
{
fps = 1.0 / r2d(ic->streams[video_stream]->codec->time_base);
}
return fps;
}
int64_t CvCapture_FFMPEG_2::get_total_frames()
{
int64_t nbf = ic->streams[video_stream]->nb_frames;
if (nbf == 0)
{
nbf = static_cast<int64_t>(get_duration_sec() * get_fps());
}
return nbf;
}
//#include <iostream>
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);
return static_cast<int64_t>(get_fps() * sec);
}
double CvCapture_FFMPEG_2::dts_to_sec(int64_t dts)
{
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)
{
double sec = static_cast<double>(frame_number) / static_cast<double>(get_fps());
this->frame_number = std::min<int>(frame_number, get_total_frames());
seek(sec);
/* int64_t dts = dts_to_frame_number(ic->streams[video_stream]->cur_dts);
if (abs(dts - 2 - frame_number) > 16)
{
double sec = static_cast<double>(frame_number) / static_cast<double>(get_fps());
int64_t time_stamp = ic->streams[video_stream]->start_time;
double time_base = r2d(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);
}
while(dts - 2 < frame_number)
{
cv::Mat i = read();
if (i.empty())
break;
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)
{
// 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()
{
avformat_close_input(&ic);
}
bool CvCapture_FFMPEG_2::setProperty( int property_id, double value )
{
if (!video_stream) return false;
switch( property_id )
{
case CV_FFMPEG_CAP_PROP_POS_MSEC:
case CV_FFMPEG_CAP_PROP_POS_FRAMES:
case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO:
{
switch( property_id )
{
case CV_FFMPEG_CAP_PROP_POS_FRAMES:
seek(value/1000.0); break;
break;
case CV_FFMPEG_CAP_PROP_POS_MSEC:
seek(value);
break;
case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO:
seek(value*this->get_bitrate());
break;
}
/* if ( filename )
{
// 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;
default:
return false;
}
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 //////////////////////////
struct CvVideoWriter_FFMPEG
{
bool open( const char* filename, int fourcc,
double fps, int width, int height, bool isColor );
void close();
bool writeFrame( const unsigned char* data, int step, int width, int height, int cn, int origin );
void init();
AVOutputFormat *fmt;
AVFormatContext *oc;
uint8_t * outbuf;
uint32_t outbuf_size;
FILE * outfile;
AVFrame * picture;
AVFrame * input_picture;
uint8_t * picbuf;
AVStream * video_st;
int input_pix_fmt;
Image_FFMPEG temp_image;
#if defined(HAVE_FFMPEG_SWSCALE)
struct SwsContext *img_convert_ctx;
#endif
};
static const char * icvFFMPEGErrStr(int err)
{
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
switch(err) {
case AVERROR_BSF_NOT_FOUND:
return "Bitstream filter not found";
case AVERROR_DECODER_NOT_FOUND:
return "Decoder not found";
case AVERROR_DEMUXER_NOT_FOUND:
return "Demuxer not found";
case AVERROR_ENCODER_NOT_FOUND:
return "Encoder not found";
case AVERROR_EOF:
return "End of file";
case AVERROR_EXIT:
return "Immediate exit was requested; the called function should not be restarted";
case AVERROR_FILTER_NOT_FOUND:
return "Filter not found";
case AVERROR_INVALIDDATA:
return "Invalid data found when processing input";
case AVERROR_MUXER_NOT_FOUND:
return "Muxer not found";
case AVERROR_OPTION_NOT_FOUND:
return "Option not found";
case AVERROR_PATCHWELCOME:
return "Not yet implemented in FFmpeg, patches welcome";
case AVERROR_PROTOCOL_NOT_FOUND:
return "Protocol not found";
case AVERROR_STREAM_NOT_FOUND:
return "Stream not found";
default:
break;
}
#else
switch(err) {
case AVERROR_NUMEXPECTED:
return "Incorrect filename syntax";
case AVERROR_INVALIDDATA:
return "Invalid data in header";
case AVERROR_NOFMT:
return "Unknown format";
case AVERROR_IO:
return "I/O error occurred";
case AVERROR_NOMEM:
return "Memory allocation error";
default:
break;
}
#endif
return "Unspecified error";
}
/* function internal to FFMPEG (libavformat/riff.c) to lookup codec id by fourcc tag*/
extern "C" {
enum CodecID codec_get_bmp_id(unsigned int tag);
}
void CvVideoWriter_FFMPEG::init()
{
fmt = 0;
oc = 0;
outbuf = 0;
outbuf_size = 0;
outfile = 0;
picture = 0;
input_picture = 0;
picbuf = 0;
video_st = 0;
input_pix_fmt = 0;
memset(&temp_image, 0, sizeof(temp_image));
#if defined(HAVE_FFMPEG_SWSCALE)
img_convert_ctx = 0;
#endif
}
/**
* the following function is a modified version of code
* found in ffmpeg-0.4.9-pre1/output_example.c
*/
static AVFrame * icv_alloc_picture_FFMPEG(int pix_fmt, int width, int height, bool alloc)
{
AVFrame * picture;
uint8_t * picture_buf;
int size;
picture = avcodec_alloc_frame();
if (!picture)
return NULL;
size = avpicture_get_size( (PixelFormat) pix_fmt, width, height);
if(alloc){
picture_buf = (uint8_t *) malloc(size);
if (!picture_buf)
{
av_free(picture);
return NULL;
}
avpicture_fill((AVPicture *)picture, picture_buf,
(PixelFormat) pix_fmt, width, height);
}
else {
}
return picture;
}
/* add a video output stream to the container */
static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc,
CodecID codec_id,
int w, int h, int bitrate,
double fps, int pixel_format)
{
AVCodecContext *c;
AVStream *st;
int frame_rate, frame_rate_base;
AVCodec *codec;
st = av_new_stream(oc, 0);
if (!st) {
/* CV_WARN("Could not allocate stream"); */
return NULL;
}
#if LIBAVFORMAT_BUILD > 4628
c = st->codec;
#else
c = &(st->codec);
#endif
#if LIBAVFORMAT_BUILD > 4621
c->codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, AVMEDIA_TYPE_VIDEO);
#else
c->codec_id = oc->oformat->video_codec;
#endif
if(codec_id != CODEC_ID_NONE){
c->codec_id = codec_id;
}
//if(codec_tag) c->codec_tag=codec_tag;
codec = avcodec_find_encoder(c->codec_id);
c->codec_type = AVMEDIA_TYPE_VIDEO;
/* put sample parameters */
c->bit_rate = bitrate;
/* resolution must be a multiple of two */
c->width = w;
c->height = h;
/* time base: this is the fundamental unit of time (in seconds) in terms
of which frame timestamps are represented. for fixed-fps content,
timebase should be 1/framerate and timestamp increments should be
identically 1. */
frame_rate=(int)(fps+0.5);
frame_rate_base=1;
while (fabs((double)frame_rate/frame_rate_base) - fps > 0.001){
frame_rate_base*=10;
frame_rate=(int)(fps*frame_rate_base + 0.5);
}
#if LIBAVFORMAT_BUILD > 4752
c->time_base.den = frame_rate;
c->time_base.num = frame_rate_base;
/* adjust time base for supported framerates */
if(codec && codec->supported_framerates){
const AVRational *p= codec->supported_framerates;
AVRational req = {frame_rate, frame_rate_base};
const AVRational *best=NULL;
AVRational best_error= {INT_MAX, 1};
for(; p->den!=0; p++){
AVRational error= av_sub_q(req, *p);
if(error.num <0) error.num *= -1;
if(av_cmp_q(error, best_error) < 0){
best_error= error;
best= p;
}
}
c->time_base.den= best->num;
c->time_base.num= best->den;
}
#else
c->frame_rate = frame_rate;
c->frame_rate_base = frame_rate_base;
#endif
c->gop_size = 12; /* emit one intra frame every twelve frames at most */
c->pix_fmt = (PixelFormat) pixel_format;
if (c->codec_id == CODEC_ID_MPEG2VIDEO) {
c->max_b_frames = 2;
}
if (c->codec_id == CODEC_ID_MPEG1VIDEO || c->codec_id == CODEC_ID_MSMPEG4V3){
/* needed to avoid using macroblocks in which some coeffs overflow
this doesnt happen with normal video, it just happens here as the
motion of the chroma plane doesnt match the luma plane */
/* avoid FFMPEG warning 'clipping 1 dct coefficients...' */
c->mb_decision=2;
}
#if LIBAVCODEC_VERSION_INT>0x000409
// some formats want stream headers to be seperate
if(oc->oformat->flags & AVFMT_GLOBALHEADER)
{
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
#endif
return st;
}
int icv_av_write_frame_FFMPEG( AVFormatContext * oc, AVStream * video_st, uint8_t * outbuf, uint32_t outbuf_size, AVFrame * picture )
{
#if LIBAVFORMAT_BUILD > 4628
AVCodecContext * c = video_st->codec;
#else
AVCodecContext * c = &(video_st->codec);
#endif
int out_size;
int ret;
if (oc->oformat->flags & AVFMT_RAWPICTURE) {
/* raw video case. The API will change slightly in the near
futur for that */
AVPacket pkt;
av_init_packet(&pkt);
#ifndef PKT_FLAG_KEY
#define PKT_FLAG_KEY AV_PKT_FLAG_KEY
#endif
pkt.flags |= PKT_FLAG_KEY;
pkt.stream_index= video_st->index;
pkt.data= (uint8_t *)picture;
pkt.size= sizeof(AVPicture);
ret = av_write_frame(oc, &pkt);
} else {
/* encode the image */
out_size = avcodec_encode_video(c, outbuf, outbuf_size, picture);
/* if zero size, it means the image was buffered */
if (out_size > 0) {
AVPacket pkt;
av_init_packet(&pkt);
#if LIBAVFORMAT_BUILD > 4752
pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, video_st->time_base);
#else
pkt.pts = c->coded_frame->pts;
#endif
if(c->coded_frame->key_frame)
pkt.flags |= PKT_FLAG_KEY;
pkt.stream_index= video_st->index;
pkt.data= outbuf;
pkt.size= out_size;
/* write the compressed frame in the media file */
ret = av_write_frame(oc, &pkt);
} else {
ret = 0;
}
}
if (ret != 0) return -1;
return 0;
}
/// write a frame with FFMPEG
bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int width, int height, int cn, int origin )
{
bool ret = false;
// typecast from opaque data type to implemented struct
#if LIBAVFORMAT_BUILD > 4628
AVCodecContext *c = video_st->codec;
#else
AVCodecContext *c = &(video_st->codec);
#endif
#if LIBAVFORMAT_BUILD < 5231
// It is not needed in the latest versions of the ffmpeg
if( c->codec_id == CODEC_ID_RAWVIDEO && origin != 1 )
{
if( !temp_image.data )
{
temp_image.step = (width*cn + 3) & -4;
temp_image.width = width;
temp_image.height = height;
temp_image.cn = cn;
temp_image.data = (unsigned char*)malloc(temp_image.step*temp_image.height);
}
for( int y = 0; y < height; y++ )
memcpy(temp_image.data + y*temp_image.step, data + (height-1-y)*step, width*cn);
data = temp_image.data;
step = temp_image.step;
}
#else
if( width*cn != step )
{
if( !temp_image.data )
{
temp_image.step = width*cn;
temp_image.width = width;
temp_image.height = height;
temp_image.cn = cn;
temp_image.data = (unsigned char*)malloc(temp_image.step*temp_image.height);
}
if (origin == 1)
for( int y = 0; y < height; y++ )
memcpy(temp_image.data + y*temp_image.step, data + (height-1-y)*step, temp_image.step);
else
for( int y = 0; y < height; y++ )
memcpy(temp_image.data + y*temp_image.step, data + y*step, temp_image.step);
data = temp_image.data;
step = temp_image.step;
}
#endif
// check parameters
if (input_pix_fmt == PIX_FMT_BGR24) {
if (cn != 3) {
return false;
}
}
else if (input_pix_fmt == PIX_FMT_GRAY8) {
if (cn != 1) {
return false;
}
}
else {
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 ) {
assert( input_picture );
// let input_picture point to the raw data buffer of 'image'
avpicture_fill((AVPicture *)input_picture, (uint8_t *) data,
(PixelFormat)input_pix_fmt, width, height);
#if !defined(HAVE_FFMPEG_SWSCALE)
// convert to the color format needed by the codec
if( img_convert((AVPicture *)picture, c->pix_fmt,
(AVPicture *)input_picture, (PixelFormat)input_pix_fmt,
width, height) < 0){
return false;
}
#else
img_convert_ctx = sws_getContext(width,
height,
(PixelFormat)input_pix_fmt,
c->width,
c->height,
c->pix_fmt,
SWS_BICUBIC,
NULL, NULL, NULL);
if ( sws_scale(img_convert_ctx, input_picture->data,
input_picture->linesize, 0,
height,
picture->data, picture->linesize) < 0 )
{
return false;
}
sws_freeContext(img_convert_ctx);
#endif
}
else{
avpicture_fill((AVPicture *)picture, (uint8_t *) data,
(PixelFormat)input_pix_fmt, width, height);
}
ret = icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, picture) >= 0;
return ret;
}
/// close video output stream and free associated memory
void CvVideoWriter_FFMPEG::close()
{
unsigned i;
// nothing to do if already released
if ( !picture )
return;
/* no more frame to compress. The codec has a latency of a few
frames if using B frames, so we get the last frames by
passing the same picture again */
// TODO -- do we need to account for latency here?
/* write the trailer, if any */
av_write_trailer(oc);
// free pictures
#if LIBAVFORMAT_BUILD > 4628
if( video_st->codec->pix_fmt != input_pix_fmt){
#else
if( video_st->codec.pix_fmt != input_pix_fmt){
#endif
if(picture->data[0])
free(picture->data[0]);
picture->data[0] = 0;
}
av_free(picture);
if (input_picture) {
av_free(input_picture);
}
/* close codec */
#if LIBAVFORMAT_BUILD > 4628
avcodec_close(video_st->codec);
#else
avcodec_close(&(video_st->codec));
#endif
av_free(outbuf);
/* free the streams */
for(i = 0; i < oc->nb_streams; i++) {
av_freep(&oc->streams[i]->codec);
av_freep(&oc->streams[i]);
}
if (!(fmt->flags & AVFMT_NOFILE)) {
/* close the output file */
#if LIBAVCODEC_VERSION_INT >= ((51<<16)+(49<<8)+0) && LIBAVCODEC_VERSION_INT <= ((54<<16)+(5<<8)+0)
url_fclose(oc->pb);
#else
#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
url_fclose(&oc->pb);
#endif
#endif
}
/* free the stream */
av_free(oc);
if( temp_image.data )
{
free(temp_image.data);
temp_image.data = 0;
}
init();
}
/// Create a video writer object that uses FFMPEG
bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc,
double fps, int width, int height, bool is_color )
{
CodecID codec_id = CODEC_ID_NONE;
int err, codec_pix_fmt, bitrate_scale=64;
close();
// check arguments
assert (filename);
assert (fps > 0);
assert (width > 0 && height > 0);
// tell FFMPEG to register codecs
av_register_all ();
/* 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);
#else
fmt = guess_format(NULL, filename, NULL);
#endif
if (!fmt)
return false;
/* determine optimal pixel format */
if (is_color) {
input_pix_fmt = PIX_FMT_BGR24;
}
else {
input_pix_fmt = PIX_FMT_GRAY8;
}
/* Lookup codec_id for given fourcc */
#if LIBAVCODEC_VERSION_INT<((51<<16)+(49<<8)+0)
if( (codec_id = codec_get_bmp_id( fourcc )) == CODEC_ID_NONE )
return false;
#else
/* const struct AVCodecTag * tags[] = { codec_bmp_tags, NULL};
if( (codec_id = av_codec_get_id(tags, fourcc)) == CODEC_ID_NONE )
return false; */
#endif
// alloc memory for context
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
oc = avformat_alloc_context();
#else
oc = av_alloc_format_context();
#endif
assert (oc);
/* set file name */
oc->oformat = fmt;
snprintf(oc->filename, sizeof(oc->filename), "%s", filename);
/* set some options */
oc->max_delay = (int)(0.7*AV_TIME_BASE); /* This reduces buffer underrun warnings with MPEG */
// set a few optimal pixel formats for lossless codecs of interest..
switch (codec_id) {
#if LIBAVCODEC_VERSION_INT>((50<<16)+(1<<8)+0)
case CODEC_ID_JPEGLS:
// BGR24 or GRAY8 depending on is_color...
codec_pix_fmt = input_pix_fmt;
break;
#endif
case CODEC_ID_HUFFYUV:
codec_pix_fmt = PIX_FMT_YUV422P;
break;
case CODEC_ID_MJPEG:
case CODEC_ID_LJPEG:
codec_pix_fmt = PIX_FMT_YUVJ420P;
bitrate_scale = 128;
break;
case CODEC_ID_RAWVIDEO:
codec_pix_fmt = input_pix_fmt;
break;
default:
// good for lossy formats, MPEG, etc.
codec_pix_fmt = PIX_FMT_YUV420P;
break;
}
// TODO -- safe to ignore output audio stream?
video_st = icv_add_video_stream_FFMPEG(oc, codec_id,
width, height, width*height*bitrate_scale,
fps, codec_pix_fmt);
/* set the output parameters (must be done even if no
parameters). */
#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
if (av_set_parameters(oc, NULL) < 0) {
return false;
}
#endif
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
av_dump_format(oc, 0, filename, 1);
#else
dump_format(oc, 0, filename, 1);
#endif
/* now that all the parameters are set, we can open the audio and
video codecs and allocate the necessary encode buffers */
if (!video_st){
return false;
}
AVCodec *codec;
AVCodecContext *c;
#if LIBAVFORMAT_BUILD > 4628
c = (video_st->codec);
#else
c = &(video_st->codec);
#endif
c->codec_tag = fourcc;
/* find the video encoder */
codec = avcodec_find_encoder(c->codec_id);
if (!codec) {
return false;
}
c->bit_rate_tolerance = c->bit_rate;
/* open the codec */
if ( (err=avcodec_open(c, codec)) < 0) {
char errtext[256];
sprintf(errtext, "Could not open codec '%s': %s", codec->name, icvFFMPEGErrStr(err));
return false;
}
outbuf = NULL;
if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) {
/* allocate output buffer */
/* assume we will never get codec output with more than 4 bytes per pixel... */
outbuf_size = width*height*4;
outbuf = (uint8_t *) av_malloc(outbuf_size);
}
bool need_color_convert;
need_color_convert = (c->pix_fmt != input_pix_fmt);
/* allocate the encoded raw picture */
picture = icv_alloc_picture_FFMPEG(c->pix_fmt, c->width, c->height, need_color_convert);
if (!picture) {
return false;
}
/* if the output format is not our input format, then a temporary
picture of the input format is needed too. It is then converted
to the required output format */
input_picture = NULL;
if ( need_color_convert ) {
input_picture = icv_alloc_picture_FFMPEG(input_pix_fmt, c->width, c->height, false);
if (!input_picture) {
return false;
}
}
/* open the output file, if needed */
#ifndef URL_RDONLY
#define URL_RDONLY 1
#endif
#ifndef URL_WRONLY
#define URL_WRONLY 2
#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;
}
#endif
}
/* write the stream header, if any */
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
avformat_write_header(oc, NULL);
#else
av_write_header( oc );
#endif
return true;
}
CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG( const char* filename, int fourcc, double fps,
int width, int height, int isColor )
{
CvVideoWriter_FFMPEG* writer = (CvVideoWriter_FFMPEG*)malloc(sizeof(*writer));
writer->init();
if( writer->open( filename, fourcc, fps, width, height, isColor != 0 ))
return writer;
writer->close();
free(writer);
return 0;
}
void cvReleaseVideoWriter_FFMPEG( CvVideoWriter_FFMPEG** writer )
{
if( writer && *writer )
{
(*writer)->close();
free(*writer);
*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);
}
int cvSetCaptureProperty_FFMPEG_2(CvCapture_FFMPEG_2* capture, int prop_id, double value)
{
return capture->setProperty(prop_id, value);
}
double cvGetCaptureProperty_FFMPEG_2(CvCapture_FFMPEG_2* capture, int prop_id)
{
return capture->getProperty(prop_id);
}
int cvGrabFrame_FFMPEG_2(CvCapture_FFMPEG_2* capture)
{
return capture->grabFrame();
}
int cvRetrieveFrame_FFMPEG_2(CvCapture_FFMPEG_2* capture, unsigned char** data, int* step, int* width, int* height, int* cn)
{
return capture->retrieveFrame(0, data, step, width, height, cn);
}
CvCapture_FFMPEG_2* cvCreateFileCapture_FFMPEG_2( const char* filename )
{
CvCapture_FFMPEG_2* capture = (CvCapture_FFMPEG_2*)malloc(sizeof(*capture));
capture->init();
if( capture->open( filename ))
return capture;
capture->close();
free(capture);
return 0;
}
void cvReleaseCapture_FFMPEG_2(CvCapture_FFMPEG_2** capture)
{
if( capture && *capture )
{
(*capture)->close();
free(*capture);
*capture = 0;
}
}
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// Intel License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
#ifdef HAVE_FFMPEG
#include "cap_ffmpeg_impl_v2.hpp"
#else
#include "cap_ffmpeg_api.hpp"
#endif
static CvCreateFileCapture_Plugin icvCreateFileCapture_FFMPEG_p = 0;
static CvReleaseCapture_Plugin icvReleaseCapture_FFMPEG_p = 0;
static CvGrabFrame_Plugin icvGrabFrame_FFMPEG_p = 0;
static CvRetrieveFrame_Plugin icvRetrieveFrame_FFMPEG_p = 0;
static CvSetCaptureProperty_Plugin icvSetCaptureProperty_FFMPEG_p = 0;
static CvGetCaptureProperty_Plugin icvGetCaptureProperty_FFMPEG_p = 0;
static CvCreateVideoWriter_Plugin icvCreateVideoWriter_FFMPEG_p = 0;
static CvReleaseVideoWriter_Plugin icvReleaseVideoWriter_FFMPEG_p = 0;
static CvWriteFrame_Plugin icvWriteFrame_FFMPEG_p = 0;
static void
icvInitFFMPEG(void)
{
static int ffmpegInitialized = 0;
if( !ffmpegInitialized )
{
#if defined WIN32 || defined _WIN32
const char* module_name = "opencv_ffmpeg"
#if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__)
"_64"
#endif
".dll";
static HMODULE icvFFOpenCV = LoadLibrary( module_name );
if( icvFFOpenCV )
{
icvCreateFileCapture_FFMPEG_p =
(CvCreateFileCapture_Plugin)GetProcAddress(icvFFOpenCV, "cvCreateFileCapture_FFMPEG_2");
icvReleaseCapture_FFMPEG_p =
(CvReleaseCapture_Plugin)GetProcAddress(icvFFOpenCV, "cvReleaseCapture_FFMPEG_2");
icvGrabFrame_FFMPEG_p =
(CvGrabFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvGrabFrame_FFMPEG_2");
icvRetrieveFrame_FFMPEG_p =
(CvRetrieveFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvRetrieveFrame_FFMPEG_2");
icvSetCaptureProperty_FFMPEG_p =
(CvSetCaptureProperty_Plugin)GetProcAddress(icvFFOpenCV, "cvSetCaptureProperty_FFMPEG_2");
icvGetCaptureProperty_FFMPEG_p =
(CvGetCaptureProperty_Plugin)GetProcAddress(icvFFOpenCV, "cvGetCaptureProperty_FFMPEG_2");
icvCreateVideoWriter_FFMPEG_p =
(CvCreateVideoWriter_Plugin)GetProcAddress(icvFFOpenCV, "cvCreateVideoWriter_FFMPEG");
icvReleaseVideoWriter_FFMPEG_p =
(CvReleaseVideoWriter_Plugin)GetProcAddress(icvFFOpenCV, "cvReleaseVideoWriter_FFMPEG");
icvWriteFrame_FFMPEG_p =
(CvWriteFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvWriteFrame_FFMPEG");
#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
{
printf("Failed to load FFMPEG plugin: module handle=%p\n", icvFFOpenCV);
}
#endif
}
#elif defined HAVE_FFMPEG
icvCreateFileCapture_FFMPEG_p = (CvCreateFileCapture_Plugin)cvCreateFileCapture_FFMPEG_2;
icvReleaseCapture_FFMPEG_p = (CvReleaseCapture_Plugin)cvReleaseCapture_FFMPEG_2;
icvGrabFrame_FFMPEG_p = (CvGrabFrame_Plugin)cvGrabFrame_FFMPEG_2;
icvRetrieveFrame_FFMPEG_p = (CvRetrieveFrame_Plugin)cvRetrieveFrame_FFMPEG_2;
icvSetCaptureProperty_FFMPEG_p = (CvSetCaptureProperty_Plugin)cvSetCaptureProperty_FFMPEG_2;
icvGetCaptureProperty_FFMPEG_p = (CvGetCaptureProperty_Plugin)cvGetCaptureProperty_FFMPEG_2;
icvCreateVideoWriter_FFMPEG_p = (CvCreateVideoWriter_Plugin)cvCreateVideoWriter_FFMPEG;
icvReleaseVideoWriter_FFMPEG_p = (CvReleaseVideoWriter_Plugin)cvReleaseVideoWriter_FFMPEG;
icvWriteFrame_FFMPEG_p = (CvWriteFrame_Plugin)cvWriteFrame_FFMPEG;
#endif
ffmpegInitialized = 1;
}
}
class CvCapture_FFMPEG_proxy : public CvCapture
{
public:
CvCapture_FFMPEG_proxy() { ffmpegCapture = 0; }
virtual ~CvCapture_FFMPEG_proxy() { close(); }
virtual double getProperty(int propId)
{
return ffmpegCapture ? icvGetCaptureProperty_FFMPEG_p(ffmpegCapture, propId) : 0;
}
virtual bool setProperty(int propId, double value)
{
return ffmpegCapture ? icvSetCaptureProperty_FFMPEG_p(ffmpegCapture, propId, value)!=0 : false;
}
virtual bool grabFrame()
{
return ffmpegCapture ? icvGrabFrame_FFMPEG_p(ffmpegCapture)!=0 : false;
}
virtual IplImage* retrieveFrame(int)
{
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;
cvInitImageHeader(&frame, cvSize(width, height), 8, cn);
cvSetData(&frame, data, step);
return &frame;
}
virtual bool open( const char* filename )
{
close();
icvInitFFMPEG();
if( !icvCreateFileCapture_FFMPEG_p )
return false;
ffmpegCapture = icvCreateFileCapture_FFMPEG_p( filename );
return ffmpegCapture != 0;
}
virtual void close()
{
if( ffmpegCapture && icvReleaseCapture_FFMPEG_p )
icvReleaseCapture_FFMPEG_p( &ffmpegCapture );
assert( ffmpegCapture == 0 );
ffmpegCapture = 0;
}
protected:
void* ffmpegCapture;
IplImage frame;
};
CvCapture* cvCreateFileCapture_FFMPEG_proxy(const char * filename)
{
CvCapture_FFMPEG_proxy* result = new CvCapture_FFMPEG_proxy;
if( result->open( filename ))
return result;
delete result;
#if defined WIN32 || defined _WIN32
return cvCreateFileCapture_VFW(filename);
#else
return 0;
#endif
}
class CvVideoWriter_FFMPEG_proxy : public CvVideoWriter
{
public:
CvVideoWriter_FFMPEG_proxy() { ffmpegWriter = 0; }
virtual ~CvVideoWriter_FFMPEG_proxy() { close(); }
virtual bool writeFrame( const IplImage* image )
{
if(!ffmpegWriter)
return false;
CV_Assert(image->depth == 8);
return icvWriteFrame_FFMPEG_p(ffmpegWriter, (const uchar*)image->imageData,
image->widthStep, image->width, image->height, image->nChannels, image->origin) !=0;
}
virtual bool open( const char* filename, int fourcc, double fps, CvSize frameSize, bool isColor )
{
close();
icvInitFFMPEG();
if( !icvCreateVideoWriter_FFMPEG_p )
return false;
ffmpegWriter = icvCreateVideoWriter_FFMPEG_p( filename, fourcc, fps, frameSize.width, frameSize.height, isColor );
return ffmpegWriter != 0;
}
virtual void close()
{
if( ffmpegWriter && icvReleaseVideoWriter_FFMPEG_p )
icvReleaseVideoWriter_FFMPEG_p( &ffmpegWriter );
assert( ffmpegWriter == 0 );
ffmpegWriter = 0;
}
protected:
void* ffmpegWriter;
};
CvVideoWriter* cvCreateVideoWriter_FFMPEG_proxy( const char* filename, int fourcc,
double fps, CvSize frameSize, int isColor )
{
CvVideoWriter_FFMPEG_proxy* result = new CvVideoWriter_FFMPEG_proxy;
if( result->open( filename, fourcc, fps, frameSize, isColor != 0 ))
return result;
delete result;
#if defined WIN32 || defined _WIN32
return cvCreateVideoWriter_VFW(filename, fourcc, fps, frameSize, isColor);
#else
return 0;
#endif
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册