From: Michael Niedermayer Date: Sat, 19 Nov 2011 00:55:55 +0000 (+0100) Subject: Merge remote-tracking branch 'qatar/master' X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=e161b079dee12b11c40df67cf422edeb84772bbe;p=ffmpeg Merge remote-tracking branch 'qatar/master' * qatar/master: (22 commits) configure: add check for w32threads to enable it automatically rtmp: do not hardcode invoke numbers cinepack: return non-generic errors fate-lavf-ts: use -mpegts_transport_stream_id option. Add an APIchanges entry and a minor bump for avio changes. avio: Mark the old interrupt callback mechanism as deprecated avplay: Set the new interrupt callback avconv: Set new interrupt callbacks for all AVFormatContexts, use avio_open2() everywhere cinepak: remove redundant coordinate checks cinepak: check strip_size cinepak, simplify, use AV_RB24() cinepak: simplify, use FFMIN() cinepak: Fix division by zero, ask for sample if encoded_buf_size is 0 applehttp: Fix seeking in streams not starting at DTS=0 http: Don't use the normal http proxy mechanism for https tls: Handle connection via a http proxy http: Reorder two code blocks http: Add a new protocol for opening connections via http proxies http: Split out the non-chunked buffer reading part from http_read segafilm: add support for raw videos ... Conflicts: avconv.c configure doc/APIchanges libavcodec/cinepak.c libavformat/applehttp.c libavformat/version.h tests/lavf-regression.sh tests/ref/lavf/ts Merged-by: Michael Niedermayer --- e161b079dee12b11c40df67cf422edeb84772bbe diff --cc avconv.c index 76d8def806a,ef41245726d..a019ffaf6f7 --- a/avconv.c +++ b/avconv.c @@@ -557,43 -503,13 +557,45 @@@ static void term_init(void #endif } +/* 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; + + if(run_as_daemon) + return -1; + + 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_KBHIT + if(kbhit()) + return(getch()); +#endif + return -1; +} + - static int decode_interrupt_cb(void) + static int decode_interrupt_cb(void *ctx) { - return received_nb_signals > 1; + q_pressed += read_key() == 'q'; + return q_pressed > 1; } + static const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL }; + void exit_program(int ret) { int i; @@@ -3585,11 -3466,12 +3589,12 @@@ static int copy_chapters(InputFile *ifi return 0; } -static int read_avserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename) +static int read_ffserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename) { int i, err; - AVFormatContext *ic = NULL; + AVFormatContext *ic = avformat_alloc_context(); + ic->interrupt_callback = int_cb; err = avformat_open_input(&ic, filename, NULL, NULL); if (err < 0) return err; @@@ -3637,7 -3518,24 +3642,8 @@@ static void opt_output_file(void *optct exit_program(1); } - if (o->format) { - file_oformat = av_guess_format(o->format, NULL, NULL); - if (!file_oformat) { - av_log(NULL, AV_LOG_FATAL, "Requested output format '%s' is not a suitable output format\n", o->format); - exit_program(1); - } - } else { - file_oformat = av_guess_format(NULL, filename, NULL); - if (!file_oformat) { - av_log(NULL, AV_LOG_FATAL, "Unable to find a suitable output format for '%s'\n", - filename); - exit_program(1); - } - } - - oc->oformat = file_oformat; + file_oformat= oc->oformat; + oc->interrupt_callback = int_cb; - av_strlcpy(oc->filename, filename, sizeof(oc->filename)); if (!strcmp(file_oformat->name, "ffm") && av_strstart(filename, "http:", NULL)) { @@@ -4350,12 -4227,7 +4358,6 @@@ int main(int argc, char **argv av_register_all(); avformat_network_init(); - #if HAVE_ISATTY - if(isatty(STDIN_FILENO)) - avio_set_interrupt_cb(decode_interrupt_cb); - #endif - -- show_banner(); /* parse options */ parse_options(&o, argc, argv, options, opt_output_file); diff --cc configure index 2daa079b573,61bb4dfb547..d0376bb391f --- a/configure +++ b/configure @@@ -2991,17 -2849,15 +2990,21 @@@ check_header X11/extensions/XvMClib. disabled zlib || check_lib zlib.h zlibVersion -lz || disable zlib disabled bzlib || check_lib2 bzlib.h BZ2_bzlibVersion -lbz2 || disable bzlib +# check for VDA header +if ! disabled vda; then + if check_header VideoDecodeAcceleration/VDADecoder.h; then + enable vda + add_ldflags -framework CoreFoundation -framework VideoDecodeAcceleration -framework QuartzCore + fi +fi + + if ! disabled w32threads && ! enabled pthreads; then + check_func _beginthreadex && enable w32threads + fi + # check for some common methods of building with pthread support # do this before the optional library checks as some of them require pthreads -if ! disabled pthreads && ! enabled w32threads; then +if ! disabled pthreads && ! enabled w32threads && ! enabled os2threads; then enable pthreads if check_func pthread_create; then : diff --cc doc/APIchanges index 03f7d460d29,f1913bd6ded..2ce14618fa7 --- a/doc/APIchanges +++ b/doc/APIchanges @@@ -13,12 -13,16 +13,22 @@@ libavutil: 2011-04-1 API changes, most recent first: +2011-11-03 - 96949da - lavu 51.23.0 + Add av_strcasecmp() and av_strncasecmp() to avstring.h. + +2011-10-20 - b35e9e1 - lavu 51.22.0 + Add av_strtok() to avstring.h. + + 2011-11-13 - lavf 53.15.0 + New interrupt callback API, allowing per-AVFormatContext/AVIOContext + interrupt callbacks. + 6aa0b98 Add AVIOInterruptCB struct and the interrupt_callback field to + AVFormatContext. + 1dee0ac Add avio_open2() with additional parameters. Those are + an interrupt callback and an options AVDictionary. + This will allow passing AVOptions to protocols after lavf + 54.0. + 2011-11-xx - xxxxxxx - lavu 51.16.0 Add av_timegm() diff --cc ffmpeg.c index 9895fb39703,c731cec53b4..507c35dba4e --- a/ffmpeg.c +++ b/ffmpeg.c @@@ -581,66 -441,12 +581,68 @@@ static void term_init(void #endif } -static int decode_interrupt_cb(void) +/* read a key without blocking */ +static int read_key(void) +{ + unsigned char ch; +#if HAVE_TERMIOS_H + int n = 1; + 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_KBHIT +# if HAVE_PEEKNAMEDPIPE + static int is_pipe; + static HANDLE input_handle; + DWORD dw, nchars; + if(!input_handle){ + input_handle = GetStdHandle(STD_INPUT_HANDLE); + is_pipe = !GetConsoleMode(input_handle, &dw); + } + + if (stdin->_cnt > 0) { + read(0, &ch, 1); + return ch; + } + if (is_pipe) { + /* When running under a GUI, you will end here. */ + if (!PeekNamedPipe(input_handle, NULL, 0, NULL, &nchars, NULL)) + return -1; + //Read it + if(nchars != 0) { + read(0, &ch, 1); + return ch; + }else{ + return -1; + } + } +# endif + if(kbhit()) + return(getch()); +#endif + return -1; +} + - static int decode_interrupt_cb(void) ++static int decode_interrupt_cb(void *ctx) { return received_nb_signals > 1; } -void exit_program(int ret) ++static const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL }; ++ +void av_noreturn exit_program(int ret) { int i; @@@ -2371,39 -2331,150 +2373,40 @@@ static int transcode_init(OutputFile *o assert_avoptions(ost->opts); if (ost->st->codec->bit_rate && ost->st->codec->bit_rate < 1000) av_log(NULL, AV_LOG_WARNING, "The bitrate parameter is set too low." - "It takes bits/s as argument, not kbits/s\n"); + " It takes bits/s as argument, not kbits/s\n"); extra_size += ost->st->codec->extradata_size; - } - } - - /* open each decoder */ - for (i = 0; i < nb_input_streams; i++) { - ist = &input_streams[i]; - if (ist->decoding_needed) { - AVCodec *codec = ist->dec; - if (!codec) - codec = avcodec_find_decoder(ist->st->codec->codec_id); - if (!codec) { - snprintf(error, sizeof(error), "Decoder (codec id %d) not found for input stream #%d.%d", - ist->st->codec->codec_id, ist->file_index, ist->st->index); - ret = AVERROR(EINVAL); - goto dump_format; - } - - /* update requested sample format for the decoder based on the - corresponding encoder sample format */ - for (j = 0; j < nb_ostreams; j++) { - ost = ost_table[j]; - if (ost->source_index == i) { - update_sample_fmt(ist->st->codec, codec, ost->st->codec); - break; - } - } - - if (avcodec_open2(ist->st->codec, codec, &ist->opts) < 0) { - snprintf(error, sizeof(error), "Error while opening decoder for input stream #%d.%d", - ist->file_index, ist->st->index); - ret = AVERROR(EINVAL); - goto dump_format; - } - assert_codec_experimental(ist->st->codec, 0); - assert_avoptions(ost->opts); - } - } - - /* init pts */ - for (i = 0; i < nb_input_streams; i++) { - AVStream *st; - ist = &input_streams[i]; - st= ist->st; - ist->pts = st->avg_frame_rate.num ? - st->codec->has_b_frames*AV_TIME_BASE / av_q2d(st->avg_frame_rate) : 0; - ist->next_pts = AV_NOPTS_VALUE; - init_pts_correction(&ist->pts_ctx); - ist->is_start = 1; - } - - /* set meta data information from input file if required */ - for (i=0;i= (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].ctx; - - for (j = 0; j < 2; j++) { - MetadataMap *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; - } + if (ost->st->codec->me_threshold) + input_streams[ost->source_index].st->codec->debug |= FF_DEBUG_MV; } - - av_dict_copy(meta[0], *meta[1], AV_DICT_DONT_OVERWRITE); } - /* copy global metadata by default */ - if (metadata_global_autocopy) { - - for (i = 0; i < nb_output_files; i++) - av_dict_copy(&output_files[i]->metadata, input_files[0].ctx->metadata, - AV_DICT_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 (outfile >= nb_output_files) { - snprintf(error, sizeof(error), "Invalid output file index %d in chapter mapping.\n",outfile); - ret = AVERROR(EINVAL); + /* init input streams */ + for (i = 0; i < nb_input_streams; i++) + if ((ret = init_input_stream(i, output_streams, nb_output_streams, error, sizeof(error))) < 0) goto dump_format; - } - copy_chapters(infile, outfile); - } - /* copy chapters from the first input file that has them*/ - if (!nb_chapter_maps) - for (i = 0; i < nb_input_files; i++) { - if (!input_files[i].ctx->nb_chapters) - continue; + /* discard unused programs */ + for (i = 0; i < nb_input_files; i++) { + InputFile *ifile = &input_files[i]; + for (j = 0; j < ifile->ctx->nb_programs; j++) { + AVProgram *p = ifile->ctx->programs[j]; + int discard = AVDISCARD_ALL; - for (j = 0; j < nb_output_files; j++) - if ((ret = copy_chapters(i, j)) < 0) - goto dump_format; - break; + for (k = 0; k < p->nb_stream_indexes; k++) + if (!input_streams[ifile->ist_index + p->stream_index[k]].discard) { + discard = AVDISCARD_DEFAULT; + break; + } + p->discard = discard; } + } /* open files and write file headers */ - for(i=0;iinterrupt_callback = int_cb; + if (avformat_write_header(os, &output_files[i].opts) < 0) { snprintf(error, sizeof(error), "Could not write header for output file #%d (incorrect codec parameters ?)", i); ret = AVERROR(EINVAL); goto dump_format; @@@ -2468,35 -2519,9 +2471,34 @@@ print_sdp(output_files, nb_output_files); } - if (verbose >= 0) - fprintf(stderr, "Press ctrl-c to stop encoding\n"); - term_init(); + return 0; +} + +/* + * The following code is the main loop of the file converter + */ +static int transcode(OutputFile *output_files, int nb_output_files, + InputFile *input_files, int nb_input_files) +{ + int ret, i; + AVFormatContext *is, *os; + OutputStream *ost; + InputStream *ist; + uint8_t *no_packet; + int no_packet_count=0; + int64_t timer_start; + int key; + + if (!(no_packet = av_mallocz(nb_input_files))) + exit_program(1); + + ret = transcode_init(output_files, nb_output_files, input_files, nb_input_files); + if (ret < 0) + goto fail; + + if (!using_stdin) { + av_log(NULL, AV_LOG_INFO, "Press [q] to stop, [?] for help\n"); - avio_set_interrupt_cb(decode_interrupt_cb); + } timer_start = av_gettime(); @@@ -3087,174 -3064,75 +3089,174 @@@ static int opt_recording_timestamp(Opti return 0; } -static int opt_input_ts_scale(const char *opt, const char *arg) +static AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder) { - unsigned int stream; - double scale; - char *p; - - stream = strtol(arg, &p, 0); - if (*p) - p++; - scale= strtod(p, &p); + const char *codec_string = encoder ? "encoder" : "decoder"; + AVCodec *codec; - ts_scale = grow_array(ts_scale, sizeof(*ts_scale), &nb_ts_scale, stream + 1); - ts_scale[stream] = scale; - return 0; + codec = encoder ? + avcodec_find_encoder_by_name(name) : + avcodec_find_decoder_by_name(name); + if(!codec) { + av_log(NULL, AV_LOG_FATAL, "Unknown %s '%s'\n", codec_string, name); + exit_program(1); + } + if(codec->type != type) { + av_log(NULL, AV_LOG_FATAL, "Invalid %s type '%s'\n", codec_string, name); + exit_program(1); + } + return codec; } -static int opt_recording_time(const char *opt, const char *arg) +static AVCodec *choose_decoder(OptionsContext *o, AVFormatContext *s, AVStream *st) { - recording_time = parse_time_or_die(opt, arg, 1); - return 0; -} + char *codec_name = NULL; -static int opt_start_time(const char *opt, const char *arg) -{ - start_time = parse_time_or_die(opt, arg, 1); - return 0; + MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, st); + if (codec_name) { + AVCodec *codec = find_codec_or_die(codec_name, st->codec->codec_type, 0); + st->codec->codec_id = codec->id; + return codec; + } else + return avcodec_find_decoder(st->codec->codec_id); } -static int opt_recording_timestamp(const char *opt, const char *arg) +/** + * Add all the streams from the given input file to the global + * list of input streams. + */ +static void add_input_streams(OptionsContext *o, AVFormatContext *ic) { - char buf[128]; - int64_t recording_timestamp = parse_time_or_die(opt, arg, 0) / 1E6; - struct tm time = *gmtime((time_t*)&recording_timestamp); - strftime(buf, sizeof(buf), "creation_time=%FT%T%z", &time); - opt_metadata("metadata", buf); + int i, rfps, rfps_base; + char *next, *codec_tag = NULL; - av_log(NULL, AV_LOG_WARNING, "%s is deprecated, set the 'creation_time' metadata " - "tag instead.\n", opt); - return 0; + for (i = 0; i < ic->nb_streams; i++) { + AVStream *st = ic->streams[i]; + AVCodecContext *dec = st->codec; + InputStream *ist; + + input_streams = grow_array(input_streams, sizeof(*input_streams), &nb_input_streams, nb_input_streams + 1); + ist = &input_streams[nb_input_streams - 1]; + ist->st = st; + ist->file_index = nb_input_files; + ist->discard = 1; + ist->opts = filter_codec_opts(codec_opts, ist->st->codec->codec_id, ic, st); + + ist->ts_scale = 1.0; + MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st); + + MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st); + if (codec_tag) { + uint32_t tag = strtol(codec_tag, &next, 0); + if (*next) + tag = AV_RL32(codec_tag); + st->codec->codec_tag = tag; + } + + ist->dec = choose_decoder(o, ic, st); + + switch (dec->codec_type) { + case AVMEDIA_TYPE_AUDIO: + if(!ist->dec) + ist->dec = avcodec_find_decoder(dec->codec_id); + if(o->audio_disable) + st->discard= AVDISCARD_ALL; + break; + case AVMEDIA_TYPE_VIDEO: + if(!ist->dec) + ist->dec = avcodec_find_decoder(dec->codec_id); + rfps = ic->streams[i]->r_frame_rate.num; + rfps_base = ic->streams[i]->r_frame_rate.den; + if (dec->lowres) { + dec->flags |= CODEC_FLAG_EMU_EDGE; + } + + if (dec->time_base.den != rfps*dec->ticks_per_frame || dec->time_base.num != rfps_base) { + + av_log(NULL, AV_LOG_INFO,"\nSeems stream %d codec frame rate differs from container frame rate: %2.2f (%d/%d) -> %2.2f (%d/%d)\n", + i, (float)dec->time_base.den / dec->time_base.num, dec->time_base.den, dec->time_base.num, + (float)rfps / rfps_base, rfps, rfps_base); + } + + if (o->video_disable) + st->discard= AVDISCARD_ALL; + else if(video_discard) + st->discard= video_discard; + break; + case AVMEDIA_TYPE_DATA: + break; + case AVMEDIA_TYPE_SUBTITLE: + if(!ist->dec) + ist->dec = avcodec_find_decoder(dec->codec_id); + if(o->subtitle_disable) + st->discard = AVDISCARD_ALL; + break; + case AVMEDIA_TYPE_ATTACHMENT: + case AVMEDIA_TYPE_UNKNOWN: + break; + default: + abort(); + } + } } -static int opt_input_ts_offset(const char *opt, const char *arg) +static void assert_file_overwrite(const char *filename) { - input_ts_offset = parse_time_or_die(opt, arg, 1); - return 0; + if (!file_overwrite && + (strchr(filename, ':') == NULL || filename[1] == ':' || + av_strstart(filename, "file:", NULL))) { + if (avio_check(filename, 0) == 0) { + if (!using_stdin) { + fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename); + fflush(stderr); + term_exit(); + if (!read_yesno()) { + av_log(0, AV_LOG_FATAL, "Not overwriting - exiting\n"); + exit_program(1); + } + term_init(); + } + else { + av_log(0, AV_LOG_FATAL, "File '%s' already exists. Exiting.\n", filename); + exit_program(1); + } + } + } } -static enum CodecID find_codec_or_die(const char *name, int type, int encoder) +static void dump_attachment(AVStream *st, const char *filename) { - const char *codec_string = encoder ? "encoder" : "decoder"; - AVCodec *codec; + int ret; + AVIOContext *out = NULL; + AVDictionaryEntry *e; - if(!name) - return CODEC_ID_NONE; - codec = encoder ? - avcodec_find_encoder_by_name(name) : - avcodec_find_decoder_by_name(name); - if(!codec) { - fprintf(stderr, "Unknown %s '%s'\n", codec_string, name); + if (!st->codec->extradata_size) { + av_log(NULL, AV_LOG_WARNING, "No extradata to dump in stream #%d:%d.\n", + nb_input_files - 1, st->index); + return; + } + if (!*filename && (e = av_dict_get(st->metadata, "filename", NULL, 0))) + filename = e->value; + if (!*filename) { + av_log(NULL, AV_LOG_FATAL, "No filename specified and no 'filename' tag" + "in stream #%d:%d.\n", nb_input_files - 1, st->index); exit_program(1); } - if(codec->type != type) { - fprintf(stderr, "Invalid %s type '%s'\n", codec_string, name); + + assert_file_overwrite(filename); + - if ((ret = avio_open (&out, filename, AVIO_FLAG_WRITE)) < 0) { ++ if ((ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &int_cb, NULL)) < 0) { + av_log(NULL, AV_LOG_FATAL, "Could not open file %s for writing.\n", + filename); exit_program(1); } - return codec->id; + + avio_write(out, st->codec->extradata, st->codec->extradata_size); + avio_flush(out); + avio_close(out); } -static int opt_input_file(const char *opt, const char *filename) +static int opt_input_file(OptionsContext *o, const char *opt, const char *filename) { AVFormatContext *ic; AVInputFormat *file_iformat = NULL; @@@ -3283,35 -3162,32 +3285,36 @@@ print_error(filename, AVERROR(ENOMEM)); exit_program(1); } - if (audio_sample_rate) { - snprintf(buf, sizeof(buf), "%d", audio_sample_rate); + if (o->nb_audio_sample_rate) { + snprintf(buf, sizeof(buf), "%d", o->audio_sample_rate[o->nb_audio_sample_rate - 1].u.i); av_dict_set(&format_opts, "sample_rate", buf, 0); } - if (audio_channels) { - snprintf(buf, sizeof(buf), "%d", audio_channels); + if (o->nb_audio_channels) { + snprintf(buf, sizeof(buf), "%d", o->audio_channels[o->nb_audio_channels - 1].u.i); av_dict_set(&format_opts, "channels", buf, 0); } - if (frame_rate.num) { - snprintf(buf, sizeof(buf), "%d/%d", frame_rate.num, frame_rate.den); - av_dict_set(&format_opts, "framerate", buf, 0); + if (o->nb_frame_rates) { + av_dict_set(&format_opts, "framerate", o->frame_rates[o->nb_frame_rates - 1].u.str, 0); } - if (frame_width && frame_height) { - snprintf(buf, sizeof(buf), "%dx%d", frame_width, frame_height); - av_dict_set(&format_opts, "video_size", buf, 0); + if (o->nb_frame_sizes) { + av_dict_set(&format_opts, "video_size", o->frame_sizes[o->nb_frame_sizes - 1].u.str, 0); } - if (frame_pix_fmt != PIX_FMT_NONE) - av_dict_set(&format_opts, "pixel_format", av_get_pix_fmt_name(frame_pix_fmt), 0); - - ic->video_codec_id = - find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0); - ic->audio_codec_id = - find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0); - ic->subtitle_codec_id= - find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0); + if (o->nb_frame_pix_fmts) + av_dict_set(&format_opts, "pixel_format", o->frame_pix_fmts[o->nb_frame_pix_fmts - 1].u.str, 0); + + ic->video_codec_id = video_codec_name ? + find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0)->id : CODEC_ID_NONE; + ic->audio_codec_id = audio_codec_name ? + find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0)->id : CODEC_ID_NONE; + ic->subtitle_codec_id= subtitle_codec_name ? + find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0)->id : CODEC_ID_NONE; ic->flags |= AVFMT_FLAG_NONBLOCK; ++ ic->interrupt_callback = int_cb; + + if (loop_input) { + av_log(NULL, AV_LOG_WARNING, "-loop_input is deprecated, use -loop 1\n"); + ic->loop_input = loop_input; + } /* open the input file with generic libav function */ err = avformat_open_input(&ic, filename, file_iformat, &format_opts); @@@ -3384,244 -3351,108 +3387,244 @@@ return 0; } -static void check_inputs(int *has_video_ptr, - int *has_audio_ptr, - int *has_subtitle_ptr, - int *has_data_ptr) +static void parse_forced_key_frames(char *kf, OutputStream *ost) { - int has_video, has_audio, has_subtitle, has_data, i, j; - AVFormatContext *ic; + char *p; + int n = 1, i; - has_video = 0; - has_audio = 0; - has_subtitle = 0; - has_data = 0; + for (p = kf; *p; p++) + if (*p == ',') + n++; + ost->forced_kf_count = n; + ost->forced_kf_pts = av_malloc(sizeof(*ost->forced_kf_pts) * n); + if (!ost->forced_kf_pts) { + av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n"); + exit_program(1); + } + for (i = 0; i < n; i++) { + p = i ? strchr(p, ',') + 1 : kf; + ost->forced_kf_pts[i] = parse_time_or_die("force_key_frames", p, 1); + } +} - for(j=0;jnb_streams;i++) { - AVCodecContext *enc = ic->streams[i]->codec; - switch(enc->codec_type) { - case AVMEDIA_TYPE_AUDIO: - has_audio = 1; - break; - case AVMEDIA_TYPE_VIDEO: - has_video = 1; - break; - case AVMEDIA_TYPE_SUBTITLE: - has_subtitle = 1; - break; - case AVMEDIA_TYPE_DATA: - case AVMEDIA_TYPE_ATTACHMENT: - case AVMEDIA_TYPE_UNKNOWN: - has_data = 1; - break; - default: - abort(); - } +static uint8_t *get_line(AVIOContext *s) +{ + AVIOContext *line; + uint8_t *buf; + char c; + + if (avio_open_dyn_buf(&line) < 0) { + av_log(NULL, AV_LOG_FATAL, "Could not alloc buffer for reading preset.\n"); + exit_program(1); + } + + while ((c = avio_r8(s)) && c != '\n') + avio_w8(line, c); + avio_w8(line, 0); + avio_close_dyn_buf(line, &buf); + + return buf; +} + +static int get_preset_file_2(const char *preset_name, const char *codec_name, AVIOContext **s) +{ + int i, ret = 1; + char filename[1000]; + const char *base[3] = { getenv("AVCONV_DATADIR"), + getenv("HOME"), + AVCONV_DATADIR, + }; + + for (i = 0; i < FF_ARRAY_ELEMS(base) && ret; i++) { + if (!base[i]) + continue; + if (codec_name) { + snprintf(filename, sizeof(filename), "%s%s/%s-%s.avpreset", base[i], + i != 1 ? "" : "/.avconv", codec_name, preset_name); - ret = avio_open(s, filename, AVIO_FLAG_READ); ++ ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL); + } + if (ret) { + snprintf(filename, sizeof(filename), "%s%s/%s.avpreset", base[i], + i != 1 ? "" : "/.avconv", preset_name); - ret = avio_open(s, filename, AVIO_FLAG_READ); ++ ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL); } } - *has_video_ptr = has_video; - *has_audio_ptr = has_audio; - *has_subtitle_ptr = has_subtitle; - *has_data_ptr = has_data; + return ret; } -static void new_video_stream(AVFormatContext *oc, int file_idx) +static void choose_encoder(OptionsContext *o, AVFormatContext *s, OutputStream *ost) +{ + char *codec_name = NULL; + + MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, ost->st); + if (!codec_name) { + ost->st->codec->codec_id = av_guess_codec(s->oformat, NULL, s->filename, + NULL, ost->st->codec->codec_type); + ost->enc = avcodec_find_encoder(ost->st->codec->codec_id); + } else if (!strcmp(codec_name, "copy")) + ost->stream_copy = 1; + else { + ost->enc = find_codec_or_die(codec_name, ost->st->codec->codec_type, 1); + ost->st->codec->codec_id = ost->enc->id; + } +} + +static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type) { - AVStream *st; OutputStream *ost; - AVCodecContext *video_enc; - enum CodecID codec_id = CODEC_ID_NONE; - AVCodec *codec= NULL; + AVStream *st = avformat_new_stream(oc, NULL); + int idx = oc->nb_streams - 1, ret = 0; + char *bsf = NULL, *next, *codec_tag = NULL; + AVBitStreamFilterContext *bsfc, *bsfc_prev = NULL; + double qscale = -1; + char *buf = NULL, *arg = NULL, *preset = NULL; + AVIOContext *s = NULL; - if(!video_stream_copy){ - if (video_codec_name) { - codec_id = find_codec_or_die(video_codec_name, AVMEDIA_TYPE_VIDEO, 1); - codec = avcodec_find_encoder_by_name(video_codec_name); - } else { - codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, AVMEDIA_TYPE_VIDEO); - codec = avcodec_find_encoder(codec_id); - } + if (!st) { + av_log(NULL, AV_LOG_FATAL, "Could not alloc stream.\n"); + exit_program(1); } - ost = new_output_stream(oc, file_idx, codec); - st = ost->st; - if (!video_stream_copy) { - ost->frame_aspect_ratio = frame_aspect_ratio; - frame_aspect_ratio = 0; -#if CONFIG_AVFILTER - ost->avfilter= vfilters; - vfilters = NULL; -#endif + if (oc->nb_streams - 1 < o->nb_streamid_map) + st->id = o->streamid_map[oc->nb_streams - 1]; + + output_streams = grow_array(output_streams, sizeof(*output_streams), &nb_output_streams, + nb_output_streams + 1); + ost = &output_streams[nb_output_streams - 1]; + ost->file_index = nb_output_files; + ost->index = idx; + ost->st = st; + st->codec->codec_type = type; + choose_encoder(o, oc, ost); + if (ost->enc) { + ost->opts = filter_codec_opts(codec_opts, ost->enc->id, oc, st); + } + + avcodec_get_context_defaults3(st->codec, ost->enc); + st->codec->codec_type = type; // XXX hack, avcodec_get_context_defaults2() sets type to unknown for stream copy + + MATCH_PER_STREAM_OPT(presets, str, preset, oc, st); + if (preset && (!(ret = get_preset_file_2(preset, ost->enc->name, &s)))) { + do { + buf = get_line(s); + if (!buf[0] || buf[0] == '#') { + av_free(buf); + continue; + } + if (!(arg = strchr(buf, '='))) { + av_log(NULL, AV_LOG_FATAL, "Invalid line found in the preset file.\n"); + exit_program(1); + } + *arg++ = 0; + av_dict_set(&ost->opts, buf, arg, AV_DICT_DONT_OVERWRITE); + av_free(buf); + } while (!s->eof_reached); + avio_close(s); + } + if (ret) { + av_log(NULL, AV_LOG_FATAL, + "Preset %s specified for stream %d:%d, but could not be opened.\n", + preset, ost->file_index, ost->index); + exit_program(1); } - ost->bitstream_filters = video_bitstream_filters; - video_bitstream_filters= NULL; + ost->max_frames = INT64_MAX; + MATCH_PER_STREAM_OPT(max_frames, i64, ost->max_frames, oc, st); - st->codec->thread_count= thread_count; + MATCH_PER_STREAM_OPT(bitstream_filters, str, bsf, oc, st); + while (bsf) { + if (next = strchr(bsf, ',')) + *next++ = 0; + if (!(bsfc = av_bitstream_filter_init(bsf))) { + av_log(NULL, AV_LOG_FATAL, "Unknown bitstream filter %s\n", bsf); + exit_program(1); + } + if (bsfc_prev) + bsfc_prev->next = bsfc; + else + ost->bitstream_filters = bsfc; - video_enc = st->codec; + bsfc_prev = bsfc; + bsf = next; + } - if(video_codec_tag) - video_enc->codec_tag= video_codec_tag; + MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, oc, st); + if (codec_tag) { + uint32_t tag = strtol(codec_tag, &next, 0); + if (*next) + tag = AV_RL32(codec_tag); + st->codec->codec_tag = tag; + } - if(oc->oformat->flags & AVFMT_GLOBALHEADER) { - video_enc->flags |= CODEC_FLAG_GLOBAL_HEADER; + MATCH_PER_STREAM_OPT(qscale, dbl, qscale, oc, st); + if (qscale >= 0 || same_quant) { + st->codec->flags |= CODEC_FLAG_QSCALE; + st->codec->global_quality = FF_QP2LAMBDA * qscale; } - video_enc->codec_type = AVMEDIA_TYPE_VIDEO; - if (video_stream_copy) { - st->stream_copy = 1; - video_enc->sample_aspect_ratio = - st->sample_aspect_ratio = av_d2q(frame_aspect_ratio*frame_height/frame_width, 255); - } else { - const char *p; + if (oc->oformat->flags & AVFMT_GLOBALHEADER) + st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; + + av_opt_get_int(sws_opts, "sws_flags", 0, &ost->sws_flags); + return ost; +} + +static void parse_matrix_coeffs(uint16_t *dest, const char *str) +{ + int i; + const char *p = str; + for(i = 0;; i++) { + dest[i] = atoi(p); + if(i == 63) + break; + p = strchr(p, ','); + if(!p) { + av_log(NULL, AV_LOG_FATAL, "Syntax error in matrix \"%s\" at coeff %d\n", str, i); + exit_program(1); + } + p++; + } +} + +static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc) +{ + AVStream *st; + OutputStream *ost; + AVCodecContext *video_enc; + + ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO); + st = ost->st; + video_enc = st->codec; + + if (!ost->stream_copy) { + const char *p = NULL; + char *forced_key_frames = NULL, *frame_rate = NULL, *frame_size = NULL; + char *frame_aspect_ratio = NULL, *frame_pix_fmt = NULL; + char *intra_matrix = NULL, *inter_matrix = NULL, *filters = NULL; int i; - if (frame_rate.num) - ost->frame_rate = frame_rate; - video_enc->codec_id = codec_id; + MATCH_PER_STREAM_OPT(frame_rates, str, frame_rate, oc, st); + if (frame_rate && av_parse_video_rate(&ost->frame_rate, frame_rate) < 0) { + av_log(NULL, AV_LOG_FATAL, "Invalid framerate value: %s\n", frame_rate); + exit_program(1); + } - video_enc->width = frame_width; - video_enc->height = frame_height; - video_enc->pix_fmt = frame_pix_fmt; + MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st); + if (frame_size && av_parse_video_size(&video_enc->width, &video_enc->height, frame_size) < 0) { + av_log(NULL, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size); + exit_program(1); + } + + MATCH_PER_STREAM_OPT(frame_aspect_ratios, str, frame_aspect_ratio, oc, st); + if (frame_aspect_ratio) + ost->frame_aspect_ratio = parse_frame_aspect_ratio(frame_aspect_ratio); + + video_enc->bits_per_raw_sample = frame_bits_per_raw_sample; + MATCH_PER_STREAM_OPT(frame_pix_fmts, str, frame_pix_fmt, oc, st); + if (frame_pix_fmt && (video_enc->pix_fmt = av_get_pix_fmt(frame_pix_fmt)) == PIX_FMT_NONE) { + av_log(NULL, AV_LOG_FATAL, "Unknown pixel format requested: %s.\n", frame_pix_fmt); + exit_program(1); + } st->sample_aspect_ratio = video_enc->sample_aspect_ratio; if (intra_only) @@@ -3786,107 -3638,70 +3789,108 @@@ static OutputStream *new_subtitle_strea st = ost->st; subtitle_enc = st->codec; - ost->bitstream_filters = subtitle_bitstream_filters; - subtitle_bitstream_filters= NULL; - subtitle_enc->codec_type = AVMEDIA_TYPE_SUBTITLE; - if(subtitle_codec_tag) - subtitle_enc->codec_tag= subtitle_codec_tag; + return ost; +} + +/* arg format is "output-stream-index:streamid-value". */ +static int opt_streamid(OptionsContext *o, const char *opt, const char *arg) +{ + int idx; + char *p; + char idx_str[16]; + + av_strlcpy(idx_str, arg, sizeof(idx_str)); + p = strchr(idx_str, ':'); + if (!p) { + av_log(NULL, AV_LOG_FATAL, + "Invalid value '%s' for option '%s', required syntax is 'index:value'\n", + arg, opt); + exit_program(1); + } + *p++ = '\0'; + idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, MAX_STREAMS-1); + o->streamid_map = grow_array(o->streamid_map, sizeof(*o->streamid_map), &o->nb_streamid_map, idx+1); + o->streamid_map[idx] = parse_number_or_die(opt, p, OPT_INT, 0, INT_MAX); + return 0; +} + +static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata) +{ + AVFormatContext *is = ifile->ctx; + AVFormatContext *os = ofile->ctx; + int i; + + for (i = 0; i < is->nb_chapters; i++) { + AVChapter *in_ch = is->chapters[i], *out_ch; + int64_t ts_off = av_rescale_q(ofile->start_time - ifile->ts_offset, + AV_TIME_BASE_Q, in_ch->time_base); + int64_t rt = (ofile->recording_time == INT64_MAX) ? INT64_MAX : + av_rescale_q(ofile->recording_time, AV_TIME_BASE_Q, in_ch->time_base); + + + if (in_ch->end < ts_off) + continue; + if (rt != INT64_MAX && in_ch->start > rt + ts_off) + break; + + out_ch = av_mallocz(sizeof(AVChapter)); + if (!out_ch) + return AVERROR(ENOMEM); + + out_ch->id = in_ch->id; + out_ch->time_base = in_ch->time_base; + out_ch->start = FFMAX(0, in_ch->start - ts_off); + out_ch->end = FFMIN(rt, in_ch->end - ts_off); - if (oc->oformat->flags & AVFMT_GLOBALHEADER) { - subtitle_enc->flags |= CODEC_FLAG_GLOBAL_HEADER; - } - if (subtitle_stream_copy) { - st->stream_copy = 1; - } else { - subtitle_enc->codec_id = codec_id; - } + if (copy_metadata) + av_dict_copy(&out_ch->metadata, in_ch->metadata, 0); - if (subtitle_language) { - av_dict_set(&st->metadata, "language", subtitle_language, 0); - av_freep(&subtitle_language); + os->nb_chapters++; + os->chapters = av_realloc_f(os->chapters, os->nb_chapters, sizeof(AVChapter)); + if (!os->chapters) + return AVERROR(ENOMEM); + os->chapters[os->nb_chapters - 1] = out_ch; } - - subtitle_disable = 0; - av_freep(&subtitle_codec_name); - subtitle_stream_copy = 0; + return 0; } -static int opt_new_stream(const char *opt, const char *arg) +static int read_ffserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename) { - AVFormatContext *oc; - int file_idx = nb_output_files - 1; - if (nb_output_files <= 0) { - fprintf(stderr, "At least one output file must be specified\n"); - exit_program(1); - } - oc = output_files[file_idx]; + int i, err; - AVFormatContext *ic = NULL; ++ AVFormatContext *ic = avformat_alloc_context(); - if (!strcmp(opt, "newvideo" )) new_video_stream (oc, file_idx); - else if (!strcmp(opt, "newaudio" )) new_audio_stream (oc, file_idx); - else if (!strcmp(opt, "newsubtitle")) new_subtitle_stream(oc, file_idx); - else if (!strcmp(opt, "newdata" )) new_data_stream (oc, file_idx); - else av_assert0(0); - return 0; -} ++ ic->interrupt_callback = int_cb; + err = avformat_open_input(&ic, filename, NULL, NULL); + if (err < 0) + return err; + /* copy stream format */ + for(i=0;inb_streams;i++) { + AVStream *st; + OutputStream *ost; + AVCodec *codec; + AVCodecContext *avctx; -/* arg format is "output-stream-index:streamid-value". */ -static int opt_streamid(const char *opt, const char *arg) -{ - int idx; - char *p; - char idx_str[16]; + codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id); + ost = new_output_stream(o, s, codec->type); + st = ost->st; + avctx = st->codec; - av_strlcpy(idx_str, arg, sizeof(idx_str)); - p = strchr(idx_str, ':'); - if (!p) { - fprintf(stderr, - "Invalid value '%s' for option '%s', required syntax is 'index:value'\n", - arg, opt); - exit_program(1); + // FIXME: a more elegant solution is needed + memcpy(st, ic->streams[i], sizeof(AVStream)); + st->info = av_malloc(sizeof(*st->info)); + memcpy(st->info, ic->streams[i]->info, sizeof(*st->info)); + st->codec= avctx; + avcodec_copy_context(st->codec, ic->streams[i]->codec); + + if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && !ost->stream_copy) + choose_sample_fmt(st, codec); + else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && !ost->stream_copy) + choose_pixel_fmt(st, codec); } - *p++ = '\0'; - idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, INT_MAX); - streamid_map = grow_array(streamid_map, sizeof(*streamid_map), &nb_streamid_map, idx+1); - streamid_map[idx] = parse_number_or_die(opt, p, OPT_INT, 0, INT_MAX); + + av_close_input_file(ic); return 0; } @@@ -3902,159 -3715,78 +3906,160 @@@ static void opt_output_file(void *optct if (!strcmp(filename, "-")) filename = "pipe:"; - oc = avformat_alloc_context(); + err = avformat_alloc_output_context2(&oc, NULL, o->format, filename); if (!oc) { - print_error(filename, AVERROR(ENOMEM)); + print_error(filename, err); exit_program(1); } + file_oformat= oc->oformat; ++ oc->interrupt_callback = int_cb; - if (last_asked_format) { - file_oformat = av_guess_format(last_asked_format, NULL, NULL); - if (!file_oformat) { - fprintf(stderr, "Requested output format '%s' is not a suitable output format\n", last_asked_format); + if (!strcmp(file_oformat->name, "ffm") && + av_strstart(filename, "http:", NULL)) { + int j; + /* special case for files sent to ffserver: we get the stream + parameters from ffserver */ + int err = read_ffserver_streams(o, oc, filename); + if (err < 0) { + print_error(filename, err); exit_program(1); } - last_asked_format = NULL; + for(j = nb_output_streams - oc->nb_streams; j < nb_output_streams; j++) { + ost = &output_streams[j]; + for (i = 0; i < nb_input_streams; i++) { + ist = &input_streams[i]; + if(ist->st->codec->codec_type == ost->st->codec->codec_type){ + ost->sync_ist= ist; + ost->source_index= i; + ist->discard = 0; + break; + } + } + } + } else if (!o->nb_stream_maps) { + /* pick the "best" stream of each type */ +#define NEW_STREAM(type, index)\ + if (index >= 0) {\ + ost = new_ ## type ## _stream(o, oc);\ + ost->source_index = index;\ + ost->sync_ist = &input_streams[index];\ + input_streams[index].discard = 0;\ + } + + /* video: highest resolution */ + if (!o->video_disable && oc->oformat->video_codec != CODEC_ID_NONE) { + int area = 0, idx = -1; + for (i = 0; i < nb_input_streams; i++) { + ist = &input_streams[i]; + if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO && + ist->st->codec->width * ist->st->codec->height > area) { + area = ist->st->codec->width * ist->st->codec->height; + idx = i; + } + } + NEW_STREAM(video, idx); + } + + /* audio: most channels */ + if (!o->audio_disable && oc->oformat->audio_codec != CODEC_ID_NONE) { + int channels = 0, idx = -1; + for (i = 0; i < nb_input_streams; i++) { + ist = &input_streams[i]; + if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO && + ist->st->codec->channels > channels) { + channels = ist->st->codec->channels; + idx = i; + } + } + NEW_STREAM(audio, idx); + } + + /* subtitles: pick first */ + if (!o->subtitle_disable && (oc->oformat->subtitle_codec != CODEC_ID_NONE || subtitle_codec_name)) { + for (i = 0; i < nb_input_streams; i++) + if (input_streams[i].st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { + NEW_STREAM(subtitle, i); + break; + } + } + /* do something with data? */ } else { - file_oformat = av_guess_format(NULL, filename, NULL); - if (!file_oformat) { - fprintf(stderr, "Unable to find a suitable output format for '%s'\n", - filename); - exit_program(1); + for (i = 0; i < o->nb_stream_maps; i++) { + StreamMap *map = &o->stream_maps[i]; + + if (map->disabled) + continue; + + ist = &input_streams[input_files[map->file_index].ist_index + map->stream_index]; + if(o->subtitle_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) + continue; + if(o-> audio_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO) + continue; + if(o-> video_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) + continue; + + switch (ist->st->codec->codec_type) { + case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc); break; + case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc); break; + case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream(o, oc); break; + case AVMEDIA_TYPE_DATA: ost = new_data_stream(o, oc); break; + case AVMEDIA_TYPE_ATTACHMENT: ost = new_attachment_stream(o, oc); break; + default: + av_log(NULL, AV_LOG_FATAL, "Cannot map stream #%d:%d - unsupported type.\n", + map->file_index, map->stream_index); + exit_program(1); + } + + ost->source_index = input_files[map->file_index].ist_index + map->stream_index; + ost->sync_ist = &input_streams[input_files[map->sync_file_index].ist_index + + map->sync_stream_index]; + ist->discard = 0; } } - oc->oformat = file_oformat; - av_strlcpy(oc->filename, filename, sizeof(oc->filename)); + /* handle attached files */ + for (i = 0; i < o->nb_attachments; i++) { + AVIOContext *pb; + uint8_t *attachment; + const char *p; + int64_t len; - if ((err = avio_open(&pb, o->attachments[i], AVIO_FLAG_READ)) < 0) { - if (!strcmp(file_oformat->name, "ffm") && - av_strstart(filename, "http:", NULL)) { - /* special case for files sent to avserver: we get the stream - parameters from avserver */ - int err = read_avserver_streams(oc, filename); - if (err < 0) { - print_error(filename, err); ++ if ((err = avio_open2(&pb, o->attachments[i], AVIO_FLAG_READ, &int_cb, NULL)) < 0) { + av_log(NULL, AV_LOG_FATAL, "Could not open attachment file %s.\n", + o->attachments[i]); exit_program(1); } - } else { - use_video = file_oformat->video_codec != CODEC_ID_NONE || video_stream_copy || video_codec_name; - use_audio = file_oformat->audio_codec != CODEC_ID_NONE || audio_stream_copy || audio_codec_name; - use_subtitle = file_oformat->subtitle_codec != CODEC_ID_NONE || subtitle_stream_copy || subtitle_codec_name; - use_data = data_stream_copy || data_codec_name; /* XXX once generic data codec will be available add a ->data_codec reference and use it here */ - - /* disable if no corresponding type found */ - check_inputs(&input_has_video, - &input_has_audio, - &input_has_subtitle, - &input_has_data); - - if (!input_has_video) - use_video = 0; - if (!input_has_audio) - use_audio = 0; - if (!input_has_subtitle) - use_subtitle = 0; - if (!input_has_data) - use_data = 0; - - /* manual disable */ - if (audio_disable) use_audio = 0; - if (video_disable) use_video = 0; - if (subtitle_disable) use_subtitle = 0; - if (data_disable) use_data = 0; - - if (use_video) new_video_stream(oc, nb_output_files); - if (use_audio) new_audio_stream(oc, nb_output_files); - if (use_subtitle) new_subtitle_stream(oc, nb_output_files); - if (use_data) new_data_stream(oc, nb_output_files); - - av_dict_copy(&oc->metadata, metadata, 0); - av_dict_free(&metadata); - } - - av_dict_copy(&output_opts[nb_output_files], format_opts, 0); - output_files[nb_output_files++] = oc; + if ((len = avio_size(pb)) <= 0) { + av_log(NULL, AV_LOG_FATAL, "Could not get size of the attachment %s.\n", + o->attachments[i]); + exit_program(1); + } + if (!(attachment = av_malloc(len))) { + av_log(NULL, AV_LOG_FATAL, "Attachment %s too large to fit into memory.\n", + o->attachments[i]); + exit_program(1); + } + avio_read(pb, attachment, len); + + ost = new_attachment_stream(o, oc); + ost->stream_copy = 0; + ost->source_index = -1; + ost->attachment_filename = o->attachments[i]; + ost->st->codec->extradata = attachment; + ost->st->codec->extradata_size = len; + + p = strrchr(o->attachments[i], '/'); + av_dict_set(&ost->st->metadata, "filename", (p && *p) ? p + 1 : o->attachments[i], AV_DICT_DONT_OVERWRITE); + avio_close(pb); + } + + output_files = grow_array(output_files, sizeof(*output_files), &nb_output_files, nb_output_files + 1); + output_files[nb_output_files - 1].ctx = oc; + output_files[nb_output_files - 1].ost_index = nb_output_streams - oc->nb_streams; + output_files[nb_output_files - 1].recording_time = o->recording_time; + output_files[nb_output_files - 1].start_time = o->start_time; + output_files[nb_output_files - 1].limit_filesize = o->limit_filesize; + av_dict_copy(&output_files[nb_output_files - 1].opts, format_opts, 0); /* check filename in case of an image number is expected */ if (oc->oformat->flags & AVFMT_NEEDNUMBER) { @@@ -4066,10 -3798,28 +4071,12 @@@ if (!(oc->oformat->flags & AVFMT_NOFILE)) { /* test if it already exists to avoid loosing precious files */ - if (!file_overwrite && - (strchr(filename, ':') == NULL || - filename[1] == ':' || - av_strstart(filename, "file:", NULL))) { - if (avio_check(filename, 0) == 0) { - if (!using_stdin) { - fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename); - fflush(stderr); - if (!read_yesno()) { - fprintf(stderr, "Not overwriting - exiting\n"); - exit_program(1); - } - } - else { - fprintf(stderr,"File '%s' already exists. Exiting.\n", filename); - exit_program(1); - } - } - } + assert_file_overwrite(filename); /* open the file */ -- if ((err = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE)) < 0) { ++ if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, ++ &oc->interrupt_callback, ++ &output_files[nb_output_files - 1].opts)) < 0) { print_error(filename, err); exit_program(1); } @@@ -4725,17 -4370,18 +4732,11 @@@ int main(int argc, char **argv av_register_all(); avformat_network_init(); - #if HAVE_ISATTY - if(isatty(STDIN_FILENO)) - avio_set_interrupt_cb(decode_interrupt_cb); - #endif - - show_banner(); - avio_set_interrupt_cb(decode_interrupt_cb); - init_opts(); - - show_banner(); - - av_log(NULL, AV_LOG_WARNING, "This program is not developed anymore and is only " - "provided for compatibility. Use avconv instead " - "(see Changelog for the list of incompatible changes).\n"); + term_init(); /* parse options */ - parse_options(NULL, argc, argv, options, opt_output_file); + parse_options(&o, argc, argv, options, opt_output_file); if(nb_output_files <= 0 && nb_input_files == 0) { show_usage(); diff --cc libavcodec/cinepak.c index fe655248707,9cf38edb8e5..ebdbb5eaece --- a/libavcodec/cinepak.c +++ b/libavcodec/cinepak.c @@@ -359,11 -359,9 +359,11 @@@ static int cinepak_decode (CinepakConte num_strips = FFMIN(num_strips, MAX_STRIPS); + s->frame.key_frame = 0; + for (i=0; i < num_strips; i++) { if ((s->data + 12) > eod) - return -1; + return AVERROR_INVALIDDATA; s->strips[i].id = s->data[0]; s->strips[i].y1 = y0; @@@ -371,12 -369,9 +371,12 @@@ s->strips[i].y2 = y0 + AV_RB16 (&s->data[8]); s->strips[i].x2 = s->avctx->width; + if (s->strips[i].id == 0x10) + s->frame.key_frame = 1; + strip_size = AV_RB24 (&s->data[1]) - 12; - if(strip_size < 0) - return -1; + if (strip_size < 0) + return AVERROR_INVALIDDATA; s->data += 12; strip_size = ((s->data + strip_size) > eod) ? (eod - s->data) : strip_size; @@@ -433,12 -427,12 +433,12 @@@ static int cinepak_decode_frame(AVCodec s->data = buf; s->size = buf_size; - s->frame.reference = 1; + s->frame.reference = 3; s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; - if (avctx->reget_buffer(avctx, &s->frame)) { + if ((ret = avctx->reget_buffer(avctx, &s->frame))) { av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); - return -1; + return ret; } if (s->palette_video) { diff --cc libavformat/applehttp.c index 7c41d9893c5,366d8327ff5..1694096d9ba --- a/libavformat/applehttp.c +++ b/libavformat/applehttp.c @@@ -644,11 -644,11 +644,12 @@@ static int applehttp_read_seek(AVFormat for (i = 0; i < c->n_variants; i++) { /* Reset reading */ struct variant *var = c->variants[i]; - int64_t pos = av_rescale_rnd(c->first_timestamp, 1, stream_index >= 0 ? + int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ? 0 : - av_rescale_rnd(c->first_timestamp, 1, - stream_index >= 0 ? s->streams[stream_index]->time_base.den : AV_TIME_BASE, - flags & AVSEEK_FLAG_BACKWARD ? AV_ROUND_DOWN : AV_ROUND_UP); - if (var->input) { ++ av_rescale_rnd(c->first_timestamp, 1, stream_index >= 0 ? + s->streams[stream_index]->time_base.den : + AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ? + AV_ROUND_DOWN : AV_ROUND_UP); + if (var->input) { ffurl_close(var->input); var->input = NULL; } diff --cc libavformat/avio.c index 879844aefc4,4750a9d5444..b2b39b32d76 --- a/libavformat/avio.c +++ b/libavformat/avio.c @@@ -83,10 -83,13 +83,12 @@@ const AVClass ffurl_context_class = }; /*@}*/ - static int default_interrupt_cb(void); + #if FF_API_OLD_INTERRUPT_CB + static int default_interrupt_cb(void); int (*url_interrupt_cb)(void) = default_interrupt_cb; + #endif -#if FF_API_OLD_AVIO URLProtocol *av_protocol_next(URLProtocol *p) { return ffurl_protocol_next(p); diff --cc libavformat/version.h index 954d87a88e3,d56bdb7c87e..5c7ed6863e0 --- a/libavformat/version.h +++ b/libavformat/version.h @@@ -24,7 -24,7 +24,7 @@@ #include "libavutil/avutil.h" #define LIBAVFORMAT_VERSION_MAJOR 53 - #define LIBAVFORMAT_VERSION_MINOR 20 -#define LIBAVFORMAT_VERSION_MINOR 15 ++#define LIBAVFORMAT_VERSION_MINOR 21 #define LIBAVFORMAT_VERSION_MICRO 0 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ diff --cc tests/lavf-regression.sh index 292845d4e45,4a72e0ac1c4..1c579060cc4 --- a/tests/lavf-regression.sh +++ b/tests/lavf-regression.sh @@@ -71,7 -71,7 +71,7 @@@ do_lavf mxf_d10 "-ar 48000 -ac 2 -r 25 fi if [ -n "$do_ts" ] ; then - do_lavf ts "-ab 64k" -do_lavf ts "-mpegts_transport_stream_id 42" ++do_lavf ts "-ab 64k -mpegts_transport_stream_id 42" fi if [ -n "$do_swf" ] ; then diff --cc tests/ref/lavf/ts index 3b2dad1b5e0,ebe6a77566c..018d61813a3 --- a/tests/ref/lavf/ts +++ b/tests/ref/lavf/ts @@@ -1,3 -1,3 +1,3 @@@ - 151774afed45b19da9b7e83613a1e72b *./tests/data/lavf/lavf.ts -293142d7286db15e5f4d7d1ca0d9c97c *./tests/data/lavf/lavf.ts ++024f0cdd4c51a158b2a38b901d2ed2e5 *./tests/data/lavf/lavf.ts 406644 ./tests/data/lavf/lavf.ts ./tests/data/lavf/lavf.ts CRC=0x133216c1