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