Files
yanshui177 6dcd378738 完善目录结构
完善了目录结构,添加了以前的web段com组件调用的代码(在/测试目录下)(部署没有使用到)
2017-05-17 20:43:16 +08:00

796 lines
23 KiB
C++

/*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 "_highgui.h"
extern "C" {
#include <ffmpeg/avformat.h>
}
#ifdef NDEBUG
#define CV_WARN(message)
#else
#define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__)
#endif
typedef struct CvCaptureAVI_FFMPEG
{
CvCaptureVTable * vtable;
AVFormatContext * ic;
int video_stream;
AVStream * video_st;
AVFrame * picture;
int64_t picture_pts;
AVFrame rgb_picture;
IplImage frame;
} CvCaptureAVI_FFMPEG;
static void icvCloseAVI_FFMPEG( CvCaptureAVI_FFMPEG* capture )
{
//cvFree( (void**)&(capture->entries) );
if( capture->picture )
av_free(capture->picture);
if( capture->video_st )
{
#if LIBAVFORMAT_BUILD > 4628
avcodec_close( capture->video_st->codec );
#else
avcodec_close( &capture->video_st->codec );
#endif
capture->video_st = NULL;
}
if( capture->ic )
{
av_close_input_file(capture->ic);
capture->ic = NULL;
}
if( capture->rgb_picture.data[0] )
cvFree( &capture->rgb_picture.data[0] );
memset( &capture->frame, 0, sizeof(capture->frame));
}
static int icvOpenAVI_FFMPEG( CvCaptureAVI_FFMPEG* capture, const char* filename )
{
int err, valid = 0, video_index = -1, i;
AVFormatContext *ic;
capture->ic = NULL;
capture->video_stream = -1;
capture->video_st = NULL;
/* register all codecs, demux and protocols */
av_register_all();
err = av_open_input_file(&ic, filename, NULL, 0, NULL);
if (err < 0) {
CV_WARN("Error opening file");
goto exit_func;
}
capture->ic = ic;
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
AVCodecContext *enc = ic->streams[i]->codec;
#else
AVCodecContext *enc = &ic->streams[i]->codec;
#endif
AVCodec *codec;
if( CODEC_TYPE_VIDEO == enc->codec_type && video_index < 0) {
video_index = i;
codec = avcodec_find_decoder(enc->codec_id);
if (!codec ||
avcodec_open(enc, codec) < 0)
goto exit_func;
capture->video_stream = i;
capture->video_st = ic->streams[i];
capture->picture = avcodec_alloc_frame();
capture->rgb_picture.data[0] = (uchar*)cvAlloc(
avpicture_get_size( PIX_FMT_BGR24,
enc->width, enc->height ));
avpicture_fill( (AVPicture*)&capture->rgb_picture, capture->rgb_picture.data[0],
PIX_FMT_BGR24, enc->width, enc->height );
cvInitImageHeader( &capture->frame, cvSize( enc->width,
enc->height ), 8, 3, 0, 4 );
cvSetData( &capture->frame, capture->rgb_picture.data[0],
capture->rgb_picture.linesize[0] );
break;
}
}
if(video_index >= 0)
valid = 1;
exit_func:
if( !valid )
icvCloseAVI_FFMPEG( capture );
return valid;
}
static int icvGrabFrameAVI_FFMPEG( CvCaptureAVI_FFMPEG* capture )
{
int valid=0;
static bool bFirstTime = true;
static AVPacket pkt;
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;
pkt.data = NULL;
}
if( !capture || !capture->ic || !capture->video_st )
return 0;
// free last packet if exist
if (pkt.data != NULL) {
av_free_packet (&pkt);
}
// get the next frame
while ((0 == valid) && (av_read_frame(capture->ic, &pkt) >= 0)) {
if( pkt.stream_index != capture->video_stream ) continue;
#if LIBAVFORMAT_BUILD > 4628
avcodec_decode_video(capture->video_st->codec,
capture->picture, &got_picture,
pkt.data, pkt.size);
#else
avcodec_decode_video(&capture->video_st->codec,
capture->picture, &got_picture,
pkt.data, pkt.size);
#endif
if (got_picture) {
// we have a new picture, so memorize it
capture->picture_pts = pkt.pts;
valid = 1;
}
}
// return if we have a new picture or not
return valid;
}
static const IplImage* icvRetrieveFrameAVI_FFMPEG( CvCaptureAVI_FFMPEG* capture )
{
if( !capture || !capture->video_st || !capture->picture->data[0] )
return 0;
#if LIBAVFORMAT_BUILD > 4628
img_convert( (AVPicture*)&capture->rgb_picture, PIX_FMT_BGR24,
(AVPicture*)capture->picture,
capture->video_st->codec->pix_fmt,
capture->video_st->codec->width,
capture->video_st->codec->height );
#else
img_convert( (AVPicture*)&capture->rgb_picture, PIX_FMT_BGR24,
(AVPicture*)capture->picture,
capture->video_st->codec.pix_fmt,
capture->video_st->codec.width,
capture->video_st->codec.height );
#endif
return &capture->frame;
}
static int icvSetPropertyAVI_FFMPEG( CvCaptureAVI_FFMPEG* capture,
int property_id, double value );
static double icvGetPropertyAVI_FFMPEG( CvCaptureAVI_FFMPEG* capture, int property_id )
{
if( !capture || !capture->video_st || !capture->picture->data[0] )
return 0;
int64_t timestamp;
timestamp = capture->picture_pts;
switch( property_id )
{
case CV_CAP_PROP_POS_MSEC:
if(capture->ic->start_time != static_cast<double>(AV_NOPTS_VALUE))
return (double)(timestamp - capture->ic->start_time)*1000/(double)AV_TIME_BASE;
break;
case CV_CAP_PROP_POS_FRAMES:
if(capture->video_st->cur_dts != static_cast<double>(AV_NOPTS_VALUE))
return (double)capture->video_st->cur_dts-1;
break;
case CV_CAP_PROP_POS_AVI_RATIO:
if(capture->ic->start_time != static_cast<double>(AV_NOPTS_VALUE) && capture->ic->duration != static_cast<double>(AV_NOPTS_VALUE))
return (double)(timestamp-capture->ic->start_time)/(double)capture->ic->duration;
break;
case CV_CAP_PROP_FRAME_WIDTH:
return capture->frame.width;
break;
case CV_CAP_PROP_FRAME_HEIGHT:
return capture->frame.height;
break;
case CV_CAP_PROP_FPS:
#if LIBAVCODEC_BUILD > 4753
return av_q2d (capture->video_st->r_frame_rate);
#else
return (double)capture->video_st->codec.frame_rate
/ (double)capture->video_st->codec.frame_rate_base;
#endif
break;
case CV_CAP_PROP_FOURCC:
#if LIBAVFORMAT_BUILD > 4628
return (double)capture->video_st->codec->codec_tag;
#else
return (double)capture->video_st->codec.codec_tag;
#endif
break;
}
return 0;
}
static int icvSetPropertyAVI_FFMPEG( CvCaptureAVI_FFMPEG* capture,
int property_id, double value )
{
if( !capture || !capture->video_st || !capture->picture->data[0] )
return 0;
switch( property_id )
{
#if 0
case CV_CAP_PROP_POS_MSEC:
case CV_CAP_PROP_POS_FRAMES:
case CV_CAP_PROP_POS_AVI_RATIO:
{
int64_t timestamp = AV_NOPTS_VALUE;
switch( property_id )
{
case CV_CAP_PROP_POS_FRAMES:
if(capture->ic->start_time != AV_NOPTS_VALUE) {
value *= (double)capture->video_st->codec.frame_rate_base
/ (double)capture->video_st->codec.frame_rate;
timestamp = capture->ic->start_time+(int64_t)(value*AV_TIME_BASE);
}
break;
case CV_CAP_PROP_POS_MSEC:
if(capture->ic->start_time != AV_NOPTS_VALUE)
timestamp = capture->ic->start_time+(int64_t)(value*AV_TIME_BASE/1000);
break;
case CV_CAP_PROP_POS_AVI_RATIO:
if(capture->ic->start_time != AV_NOPTS_VALUE && capture->ic->duration != AV_NOPTS_VALUE)
timestamp = capture->ic->start_time+(int64_t)(value*capture->ic->duration);
break;
}
if(timestamp != AV_NOPTS_VALUE) {
//printf("timestamp=%g\n",(double)timestamp);
int ret = av_seek_frame(capture->ic, -1, timestamp, 0);
if (ret < 0) {
fprintf(stderr, "HIGHGUI ERROR: AVI: could not seek to position %0.3f\n",
(double)timestamp / AV_TIME_BASE);
return 0;
}
}
}
break;
#endif
default:
return 0;
}
return 1;
}
static CvCaptureVTable captureAVI_FFMPEG_vtable =
{
6,
(CvCaptureCloseFunc)icvCloseAVI_FFMPEG,
(CvCaptureGrabFrameFunc)icvGrabFrameAVI_FFMPEG,
(CvCaptureRetrieveFrameFunc)icvRetrieveFrameAVI_FFMPEG,
(CvCaptureGetPropertyFunc)icvGetPropertyAVI_FFMPEG,
(CvCaptureSetPropertyFunc)icvSetPropertyAVI_FFMPEG,
(CvCaptureGetDescriptionFunc)0
};
CvCapture* cvCaptureFromFile_FFMPEG( const char* filename )
{
CvCaptureAVI_FFMPEG* capture = 0;
if( filename )
{
capture = (CvCaptureAVI_FFMPEG*)cvAlloc( sizeof(*capture));
memset( capture, 0, sizeof(*capture));
capture->vtable = &captureAVI_FFMPEG_vtable;
if( !icvOpenAVI_FFMPEG( capture, filename ))
cvReleaseCapture( (CvCapture**)&capture );
}
return (CvCapture*)capture;
}
///////////////// FFMPEG CvVideoWriter implementation //////////////////////////
typedef struct CvAVI_FFMPEG_Writer
{
AVOutputFormat *fmt;
AVFormatContext *oc;
uint8_t * outbuf;
uint32_t outbuf_size;
FILE * outfile;
AVFrame * picture;
AVFrame * rgb_picture;
uint8_t * picbuf;
AVStream * video_st;
} CvAVI_FFMPEG_Writer;
/**
* 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(pix_fmt, width, height);
if(alloc){
picture_buf = (uint8_t *) cvAlloc(size);
if (!picture_buf)
{
av_free(picture);
return NULL;
}
avpicture_fill((AVPicture *)picture, picture_buf,
pix_fmt, width, height);
}
else {
}
return picture;
}
/* add a video output stream */
static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc, int codec_tag, int w, int h, int bitrate, double fps, int pixel_format)
{
AVCodecContext *c;
AVStream *st;
int codec_id;
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
codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, CODEC_TYPE_VIDEO);
#else
codec_id = oc->oformat->video_codec;
#endif
if(codec_tag) c->codec_tag=codec_tag;
c->codec_id = (CodecID) codec_id;
codec = avcodec_find_encoder(c->codec_id);
c->codec_type = CODEC_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=cvRound(fps);
frame_rate_base=1;
while (fabs((double)frame_rate/frame_rate_base) - fps > 0.001){
frame_rate_base*=10;
frame_rate=cvRound(fps*frame_rate_base);
}
#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= (AVRational){frame_rate, frame_rate_base};
const AVRational *best=NULL;
AVRational best_error= (AVRational){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) {
/* just for testing, we also add B frames */
c->max_b_frames = 2;
}
if (c->codec_id == CODEC_ID_MPEG1VIDEO){
/* 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 */
c->mb_decision=2;
}
// some formats want stream headers to be seperate
if(!strcmp(oc->oformat->name, "mp4") || !strcmp(oc->oformat->name, "mov") || !strcmp(oc->oformat->name, "3gp"))
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
return st;
}
/// Create a video writer object that uses FFMPEG
CV_IMPL CvVideoWriter* cvCreateVideoWriter( const char * filename, int fourcc,
double fps, CvSize frameSize, int /*is_color*/ )
{
CV_FUNCNAME("cvCreateVideoWriter");
CvAVI_FFMPEG_Writer * writer = NULL;
__BEGIN__;
// check arguments
assert (filename);
assert (fps > 0);
assert (frameSize.width > 0 && frameSize.height > 0);
// allocate memory for structure...
writer = (CvAVI_FFMPEG_Writer *) cvAlloc( sizeof(CvAVI_FFMPEG_Writer));
memset (writer, 0, sizeof (*writer));
// tell FFMPEG to register codecs
av_register_all ();
/* auto detect the output format from the name. default is mpeg. */
writer->fmt = guess_format(NULL, filename, NULL);
if (!writer->fmt) {
CV_ERROR( CV_StsUnsupportedFormat, "Could not deduce output format from file extension");
//writer->fmt = guess_format("mpeg", NULL, NULL);
}
// alloc memory for context
writer->oc = av_alloc_format_context();
assert (writer->oc);
/* set file name */
writer->oc->oformat = writer->fmt;
snprintf(writer->oc->filename, sizeof(writer->oc->filename), "%s", filename);
// TODO -- safe to ignore output audio stream?
writer->video_st = icv_add_video_stream_FFMPEG(writer->oc, fourcc, frameSize.width, frameSize.height, 800000, fps, PIX_FMT_YUV420P);
/* set the output parameters (must be done even if no
parameters). */
if (av_set_parameters(writer->oc, NULL) < 0) {
CV_ERROR(CV_StsBadArg, "Invalid output format parameters");
}
dump_format(writer->oc, 0, filename, 1);
/* now that all the parameters are set, we can open the audio and
video codecs and allocate the necessary encode buffers */
if (!writer->video_st){
CV_ERROR(CV_StsBadArg, "Couldn't open video stream");
}
AVCodec *codec;
AVCodecContext *c;
#if LIBAVFORMAT_BUILD > 4628
c = (writer->video_st->codec);
#else
c = &(writer->video_st->codec);
#endif
/* find the video encoder */
codec = avcodec_find_encoder(c->codec_id);
if (!codec) {
CV_ERROR(CV_StsBadArg, "codec not found");
}
/* open the codec */
if (avcodec_open(c, codec) < 0) {
char errtext[256];
sprintf(errtext, "Could not open codec '%s'", codec->name);
CV_ERROR(CV_StsBadArg, errtext);
}
// printf("Using codec %s\n", codec->name);
writer->outbuf = NULL;
if (!(writer->oc->oformat->flags & AVFMT_RAWPICTURE)) {
/* allocate output buffer */
/* XXX: API change will be done */
writer->outbuf_size = 200000;
writer->outbuf = (uint8_t *) malloc(writer->outbuf_size);
}
bool need_color_convert;
need_color_convert = c->pix_fmt != PIX_FMT_BGR24;
/* allocate the encoded raw picture */
writer->picture = icv_alloc_picture_FFMPEG(c->pix_fmt, c->width, c->height, need_color_convert);
if (!writer->picture) {
CV_ERROR(CV_StsNoMem, "Could not allocate picture");
}
/* if the output format is not YUV420P, then a temporary YUV420P
picture is needed too. It is then converted to the required
output format */
writer->rgb_picture = NULL;
if ( need_color_convert ) {
writer->rgb_picture = icv_alloc_picture_FFMPEG(PIX_FMT_BGR24, c->width, c->height, false);
if (!writer->rgb_picture) {
CV_ERROR(CV_StsNoMem, "Could not allocate picture");
}
}
/* open the output file, if needed */
if (!(writer->fmt->flags & AVFMT_NOFILE)) {
if (url_fopen(&writer->oc->pb, filename, URL_WRONLY) < 0) {
CV_ERROR(CV_StsBadArg, "Couldn't open output file for writing");
}
}
/* write the stream header, if any */
av_write_header( writer->oc );
__END__;
// return what we got
return (CvVideoWriter *) writer;
}
int icv_av_write_frame_FFMPEG( AVFormatContext * oc, AVStream * video_st, uint8_t * outbuf, uint32_t outbuf_size, AVFrame * picture ){
CV_FUNCNAME("icv_av_write_frame_FFMPEG");
#if LIBAVFORMAT_BUILD > 4628
AVCodecContext * c = video_st->codec;
#else
AVCodecContext * c = &(video_st->codec);
#endif
int out_size;
int ret;
__BEGIN__;
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);
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) {
CV_ERROR(CV_StsError, "Error while writing video frame");
}
__END__;
return CV_StsOk;
}
/// write a frame with FFMPEG
CV_IMPL int cvWriteFrame( CvVideoWriter * writer, const IplImage * image )
{
int ret = 0;
CV_FUNCNAME("cvWriteFrame");
__BEGIN__;
// typecast from opaque data type to implemented struct
CvAVI_FFMPEG_Writer * mywriter = (CvAVI_FFMPEG_Writer*) writer;
#if LIBAVFORMAT_BUILD > 4628
AVCodecContext *c = mywriter->video_st->codec;
#else
AVCodecContext *c = &(mywriter->video_st->codec);
#endif
// check parameters
assert ( image );
assert ( image->nChannels == 3 );
assert ( image->depth == IPL_DEPTH_8U );
// check if buffer sizes match, i.e. image has expected format (size, channels, bitdepth, alignment)
assert (image->imageSize == avpicture_get_size (PIX_FMT_BGR24, image->width, image->height));
if (c->pix_fmt != PIX_FMT_BGR24 ) {
assert( mywriter->rgb_picture );
// let rgb_picture point to the raw data buffer of 'image'
avpicture_fill((AVPicture *)mywriter->rgb_picture, (uint8_t *) image->imageData,
PIX_FMT_BGR24, image->width, image->height);
// convert to the color format needed by the codec
if( img_convert((AVPicture *)mywriter->picture, c->pix_fmt,
(AVPicture *)mywriter->rgb_picture, PIX_FMT_BGR24,
image->width, image->height) < 0){
CV_ERROR(CV_StsUnsupportedFormat, "FFMPEG::img_convert pixel format conversion from BGR24 not handled");
}
}
else{
avpicture_fill((AVPicture *)mywriter->picture, (uint8_t *) image->imageData,
PIX_FMT_BGR24, image->width, image->height);
}
ret = icv_av_write_frame_FFMPEG( mywriter->oc, mywriter->video_st, mywriter->outbuf, mywriter->outbuf_size, mywriter->picture);
__END__;
return ret;
}
/// close video output stream and free associated memory
CV_IMPL void cvReleaseVideoWriter( CvVideoWriter ** writer )
{
int i;
// nothing to do if already released
if ( !(*writer) )
return;
// release data structures in reverse order
CvAVI_FFMPEG_Writer * mywriter = (CvAVI_FFMPEG_Writer*)(*writer);
/* 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(mywriter->oc);
// free pictures
#if LIBAVFORMAT_BUILD > 4628
if( mywriter->video_st->codec->pix_fmt != PIX_FMT_BGR24){
#else
if( mywriter->video_st->codec.pix_fmt != PIX_FMT_BGR24){
#endif
cvFree(&(mywriter->picture->data[0]));
}
av_free(mywriter->picture);
if (mywriter->rgb_picture) {
av_free(mywriter->rgb_picture);
}
/* close codec */
#if LIBAVFORMAT_BUILD > 4628
avcodec_close(mywriter->video_st->codec);
#else
avcodec_close(&(mywriter->video_st->codec));
#endif
av_free(mywriter->outbuf);
/* free the streams */
for(i = 0; i < mywriter->oc->nb_streams; i++) {
av_freep(&mywriter->oc->streams[i]->codec);
av_freep(&mywriter->oc->streams[i]);
}
if (!(mywriter->fmt->flags & AVFMT_NOFILE)) {
/* close the output file */
url_fclose(&mywriter->oc->pb);
}
/* free the stream */
av_free(mywriter->oc);
/* free cvVideoWriter */
cvFree ( writer );
// mark as released
(*writer) = 0;
}