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