00001
00002 #ifndef vidl_ffmpeg_ostream_v3_txx_
00003 #define vidl_ffmpeg_ostream_v3_txx_
00004 #include "vidl_ffmpeg_ostream.h"
00005
00006
00007
00008
00009
00010
00011
00012
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
00059 vidl_ffmpeg_ostream::
00060 vidl_ffmpeg_ostream()
00061 : os_( new vidl_ffmpeg_ostream::pimpl )
00062 {
00063 vidl_ffmpeg_init();
00064 }
00065
00066
00067
00068 vidl_ffmpeg_ostream::
00069 ~vidl_ffmpeg_ostream()
00070 {
00071 close();
00072 delete os_;
00073 }
00074
00075
00076
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
00088 bool
00089 vidl_ffmpeg_ostream::
00090 open()
00091 {
00092
00093 close();
00094
00095
00096
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
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
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
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
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
00234
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
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
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
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
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
00464 bool
00465 vidl_ffmpeg_ostream::
00466 is_open() const
00467 {
00468 return os_->file_opened_;
00469 }
00470
00471
00472
00473
00474 bool
00475 vidl_ffmpeg_ostream::
00476 write_frame(const vidl_frame_sptr& frame)
00477 {
00478 if (!is_open()) {
00479
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
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
00519 if (!vidl_ffmpeg_convert(frame, temp_frame)) {
00520
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_