/// 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; }
/// write a frame with FFMPEG bool CvVideoWriter_FFMPEG::writeFrame( const IplImage * image ) { bool ret = false; CV_FUNCNAME("CvVideoWriter_FFMPEG::writerFrame"); __BEGIN__; // 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 && image->origin != IPL_ORIGIN_BL ) { if( !temp_image ) temp_image = cvCreateImage( cvGetSize(image), image->depth, image->nChannels ); cvFlip( image, temp_image, 0 ); image = temp_image; } #endif // check parameters if (input_pix_fmt == PIX_FMT_BGR24) { if (image->nChannels != 3 || image->depth != IPL_DEPTH_8U) { CV_ERROR(CV_StsUnsupportedFormat, "cvWriteFrame() needs images with depth = IPL_DEPTH_8U and nChannels = 3."); } } else if (input_pix_fmt == PIX_FMT_GRAY8) { if (image->nChannels != 1 || image->depth != IPL_DEPTH_8U) { CV_ERROR(CV_StsUnsupportedFormat, "cvWriteFrame() needs images with depth = IPL_DEPTH_8U and nChannels = 1."); } } else { assert(false); } // check if buffer sizes match, i.e. image has expected format (size, channels, bitdepth, alignment) assert (image->imageSize == avpicture_get_size( input_pix_fmt, image->width, image->height )); 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 *) image->imageData, (PixelFormat)input_pix_fmt, image->width, image->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, image->width, image->height) < 0){ CV_ERROR(CV_StsUnsupportedFormat, "FFMPEG::img_convert pixel format conversion from BGR24 not handled"); } #else img_convert_ctx = sws_getContext(image->width, image->height, PIX_FMT_BGR24, 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, image->height, picture->data, picture->linesize) < 0 ) { CV_ERROR(CV_StsUnsupportedFormat, "FFMPEG::img_convert pixel format conversion from BGR24 not handled"); } sws_freeContext(img_convert_ctx); #endif } else{ avpicture_fill((AVPicture *)picture, (uint8_t *) image->imageData, (PixelFormat)input_pix_fmt, image->width, image->height); } ret = icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, picture) >= 0; __END__; return ret; }
/// close video output stream and free associated memory inline 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 */ if(ok && oc) { if( (oc->oformat->flags & AVFMT_RAWPICTURE) == 0 ) { for(;;) { int ret = icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, NULL); if( ret == OPENCV_NO_FRAMES_WRITTEN_CODE || ret < 0 ) break; } } av_write_trailer(oc); } if( img_convert_ctx ) { sws_freeContext(img_convert_ctx); img_convert_ctx = 0; } // 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 < ((52<<16)+(123<<8)+0) #if LIBAVCODEC_VERSION_INT >= ((51<<16)+(49<<8)+0) url_fclose(oc->pb); #else url_fclose(&oc->pb); #endif #else avio_close(oc->pb); #endif } /* free the stream */ av_free(oc); if( temp_image.data ) { free(temp_image.data); temp_image.data = 0; } init(); }
/// write a frame with FFMPEG inline bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int width, int height, int cn, int origin ) { bool ret = false; if( (width & -2) != frame_width || (height & -2) != frame_height || !data ) return false; width = frame_width; height = frame_height; // 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); } 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( !img_convert_ctx ) { img_convert_ctx = sws_getContext(width, height, (PixelFormat)input_pix_fmt, c->width, c->height, c->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL); if( !img_convert_ctx ) return false; } if ( sws_scale(img_convert_ctx, input_picture->data, input_picture->linesize, 0, height, picture->data, picture->linesize) < 0 ) return false; } 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; }