X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ffmpeg.c;h=46b4f0098aef19d1ca331d15863216b21fb9e4ff;hb=b2722d0a42d69bdb2461d37bad3b7ed6f7a6a51b;hp=b64655cbbd954045eb4e849e29e797686de5f500;hpb=8409b8fe74e8e13d28dd84a144a856081647b275;p=ffmpeg diff --git a/ffmpeg.c b/ffmpeg.c index b64655cbbd9..46b4f0098ae 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -18,7 +18,6 @@ */ #define HAVE_AV_CONFIG_H #include "avformat.h" -#include "tick.h" #ifndef CONFIG_WIN32 #include @@ -92,9 +91,11 @@ static int video_qmax = 31; static int video_qdiff = 3; static float video_qblur = 0.5; static float video_qcomp = 0.5; +#if 0 //experimental, (can be removed) static float video_rc_qsquish=1.0; static float video_rc_qmod_amp=0; static int video_rc_qmod_freq=0; +#endif static char *video_rc_override_string=NULL; static char *video_rc_eq="tex^qComp"; static int video_rc_buffer_size=0; @@ -104,7 +105,7 @@ static int video_rc_min_rate=0; static float video_rc_initial_cplx=0; static float video_b_qfactor = 1.25; static float video_b_qoffset = 1.25; -static float video_i_qfactor = 0.8; +static float video_i_qfactor = -0.8; static float video_i_qoffset = 0.0; static int me_method = 0; static int video_disable = 0; @@ -114,9 +115,13 @@ static int b_frames = 0; static int use_hq = 0; static int use_4mv = 0; static int do_deinterlace = 0; -static int workaround_bugs = 0; -static int error_resilience = 0; +static int workaround_bugs = FF_BUG_AUTODETECT; +static int error_resilience = 2; +static int error_concealment = 3; static int dct_algo = 0; +static int idct_algo = 0; +static int use_part = 0; +static int packet_size = 0; static int gop_size = 12; static int intra_only = 0; @@ -137,7 +142,12 @@ static int do_hex_dump = 0; static int do_play = 0; static int do_psnr = 0; static int do_vstats = 0; -static int mpeg_vcd = 0; +static int do_pass = 0; +static char *pass_logfilename = NULL; +static int audio_stream_copy = 0; +static int video_stream_copy = 0; + +#define DEFAULT_PASS_LOGFILENAME "ffmpeg2pass" #ifndef CONFIG_AUDIO_OSS const char *audio_device = "none"; @@ -151,8 +161,12 @@ typedef struct AVOutputStream { int index; /* stream index in the output file */ int source_index; /* AVInputStream index */ AVStream *st; /* stream in the output file */ - int encoding_needed; /* true if encoding needed for this stream */ - + int encoding_needed; /* true if encoding needed for this stream */ + int frame_number; + /* input pts and corresponding output pts + for A/V sync */ + double sync_ipts; + INT64 sync_opts; /* video only */ AVPicture pict_tmp; /* temporary image for resizing */ int video_resample; @@ -162,6 +176,7 @@ typedef struct AVOutputStream { int audio_resample; ReSampleContext *resample; /* for audio resampling */ FifoBuffer fifo; /* for compression: one audio fifo per codec */ + FILE *logfile; } AVOutputStream; typedef struct AVInputStream { @@ -170,12 +185,8 @@ typedef struct AVInputStream { AVStream *st; int discard; /* true if stream data should be discarded */ int decoding_needed; /* true if the packets must be decoded in 'raw_fifo' */ - Ticker pts_ticker; /* Ticker for PTS calculation */ - int ticker_inited; /* to signal if the ticker was initialized */ - INT64 pts; /* current pts */ - int pts_increment; /* expected pts increment for next packet */ - int frame_number; /* current frame */ INT64 sample_index; /* current sample */ + int frame_decoded; /* true if a video or audio frame has been decoded */ } AVInputStream; typedef struct AVInputFile { @@ -318,7 +329,7 @@ static void do_audio_out(AVFormatContext *s, &ost->fifo.rptr) == 0) { ret = avcodec_encode_audio(enc, audio_out, sizeof(audio_out), (short *)audio_buf); - s->oformat->write_packet(s, ost->index, audio_out, ret, 0); + av_write_frame(s, ost->index, audio_out, ret); } } else { /* output a pcm frame */ @@ -335,7 +346,7 @@ static void do_audio_out(AVFormatContext *s, } ret = avcodec_encode_audio(enc, audio_out, size_out, (short *)buftmp); - s->oformat->write_packet(s, ost->index, audio_out, ret, 0); + av_write_frame(s, ost->index, audio_out, ret); } } @@ -431,18 +442,20 @@ static void write_picture(AVFormatContext *s, int index, AVPicture *picture, default: return; } - s->oformat->write_packet(s, index, buf, size, 0); + av_write_frame(s, index, buf, size); av_free(buf); } +/* we begin to correct av delay at this threshold */ +#define AV_DELAY_MAX 0.100 static void do_video_out(AVFormatContext *s, AVOutputStream *ost, AVInputStream *ist, AVPicture *picture1, - int *frame_size) + int *frame_size, AVOutputStream *audio_sync) { - int n1, n2, nb, i, ret, frame_number, dec_frame_rate; + int nb_frames, i, ret; AVPicture *picture, *picture2, *pict; AVPicture picture_tmp1, picture_tmp2; static UINT8 *video_buffer; @@ -454,19 +467,43 @@ static void do_video_out(AVFormatContext *s, enc = &ost->st->codec; dec = &ist->st->codec; - frame_number = ist->frame_number; - dec_frame_rate = ist->st->r_frame_rate; - // fprintf(stderr, "\n%d", dec_frame_rate); - /* first drop frame if needed */ - n1 = ((INT64)frame_number * enc->frame_rate) / dec_frame_rate; - n2 = (((INT64)frame_number + 1) * enc->frame_rate) / dec_frame_rate; - nb = n2 - n1; - if (nb <= 0) + /* by default, we output a single frame */ + nb_frames = 1; + + /* NOTE: the A/V sync is always done by considering the audio is + the master clock. It is suffisant for transcoding or playing, + but not for the general case */ + if (audio_sync) { + /* compute the A-V delay and duplicate/remove frames if needed */ + double adelta, vdelta, apts, vpts, av_delay; + + if (audio_sync->sync_ipts != AV_NOPTS_VALUE && + ost->sync_ipts != AV_NOPTS_VALUE) { + + adelta = (double)(ost->st->pts.val - audio_sync->sync_opts) * + s->pts_num / s->pts_den; + apts = audio_sync->sync_ipts + adelta; + + vdelta = (double)(ost->st->pts.val - ost->sync_opts) * + s->pts_num / s->pts_den; + vpts = ost->sync_ipts + vdelta; + + av_delay = apts - vpts; + // printf("delay=%f\n", av_delay); + if (av_delay < -AV_DELAY_MAX) + nb_frames = 2; + else if (av_delay > AV_DELAY_MAX) + nb_frames = 0; + } + } + /* XXX: also handle frame rate conversion */ + if (nb_frames <= 0) return; if (!video_buffer) - video_buffer= av_malloc(VIDEO_BUFFER_SIZE); - if(!video_buffer) return; + video_buffer = av_malloc(VIDEO_BUFFER_SIZE); + if (!video_buffer) + return; /* deinterlace : must be done before any resize */ if (do_deinterlace) { @@ -523,10 +560,9 @@ static void do_video_out(AVFormatContext *s, } else { picture = pict; } - nb=1; /* duplicates frame if needed */ /* XXX: pb because no interleaving */ - for(i=0;icodec_id != CODEC_ID_RAWVIDEO) { /* handles sameq here. This is not correct because it may not be a global option */ @@ -538,23 +574,36 @@ static void do_video_out(AVFormatContext *s, video_buffer, VIDEO_BUFFER_SIZE, picture); //enc->frame_number = enc->real_pict_num; - s->oformat->write_packet(s, ost->index, video_buffer, ret, 0); + av_write_frame(s, ost->index, video_buffer, ret); *frame_size = ret; //fprintf(stderr,"\nFrame: %3d %3d size: %5d type: %d", // enc->frame_number-1, enc->real_pict_num, ret, // enc->pict_type); + /* if two pass, output log */ + if (ost->logfile && enc->stats_out) { + fprintf(ost->logfile, "%s", enc->stats_out); + } } else { - write_picture(s, ost->index, picture, enc->pix_fmt, enc->width, enc->height); + if (s->oformat->flags & AVFMT_RAWPICTURE) { + /* raw pictures are written as AVPicture structure to + avoid any copies. We support temorarily the older + method. */ + av_write_frame(s, ost->index, + (UINT8 *)picture, sizeof(AVPicture)); + } else { + write_picture(s, ost->index, picture, enc->pix_fmt, + enc->width, enc->height); + } } + ost->frame_number++; } - the_end: + the_end: av_free(buf); av_free(buf1); } -static void do_video_stats(AVOutputStream *ost, - AVInputStream *ist, - int frame_size) +static void do_video_stats(AVFormatContext *os, AVOutputStream *ost, + int frame_size) { static FILE *fvstats=NULL; static INT64 total_size = 0; @@ -583,17 +632,14 @@ static void do_video_stats(AVOutputStream *ost, enc = &ost->st->codec; total_size += frame_size; if (enc->codec_type == CODEC_TYPE_VIDEO) { - frame_number = ist->frame_number; + frame_number = ost->frame_number; fprintf(fvstats, "frame= %5d q= %2d ", frame_number, enc->quality); if (do_psnr) fprintf(fvstats, "PSNR= %6.2f ", enc->psnr_y); fprintf(fvstats,"f_size= %6d ", frame_size); - /* compute min pts value */ - if (!ist->discard && ist->pts < ti) { - ti = ist->pts; - } - ti1 = (double)ti / 1000000.0; + /* compute pts value */ + ti1 = (double)ost->st->pts.val * os->pts_num / os->pts_den; if (ti1 < 0.01) ti1 = 0.01; @@ -603,9 +649,75 @@ static void do_video_stats(AVOutputStream *ost, (double)total_size / 1024, ti1, bitrate, avg_bitrate); fprintf(fvstats,"type= %s\n", enc->key_frame == 1 ? "I" : "P"); } +} + +void print_report(AVFormatContext **output_files, + AVOutputStream **ost_table, int nb_ostreams, + int is_last_report) +{ + char buf[1024]; + AVOutputStream *ost; + AVFormatContext *oc, *os; + INT64 total_size; + AVCodecContext *enc; + int frame_number, vid, i; + double bitrate, ti1, pts; + static INT64 last_time = -1; + + if (!is_last_report) { + INT64 cur_time; + /* display the report every 0.5 seconds */ + cur_time = av_gettime(); + if (last_time == -1) { + last_time = cur_time; + return; + } + if ((cur_time - last_time) < 500000) + return; + last_time = cur_time; + } + + + oc = output_files[0]; + total_size = url_ftell(&oc->pb); + + buf[0] = '\0'; + ti1 = 1e10; + vid = 0; + for(i=0;ifile_index]; + enc = &ost->st->codec; + if (!vid && enc->codec_type == CODEC_TYPE_VIDEO) { + frame_number = ost->frame_number; + sprintf(buf + strlen(buf), "frame=%5d q=%2d ", + frame_number, enc->quality); + if (do_psnr) + sprintf(buf + strlen(buf), "PSNR=%6.2f ", enc->psnr_y); + vid = 1; + } + /* compute min output value */ + pts = (double)ost->st->pts.val * os->pts_num / os->pts_den; + if ((pts < ti1) && (pts > 0)) + ti1 = pts; + } + if (ti1 < 0.01) + ti1 = 0.01; + bitrate = (double)(total_size * 8) / ti1 / 1000.0; + + sprintf(buf + strlen(buf), + "size=%8.0fkB time=%0.1f bitrate=%6.1fkbits/s", + (double)total_size / 1024, ti1, bitrate); + fprintf(stderr, "%s ", buf); + if (is_last_report) { + fprintf(stderr, "\n"); + } else { + fprintf(stderr, "\r"); + fflush(stderr); + } } /* @@ -617,12 +729,11 @@ static int av_encode(AVFormatContext **output_files, int nb_input_files, AVStreamMap *stream_maps, int nb_stream_maps) { - int ret, i, j, k, n, nb_istreams = 0, nb_ostreams = 0; + int ret, i, j, k, n, nb_istreams = 0, nb_ostreams = 0, pts_set; AVFormatContext *is, *os; AVCodecContext *codec, *icodec; AVOutputStream *ost, **ost_table = NULL; AVInputStream *ist, **ist_table = NULL; - INT64 min_pts, start_time; AVInputFile *file_table; AVFormatContext *stream_no_data; int key; @@ -669,8 +780,6 @@ static int av_encode(AVFormatContext **output_files, for(i=0;inb_streams; - if (mpeg_vcd) - os->flags |= AVF_FLAG_VCD; } if (nb_stream_maps > 0 && nb_stream_maps != nb_ostreams) { fprintf(stderr, "Number of stream maps must match number of output streams\n"); @@ -732,17 +841,6 @@ static int av_encode(AVFormatContext **output_files, } } - /* dump the stream mapping */ - fprintf(stderr, "Stream mapping:\n"); - for(i=0;i #%d.%d\n", - ist_table[ost->source_index]->file_index, - ist_table[ost->source_index]->index, - ost->file_index, - ost->index); - } - /* for each output stream, we compute the right encoding parameters */ for(i=0;ist->codec; icodec = &ist->st->codec; - switch(codec->codec_type) { - case CODEC_TYPE_AUDIO: - /* check if same codec with same parameters. If so, no - reencoding is needed */ - if (codec->codec_id == icodec->codec_id && - codec->bit_rate == icodec->bit_rate && - codec->sample_rate == icodec->sample_rate && - codec->channels == icodec->channels) { - /* no reencoding */ - /* use the same frame size */ - codec->frame_size = icodec->frame_size; - //codec->frame_size = 8*icodec->sample_rate*icodec->frame_size/ - // icodec->bit_rate; - //fprintf(stderr,"\nFrame size: %d", codec->frame_size); - } else { + if (ost->st->stream_copy) { + /* if stream_copy is selected, no need to decode or encode */ + codec->codec_id = icodec->codec_id; + codec->codec_type = icodec->codec_type; + codec->codec_tag = icodec->codec_tag; + codec->bit_rate = icodec->bit_rate; + switch(codec->codec_type) { + case CODEC_TYPE_AUDIO: + codec->sample_rate = icodec->sample_rate; + codec->channels = icodec->channels; + break; + case CODEC_TYPE_VIDEO: + codec->frame_rate = icodec->frame_rate; + codec->width = icodec->width; + codec->height = icodec->height; + break; + default: + av_abort(); + } + } else { + switch(codec->codec_type) { + case CODEC_TYPE_AUDIO: if (fifo_init(&ost->fifo, 2 * MAX_AUDIO_PACKET_SIZE)) goto fail; - + if (codec->channels == icodec->channels && codec->sample_rate == icodec->sample_rate) { ost->audio_resample = 0; @@ -798,18 +903,8 @@ static int av_encode(AVFormatContext **output_files, } ist->decoding_needed = 1; ost->encoding_needed = 1; - } - break; - case CODEC_TYPE_VIDEO: - /* check if same codec with same parameters. If so, no - reencoding is needed */ - if (codec->codec_id == icodec->codec_id && - codec->bit_rate == icodec->bit_rate && - codec->frame_rate == icodec->frame_rate && - codec->width == icodec->width && - codec->height == icodec->height) { - /* no reencoding */ - } else { + break; + case CODEC_TYPE_VIDEO: if (codec->width == icodec->width && codec->height == icodec->height) { ost->video_resample = 0; @@ -834,13 +929,69 @@ static int av_encode(AVFormatContext **output_files, } ost->encoding_needed = 1; ist->decoding_needed = 1; + break; + default: + av_abort(); + } + /* two pass mode */ + if (ost->encoding_needed && + (codec->flags & (CODEC_FLAG_PASS1 | CODEC_FLAG_PASS2))) { + char logfilename[1024]; + FILE *f; + int size; + char *logbuffer; + + snprintf(logfilename, sizeof(logfilename), "%s-%d.log", + pass_logfilename ? + pass_logfilename : DEFAULT_PASS_LOGFILENAME, i); + if (codec->flags & CODEC_FLAG_PASS1) { + f = fopen(logfilename, "w"); + if (!f) { + perror(logfilename); + exit(1); + } + ost->logfile = f; + } else { + /* read the log file */ + f = fopen(logfilename, "r"); + if (!f) { + perror(logfilename); + exit(1); + } + fseek(f, 0, SEEK_END); + size = ftell(f); + fseek(f, 0, SEEK_SET); + logbuffer = av_malloc(size + 1); + if (!logbuffer) { + fprintf(stderr, "Could not allocate log buffer\n"); + exit(1); + } + fread(logbuffer, 1, size, f); + fclose(f); + logbuffer[size] = '\0'; + codec->stats_in = logbuffer; + } } - break; - default: - av_abort(); } } + /* dump the file output parameters - cannot be done before in case + of stream copy */ + for(i=0;ifilename, 1); + } + + /* dump the stream mapping */ + fprintf(stderr, "Stream mapping:\n"); + for(i=0;i #%d.%d\n", + ist_table[ost->source_index]->file_index, + ist_table[ost->source_index]->index, + ost->file_index, + ost->index); + } + /* open each encoder */ for(i=0;ist->codec.codec_type == CODEC_TYPE_VIDEO) // ist->st->codec.flags |= CODEC_FLAG_REPEAT_FIELD; + ist->frame_decoded = 1; } } /* init pts */ for(i=0;ipts = 0; - ist->frame_number = 0; } /* compute buffer size max (should use a complete heuristic) */ @@ -912,8 +1062,6 @@ static int av_encode(AVFormatContext **output_files, #endif term_init(); - start_time = av_gettime(); - min_pts = 0; stream_no_data = 0; key = -1; @@ -926,7 +1074,8 @@ static int av_encode(AVFormatContext **output_files, int data_size, got_picture; AVPicture picture; short samples[AVCODEC_MAX_AUDIO_FRAME_SIZE / 2]; - + double pts_min; + redo: /* if 'q' pressed, exits */ if (key) { @@ -936,42 +1085,31 @@ static int av_encode(AVFormatContext **output_files, break; } - /* select the input file with the smallest pts */ + /* select the stream that we must read now by looking at the + smallest output pts */ file_index = -1; - min_pts = MAXINT64; - for(i=0;idiscard && !file_table[ist->file_index].eof_reached && - ist->pts /* + ist->pts_increment */ < min_pts && input_files[ist->file_index] != stream_no_data) { - min_pts = ist->pts /* + ist->pts_increment */; + pts_min = 1e10; + for(i=0;ifile_index]; + ist = ist_table[ost->source_index]; + pts = (double)ost->st->pts.val * os->pts_num / os->pts_den; + if (!file_table[ist->file_index].eof_reached && + pts < pts_min) { + pts_min = pts; file_index = ist->file_index; } } /* if none, if is finished */ if (file_index < 0) { - if (stream_no_data) { -#ifndef CONFIG_WIN32 /* no usleep in VisualC ? */ -#ifdef __BEOS__ - snooze(10 * 1000); /* mmu_man */ /* in microsec */ -#elif defined(__CYGWIN__) - usleep(10 * 1000); -#else - struct timespec ts; - - ts.tv_sec = 0; - ts.tv_nsec = 1000 * 1000 * 10; - nanosleep(&ts, 0); -#endif -#endif - stream_no_data = 0; - continue; - } break; - } + } + /* finish if recording time exhausted */ - if (recording_time > 0 && min_pts >= recording_time) + if (recording_time > 0 && pts_min >= (recording_time / 1000000.0)) break; + /* read a packet from it and output it in the fifo */ is = input_files[file_index]; if (av_read_packet(is, &pkt) < 0) { @@ -992,9 +1130,6 @@ static int av_encode(AVFormatContext **output_files, if (ist->discard) goto discard_packet; - if (pkt.flags & PKT_FLAG_DROPPED_FRAME) - ist->frame_number++; - if (do_hex_dump) { printf("stream #%d, size=%d:\n", pkt.stream_index, pkt.size); av_hex_dump(pkt.data, pkt.size); @@ -1004,12 +1139,28 @@ static int av_encode(AVFormatContext **output_files, len = pkt.size; ptr = pkt.data; + pts_set = 0; while (len > 0) { + INT64 ipts; + + ipts = AV_NOPTS_VALUE; /* decode the packet if needed */ data_buf = NULL; /* fail safe */ data_size = 0; if (ist->decoding_needed) { + /* NOTE1: we only take into account the PTS if a new + frame has begun (MPEG semantics) */ + /* NOTE2: even if the fraction is not initialized, + av_frac_set can be used to set the integer part */ + if (ist->frame_decoded && + pkt.pts != AV_NOPTS_VALUE && + !pts_set) { + ipts = pkt.pts; + ist->frame_decoded = 0; + pts_set = 1; + } + switch(ist->st->codec.codec_type) { case CODEC_TYPE_AUDIO: /* XXX: could avoid copy if PCM 16 bits with same @@ -1066,64 +1217,71 @@ static int av_encode(AVFormatContext **output_files, data_size = len; ret = len; } - /* init tickers */ - if (!ist->ticker_inited) { - switch (ist->st->codec.codec_type) { - case CODEC_TYPE_AUDIO: - ticker_init(&ist->pts_ticker, - (INT64)ist->st->codec.sample_rate, - (INT64)(1000000)); - ist->ticker_inited = 1; - break; - case CODEC_TYPE_VIDEO: - ticker_init(&ist->pts_ticker, - (INT64)ist->st->r_frame_rate, - ((INT64)1000000 * FRAME_RATE_BASE)); - ist->ticker_inited = 1; - break; - default: - av_abort(); - } - } - /* update pts */ - switch(ist->st->codec.codec_type) { - case CODEC_TYPE_AUDIO: - //ist->pts = (INT64)1000000 * ist->sample_index / ist->st->codec.sample_rate; - ist->pts = ticker_abs(&ist->pts_ticker, ist->sample_index); - ist->sample_index += data_size / (2 * ist->st->codec.channels); - ist->pts_increment = (INT64) (data_size / (2 * ist->st->codec.channels)) * 1000000 / ist->st->codec.sample_rate; - break; - case CODEC_TYPE_VIDEO: - ist->frame_number++; - //ist->pts = ((INT64)ist->frame_number * 1000000 * FRAME_RATE_BASE) / - // ist->st->codec.frame_rate; - ist->pts = ticker_abs(&ist->pts_ticker, ist->frame_number); - ist->pts_increment = ((INT64) 1000000 * FRAME_RATE_BASE) / - ist->st->codec.frame_rate; - break; - default: - av_abort(); - } ptr += ret; len -= ret; + ist->frame_decoded = 1; + +#if 0 + /* mpeg PTS deordering : if it is a P or I frame, the PTS + is the one of the next displayed one */ + /* XXX: add mpeg4 too ? */ + if (ist->st->codec.codec_id == CODEC_ID_MPEG1VIDEO) { + if (ist->st->codec.pict_type != B_TYPE) { + INT64 tmp; + tmp = ist->last_ip_pts; + ist->last_ip_pts = ist->frac_pts.val; + ist->frac_pts.val = tmp; + } + } +#endif /* transcode raw format, encode packets and output them */ - + for(i=0;isource_index == ist_index) { os = output_files[ost->file_index]; + if (ipts != AV_NOPTS_VALUE) { +#if 0 + printf("%d: got pts=%f %f\n", + i, pkt.pts / 90000.0, + (ipts - ost->st->pts.val) / 90000.0); +#endif + /* set the input output pts pairs */ + ost->sync_ipts = (double)ipts * is->pts_num / + is->pts_den; + /* XXX: take into account the various fifos, + in particular for audio */ + ost->sync_opts = ost->st->pts.val; + } + if (ost->encoding_needed) { switch(ost->st->codec.codec_type) { case CODEC_TYPE_AUDIO: do_audio_out(os, ost, ist, data_buf, data_size); break; case CODEC_TYPE_VIDEO: - do_video_out(os, ost, ist, &picture, &frame_size); - if (do_vstats) - do_video_stats(ost, ist, frame_size); + /* find an audio stream for synchro */ + { + int i; + AVOutputStream *audio_sync, *ost1; + audio_sync = NULL; + for(i=0;ifile_index == ost->file_index && + ost1->st->codec.codec_type == CODEC_TYPE_AUDIO) { + audio_sync = ost1; + break; + } + } + + do_video_out(os, ost, ist, &picture, &frame_size, audio_sync); + if (do_vstats) + do_video_stats(os, ost, frame_size); + } break; default: av_abort(); @@ -1131,117 +1289,29 @@ static int av_encode(AVFormatContext **output_files, } else { /* no reencoding needed : output the packet directly */ /* force the input stream PTS */ - os->oformat->write_packet(os, ost->index, data_buf, data_size, pkt.pts); + av_write_frame(os, ost->index, data_buf, data_size); + ost->st->codec.frame_number++; } } } + ipts = AV_NOPTS_VALUE; } discard_packet: av_free_packet(&pkt); - /* dump report by using the first video and audio streams */ - { - char buf[1024]; - AVFormatContext *oc; - INT64 total_size, ti; - AVCodecContext *enc; - int frame_number, vid; - double bitrate, ti1; - static INT64 last_time; - - if ((min_pts - last_time) >= 500000) { - last_time = min_pts; - - oc = output_files[0]; - - total_size = url_ftell(&oc->pb); - - buf[0] = '\0'; - ti = MAXINT64; - vid = 0; - for(i=0;ist->codec; - ist = ist_table[ost->source_index]; - if (!vid && enc->codec_type == CODEC_TYPE_VIDEO) { - frame_number = ist->frame_number; - sprintf(buf + strlen(buf), "frame=%5d q=%2d ", - frame_number, enc->quality); - if (do_psnr) - sprintf(buf + strlen(buf), "PSNR=%6.2f ", enc->psnr_y); - vid = 1; - } - /* compute min pts value */ - if (!ist->discard && ist->pts < ti) { - ti = ist->pts; - } - } - - ti1 = (double)ti / 1000000.0; - if (ti1 < 0.01) - ti1 = 0.01; - bitrate = (double)(total_size * 8) / ti1 / 1000.0; - - sprintf(buf + strlen(buf), - "size=%8.0fkB time=%0.1f bitrate=%6.1fkbits/s", - (double)total_size / 1024, ti1, bitrate); - - fprintf(stderr, "%s \r", buf); - fflush(stderr); - } - } + /* dump report by using the output first video and audio streams */ + print_report(output_files, ost_table, nb_ostreams, 0); } term_exit(); /* dump report by using the first video and audio streams */ - { - char buf[1024]; - AVFormatContext *oc; - INT64 total_size, ti; - AVCodecContext *enc; - int frame_number, vid; - double bitrate, ti1; - - oc = output_files[0]; - - total_size = url_ftell(&oc->pb); - - buf[0] = '\0'; - ti = MAXINT64; - vid = 0; - for(i=0;ist->codec; - ist = ist_table[ost->source_index]; - if (!vid && enc->codec_type == CODEC_TYPE_VIDEO) { - frame_number = ist->frame_number; - sprintf(buf + strlen(buf), "frame=%5d q=%2d ", - frame_number, enc->quality); - if (do_psnr) - sprintf(buf + strlen(buf), "PSNR=%6.2f ", enc->psnr_y); - vid = 1; - } - /* compute min pts value */ - if (!ist->discard && ist->pts < ti) { - ti = ist->pts; - } - } - - ti1 = ti / 1000000.0; - if (ti1 < 0.01) - ti1 = 0.01; - bitrate = (double)(total_size * 8) / ti1 / 1000.0; - - sprintf(buf + strlen(buf), - "size=%8.0fkB time=%0.1f bitrate=%6.1fkbits/s", - (double)total_size / 1024, ti1, bitrate); - - fprintf(stderr, "%s \n", buf); - } + print_report(output_files, ost_table, nb_ostreams, 1); + /* close each encoder */ for(i=0;iencoding_needed) { + av_freep(&ost->st->codec.stats_in); avcodec_close(&ost->st->codec); } } @@ -1277,6 +1347,10 @@ static int av_encode(AVFormatContext **output_files, for(i=0;ilogfile) { + fclose(ost->logfile); + ost->logfile = NULL; + } fifo_free(&ost->fifo); /* works even if fifo is not initialized but set to zero */ av_free(ost->pict_tmp.data[0]); @@ -1369,11 +1443,21 @@ void opt_video_bitrate_min(const char *arg) video_rc_min_rate = atoi(arg) * 1000; } +void opt_video_buffer_size(const char *arg) +{ + video_rc_buffer_size = atoi(arg) * 1000; +} + void opt_video_rc_eq(char *arg) { video_rc_eq = arg; } +void opt_video_rc_override_string(char *arg) +{ + video_rc_override_string = arg; +} + void opt_workaround_bugs(const char *arg) { @@ -1385,11 +1469,23 @@ void opt_dct_algo(const char *arg) dct_algo = atoi(arg); } +void opt_idct_algo(const char *arg) +{ + idct_algo = atoi(arg); +} + + void opt_error_resilience(const char *arg) { error_resilience = atoi(arg); } +void opt_error_concealment(const char *arg) +{ + error_concealment = atoi(arg); +} + + void opt_frame_rate(const char *arg) { frame_rate = (int)(strtod(arg, 0) * FRAME_RATE_BASE); @@ -1548,6 +1644,32 @@ void opt_qcomp(const char *arg) video_qcomp = atof(arg); } +void opt_rc_initial_cplx(const char *arg) +{ + video_rc_initial_cplx = atof(arg); +} +void opt_b_qfactor(const char *arg) +{ + video_b_qfactor = atof(arg); +} +void opt_i_qfactor(const char *arg) +{ + video_i_qfactor = atof(arg); +} +void opt_b_qoffset(const char *arg) +{ + video_b_qoffset = atof(arg); +} +void opt_i_qoffset(const char *arg) +{ + video_i_qoffset = atof(arg); +} + +void opt_packet_size(const char *arg) +{ + packet_size= atoi(arg); +} + void opt_audio_bitrate(const char *arg) { audio_bit_rate = atoi(arg) * 1000; @@ -1577,17 +1699,21 @@ void opt_audio_codec(const char *arg) { AVCodec *p; - p = first_avcodec; - while (p) { - if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO) - break; - p = p->next; - } - if (p == NULL) { - fprintf(stderr, "Unknown audio codec '%s'\n", arg); - exit(1); + if (!strcmp(arg, "copy")) { + audio_stream_copy = 1; } else { - audio_codec_id = p->id; + p = first_avcodec; + while (p) { + if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO) + break; + p = p->next; + } + if (p == NULL) { + fprintf(stderr, "Unknown audio codec '%s'\n", arg); + exit(1); + } else { + audio_codec_id = p->id; + } } } @@ -1621,17 +1747,21 @@ void opt_video_codec(const char *arg) { AVCodec *p; - p = first_avcodec; - while (p) { - if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO) - break; - p = p->next; - } - if (p == NULL) { - fprintf(stderr, "Unknown video codec '%s'\n", arg); - exit(1); + if (!strcmp(arg, "copy")) { + video_stream_copy = 1; } else { - video_codec_id = p->id; + p = first_avcodec; + while (p) { + if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO) + break; + p = p->next; + } + if (p == NULL) { + fprintf(stderr, "Unknown video codec '%s'\n", arg); + exit(1); + } else { + video_codec_id = p->id; + } } } @@ -1721,6 +1851,8 @@ void opt_input_file(const char *filename) rfps = ic->streams[i]->r_frame_rate; enc->workaround_bugs = workaround_bugs; enc->error_resilience = error_resilience; + enc->error_concealment = error_concealment; + enc->idct_algo= idct_algo; if (enc->frame_rate != rfps) { fprintf(stderr,"\nSeems that stream %d comes from film source: %2.2f->%2.2f\n", i, (float)enc->frame_rate / FRAME_RATE_BASE, @@ -1831,76 +1963,129 @@ void opt_output_file(const char *filename) fprintf(stderr, "Could not alloc stream\n"); exit(1); } - video_enc = &st->codec; - - codec_id = file_oformat->video_codec; - if (video_codec_id != CODEC_ID_NONE) - codec_id = video_codec_id; - video_enc->codec_id = codec_id; - video_enc->codec_type = CODEC_TYPE_VIDEO; + video_enc = &st->codec; + if (video_stream_copy) { + st->stream_copy = 1; + video_enc->codec_type = CODEC_TYPE_VIDEO; + } else { + char *p; + int i; - video_enc->bit_rate = video_bit_rate; - video_enc->bit_rate_tolerance = video_bit_rate_tolerance; - video_enc->frame_rate = frame_rate; + codec_id = file_oformat->video_codec; + if (video_codec_id != CODEC_ID_NONE) + codec_id = video_codec_id; + + video_enc->codec_id = codec_id; + + video_enc->bit_rate = video_bit_rate; + video_enc->bit_rate_tolerance = video_bit_rate_tolerance; + video_enc->frame_rate = frame_rate; + + video_enc->width = frame_width; + video_enc->height = frame_height; + + if (!intra_only) + video_enc->gop_size = gop_size; + else + video_enc->gop_size = 0; + if (video_qscale || same_quality) { + video_enc->flags |= CODEC_FLAG_QSCALE; + video_enc->quality = video_qscale; + } - video_enc->width = frame_width; - video_enc->height = frame_height; - if (!intra_only) - video_enc->gop_size = gop_size; - else - video_enc->gop_size = 0; - if (video_qscale || same_quality) { - video_enc->flags |= CODEC_FLAG_QSCALE; - video_enc->quality = video_qscale; - } + if (use_hq) { + video_enc->flags |= CODEC_FLAG_HQ; + } - if (use_hq) { - video_enc->flags |= CODEC_FLAG_HQ; - } + if (use_4mv) { + video_enc->flags |= CODEC_FLAG_HQ; + video_enc->flags |= CODEC_FLAG_4MV; + } - if (use_4mv) { - video_enc->flags |= CODEC_FLAG_HQ; - video_enc->flags |= CODEC_FLAG_4MV; - } + if(use_part) + video_enc->flags |= CODEC_FLAG_PART; + - if (b_frames) { - if (codec_id != CODEC_ID_MPEG4) { - fprintf(stderr, "\nB frames encoding only supported by MPEG-4.\n"); - exit(1); + if (b_frames) { + if (codec_id != CODEC_ID_MPEG4) { + fprintf(stderr, "\nB frames encoding only supported by MPEG-4.\n"); + exit(1); + } + video_enc->max_b_frames = b_frames; + video_enc->b_frame_strategy = 0; + video_enc->b_quant_factor = 2.0; } - video_enc->max_b_frames = b_frames; - video_enc->b_frame_strategy = 0; - video_enc->b_quant_factor = 2.0; - } - video_enc->qmin = video_qmin; - video_enc->qmax = video_qmax; - video_enc->max_qdiff = video_qdiff; - video_enc->qblur = video_qblur; - video_enc->qcompress = video_qcomp; - video_enc->rc_eq = video_rc_eq; - video_enc->rc_max_rate = video_rc_max_rate; - video_enc->rc_min_rate = video_rc_min_rate; - video_enc->rc_buffer_size = video_rc_buffer_size; - video_enc->i_quant_factor = video_i_qfactor; - video_enc->b_quant_factor = video_b_qfactor; - video_enc->i_quant_offset = video_i_qoffset; - video_enc->b_quant_offset = video_b_qoffset; - video_enc->dct_algo = dct_algo; + video_enc->qmin = video_qmin; + video_enc->qmax = video_qmax; + video_enc->max_qdiff = video_qdiff; + video_enc->qblur = video_qblur; + video_enc->qcompress = video_qcomp; + video_enc->rc_eq = video_rc_eq; + + p= video_rc_override_string; + for(i=0; p; i++){ + int start, end, q; + int e=sscanf(p, "%d,%d,%d", &start, &end, &q); + if(e!=3){ + fprintf(stderr, "error parsing rc_override\n"); + exit(1); + } + video_enc->rc_override= + realloc(video_enc->rc_override, sizeof(RcOverride)*(i+1)); + video_enc->rc_override[i].start_frame= start; + video_enc->rc_override[i].end_frame = end; + if(q>0){ + video_enc->rc_override[i].qscale= q; + video_enc->rc_override[i].quality_factor= 1.0; + } + else{ + video_enc->rc_override[i].qscale= 0; + video_enc->rc_override[i].quality_factor= -q/100.0; + } + p= strchr(p, '/'); + if(p) p++; + } + video_enc->rc_override_count=i; + + video_enc->rc_max_rate = video_rc_max_rate; + video_enc->rc_min_rate = video_rc_min_rate; + video_enc->rc_buffer_size = video_rc_buffer_size; + video_enc->rc_buffer_aggressivity= video_rc_buffer_aggressivity; + video_enc->rc_initial_cplx= video_rc_initial_cplx; + video_enc->i_quant_factor = video_i_qfactor; + video_enc->b_quant_factor = video_b_qfactor; + video_enc->i_quant_offset = video_i_qoffset; + video_enc->b_quant_offset = video_b_qoffset; + video_enc->dct_algo = dct_algo; + video_enc->idct_algo = idct_algo; + if(packet_size){ + video_enc->rtp_mode= 1; + video_enc->rtp_payload_size= packet_size; + } - if (do_psnr) - video_enc->get_psnr = 1; - else - video_enc->get_psnr = 0; + if (do_psnr) + video_enc->get_psnr = 1; + else + video_enc->get_psnr = 0; - video_enc->me_method = me_method; + video_enc->me_method = me_method; + + /* two pass mode */ + if (do_pass) { + if (do_pass == 1) { + video_enc->flags |= CODEC_FLAG_PASS1; + } else { + video_enc->flags |= CODEC_FLAG_PASS2; + } + } - /* XXX: need to find a way to set codec parameters */ - if (oc->oformat->flags & AVFMT_RGB24) { - video_enc->pix_fmt = PIX_FMT_RGB24; + /* XXX: need to find a way to set codec parameters */ + if (oc->oformat->flags & AVFMT_RGB24) { + video_enc->pix_fmt = PIX_FMT_RGB24; + } } - oc->streams[nb_streams] = st; nb_streams++; } @@ -1913,21 +2098,26 @@ void opt_output_file(const char *filename) fprintf(stderr, "Could not alloc stream\n"); exit(1); } + audio_enc = &st->codec; - codec_id = file_oformat->audio_codec; - if (audio_codec_id != CODEC_ID_NONE) - codec_id = audio_codec_id; - audio_enc->codec_id = codec_id; audio_enc->codec_type = CODEC_TYPE_AUDIO; - - audio_enc->bit_rate = audio_bit_rate; - audio_enc->sample_rate = audio_sample_rate; - /* For audio codecs other than AC3 we limit */ - /* the number of coded channels to stereo */ - if (audio_channels > 2 && codec_id != CODEC_ID_AC3) { - audio_enc->channels = 2; - } else - audio_enc->channels = audio_channels; + if (audio_stream_copy) { + st->stream_copy = 1; + } else { + codec_id = file_oformat->audio_codec; + if (audio_codec_id != CODEC_ID_NONE) + codec_id = audio_codec_id; + audio_enc->codec_id = codec_id; + + audio_enc->bit_rate = audio_bit_rate; + audio_enc->sample_rate = audio_sample_rate; + /* For audio codecs other than AC3 we limit */ + /* the number of coded channels to stereo */ + if (audio_channels > 2 && codec_id != CODEC_ID_AC3) { + audio_enc->channels = 2; + } else + audio_enc->channels = audio_channels; + } oc->streams[nb_streams] = st; nb_streams++; } @@ -1949,10 +2139,7 @@ void opt_output_file(const char *filename) pstrcpy(oc->comment, sizeof(oc->comment), str_comment); } - output_files[nb_output_files] = oc; - /* dump the file content */ - dump_format(oc, nb_output_files, filename, 1); - nb_output_files++; + output_files[nb_output_files++] = oc; strcpy(oc->filename, filename); @@ -1996,6 +2183,8 @@ void opt_output_file(const char *filename) video_disable = 0; audio_codec_id = CODEC_ID_NONE; video_codec_id = CODEC_ID_NONE; + audio_stream_copy = 0; + video_stream_copy = 0; } /* prepare dummy protocols for grab */ @@ -2081,6 +2270,17 @@ void prepare_play(void) opt_output_file(audio_device); } +/* same option as mencoder */ +void opt_pass(const char *pass_str) +{ + int pass; + pass = atoi(pass_str); + if (pass != 1 && pass != 2) { + fprintf(stderr, "pass number can be only 1 or 2\n"); + exit(1); + } + do_pass = pass; +} #ifndef CONFIG_WIN32 INT64 getutime(void) @@ -2209,7 +2409,6 @@ const OptionDef options[] = { { "h", 0, {(void*)show_help}, "show help" }, { "formats", 0, {(void*)show_formats}, "show available formats, codecs, protocols, ..." }, { "f", HAS_ARG, {(void*)opt_format}, "force format", "fmt" }, - { "vcd", OPT_BOOL, {(void*)&mpeg_vcd}, "output Video CD MPEG-PS compliant file" }, { "i", HAS_ARG, {(void*)opt_input_file}, "input file name", "filename" }, { "y", OPT_BOOL, {(void*)&file_overwrite}, "overwrite output files" }, { "map", HAS_ARG | OPT_EXPERT, {(void*)opt_map}, "set input stream mapping", "file:stream" }, @@ -2218,6 +2417,8 @@ const OptionDef options[] = { { "author", HAS_ARG | OPT_STRING, {(void*)&str_author}, "set the author", "string" }, { "copyright", HAS_ARG | OPT_STRING, {(void*)&str_copyright}, "set the copyright", "string" }, { "comment", HAS_ARG | OPT_STRING, {(void*)&str_comment}, "set the comment", "string" }, + { "pass", HAS_ARG, {(void*)&opt_pass}, "select the pass number (1 or 2)", "n" }, + { "passlogfile", HAS_ARG | OPT_STRING, {(void*)&pass_logfilename}, "select two pass log file name", "file" }, /* video options */ { "b", HAS_ARG, {(void*)opt_video_bitrate}, "set video bitrate (in kbit/s)", "bitrate" }, { "r", HAS_ARG, {(void*)opt_frame_rate}, "set frame rate (in Hz)", "rate" }, @@ -2235,20 +2436,31 @@ const OptionDef options[] = { { "qdiff", HAS_ARG | OPT_EXPERT, {(void*)opt_qdiff}, "max difference between the quantiser scale (VBR)", "q" }, { "qblur", HAS_ARG | OPT_EXPERT, {(void*)opt_qblur}, "video quantiser scale blur (VBR)", "blur" }, { "qcomp", HAS_ARG | OPT_EXPERT, {(void*)opt_qcomp}, "video quantiser scale compression (VBR)", "compression" }, + { "rc_init_cplx", HAS_ARG | OPT_EXPERT, {(void*)opt_rc_initial_cplx}, "initial complexity for 1-pass encoding", "complexity" }, + { "b_qfactor", HAS_ARG | OPT_EXPERT, {(void*)opt_b_qfactor}, "qp factor between p and b frames", "factor" }, + { "i_qfactor", HAS_ARG | OPT_EXPERT, {(void*)opt_i_qfactor}, "qp factor between p and i frames", "factor" }, + { "b_qoffset", HAS_ARG | OPT_EXPERT, {(void*)opt_b_qoffset}, "qp offset between p and b frames", "offset" }, + { "i_qoffset", HAS_ARG | OPT_EXPERT, {(void*)opt_i_qoffset}, "qp offset between p and i frames", "offset" }, { "rc_eq", HAS_ARG | OPT_EXPERT, {(void*)opt_video_rc_eq}, "", "equation" }, + { "rc_override", HAS_ARG | OPT_EXPERT, {(void*)opt_video_rc_override_string}, "Rate control override", "qualities for specific intervals" }, { "bt", HAS_ARG, {(void*)opt_video_bitrate_tolerance}, "set video bitrate tolerance (in kbit/s)", "tolerance" }, { "maxrate", HAS_ARG, {(void*)opt_video_bitrate_max}, "set max video bitrate tolerance (in kbit/s)", "bitrate" }, { "minrate", HAS_ARG, {(void*)opt_video_bitrate_min}, "set min video bitrate tolerance (in kbit/s)", "bitrate" }, + { "bufsize", HAS_ARG, {(void*)opt_video_buffer_size}, "set ratecontrol buffere size (in kbit)", "size" }, { "vd", HAS_ARG | OPT_EXPERT, {(void*)opt_video_device}, "set video grab device", "device" }, - { "vcodec", HAS_ARG | OPT_EXPERT, {(void*)opt_video_codec}, "force video codec", "codec" }, + { "vcodec", HAS_ARG | OPT_EXPERT, {(void*)opt_video_codec}, "force video codec ('copy' to copy stream)", "codec" }, { "me", HAS_ARG | OPT_EXPERT, {(void*)opt_motion_estimation}, "set motion estimation method", "method" }, { "dct_algo", HAS_ARG | OPT_EXPERT, {(void*)opt_dct_algo}, "set dct algo", "algo" }, + { "idct_algo", HAS_ARG | OPT_EXPERT, {(void*)opt_idct_algo}, "set idct algo", "algo" }, { "er", HAS_ARG | OPT_EXPERT, {(void*)opt_error_resilience}, "set error resilience", "" }, + { "ec", HAS_ARG | OPT_EXPERT, {(void*)opt_error_resilience}, "set error concealment", "" }, { "bf", HAS_ARG | OPT_EXPERT, {(void*)opt_b_frames}, "use 'frames' B frames (only MPEG-4)", "frames" }, { "hq", OPT_BOOL | OPT_EXPERT, {(void*)&use_hq}, "activate high quality settings" }, { "4mv", OPT_BOOL | OPT_EXPERT, {(void*)&use_4mv}, "use four motion vector by macroblock (only MPEG-4)" }, + { "part", OPT_BOOL | OPT_EXPERT, {(void*)&use_part}, "use data partitioning (only MPEG-4)" }, { "bug", HAS_ARG | OPT_EXPERT, {(void*)opt_workaround_bugs}, "workaround not auto detected encoder bugs", "param" }, + { "ps", HAS_ARG | OPT_EXPERT, {(void*)opt_packet_size}, "packet size", "size in bits" }, { "sameq", OPT_BOOL, {(void*)&same_quality}, "use same video quality as source (implies VBR)" }, /* audio options */ @@ -2257,7 +2469,7 @@ const OptionDef options[] = { { "ac", HAS_ARG, {(void*)opt_audio_channels}, "set number of audio channels", "channels" }, { "an", OPT_BOOL, {(void*)&audio_disable}, "disable audio" }, { "ad", HAS_ARG | OPT_EXPERT, {(void*)opt_audio_device}, "set audio device", "device" }, - { "acodec", HAS_ARG | OPT_EXPERT, {(void*)opt_audio_codec}, "force audio codec", "codec" }, + { "acodec", HAS_ARG | OPT_EXPERT, {(void*)opt_audio_codec}, "force audio codec ('copy' to copy stream)", "codec" }, { "deinterlace", OPT_BOOL | OPT_EXPERT, {(void*)&do_deinterlace}, "deinterlace pictures" }, { "benchmark", OPT_BOOL | OPT_EXPERT, {(void*)&do_benchmark},