X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ffmpeg.c;h=ff782d285e260485dd134d07bde0432dea614b8c;hb=890972be037a2deab8a39680087bf0c9ad533e90;hp=94abd74948d9ab2339e5efb1d7bacbbeaf64e270;hpb=5b685a7a76d184af8d4b9d213c9ba4a3c0b52542;p=ffmpeg diff --git a/ffmpeg.c b/ffmpeg.c index 94abd74948d..ff782d285e2 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -17,11 +17,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define HAVE_AV_CONFIG_H -#include "common.h" #include "avformat.h" #include "framehook.h" -/* usleep() */ -#include "os_support.h" #ifndef CONFIG_WIN32 #include @@ -38,7 +35,6 @@ #include #endif #include -#include #include "cmdutils.h" @@ -54,7 +50,8 @@ typedef struct AVStreamMap { extern const OptionDef options[]; -void show_help(void); +static void show_help(void); +static void show_license(void); #define MAX_FILES 20 @@ -82,7 +79,7 @@ static int frame_rate = 25; static int frame_rate_base = 1; static int video_bit_rate = 200*1000; static int video_bit_rate_tolerance = 4000*1000; -static int video_qscale = 0; +static float video_qscale = 0; static int video_qmin = 2; static int video_qmax = 31; static int video_mb_qmin = 2; @@ -90,6 +87,8 @@ static int video_mb_qmax = 31; static int video_qdiff = 3; static float video_qblur = 0.5; static float video_qcomp = 0.5; +static uint16_t *intra_matrix = NULL; +static uint16_t *inter_matrix = NULL; #if 0 //experimental, (can be removed) static float video_rc_qsquish=1.0; static float video_rc_qmod_amp=0; @@ -112,12 +111,16 @@ static int video_codec_id = CODEC_ID_NONE; static int same_quality = 0; static int b_frames = 0; static int mb_decision = FF_MB_DECISION_SIMPLE; +static int mb_cmp = FF_CMP_SAD; +static int sub_cmp = FF_CMP_SAD; +static int cmp = FF_CMP_SAD; static int use_4mv = 0; -/* Fx */ +static int use_obmc = 0; static int use_aic = 0; +static int use_aiv = 0; static int use_umv = 0; -/* /Fx */ static int do_deinterlace = 0; +static int do_interlace = 0; static int workaround_bugs = FF_BUG_AUTODETECT; static int error_resilience = 2; static int error_concealment = 3; @@ -125,8 +128,10 @@ static int dct_algo = 0; static int idct_algo = 0; static int use_part = 0; static int packet_size = 0; +static int error_rate = 0; static int strict = 0; static int debug = 0; +extern int loop_input; /* currently a hack */ static int gop_size = 12; static int intra_only = 0; @@ -137,6 +142,7 @@ static int audio_channels = 1; static int audio_codec_id = CODEC_ID_NONE; static int64_t recording_time = 0; +static int64_t start_time = 0; static int file_overwrite = 0; static char *str_title = NULL; static char *str_author = NULL; @@ -144,6 +150,7 @@ static char *str_copyright = NULL; static char *str_comment = NULL; static int do_benchmark = 0; static int do_hex_dump = 0; +static int do_pkt_dump = 0; static int do_psnr = 0; static int do_vstats = 0; static int do_pass = 0; @@ -162,6 +169,10 @@ static char *video_standard = "ntsc"; static char *audio_grab_format = "audio_device"; static char *audio_device = NULL; +static int using_stdin = 0; +static int using_vhook = 0; +static int verbose = 1; + #define DEFAULT_PASS_LOGFILENAME "ffmpeg2pass" typedef struct AVOutputStream { @@ -199,11 +210,11 @@ typedef struct AVInputStream { int discard; /* true if stream data should be discarded */ int decoding_needed; /* true if the packets must be decoded in 'raw_fifo' */ int64_t sample_index; /* current sample */ - int frame_decoded; /* true if a video or audio frame has been decoded */ int64_t start; /* time when read started */ unsigned long frame; /* current frame */ - AVFrac next_pts; /* synthetic pts for cases where pkt.pts == 0 */ + int64_t next_pts; /* synthetic pts for cases where pkt.pts + is not defined */ int64_t pts; /* current pts */ } AVInputStream; @@ -292,6 +303,8 @@ static int read_key(void) #else +static volatile int received_sigterm = 0; + /* no interactive support */ static void term_exit(void) { @@ -410,7 +423,7 @@ static void pre_process_video_frame(AVInputStream *ist, AVPicture *picture, void dec = &ist->st->codec; /* deinterlace : must be done before any resize */ - if (do_deinterlace) { + if (do_deinterlace || using_vhook) { int size; /* create temporary picture */ @@ -422,12 +435,22 @@ static void pre_process_video_frame(AVInputStream *ist, AVPicture *picture, void picture2 = &picture_tmp; avpicture_fill(picture2, buf, dec->pix_fmt, dec->width, dec->height); - if (avpicture_deinterlace(picture2, picture, - dec->pix_fmt, dec->width, dec->height) < 0) { - /* if error, do not deinterlace */ - av_free(buf); - buf = NULL; - picture2 = picture; + if (do_deinterlace){ + if(avpicture_deinterlace(picture2, picture, + dec->pix_fmt, dec->width, dec->height) < 0) { + /* if error, do not deinterlace */ + av_free(buf); + buf = NULL; + picture2 = picture; + } + } else { + if (img_convert(picture2, dec->pix_fmt, picture, + dec->pix_fmt, dec->width, dec->height) < 0) { + /* if error, do not copy */ + av_free(buf); + buf = NULL; + picture2 = picture; + } } } else { picture2 = picture; @@ -446,7 +469,7 @@ static void pre_process_video_frame(AVInputStream *ist, AVPicture *picture, void static void do_video_out(AVFormatContext *s, AVOutputStream *ost, AVInputStream *ist, - AVPicture *in_picture, + AVFrame *in_picture, int *frame_size, AVOutputStream *audio_sync) { int nb_frames, i, ret; @@ -455,6 +478,7 @@ static void do_video_out(AVFormatContext *s, static uint8_t *video_buffer; uint8_t *buf = NULL, *buf1 = NULL; AVCodecContext *enc, *dec; + enum PixelFormat target_pixfmt; #define VIDEO_BUFFER_SIZE (1024*1024) @@ -502,15 +526,17 @@ static void do_video_out(AVFormatContext *s, } #if defined(AVSYNC_DEBUG) - static char *action[] = { "drop frame", "copy frame", "dup frame" }; - if (audio_sync) - fprintf(stderr, "Input APTS %12.6f, output APTS %12.6f, ", - (double) audio_sync->sync_ipts, - (double) audio_sync->st->pts.val * s->pts_num / s->pts_den); - fprintf(stderr, "Input VPTS %12.6f, output VPTS %12.6f: %s\n", - (double) ost->sync_ipts, - (double) ost->st->pts.val * s->pts_num / s->pts_den, - action[nb_frames]); + { + static char *action[] = { "drop frame", "copy frame", "dup frame" }; + if (audio_sync) + fprintf(stderr, "Input APTS %12.6f, output APTS %12.6f, ", + (double) audio_sync->sync_ipts, + (double) audio_sync->st->pts.val * s->pts_num / s->pts_den); + fprintf(stderr, "Input VPTS %12.6f, output VPTS %12.6f: %s\n", + (double) ost->sync_ipts, + (double) ost->st->pts.val * s->pts_num / s->pts_den, + action[nb_frames]); + } #endif if (nb_frames <= 0) @@ -522,25 +548,26 @@ static void do_video_out(AVFormatContext *s, return; /* convert pixel format if needed */ - if (enc->pix_fmt != dec->pix_fmt) { + target_pixfmt = ost->video_resample ? PIX_FMT_YUV420P : enc->pix_fmt; + if (dec->pix_fmt != target_pixfmt) { int size; /* create temporary picture */ - size = avpicture_get_size(enc->pix_fmt, dec->width, dec->height); + size = avpicture_get_size(target_pixfmt, dec->width, dec->height); buf = av_malloc(size); if (!buf) return; formatted_picture = &picture_format_temp; - avpicture_fill(formatted_picture, buf, enc->pix_fmt, dec->width, dec->height); + avpicture_fill(formatted_picture, buf, target_pixfmt, dec->width, dec->height); - if (img_convert(formatted_picture, enc->pix_fmt, - in_picture, dec->pix_fmt, + if (img_convert(formatted_picture, target_pixfmt, + (AVPicture *)in_picture, dec->pix_fmt, dec->width, dec->height) < 0) { fprintf(stderr, "pixel format conversion not handled\n"); goto the_end; } } else { - formatted_picture = in_picture; + formatted_picture = (AVPicture *)in_picture; } /* XXX: resampling could be done before raw format convertion in @@ -549,6 +576,25 @@ static void do_video_out(AVFormatContext *s, if (ost->video_resample) { final_picture = &ost->pict_tmp; img_resample(ost->img_resample_ctx, final_picture, formatted_picture); + if (enc->pix_fmt != PIX_FMT_YUV420P) { + int size; + + av_free(buf); + /* create temporary picture */ + size = avpicture_get_size(enc->pix_fmt, enc->width, enc->height); + buf = av_malloc(size); + if (!buf) + return; + final_picture = &picture_format_temp; + avpicture_fill(final_picture, buf, enc->pix_fmt, enc->width, enc->height); + + if (img_convert(final_picture, enc->pix_fmt, + &ost->pict_tmp, PIX_FMT_YUV420P, + enc->width, enc->height) < 0) { + fprintf(stderr, "pixel format conversion not handled\n"); + goto the_end; + } + } } else if (ost->video_crop) { picture_crop_temp.data[0] = formatted_picture->data[0] + (ost->topBand * formatted_picture->linesize[0]) + ost->leftBand; @@ -575,14 +621,21 @@ static void do_video_out(AVFormatContext *s, /* raw pictures are written as AVPicture structure to avoid any copies. We support temorarily the older method. */ + AVFrame* old_frame = enc->coded_frame; + enc->coded_frame = dec->coded_frame; av_write_frame(s, ost->index, (uint8_t *)final_picture, sizeof(AVPicture)); + enc->coded_frame = old_frame; } else { AVFrame big_picture; memset(&big_picture, 0, sizeof(AVFrame)); *(AVPicture*)&big_picture= *final_picture; - + /* better than nothing: use input picture interlaced + settings */ + big_picture.interlaced_frame = in_picture->interlaced_frame; + big_picture.top_field_first = in_picture->top_field_first; + /* handles sameq here. This is not correct because it may not be a global option */ if (same_quality) { @@ -647,7 +700,7 @@ static void do_video_stats(AVFormatContext *os, AVOutputStream *ost, total_size += frame_size; if (enc->codec_type == CODEC_TYPE_VIDEO) { frame_number = ost->frame_number; - fprintf(fvstats, "frame= %5d q= %2.1f ", frame_number, enc->coded_frame->quality); + fprintf(fvstats, "frame= %5d q= %2.1f ", frame_number, enc->coded_frame->quality/(float)FF_QP2LAMBDA); if (enc->flags&CODEC_FLAG_PSNR) fprintf(fvstats, "PSNR= %6.2f ", psnr(enc->coded_frame->error[0]/(enc->width*enc->height*255.0*255.0))); @@ -705,14 +758,35 @@ static void print_report(AVFormatContext **output_files, enc = &ost->st->codec; if (vid && enc->codec_type == CODEC_TYPE_VIDEO) { sprintf(buf + strlen(buf), "q=%2.1f ", - enc->coded_frame->quality); + enc->coded_frame->quality/(float)FF_QP2LAMBDA); } if (!vid && enc->codec_type == CODEC_TYPE_VIDEO) { frame_number = ost->frame_number; sprintf(buf + strlen(buf), "frame=%5d q=%2.1f ", - frame_number, enc->coded_frame ? enc->coded_frame->quality : 0); - if (enc->flags&CODEC_FLAG_PSNR) - sprintf(buf + strlen(buf), "PSNR= %6.2f ", psnr(enc->coded_frame->error[0]/(enc->width*enc->height*255.0*255.0))); + frame_number, enc->coded_frame ? enc->coded_frame->quality/(float)FF_QP2LAMBDA : 0); + if(is_last_report) + sprintf(buf + strlen(buf), "L"); + if (enc->flags&CODEC_FLAG_PSNR){ + int j; + double error, error_sum=0; + double scale, scale_sum=0; + char type[3]= {'Y','U','V'}; + sprintf(buf + strlen(buf), "PSNR="); + for(j=0; j<3; j++){ + if(is_last_report){ + error= enc->error[j]; + scale= enc->width*enc->height*255.0*255.0*frame_number; + }else{ + error= enc->coded_frame->error[j]; + scale= enc->width*enc->height*255.0*255.0; + } + if(j) scale/=4; + error_sum += error; + scale_sum += scale; + sprintf(buf + strlen(buf), "%c:%2.2f ", type[j], psnr(error/scale)); + } + sprintf(buf + strlen(buf), "*:%2.2f ", psnr(error_sum/scale_sum)); + } vid = 1; } /* compute min output value */ @@ -722,22 +796,213 @@ static void print_report(AVFormatContext **output_files, } if (ti1 < 0.01) ti1 = 0.01; - bitrate = (double)(total_size * 8) / ti1 / 1000.0; - sprintf(buf + strlen(buf), + if (verbose || is_last_report) { + 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, "%s \r", buf); + fflush(stderr); + } + + if (is_last_report) fprintf(stderr, "\n"); +} + +/* pkt = NULL means EOF (needed to flush decoder buffers) */ +static int output_packet(AVInputStream *ist, int ist_index, + AVOutputStream **ost_table, int nb_ostreams, + AVPacket *pkt) +{ + AVFormatContext *os; + AVOutputStream *ost; + uint8_t *ptr; + int len, ret, i; + uint8_t *data_buf; + int data_size, got_picture; + AVFrame picture; + short samples[AVCODEC_MAX_AUDIO_FRAME_SIZE / 2]; + void *buffer_to_free; + + if (pkt && pkt->pts != AV_NOPTS_VALUE) { + ist->pts = pkt->pts; } else { - fprintf(stderr, "\r"); - fflush(stderr); + ist->pts = ist->next_pts; } + + if (pkt == NULL) { + /* EOF handling */ + ptr = NULL; + len = 0; + goto handle_eof; + } + + len = pkt->size; + ptr = pkt->data; + while (len > 0) { + handle_eof: + /* decode the packet if needed */ + data_buf = NULL; /* fail safe */ + data_size = 0; + if (ist->decoding_needed) { + switch(ist->st->codec.codec_type) { + case CODEC_TYPE_AUDIO: + /* XXX: could avoid copy if PCM 16 bits with same + endianness as CPU */ + ret = avcodec_decode_audio(&ist->st->codec, samples, &data_size, + ptr, len); + if (ret < 0) + goto fail_decode; + ptr += ret; + len -= ret; + /* Some bug in mpeg audio decoder gives */ + /* data_size < 0, it seems they are overflows */ + if (data_size <= 0) { + /* no audio frame */ + continue; + } + data_buf = (uint8_t *)samples; + ist->next_pts += ((int64_t)AV_TIME_BASE * data_size) / + (2 * ist->st->codec.channels); + break; + case CODEC_TYPE_VIDEO: + data_size = (ist->st->codec.width * ist->st->codec.height * 3) / 2; + /* XXX: allocate picture correctly */ + memset(&picture, 0, sizeof(picture)); + ret = avcodec_decode_video(&ist->st->codec, + &picture, &got_picture, ptr, len); + ist->st->quality= picture.quality; + if (ret < 0) + goto fail_decode; + if (!got_picture) { + /* no picture yet */ + goto discard_packet; + } + if (ist->st->codec.frame_rate_base != 0) { + ist->next_pts += ((int64_t)AV_TIME_BASE * + ist->st->codec.frame_rate_base) / + ist->st->codec.frame_rate; + } + len = 0; + break; + default: + goto fail_decode; + } + } else { + data_buf = ptr; + data_size = len; + ret = len; + len = 0; + } + + buffer_to_free = NULL; + if (ist->st->codec.codec_type == CODEC_TYPE_VIDEO) { + pre_process_video_frame(ist, (AVPicture *)&picture, + &buffer_to_free); + } + + /* frame rate emulation */ + if (ist->st->codec.rate_emu) { + int64_t pts = av_rescale((int64_t) ist->frame * ist->st->codec.frame_rate_base, 1000000, ist->st->codec.frame_rate); + int64_t now = av_gettime() - ist->start; + if (pts > now) + usleep(pts - now); + + ist->frame++; + } + +#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_t tmp; + tmp = ist->last_ip_pts; + ist->last_ip_pts = ist->frac_pts.val; + ist->frac_pts.val = tmp; + } + } +#endif + /* if output time reached then transcode raw format, + encode packets and output them */ + if (start_time == 0 || ist->pts >= start_time) + for(i=0;isource_index == ist_index) { + os = output_files[ost->file_index]; + +#if 0 + printf("%d: got pts=%0.3f %0.3f\n", i, + (double)pkt->pts / AV_TIME_BASE, + ((double)ist->pts / AV_TIME_BASE) - + ((double)ost->st->pts.val * os->pts_num / os->pts_den)); +#endif + /* set the input output pts pairs */ + ost->sync_ipts = (double)ist->pts / AV_TIME_BASE; + /* XXX: take into account the various fifos, + in particular for audio */ + ost->sync_opts = ost->st->pts.val; + //printf("ipts=%lld sync_ipts=%f sync_opts=%lld pts.val=%lld pkt->pts=%lld\n", ist->pts, ost->sync_ipts, ost->sync_opts, ost->st->pts.val, pkt->pts); + + 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: + /* 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 && frame_size) + do_video_stats(os, ost, frame_size); + } + break; + default: + av_abort(); + } + } else { + AVFrame avframe; + + /* no reencoding needed : output the packet directly */ + /* force the input stream PTS */ + + memset(&avframe, 0, sizeof(AVFrame)); + ost->st->codec.coded_frame= &avframe; + avframe.key_frame = pkt->flags & PKT_FLAG_KEY; + + av_write_frame(os, ost->index, data_buf, data_size); + ost->st->codec.frame_number++; + ost->frame_number++; + } + } + } + av_free(buffer_to_free); + } + discard_packet: + return 0; + fail_decode: + return -1; } + /* * The following code is the main loop of the file converter */ @@ -936,6 +1201,11 @@ static int av_encode(AVFormatContext **output_files, ost->resample = audio_resample_init(codec->channels, icodec->channels, codec->sample_rate, icodec->sample_rate); + if(!ost->resample) + { + printf("Can't resample. Aborting.\n"); + av_abort(); + } } /* Request specific number of channels */ icodec->channels = codec->channels; @@ -944,6 +1214,11 @@ static int av_encode(AVFormatContext **output_files, ost->resample = audio_resample_init(codec->channels, icodec->channels, codec->sample_rate, icodec->sample_rate); + if(!ost->resample) + { + printf("Can't resample. Aborting.\n"); + av_abort(); + } } } ist->decoding_needed = 1; @@ -1090,7 +1365,6 @@ static int av_encode(AVFormatContext **output_files, } //if (ist->st->codec.codec_type == CODEC_TYPE_VIDEO) // ist->st->codec.flags |= CODEC_FLAG_REPEAT_FIELD; - ist->frame_decoded = 1; } } @@ -1099,18 +1373,7 @@ static int av_encode(AVFormatContext **output_files, ist = ist_table[i]; is = input_files[ist->file_index]; ist->pts = 0; - switch (ist->st->codec.codec_type) { - case CODEC_TYPE_AUDIO: - av_frac_init(&ist->next_pts, - 0, 0, is->pts_num * ist->st->codec.sample_rate); - break; - case CODEC_TYPE_VIDEO: - av_frac_init(&ist->next_pts, - 0, 0, is->pts_num * ist->st->codec.frame_rate); - break; - default: - break; - } + ist->next_pts = 0; } /* compute buffer size max (should use a complete heuristic) */ @@ -1129,28 +1392,22 @@ static int av_encode(AVFormatContext **output_files, } #ifndef CONFIG_WIN32 - fprintf(stderr, "Press [q] to stop encoding\n"); + if ( !using_stdin ) + fprintf(stderr, "Press [q] to stop encoding\n"); #endif term_init(); stream_no_data = 0; key = -1; - for(;;) { + for(; received_sigterm == 0;) { int file_index, ist_index; AVPacket pkt; - uint8_t *ptr; - int len; - uint8_t *data_buf; - int data_size, got_picture; - AVPicture picture; - short samples[AVCODEC_MAX_AUDIO_FRAME_SIZE / 2]; - void *buffer_to_free; double pts_min; redo: /* if 'q' pressed, exits */ - if (key) { + if (!using_stdin) { /* read_key() returns 0 on EOF */ key = read_key(); if (key == 'q') @@ -1182,9 +1439,9 @@ static int av_encode(AVFormatContext **output_files, if (recording_time > 0 && pts_min >= (recording_time / 1000000.0)) break; - /* read a packet from it and output it in the fifo */ + /* read a frame from it and output it in the fifo */ is = input_files[file_index]; - if (av_read_packet(is, &pkt) < 0) { + if (av_read_frame(is, &pkt) < 0) { file_table[file_index].eof_reached = 1; continue; } @@ -1193,9 +1450,8 @@ static int av_encode(AVFormatContext **output_files, } else { stream_no_data = 0; } - if (do_hex_dump) { - printf("stream #%d, size=%d:\n", pkt.stream_index, pkt.size); - av_hex_dump(pkt.data, pkt.size); + if (do_pkt_dump) { + av_pkt_dump(stdout, &pkt, do_hex_dump); } /* the following test is needed in case new streams appear dynamically in stream : we ignore them */ @@ -1206,192 +1462,29 @@ static int av_encode(AVFormatContext **output_files, if (ist->discard) goto discard_packet; - // printf("read #%d.%d size=%d\n", ist->file_index, ist->index, pkt.size); - - len = pkt.size; - ptr = pkt.data; - while (len > 0) { - /* 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) { - /* If pts is unavailable -- we have to use synthetic one */ - if( pkt.pts != AV_NOPTS_VALUE ) - { - ist->pts = ist->next_pts.val = pkt.pts; - } - else - { - ist->pts = ist->next_pts.val; - } - ist->frame_decoded = 0; - } - - switch(ist->st->codec.codec_type) { - case CODEC_TYPE_AUDIO: - /* XXX: could avoid copy if PCM 16 bits with same - endianness as CPU */ - ret = avcodec_decode_audio(&ist->st->codec, samples, &data_size, - ptr, len); - if (ret < 0) - goto fail_decode; - /* Some bug in mpeg audio decoder gives */ - /* data_size < 0, it seems they are overflows */ - if (data_size <= 0) { - /* no audio frame */ - ptr += ret; - len -= ret; - continue; - } - data_buf = (uint8_t *)samples; - av_frac_add(&ist->next_pts, - is->pts_den * data_size / (2 * ist->st->codec.channels)); - break; - case CODEC_TYPE_VIDEO: - { - AVFrame big_picture; - - data_size = (ist->st->codec.width * ist->st->codec.height * 3) / 2; - ret = avcodec_decode_video(&ist->st->codec, - &big_picture, &got_picture, ptr, len); - picture= *(AVPicture*)&big_picture; - ist->st->quality= big_picture.quality; - if (ret < 0) { - fail_decode: - fprintf(stderr, "Error while decoding stream #%d.%d\n", - ist->file_index, ist->index); - av_free_packet(&pkt); - goto redo; - } - if (!got_picture) { - /* no picture yet */ - ptr += ret; - len -= ret; - continue; - } - av_frac_add(&ist->next_pts, - is->pts_den * ist->st->codec.frame_rate_base); - } - break; - default: - goto fail_decode; - } - } else { - data_buf = ptr; - data_size = len; - ret = len; - } - ptr += ret; - len -= ret; - - buffer_to_free = 0; - if (ist->st->codec.codec_type == CODEC_TYPE_VIDEO) { - pre_process_video_frame(ist, &picture, &buffer_to_free); - } - - ist->frame_decoded = 1; - - /* frame rate emulation */ - if (ist->st->codec.rate_emu) { - int64_t pts = av_rescale((int64_t) ist->frame * ist->st->codec.frame_rate_base, 1000000, ist->st->codec.frame_rate); - int64_t now = av_gettime() - ist->start; - if (pts > now) - usleep(pts - now); - - ist->frame++; - } - -#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_t 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 0 - printf("%d: got pts=%f %f\n", i, pkt.pts / 90000.0, - (ist->pts - ost->st->pts.val) / 90000.0); -#endif - /* set the input output pts pairs */ - ost->sync_ipts = (double)ist->pts * is->pts_num / - is->pts_den; - /* XXX: take into account the various fifos, - in particular for audio */ - ost->sync_opts = ost->st->pts.val; - //printf("ipts=%lld sync_ipts=%f sync_opts=%lld pts.val=%lld pkt.pts=%lld\n", ist->pts, ost->sync_ipts, ost->sync_opts, ost->st->pts.val, pkt.pts); - - 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: - /* 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 && frame_size) - do_video_stats(os, ost, frame_size); - } - break; - default: - av_abort(); - } - } else { - AVFrame avframe; - - /* no reencoding needed : output the packet directly */ - /* force the input stream PTS */ - - memset(&avframe, 0, sizeof(AVFrame)); - ost->st->codec.coded_frame= &avframe; - avframe.key_frame = pkt.flags & PKT_FLAG_KEY; - - av_write_frame(os, ost->index, data_buf, data_size); - ost->st->codec.frame_number++; - ost->frame_number++; - } - } - } - av_free(buffer_to_free); + //fprintf(stderr,"read #%d.%d size=%d\n", ist->file_index, ist->index, pkt.size); + if (output_packet(ist, ist_index, ost_table, nb_ostreams, &pkt) < 0) { + fprintf(stderr, "Error while decoding stream #%d.%d\n", + ist->file_index, ist->index); + av_free_packet(&pkt); + goto redo; } + discard_packet: av_free_packet(&pkt); /* dump report by using the output first video and audio streams */ print_report(output_files, ost_table, nb_ostreams, 0); } + + /* at the end of stream, we must flush the decoder buffers */ + for(i=0;idecoding_needed) { + output_packet(ist, i, ost_table, nb_ostreams, NULL); + } + } + term_exit(); /* dump report by using the first video and audio streams */ @@ -1481,28 +1574,6 @@ int file_read(const char *filename) } #endif -static void show_licence(void) -{ - printf( - "ffmpeg version " FFMPEG_VERSION "\n" - "Copyright (c) 2000, 2001, 2002 Fabrice Bellard\n" - "This library is free software; you can redistribute it and/or\n" - "modify it under the terms of the GNU Lesser General Public\n" - "License as published by the Free Software Foundation; either\n" - "version 2 of the License, or (at your option) any later version.\n" - "\n" - "This library is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" - "Lesser General Public License for more details.\n" - "\n" - "You should have received a copy of the GNU Lesser General Public\n" - "License along with this library; if not, write to the Free Software\n" - "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n" - ); - exit(1); -} - static void opt_image_format(const char *arg) { AVImageFormat *f; @@ -1556,7 +1627,7 @@ static void opt_video_bitrate_min(const char *arg) static void opt_video_buffer_size(const char *arg) { - video_rc_buffer_size = atoi(arg) * 1000; + video_rc_buffer_size = atoi(arg) * 1024; } static void opt_video_rc_eq(char *arg) @@ -1601,6 +1672,11 @@ static void opt_debug(const char *arg) debug = atoi(arg); } +static void opt_verbose(const char *arg) +{ + verbose = atoi(arg); +} + static void opt_frame_rate(const char *arg) { if (parse_frame_rate(&frame_rate, &frame_rate_base, arg) < 0) { @@ -1743,12 +1819,27 @@ static void opt_mb_decision(const char *arg) mb_decision = atoi(arg); } +static void opt_mb_cmp(const char *arg) +{ + mb_cmp = atoi(arg); +} + +static void opt_sub_cmp(const char *arg) +{ + sub_cmp = atoi(arg); +} + +static void opt_cmp(const char *arg) +{ + cmp = atoi(arg); +} + static void opt_qscale(const char *arg) { - video_qscale = atoi(arg); - if (video_qscale < 0 || - video_qscale > 31) { - fprintf(stderr, "qscale must be >= 1 and <= 31\n"); + video_qscale = atof(arg); + if (video_qscale < 0.01 || + video_qscale > 255) { + fprintf(stderr, "qscale must be >= 0.01 and <= 255\n"); exit(1); } } @@ -1839,6 +1930,11 @@ static void opt_packet_size(const char *arg) packet_size= atoi(arg); } +static void opt_error_rate(const char *arg) +{ + error_rate= atoi(arg); +} + static void opt_strict(const char *arg) { strict= atoi(arg); @@ -1914,6 +2010,8 @@ static void add_frame_hooker(const char *arg) int i; char *args = av_strdup(arg); + using_vhook = 1; + argv[0] = strtok(args, " "); while (argc < 62 && (argv[++argc] = strtok(NULL, " "))) { } @@ -1994,6 +2092,11 @@ static void opt_recording_time(const char *arg) recording_time = parse_date(arg, 1); } +static void opt_start_time(const char *arg) +{ + start_time = parse_date(arg, 1); +} + static void opt_input_file(const char *filename) { AVFormatContext *ic; @@ -2003,6 +2106,9 @@ static void opt_input_file(const char *filename) if (!strcmp(filename, "-")) filename = "pipe:"; + using_stdin |= !strcmp(filename, "pipe:" ) || + !strcmp( filename, "/dev/stdin" ); + /* get default parameters from command line */ memset(ap, 0, sizeof(*ap)); ap->sample_rate = audio_sample_rate; @@ -2029,6 +2135,23 @@ static void opt_input_file(const char *filename) exit(1); } + /* if seeking requested, we execute it */ + if (start_time != 0) { + int64_t timestamp; + + timestamp = start_time; + /* add the stream start time */ + if (ic->start_time != AV_NOPTS_VALUE) + timestamp += ic->start_time; + ret = av_seek_frame(ic, -1, timestamp); + if (ret < 0) { + fprintf(stderr, "%s: could not seek to position %0.3f\n", + filename, (double)timestamp / AV_TIME_BASE); + } + /* reset seek info */ + start_time = 0; + } + /* update the current parameters so that they match the one of the input stream */ for(i=0;inb_streams;i++) { AVCodecContext *enc = &ic->streams[i]->codec; @@ -2041,7 +2164,7 @@ static void opt_input_file(const char *filename) case CODEC_TYPE_VIDEO: frame_height = enc->height; frame_width = enc->width; - frame_aspect_ratio = enc->aspect_ratio; + frame_aspect_ratio = av_q2d(enc->sample_aspect_ratio) * enc->width / enc->height; frame_pix_fmt = enc->pix_fmt; rfps = ic->streams[i]->r_frame_rate; rfps_base = ic->streams[i]->r_frame_rate_base; @@ -2050,11 +2173,6 @@ static void opt_input_file(const char *filename) enc->error_concealment = error_concealment; enc->idct_algo= idct_algo; enc->debug= debug; -/* if(enc->codec->capabilities & CODEC_CAP_TRUNCATED) - enc->flags|= CODEC_FLAG_TRUNCATED; */ - if(/*enc->codec_id==CODEC_ID_MPEG4 || */enc->codec_id==CODEC_ID_MPEG1VIDEO || enc->codec_id==CODEC_ID_H264) - enc->flags|= CODEC_FLAG_TRUNCATED; - if(bitexact) enc->flags|= CODEC_FLAG_BITEXACT; @@ -2070,6 +2188,8 @@ static void opt_input_file(const char *filename) enc->rate_emu = rate_emu; break; + case CODEC_TYPE_DATA: + break; default: av_abort(); } @@ -2179,6 +2299,9 @@ static void opt_output_file(const char *filename) avcodec_get_context_defaults(&st->codec); video_enc = &st->codec; + + if(!strcmp(file_oformat->name, "mp4") || !strcmp(file_oformat->name, "mov") || !strcmp(file_oformat->name, "3gp")) + video_enc->flags |= CODEC_FLAG_GLOBAL_HEADER; if (video_stream_copy) { st->stream_copy = 1; video_enc->codec_type = CODEC_TYPE_VIDEO; @@ -2199,7 +2322,7 @@ static void opt_output_file(const char *filename) video_enc->width = frame_width; video_enc->height = frame_height; - video_enc->aspect_ratio = frame_aspect_ratio; + video_enc->sample_aspect_ratio = av_d2q(frame_aspect_ratio*frame_height/frame_width, 255); video_enc->pix_fmt = frame_pix_fmt; if (!intra_only) @@ -2208,37 +2331,49 @@ static void opt_output_file(const char *filename) video_enc->gop_size = 0; if (video_qscale || same_quality) { video_enc->flags |= CODEC_FLAG_QSCALE; - st->quality = video_qscale; + st->quality = FF_QP2LAMBDA * video_qscale; } - + + if(intra_matrix) + video_enc->intra_matrix = intra_matrix; + if(inter_matrix) + video_enc->inter_matrix = inter_matrix; + if(bitexact) video_enc->flags |= CODEC_FLAG_BITEXACT; video_enc->mb_decision = mb_decision; + video_enc->mb_cmp = mb_cmp; + video_enc->me_sub_cmp = sub_cmp; + video_enc->me_cmp = cmp; - /* Fx */ if (use_umv) { video_enc->flags |= CODEC_FLAG_H263P_UMV; } if (use_aic) { video_enc->flags |= CODEC_FLAG_H263P_AIC; } - /* /Fx */ + if (use_aiv) { + video_enc->flags |= CODEC_FLAG_H263P_AIV; + } if (use_4mv) { - video_enc->mb_decision = FF_MB_DECISION_BITS; //FIXME remove video_enc->flags |= CODEC_FLAG_4MV; } + if (use_obmc) { + video_enc->flags |= CODEC_FLAG_OBMC; + } - if(use_part) + if(use_part) { video_enc->flags |= CODEC_FLAG_PART; - - + } if (b_frames) { video_enc->max_b_frames = b_frames; video_enc->b_frame_strategy = 0; video_enc->b_quant_factor = 2.0; } - + if (do_interlace) { + video_enc->flags |= CODEC_FLAG_INTERLACED_DCT; + } video_enc->qmin = video_qmin; video_enc->qmax = video_qmax; video_enc->mb_qmin = video_mb_qmin; @@ -2287,6 +2422,7 @@ static void opt_output_file(const char *filename) video_enc->dct_algo = dct_algo; video_enc->idct_algo = idct_algo; video_enc->strict_std_compliance = strict; + video_enc->error_rate = error_rate; if(packet_size){ video_enc->rtp_mode= 1; video_enc->rtp_payload_size= packet_size; @@ -2322,6 +2458,9 @@ static void opt_output_file(const char *filename) audio_enc = &st->codec; audio_enc->codec_type = CODEC_TYPE_AUDIO; + + if(!strcmp(file_oformat->name, "mp4") || !strcmp(file_oformat->name, "mov") || !strcmp(file_oformat->name, "3gp")) + audio_enc->flags |= CODEC_FLAG_GLOBAL_HEADER; if (audio_stream_copy) { st->stream_copy = 1; } else { @@ -2380,13 +2519,19 @@ static void opt_output_file(const char *filename) if (url_exist(filename)) { int c; - printf("File '%s' already exists. Overwrite ? [y/N] ", filename); - fflush(stdout); - c = getchar(); - if (toupper(c) != 'Y') { - fprintf(stderr, "Not overwriting - exiting\n"); + if ( !using_stdin ) { + fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename); + fflush(stderr); + c = getchar(); + if (toupper(c) != 'Y') { + fprintf(stderr, "Not overwriting - exiting\n"); + exit(1); + } + } + else { + fprintf(stderr,"File '%s' already exists. Exiting.\n", filename); exit(1); - } + } } } @@ -2477,6 +2622,12 @@ static void prepare_grab(void) fprintf(stderr, "Could not find video grab device\n"); exit(1); } + /* If not enough info to get the stream parameters, we decode the + first frames to get it. */ + if ((ic->ctx_flags & AVFMTCTX_NOHEADER) && av_find_stream_info(ic) < 0) { + fprintf(stderr, "Could not find video grab parameters\n"); + exit(1); + } /* by now video grab has one stream */ ic->streams[0]->r_frame_rate = vp->frame_rate; ic->streams[0]->r_frame_rate_base = vp->frame_rate_base; @@ -2591,7 +2742,7 @@ static void show_formats(void) printf(" %s:", up->name); printf("\n"); - printf("Frame size, frame rate abbreviations: ntsc pal film ntsc-film sqcif qcif cif 4cif\n"); + printf("Frame size, frame rate abbreviations: ntsc pal qntsc qpal sntsc spal film ntsc-film sqcif qcif cif 4cif\n"); printf("Motion estimation methods:"); pp = motion_str; while (*pp) { @@ -2608,8 +2759,146 @@ static void show_formats(void) exit(1); } +void parse_matrix_coeffs(uint16_t *dest, const char *str) +{ + int i; + const char *p = str; + for(i = 0;; i++) { + dest[i] = atoi(p); + if(i == 63) + break; + p = strchr(p, ','); + if(!p) { + fprintf(stderr, "Syntax error in matrix \"%s\" at coeff %d\n", str, i); + exit(1); + } + p++; + } +} + +void opt_inter_matrix(const char *arg) +{ + inter_matrix = av_mallocz(sizeof(uint16_t) * 64); + parse_matrix_coeffs(inter_matrix, arg); +} + +void opt_intra_matrix(const char *arg) +{ + intra_matrix = av_mallocz(sizeof(uint16_t) * 64); + parse_matrix_coeffs(intra_matrix, arg); +} + +static void opt_target(const char *arg) +{ + int norm = -1; + + if(!strncmp(arg, "pal-", 4)) { + norm = 0; + arg += 4; + } else if(!strncmp(arg, "ntsc-", 5)) { + norm = 1; + arg += 5; + } else { + int fr; + /* Calculate FR via float to avoid int overflow */ + fr = (int)(frame_rate * 1000.0 / frame_rate_base); + if(fr == 25000) { + norm = 0; + } else if((fr == 29970) || (fr == 23976)) { + norm = 1; + } else { + /* Try to determine PAL/NTSC by peeking in the input files */ + if(nb_input_files) { + int i, j; + for(j = 0; j < nb_input_files; j++) { + for(i = 0; i < input_files[j]->nb_streams; i++) { + AVCodecContext *c = &input_files[j]->streams[i]->codec; + if(c->codec_type != CODEC_TYPE_VIDEO) + continue; + fr = c->frame_rate * 1000 / c->frame_rate_base; + if(fr == 25000) { + norm = 0; + break; + } else if((fr == 29970) || (fr == 23976)) { + norm = 1; + break; + } + } + if(norm >= 0) + break; + } + } + } + if(verbose && norm >= 0) + printf("Assuming %s for target.\n", norm ? "NTSC" : "PAL"); + } + + if(norm < 0) { + fprintf(stderr, "Could not determine norm (PAL/NTSC) for target.\n"); + fprintf(stderr, "Please prefix target with \"pal-\" or \"ntsc-\",\n"); + fprintf(stderr, "or set a framerate with \"-r xxx\".\n"); + exit(1); + } + + if(!strcmp(arg, "vcd")) { + + opt_video_codec("mpeg1video"); + opt_audio_codec("mp2"); + opt_format("vcd"); + + opt_frame_size(norm ? "352x240" : "352x288"); + + video_bit_rate = 1150000; + video_rc_max_rate = 1150000; + video_rc_min_rate = 1150000; + video_rc_buffer_size = 40*1024*8; + + audio_bit_rate = 224000; + audio_sample_rate = 44100; + + } else if(!strcmp(arg, "svcd")) { + + opt_video_codec("mpeg2video"); + opt_audio_codec("mp2"); + opt_format("vcd"); + + opt_frame_size(norm ? "480x480" : "480x576"); + opt_gop_size(norm ? "18" : "15"); + + video_bit_rate = 2040000; + video_rc_max_rate = 2516000; + video_rc_min_rate = 1145000; + video_rc_buffer_size = 224*1024*8; + + audio_bit_rate = 224000; + audio_sample_rate = 44100; + + } else if(!strcmp(arg, "dvd")) { + + opt_video_codec("mpeg2video"); + opt_audio_codec("ac3"); + opt_format("vob"); + + opt_frame_size(norm ? "720x480" : "720x576"); + opt_gop_size(norm ? "18" : "15"); + + video_bit_rate = 6000000; + video_rc_max_rate = 9000000; + video_rc_min_rate = 1500000; + video_rc_buffer_size = 224*1024*8; + + audio_bit_rate = 448000; + audio_sample_rate = 48000; + + } else { + fprintf(stderr, "Unknown target: %s\n", arg); + exit(1); + } +} + const OptionDef options[] = { - { "L", 0, {(void*)show_licence}, "show license" }, + /* main options */ + { "L", 0, {(void*)show_license}, "show license" }, { "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" }, @@ -2618,99 +2907,162 @@ const OptionDef options[] = { { "y", OPT_BOOL, {(void*)&file_overwrite}, "overwrite output files" }, { "map", HAS_ARG | OPT_EXPERT, {(void*)opt_map}, "set input stream mapping", "file:stream" }, { "t", HAS_ARG, {(void*)opt_recording_time}, "set the recording time", "duration" }, + { "ss", HAS_ARG, {(void*)opt_start_time}, "set the start time offset", "time_off" }, { "title", HAS_ARG | OPT_STRING, {(void*)&str_title}, "set the title", "string" }, { "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 (Hz value, fraction or abbreviation)", "rate" }, - { "re", OPT_BOOL|OPT_EXPERT, {(void*)&rate_emu}, "read input at native frame rate" }, - { "s", HAS_ARG, {(void*)opt_frame_size}, "set frame size (WxH or abbreviation)", "size" }, - { "aspect", HAS_ARG, {(void*)opt_frame_aspect_ratio}, "set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)", "aspect" }, - { "pix_fmt", HAS_ARG | OPT_EXPERT, {(void*)opt_frame_pix_fmt}, "set pixel format", "format" }, - { "croptop", HAS_ARG, {(void*)opt_frame_crop_top}, "set top crop band size (in pixels)", "size" }, - { "cropbottom", HAS_ARG, {(void*)opt_frame_crop_bottom}, "set bottom crop band size (in pixels)", "size" }, - { "cropleft", HAS_ARG, {(void*)opt_frame_crop_left}, "set left crop band size (in pixels)", "size" }, - { "cropright", HAS_ARG, {(void*)opt_frame_crop_right}, "set right crop band size (in pixels)", "size" }, - { "g", HAS_ARG | OPT_EXPERT, {(void*)opt_gop_size}, "set the group of picture size", "gop_size" }, - { "intra", OPT_BOOL | OPT_EXPERT, {(void*)&intra_only}, "use only intra frames"}, - { "vn", OPT_BOOL, {(void*)&video_disable}, "disable video" }, - { "qscale", HAS_ARG | OPT_EXPERT, {(void*)opt_qscale}, "use fixed video quantiser scale (VBR)", "q" }, - { "qmin", HAS_ARG | OPT_EXPERT, {(void*)opt_qmin}, "min video quantiser scale (VBR)", "q" }, - { "qmax", HAS_ARG | OPT_EXPERT, {(void*)opt_qmax}, "max video quantiser scale (VBR)", "q" }, - { "mbqmin", HAS_ARG | OPT_EXPERT, {(void*)opt_mb_qmin}, "min macroblock quantiser scale (VBR)", "q" }, - { "mbqmax", HAS_ARG | OPT_EXPERT, {(void*)opt_mb_qmax}, "max macroblock quantiser scale (VBR)", "q" }, - { "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" }, -// { "b_strategy", HAS_ARG | OPT_EXPERT, {(void*)opt_b_strategy}, "dynamic b frame selection strategy", "strategy" }, - { "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" }, - { "vc", HAS_ARG | OPT_EXPERT, {(void*)opt_video_channel}, "set video grab channel (DV1394 only)", "channel" }, - { "tvstd", HAS_ARG | OPT_EXPERT, {(void*)opt_video_standard}, "set television standard (NTSC, PAL (SECAM))", "standard" }, - { "dv1394", OPT_EXPERT, {(void*)opt_dv1394}, "set DV1394 grab", "" }, - { "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_concealment}, "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*)&mb_decision}, "activate high quality settings" }, - { "mbd", HAS_ARG | OPT_EXPERT, {(void*)opt_mb_decision}, "macroblock decision", "mode" }, - { "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" }, - { "strict", HAS_ARG | OPT_EXPERT, {(void*)opt_strict}, "strictness", "how strictly to follow the standarts" }, - { "sameq", OPT_BOOL, {(void*)&same_quality}, - "use same video quality as source (implies VBR)" }, { "debug", HAS_ARG | OPT_EXPERT, {(void*)opt_debug}, "print specific debug info", "" }, - /* audio options */ - { "ab", HAS_ARG, {(void*)opt_audio_bitrate}, "set audio bitrate (in kbit/s)", "bitrate", }, - { "ar", HAS_ARG, {(void*)opt_audio_rate}, "set audio sampling rate (in Hz)", "rate" }, - { "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 ('copy' to copy stream)", "codec" }, - { "deinterlace", OPT_BOOL | OPT_EXPERT, {(void*)&do_deinterlace}, - "deinterlace pictures" }, { "benchmark", OPT_BOOL | OPT_EXPERT, {(void*)&do_benchmark}, "add timings for benchmarking" }, - { "hex", OPT_BOOL | OPT_EXPERT, {(void*)&do_hex_dump}, + { "dump", OPT_BOOL | OPT_EXPERT, {(void*)&do_pkt_dump}, "dump each input packet" }, - { "psnr", OPT_BOOL | OPT_EXPERT, {(void*)&do_psnr}, "calculate PSNR of compressed frames" }, - { "vstats", OPT_BOOL | OPT_EXPERT, {(void*)&do_vstats}, "dump video coding statistics to file" }, + { "hex", OPT_BOOL | OPT_EXPERT, {(void*)&do_hex_dump}, + "when dumping packets, also dump the payload" }, { "bitexact", OPT_EXPERT, {(void*)opt_bitexact}, "only use bit exact algorithms (for codec testing)" }, - { "vhook", HAS_ARG | OPT_EXPERT, {(void*)add_frame_hooker}, "insert video processing module", "module name and parameters" }, - /* Fx */ - { "aic", OPT_BOOL | OPT_EXPERT, {(void*)&use_aic}, "enable Advanced intra coding (h263+)" }, - { "umv", OPT_BOOL | OPT_EXPERT, {(void*)&use_umv}, "enable Unlimited Motion Vector (h263+)" }, - /* /Fx */ + { "re", OPT_BOOL | OPT_EXPERT, {(void*)&rate_emu}, "read input at native frame rate", "" }, + { "loop", OPT_BOOL | OPT_EXPERT, {(void*)&loop_input}, "loop (current only works with images)" }, + { "v", HAS_ARG, {(void*)opt_verbose}, "control amount of logging", "verbose" }, + { "target", HAS_ARG, {(void*)opt_target}, "specify target file type (\"vcd\", \"svcd\" or \"dvd\")", "type" }, + + /* video options */ + { "b", HAS_ARG | OPT_VIDEO, {(void*)opt_video_bitrate}, "set video bitrate (in kbit/s)", "bitrate" }, + { "r", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_rate}, "set frame rate (Hz value, fraction or abbreviation)", "rate" }, + { "s", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_size}, "set frame size (WxH or abbreviation)", "size" }, + { "aspect", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_aspect_ratio}, "set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)", "aspect" }, + { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_frame_pix_fmt}, "set pixel format", "format" }, + { "croptop", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_crop_top}, "set top crop band size (in pixels)", "size" }, + { "cropbottom", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_crop_bottom}, "set bottom crop band size (in pixels)", "size" }, + { "cropleft", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_crop_left}, "set left crop band size (in pixels)", "size" }, + { "cropright", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_crop_right}, "set right crop band size (in pixels)", "size" }, + { "g", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_gop_size}, "set the group of picture size", "gop_size" }, + { "intra", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&intra_only}, "use only intra frames"}, + { "vn", OPT_BOOL | OPT_VIDEO, {(void*)&video_disable}, "disable video" }, + { "qscale", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_qscale}, "use fixed video quantiser scale (VBR)", "q" }, + { "qmin", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_qmin}, "min video quantiser scale (VBR)", "q" }, + { "qmax", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_qmax}, "max video quantiser scale (VBR)", "q" }, + { "mbqmin", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_mb_qmin}, "min macroblock quantiser scale (VBR)", "q" }, + { "mbqmax", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_mb_qmax}, "max macroblock quantiser scale (VBR)", "q" }, + { "qdiff", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_qdiff}, "max difference between the quantiser scale (VBR)", "q" }, + { "qblur", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_qblur}, "video quantiser scale blur (VBR)", "blur" }, + { "qcomp", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_qcomp}, "video quantiser scale compression (VBR)", "compression" }, + { "rc_init_cplx", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_rc_initial_cplx}, "initial complexity for 1-pass encoding", "complexity" }, + { "b_qfactor", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_b_qfactor}, "qp factor between p and b frames", "factor" }, + { "i_qfactor", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_i_qfactor}, "qp factor between p and i frames", "factor" }, + { "b_qoffset", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_b_qoffset}, "qp offset between p and b frames", "offset" }, + { "i_qoffset", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_i_qoffset}, "qp offset between p and i frames", "offset" }, +// { "b_strategy", HAS_ARG | OPT_EXPERT, {(void*)opt_b_strategy}, "dynamic b frame selection strategy", "strategy" }, + { "rc_eq", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_video_rc_eq}, "set rate control equation", "equation" }, + { "rc_override", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_video_rc_override_string}, "rate control override for specific intervals", "override" }, + { "bt", HAS_ARG | OPT_VIDEO, {(void*)opt_video_bitrate_tolerance}, "set video bitrate tolerance (in kbit/s)", "tolerance" }, + { "maxrate", HAS_ARG | OPT_VIDEO, {(void*)opt_video_bitrate_max}, "set max video bitrate tolerance (in kbit/s)", "bitrate" }, + { "minrate", HAS_ARG | OPT_VIDEO, {(void*)opt_video_bitrate_min}, "set min video bitrate tolerance (in kbit/s)", "bitrate" }, + { "bufsize", HAS_ARG | OPT_VIDEO, {(void*)opt_video_buffer_size}, "set ratecontrol buffere size (in kbit)", "size" }, + { "vcodec", HAS_ARG | OPT_VIDEO, {(void*)opt_video_codec}, "force video codec ('copy' to copy stream)", "codec" }, + { "me", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_motion_estimation}, "set motion estimation method", + "method" }, + { "dct_algo", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_dct_algo}, "set dct algo", "algo" }, + { "idct_algo", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_idct_algo}, "set idct algo", "algo" }, + { "er", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_error_resilience}, "set error resilience", "n" }, + { "ec", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_error_concealment}, "set error concealment", "bit_mask" }, + { "bf", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_b_frames}, "use 'frames' B frames", "frames" }, + { "hq", OPT_BOOL, {(void*)&mb_decision}, "activate high quality settings" }, + { "mbd", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_mb_decision}, "macroblock decision", "mode" }, + { "mbcmp", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_mb_cmp}, "macroblock compare function", "cmp function" }, + { "subcmp", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_sub_cmp}, "subpel compare function", "cmp function" }, + { "cmp", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_cmp}, "fullpel compare function", "cmp function" }, + { "4mv", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&use_4mv}, "use four motion vector by macroblock (MPEG4)" }, + { "obmc", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&use_obmc}, "use overlapped block motion compensation (h263+)" }, + { "part", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&use_part}, "use data partitioning (MPEG4)" }, + { "bug", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_workaround_bugs}, "workaround not auto detected encoder bugs", "param" }, + { "ps", HAS_ARG | OPT_EXPERT, {(void*)opt_packet_size}, "set packet size in bits", "size" }, + { "error", HAS_ARG | OPT_EXPERT, {(void*)opt_error_rate}, "error rate", "rate" }, + { "strict", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_strict}, "how strictly to follow the standarts", "strictness" }, + { "sameq", OPT_BOOL | OPT_VIDEO, {(void*)&same_quality}, + "use same video quality as source (implies VBR)" }, + { "pass", HAS_ARG | OPT_VIDEO, {(void*)&opt_pass}, "select the pass number (1 or 2)", "n" }, + { "passlogfile", HAS_ARG | OPT_STRING | OPT_VIDEO, {(void*)&pass_logfilename}, "select two pass log file name", "file" }, + { "deinterlace", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&do_deinterlace}, + "deinterlace pictures" }, + { "interlace", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&do_interlace}, + "force interlacing support in encoder (MPEG2/MPEG4)" }, + { "psnr", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&do_psnr}, "calculate PSNR of compressed frames" }, + { "vstats", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&do_vstats}, "dump video coding statistics to file" }, + { "vhook", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)add_frame_hooker}, "insert video processing module", "module" }, + { "aic", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&use_aic}, "enable Advanced intra coding (h263+)" }, + { "aiv", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&use_aiv}, "enable Alternative inter vlc (h263+)" }, + { "umv", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&use_umv}, "enable Unlimited Motion Vector (h263+)" }, + { "intra_matrix", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_intra_matrix}, "specify intra matrix coeffs", "matrix" }, + { "inter_matrix", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_inter_matrix}, "specify inter matrix coeffs", "matrix" }, + + /* audio options */ + { "ab", HAS_ARG | OPT_AUDIO, {(void*)opt_audio_bitrate}, "set audio bitrate (in kbit/s)", "bitrate", }, + { "ar", HAS_ARG | OPT_AUDIO, {(void*)opt_audio_rate}, "set audio sampling rate (in Hz)", "rate" }, + { "ac", HAS_ARG | OPT_AUDIO, {(void*)opt_audio_channels}, "set number of audio channels", "channels" }, + { "an", OPT_BOOL | OPT_AUDIO, {(void*)&audio_disable}, "disable audio" }, + { "acodec", HAS_ARG | OPT_AUDIO, {(void*)opt_audio_codec}, "force audio codec ('copy' to copy stream)", "codec" }, + + /* grab options */ + { "vd", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_GRAB, {(void*)opt_video_device}, "set video grab device", "device" }, + { "vc", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_GRAB, {(void*)opt_video_channel}, "set video grab channel (DV1394 only)", "channel" }, + { "tvstd", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_GRAB, {(void*)opt_video_standard}, "set television standard (NTSC, PAL (SECAM))", "standard" }, + { "dv1394", OPT_EXPERT | OPT_GRAB, {(void*)opt_dv1394}, "set DV1394 grab", "" }, + { "ad", HAS_ARG | OPT_EXPERT | OPT_AUDIO | OPT_GRAB, {(void*)opt_audio_device}, "set audio device", "device" }, { NULL, }, }; -void show_help(void) +static void show_banner(void) +{ + printf("ffmpeg version " FFMPEG_VERSION ", Copyright (c) 2000-2003 Fabrice Bellard\n"); +} + +static void show_license(void) +{ + show_banner(); + printf( + "This library is free software; you can redistribute it and/or\n" + "modify it under the terms of the GNU Lesser General Public\n" + "License as published by the Free Software Foundation; either\n" + "version 2 of the License, or (at your option) any later version.\n" + "\n" + "This library is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" + "Lesser General Public License for more details.\n" + "\n" + "You should have received a copy of the GNU Lesser General Public\n" + "License along with this library; if not, write to the Free Software\n" + "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n" + ); + exit(1); +} + +static void show_help(void) { - printf("ffmpeg version " FFMPEG_VERSION ", Copyright (c) 2000, 2001, 2002 Fabrice Bellard\n"); + show_banner(); printf("usage: ffmpeg [[options] -i input_file]... {[options] outfile}...\n" "Hyper fast Audio and Video encoder\n"); printf("\n"); - show_help_options(options); + show_help_options(options, "Main options:\n", + OPT_EXPERT | OPT_AUDIO | OPT_VIDEO, 0); + show_help_options(options, "\nVideo options:\n", + OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_GRAB, + OPT_VIDEO); + show_help_options(options, "\nAdvanced Video options:\n", + OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_GRAB, + OPT_VIDEO | OPT_EXPERT); + show_help_options(options, "\nAudio options:\n", + OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_GRAB, + OPT_AUDIO); + show_help_options(options, "\nAdvanced Audio options:\n", + OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_GRAB, + OPT_AUDIO | OPT_EXPERT); + show_help_options(options, "\nAudio/Video grab options:\n", + OPT_GRAB, + OPT_GRAB); + show_help_options(options, "\nAdvanced options:\n", + OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_GRAB, + OPT_EXPERT); exit(1); } @@ -2766,6 +3118,10 @@ int main(int argc, char **argv) av_free_static(); + if(intra_matrix) + av_free(intra_matrix); + if(inter_matrix) + av_free(inter_matrix); #ifdef POWERPC_PERFORMANCE_REPORT extern void powerpc_display_perf_report(void);