core/vidl/vidl_ffmpeg_ostream_v3.txx

Go to the documentation of this file.
00001 // This is core/vidl/vidl_ffmpeg_ostream_v3.txx
00002 #ifndef vidl_ffmpeg_ostream_v3_txx_
00003 #define vidl_ffmpeg_ostream_v3_txx_
00004 #include "vidl_ffmpeg_ostream.h"
00005 //:
00006 // \file
00007 // \author Matt Leotta
00008 // \author Amitha Perera
00009 // \author David Law
00010 // \date   26 Jan 2009
00011 //
00012 // Updated for ffmpeg based on -r16810
00013 //
00014 //-----------------------------------------------------------------------------
00015 
00016 #include "vidl_ffmpeg_init.h"
00017 #include "vidl_ffmpeg_convert.h"
00018 #include "vidl_frame.h"
00019 #include "vidl_convert.h"
00020 #include <vcl_cstring.h>
00021 #include <vcl_climits.h>
00022 #include <vil/vil_memory_chunk.h>
00023 
00024 extern "C" {
00025 #if FFMPEG_IN_SEVERAL_DIRECTORIES
00026 #include <libavformat/avformat.h>
00027 #else
00028 #include <ffmpeg/avformat.h>
00029 #endif
00030 }
00031 
00032 //-----------------------------------------------------------------------------
00033 
00034 
00035 struct vidl_ffmpeg_ostream::pimpl
00036 {
00037   pimpl()
00038   : fmt_cxt_( 0 ),
00039   file_opened_( false ),
00040   codec_opened_( false ),
00041   cur_frame_( 0 ),
00042   video_rc_eq_(NULL)
00043   { }
00044 
00045 
00046   AVFormatContext* fmt_cxt_;
00047   bool file_opened_;
00048   bool codec_opened_;
00049   vil_memory_chunk_sptr bit_buf_;
00050   unsigned int cur_frame_;
00051   char* video_rc_eq_;
00052 };
00053 
00054 
00055 //-----------------------------------------------------------------------------
00056 
00057 
00058 //: Constructor
00059 vidl_ffmpeg_ostream::
00060 vidl_ffmpeg_ostream()
00061   : os_( new vidl_ffmpeg_ostream::pimpl )
00062 {
00063   vidl_ffmpeg_init();
00064 }
00065 
00066 
00067 //: Destructor
00068 vidl_ffmpeg_ostream::
00069 ~vidl_ffmpeg_ostream()
00070 {
00071   close();
00072   delete os_;
00073 }
00074 
00075 
00076 //: Constructor - opens a stream
00077 vidl_ffmpeg_ostream::
00078 vidl_ffmpeg_ostream(const vcl_string& filename,
00079                     const vidl_ffmpeg_ostream_params& params)
00080   : os_( new vidl_ffmpeg_ostream::pimpl ),
00081     filename_(filename), params_(params)
00082 {
00083   vidl_ffmpeg_init();
00084 }
00085 
00086 
00087 //: Open the stream
00088 bool
00089 vidl_ffmpeg_ostream::
00090 open()
00091 {
00092   // Close any open files
00093   close();
00094 
00095   // a raw video packet is the same size as the input image. Others
00096   // are smaller.
00097   os_->bit_buf_ = new vil_memory_chunk( params_.ni_ * params_.nj_ * 3, VIL_PIXEL_FORMAT_BYTE );
00098 
00099   os_->fmt_cxt_ = avformat_alloc_context();
00100 
00101   AVOutputFormat* file_oformat = 0;
00102   if ( params_.file_format_ == vidl_ffmpeg_ostream_params::GUESS ) {
00103     file_oformat = guess_format(NULL, filename_.c_str(), NULL);
00104     if (!file_oformat) {
00105       vcl_cerr << "ffmpeg: Unable for find a suitable output format for "
00106                << filename_ << '\n';
00107       close();
00108       return false;
00109     }
00110   } else {
00111     close();
00112     return false;
00113   }
00114 
00115   os_->fmt_cxt_->oformat = file_oformat;
00116   os_->fmt_cxt_->nb_streams = 0;
00117 
00118   // Create stream
00119   AVStream* st = av_new_stream( os_->fmt_cxt_, 0 );
00120   if ( !st ) {
00121     vcl_cerr << "ffmpeg: could not alloc stream\n";
00122     close();
00123     return false;
00124   }
00125 
00126   //os_->fmt_cxt_->nb_streams = 1;
00127 
00128   AVCodecContext *video_enc = st->codec;
00129 
00130   if (vcl_strcmp(file_oformat->name, "mp4") != 0 ||
00131       vcl_strcmp(file_oformat->name, "mov") != 0 ||
00132       vcl_strcmp(file_oformat->name, "3gp") != 0 )
00133     video_enc->flags |= CODEC_FLAG_GLOBAL_HEADER;
00134 
00135   video_enc->codec_type = CODEC_TYPE_VIDEO;
00136 
00137   switch ( params_.encoder_ )
00138   {
00139    case vidl_ffmpeg_ostream_params::DEFAULT:
00140     video_enc->codec_id = file_oformat->video_codec;
00141     break;
00142    case vidl_ffmpeg_ostream_params::MPEG4:
00143     video_enc->codec_id = CODEC_ID_MPEG4;
00144     break;
00145    case vidl_ffmpeg_ostream_params::MPEG2VIDEO:
00146     video_enc->codec_id = CODEC_ID_MPEG2VIDEO;
00147     break;
00148    case vidl_ffmpeg_ostream_params::MSMPEG4V2:
00149     video_enc->codec_id = CODEC_ID_MSMPEG4V2;
00150     break;
00151    case vidl_ffmpeg_ostream_params::RAWVIDEO:
00152     video_enc->codec_id = CODEC_ID_RAWVIDEO;
00153     break;
00154    case vidl_ffmpeg_ostream_params::LJPEG:
00155     video_enc->codec_id = CODEC_ID_LJPEG;
00156     break;
00157    case vidl_ffmpeg_ostream_params::HUFFYUV:
00158     video_enc->codec_id = CODEC_ID_HUFFYUV;
00159     break;
00160    case vidl_ffmpeg_ostream_params::DVVIDEO:
00161     video_enc->codec_id = CODEC_ID_DVVIDEO;
00162     break;
00163    default:
00164     vcl_cout << "ffmpeg: Unknown encoder type\n";
00165     return false;
00166   }
00167 
00168   AVCodec* codec = avcodec_find_encoder( video_enc->codec_id );
00169   if ( !codec )
00170   {
00171     vcl_cerr << "ffmpeg_writer:: couldn't find encoder for " << video_enc->codec_id << '\n';
00172     return false;
00173   }
00174 
00175   video_enc->bit_rate = params_.bit_rate_ * 1000;
00176   video_enc->bit_rate_tolerance = params_.video_bit_rate_tolerance_;
00177   video_enc->time_base.num = 1000;
00178   video_enc->time_base.den = int(params_.frame_rate_*1000);
00179 
00180   if ( codec && codec->supported_framerates )
00181   {
00182     AVRational const* p = codec->supported_framerates;
00183     AVRational req = { video_enc->time_base.den, video_enc->time_base.num };
00184     AVRational const* best = NULL;
00185     AVRational best_error = { INT_MAX, 1 };
00186     for (; p->den!=0; p++)
00187     {
00188       AVRational error = av_sub_q(req, *p);
00189       if ( error.num < 0 )   error.num *= -1;
00190       if ( av_cmp_q( error, best_error ) < 0 )
00191       {
00192         best_error= error;
00193         best= p;
00194       }
00195     }
00196     video_enc->time_base.den= best->num;
00197     video_enc->time_base.num= best->den;
00198   }
00199 
00200   video_enc->width  = params_.ni_;
00201   video_enc->height = params_.nj_;
00202   video_enc->sample_aspect_ratio = av_d2q(params_.frame_aspect_ratio_*params_.ni_/params_.nj_, 255);
00203 
00204   // Our source is packed RGB. Use that if possible.
00205   video_enc->pix_fmt = PIX_FMT_RGB24;
00206   if ( codec && codec->pix_fmts )
00207   {
00208     const enum PixelFormat* p= codec->pix_fmts;
00209     for ( ; *p != -1; p++ )
00210     {
00211       if ( *p == video_enc->pix_fmt )
00212         break;
00213     }
00214     if ( *p == -1 )
00215       video_enc->pix_fmt = codec->pix_fmts[0];
00216   }
00217   else if ( codec && ( codec->id == CODEC_ID_RAWVIDEO ||
00218                       codec->id == CODEC_ID_HUFFYUV ) )
00219   {
00220     // these formats only support the YUV input image formats
00221     video_enc->pix_fmt = PIX_FMT_YUV420P;
00222   }
00223 
00224   if (!params_.intra_only_)
00225     video_enc->gop_size = params_.gop_size_;
00226   else
00227     video_enc->gop_size = 0;
00228   if (params_.video_qscale_ || params_.same_quality_)
00229   {
00230     video_enc->flags |= CODEC_FLAG_QSCALE;
00231     st->quality = FF_QP2LAMBDA * params_.video_qscale_;
00232   }
00233   // if (bitexact)
00234   //   video_enc->flags |= CODEC_FLAG_BITEXACT;
00235 
00236   video_enc->mb_decision = params_.mb_decision_;
00237   video_enc->mb_cmp = params_.mb_cmp_;
00238   video_enc->ildct_cmp = params_.ildct_cmp_;
00239   video_enc->me_sub_cmp = params_.sub_cmp_;
00240   video_enc->me_cmp = params_.cmp_;
00241   video_enc->me_pre_cmp = params_.pre_cmp_;
00242   video_enc->pre_me = params_.pre_me_;
00243   video_enc->lumi_masking = params_.lumi_mask_;
00244   video_enc->dark_masking = params_.dark_mask_;
00245   video_enc->spatial_cplx_masking = params_.scplx_mask_;
00246   video_enc->temporal_cplx_masking = params_.tcplx_mask_;
00247   video_enc->p_masking = params_.p_mask_;
00248   video_enc->quantizer_noise_shaping= params_.qns_;
00249 
00250   if (params_.use_umv_)
00251   {
00252     video_enc->flags |= CODEC_FLAG_H263P_UMV;
00253   }
00254   if (params_.use_ss_)
00255   {
00256     video_enc->flags |= CODEC_FLAG_H263P_SLICE_STRUCT;
00257   }
00258   if (params_.use_aiv_)
00259   {
00260     video_enc->flags |= CODEC_FLAG_H263P_AIV;
00261   }
00262   if (params_.use_4mv_)
00263   {
00264     video_enc->flags |= CODEC_FLAG_4MV;
00265   }
00266   if (params_.use_obmc_)
00267   {
00268     video_enc->flags |= CODEC_FLAG_OBMC;
00269   }
00270   if (params_.use_loop_)
00271   {
00272     video_enc->flags |= CODEC_FLAG_LOOP_FILTER;
00273   }
00274 
00275   if (params_.use_part_)
00276   {
00277     video_enc->flags |= CODEC_FLAG_PART;
00278   }
00279   if (params_.use_alt_scan_)
00280   {
00281     video_enc->flags |= CODEC_FLAG_ALT_SCAN;
00282   }
00283   if (params_.use_scan_offset_)
00284   {
00285     video_enc->flags |= CODEC_FLAG_SVCD_SCAN_OFFSET;
00286   }
00287   if (params_.closed_gop_)
00288   {
00289     video_enc->flags |= CODEC_FLAG_CLOSED_GOP;
00290   }
00291   if (params_.use_qpel_)
00292   {
00293     video_enc->flags |= CODEC_FLAG_QPEL;
00294   }
00295   if (params_.use_qprd_)
00296   {
00297     video_enc->flags |= CODEC_FLAG_QP_RD;
00298   }
00299   if (params_.use_cbprd_)
00300   {
00301     video_enc->flags |= CODEC_FLAG_CBP_RD;
00302   }
00303   if (params_.b_frames_)
00304   {
00305     video_enc->max_b_frames = params_.b_frames_;
00306     video_enc->b_frame_strategy = 0;
00307     video_enc->b_quant_factor = 2.0;
00308   }
00309   if (params_.do_interlace_dct_)
00310   {
00311     video_enc->flags |= CODEC_FLAG_INTERLACED_DCT;
00312   }
00313   if (params_.do_interlace_me_)
00314   {
00315     video_enc->flags |= CODEC_FLAG_INTERLACED_ME;
00316   }
00317   video_enc->qmin = params_.video_qmin_;
00318   video_enc->qmax = params_.video_qmax_;
00319   video_enc->lmin = params_.video_lmin_;
00320   video_enc->lmax = params_.video_lmax_;
00321   video_enc->mb_qmin = params_.video_mb_qmin_;
00322   video_enc->mb_qmax = params_.video_mb_qmax_;
00323   video_enc->max_qdiff = params_.video_qdiff_;
00324   video_enc->qblur = params_.video_qblur_;
00325   video_enc->qcompress = params_.video_qcomp_;
00326 
00327   // delete when the stream is closed
00328   os_->video_rc_eq_ = new char[params_.video_rc_eq_.length()+1];
00329   vcl_strcpy(os_->video_rc_eq_, params_.video_rc_eq_.c_str());
00330   video_enc->rc_eq = os_->video_rc_eq_;
00331 
00332   video_enc->debug = params_.debug_;
00333   video_enc->debug_mv = params_.debug_mv_;
00334   video_enc->thread_count = 1;
00335 
00336   video_enc->rc_max_rate = params_.video_rc_max_rate_;
00337   video_enc->rc_min_rate = params_.video_rc_min_rate_;
00338   video_enc->rc_buffer_size = params_.video_rc_buffer_size_;
00339   video_enc->rc_buffer_aggressivity= params_.video_rc_buffer_aggressivity_;
00340   video_enc->rc_initial_cplx= params_.video_rc_initial_cplx_;
00341   video_enc->i_quant_factor = params_.video_i_qfactor_;
00342   video_enc->b_quant_factor = params_.video_b_qfactor_;
00343   video_enc->i_quant_offset = params_.video_i_qoffset_;
00344   video_enc->b_quant_offset = params_.video_b_qoffset_;
00345   video_enc->intra_quant_bias = params_.video_intra_quant_bias_;
00346   video_enc->inter_quant_bias = params_.video_inter_quant_bias_;
00347   video_enc->dct_algo = params_.dct_algo_;
00348   video_enc->idct_algo = params_.idct_algo_;
00349   video_enc->me_threshold= params_.me_threshold_;
00350   video_enc->mb_threshold= params_.mb_threshold_;
00351   video_enc->intra_dc_precision= params_.intra_dc_precision_ - 8;
00352   video_enc->strict_std_compliance = params_.strict_;
00353   video_enc->error_rate = params_.error_rate_;
00354   video_enc->noise_reduction= params_.noise_reduction_;
00355   video_enc->scenechange_threshold= params_.sc_threshold_;
00356   video_enc->me_range = params_.me_range_;
00357   video_enc->coder_type= params_.coder_;
00358   video_enc->context_model= params_.context_;
00359   video_enc->prediction_method= params_.predictor_;
00360 
00361   if (params_.do_psnr_)
00362     video_enc->flags|= CODEC_FLAG_PSNR;
00363 
00364   video_enc->me_method = params_.me_method_;
00365 
00366   /* two pass mode */
00367   if (params_.do_pass_)
00368   {
00369     if (params_.do_pass_ == 1)
00370     {
00371       video_enc->flags |= CODEC_FLAG_PASS1;
00372     }
00373     else
00374     {
00375       video_enc->flags |= CODEC_FLAG_PASS2;
00376     }
00377   }
00378 
00379   os_->fmt_cxt_->timestamp = 0;
00380   os_->fmt_cxt_->title[0] = '\0';
00381   os_->fmt_cxt_->author[0] = '\0';
00382   os_->fmt_cxt_->copyright[0] = '\0';
00383   os_->fmt_cxt_->comment[0] = '\0';
00384 
00385   vcl_strncpy( os_->fmt_cxt_->filename, filename_.c_str(), 1023 );
00386 
00387   if ( url_fopen( &os_->fmt_cxt_->pb, filename_.c_str(), URL_WRONLY) < 0 )
00388   {
00389     vcl_cerr << "ffmpeg: couldn't open " << filename_ << " for writing\n";
00390     close();
00391     return false;
00392   }
00393   os_->file_opened_ = true;
00394 
00395   AVFormatParameters fmt_param;
00396   vcl_memset( &fmt_param, 0, sizeof(fmt_param) );
00397   if ( av_set_parameters( os_->fmt_cxt_, &fmt_param ) < 0 )
00398   {
00399     vcl_cerr << "ffmpeg: invalid encoding parameter\n";
00400     close();
00401     return false;
00402   }
00403 
00404   //dump_format( os_->fmt_cxt_, 1, filename_, 1 );
00405 
00406   if ( avcodec_open( video_enc, codec ) < 0 )
00407   {
00408     vcl_cerr << "ffmpeg: couldn't open codec\n";
00409     close();
00410     return false;
00411   }
00412   os_->codec_opened_ = true;
00413 
00414   if ( av_write_header( os_->fmt_cxt_ ) < 0 )
00415   {
00416     vcl_cerr << "ffmpeg: couldn't write header\n";
00417     close();
00418     return false;
00419   }
00420 
00421   return true;
00422 }
00423 
00424 
00425 //: Close the stream
00426 void
00427 vidl_ffmpeg_ostream::
00428 close()
00429 {
00430   delete os_->video_rc_eq_;
00431   os_->video_rc_eq_ = NULL;
00432 
00433   if ( os_->fmt_cxt_ ) {
00434 
00435     if ( os_->file_opened_ ) {
00436       av_write_trailer( os_->fmt_cxt_ );
00437       url_fclose( os_->fmt_cxt_->pb );
00438       os_->file_opened_ = false;
00439     }
00440 
00441     if ( os_->fmt_cxt_->nb_streams > 0 ) {
00442       if ( os_->codec_opened_ ) {
00443         for ( unsigned i = 0; i < os_->fmt_cxt_->nb_streams; ++i ) {
00444           AVCodecContext* codec = os_->fmt_cxt_->streams[i]->codec;
00445           if ( codec->stats_in ) {
00446             av_freep( codec->stats_in );
00447           }
00448           avcodec_close( codec );
00449         }
00450       }
00451       os_->codec_opened_ = false;
00452       for ( unsigned i = 0; i < os_->fmt_cxt_->nb_streams; ++i ) {
00453         av_free( os_->fmt_cxt_->streams[i] );
00454       }
00455     }
00456 
00457     av_free( os_->fmt_cxt_ );
00458     os_->fmt_cxt_ = 0;
00459   }
00460 }
00461 
00462 
00463 //: Return true if the stream is open for writing
00464 bool
00465 vidl_ffmpeg_ostream::
00466 is_open() const
00467 {
00468   return os_->file_opened_;
00469 }
00470 
00471 
00472 //: Write and image to the stream
00473 // \retval false if the image could not be written
00474 bool
00475 vidl_ffmpeg_ostream::
00476 write_frame(const vidl_frame_sptr& frame)
00477 {
00478   if (!is_open()) {
00479     // resize to the first frame
00480     params_.size(frame->ni(),frame->nj());
00481     open();
00482   }
00483 
00484   AVCodecContext* codec = os_->fmt_cxt_->streams[0]->codec;
00485 
00486   if (unsigned( codec->width ) != frame->ni() ||
00487       unsigned( codec->height) != frame->nj() ) {
00488     vcl_cerr << "ffmpeg: Input image has wrong size. Expecting ("
00489              << codec->width << 'x' << codec->height << "), got ("
00490              << frame->ni() << 'x' << frame->nj() << ")\n";
00491     return false;
00492   }
00493 
00494 
00495   PixelFormat fmt = vidl_pixel_format_to_ffmpeg(frame->pixel_format());
00496 
00497   vidl_pixel_format target_fmt = vidl_pixel_format_from_ffmpeg(codec->pix_fmt);
00498   static vidl_frame_sptr temp_frame = new vidl_shared_frame(NULL,frame->ni(),frame->nj(),target_fmt);
00499 
00500   AVFrame out_frame;
00501   avcodec_get_frame_defaults( &out_frame );
00502 
00503   // The frame is in the correct format to encode directly
00504   if ( codec->pix_fmt == fmt )
00505   {
00506     avpicture_fill((AVPicture*)&out_frame, (uint8_t*) frame->data(),
00507                    fmt, frame->ni(), frame->nj());
00508   }
00509   else
00510   {
00511     if (!temp_frame->data()) {
00512       unsigned ni = frame->ni();
00513       unsigned nj = frame->nj();
00514       unsigned out_size = vidl_pixel_format_buffer_size(ni,nj,target_fmt);
00515       temp_frame = new vidl_memory_chunk_frame(ni, nj, target_fmt,
00516                                                new vil_memory_chunk(out_size, VIL_PIXEL_FORMAT_BYTE));
00517     }
00518     // try conversion with FFMPEG functions
00519     if (!vidl_ffmpeg_convert(frame, temp_frame)) {
00520       // try conversion with vidl functions
00521       if (!vidl_convert_frame(*frame, *temp_frame)) {
00522         vcl_cout << "unable to convert " << frame->pixel_format() << " to "<<target_fmt<<vcl_endl;
00523         return false;
00524       }
00525     }
00526     avpicture_fill((AVPicture*)&out_frame, (uint8_t*) temp_frame->data(),
00527                    codec->pix_fmt, frame->ni(), frame->nj());
00528   }
00529 
00530   AVPacket pkt;
00531   av_init_packet( &pkt );
00532   pkt.stream_index = 0;
00533 
00534   out_frame.pts = os_->cur_frame_;
00535 
00536   int ret = avcodec_encode_video( codec, (uint8_t*)os_->bit_buf_->data(), os_->bit_buf_->size(), &out_frame );
00537 
00538   if ( ret ) {
00539     pkt.data = (uint8_t*)os_->bit_buf_->data();
00540     pkt.size = ret;
00541     if ( codec->coded_frame ) {
00542       pkt.pts = codec->coded_frame->pts;
00543     }
00544     if ( codec->coded_frame && codec->coded_frame->key_frame ) {
00545       pkt.flags |= PKT_FLAG_KEY;
00546     }
00547     av_interleaved_write_frame( os_->fmt_cxt_, &pkt );
00548   }
00549   else {
00550     return false;
00551   }
00552 
00553   ++os_->cur_frame_;
00554   return true;
00555 }
00556 
00557 #endif // vidl_ffmpeg_ostream_v3_txx_

Generated on Mon Mar 8 05:10:34 2010 for core/vidl by  doxygen 1.5.1