-/// 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;
- CodecID codec_id = CODEC_ID_NONE;
- int err;
-
- __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 and fourcc code. */
- writer->fmt = guess_format(NULL, filename, NULL);
- if (!writer->fmt) {
- CV_ERROR( CV_StsUnsupportedFormat, "FFMPEG does not recognize the given file extension");
- }
-
- /* determine optimal pixel format */
- if (is_color) {
- writer->input_pix_fmt = PIX_FMT_BGR24;
- }
- else {
- writer->input_pix_fmt = PIX_FMT_GRAY8;
- }
-
- // 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);
-
- /* set some options */
- writer->oc->max_delay = (int)(0.7*AV_TIME_BASE); /* This reduces buffer underrun warnings with MPEG */
-
- /* Lookup codec id for given fourcc */
- if(fourcc!=CV_FOURCC_DEFAULT){
-#if LIBAVCODEC_VERSION_INT<((51<<16)+(49<<8)+0)
- if( (codec_id = codec_get_bmp_id( fourcc )) == CODEC_ID_NONE ){
- CV_ERROR( CV_StsUnsupportedFormat,
- "FFMPEG could not find a codec matching the given FOURCC code. Use fourcc=CV_FOURCC_DEFAULT for auto selection." );
- }
- }
-#else
- if( (codec_id = av_codec_get_id((const AVCodecTag**)(&codec_bmp_tags), fourcc)) == CODEC_ID_NONE ){
- CV_ERROR( CV_StsUnsupportedFormat,
- "FFMPEG could not find a codec matching the given FOURCC code. Use fourcc=CV_FOURCC_DEFAULT for auto selection." );
- }
- }
-#endif
-
- // set a few optimal pixel formats for lossless codecs of interest..
- int codec_pix_fmt;
- switch (codec_id) {
-#if LIBAVCODEC_VERSION_INT>0x000409
- case CODEC_ID_JPEGLS:
- // BGR24 or GRAY8 depending on is_color...
- codec_pix_fmt = writer->input_pix_fmt;
- break;
-#endif
- case CODEC_ID_FFV1:
- // no choice... other supported formats are YUV only
- codec_pix_fmt = PIX_FMT_RGBA32;
- break;
- case CODEC_ID_MJPEG:
- case CODEC_ID_LJPEG:
- codec_pix_fmt = PIX_FMT_YUVJ420P;
- break;
- case CODEC_ID_RAWVIDEO:
- default:
- // good for lossy formats, MPEG, etc.
- codec_pix_fmt = PIX_FMT_YUV420P;
- break;
- }
-
- // TODO -- safe to ignore output audio stream?
- writer->video_st = icv_add_video_stream_FFMPEG(writer->oc, codec_id,
- frameSize.width, frameSize.height, frameSize.width*frameSize.height*64,
- fps, codec_pix_fmt);
-
-
- /* 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
-
- c->codec_tag = fourcc;
- /* find the video encoder */
- codec = avcodec_find_encoder(c->codec_id);
- if (!codec) {
- CV_ERROR(CV_StsBadArg, "codec not found");
- }
-
- /* open the codec */
- if ( (err=avcodec_open(c, codec)) < 0) {
- char errtext[256];
- sprintf(errtext, "Could not open codec '%s': %s", codec->name, icv_FFMPEG_ErrStr(err));
- CV_ERROR(CV_StsBadArg, errtext);
- }
-
- writer->outbuf = NULL;
-
- if (!(writer->oc->oformat->flags & AVFMT_RAWPICTURE)) {
- /* allocate output buffer */
- /* assume we will never get codec output with more than 4 bytes per pixel... */
- writer->outbuf_size = frameSize.width*frameSize.height*4;
- writer->outbuf = (uint8_t *) av_malloc(writer->outbuf_size);
- }
-
- bool need_color_convert;
- need_color_convert = (c->pix_fmt != writer->input_pix_fmt);
-
- /* 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 our input format, then a temporary
- picture of the input format is needed too. It is then converted
- to the required output format */
- writer->input_picture = NULL;
- if ( need_color_convert ) {
- writer->input_picture = icv_alloc_picture_FFMPEG(writer->input_pix_fmt, c->width, c->height, false);
- if (!writer->input_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;
-}
-