static int opt_output_file(const char *opt, const char *filename)

{

    AVFormatContext *oc;

    int i, err;

    AVOutputFormat *file_oformat;

    OutputStream *ost;

    InputStream  *ist;



    if (!strcmp(filename, "-"))

        filename = "pipe:";



    err = avformat_alloc_output_context2(&oc, NULL, last_asked_format, filename);

    last_asked_format = NULL;

    if (!oc) {

        print_error(filename, err);

        exit_program(1);

    }

    file_oformat= oc->oformat;



    if (!strcmp(file_oformat->name, "ffm") &&

        av_strstart(filename, "http:", NULL)) {

        /* special case for files sent to ffserver: we get the stream

           parameters from ffserver */

        int err = read_ffserver_streams(oc, filename);

        if (err < 0) {

            print_error(filename, err);

            exit_program(1);

        }

    } else if (!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 < nb_stream_maps; i++) {

            StreamMap *map = &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);





    if (nb_output_files == MAX_FILES)

        exit_program(1);                /* a temporary hack until all the other MAX_FILES-sized arrays are removed */

    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;

    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);



    if (loop_output >= 0) {

        av_log(NULL, AV_LOG_WARNING, "-loop_output is deprecated, use -loop\n");

        oc->loop_output = loop_output;

    }



    /* 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(chapters_input_file, 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;



    av_freep(&meta_data_maps);

    nb_meta_data_maps = 0;

    metadata_global_autocopy   = 1;

    metadata_streams_autocopy  = 1;

    metadata_chapters_autocopy = 1;

    av_freep(&stream_maps);

    nb_stream_maps = 0;



    av_dict_free(&codec_names);



    av_freep(&forced_key_frames);

    uninit_opts();

    init_opts();

    return 0;

}
