static void opt_output_file(void *optctx, const char *filename) { OptionsContext *o = optctx; AVFormatContext *oc; int i, err; AVOutputFormat *file_oformat; OutputStream *ost; InputStream *ist; if (!strcmp(filename, "-")) filename = "pipe:"; oc = avformat_alloc_context(); if (!oc) { print_error(filename, AVERROR(ENOMEM)); exit_program(1); } 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); exit_program(1); } last_asked_format = NULL; } 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); } } oc->oformat = file_oformat; av_strlcpy(oc->filename, filename, sizeof(oc->filename)); 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); exit_program(1); } } 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(oc);\ ost->source_index = index;\ ost->sync_ist = &input_streams[index];\ input_streams[index].discard = 0;\ } /* video: highest resolution */ if (!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 (!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 (!subtitle_disable && oc->oformat->subtitle_codec != CODEC_ID_NONE) { 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 { 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]; switch (ist->st->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(oc); break; case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(oc); break; case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream(oc); break; case AVMEDIA_TYPE_DATA: ost = new_data_stream(oc); break; default: av_log(NULL, AV_LOG_ERROR, "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; } } av_dict_copy(&oc->metadata, metadata, 0); av_dict_free(&metadata); 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 = 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) { if (!av_filename_number_test(oc->filename)) { print_error(oc->filename, AVERROR(EINVAL)); exit_program(1); } } 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); } } } /* open the file */ if ((err = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE)) < 0) { print_error(filename, err); exit_program(1); } } oc->preload= (int)(mux_preload*AV_TIME_BASE); oc->max_delay= (int)(mux_max_delay*AV_TIME_BASE); oc->flags |= AVFMT_FLAG_NONBLOCK; /* copy chapters */ if (chapters_input_file >= nb_input_files) { if (chapters_input_file == INT_MAX) { /* copy chapters from the first input file that has them*/ chapters_input_file = -1; for (i = 0; i < nb_input_files; i++) if (input_files[i].ctx->nb_chapters) { chapters_input_file = i; break; } } else { av_log(NULL, AV_LOG_ERROR, "Invalid input file index %d in chapter mapping.\n", chapters_input_file); exit_program(1); } } if (chapters_input_file >= 0) copy_chapters(&input_files[chapters_input_file], &output_files[nb_output_files - 1]); /* copy metadata */ for (i = 0; i < nb_meta_data_maps; i++) { AVFormatContext *files[2]; AVDictionary **meta[2]; int j; #define METADATA_CHECK_INDEX(index, nb_elems, desc)\ if ((index) < 0 || (index) >= (nb_elems)) {\ av_log(NULL, AV_LOG_ERROR, "Invalid %s index %d while processing metadata maps\n",\ (desc), (index));\ exit_program(1);\ } int in_file_index = meta_data_maps[i][1].file; if (in_file_index < 0) continue; METADATA_CHECK_INDEX(in_file_index, nb_input_files, "input file") files[0] = oc; 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; } } av_dict_copy(meta[0], *meta[1], AV_DICT_DONT_OVERWRITE); } /* copy global metadata by default */ if (metadata_global_autocopy && nb_input_files) av_dict_copy(&oc->metadata, input_files[0].ctx->metadata, AV_DICT_DONT_OVERWRITE); if (metadata_streams_autocopy) for (i = output_files[nb_output_files - 1].ost_index; i < nb_output_streams; i++) { InputStream *ist = &input_streams[output_streams[i].source_index]; av_dict_copy(&output_streams[i].st->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE); } frame_rate = (AVRational){0, 0}; frame_width = 0; frame_height = 0; audio_sample_rate = 0; audio_channels = 0; audio_sample_fmt = AV_SAMPLE_FMT_NONE; chapters_input_file = INT_MAX; limit_filesize = UINT64_MAX; av_freep(&meta_data_maps); nb_meta_data_maps = 0; metadata_global_autocopy = 1; metadata_streams_autocopy = 1; metadata_chapters_autocopy = 1; av_freep(&streamid_map); nb_streamid_map = 0; av_dict_free(&codec_names); av_freep(&forced_key_frames); reset_options(o); }