X-Git-Url: http://rtime.felk.cvut.cz/gitweb/frescor/ffmpeg.git/blobdiff_plain/9f72ac9220eb9c3c998395d6f376ace102b058c3..HEAD:/ffmpeg.c diff --git a/ffmpeg.c b/ffmpeg.c index d9027aeaf..5f407c96c 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -20,7 +20,7 @@ */ /* needed for usleep() */ -#define _XOPEN_SOURCE 500 +#define _XOPEN_SOURCE 600 #include "config.h" #include @@ -34,26 +34,29 @@ #include "libavformat/avformat.h" #include "libavdevice/avdevice.h" #include "libswscale/swscale.h" -#include "libavformat/framehook.h" #include "libavcodec/opt.h" #include "libavcodec/audioconvert.h" #include "libavutil/fifo.h" #include "libavutil/avstring.h" #include "libavformat/os_support.h" -#ifdef HAVE_SYS_RESOURCE_H +#if HAVE_SYS_RESOURCE_H #include #include -#elif defined(HAVE_GETPROCESSTIMES) +#elif HAVE_GETPROCESSTIMES #include #endif -#if defined(HAVE_TERMIOS_H) +#if HAVE_SYS_SELECT_H +#include +#endif + +#if HAVE_TERMIOS_H #include #include #include #include -#elif defined(HAVE_CONIO_H) +#elif HAVE_CONIO_H #include #endif #undef time //needed because HAVE_AV_CONFIG_H is defined on top @@ -90,10 +93,14 @@ static const OptionDef options[]; static AVFormatContext *input_files[MAX_FILES]; static int64_t input_files_ts_offset[MAX_FILES]; static double input_files_ts_scale[MAX_FILES][MAX_STREAMS]; +static AVCodec *input_codecs[MAX_FILES*MAX_STREAMS]; static int nb_input_files = 0; +static int nb_icodecs; static AVFormatContext *output_files[MAX_FILES]; +static AVCodec *output_codecs[MAX_FILES*MAX_STREAMS]; static int nb_output_files = 0; +static int nb_ocodecs; static AVStreamMap stream_maps[MAX_FILES*MAX_STREAMS]; static int nb_stream_maps; @@ -143,6 +150,7 @@ static int qp_hist = 0; static int intra_only = 0; static int audio_sample_rate = 44100; +static int64_t channel_layout = 0; #define QSCALE_NONE -99999 static float audio_qscale = QSCALE_NONE; static int audio_disable = 0; @@ -154,6 +162,7 @@ static char *audio_language = NULL; static int subtitle_disable = 0; static char *subtitle_codec_name = NULL; static char *subtitle_language = NULL; +static int subtitle_codec_tag = 0; static float mux_preload= 0.5; static float mux_max_delay= 0.7; @@ -163,18 +172,14 @@ static int64_t start_time = 0; static int64_t rec_timestamp = 0; static int64_t input_ts_offset = 0; static int file_overwrite = 0; -static char *str_title = NULL; -static char *str_author = NULL; -static char *str_copyright = NULL; -static char *str_comment = NULL; -static char *str_genre = NULL; -static char *str_album = NULL; +static int metadata_count; +static AVMetadataTag *metadata; 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_pass = 0; -static char *pass_logfilename = NULL; +static char *pass_logfilename_prefix = NULL; static int audio_stream_copy = 0; static int video_stream_copy = 0; static int subtitle_stream_copy = 0; @@ -182,11 +187,12 @@ static int video_sync_method= -1; static int audio_sync_method= 0; static float audio_drift_threshold= 0.1; static int copy_ts= 0; -static int opt_shortest = 0; // +static int opt_shortest = 0; static int video_global_header = 0; static char *vstats_filename; static FILE *vstats_file; static int opt_programid = 0; +static int copy_initial_nonkeyframes = 0; static int rate_emu = 0; @@ -197,7 +203,6 @@ static int audio_volume = 256; static int exit_on_error = 0; static int using_stdin = 0; -static int using_vhook = 0; static int verbose = 1; static int thread_count= 1; static int q_pressed = 0; @@ -207,26 +212,28 @@ static int64_t extra_size = 0; static int nb_frames_dup = 0; static int nb_frames_drop = 0; static int input_sync; -static uint64_t limit_filesize = 0; // +static uint64_t limit_filesize = 0; +static int force_fps = 0; static int pgmyuv_compatibility_hack=0; static float dts_delta_threshold = 10; static unsigned int sws_flags = SWS_BICUBIC; -static const char **opt_names; -static int opt_name_count; -static AVCodecContext *avctx_opts[CODEC_TYPE_NB]; -static AVFormatContext *avformat_opts; -static struct SwsContext *sws_opts; static int64_t timer_start; +static uint8_t *audio_buf; +static uint8_t *audio_out; +static uint8_t *audio_out2; + +static short *samples; + static AVBitStreamFilterContext *video_bitstream_filters=NULL; static AVBitStreamFilterContext *audio_bitstream_filters=NULL; static AVBitStreamFilterContext *subtitle_bitstream_filters=NULL; static AVBitStreamFilterContext *bitstream_filters[MAX_FILES][MAX_STREAMS]; -#define DEFAULT_PASS_LOGFILENAME "ffmpeg2pass" +#define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass" struct AVInputStream; @@ -263,7 +270,7 @@ typedef struct AVOutputStream { ReSampleContext *resample; /* for audio resampling */ int reformat_pair; AVAudioConvert *reformat_ctx; - AVFifoBuffer fifo; /* for compression: one audio fifo per codec */ + AVFifoBuffer *fifo; /* for compression: one audio fifo per codec */ FILE *logfile; } AVOutputStream; @@ -276,7 +283,6 @@ typedef struct AVInputStream { int64_t sample_index; /* current sample */ int64_t start; /* time when read started */ - unsigned long frame; /* current frame */ int64_t next_pts; /* synthetic pts for cases where pkt.pts is not defined */ int64_t pts; /* current pts */ @@ -290,7 +296,7 @@ typedef struct AVInputFile { int nb_streams; /* nb streams we are aware of */ } AVInputFile; -#ifdef HAVE_TERMIOS_H +#if HAVE_TERMIOS_H /* init terminal so that we can grab keys */ static struct termios oldtty; @@ -298,7 +304,7 @@ static struct termios oldtty; static void term_exit(void) { -#ifdef HAVE_TERMIOS_H +#if HAVE_TERMIOS_H tcsetattr (0, TCSANOW, &oldtty); #endif } @@ -314,7 +320,7 @@ sigterm_handler(int sig) static void term_init(void) { -#ifdef HAVE_TERMIOS_H +#if HAVE_TERMIOS_H struct termios tty; tcgetattr (0, &tty); @@ -339,7 +345,7 @@ static void term_init(void) register a function to be called at normal program termination */ atexit(term_exit); -#ifdef CONFIG_BEOS_NETSERVER +#if CONFIG_BEOS_NETSERVER fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK); #endif } @@ -347,10 +353,10 @@ static void term_init(void) /* read a key without blocking */ static int read_key(void) { -#if defined(HAVE_TERMIOS_H) +#if HAVE_TERMIOS_H int n = 1; unsigned char ch; -#ifndef CONFIG_BEOS_NETSERVER +#if !CONFIG_BEOS_NETSERVER struct timeval tv; fd_set rfds; @@ -367,7 +373,7 @@ static int read_key(void) return n; } -#elif defined(HAVE_CONIO_H) +#elif HAVE_CONIO_H if(kbhit()) return(getch()); #endif @@ -391,9 +397,17 @@ static int av_exit(int ret) if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb) url_fclose(s->pb); for(j=0;jnb_streams;j++) { + av_metadata_free(&s->streams[j]->metadata); av_free(s->streams[j]->codec); av_free(s->streams[j]); } + for(j=0;jnb_programs;j++) { + av_metadata_free(&s->programs[j]->metadata); + } + for(j=0;jnb_chapters;j++) { + av_metadata_free(&s->chapters[j]->metadata); + } + av_metadata_free(&s->metadata); av_free(s); } for(i=0;iaudio_resample = 1; if (ost->audio_resample && !ost->resample) { - if (dec->sample_fmt != SAMPLE_FMT_S16) { - fprintf(stderr, "Audio resampler only works with 16 bits per sample, patch welcome.\n"); - av_exit(1); - } - ost->resample = audio_resample_init(enc->channels, dec->channels, - enc->sample_rate, dec->sample_rate); + if (dec->sample_fmt != SAMPLE_FMT_S16) + fprintf(stderr, "Warning, using s16 intermediate sample format for resampling\n"); + ost->resample = av_audio_resample_init(enc->channels, dec->channels, + enc->sample_rate, dec->sample_rate, + enc->sample_fmt, dec->sample_fmt, + 16, 10, 0, 0.8); if (!ost->resample) { fprintf(stderr, "Can not resample %d channels @ %d Hz to %d channels @ %d Hz\n", dec->channels, dec->sample_rate, @@ -557,7 +577,7 @@ static void do_audio_out(AVFormatContext *s, } #define MAKE_SFMT_PAIR(a,b) ((a)+SAMPLE_FMT_NB*(b)) - if (dec->sample_fmt!=enc->sample_fmt && + if (!ost->audio_resample && dec->sample_fmt!=enc->sample_fmt && MAKE_SFMT_PAIR(enc->sample_fmt,dec->sample_fmt)!=ost->reformat_pair) { if (!audio_out2) audio_out2 = av_malloc(audio_out_size); @@ -578,7 +598,7 @@ static void do_audio_out(AVFormatContext *s, if(audio_sync_method){ double delta = get_sync_ipts(ost) * enc->sample_rate - ost->sync_opts - - av_fifo_size(&ost->fifo)/(ost->st->codec->channels * 2); + - av_fifo_size(ost->fifo)/(ost->st->codec->channels * 2); double idelta= delta*ist->st->codec->sample_rate / enc->sample_rate; int byte_delta= ((int)idelta)*2*ist->st->codec->channels; @@ -615,13 +635,13 @@ static void do_audio_out(AVFormatContext *s, assert(ost->audio_resample); if(verbose > 2) fprintf(stderr, "compensating audio timestamp drift:%f compensation:%d in:%d\n", delta, comp, enc->sample_rate); -// fprintf(stderr, "drift:%f len:%d opts:%"PRId64" ipts:%"PRId64" fifo:%d\n", delta, -1, ost->sync_opts, (int64_t)(get_sync_ipts(ost) * enc->sample_rate), av_fifo_size(&ost->fifo)/(ost->st->codec->channels * 2)); +// fprintf(stderr, "drift:%f len:%d opts:%"PRId64" ipts:%"PRId64" fifo:%d\n", delta, -1, ost->sync_opts, (int64_t)(get_sync_ipts(ost) * enc->sample_rate), av_fifo_size(ost->fifo)/(ost->st->codec->channels * 2)); av_resample_compensate(*(struct AVResampleContext**)ost->resample, comp, enc->sample_rate); } } }else ost->sync_opts= lrintf(get_sync_ipts(ost) * enc->sample_rate) - - av_fifo_size(&ost->fifo)/(ost->st->codec->channels * 2); //FIXME wrong + - av_fifo_size(ost->fifo)/(ost->st->codec->channels * 2); //FIXME wrong if (ost->audio_resample) { buftmp = audio_buf; @@ -634,7 +654,7 @@ static void do_audio_out(AVFormatContext *s, size_out = size; } - if (dec->sample_fmt!=enc->sample_fmt) { + if (!ost->audio_resample && dec->sample_fmt!=enc->sample_fmt) { const void *ibuf[6]= {buftmp}; void *obuf[6]= {audio_out2}; int istride[6]= {isize}; @@ -653,24 +673,28 @@ static void do_audio_out(AVFormatContext *s, /* now encode as many frames as possible */ if (enc->frame_size > 1) { /* output resampled raw samples */ - if (av_fifo_realloc2(&ost->fifo, av_fifo_size(&ost->fifo) + size_out) < 0) { + if (av_fifo_realloc2(ost->fifo, av_fifo_size(ost->fifo) + size_out) < 0) { fprintf(stderr, "av_fifo_realloc2() failed\n"); av_exit(1); } - av_fifo_generic_write(&ost->fifo, buftmp, size_out, NULL); + av_fifo_generic_write(ost->fifo, buftmp, size_out, NULL); frame_bytes = enc->frame_size * osize * enc->channels; - while (av_fifo_size(&ost->fifo) >= frame_bytes) { + while (av_fifo_size(ost->fifo) >= frame_bytes) { AVPacket pkt; av_init_packet(&pkt); - av_fifo_read(&ost->fifo, audio_buf, frame_bytes); + av_fifo_generic_read(ost->fifo, audio_buf, frame_bytes, NULL); //FIXME pass ost->sync_opts as AVFrame.pts in avcodec_encode_audio() ret = avcodec_encode_audio(enc, audio_out, audio_out_size, (short *)audio_buf); + if (ret < 0) { + fprintf(stderr, "Audio encoding failed\n"); + av_exit(1); + } audio_size += ret; pkt.stream_index= ost->index; pkt.data= audio_out; @@ -698,6 +722,10 @@ static void do_audio_out(AVFormatContext *s, //FIXME pass ost->sync_opts as AVFrame.pts in avcodec_encode_audio() ret = avcodec_encode_audio(enc, audio_out, size_out, (short *)buftmp); + if (ret < 0) { + fprintf(stderr, "Audio encoding failed\n"); + av_exit(1); + } audio_size += ret; pkt.stream_index= ost->index; pkt.data= audio_out; @@ -719,7 +747,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 || using_vhook) { + if (do_deinterlace) { int size; /* create temporary picture */ @@ -747,10 +775,6 @@ static void pre_process_video_frame(AVInputStream *ist, AVPicture *picture, void picture2 = picture; } - if (ENABLE_VHOOK) - frame_hook_process(picture2, dec->pix_fmt, dec->width, dec->height, - 1000000 * ist->pts / AV_TIME_BASE); - if (picture != picture2) *picture = *picture2; *bufp = buf; @@ -844,11 +868,14 @@ static void do_video_out(AVFormatContext *s, //FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c if (vdelta < -1.1) nb_frames = 0; - else if (video_sync_method == 2) + else if (video_sync_method == 2 || (video_sync_method<0 && (s->oformat->flags & AVFMT_VARIABLE_FPS))){ + if(vdelta<=-0.6){ + nb_frames=0; + }else if(vdelta>0.6) ost->sync_opts= lrintf(get_sync_ipts(ost) / av_q2d(enc->time_base)); - else if (vdelta > 1.1) + }else if (vdelta > 1.1) nb_frames = lrintf(vdelta); -//fprintf(stderr, "vdelta:%f, ost->sync_opts:%"PRId64", ost->sync_ipts:%f nb_frames:%d\n", vdelta, ost->sync_opts, ost->sync_ipts, nb_frames); +//fprintf(stderr, "vdelta:%f, ost->sync_opts:%"PRId64", ost->sync_ipts:%f nb_frames:%d\n", vdelta, ost->sync_opts, get_sync_ipts(ost), nb_frames); if (nb_frames == 0){ ++nb_frames_drop; if (verbose>2) @@ -867,7 +894,7 @@ static void do_video_out(AVFormatContext *s, if (ost->video_crop) { if (av_picture_crop((AVPicture *)&picture_crop_temp, (AVPicture *)in_picture, dec->pix_fmt, ost->topBand, ost->leftBand) < 0) { - av_log(NULL, AV_LOG_ERROR, "error cropping picture\n"); + fprintf(stderr, "error cropping picture\n"); if (exit_on_error) av_exit(1); return; @@ -884,7 +911,7 @@ static void do_video_out(AVFormatContext *s, final_picture = &ost->pict_tmp; if (ost->video_resample) { if (av_picture_crop((AVPicture *)&picture_pad_temp, (AVPicture *)final_picture, enc->pix_fmt, ost->padtop, ost->padleft) < 0) { - av_log(NULL, AV_LOG_ERROR, "error padding picture\n"); + fprintf(stderr, "error padding picture\n"); if (exit_on_error) av_exit(1); return; @@ -932,7 +959,7 @@ static void do_video_out(AVFormatContext *s, /* better than nothing: use input picture interlaced settings */ big_picture.interlaced_frame = in_picture->interlaced_frame; - if(avctx_opts[CODEC_TYPE_VIDEO]->flags & (CODEC_FLAG_INTERLACED_DCT|CODEC_FLAG_INTERLACED_ME)){ + if(avcodec_opts[CODEC_TYPE_VIDEO]->flags & (CODEC_FLAG_INTERLACED_DCT|CODEC_FLAG_INTERLACED_ME)){ if(top_field_first == -1) big_picture.top_field_first = in_picture->top_field_first; else @@ -954,7 +981,7 @@ static void do_video_out(AVFormatContext *s, ret = avcodec_encode_video(enc, bit_buffer, bit_buffer_size, &big_picture); - if (ret == -1) { + if (ret < 0) { fprintf(stderr, "Video encoding failed\n"); av_exit(1); } @@ -1034,7 +1061,7 @@ static void print_report(AVFormatContext **output_files, { char buf[1024]; AVOutputStream *ost; - AVFormatContext *oc, *os; + AVFormatContext *oc; int64_t total_size; AVCodecContext *enc; int frame_number, vid, i; @@ -1067,7 +1094,6 @@ static void print_report(AVFormatContext **output_files, vid = 0; for(i=0;ifile_index]; enc = ost->st->codec; if (vid && enc->codec_type == CODEC_TYPE_VIDEO) { snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "q=%2.1f ", @@ -1087,7 +1113,7 @@ static void print_report(AVFormatContext **output_files, if(qp_hist){ int j; int qp= lrintf(enc->coded_frame->quality/(float)FF_QP2LAMBDA); - if(qp>=0 && qp=0 && qpnext_pts == AV_NOPTS_VALUE) ist->next_pts= ist->pts; if (pkt == NULL) { /* EOF handling */ - ptr = NULL; - len = 0; + av_init_packet(&avpkt); + avpkt.data = NULL; + avpkt.size = 0; goto handle_eof; + } else { + avpkt = *pkt; } if(pkt->dts != AV_NOPTS_VALUE) ist->next_pts = ist->pts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q); - len = pkt->size; - ptr = pkt->data; - //while we have more to decode or while the decoder did output something on EOF - while (len > 0 || (!pkt && ist->next_pts != ist->pts)) { + while (avpkt.size > 0 || (!pkt && ist->next_pts != ist->pts)) { handle_eof: ist->pts= ist->next_pts; - if(len && len != pkt->size && verbose>0) + if(avpkt.size && avpkt.size != pkt->size && verbose>0) fprintf(stderr, "Multiple frames in a packet from stream %d\n", pkt->stream_index); /* decode the packet if needed */ @@ -1209,12 +1234,12 @@ static int output_packet(AVInputStream *ist, int ist_index, data_size= samples_size; /* XXX: could avoid copy if PCM 16 bits with same endianness as CPU */ - ret = avcodec_decode_audio2(ist->st->codec, samples, &data_size, - ptr, len); + ret = avcodec_decode_audio3(ist->st->codec, samples, &data_size, + &avpkt); if (ret < 0) goto fail_decode; - ptr += ret; - len -= ret; + avpkt.data += ret; + avpkt.size -= ret; /* Some bug in mpeg audio decoder gives */ /* data_size < 0, it seems they are overflows */ if (data_size <= 0) { @@ -1230,8 +1255,8 @@ static int output_packet(AVInputStream *ist, int ist_index, /* XXX: allocate picture correctly */ avcodec_get_frame_defaults(&picture); - ret = avcodec_decode_video(ist->st->codec, - &picture, &got_picture, ptr, len); + ret = avcodec_decode_video2(ist->st->codec, + &picture, &got_picture, &avpkt); ist->st->quality= picture.quality; if (ret < 0) goto fail_decode; @@ -1240,22 +1265,23 @@ static int output_packet(AVInputStream *ist, int ist_index, goto discard_packet; } if (ist->st->codec->time_base.num != 0) { + int ticks= ist->st->parser ? ist->st->parser->repeat_pict+1 : ist->st->codec->ticks_per_frame; ist->next_pts += ((int64_t)AV_TIME_BASE * - ist->st->codec->time_base.num) / + ist->st->codec->time_base.num * ticks) / ist->st->codec->time_base.den; } - len = 0; + avpkt.size = 0; break; case CODEC_TYPE_SUBTITLE: - ret = avcodec_decode_subtitle(ist->st->codec, - &subtitle, &got_subtitle, ptr, len); + ret = avcodec_decode_subtitle2(ist->st->codec, + &subtitle, &got_subtitle, &avpkt); if (ret < 0) goto fail_decode; if (!got_subtitle) { goto discard_packet; } subtitle_to_free = &subtitle; - len = 0; + avpkt.size = 0; break; default: goto fail_decode; @@ -1268,16 +1294,17 @@ static int output_packet(AVInputStream *ist, int ist_index, break; case CODEC_TYPE_VIDEO: if (ist->st->codec->time_base.num != 0) { + int ticks= ist->st->parser ? ist->st->parser->repeat_pict+1 : ist->st->codec->ticks_per_frame; ist->next_pts += ((int64_t)AV_TIME_BASE * - ist->st->codec->time_base.num) / + ist->st->codec->time_base.num * ticks) / ist->st->codec->time_base.den; } break; } - data_buf = ptr; - data_size = len; - ret = len; - len = 0; + data_buf = avpkt.data; + data_size = avpkt.size; + ret = avpkt.size; + avpkt.size = 0; } buffer_to_free = NULL; @@ -1301,28 +1328,13 @@ static int output_packet(AVInputStream *ist, int ist_index, } /* frame rate emulation */ - if (ist->st->codec->rate_emu) { - int64_t pts = av_rescale((int64_t) ist->frame * ist->st->codec->time_base.num, 1000000, ist->st->codec->time_base.den); + if (rate_emu) { + int64_t pts = av_rescale(ist->pts, 1000000, AV_TIME_BASE); 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) @@ -1362,9 +1374,11 @@ static int output_packet(AVInputStream *ist, int ist_index, } else { AVFrame avframe; //FIXME/XXX remove this AVPacket opkt; + int64_t ost_tb_start_time= av_rescale_q(start_time, AV_TIME_BASE_Q, ost->st->time_base); + av_init_packet(&opkt); - if (!ost->frame_number && !(pkt->flags & PKT_FLAG_KEY)) + if ((!ost->frame_number && !(pkt->flags & PKT_FLAG_KEY)) && !copy_initial_nonkeyframes) continue; /* no reencoding needed : output the packet directly */ @@ -1383,7 +1397,7 @@ static int output_packet(AVInputStream *ist, int ist_index, opkt.stream_index= ost->index; if(pkt->pts != AV_NOPTS_VALUE) - opkt.pts= av_rescale_q(pkt->pts, ist->st->time_base, ost->st->time_base); + opkt.pts= av_rescale_q(pkt->pts, ist->st->time_base, ost->st->time_base) - ost_tb_start_time; else opkt.pts= AV_NOPTS_VALUE; @@ -1391,6 +1405,7 @@ static int output_packet(AVInputStream *ist, int ist_index, opkt.dts = av_rescale_q(ist->pts, AV_TIME_BASE_Q, ost->st->time_base); else opkt.dts = av_rescale_q(pkt->dts, ist->st->time_base, ost->st->time_base); + opkt.dts -= ost_tb_start_time; opkt.duration = av_rescale_q(pkt->duration, ist->st->time_base, ost->st->time_base); opkt.flags= pkt->flags; @@ -1411,8 +1426,9 @@ static int output_packet(AVInputStream *ist, int ist_index, if (subtitle_to_free) { if (subtitle_to_free->rects != NULL) { for (i = 0; i < subtitle_to_free->num_rects; i++) { - av_free(subtitle_to_free->rects[i].bitmap); - av_free(subtitle_to_free->rects[i].rgba_palette); + av_freep(&subtitle_to_free->rects[i]->pict.data[0]); + av_freep(&subtitle_to_free->rects[i]->pict.data[1]); + av_freep(&subtitle_to_free->rects[i]); } av_freep(&subtitle_to_free->rects); } @@ -1444,24 +1460,35 @@ static int output_packet(AVInputStream *ist, int ist_index, switch(ost->st->codec->codec_type) { case CODEC_TYPE_AUDIO: - fifo_bytes = av_fifo_size(&ost->fifo); + fifo_bytes = av_fifo_size(ost->fifo); ret = 0; /* encode any samples remaining in fifo */ if(fifo_bytes > 0 && enc->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME) { + int osize = av_get_bits_per_sample_format(enc->sample_fmt) >> 3; int fs_tmp = enc->frame_size; - enc->frame_size = fifo_bytes / (2 * enc->channels); - av_fifo_read(&ost->fifo, (uint8_t *)samples, fifo_bytes); - ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, samples); + enc->frame_size = fifo_bytes / (osize * enc->channels); + av_fifo_generic_read(ost->fifo, samples, fifo_bytes, NULL); + ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, samples); + pkt.duration = av_rescale((int64_t)enc->frame_size*ost->st->time_base.den, + ost->st->time_base.num, enc->sample_rate); enc->frame_size = fs_tmp; } if(ret <= 0) { ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, NULL); } + if (ret < 0) { + fprintf(stderr, "Audio encoding failed\n"); + av_exit(1); + } audio_size += ret; pkt.flags |= PKT_FLAG_KEY; break; case CODEC_TYPE_VIDEO: ret = avcodec_encode_video(enc, bit_buffer, bit_buffer_size, NULL); + if (ret < 0) { + fprintf(stderr, "Video encoding failed\n"); + av_exit(1); + } video_size += ret; if(enc->coded_frame && enc->coded_frame->key_frame) pkt.flags |= PKT_FLAG_KEY; @@ -1497,6 +1524,7 @@ static void print_sdp(AVFormatContext **avc, int n) avf_sdp_create(avc, n, sdp, sizeof(sdp)); printf("SDP:\n%s\n", sdp); + fflush(stdout); } static int stream_index_from_inputs(AVFormatContext **input_files, @@ -1534,14 +1562,17 @@ 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 = 0, i, j, k, n, nb_istreams = 0, nb_ostreams = 0; AVFormatContext *is, *os; AVCodecContext *codec, *icodec; AVOutputStream *ost, **ost_table = NULL; AVInputStream *ist, **ist_table = NULL; AVInputFile *file_table; + char error[1024]; int key; int want_sdp = 1; + uint8_t no_packet[MAX_FILES]={0}; + int no_packet_count=0; file_table= av_mallocz(nb_input_files * sizeof(AVInputFile)); if (!file_table) @@ -1578,9 +1609,8 @@ static int av_encode(AVFormatContext **output_files, ist->discard = 1; /* the stream is discarded by default (changed later) */ - if (ist->st->codec->rate_emu) { + if (rate_emu) { ist->start = av_gettime(); - ist->frame = 0; } } } @@ -1590,7 +1620,8 @@ static int av_encode(AVFormatContext **output_files, for(i=0;inb_streams) { - fprintf(stderr, "Output file does not contain any stream\n"); + dump_format(output_files[i], i, output_files[i]->filename, 1); + fprintf(stderr, "Output file #%d does not contain any stream\n", i); av_exit(1); } nb_ostreams += os->nb_streams; @@ -1704,6 +1735,7 @@ static int av_encode(AVFormatContext **output_files, /* for each output stream, we compute the right encoding parameters */ for(i=0;ifile_index]; ist = ist_table[ost->source_index]; @@ -1711,11 +1743,13 @@ static int av_encode(AVFormatContext **output_files, codec = ost->st->codec; icodec = ist->st->codec; - if (!ost->st->language[0]) - av_strlcpy(ost->st->language, ist->st->language, - sizeof(ost->st->language)); + if ((lang=av_metadata_get(ist->st->metadata, "language", NULL, 0)) + && !av_metadata_get(ost->st->metadata, "language", NULL, 0)) + av_metadata_set(&ost->st->metadata, "language", lang->value); ost->st->disposition = ist->st->disposition; + codec->bits_per_raw_sample= icodec->bits_per_raw_sample; + codec->chroma_sample_location = icodec->chroma_sample_location; if (ost->st->stream_copy) { /* if stream_copy is selected, no need to decode or encode */ @@ -1732,9 +1766,10 @@ static int av_encode(AVFormatContext **output_files, codec->bit_rate = icodec->bit_rate; codec->extradata= icodec->extradata; codec->extradata_size= icodec->extradata_size; - if(av_q2d(icodec->time_base) > av_q2d(ist->st->time_base) && av_q2d(ist->st->time_base) < 1.0/1000) + if(av_q2d(icodec->time_base)*icodec->ticks_per_frame > av_q2d(ist->st->time_base) && av_q2d(ist->st->time_base) < 1.0/1000){ codec->time_base = icodec->time_base; - else + codec->time_base.num *= icodec->ticks_per_frame; + }else codec->time_base = ist->st->time_base; switch(codec->codec_type) { case CODEC_TYPE_AUDIO: @@ -1742,6 +1777,7 @@ static int av_encode(AVFormatContext **output_files, fprintf(stderr,"-acodec copy and -vol are incompatible (frames are not decoded)\n"); av_exit(1); } + codec->channel_layout = icodec->channel_layout; codec->sample_rate = icodec->sample_rate; codec->channels = icodec->channels; codec->frame_size = icodec->frame_size; @@ -1752,16 +1788,14 @@ static int av_encode(AVFormatContext **output_files, codec->block_align= 0; break; case CODEC_TYPE_VIDEO: - if(using_vhook) { - fprintf(stderr,"-vcodec copy and -vhook are incompatible (frames are not decoded)\n"); - av_exit(1); - } codec->pix_fmt = icodec->pix_fmt; codec->width = icodec->width; codec->height = icodec->height; codec->has_b_frames = icodec->has_b_frames; break; case CODEC_TYPE_SUBTITLE: + codec->width = icodec->width; + codec->height = icodec->height; break; default: abort(); @@ -1769,7 +1803,8 @@ static int av_encode(AVFormatContext **output_files, } else { switch(codec->codec_type) { case CODEC_TYPE_AUDIO: - if (av_fifo_init(&ost->fifo, 1024)) + ost->fifo= av_fifo_alloc(1024); + if(!ost->fifo) goto fail; ost->reformat_pair = MAKE_SFMT_PAIR(SAMPLE_FMT_NONE,SAMPLE_FMT_NONE); ost->audio_resample = codec->sample_rate != icodec->sample_rate || audio_sync_method > 1; @@ -1824,6 +1859,7 @@ static int av_encode(AVFormatContext **output_files, av_exit(1); } ost->resample_height = icodec->height - (frame_topBand + frame_bottomBand); + codec->bits_per_raw_sample= 0; } ost->encoding_needed = 1; ist->decoding_needed = 1; @@ -1845,12 +1881,12 @@ static int av_encode(AVFormatContext **output_files, char *logbuffer; snprintf(logfilename, sizeof(logfilename), "%s-%d.log", - pass_logfilename ? - pass_logfilename : DEFAULT_PASS_LOGFILENAME, i); + pass_logfilename_prefix ? pass_logfilename_prefix : DEFAULT_PASS_LOGFILENAME_PREFIX, + i); if (codec->flags & CODEC_FLAG_PASS1) { f = fopen(logfilename, "w"); if (!f) { - perror(logfilename); + fprintf(stderr, "Cannot write log file '%s' for pass-1 encoding: %s\n", logfilename, strerror(errno)); av_exit(1); } ost->logfile = f; @@ -1858,7 +1894,7 @@ static int av_encode(AVFormatContext **output_files, /* read the log file */ f = fopen(logfilename, "r"); if (!f) { - perror(logfilename); + fprintf(stderr, "Cannot read log file '%s' for pass-2 encoding: %s\n", logfilename, strerror(errno)); av_exit(1); } fseek(f, 0, SEEK_END); @@ -1878,54 +1914,35 @@ static int av_encode(AVFormatContext **output_files, } if(codec->codec_type == CODEC_TYPE_VIDEO){ int size= codec->width * codec->height; - bit_buffer_size= FFMAX(bit_buffer_size, 4*size); + bit_buffer_size= FFMAX(bit_buffer_size, 6*size + 200); } } if (!bit_buffer) bit_buffer = av_malloc(bit_buffer_size); - if (!bit_buffer) + if (!bit_buffer) { + ret = AVERROR(ENOMEM); goto fail; - - /* dump the file output parameters - cannot be done before in case - of stream copy */ - for(i=0;ifilename, 1); - } - - /* dump the stream mapping */ - if (verbose >= 0) { - fprintf(stderr, "Stream mapping:\n"); - for(i=0;i #%d.%d", - ist_table[ost->source_index]->file_index, - ist_table[ost->source_index]->index, - ost->file_index, - ost->index); - if (ost->sync_ist != ist_table[ost->source_index]) - fprintf(stderr, " [sync #%d.%d]", - ost->sync_ist->file_index, - ost->sync_ist->index); - fprintf(stderr, "\n"); - } } /* open each encoder */ for(i=0;iencoding_needed) { - AVCodec *codec; - codec = avcodec_find_encoder(ost->st->codec->codec_id); + AVCodec *codec = output_codecs[i]; + if (!codec) + codec = avcodec_find_encoder(ost->st->codec->codec_id); if (!codec) { - fprintf(stderr, "Unsupported codec for output stream #%d.%d\n", + snprintf(error, sizeof(error), "Unsupported codec for output stream #%d.%d", ost->file_index, ost->index); - av_exit(1); + ret = AVERROR(EINVAL); + goto dump_format; } if (avcodec_open(ost->st->codec, codec) < 0) { - fprintf(stderr, "Error while opening codec for output stream #%d.%d - maybe incorrect parameters such as bit_rate, rate, width or height\n", + snprintf(error, sizeof(error), "Error while opening codec for output stream #%d.%d - maybe incorrect parameters such as bit_rate, rate, width or height", ost->file_index, ost->index); - av_exit(1); + ret = AVERROR(EINVAL); + goto dump_format; } extra_size += ost->st->codec->extradata_size; } @@ -1935,17 +1952,20 @@ static int av_encode(AVFormatContext **output_files, for(i=0;idecoding_needed) { - AVCodec *codec; - codec = avcodec_find_decoder(ist->st->codec->codec_id); + AVCodec *codec = input_codecs[i]; + if (!codec) + codec = avcodec_find_decoder(ist->st->codec->codec_id); if (!codec) { - fprintf(stderr, "Unsupported codec (id=%d) for input stream #%d.%d\n", + snprintf(error, sizeof(error), "Unsupported codec (id=%d) for input stream #%d.%d", ist->st->codec->codec_id, ist->file_index, ist->index); - av_exit(1); + ret = AVERROR(EINVAL); + goto dump_format; } if (avcodec_open(ist->st->codec, codec) < 0) { - fprintf(stderr, "Error while opening codec for input stream #%d.%d\n", + snprintf(error, sizeof(error), "Error while opening codec for input stream #%d.%d", ist->file_index, ist->index); - av_exit(1); + ret = AVERROR(EINVAL); + goto dump_format; } //if (ist->st->codec->codec_type == CODEC_TYPE_VIDEO) // ist->st->codec->flags |= CODEC_FLAG_REPEAT_FIELD; @@ -1955,7 +1975,6 @@ static int av_encode(AVFormatContext **output_files, /* init pts */ for(i=0;ifile_index]; ist->pts = 0; ist->next_pts = AV_NOPTS_VALUE; ist->is_start = 1; @@ -1965,45 +1984,77 @@ static int av_encode(AVFormatContext **output_files, for (i=0;i= nb_output_files) { - fprintf(stderr, "Invalid output file index %d map_meta_data(%d,%d)\n", out_file_index, out_file_index, in_file_index); + snprintf(error, sizeof(error), "Invalid output file index %d map_meta_data(%d,%d)", + out_file_index, out_file_index, in_file_index); ret = AVERROR(EINVAL); - goto fail; + goto dump_format; } if (in_file_index < 0 || in_file_index >= nb_input_files) { - fprintf(stderr, "Invalid input file index %d map_meta_data(%d,%d)\n", in_file_index, out_file_index, in_file_index); + snprintf(error, sizeof(error), "Invalid input file index %d map_meta_data(%d,%d)", + in_file_index, out_file_index, in_file_index); ret = AVERROR(EINVAL); - goto fail; + goto dump_format; } out_file = output_files[out_file_index]; in_file = input_files[in_file_index]; - strcpy(out_file->title, in_file->title); - strcpy(out_file->author, in_file->author); - strcpy(out_file->copyright, in_file->copyright); - strcpy(out_file->comment, in_file->comment); - strcpy(out_file->album, in_file->album); - out_file->year = in_file->year; - out_file->track = in_file->track; - strcpy(out_file->genre, in_file->genre); + + mtag=NULL; + while((mtag=av_metadata_get(in_file->metadata, "", mtag, AV_METADATA_IGNORE_SUFFIX))) + av_metadata_set(&out_file->metadata, mtag->key, mtag->value); + av_metadata_conv(out_file, out_file->oformat->metadata_conv, + in_file->iformat->metadata_conv); } /* open files and write file headers */ for(i=0;ioformat->name, "rtp")) { want_sdp = 0; } } + + dump_format: + /* dump the file output parameters - cannot be done before in case + of stream copy */ + for(i=0;ifilename, 1); + } + + /* dump the stream mapping */ + if (verbose >= 0) { + fprintf(stderr, "Stream mapping:\n"); + for(i=0;i #%d.%d", + ist_table[ost->source_index]->file_index, + ist_table[ost->source_index]->index, + ost->file_index, + ost->index); + if (ost->sync_ist != ist_table[ost->source_index]) + fprintf(stderr, " [sync #%d.%d]", + ost->sync_ist->file_index, + ost->sync_ist->index); + fprintf(stderr, "\n"); + } + } + + if (ret) { + fprintf(stderr, "%s\n", error); + goto fail; + } + if (want_sdp) { print_sdp(output_files, nb_output_files); } @@ -2014,7 +2065,6 @@ static int av_encode(AVFormatContext **output_files, } term_init(); - key = -1; timer_start = av_gettime(); for(; received_sigterm == 0;) { @@ -2044,6 +2094,8 @@ static int av_encode(AVFormatContext **output_files, ost = ost_table[i]; os = output_files[ost->file_index]; ist = ist_table[ost->source_index]; + if(no_packet[ist->file_index]) + continue; if(ost->st->codec->codec_type == CODEC_TYPE_VIDEO) opts = ost->sync_opts * av_q2d(ost->st->codec->time_base); else @@ -2066,6 +2118,12 @@ static int av_encode(AVFormatContext **output_files, } /* if none, if is finished */ if (file_index < 0) { + if(no_packet_count){ + no_packet_count=0; + memset(no_packet, 0, sizeof(no_packet)); + usleep(10000); + continue; + } break; } @@ -2079,7 +2137,13 @@ static int av_encode(AVFormatContext **output_files, /* read a frame from it and output it in the fifo */ is = input_files[file_index]; - if (av_read_frame(is, &pkt) < 0) { + ret= av_read_frame(is, &pkt); + if(ret == AVERROR(EAGAIN)){ + no_packet[file_index]=1; + no_packet_count++; + continue; + } + if (ret < 0) { file_table[file_index].eof_reached = 1; if (opt_shortest) break; @@ -2087,6 +2151,9 @@ static int av_encode(AVFormatContext **output_files, continue; } + no_packet_count=0; + memset(no_packet, 0, sizeof(no_packet)); + if (do_pkt_dump) { av_pkt_dump_log(NULL, AV_LOG_DEBUG, &pkt, do_hex_dump); } @@ -2112,7 +2179,8 @@ static int av_encode(AVFormatContext **output_files, } // fprintf(stderr, "next:%"PRId64" dts:%"PRId64" off:%"PRId64" %d\n", ist->next_pts, pkt.dts, input_files_ts_offset[ist->file_index], ist->st->codec->codec_type); - if (pkt.dts != AV_NOPTS_VALUE && ist->next_pts != AV_NOPTS_VALUE) { + if (pkt.dts != AV_NOPTS_VALUE && ist->next_pts != AV_NOPTS_VALUE + && (is->iformat->flags & AVFMT_TS_DISCONT)) { int64_t pkt_dts= av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q); int64_t delta= pkt_dts - ist->next_pts; if((FFABS(delta) > 1LL*dts_delta_threshold*AV_TIME_BASE || pkt_dts+1pts)&& !copy_ts){ @@ -2181,9 +2249,9 @@ static int av_encode(AVFormatContext **output_files, } /* finished ! */ - ret = 0; - fail1: + + fail: av_freep(&bit_buffer); av_free(file_table); @@ -2202,7 +2270,7 @@ static int av_encode(AVFormatContext **output_files, fclose(ost->logfile); ost->logfile = NULL; } - av_fifo_free(&ost->fifo); /* works even if fifo is not + av_fifo_free(ost->fifo); /* works even if fifo is not initialized but set to zero */ av_free(ost->pict_tmp.data[0]); if (ost->video_resample) @@ -2217,9 +2285,6 @@ static int av_encode(AVFormatContext **output_files, av_free(ost_table); } return ret; - fail: - ret = AVERROR(ENOMEM); - goto fail1; } #if 0 @@ -2262,42 +2327,6 @@ static void opt_format(const char *arg) } } -static int opt_default(const char *opt, const char *arg){ - int type; - const AVOption *o= NULL; - int opt_types[]={AV_OPT_FLAG_VIDEO_PARAM, AV_OPT_FLAG_AUDIO_PARAM, 0, AV_OPT_FLAG_SUBTITLE_PARAM, 0}; - - for(type=0; typename; - - if(avctx_opts[0]->debug || avformat_opts->debug) - av_log_set_level(AV_LOG_DEBUG); - return 0; -} - static void opt_video_rc_override_string(const char *arg) { video_rc_override_string = arg; @@ -2309,10 +2338,16 @@ static int opt_me_threshold(const char *opt, const char *arg) return 0; } +static int opt_loglevel(const char *opt, const char *arg) +{ + int level = parse_number_or_die(opt, arg, OPT_INT, INT_MIN, INT_MAX); + av_log_set_level(level); + return 0; +} + static int opt_verbose(const char *opt, const char *arg) { verbose = parse_number_or_die(opt, arg, OPT_INT64, -10, 10); - av_log_set_level(verbose); return 0; } @@ -2331,7 +2366,7 @@ static int opt_bitrate(const char *opt, const char *arg) opt_default(opt, arg); - if (av_get_int(avctx_opts[codec_type], "b", NULL) < 1000) + if (av_get_int(avcodec_opts[codec_type], "b", NULL) < 1000) fprintf(stderr, "WARNING: The bitrate parameter is set too low. It takes bits/s as argument, not kbits/s\n"); return 0; @@ -2519,9 +2554,13 @@ static void list_fmts(void (*get_fmt_string)(char *buf, int buf_size, int fmt), static void opt_frame_pix_fmt(const char *arg) { - if (strcmp(arg, "list")) + if (strcmp(arg, "list")) { frame_pix_fmt = avcodec_get_pix_fmt(arg); - else { + if (frame_pix_fmt == PIX_FMT_NONE) { + fprintf(stderr, "Unknown pixel format requested: %s\n", arg); + av_exit(1); + } + } else { list_fmts(avcodec_pix_fmt_string, PIX_FMT_NB); av_exit(0); } @@ -2551,6 +2590,24 @@ static void opt_frame_aspect_ratio(const char *arg) frame_aspect_ratio = ar; } +static int opt_metadata(const char *opt, const char *arg) +{ + char *mid= strchr(arg, '='); + + if(!mid){ + fprintf(stderr, "Missing =\n"); + av_exit(1); + } + *mid++= 0; + + metadata_count++; + metadata= av_realloc(metadata, sizeof(*metadata)*metadata_count); + metadata[metadata_count-1].key = av_strdup(arg); + metadata[metadata_count-1].value= av_strdup(mid); + + return 0; +} + static void opt_qscale(const char *arg) { video_qscale = atof(arg); @@ -2569,7 +2626,7 @@ static void opt_top_field_first(const char *arg) static int opt_thread_count(const char *opt, const char *arg) { thread_count= parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX); -#if !defined(HAVE_THREADS) +#if !HAVE_THREADS if (verbose >= 0) fprintf(stderr, "Warning: not compiled with thread support, using thread emulation\n"); #endif @@ -2642,29 +2699,6 @@ static void opt_video_tag(const char *arg) video_codec_tag= arg[0] + (arg[1]<<8) + (arg[2]<<16) + (arg[3]<<24); } -#ifdef CONFIG_VHOOK -static void add_frame_hooker(const char *arg) -{ - int argc = 0; - char *argv[64]; - int i; - char *args = av_strdup(arg); - - using_vhook = 1; - - argv[0] = strtok(args, " "); - while (argc < 62 && (argv[++argc] = strtok(NULL, " "))) { - } - - i = frame_hook_add(argc, argv); - - if (i != 0) { - fprintf(stderr, "Failed to add video hook function: %s\n", arg); - av_exit(1); - } -} -#endif - static void opt_video_codec(const char *arg) { opt_codec(&video_stream_copy, &video_codec_name, CODEC_TYPE_VIDEO, arg); @@ -2675,6 +2709,15 @@ static void opt_subtitle_codec(const char *arg) opt_codec(&subtitle_stream_copy, &subtitle_codec_name, CODEC_TYPE_SUBTITLE, arg); } +static void opt_subtitle_tag(const char *arg) +{ + char *tail; + subtitle_codec_tag= strtol(arg, &tail, 0); + + if(!tail || *tail) + subtitle_codec_tag= arg[0] + (arg[1]<<8) + (arg[2]<<16) + (arg[3]<<24); +} + static void opt_map(const char *arg) { AVStreamMap *m; @@ -2765,29 +2808,16 @@ static enum CodecID find_codec_or_die(const char *name, int type, int encoder) avcodec_find_encoder_by_name(name) : avcodec_find_decoder_by_name(name); if(!codec) { - av_log(NULL, AV_LOG_ERROR, "Unknown %s '%s'\n", codec_string, name); + fprintf(stderr, "Unknown %s '%s'\n", codec_string, name); av_exit(1); } if(codec->type != type) { - av_log(NULL, AV_LOG_ERROR, "Invalid %s type '%s'\n", codec_string, name); + fprintf(stderr, "Invalid %s type '%s'\n", codec_string, name); av_exit(1); } return codec->id; } -static void set_context_opts(void *ctx, void *opts_ctx, int flags) -{ - int i; - for(i=0; iflags & flags) == flags)) - av_set_string2(ctx, opt_names[i], str, 1); - } -} - static void opt_input_file(const char *filename) { AVFormatContext *ic; @@ -2802,7 +2832,7 @@ static void opt_input_file(const char *filename) !strcmp(filename, "/dev/stdin"); /* get default parameters from command line */ - ic = av_alloc_format_context(); + ic = avformat_alloc_context(); memset(ap, 0, sizeof(*ap)); ap->prealloced_context = 1; @@ -2826,6 +2856,7 @@ static void opt_input_file(const char *filename) ic->video_codec_id = find_codec_or_die(video_codec_name , CODEC_TYPE_VIDEO , 0); ic->audio_codec_id = find_codec_or_die(audio_codec_name , CODEC_TYPE_AUDIO , 0); ic->subtitle_codec_id= find_codec_or_die(subtitle_codec_name, CODEC_TYPE_SUBTITLE, 0); + ic->flags |= AVFMT_FLAG_NONBLOCK; /* open the input file with generic libav function */ err = av_open_input_file(&ic, filename, file_iformat, 0, ap); @@ -2874,16 +2905,18 @@ static void opt_input_file(const char *filename) enc->thread_count= thread_count; switch(enc->codec_type) { case CODEC_TYPE_AUDIO: - set_context_opts(enc, avctx_opts[CODEC_TYPE_AUDIO], AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM); + set_context_opts(enc, avcodec_opts[CODEC_TYPE_AUDIO], AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM); //fprintf(stderr, "\nInput Audio channels: %d", enc->channels); + channel_layout = enc->channel_layout; audio_channels = enc->channels; audio_sample_rate = enc->sample_rate; audio_sample_fmt = enc->sample_fmt; + input_codecs[nb_icodecs++] = avcodec_find_decoder_by_name(audio_codec_name); if(audio_disable) ic->streams[i]->discard= AVDISCARD_ALL; break; case CODEC_TYPE_VIDEO: - set_context_opts(enc, avctx_opts[CODEC_TYPE_VIDEO], AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM); + set_context_opts(enc, avcodec_opts[CODEC_TYPE_VIDEO], AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM); frame_height = enc->height; frame_width = enc->width; if(ic->streams[i]->sample_aspect_ratio.num) @@ -2910,7 +2943,7 @@ static void opt_input_file(const char *filename) frame_rate.num = rfps; frame_rate.den = rfps_base; - enc->rate_emu = rate_emu; + input_codecs[nb_icodecs++] = avcodec_find_decoder_by_name(video_codec_name); if(video_disable) ic->streams[i]->discard= AVDISCARD_ALL; else if(video_discard) @@ -2919,11 +2952,13 @@ static void opt_input_file(const char *filename) case CODEC_TYPE_DATA: break; case CODEC_TYPE_SUBTITLE: + input_codecs[nb_icodecs++] = avcodec_find_decoder_by_name(subtitle_codec_name); if(subtitle_disable) ic->streams[i]->discard = AVDISCARD_ALL; break; case CODEC_TYPE_ATTACHMENT: case CODEC_TYPE_UNKNOWN: + nb_icodecs++; break; default: abort(); @@ -2942,7 +2977,6 @@ static void opt_input_file(const char *filename) video_channel = 0; - rate_emu = 0; av_freep(&video_codec_name); av_freep(&audio_codec_name); av_freep(&subtitle_codec_name); @@ -3011,16 +3045,17 @@ static void new_video_stream(AVFormatContext *oc) if( (video_global_header&1) || (video_global_header==0 && (oc->oformat->flags & AVFMT_GLOBALHEADER))){ video_enc->flags |= CODEC_FLAG_GLOBAL_HEADER; - avctx_opts[CODEC_TYPE_VIDEO]->flags|= CODEC_FLAG_GLOBAL_HEADER; + avcodec_opts[CODEC_TYPE_VIDEO]->flags|= CODEC_FLAG_GLOBAL_HEADER; } if(video_global_header&2){ video_enc->flags2 |= CODEC_FLAG2_LOCAL_HEADER; - avctx_opts[CODEC_TYPE_VIDEO]->flags2|= CODEC_FLAG2_LOCAL_HEADER; + avcodec_opts[CODEC_TYPE_VIDEO]->flags2|= CODEC_FLAG2_LOCAL_HEADER; } if (video_stream_copy) { st->stream_copy = 1; video_enc->codec_type = CODEC_TYPE_VIDEO; + video_enc->sample_aspect_ratio = st->sample_aspect_ratio = av_d2q(frame_aspect_ratio*frame_height/frame_width, 255); } else { const char *p; @@ -3028,32 +3063,23 @@ static void new_video_stream(AVFormatContext *oc) AVCodec *codec; AVRational fps= frame_rate.num ? frame_rate : (AVRational){25,1}; - codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, CODEC_TYPE_VIDEO); - if (video_codec_name) + if (video_codec_name) { codec_id = find_codec_or_die(video_codec_name, CODEC_TYPE_VIDEO, 1); + codec = avcodec_find_encoder_by_name(video_codec_name); + output_codecs[nb_ocodecs] = codec; + } else { + codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, CODEC_TYPE_VIDEO); + codec = avcodec_find_encoder(codec_id); + } video_enc->codec_id = codec_id; - codec = avcodec_find_encoder(codec_id); - set_context_opts(video_enc, avctx_opts[CODEC_TYPE_VIDEO], AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM); + set_context_opts(video_enc, avcodec_opts[CODEC_TYPE_VIDEO], AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM); + if (codec && codec->supported_framerates && !force_fps) + fps = codec->supported_framerates[av_find_nearest_q_idx(fps, codec->supported_framerates)]; video_enc->time_base.den = fps.num; video_enc->time_base.num = fps.den; - if(codec && codec->supported_framerates){ - const AVRational *p= codec->supported_framerates; - const AVRational *best=NULL; - AVRational best_error= (AVRational){INT_MAX, 1}; - for(; p->den!=0; p++){ - AVRational error= av_sub_q(fps, *p); - if(error.num <0) error.num *= -1; - if(av_cmp_q(error, best_error) < 0){ - best_error= error; - best= p; - } - } - video_enc->time_base.den= best->num; - video_enc->time_base.num= best->den; - } video_enc->width = frame_width + frame_padright + frame_padleft; video_enc->height = frame_height + frame_padtop + frame_padbottom; @@ -3127,6 +3153,7 @@ static void new_video_stream(AVFormatContext *oc) } } } + nb_ocodecs++; /* reset some key parameters */ video_disable = 0; @@ -3161,21 +3188,25 @@ static void new_audio_stream(AVFormatContext *oc) if (oc->oformat->flags & AVFMT_GLOBALHEADER) { audio_enc->flags |= CODEC_FLAG_GLOBAL_HEADER; - avctx_opts[CODEC_TYPE_AUDIO]->flags|= CODEC_FLAG_GLOBAL_HEADER; + avcodec_opts[CODEC_TYPE_AUDIO]->flags|= CODEC_FLAG_GLOBAL_HEADER; } if (audio_stream_copy) { st->stream_copy = 1; audio_enc->channels = audio_channels; } else { AVCodec *codec; - codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, CODEC_TYPE_AUDIO); - set_context_opts(audio_enc, avctx_opts[CODEC_TYPE_AUDIO], AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM); + set_context_opts(audio_enc, avcodec_opts[CODEC_TYPE_AUDIO], AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM); - if (audio_codec_name) + if (audio_codec_name) { codec_id = find_codec_or_die(audio_codec_name, CODEC_TYPE_AUDIO, 1); + codec = avcodec_find_encoder_by_name(audio_codec_name); + output_codecs[nb_ocodecs] = codec; + } else { + codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, CODEC_TYPE_AUDIO); + codec = avcodec_find_encoder(codec_id); + } audio_enc->codec_id = codec_id; - codec = avcodec_find_encoder(codec_id); if (audio_qscale > QSCALE_NONE) { audio_enc->flags |= CODEC_FLAG_QSCALE; @@ -3184,6 +3215,9 @@ static void new_audio_stream(AVFormatContext *oc) audio_enc->thread_count = thread_count; audio_enc->channels = audio_channels; audio_enc->sample_fmt = audio_sample_fmt; + audio_enc->channel_layout = channel_layout; + if (avcodec_channel_layout_num_channels(channel_layout) != audio_channels) + audio_enc->channel_layout = 0; if(codec && codec->sample_fmts){ const enum SampleFormat *p= codec->sample_fmts; @@ -3195,10 +3229,11 @@ static void new_audio_stream(AVFormatContext *oc) audio_enc->sample_fmt = codec->sample_fmts[0]; } } + nb_ocodecs++; audio_enc->sample_rate = audio_sample_rate; audio_enc->time_base= (AVRational){1, audio_sample_rate}; if (audio_language) { - av_strlcpy(st->language, audio_language, sizeof(st->language)); + av_metadata_set(&st->metadata, "language", audio_language); av_free(audio_language); audio_language = NULL; } @@ -3226,15 +3261,21 @@ static void new_subtitle_stream(AVFormatContext *oc) subtitle_enc = st->codec; subtitle_enc->codec_type = CODEC_TYPE_SUBTITLE; + + if(subtitle_codec_tag) + subtitle_enc->codec_tag= subtitle_codec_tag; + if (subtitle_stream_copy) { st->stream_copy = 1; } else { - set_context_opts(avctx_opts[CODEC_TYPE_SUBTITLE], subtitle_enc, AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_ENCODING_PARAM); + set_context_opts(avcodec_opts[CODEC_TYPE_SUBTITLE], subtitle_enc, AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_ENCODING_PARAM); subtitle_enc->codec_id = find_codec_or_die(subtitle_codec_name, CODEC_TYPE_SUBTITLE, 1); + output_codecs[nb_ocodecs] = avcodec_find_encoder_by_name(subtitle_codec_name); } + nb_ocodecs++; if (subtitle_language) { - av_strlcpy(st->language, subtitle_language, sizeof(st->language)); + av_metadata_set(&st->metadata, "language", subtitle_language); av_free(subtitle_language); subtitle_language = NULL; } @@ -3287,7 +3328,7 @@ static void opt_output_file(const char *filename) if (!strcmp(filename, "-")) filename = "pipe:"; - oc = av_alloc_format_context(); + oc = avformat_alloc_context(); if (!file_oformat) { file_oformat = guess_format(NULL, filename, NULL); @@ -3353,18 +3394,11 @@ static void opt_output_file(const char *filename) oc->timestamp = rec_timestamp; - if (str_title) - av_strlcpy(oc->title, str_title, sizeof(oc->title)); - if (str_author) - av_strlcpy(oc->author, str_author, sizeof(oc->author)); - if (str_copyright) - av_strlcpy(oc->copyright, str_copyright, sizeof(oc->copyright)); - if (str_comment) - av_strlcpy(oc->comment, str_comment, sizeof(oc->comment)); - if (str_album) - av_strlcpy(oc->album, str_album, sizeof(oc->album)); - if (str_genre) - av_strlcpy(oc->genre, str_genre, sizeof(oc->genre)); + for(; metadata_count>0; metadata_count--){ + av_metadata_set(&oc->metadata, metadata[metadata_count-1].key, + metadata[metadata_count-1].value); + } + av_metadata_conv(oc, oc->oformat->metadata_conv, NULL); } output_files[nb_output_files++] = oc; @@ -3384,13 +3418,10 @@ static void opt_output_file(const char *filename) filename[1] == ':' || av_strstart(filename, "file:", NULL))) { if (url_exist(filename)) { - int c; - if (!using_stdin) { fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename); fflush(stderr); - c = getchar(); - if (toupper(c) != 'Y') { + if (!read_yesno()) { fprintf(stderr, "Not overwriting - exiting\n"); av_exit(1); } @@ -3419,6 +3450,7 @@ static void opt_output_file(const char *filename) oc->preload= (int)(mux_preload*AV_TIME_BASE); oc->max_delay= (int)(mux_max_delay*AV_TIME_BASE); oc->loop_output = loop_output; + oc->flags |= AVFMT_FLAG_NONBLOCK; set_context_opts(oc, avformat_opts, AV_OPT_FLAG_ENCODING_PARAM); @@ -3441,12 +3473,12 @@ static void opt_pass(const char *pass_str) static int64_t getutime(void) { -#ifdef HAVE_GETRUSAGE +#if HAVE_GETRUSAGE struct rusage rusage; getrusage(RUSAGE_SELF, &rusage); return (rusage.ru_utime.tv_sec * 1000000LL) + rusage.ru_utime.tv_usec; -#elif defined(HAVE_GETPROCESSTIMES) +#elif HAVE_GETPROCESSTIMES HANDLE proc; FILETIME c, e, k, u; proc = GetCurrentProcess(); @@ -3525,7 +3557,7 @@ static void show_help(void) OPT_GRAB, OPT_GRAB); printf("\n"); - av_opt_show(avctx_opts[0], NULL); + av_opt_show(avcodec_opts[0], NULL); printf("\n"); av_opt_show(avformat_opts, NULL); printf("\n"); @@ -3718,27 +3750,31 @@ static int opt_bsf(const char *opt, const char *arg) static int opt_preset(const char *opt, const char *arg) { FILE *f=NULL; - char tmp[1000], tmp2[1000], line[1000]; + char filename[1000], tmp[1000], tmp2[1000], line[1000]; int i; - const char *base[3]= { getenv("HOME"), - "/usr/local/share", - "/usr/share", + const char *base[2]= { getenv("HOME"), + FFMPEG_DATADIR, }; - for(i=!base[0]; i<3 && !f; i++){ - snprintf(tmp, sizeof(tmp), "%s/%sffmpeg/%s.ffpreset", base[i], i ? "" : ".", arg); - f= fopen(tmp, "r"); + for(i=!base[0]; i<2 && !f; i++){ + snprintf(filename, sizeof(filename), "%s%s/%s.ffpreset", base[i], i ? "" : "/.ffmpeg", arg); + f= fopen(filename, "r"); if(!f){ char *codec_name= *opt == 'v' ? video_codec_name : *opt == 'a' ? audio_codec_name : subtitle_codec_name; - snprintf(tmp, sizeof(tmp), "%s/%sffmpeg/%s-%s.ffpreset", base[i], i ? "" : ".", codec_name, arg); - f= fopen(tmp, "r"); + snprintf(filename, sizeof(filename), "%s%s/%s-%s.ffpreset", base[i], i ? "" : "/.ffmpeg", codec_name, arg); + f= fopen(filename, "r"); } } + if(!f && ((arg[0]=='.' && arg[1]=='/') || arg[0]=='/' || + is_dos_path(arg))){ + av_strlcpy(filename, arg, sizeof(filename)); + f= fopen(filename, "r"); + } if(!f){ - fprintf(stderr, "Preset file not found\n"); + fprintf(stderr, "File for preset '%s' not found\n", arg); av_exit(1); } @@ -3748,7 +3784,7 @@ static int opt_preset(const char *opt, const char *arg) continue; e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2; if(e){ - fprintf(stderr, "Preset file invalid\n"); + fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line); av_exit(1); } if(!strcmp(tmp, "acodec")){ @@ -3757,8 +3793,10 @@ static int opt_preset(const char *opt, const char *arg) opt_video_codec(tmp2); }else if(!strcmp(tmp, "scodec")){ opt_subtitle_codec(tmp2); - }else - opt_default(tmp, tmp2); + }else if(opt_default(tmp, tmp2) < 0){ + fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2); + av_exit(1); + } } fclose(f); @@ -3782,13 +3820,8 @@ static const OptionDef options[] = { { "ss", OPT_FUNC2 | HAS_ARG, {(void*)opt_start_time}, "set the start time offset", "time_off" }, { "itsoffset", OPT_FUNC2 | HAS_ARG, {(void*)opt_input_ts_offset}, "set the input ts offset", "time_off" }, { "itsscale", HAS_ARG, {(void*)opt_input_ts_scale}, "set the input ts scale", "stream:scale" }, - { "title", HAS_ARG | OPT_STRING, {(void*)&str_title}, "set the title", "string" }, - { "timestamp", OPT_FUNC2 | HAS_ARG, {(void*)&opt_rec_timestamp}, "set the timestamp", "time" }, - { "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" }, - { "genre", HAS_ARG | OPT_STRING, {(void*)&str_genre}, "set the genre", "string" }, - { "album", HAS_ARG | OPT_STRING, {(void*)&str_album}, "set the album", "string" }, + { "timestamp", OPT_FUNC2 | HAS_ARG, {(void*)opt_rec_timestamp}, "set the timestamp ('now' to set the current time)", "time" }, + { "metadata", OPT_FUNC2 | HAS_ARG, {(void*)opt_metadata}, "add metadata", "string=string" }, { "dframes", OPT_INT | HAS_ARG, {(void*)&max_frames[CODEC_TYPE_DATA]}, "set the number of data frames to record", "number" }, { "benchmark", OPT_BOOL | OPT_EXPERT, {(void*)&do_benchmark}, "add timings for benchmarking" }, @@ -3799,7 +3832,8 @@ static const OptionDef options[] = { { "re", OPT_BOOL | OPT_EXPERT, {(void*)&rate_emu}, "read input at native frame rate", "" }, { "loop_input", OPT_BOOL | OPT_EXPERT, {(void*)&loop_input}, "loop (current only works with images)" }, { "loop_output", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&loop_output}, "number of times to loop output in formats that support looping (0 loops forever)", "" }, - { "v", HAS_ARG | OPT_FUNC2, {(void*)opt_verbose}, "set the logging verbosity level", "number" }, + { "v", HAS_ARG | OPT_FUNC2, {(void*)opt_verbose}, "set ffmpeg verbosity level", "number" }, + { "loglevel", HAS_ARG | OPT_FUNC2, {(void*)opt_loglevel}, "set libav* logging level", "number" }, { "target", HAS_ARG, {(void*)opt_target}, "specify target file type (\"vcd\", \"svcd\", \"dvd\", \"dv\", \"dv50\", \"pal-vcd\", \"ntsc-svcd\", ...)", "type" }, { "threads", OPT_FUNC2 | HAS_ARG | OPT_EXPERT, {(void*)opt_thread_count}, "thread count", "count" }, { "vsync", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&video_sync_method}, "video sync method", "" }, @@ -3811,6 +3845,7 @@ static const OptionDef options[] = { { "dts_delta_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, {(void*)&dts_delta_threshold}, "timestamp discontinuity delta threshold", "threshold" }, { "programid", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&opt_programid}, "desired program number", "" }, { "xerror", OPT_BOOL, {(void*)&exit_on_error}, "exit on error", "error" }, + { "copyinkf", OPT_BOOL | OPT_EXPERT, {(void*)©_initial_nonkeyframes}, "copy initial non-keyframes" }, /* video options */ { "b", OPT_FUNC2 | HAS_ARG | OPT_VIDEO, {(void*)opt_bitrate}, "set bitrate (in bits/s)", "bitrate" }, @@ -3839,15 +3874,12 @@ static const OptionDef options[] = { { "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" }, + { "passlogfile", HAS_ARG | OPT_STRING | OPT_VIDEO, {(void*)&pass_logfilename_prefix}, "select two pass log file name prefix", "prefix" }, { "deinterlace", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&do_deinterlace}, "deinterlace pictures" }, { "psnr", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&do_psnr}, "calculate PSNR of compressed frames" }, { "vstats", OPT_EXPERT | OPT_VIDEO, {(void*)&opt_vstats}, "dump video coding statistics to file" }, { "vstats_file", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_vstats_file}, "dump video coding statistics to file", "file" }, -#ifdef CONFIG_VHOOK - { "vhook", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)add_frame_hooker}, "insert video processing module", "module" }, -#endif { "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" }, { "top", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_top_field_first}, "top=1/bottom=0/auto=-1 field first", "" }, @@ -3855,6 +3887,7 @@ static const OptionDef options[] = { { "vtag", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_video_tag}, "force video tag/fourcc", "fourcc/tag" }, { "newvideo", OPT_VIDEO, {(void*)opt_new_video_stream}, "add a new video stream to the current output stream" }, { "qphist", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, { (void *)&qp_hist }, "show QP histogram" }, + { "force_fps", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&force_fps}, "force the selected framerate, disable the best supported framerate selection" }, /* audio options */ { "ab", OPT_FUNC2 | HAS_ARG | OPT_AUDIO, {(void*)opt_bitrate}, "set bitrate (in bits/s)", "bitrate" }, @@ -3875,6 +3908,7 @@ static const OptionDef options[] = { { "scodec", HAS_ARG | OPT_SUBTITLE, {(void*)opt_subtitle_codec}, "force subtitle codec ('copy' to copy stream)", "codec" }, { "newsubtitle", OPT_SUBTITLE, {(void*)opt_new_subtitle_stream}, "add a new subtitle stream to the current output stream" }, { "slang", HAS_ARG | OPT_STRING | OPT_SUBTITLE, {(void *)&subtitle_language}, "set the ISO 639 language code (3 letters) of the current subtitle stream" , "code" }, + { "stag", HAS_ARG | OPT_EXPERT | OPT_SUBTITLE, {(void*)opt_subtitle_tag}, "force subtitle tag/fourcc", "fourcc/tag" }, /* grab options */ { "vc", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_GRAB, {(void*)opt_video_channel}, "set video grab channel (DV1394 only)", "channel" }, @@ -3889,9 +3923,9 @@ static const OptionDef options[] = { { "vbsf", OPT_FUNC2 | HAS_ARG | OPT_VIDEO | OPT_EXPERT, {(void*)opt_bsf}, "", "bitstream_filter" }, { "sbsf", OPT_FUNC2 | HAS_ARG | OPT_SUBTITLE | OPT_EXPERT, {(void*)opt_bsf}, "", "bitstream_filter" }, - { "apre", OPT_FUNC2 | HAS_ARG | OPT_AUDIO | OPT_EXPERT, {(void*)opt_preset}, "", "preset" }, - { "vpre", OPT_FUNC2 | HAS_ARG | OPT_VIDEO | OPT_EXPERT, {(void*)opt_preset}, "", "preset" }, - { "spre", OPT_FUNC2 | HAS_ARG | OPT_SUBTITLE | OPT_EXPERT, {(void*)opt_preset}, "", "preset" }, + { "apre", OPT_FUNC2 | HAS_ARG | OPT_AUDIO | OPT_EXPERT, {(void*)opt_preset}, "set the audio options to the indicated preset", "preset" }, + { "vpre", OPT_FUNC2 | HAS_ARG | OPT_VIDEO | OPT_EXPERT, {(void*)opt_preset}, "set the video options to the indicated preset", "preset" }, + { "spre", OPT_FUNC2 | HAS_ARG | OPT_SUBTITLE | OPT_EXPERT, {(void*)opt_preset}, "set the subtitle options to the indicated preset", "preset" }, { "default", OPT_FUNC2 | HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {(void*)opt_default}, "generic catch all option", "" }, { NULL, }, @@ -3910,34 +3944,31 @@ int main(int argc, char **argv) url_set_interrupt_cb(decode_interrupt_cb); for(i=0; i