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