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 (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;
    oc->interrupt_callback = int_cb;
    av_strlcpy(oc->filename, filename, sizeof(oc->filename));
    if (!o->nb_stream_maps) {
#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;\
        }
        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);
        }
        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);
        }
        if (!o->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;
                }
        }
    } 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(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;
        }
    }
    for (i = 0; i < o->nb_attachments; i++) {
        AVIOContext *pb;
        uint8_t *attachment;
        const char *p;
        int64_t len;
        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);
        }
        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);
    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)) {
        assert_file_overwrite(filename);
        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);
        }
    }
    if (o->mux_preload) {
        uint8_t buf[64];
        snprintf(buf, sizeof(buf), "%d", (int)(o->mux_preload*AV_TIME_BASE));
        av_dict_set(&output_files[nb_output_files - 1].opts, "preload", buf, 0);
    }
    oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE);
    oc->flags |= AVFMT_FLAG_NONBLOCK;
    for (i = 0; i < o->nb_metadata_map; i++) {
        char *p;
        int in_file_index = strtol(o->metadata_map[i].u.str, &p, 0);
        if (in_file_index < 0)
            continue;
        if (in_file_index >= nb_input_files) {
            av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d while processing metadata maps\n", in_file_index);
            exit_program(1);
        }
        copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc, input_files[in_file_index].ctx, o);
    }
    if (o->chapters_input_file >= nb_input_files) {
        if (o->chapters_input_file == INT_MAX) {
            o->chapters_input_file = -1;
            for (i = 0; i < nb_input_files; i++)
                if (input_files[i].ctx->nb_chapters) {
                    o->chapters_input_file = i;
                    break;
                }
        } else {
            av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d in chapter mapping.\n",
                   o->chapters_input_file);
            exit_program(1);
        }
    }
    if (o->chapters_input_file >= 0)
        copy_chapters(&input_files[o->chapters_input_file], &output_files[nb_output_files - 1],
                      !o->metadata_chapters_manual);
    if (!o->metadata_global_manual && nb_input_files)
        av_dict_copy(&oc->metadata, input_files[0].ctx->metadata,
                     AV_DICT_DONT_OVERWRITE);
    if (!o->metadata_streams_manual)
        for (i = output_files[nb_output_files - 1].ost_index; i < nb_output_streams; i++) {
            InputStream *ist;
            if (output_streams[i].source_index < 0)
                continue;
            ist = &input_streams[output_streams[i].source_index];
            av_dict_copy(&output_streams[i].st->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE);
        }
    for (i = 0; i < o->nb_metadata; i++) {
        AVDictionary **m;
        char type, *val;
        const char *stream_spec;
        int index = 0, j, ret;
        val = strchr(o->metadata[i].u.str, '=');
        if (!val) {
            av_log(NULL, AV_LOG_FATAL, "No '=' character in metadata string %s.\n",
                   o->metadata[i].u.str);
            exit_program(1);
        }
        *val++ = 0;
        parse_meta_type(o->metadata[i].specifier, &type, &index, &stream_spec);
        if (type == 's') {
            for (j = 0; j < oc->nb_streams; j++) {
                if ((ret = check_stream_specifier(oc, oc->streams[j], stream_spec)) > 0) {
                    av_dict_set(&oc->streams[j]->metadata, o->metadata[i].u.str, *val ? val : NULL, 0);
                } else if (ret < 0)
                    exit_program(1);
            }
            printf("ret %d, stream_spec %s\n", ret, stream_spec);
        }
        else {
            switch (type) {
            case 'g':
                m = &oc->metadata;
                break;
            case 'c':
                if (index < 0 || index >= oc->nb_chapters) {
                    av_log(NULL, AV_LOG_FATAL, "Invalid chapter index %d in metadata specifier.\n", index);
                    exit_program(1);
                }
                m = &oc->chapters[index]->metadata;
                break;
            default:
                av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata[i].specifier);
                exit_program(1);
            }
            av_dict_set(m, o->metadata[i].u.str, *val ? val : NULL, 0);
        }
    }
    reset_options(o);
}
['static void opt_output_file(void *optctx, const char *filename)\n{\n    OptionsContext *o = optctx;\n    AVFormatContext *oc;\n    int i, err;\n    AVOutputFormat *file_oformat;\n    OutputStream *ost;\n    InputStream  *ist;\n    if (!strcmp(filename, "-"))\n        filename = "pipe:";\n    oc = avformat_alloc_context();\n    if (!oc) {\n        print_error(filename, AVERROR(ENOMEM));\n        exit_program(1);\n    }\n    if (o->format) {\n        file_oformat = av_guess_format(o->format, NULL, NULL);\n        if (!file_oformat) {\n            av_log(NULL, AV_LOG_FATAL, "Requested output format \'%s\' is not a suitable output format\\n", o->format);\n            exit_program(1);\n        }\n    } else {\n        file_oformat = av_guess_format(NULL, filename, NULL);\n        if (!file_oformat) {\n            av_log(NULL, AV_LOG_FATAL, "Unable to find a suitable output format for \'%s\'\\n",\n                   filename);\n            exit_program(1);\n        }\n    }\n    oc->oformat = file_oformat;\n    oc->interrupt_callback = int_cb;\n    av_strlcpy(oc->filename, filename, sizeof(oc->filename));\n    if (!o->nb_stream_maps) {\n#define NEW_STREAM(type, index)\\\n        if (index >= 0) {\\\n            ost = new_ ## type ## _stream(o, oc);\\\n            ost->source_index = index;\\\n            ost->sync_ist     = &input_streams[index];\\\n            input_streams[index].discard = 0;\\\n        }\n        if (!o->video_disable && oc->oformat->video_codec != CODEC_ID_NONE) {\n            int area = 0, idx = -1;\n            for (i = 0; i < nb_input_streams; i++) {\n                ist = &input_streams[i];\n                if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&\n                    ist->st->codec->width * ist->st->codec->height > area) {\n                    area = ist->st->codec->width * ist->st->codec->height;\n                    idx = i;\n                }\n            }\n            NEW_STREAM(video, idx);\n        }\n        if (!o->audio_disable && oc->oformat->audio_codec != CODEC_ID_NONE) {\n            int channels = 0, idx = -1;\n            for (i = 0; i < nb_input_streams; i++) {\n                ist = &input_streams[i];\n                if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&\n                    ist->st->codec->channels > channels) {\n                    channels = ist->st->codec->channels;\n                    idx = i;\n                }\n            }\n            NEW_STREAM(audio, idx);\n        }\n        if (!o->subtitle_disable && oc->oformat->subtitle_codec != CODEC_ID_NONE) {\n            for (i = 0; i < nb_input_streams; i++)\n                if (input_streams[i].st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {\n                    NEW_STREAM(subtitle, i);\n                    break;\n                }\n        }\n    } else {\n        for (i = 0; i < o->nb_stream_maps; i++) {\n            StreamMap *map = &o->stream_maps[i];\n            if (map->disabled)\n                continue;\n            ist = &input_streams[input_files[map->file_index].ist_index + map->stream_index];\n            switch (ist->st->codec->codec_type) {\n            case AVMEDIA_TYPE_VIDEO:    ost = new_video_stream(o, oc);    break;\n            case AVMEDIA_TYPE_AUDIO:    ost = new_audio_stream(o, oc);    break;\n            case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream(o, oc); break;\n            case AVMEDIA_TYPE_DATA:     ost = new_data_stream(o, oc);     break;\n            case AVMEDIA_TYPE_ATTACHMENT: ost = new_attachment_stream(o, oc); break;\n            default:\n                av_log(NULL, AV_LOG_FATAL, "Cannot map stream #%d:%d - unsupported type.\\n",\n                       map->file_index, map->stream_index);\n                exit_program(1);\n            }\n            ost->source_index = input_files[map->file_index].ist_index + map->stream_index;\n            ost->sync_ist = &input_streams[input_files[map->sync_file_index].ist_index +\n                                           map->sync_stream_index];\n            ist->discard = 0;\n        }\n    }\n    for (i = 0; i < o->nb_attachments; i++) {\n        AVIOContext *pb;\n        uint8_t *attachment;\n        const char *p;\n        int64_t len;\n        if ((err = avio_open2(&pb, o->attachments[i], AVIO_FLAG_READ, &int_cb, NULL)) < 0) {\n            av_log(NULL, AV_LOG_FATAL, "Could not open attachment file %s.\\n",\n                   o->attachments[i]);\n            exit_program(1);\n        }\n        if ((len = avio_size(pb)) <= 0) {\n            av_log(NULL, AV_LOG_FATAL, "Could not get size of the attachment %s.\\n",\n                   o->attachments[i]);\n            exit_program(1);\n        }\n        if (!(attachment = av_malloc(len))) {\n            av_log(NULL, AV_LOG_FATAL, "Attachment %s too large to fit into memory.\\n",\n                   o->attachments[i]);\n            exit_program(1);\n        }\n        avio_read(pb, attachment, len);\n        ost = new_attachment_stream(o, oc);\n        ost->stream_copy               = 0;\n        ost->source_index              = -1;\n        ost->attachment_filename       = o->attachments[i];\n        ost->st->codec->extradata      = attachment;\n        ost->st->codec->extradata_size = len;\n        p = strrchr(o->attachments[i], \'/\');\n        av_dict_set(&ost->st->metadata, "filename", (p && *p) ? p + 1 : o->attachments[i], AV_DICT_DONT_OVERWRITE);\n        avio_close(pb);\n    }\n    output_files = grow_array(output_files, sizeof(*output_files), &nb_output_files, nb_output_files + 1);\n    output_files[nb_output_files - 1].ctx       = oc;\n    output_files[nb_output_files - 1].ost_index = nb_output_streams - oc->nb_streams;\n    output_files[nb_output_files - 1].recording_time = o->recording_time;\n    output_files[nb_output_files - 1].start_time     = o->start_time;\n    output_files[nb_output_files - 1].limit_filesize = o->limit_filesize;\n    av_dict_copy(&output_files[nb_output_files - 1].opts, format_opts, 0);\n    if (oc->oformat->flags & AVFMT_NEEDNUMBER) {\n        if (!av_filename_number_test(oc->filename)) {\n            print_error(oc->filename, AVERROR(EINVAL));\n            exit_program(1);\n        }\n    }\n    if (!(oc->oformat->flags & AVFMT_NOFILE)) {\n        assert_file_overwrite(filename);\n        if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE,\n                              &oc->interrupt_callback,\n                              &output_files[nb_output_files - 1].opts)) < 0) {\n            print_error(filename, err);\n            exit_program(1);\n        }\n    }\n    if (o->mux_preload) {\n        uint8_t buf[64];\n        snprintf(buf, sizeof(buf), "%d", (int)(o->mux_preload*AV_TIME_BASE));\n        av_dict_set(&output_files[nb_output_files - 1].opts, "preload", buf, 0);\n    }\n    oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE);\n    oc->flags |= AVFMT_FLAG_NONBLOCK;\n    for (i = 0; i < o->nb_metadata_map; i++) {\n        char *p;\n        int in_file_index = strtol(o->metadata_map[i].u.str, &p, 0);\n        if (in_file_index < 0)\n            continue;\n        if (in_file_index >= nb_input_files) {\n            av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d while processing metadata maps\\n", in_file_index);\n            exit_program(1);\n        }\n        copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc, input_files[in_file_index].ctx, o);\n    }\n    if (o->chapters_input_file >= nb_input_files) {\n        if (o->chapters_input_file == INT_MAX) {\n            o->chapters_input_file = -1;\n            for (i = 0; i < nb_input_files; i++)\n                if (input_files[i].ctx->nb_chapters) {\n                    o->chapters_input_file = i;\n                    break;\n                }\n        } else {\n            av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d in chapter mapping.\\n",\n                   o->chapters_input_file);\n            exit_program(1);\n        }\n    }\n    if (o->chapters_input_file >= 0)\n        copy_chapters(&input_files[o->chapters_input_file], &output_files[nb_output_files - 1],\n                      !o->metadata_chapters_manual);\n    if (!o->metadata_global_manual && nb_input_files)\n        av_dict_copy(&oc->metadata, input_files[0].ctx->metadata,\n                     AV_DICT_DONT_OVERWRITE);\n    if (!o->metadata_streams_manual)\n        for (i = output_files[nb_output_files - 1].ost_index; i < nb_output_streams; i++) {\n            InputStream *ist;\n            if (output_streams[i].source_index < 0)\n                continue;\n            ist = &input_streams[output_streams[i].source_index];\n            av_dict_copy(&output_streams[i].st->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE);\n        }\n    for (i = 0; i < o->nb_metadata; i++) {\n        AVDictionary **m;\n        char type, *val;\n        const char *stream_spec;\n        int index = 0, j, ret;\n        val = strchr(o->metadata[i].u.str, \'=\');\n        if (!val) {\n            av_log(NULL, AV_LOG_FATAL, "No \'=\' character in metadata string %s.\\n",\n                   o->metadata[i].u.str);\n            exit_program(1);\n        }\n        *val++ = 0;\n        parse_meta_type(o->metadata[i].specifier, &type, &index, &stream_spec);\n        if (type == \'s\') {\n            for (j = 0; j < oc->nb_streams; j++) {\n                if ((ret = check_stream_specifier(oc, oc->streams[j], stream_spec)) > 0) {\n                    av_dict_set(&oc->streams[j]->metadata, o->metadata[i].u.str, *val ? val : NULL, 0);\n                } else if (ret < 0)\n                    exit_program(1);\n            }\n            printf("ret %d, stream_spec %s\\n", ret, stream_spec);\n        }\n        else {\n            switch (type) {\n            case \'g\':\n                m = &oc->metadata;\n                break;\n            case \'c\':\n                if (index < 0 || index >= oc->nb_chapters) {\n                    av_log(NULL, AV_LOG_FATAL, "Invalid chapter index %d in metadata specifier.\\n", index);\n                    exit_program(1);\n                }\n                m = &oc->chapters[index]->metadata;\n                break;\n            default:\n                av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\\n", o->metadata[i].specifier);\n                exit_program(1);\n            }\n            av_dict_set(m, o->metadata[i].u.str, *val ? val : NULL, 0);\n        }\n    }\n    reset_options(o);\n}', 'AVFormatContext *avformat_alloc_context(void)\n{\n    AVFormatContext *ic;\n    ic = av_malloc(sizeof(AVFormatContext));\n    if (!ic) return ic;\n    avformat_get_context_defaults(ic);\n    return ic;\n}', 'void *av_malloc(size_t size)\n{\n    void *ptr = NULL;\n#if CONFIG_MEMALIGN_HACK\n    long diff;\n#endif\n    if(size > (INT_MAX-32) )\n        return NULL;\n#if CONFIG_MEMALIGN_HACK\n    ptr = malloc(size+32);\n    if(!ptr)\n        return ptr;\n    diff= ((-(long)ptr - 1)&31) + 1;\n    ptr = (char*)ptr + diff;\n    ((char*)ptr)[-1]= diff;\n#elif HAVE_POSIX_MEMALIGN\n    if (posix_memalign(&ptr,32,size))\n        ptr = NULL;\n#elif HAVE_MEMALIGN\n    ptr = memalign(32,size);\n#else\n    ptr = malloc(size);\n#endif\n    return ptr;\n}', 'void print_error(const char *filename, int err)\n{\n    char errbuf[128];\n    const char *errbuf_ptr = errbuf;\n    if (av_strerror(err, errbuf, sizeof(errbuf)) < 0)\n        errbuf_ptr = strerror(AVUNERROR(err));\n    av_log(NULL, AV_LOG_ERROR, "%s: %s\\n", filename, errbuf_ptr);\n}']