X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ffmpeg.c;h=886d5da7de27a332e647cec2f53095cbe4918fd2;hb=84465f2180308a3e998089517e76586563fd6162;hp=779986857dab5e371e3baab595bbe76b810043f4;hpb=63e856df0ac750dd4fefb6fc72ca4826ebdb5a0f;p=ffmpeg diff --git a/ffmpeg.c b/ffmpeg.c index 779986857da..886d5da7de2 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -2,20 +2,20 @@ * FFmpeg main * Copyright (c) 2000-2003 Fabrice Bellard * - * This file is part of FFmpeg. + * This file is part of Libav. * - * FFmpeg is free software; you can redistribute it and/or + * Libav is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * FFmpeg is distributed in the hope that it will be useful, + * Libav is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software + * License along with Libav; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -34,11 +34,14 @@ #include "libavformat/avformat.h" #include "libavdevice/avdevice.h" #include "libswscale/swscale.h" -#include "libavcodec/opt.h" +#include "libavutil/opt.h" #include "libavcodec/audioconvert.h" -#include "libavcore/parseutils.h" +#include "libavutil/audioconvert.h" +#include "libavutil/parseutils.h" +#include "libavutil/samplefmt.h" #include "libavutil/colorspace.h" #include "libavutil/fifo.h" +#include "libavutil/intreadwrite.h" #include "libavutil/pixdesc.h" #include "libavutil/avstring.h" #include "libavutil/libm.h" @@ -47,7 +50,6 @@ #if CONFIG_AVFILTER # include "libavfilter/avfilter.h" # include "libavfilter/avfiltergraph.h" -# include "libavfilter/graphparser.h" # include "libavfilter/vsrc_buffer.h" #endif @@ -67,12 +69,7 @@ #include #endif -#if HAVE_TERMIOS_H -#include -#include -#include -#include -#elif HAVE_CONIO_H +#if HAVE_KBHIT #include #endif #include @@ -96,16 +93,22 @@ typedef struct AVStreamMap { * select an input file for an output file */ typedef struct AVMetaDataMap { - int out_file; - int in_file; + int file; //< file index + char type; //< type of metadata to copy -- (g)lobal, (s)tream, (c)hapter or (p)rogram + int index; //< stream/chapter/program number } AVMetaDataMap; +typedef struct AVChapterMap { + int in_file; + int out_file; +} AVChapterMap; + static const OptionDef options[]; #define MAX_FILES 100 -#if !FF_API_MAX_STREAMS #define MAX_STREAMS 1024 /* arbitrary sanity check value */ -#endif + +#define FFM_PACKET_SIZE 4096 //XXX a duplicate of the line in ffm.h static const char *last_asked_format = NULL; static AVFormatContext *input_files[MAX_FILES]; @@ -124,8 +127,15 @@ static int nb_output_codecs = 0; static AVStreamMap *stream_maps = NULL; static int nb_stream_maps; -static AVMetaDataMap *meta_data_maps = NULL; +/* first item specifies output metadata, second is input */ +static AVMetaDataMap (*meta_data_maps)[2] = NULL; static int nb_meta_data_maps; +static int metadata_global_autocopy = 1; +static int metadata_streams_autocopy = 1; +static int metadata_chapters_autocopy = 1; + +static AVChapterMap *chapter_maps = NULL; +static int nb_chapter_maps; /* indexed by output file stream index */ static int *streamid_map = NULL; @@ -135,7 +145,7 @@ static int frame_width = 0; static int frame_height = 0; static float frame_aspect_ratio = 0; static enum PixelFormat frame_pix_fmt = PIX_FMT_NONE; -static enum SampleFormat audio_sample_fmt = SAMPLE_FMT_NONE; +static enum AVSampleFormat audio_sample_fmt = AV_SAMPLE_FMT_NONE; static int max_frames[4] = {INT_MAX, INT_MAX, INT_MAX, INT_MAX}; static AVRational frame_rate; static float video_qscale = 0; @@ -157,7 +167,7 @@ static int loop_output = AVFMT_NOOUTPUTLOOP; static int qp_hist = 0; #if CONFIG_AVFILTER static char *vfilters = NULL; -AVFilterGraph *graph = NULL; +static AVFilterGraph *graph = NULL; #endif static int intra_only = 0; @@ -198,6 +208,7 @@ 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 copy_tb; static int opt_shortest = 0; static int video_global_header = 0; static char *vstats_filename; @@ -227,7 +238,6 @@ static uint64_t limit_filesize = 0; static int force_fps = 0; static char *forced_key_frames = NULL; -static int pgmyuv_compatibility_hack=0; static float dts_delta_threshold = 10; static unsigned int sws_flags = SWS_BICUBIC; @@ -236,7 +246,7 @@ static int64_t timer_start; static uint8_t *audio_buf; static uint8_t *audio_out; -unsigned int allocated_audio_out_size, allocated_audio_buf_size; +static unsigned int allocated_audio_out_size, allocated_audio_buf_size; static short *samples; @@ -281,6 +291,9 @@ typedef struct AVOutputStream { /* audio only */ int audio_resample; ReSampleContext *resample; /* for audio resampling */ + int resample_sample_fmt; + int resample_channels; + int resample_sample_rate; int reformat_pair; AVAudioConvert *reformat_ctx; AVFifoBuffer *fifo; /* for compression: one audio fifo per codec */ @@ -322,12 +335,6 @@ typedef struct AVInputFile { int nb_streams; /* nb streams we are aware of */ } AVInputFile; -#if HAVE_TERMIOS_H - -/* init terminal so that we can grab keys */ -static struct termios oldtty; -#endif - #if CONFIG_AVFILTER static int configure_filters(AVInputStream *ist, AVOutputStream *ost) @@ -340,25 +347,18 @@ static int configure_filters(AVInputStream *ist, AVOutputStream *ost) char args[255]; int ret; - graph = av_mallocz(sizeof(AVFilterGraph)); - - if ((ret = avfilter_open(&ist->input_video_filter, avfilter_get_by_name("buffer"), "src")) < 0) - return ret; - if ((ret = avfilter_open(&ist->output_video_filter, &ffsink, "out")) < 0) - return ret; + graph = avfilter_graph_alloc(); snprintf(args, 255, "%d:%d:%d:%d:%d", ist->st->codec->width, - ist->st->codec->height, ist->st->codec->pix_fmt, - ist->st->time_base.num, ist->st->time_base.den); - if ((ret = avfilter_init_filter(ist->input_video_filter, args, NULL)) < 0) + ist->st->codec->height, ist->st->codec->pix_fmt, 1, AV_TIME_BASE); + ret = avfilter_graph_create_filter(&ist->input_video_filter, avfilter_get_by_name("buffer"), + "src", args, NULL, graph); + if (ret < 0) return ret; - if ((ret = avfilter_init_filter(ist->output_video_filter, NULL, &ffsink_ctx)) < 0) + ret = avfilter_graph_create_filter(&ist->output_video_filter, &ffsink, + "out", NULL, &ffsink_ctx, graph); + if (ret < 0) return ret; - - /* add input and output filters to the overall graph */ - avfilter_graph_add_filter(graph, ist->input_video_filter); - avfilter_graph_add_filter(graph, ist->output_video_filter); - last_filter = ist->input_video_filter; if (codec->width != icodec->width || codec->height != icodec->height) { @@ -366,14 +366,12 @@ static int configure_filters(AVInputStream *ist, AVOutputStream *ost) codec->width, codec->height, (int)av_get_int(sws_opts, "sws_flags", NULL)); - if ((ret = avfilter_open(&filter, avfilter_get_by_name("scale"), NULL)) < 0) - return ret; - if ((ret = avfilter_init_filter(filter, args, NULL)) < 0) + if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"), + NULL, args, NULL, graph)) < 0) return ret; if ((ret = avfilter_link(last_filter, 0, filter, 0)) < 0) return ret; last_filter = filter; - avfilter_graph_add_filter(graph, last_filter); } snprintf(args, sizeof(args), "flags=0x%X", (int)av_get_int(sws_opts, "sws_flags", NULL)); @@ -384,12 +382,12 @@ static int configure_filters(AVInputStream *ist, AVOutputStream *ost) AVFilterInOut *inputs = av_malloc(sizeof(AVFilterInOut)); outputs->name = av_strdup("in"); - outputs->filter = last_filter; + outputs->filter_ctx = last_filter; outputs->pad_idx = 0; outputs->next = NULL; inputs->name = av_strdup("out"); - inputs->filter = ist->output_video_filter; + inputs->filter_ctx = ist->output_video_filter; inputs->pad_idx = 0; inputs->next = NULL; @@ -414,9 +412,6 @@ static int configure_filters(AVInputStream *ist, AVOutputStream *ost) static void term_exit(void) { av_log(NULL, AV_LOG_QUIET, ""); -#if HAVE_TERMIOS_H - tcsetattr (0, TCSANOW, &oldtty); -#endif } static volatile int received_sigterm = 0; @@ -430,26 +425,6 @@ sigterm_handler(int sig) static void term_init(void) { -#if HAVE_TERMIOS_H - struct termios tty; - - tcgetattr (0, &tty); - oldtty = tty; - atexit(term_exit); - - tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP - |INLCR|IGNCR|ICRNL|IXON); - tty.c_oflag |= OPOST; - tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); - tty.c_cflag &= ~(CSIZE|PARENB); - tty.c_cflag |= CS8; - tty.c_cc[VMIN] = 1; - tty.c_cc[VTIME] = 0; - - tcsetattr (0, TCSANOW, &tty); - signal(SIGQUIT, sigterm_handler); /* Quit (POSIX). */ -#endif - signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */ signal(SIGTERM, sigterm_handler); /* Termination (ANSI). */ #ifdef SIGXCPU @@ -460,25 +435,7 @@ static void term_init(void) /* read a key without blocking */ static int read_key(void) { -#if HAVE_TERMIOS_H - int n = 1; - unsigned char ch; - struct timeval tv; - fd_set rfds; - - FD_ZERO(&rfds); - FD_SET(0, &rfds); - tv.tv_sec = 0; - tv.tv_usec = 0; - n = select(1, &rfds, NULL, NULL, &tv); - if (n > 0) { - n = read(0, &ch, 1); - if (n == 1) - return ch; - - return n; - } -#elif HAVE_CONIO_H +#if HAVE_KBHIT if(kbhit()) return(getch()); #endif @@ -496,25 +453,10 @@ static int ffmpeg_exit(int ret) /* close files */ for(i=0;ioformat->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]->info); - 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); + avio_close(s->pb); + avformat_free_context(s); av_free(output_streams_for_file[i]); } for(i=0;isample_fmts){ - const enum SampleFormat *p= codec->sample_fmts; + const enum AVSampleFormat *p= codec->sample_fmts; for(; *p!=-1; p++){ if(*p == st->codec->sample_fmt) break; } - if(*p == -1) + if (*p == -1) { + av_log(NULL, AV_LOG_WARNING, + "Incompatible sample format '%s' for codec '%s', auto-selecting format '%s'\n", + av_get_sample_fmt_name(st->codec->sample_fmt), + codec->name, + av_get_sample_fmt_name(codec->sample_fmts[0])); st->codec->sample_fmt = codec->sample_fmts[0]; + } } } @@ -620,19 +567,43 @@ static void choose_pixel_fmt(AVStream *st, AVCodec *codec) { if(codec && codec->pix_fmts){ const enum PixelFormat *p= codec->pix_fmts; + if(st->codec->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL){ + if(st->codec->codec_id==CODEC_ID_MJPEG){ + p= (const enum PixelFormat[]){PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P, PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_NONE}; + }else if(st->codec->codec_id==CODEC_ID_LJPEG){ + p= (const enum PixelFormat[]){PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ444P, PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_YUV444P, PIX_FMT_BGRA, PIX_FMT_NONE}; + } + } for(; *p!=-1; p++){ if(*p == st->codec->pix_fmt) break; } - if(*p == -1 - && !( st->codec->codec_id==CODEC_ID_MJPEG - && st->codec->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL - && ( st->codec->pix_fmt == PIX_FMT_YUV420P - || st->codec->pix_fmt == PIX_FMT_YUV422P))) + if(*p == -1) st->codec->pix_fmt = codec->pix_fmts[0]; } } +static AVOutputStream *new_output_stream(AVFormatContext *oc, int file_idx) +{ + int idx = oc->nb_streams - 1; + AVOutputStream *ost; + + output_streams_for_file[file_idx] = + grow_array(output_streams_for_file[file_idx], + sizeof(*output_streams_for_file[file_idx]), + &nb_output_streams_for_file[file_idx], + oc->nb_streams); + ost = output_streams_for_file[file_idx][idx] = + av_mallocz(sizeof(AVOutputStream)); + if (!ost) { + fprintf(stderr, "Could not alloc output stream\n"); + ffmpeg_exit(1); + } + ost->file_index = file_idx; + ost->index = idx; + return ost; +} + static int read_ffserver_streams(AVFormatContext *s, const char *filename) { int i, err; @@ -643,11 +614,13 @@ static int read_ffserver_streams(AVFormatContext *s, const char *filename) if (err < 0) return err; /* copy stream format */ - s->nb_streams = ic->nb_streams; + s->nb_streams = 0; for(i=0;inb_streams;i++) { AVStream *st; AVCodec *codec; + s->nb_streams++; + // FIXME: a more elegant solution is needed st = av_mallocz(sizeof(AVStream)); memcpy(st, ic->streams[i], sizeof(AVStream)); @@ -672,13 +645,10 @@ static int read_ffserver_streams(AVFormatContext *s, const char *filename) choose_pixel_fmt(st, codec); } - if(!st->codec->thread_count) - st->codec->thread_count = 1; - if(st->codec->thread_count>1) - avcodec_thread_init(st->codec, st->codec->thread_count); - if(st->codec->flags & CODEC_FLAG_BITEXACT) nopts = 1; + + new_output_stream(s, nb_output_files); } if (!nopts) @@ -738,11 +708,11 @@ static void do_audio_out(AVFormatContext *s, int64_t audio_out_size, audio_buf_size; int64_t allocated_for_size= size; - int size_out, frame_bytes, ret; + int size_out, frame_bytes, ret, resample_changed; AVCodecContext *enc= ost->st->codec; AVCodecContext *dec= ist->st->codec; - int osize= av_get_bits_per_sample_format(enc->sample_fmt)/8; - int isize= av_get_bits_per_sample_format(dec->sample_fmt)/8; + int osize= av_get_bits_per_sample_fmt(enc->sample_fmt)/8; + int isize= av_get_bits_per_sample_fmt(dec->sample_fmt)/8; const int coded_bps = av_get_bits_per_sample(enc->codec->id); need_realloc: @@ -772,22 +742,46 @@ need_realloc: if (enc->channels != dec->channels) ost->audio_resample = 1; - if (ost->audio_resample && !ost->resample) { - 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, - enc->channels, enc->sample_rate); - ffmpeg_exit(1); + resample_changed = ost->resample_sample_fmt != dec->sample_fmt || + ost->resample_channels != dec->channels || + ost->resample_sample_rate != dec->sample_rate; + + if ((ost->audio_resample && !ost->resample) || resample_changed) { + if (resample_changed) { + av_log(NULL, AV_LOG_INFO, "Input stream #%d.%d frame changed from rate:%d fmt:%s ch:%d to rate:%d fmt:%s ch:%d\n", + ist->file_index, ist->index, + ost->resample_sample_rate, av_get_sample_fmt_name(ost->resample_sample_fmt), ost->resample_channels, + dec->sample_rate, av_get_sample_fmt_name(dec->sample_fmt), dec->channels); + ost->resample_sample_fmt = dec->sample_fmt; + ost->resample_channels = dec->channels; + ost->resample_sample_rate = dec->sample_rate; + if (ost->resample) + audio_resample_close(ost->resample); + } + /* if audio_sync_method is >1 the resampler is needed for audio drift compensation */ + if (audio_sync_method <= 1 && + ost->resample_sample_fmt == enc->sample_fmt && + ost->resample_channels == enc->channels && + ost->resample_sample_rate == enc->sample_rate) { + ost->resample = NULL; + ost->audio_resample = 0; + } else { + if (dec->sample_fmt != AV_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, + enc->channels, enc->sample_rate); + ffmpeg_exit(1); + } } } -#define MAKE_SFMT_PAIR(a,b) ((a)+SAMPLE_FMT_NB*(b)) +#define MAKE_SFMT_PAIR(a,b) ((a)+AV_SAMPLE_FMT_NB*(b)) if (!ost->audio_resample && dec->sample_fmt!=enc->sample_fmt && MAKE_SFMT_PAIR(enc->sample_fmt,dec->sample_fmt)!=ost->reformat_pair) { if (ost->reformat_ctx) @@ -796,8 +790,8 @@ need_realloc: dec->sample_fmt, 1, NULL, 0); if (!ost->reformat_ctx) { fprintf(stderr, "Cannot convert %s sample format to %s sample format\n", - avcodec_get_sample_fmt_name(dec->sample_fmt), - avcodec_get_sample_fmt_name(enc->sample_fmt)); + av_get_sample_fmt_name(dec->sample_fmt), + av_get_sample_fmt_name(enc->sample_fmt)); ffmpeg_exit(1); } ost->reformat_pair=MAKE_SFMT_PAIR(enc->sample_fmt,dec->sample_fmt); @@ -1087,7 +1081,7 @@ static void do_video_out(AVFormatContext *s, if(vdelta<=-0.6){ nb_frames=0; }else if(vdelta>0.6) - ost->sync_opts= lrintf(sync_ipts); + ost->sync_opts= lrintf(sync_ipts); }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, get_sync_ipts(ost), nb_frames); @@ -1303,9 +1297,9 @@ static void print_report(AVFormatContext **output_files, oc = output_files[0]; - total_size = url_fsize(oc->pb); - if(total_size<0) // FIXME improve url_fsize() so it works with non seekable output too - total_size= url_ftell(oc->pb); + total_size = avio_size(oc->pb); + if(total_size<0) // FIXME improve avio_size() so it works with non seekable output too + total_size= avio_tell(oc->pb); buf[0] = '\0'; ti1 = 1e10; @@ -1396,6 +1390,14 @@ static void print_report(AVFormatContext **output_files, } } +static void generate_silence(uint8_t* buf, enum AVSampleFormat sample_fmt, size_t size) +{ + int fill_char = 0x00; + if (sample_fmt == AV_SAMPLE_FMT_U8) + fill_char = 0x80; + memset(buf, fill_char, size); +} + /* pkt = NULL means EOF (needed to flush decoder buffers) */ static int output_packet(AVInputStream *ist, int ist_index, AVOutputStream **ost_table, int nb_ostreams, @@ -1415,7 +1417,7 @@ static int output_packet(AVInputStream *ist, int ist_index, #endif AVPacket avpkt; - int bps = av_get_bits_per_sample_format(ist->st->codec->sample_fmt)>>3; + int bps = av_get_bits_per_sample_fmt(ist->st->codec->sample_fmt)>>3; if(ist->next_pts == AV_NOPTS_VALUE) ist->next_pts= ist->pts; @@ -1486,7 +1488,8 @@ static int output_packet(AVInputStream *ist, int ist_index, decoded_data_size = (ist->st->codec->width * ist->st->codec->height * 3) / 2; /* XXX: allocate picture correctly */ avcodec_get_frame_defaults(&picture); - ist->st->codec->reordered_opaque = pkt_pts; + avpkt.pts = pkt_pts; + avpkt.dts = ist->pts; pkt_pts = AV_NOPTS_VALUE; ret = avcodec_decode_video2(ist->st->codec, @@ -1498,7 +1501,7 @@ static int output_packet(AVInputStream *ist, int ist_index, /* no picture yet */ goto discard_packet; } - ist->next_pts = ist->pts = guess_correct_pts(&ist->pts_ctx, picture.reordered_opaque, ist->pts); + ist->next_pts = ist->pts = guess_correct_pts(&ist->pts_ctx, picture.pkt_pts, picture.pkt_dts); 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 * @@ -1548,10 +1551,13 @@ static int output_packet(AVInputStream *ist, int ist_index, #if CONFIG_AVFILTER if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO && ist->input_video_filter) { + AVRational sar; + if (ist->st->sample_aspect_ratio.num) sar = ist->st->sample_aspect_ratio; + else sar = ist->st->codec->sample_aspect_ratio; // add it to be filtered av_vsrc_buffer_add_frame(ist->input_video_filter, &picture, ist->pts, - ist->st->codec->sample_aspect_ratio); + sar); } #endif @@ -1589,7 +1595,7 @@ static int output_packet(AVInputStream *ist, int ist_index, if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO && ist->output_video_filter) get_filtered_video_frame(ist->output_video_filter, &picture, &ist->picref, &ist_pts_tb); if (ist->picref) - ist->pts = ist->picref->pts; + ist->pts = av_rescale_q(ist->picref->pts, ist_pts_tb, AV_TIME_BASE_Q); #endif for(i=0;irects != NULL) { - for (i = 0; i < subtitle_to_free->num_rects; i++) { - 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); - } - subtitle_to_free->num_rects = 0; + avsubtitle_free(subtitle_to_free); subtitle_to_free = NULL; } } @@ -1732,7 +1730,7 @@ static int output_packet(AVInputStream *ist, int ist_index, ret = 0; /* encode any samples remaining in fifo */ if (fifo_bytes > 0) { - int osize = av_get_bits_per_sample_format(enc->sample_fmt) >> 3; + int osize = av_get_bits_per_sample_fmt(enc->sample_fmt) >> 3; int fs_tmp = enc->frame_size; av_fifo_generic_read(ost->fifo, audio_buf, fifo_bytes, NULL); @@ -1742,7 +1740,7 @@ static int output_packet(AVInputStream *ist, int ist_index, int frame_bytes = enc->frame_size*osize*enc->channels; if (allocated_audio_buf_size < frame_bytes) ffmpeg_exit(1); - memset(audio_buf+fifo_bytes, 0, frame_bytes - fifo_bytes); + generate_silence(audio_buf+fifo_bytes, enc->sample_fmt, frame_bytes - fifo_bytes); } ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, (short *)audio_buf); @@ -1799,7 +1797,7 @@ static void print_sdp(AVFormatContext **avc, int n) { char sdp[2048]; - avf_sdp_create(avc, n, sdp, sizeof(sdp)); + av_sdp_create(avc, n, sdp, sizeof(sdp)); printf("SDP:\n%s\n", sdp); fflush(stdout); } @@ -1812,7 +1810,6 @@ static int copy_chapters(int infile, int outfile) for (i = 0; i < is->nb_chapters; i++) { AVChapter *in_ch = is->chapters[i], *out_ch; - AVMetadataTag *t = NULL; int64_t ts_off = av_rescale_q(start_time - input_files_ts_offset[infile], AV_TIME_BASE_Q, in_ch->time_base); int64_t rt = (recording_time == INT64_MAX) ? INT64_MAX : @@ -1833,8 +1830,8 @@ static int copy_chapters(int infile, int outfile) out_ch->start = FFMAX(0, in_ch->start - ts_off); out_ch->end = FFMIN(rt, in_ch->end - ts_off); - while ((t = av_metadata_get(in_ch->metadata, "", t, AV_METADATA_IGNORE_SUFFIX))) - av_metadata_set2(&out_ch->metadata, t->key, t->value, 0); + if (metadata_chapters_autocopy) + av_metadata_copy(&out_ch->metadata, in_ch->metadata, 0); os->nb_chapters++; os->chapters = av_realloc(os->chapters, sizeof(AVChapter)*os->nb_chapters); @@ -1934,8 +1931,8 @@ static int transcode(AVFormatContext **output_files, nb_ostreams = 0; for(i=0;inb_streams) { - dump_format(output_files[i], i, output_files[i]->filename, 1); + if (!os->nb_streams && !(os->oformat->flags & AVFMT_NOSTREAMS)) { + av_dump_format(output_files[i], i, output_files[i]->filename, 1); fprintf(stderr, "Output file #%d does not contain any stream\n", i); ret = AVERROR(EINVAL); goto fail; @@ -1986,7 +1983,7 @@ static int transcode(AVFormatContext **output_files, /* Sanity check that the stream types match */ if (ist_table[ost->source_index]->st->codec->codec_type != ost->st->codec->codec_type) { int i= ost->file_index; - dump_format(output_files[i], i, output_files[i]->filename, 1); + av_dump_format(output_files[i], i, output_files[i]->filename, 1); fprintf(stderr, "Codec type mismatch for mapping #%d.%d -> #%d.%d\n", stream_maps[n].file_index, stream_maps[n].stream_index, ost->file_index, ost->index); @@ -2037,7 +2034,7 @@ static int transcode(AVFormatContext **output_files, } if (!found) { int i= ost->file_index; - dump_format(output_files[i], i, output_files[i]->filename, 1); + av_dump_format(output_files[i], i, output_files[i]->filename, 1); fprintf(stderr, "Could not find input stream matching output stream #%d.%d\n", ost->file_index, ost->index); ffmpeg_exit(1); @@ -2054,7 +2051,6 @@ static int transcode(AVFormatContext **output_files, /* for each output stream, we compute the right encoding parameters */ for(i=0;ifile_index]; ist = ist_table[ost->source_index]; @@ -2062,9 +2058,9 @@ static int transcode(AVFormatContext **output_files, codec = ost->st->codec; icodec = ist->st->codec; - while ((t = av_metadata_get(ist->st->metadata, "", t, AV_METADATA_IGNORE_SUFFIX))) { - av_metadata_set2(&ost->st->metadata, t->key, t->value, AV_METADATA_DONT_OVERWRITE); - } + if (metadata_streams_autocopy) + av_metadata_copy(&ost->st->metadata, ist->st->metadata, + AV_METADATA_DONT_OVERWRITE); ost->st->disposition = ist->st->disposition; codec->bits_per_raw_sample= icodec->bits_per_raw_sample; @@ -2095,7 +2091,7 @@ static int transcode(AVFormatContext **output_files, goto fail; memcpy(codec->extradata, icodec->extradata, icodec->extradata_size); codec->extradata_size= icodec->extradata_size; - 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){ + if(!copy_tb && av_q2d(icodec->time_base)*icodec->ticks_per_frame > av_q2d(ist->st->time_base) && av_q2d(ist->st->time_base) < 1.0/500){ codec->time_base = icodec->time_base; codec->time_base.num *= icodec->ticks_per_frame; av_reduce(&codec->time_base.num, &codec->time_base.den, @@ -2112,6 +2108,7 @@ static int transcode(AVFormatContext **output_files, codec->sample_rate = icodec->sample_rate; codec->channels = icodec->channels; codec->frame_size = icodec->frame_size; + codec->audio_service_type = icodec->audio_service_type; codec->block_align= icodec->block_align; if(codec->block_align == 1 && codec->codec_id == CODEC_ID_MP3) codec->block_align= 0; @@ -2137,11 +2134,14 @@ static int transcode(AVFormatContext **output_files, ost->fifo= av_fifo_alloc(1024); if(!ost->fifo) goto fail; - ost->reformat_pair = MAKE_SFMT_PAIR(SAMPLE_FMT_NONE,SAMPLE_FMT_NONE); + ost->reformat_pair = MAKE_SFMT_PAIR(AV_SAMPLE_FMT_NONE,AV_SAMPLE_FMT_NONE); ost->audio_resample = codec->sample_rate != icodec->sample_rate || audio_sync_method > 1; icodec->request_channels = codec->channels; ist->decoding_needed = 1; ost->encoding_needed = 1; + ost->resample_sample_fmt = icodec->sample_fmt; + ost->resample_sample_rate = icodec->sample_rate; + ost->resample_channels = icodec->channels; break; case AVMEDIA_TYPE_VIDEO: if (ost->st->codec->pix_fmt == PIX_FMT_NONE) { @@ -2152,6 +2152,7 @@ static int transcode(AVFormatContext **output_files, codec->height != icodec->height || (codec->pix_fmt != icodec->pix_fmt)); if (ost->video_resample) { +#if !CONFIG_AVFILTER avcodec_get_frame_defaults(&ost->pict_tmp); if(avpicture_alloc((AVPicture*)&ost->pict_tmp, codec->pix_fmt, codec->width, codec->height)) { @@ -2172,7 +2173,6 @@ static int transcode(AVFormatContext **output_files, ffmpeg_exit(1); } -#if !CONFIG_AVFILTER ost->original_height = icodec->height; ost->original_width = icodec->width; #endif @@ -2246,6 +2246,7 @@ static int transcode(AVFormatContext **output_files, ost = ost_table[i]; if (ost->encoding_needed) { AVCodec *codec = i < nb_output_codecs ? output_codecs[i] : NULL; + AVCodecContext *dec = ist_table[ost->source_index]->st->codec; if (!codec) codec = avcodec_find_encoder(ost->st->codec->codec_id); if (!codec) { @@ -2254,6 +2255,15 @@ static int transcode(AVFormatContext **output_files, ret = AVERROR(EINVAL); goto dump_format; } + if (dec->subtitle_header) { + ost->st->codec->subtitle_header = av_malloc(dec->subtitle_header_size); + if (!ost->st->codec->subtitle_header) { + ret = AVERROR(ENOMEM); + goto dump_format; + } + memcpy(ost->st->codec->subtitle_header, dec->subtitle_header, dec->subtitle_header_size); + ost->st->codec->subtitle_header_size = dec->subtitle_header_size; + } if (avcodec_open(ost->st->codec, codec) < 0) { snprintf(error, sizeof(error), "Error while opening encoder for output stream #%d.%d - maybe incorrect parameters such as bit_rate, rate, width or height", ost->file_index, ost->index); @@ -2301,43 +2311,92 @@ static int transcode(AVFormatContext **output_files, /* set meta data information from input file if required */ for (i=0;i= nb_output_files) { - snprintf(error, sizeof(error), "Invalid output file index %d map_meta_data(%d,%d)", - out_file_index, out_file_index, in_file_index); + AVFormatContext *files[2]; + AVMetadata **meta[2]; + int j; + +#define METADATA_CHECK_INDEX(index, nb_elems, desc)\ + if ((index) < 0 || (index) >= (nb_elems)) {\ + snprintf(error, sizeof(error), "Invalid %s index %d while processing metadata maps\n",\ + (desc), (index));\ + ret = AVERROR(EINVAL);\ + goto dump_format;\ + } + + int out_file_index = meta_data_maps[i][0].file; + int in_file_index = meta_data_maps[i][1].file; + if (in_file_index < 0 || out_file_index < 0) + continue; + METADATA_CHECK_INDEX(out_file_index, nb_output_files, "output file") + METADATA_CHECK_INDEX(in_file_index, nb_input_files, "input file") + + files[0] = output_files[out_file_index]; + files[1] = input_files[in_file_index]; + + for (j = 0; j < 2; j++) { + AVMetaDataMap *map = &meta_data_maps[i][j]; + + switch (map->type) { + case 'g': + meta[j] = &files[j]->metadata; + break; + case 's': + METADATA_CHECK_INDEX(map->index, files[j]->nb_streams, "stream") + meta[j] = &files[j]->streams[map->index]->metadata; + break; + case 'c': + METADATA_CHECK_INDEX(map->index, files[j]->nb_chapters, "chapter") + meta[j] = &files[j]->chapters[map->index]->metadata; + break; + case 'p': + METADATA_CHECK_INDEX(map->index, files[j]->nb_programs, "program") + meta[j] = &files[j]->programs[map->index]->metadata; + break; + } + } + + av_metadata_copy(meta[0], *meta[1], AV_METADATA_DONT_OVERWRITE); + } + + /* copy global metadata by default */ + if (metadata_global_autocopy) { + + for (i = 0; i < nb_output_files; i++) + av_metadata_copy(&output_files[i]->metadata, input_files[0]->metadata, + AV_METADATA_DONT_OVERWRITE); + } + + /* copy chapters according to chapter maps */ + for (i = 0; i < nb_chapter_maps; i++) { + int infile = chapter_maps[i].in_file; + int outfile = chapter_maps[i].out_file; + + if (infile < 0 || outfile < 0) + continue; + if (infile >= nb_input_files) { + snprintf(error, sizeof(error), "Invalid input file index %d in chapter mapping.\n", infile); ret = AVERROR(EINVAL); goto dump_format; } - if (in_file_index < 0 || in_file_index >= nb_input_files) { - snprintf(error, sizeof(error), "Invalid input file index %d map_meta_data(%d,%d)", - in_file_index, out_file_index, in_file_index); + if (outfile >= nb_output_files) { + snprintf(error, sizeof(error), "Invalid output file index %d in chapter mapping.\n",outfile); ret = AVERROR(EINVAL); goto dump_format; } - - out_file = output_files[out_file_index]; - in_file = input_files[in_file_index]; - - - mtag=NULL; - while((mtag=av_metadata_get(in_file->metadata, "", mtag, AV_METADATA_IGNORE_SUFFIX))) - av_metadata_set2(&out_file->metadata, mtag->key, mtag->value, AV_METADATA_DONT_OVERWRITE); + copy_chapters(infile, outfile); } /* copy chapters from the first input file that has them*/ - for (i = 0; i < nb_input_files; i++) { - if (!input_files[i]->nb_chapters) - continue; + if (!nb_chapter_maps) + for (i = 0; i < nb_input_files; i++) { + if (!input_files[i]->nb_chapters) + continue; - for (j = 0; j < nb_output_files; j++) - if ((ret = copy_chapters(i, j)) < 0) - goto dump_format; - } + for (j = 0; j < nb_output_files; j++) + if ((ret = copy_chapters(i, j)) < 0) + goto dump_format; + break; + } /* open files and write file headers */ for(i=0;ifilename, 1); + av_dump_format(output_files[i], i, output_files[i]->filename, 1); } /* dump the stream mapping */ @@ -2387,8 +2446,12 @@ static int transcode(AVFormatContext **output_files, } if (!using_stdin && verbose >= 0) { +#if HAVE_KBHIT fprintf(stderr, "Press [q] to stop encoding\n"); - url_set_interrupt_cb(decode_interrupt_cb); +#else + fprintf(stderr, "Press ctrl-c to stop encoding\n"); +#endif + avio_set_interrupt_cb(decode_interrupt_cb); } term_init(); @@ -2452,7 +2515,7 @@ static int transcode(AVFormatContext **output_files, } /* finish if limit size exhausted */ - if (limit_filesize != 0 && limit_filesize <= url_ftell(output_files[0]->pb)) + if (limit_filesize != 0 && limit_filesize <= avio_tell(output_files[0]->pb)) break; /* read a frame from it and output it in the fifo */ @@ -2475,7 +2538,8 @@ static int transcode(AVFormatContext **output_files, memset(no_packet, 0, sizeof(no_packet)); if (do_pkt_dump) { - av_pkt_dump_log(NULL, AV_LOG_DEBUG, &pkt, do_hex_dump); + av_pkt_dump_log2(NULL, AV_LOG_DEBUG, &pkt, do_hex_dump, + is->streams[pkt.stream_index]); } /* the following test is needed in case new streams appear dynamically in stream : we ignore them */ @@ -2576,10 +2640,7 @@ static int transcode(AVFormatContext **output_files, } } #if CONFIG_AVFILTER - if (graph) { - avfilter_graph_destroy(graph); - av_freep(&graph); - } + avfilter_graph_free(&graph); #endif /* finished ! */ @@ -2608,6 +2669,7 @@ static int transcode(AVFormatContext **output_files, } av_fifo_free(ost->fifo); /* works even if fifo is not initialized but set to zero */ + av_freep(&ost->st->codec->subtitle_header); av_free(ost->pict_tmp.data[0]); av_free(ost->forced_kf_pts); if (ost->video_resample) @@ -2626,14 +2688,6 @@ static int transcode(AVFormatContext **output_files, static void opt_format(const char *arg) { - /* compatibility stuff for pgmyuv */ - if (!strcmp(arg, "pgmyuv")) { - pgmyuv_compatibility_hack=1; -// opt_image_format(arg); - arg = "image2"; - fprintf(stderr, "pgmyuv format is deprecated, use image2\n"); - } - last_asked_format = arg; } @@ -2774,10 +2828,14 @@ static int opt_thread_count(const char *opt, const char *arg) static void opt_audio_sample_fmt(const char *arg) { - if (strcmp(arg, "list")) - audio_sample_fmt = avcodec_get_sample_fmt(arg); - else { - list_fmts(avcodec_sample_fmt_string, SAMPLE_FMT_NB); + if (strcmp(arg, "list")) { + audio_sample_fmt = av_get_sample_fmt(arg); + if (audio_sample_fmt == AV_SAMPLE_FMT_NONE) { + av_log(NULL, AV_LOG_ERROR, "Invalid sample format '%s'\n", arg); + ffmpeg_exit(1); + } + } else { + list_fmts(av_get_sample_fmt_string, AV_SAMPLE_FMT_NB); ffmpeg_exit(0); } } @@ -2830,7 +2888,7 @@ static void opt_subtitle_codec(const char *arg) opt_codec(&subtitle_stream_copy, &subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, arg); } -static void opt_codec_tag(const char *opt, const char *arg) +static int opt_codec_tag(const char *opt, const char *arg) { char *tail; uint32_t *codec_tag; @@ -2838,10 +2896,14 @@ static void opt_codec_tag(const char *opt, const char *arg) codec_tag = !strcmp(opt, "atag") ? &audio_codec_tag : !strcmp(opt, "vtag") ? &video_codec_tag : !strcmp(opt, "stag") ? &subtitle_codec_tag : NULL; + if (!codec_tag) + return -1; *codec_tag = strtol(arg, &tail, 0); if (!tail || *tail) - *codec_tag = arg[0] + (arg[1]<<8) + (arg[2]<<16) + (arg[3]<<24); + *codec_tag = AV_RL32(arg); + + return 0; } static void opt_map(const char *arg) @@ -2869,20 +2931,73 @@ static void opt_map(const char *arg) } } -static void opt_map_meta_data(const char *arg) +static void parse_meta_type(char *arg, char *type, int *index, char **endptr) +{ + *endptr = arg; + if (*arg == ',') { + *type = *(++arg); + switch (*arg) { + case 'g': + break; + case 's': + case 'c': + case 'p': + *index = strtol(++arg, endptr, 0); + break; + default: + fprintf(stderr, "Invalid metadata type %c.\n", *arg); + ffmpeg_exit(1); + } + } else + *type = 'g'; +} + +static void opt_map_metadata(const char *arg) { - AVMetaDataMap *m; + AVMetaDataMap *m, *m1; char *p; meta_data_maps = grow_array(meta_data_maps, sizeof(*meta_data_maps), &nb_meta_data_maps, nb_meta_data_maps + 1); - m = &meta_data_maps[nb_meta_data_maps - 1]; - m->out_file = strtol(arg, &p, 0); + m = &meta_data_maps[nb_meta_data_maps - 1][0]; + m->file = strtol(arg, &p, 0); + parse_meta_type(p, &m->type, &m->index, &p); + if (*p) + p++; + + m1 = &meta_data_maps[nb_meta_data_maps - 1][1]; + m1->file = strtol(p, &p, 0); + parse_meta_type(p, &m1->type, &m1->index, &p); + + if (m->type == 'g' || m1->type == 'g') + metadata_global_autocopy = 0; + if (m->type == 's' || m1->type == 's') + metadata_streams_autocopy = 0; + if (m->type == 'c' || m1->type == 'c') + metadata_chapters_autocopy = 0; +} + +static void opt_map_meta_data(const char *arg) +{ + fprintf(stderr, "-map_meta_data is deprecated and will be removed soon. " + "Use -map_metadata instead.\n"); + opt_map_metadata(arg); +} + +static void opt_map_chapters(const char *arg) +{ + AVChapterMap *c; + char *p; + + chapter_maps = grow_array(chapter_maps, sizeof(*chapter_maps), &nb_chapter_maps, + nb_chapter_maps + 1); + c = &chapter_maps[nb_chapter_maps - 1]; + c->out_file = strtol(arg, &p, 0); if (*p) p++; - m->in_file = strtol(p, &p, 0); + c->in_file = strtol(p, &p, 0); } static void opt_input_ts_scale(const char *arg) @@ -3016,9 +3131,6 @@ static void opt_input_file(const char *filename) avcodec_opts[AVMEDIA_TYPE_SUBTITLE]->strict_std_compliance); ic->flags |= AVFMT_FLAG_NONBLOCK; - if(pgmyuv_compatibility_hack) - ic->video_codec_id= CODEC_ID_PGMYUV; - /* open the input file with generic libav function */ err = av_open_input_file(&ic, filename, file_iformat, 0, ap); if (err < 0) { @@ -3080,7 +3192,7 @@ static void opt_input_file(const char *filename) for(i=0;inb_streams;i++) { AVStream *st = ic->streams[i]; AVCodecContext *dec = st->codec; - avcodec_thread_init(dec, thread_count); + dec->thread_count = thread_count; input_codecs = grow_array(input_codecs, sizeof(*input_codecs), &nb_input_codecs, nb_input_codecs + 1); switch (dec->codec_type) { case AVMEDIA_TYPE_AUDIO: @@ -3116,6 +3228,8 @@ static void opt_input_file(const char *filename) dec->flags |= CODEC_FLAG_EMU_EDGE; frame_height >>= dec->lowres; frame_width >>= dec->lowres; + dec->height = frame_height; + dec->width = frame_width; } if(me_threshold) dec->debug |= FF_DEBUG_MV; @@ -3156,7 +3270,7 @@ static void opt_input_file(const char *filename) input_files_ts_offset[nb_input_files] = input_ts_offset - (copy_ts ? 0 : timestamp); /* dump the file content */ if (verbose >= 0) - dump_format(ic, nb_input_files, filename, 0); + av_dump_format(ic, nb_input_files, filename, 0); nb_input_files++; @@ -3204,33 +3318,12 @@ static void check_audio_video_sub_inputs(int *has_video_ptr, int *has_audio_ptr, *has_subtitle_ptr = has_subtitle; } -static AVOutputStream *new_output_stream(AVFormatContext *oc, int file_idx) -{ - int idx = oc->nb_streams - 1; - AVOutputStream *ost; - - output_streams_for_file[file_idx] = - grow_array(output_streams_for_file[file_idx], - sizeof(*output_streams_for_file[file_idx]), - &nb_output_streams_for_file[file_idx], - oc->nb_streams); - ost = output_streams_for_file[file_idx][idx] = - av_mallocz(sizeof(AVOutputStream)); - if (!ost) { - fprintf(stderr, "Could not alloc output stream\n"); - ffmpeg_exit(1); - } - ost->file_index = file_idx; - ost->index = idx; - return ost; -} - static void new_video_stream(AVFormatContext *oc, int file_idx) { AVStream *st; AVOutputStream *ost; AVCodecContext *video_enc; - enum CodecID codec_id; + enum CodecID codec_id = CODEC_ID_NONE; AVCodec *codec= NULL; st = av_new_stream(oc, oc->nb_streams < nb_streamid_map ? streamid_map[oc->nb_streams] : 0); @@ -3257,7 +3350,7 @@ static void new_video_stream(AVFormatContext *oc, int file_idx) ost->bitstream_filters = video_bitstream_filters; video_bitstream_filters= NULL; - avcodec_thread_init(st->codec, thread_count); + st->codec->thread_count= thread_count; video_enc = st->codec; @@ -3377,7 +3470,7 @@ static void new_audio_stream(AVFormatContext *oc, int file_idx) AVOutputStream *ost; AVCodec *codec= NULL; AVCodecContext *audio_enc; - enum CodecID codec_id; + enum CodecID codec_id = CODEC_ID_NONE; st = av_new_stream(oc, oc->nb_streams < nb_streamid_map ? streamid_map[oc->nb_streams] : 0); if (!st) { @@ -3404,7 +3497,7 @@ static void new_audio_stream(AVFormatContext *oc, int file_idx) ost->bitstream_filters = audio_bitstream_filters; audio_bitstream_filters= NULL; - avcodec_thread_init(st->codec, thread_count); + st->codec->thread_count= thread_count; audio_enc = st->codec; audio_enc->codec_type = AVMEDIA_TYPE_AUDIO; @@ -3432,7 +3525,7 @@ static void new_audio_stream(AVFormatContext *oc, int file_idx) audio_enc->sample_fmt = audio_sample_fmt; audio_enc->sample_rate = audio_sample_rate; audio_enc->channel_layout = channel_layout; - if (avcodec_channel_layout_num_channels(channel_layout) != audio_channels) + if (av_get_channel_layout_nb_channels(channel_layout) != audio_channels) audio_enc->channel_layout = 0; choose_sample_fmt(st, codec); choose_sample_rate(st, codec); @@ -3455,6 +3548,7 @@ static void new_subtitle_stream(AVFormatContext *oc, int file_idx) AVOutputStream *ost; AVCodec *codec=NULL; AVCodecContext *subtitle_enc; + enum CodecID codec_id = CODEC_ID_NONE; st = av_new_stream(oc, oc->nb_streams < nb_streamid_map ? streamid_map[oc->nb_streams] : 0); if (!st) { @@ -3465,9 +3559,14 @@ static void new_subtitle_stream(AVFormatContext *oc, int file_idx) subtitle_enc = st->codec; output_codecs = grow_array(output_codecs, sizeof(*output_codecs), &nb_output_codecs, nb_output_codecs + 1); if(!subtitle_stream_copy){ - subtitle_enc->codec_id = find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 1, - avcodec_opts[AVMEDIA_TYPE_SUBTITLE]->strict_std_compliance); - codec= output_codecs[nb_output_codecs-1] = avcodec_find_encoder_by_name(subtitle_codec_name); + if (subtitle_codec_name) { + codec_id = find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 1, + avcodec_opts[AVMEDIA_TYPE_SUBTITLE]->strict_std_compliance); + codec= output_codecs[nb_output_codecs-1] = avcodec_find_encoder_by_name(subtitle_codec_name); + } else { + codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, AVMEDIA_TYPE_SUBTITLE); + codec = avcodec_find_encoder(codec_id); + } } avcodec_get_context_defaults3(st->codec, codec); @@ -3479,9 +3578,14 @@ static void new_subtitle_stream(AVFormatContext *oc, int file_idx) if(subtitle_codec_tag) subtitle_enc->codec_tag= subtitle_codec_tag; + if (oc->oformat->flags & AVFMT_GLOBALHEADER) { + subtitle_enc->flags |= CODEC_FLAG_GLOBAL_HEADER; + avcodec_opts[AVMEDIA_TYPE_SUBTITLE]->flags |= CODEC_FLAG_GLOBAL_HEADER; + } if (subtitle_stream_copy) { st->stream_copy = 1; } else { + subtitle_enc->codec_id = codec_id; set_context_opts(avcodec_opts[AVMEDIA_TYPE_SUBTITLE], subtitle_enc, AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_ENCODING_PARAM, codec); } @@ -3542,7 +3646,6 @@ static void opt_output_file(const char *filename) int input_has_video, input_has_audio, input_has_subtitle; AVFormatParameters params, *ap = ¶ms; AVOutputFormat *file_oformat; - AVMetadataTag *tag = NULL; if (!strcmp(filename, "-")) filename = "pipe:"; @@ -3610,8 +3713,7 @@ static void opt_output_file(const char *filename) oc->timestamp = recording_timestamp; - while ((tag = av_metadata_get(metadata, "", tag, AV_METADATA_IGNORE_SUFFIX))) - av_metadata_set2(&oc->metadata, tag->key, tag->value, 0); + av_metadata_copy(&oc->metadata, metadata, 0); av_metadata_free(&metadata); } @@ -3620,7 +3722,7 @@ static void opt_output_file(const char *filename) /* check filename in case of an image number is expected */ if (oc->oformat->flags & AVFMT_NEEDNUMBER) { if (!av_filename_number_test(oc->filename)) { - print_error(oc->filename, AVERROR_NUMEXPECTED); + print_error(oc->filename, AVERROR(EINVAL)); ffmpeg_exit(1); } } @@ -3631,7 +3733,7 @@ static void opt_output_file(const char *filename) (strchr(filename, ':') == NULL || filename[1] == ':' || av_strstart(filename, "file:", NULL))) { - if (url_exist(filename)) { + if (avio_check(filename, 0) == 0) { if (!using_stdin) { fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename); fflush(stderr); @@ -3648,7 +3750,7 @@ static void opt_output_file(const char *filename) } /* open the file */ - if ((err = url_fopen(&oc->pb, filename, URL_WRONLY)) < 0) { + if ((err = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE)) < 0) { print_error(filename, err); ffmpeg_exit(1); } @@ -3668,7 +3770,6 @@ static void opt_output_file(const char *filename) set_context_opts(oc, avformat_opts, AV_OPT_FLAG_ENCODING_PARAM, NULL); - nb_streamid_map = 0; av_freep(&forced_key_frames); } @@ -3758,6 +3859,9 @@ static void show_usage(void) static void show_help(void) { + AVCodec *c; + AVOutputFormat *oformat = NULL; + av_log_set_callback(log_callback_help); show_usage(); show_help_options(options, "Main options:\n", @@ -3786,8 +3890,27 @@ static void show_help(void) printf("\n"); av_opt_show2(avcodec_opts[0], NULL, AV_OPT_FLAG_ENCODING_PARAM|AV_OPT_FLAG_DECODING_PARAM, 0); printf("\n"); + + /* individual codec options */ + c = NULL; + while ((c = av_codec_next(c))) { + if (c->priv_class) { + av_opt_show2(&c->priv_class, NULL, AV_OPT_FLAG_ENCODING_PARAM|AV_OPT_FLAG_DECODING_PARAM, 0); + printf("\n"); + } + } + av_opt_show2(avformat_opts, NULL, AV_OPT_FLAG_ENCODING_PARAM|AV_OPT_FLAG_DECODING_PARAM, 0); printf("\n"); + + /* individual muxer options */ + while ((oformat = av_oformat_next(oformat))) { + if (oformat->priv_class) { + av_opt_show2(&oformat->priv_class, NULL, AV_OPT_FLAG_ENCODING_PARAM, 0); + printf("\n"); + } + } + av_opt_show2(sws_opts, NULL, AV_OPT_FLAG_ENCODING_PARAM|AV_OPT_FLAG_DECODING_PARAM, 0); } @@ -3978,32 +4101,11 @@ static int opt_preset(const char *opt, const char *arg) { FILE *f=NULL; char filename[1000], tmp[1000], tmp2[1000], line[1000]; - int i; - const char *base[3]= { getenv("FFMPEG_DATADIR"), - getenv("HOME"), - FFMPEG_DATADIR, - }; - - if (*opt != 'f') { - for(i=0; i<3 && !f; i++){ - if(!base[i]) - continue; - snprintf(filename, sizeof(filename), "%s%s/%s.ffpreset", base[i], i != 1 ? "" : "/.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(filename, sizeof(filename), "%s%s/%s-%s.ffpreset", base[i], i != 1 ? "" : "/.ffmpeg", codec_name, arg); - f= fopen(filename, "r"); - } - } - } else { - av_strlcpy(filename, arg, sizeof(filename)); - f= fopen(filename, "r"); - } + char *codec_name = *opt == 'v' ? video_codec_name : + *opt == 'a' ? audio_codec_name : + subtitle_codec_name; - if(!f){ + if (!(f = get_preset_file(filename, sizeof(filename), arg, *opt == 'f', codec_name))) { fprintf(stderr, "File for preset '%s' not found\n", arg); ffmpeg_exit(1); } @@ -4040,8 +4142,12 @@ static const OptionDef options[] = { { "f", HAS_ARG, {(void*)opt_format}, "force format", "fmt" }, { "i", HAS_ARG, {(void*)opt_input_file}, "input file name", "filename" }, { "y", OPT_BOOL, {(void*)&file_overwrite}, "overwrite output files" }, - { "map", HAS_ARG | OPT_EXPERT, {(void*)opt_map}, "set input stream mapping", "file:stream[:syncfile:syncstream]" }, - { "map_meta_data", HAS_ARG | OPT_EXPERT, {(void*)opt_map_meta_data}, "set meta data information of outfile from infile", "outfile:infile" }, + { "map", HAS_ARG | OPT_EXPERT, {(void*)opt_map}, "set input stream mapping", "file.stream[:syncfile.syncstream]" }, + { "map_meta_data", HAS_ARG | OPT_EXPERT, {(void*)opt_map_meta_data}, "DEPRECATED set meta data information of outfile from infile", + "outfile[,metadata]:infile[,metadata]" }, + { "map_metadata", HAS_ARG | OPT_EXPERT, {(void*)opt_map_metadata}, "set metadata information of outfile from infile", + "outfile[,metadata]:infile[,metadata]" }, + { "map_chapters", HAS_ARG | OPT_EXPERT, {(void*)opt_map_chapters}, "set chapters mapping", "outfile:infile" }, { "t", OPT_FUNC2 | HAS_ARG, {(void*)opt_recording_time}, "record or transcode \"duration\" seconds of audio/video", "duration" }, { "fs", HAS_ARG | OPT_INT64, {(void*)&limit_filesize}, "set the limit file size in bytes", "limit_size" }, // { "ss", OPT_FUNC2 | HAS_ARG, {(void*)opt_start_time}, "set the start time offset", "time_off" }, @@ -4068,6 +4174,7 @@ static const OptionDef options[] = { { "adrift_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, {(void*)&audio_drift_threshold}, "audio drift threshold", "threshold" }, { "vglobal", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&video_global_header}, "video global header storage type", "" }, { "copyts", OPT_BOOL | OPT_EXPERT, {(void*)©_ts}, "copy timestamps" }, + { "copytb", OPT_BOOL | OPT_EXPERT, {(void*)©_tb}, "copy input stream time base when stream copying" }, { "shortest", OPT_BOOL | OPT_EXPERT, {(void*)&opt_shortest}, "finish encoding within shortest input" }, // { "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", "" }, @@ -4099,7 +4206,7 @@ static const OptionDef options[] = { { "vcodec", HAS_ARG | OPT_VIDEO, {(void*)opt_video_codec}, "force video codec ('copy' to copy stream)", "codec" }, { "me_threshold", HAS_ARG | OPT_FUNC2 | OPT_EXPERT | OPT_VIDEO, {(void*)opt_me_threshold}, "motion estimaton threshold", "threshold" }, { "sameq", OPT_BOOL | OPT_VIDEO, {(void*)&same_quality}, - "use same video quality as source (implies VBR)" }, + "use same quantizer 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_prefix}, "select two pass log file name prefix", "prefix" }, { "deinterlace", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&do_deinterlace}, @@ -4182,7 +4289,7 @@ int main(int argc, char **argv) #if HAVE_ISATTY if(isatty(STDIN_FILENO)) - url_set_interrupt_cb(decode_interrupt_cb); + avio_set_interrupt_cb(decode_interrupt_cb); #endif init_opts();