Skip to content
Snippets Groups Projects
ffmpeg_opt.c 144 KiB
Newer Older
  • Learn to ignore specific revisions
  • 
        for (i = 0; i < nb_filtergraphs; i++) {
            ret = init_complex_filtergraph(filtergraphs[i]);
            if (ret < 0)
                return ret;
        }
        return 0;
    }
    
    
    static int configure_complex_filters(void)
    {
    
        int i, j, ret = 0;
    
        for (i = 0; i < nb_filtergraphs; i++) {
            FilterGraph *fg = filtergraphs[i];
    
            if (filtergraph_is_simple(fg))
                continue;
    
            for (j = 0; j < fg->nb_inputs; j++) {
                ret = ifilter_parameters_from_decoder(fg->inputs[j],
                                                      fg->inputs[j]->ist->dec_ctx);
                if (ret < 0) {
                    av_log(NULL, AV_LOG_ERROR,
                           "Error initializing filtergraph %d input %d\n", i, j);
                    return ret;
                }
            }
    
            ret = configure_filtergraph(filtergraphs[i]);
            if (ret < 0)
    
    static int open_output_file(OptionsContext *o, const char *filename)
    
    {
        AVFormatContext *oc;
        int i, j, err;
        AVOutputFormat *file_oformat;
    
        OutputStream *ost;
        InputStream  *ist;
    
        AVDictionary *unused_opts = NULL;
        AVDictionaryEntry *e = NULL;
    
        if (o->stop_time != INT64_MAX && o->recording_time != INT64_MAX) {
            o->stop_time = INT64_MAX;
            av_log(NULL, AV_LOG_WARNING, "-t and -to cannot be used together; using -t.\n");
        }
    
        if (o->stop_time != INT64_MAX && o->recording_time == INT64_MAX) {
    
            int64_t start_time = o->start_time == AV_NOPTS_VALUE ? 0 : o->start_time;
            if (o->stop_time <= start_time) {
    
                av_log(NULL, AV_LOG_ERROR, "-to value smaller than -ss; aborting.\n");
                exit_program(1);
    
                o->recording_time = o->stop_time - start_time;
    
        GROW_ARRAY(output_files, nb_output_files);
        of = av_mallocz(sizeof(*of));
        if (!of)
    
        output_files[nb_output_files - 1] = of;
    
        of->ost_index      = nb_output_streams;
        of->recording_time = o->recording_time;
        of->start_time     = o->start_time;
        of->limit_filesize = o->limit_filesize;
        of->shortest       = o->shortest;
        av_dict_copy(&of->opts, o->g->format_opts, 0);
    
    
        if (!strcmp(filename, "-"))
            filename = "pipe:";
    
    
        err = avformat_alloc_output_context2(&oc, NULL, o->format, filename);
    
            print_error(filename, err);
    
        of->ctx = oc;
        if (o->recording_time != INT64_MAX)
            oc->duration = o->recording_time;
    
        file_oformat= oc->oformat;
    
        oc->interrupt_callback = int_cb;
    
        /* create streams for all unlabeled output pads */
        for (i = 0; i < nb_filtergraphs; i++) {
            FilterGraph *fg = filtergraphs[i];
            for (j = 0; j < fg->nb_outputs; j++) {
                OutputFilter *ofilter = fg->outputs[j];
    
                if (!ofilter->out_tmp || ofilter->out_tmp->name)
                    continue;
    
    
                case AVMEDIA_TYPE_VIDEO:    o->video_disable    = 1; break;
                case AVMEDIA_TYPE_AUDIO:    o->audio_disable    = 1; break;
                case AVMEDIA_TYPE_SUBTITLE: o->subtitle_disable = 1; break;
                }
                init_output_filter(ofilter, o, oc);
            }
        }
    
    
        /* ffserver seeking with date=... needs a date reference */
        if (!strcmp(file_oformat->name, "ffm") &&
            av_strstart(filename, "http:", NULL)) {
            int err = parse_option(o, "metadata", "creation_time=now", options);
            if (err < 0) {
                print_error(filename, err);
                exit_program(1);
            }
        }
    
    
        if (!strcmp(file_oformat->name, "ffm") && !override_ffserver &&
    
            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);
    
            }
            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->codecpar->codec_type == ost->st->codecpar->codec_type){
    
                        ost->sync_ist= ist;
                        ost->source_index= i;
    
                        if(ost->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) ost->avfilter = av_strdup("anull");
                        if(ost->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) ost->avfilter = av_strdup("null");
    
                        ist->st->discard = ist->user_set_discard;
    
                    av_log(NULL, AV_LOG_FATAL, "Missing %s stream which is required by this ffm\n", av_get_media_type_string(ost->st->codecpar->codec_type));
    
        } else if (!o->nb_stream_maps) {
    
            /* pick the "best" stream of each type */
    
    
            /* video: highest resolution */
    
            if (!o->video_disable && av_guess_codec(oc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_VIDEO) != AV_CODEC_ID_NONE) {
    
                int area = 0, idx = -1;
    
                int qcr = avformat_query_codec(oc->oformat, oc->oformat->video_codec, 0);
    
                for (i = 0; i < nb_input_streams; i++) {
    
                    ist = input_streams[i];
    
                    new_area = ist->st->codecpar->width * ist->st->codecpar->height + 100000000*!!ist->st->codec_info_nb_frames;
    
                    if((qcr!=MKTAG('A', 'P', 'I', 'C')) && (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
                        new_area = 1;
    
                    if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
    
                        if((qcr==MKTAG('A', 'P', 'I', 'C')) && !(ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
                            continue;
    
                if (idx >= 0)
                    new_video_stream(o, oc, idx);
    
            if (!o->audio_disable && av_guess_codec(oc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_AUDIO) != AV_CODEC_ID_NONE) {
    
                int best_score = 0, idx = -1;
    
                for (i = 0; i < nb_input_streams; i++) {
    
                    ist = input_streams[i];
    
                    score = ist->st->codecpar->channels + 100000000*!!ist->st->codec_info_nb_frames;
                    if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
    
                        score > best_score) {
                        best_score = score;
    
                if (idx >= 0)
                    new_audio_stream(o, oc, idx);
    
            MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, oc, "s");
    
            if (!o->subtitle_disable && (avcodec_find_encoder(oc->oformat->subtitle_codec) || subtitle_codec_name)) {
    
                for (i = 0; i < nb_input_streams; i++)
    
                    if (input_streams[i]->st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
    
                            avcodec_descriptor_get(input_streams[i]->st->codecpar->codec_id);
    
                        AVCodecDescriptor const *output_descriptor = NULL;
                        AVCodec const *output_codec =
                            avcodec_find_encoder(oc->oformat->subtitle_codec);
                        int input_props = 0, output_props = 0;
                        if (output_codec)
                            output_descriptor = avcodec_descriptor_get(output_codec->id);
                        if (input_descriptor)
                            input_props = input_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);
                        if (output_descriptor)
                            output_props = output_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);
                        if (subtitle_codec_name ||
                            input_props & output_props ||
                            // Map dvb teletext which has neither property to any output subtitle encoder
                            input_descriptor && output_descriptor &&
                            (!input_descriptor->props ||
                             !output_descriptor->props)) {
                            new_subtitle_stream(o, oc, i);
                            break;
                        }
    
            /* Data only if codec id match */
            if (!o->data_disable ) {
                enum AVCodecID codec_id = av_guess_codec(oc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_DATA);
                for (i = 0; codec_id != AV_CODEC_ID_NONE && i < nb_input_streams; i++) {
    
                    if (input_streams[i]->st->codecpar->codec_type == AVMEDIA_TYPE_DATA
                        && input_streams[i]->st->codecpar->codec_id == codec_id )
    
        } else {
            for (i = 0; i < o->nb_stream_maps; i++) {
                StreamMap *map = &o->stream_maps[i];
    
                if (map->disabled)
                    continue;
    
                if (map->linklabel) {
                    FilterGraph *fg;
                    OutputFilter *ofilter = NULL;
                    int j, k;
    
                    for (j = 0; j < nb_filtergraphs; j++) {
                        fg = filtergraphs[j];
                        for (k = 0; k < fg->nb_outputs; k++) {
                            AVFilterInOut *out = fg->outputs[k]->out_tmp;
                            if (out && !strcmp(out->name, map->linklabel)) {
                                ofilter = fg->outputs[k];
                                goto loop_end;
                            }
                        }
                    }
    loop_end:
                    if (!ofilter) {
                        av_log(NULL, AV_LOG_FATAL, "Output with label '%s' does not exist "
    
                               "in any defined filter graph, or was already used elsewhere.\n", map->linklabel);
    
                    }
                    init_output_filter(ofilter, o, oc);
                } else {
    
                    int src_idx = input_files[map->file_index]->ist_index + map->stream_index;
    
    
                    ist = input_streams[input_files[map->file_index]->ist_index + map->stream_index];
    
                    if(o->subtitle_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)
    
                    if(o->   audio_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
    
                    if(o->   video_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
    
                    if(o->    data_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_DATA)
    
                    ost = NULL;
    
                    switch (ist->st->codecpar->codec_type) {
    
                    case AVMEDIA_TYPE_VIDEO:      ost = new_video_stream     (o, oc, src_idx); break;
                    case AVMEDIA_TYPE_AUDIO:      ost = new_audio_stream     (o, oc, src_idx); break;
                    case AVMEDIA_TYPE_SUBTITLE:   ost = new_subtitle_stream  (o, oc, src_idx); break;
                    case AVMEDIA_TYPE_DATA:       ost = new_data_stream      (o, oc, src_idx); break;
                    case AVMEDIA_TYPE_ATTACHMENT: ost = new_attachment_stream(o, oc, src_idx); break;
    
                    case AVMEDIA_TYPE_UNKNOWN:
                        if (copy_unknown_streams) {
                            ost = new_unknown_stream   (o, oc, src_idx);
                            break;
                        }
    
                        av_log(NULL, ignore_unknown_streams ? AV_LOG_WARNING : AV_LOG_FATAL,
    
                               "Cannot map stream #%d:%d - unsupported type.\n",
    
                               map->file_index, map->stream_index);
    
                        if (!ignore_unknown_streams) {
                            av_log(NULL, AV_LOG_FATAL,
    
                                   "If you want unsupported types ignored instead "
    
                                   "of failing, please use the -ignore_unknown option\n"
                                   "If you want them copied, please use -copy_unknown\n");
    
                    if (ost)
                        ost->sync_ist = input_streams[  input_files[map->sync_file_index]->ist_index
                                                      + map->sync_stream_index];
    
                }
            }
        }
    
        /* 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_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]);
    
            }
            if ((len = avio_size(pb)) <= 0) {
                av_log(NULL, AV_LOG_FATAL, "Could not get size of the attachment %s.\n",
                       o->attachments[i]);
    
            }
            if (!(attachment = av_malloc(len))) {
                av_log(NULL, AV_LOG_FATAL, "Attachment %s too large to fit into memory.\n",
                       o->attachments[i]);
    
            }
            avio_read(pb, attachment, len);
    
    
            ost = new_attachment_stream(o, oc, -1);
    
            ost->stream_copy               = 0;
    
            ost->attachment_filename       = o->attachments[i];
    
            ost->st->codecpar->extradata      = attachment;
            ost->st->codecpar->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);
    
    #if FF_API_LAVF_AVCTX
    
        for (i = nb_output_streams - oc->nb_streams; i < nb_output_streams; i++) { //for all streams of this output file
            AVDictionaryEntry *e;
            ost = output_streams[i];
    
    
            if ((ost->stream_copy || ost->attachment_filename)
    
                && (e = av_dict_get(o->g->codec_opts, "flags", NULL, AV_DICT_IGNORE_SUFFIX))
                && (!e->key[5] || check_stream_specifier(oc, ost->st, e->key+6)))
                if (av_opt_set(ost->st->codec, "flags", e->value, 0) < 0)
    
        if (!oc->nb_streams && !(oc->oformat->flags & AVFMT_NOSTREAMS)) {
            av_dump_format(oc, nb_output_files - 1, oc->filename, 1);
            av_log(NULL, AV_LOG_ERROR, "Output file #%d does not contain any stream\n", nb_output_files - 1);
            exit_program(1);
        }
    
    
        /* check if all codec options have been used */
        unused_opts = strip_specifiers(o->g->codec_opts);
        for (i = of->ost_index; i < nb_output_streams; i++) {
            e = NULL;
    
            while ((e = av_dict_get(output_streams[i]->encoder_opts, "", e,
    
                                    AV_DICT_IGNORE_SUFFIX)))
                av_dict_set(&unused_opts, e->key, NULL, 0);
        }
    
        e = NULL;
        while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
            const AVClass *class = avcodec_get_class();
            const AVOption *option = av_opt_find(&class, e->key, NULL, 0,
                                                 AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
    
            const AVClass *fclass = avformat_get_class();
            const AVOption *foption = av_opt_find(&fclass, e->key, NULL, 0,
                                                  AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
            if (!option || foption)
    
            if (!(option->flags & AV_OPT_FLAG_ENCODING_PARAM)) {
                av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for "
                       "output file #%d (%s) is not an encoding option.\n", e->key,
                       option->help ? option->help : "", nb_output_files - 1,
                       filename);
    
            // gop_timecode is injected by generic code but not always used
            if (!strcmp(e->key, "gop_timecode"))
                continue;
    
    
            av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
                   "output file #%d (%s) has not been used for any stream. The most "
                   "likely reason is either wrong type (e.g. a video option with "
                   "no video streams) or that it is a private option of some encoder "
                   "which was not actually used for any stream.\n", e->key,
                   option->help ? option->help : "", nb_output_files - 1, filename);
        }
        av_dict_free(&unused_opts);
    
    
        /* set the decoding_needed flags and create simple filtergraphs */
    
        for (i = of->ost_index; i < nb_output_streams; i++) {
            OutputStream *ost = output_streams[i];
    
            if (ost->encoding_needed && ost->source_index >= 0) {
                InputStream *ist = input_streams[ost->source_index];
    
                ist->decoding_needed |= DECODING_FOR_OST;
    
                if (ost->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
                    ost->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
    
                    err = init_simple_filtergraph(ist, ost);
                    if (err < 0) {
                        av_log(NULL, AV_LOG_ERROR,
                               "Error initializing a simple filtergraph between streams "
                               "%d:%d->%d:%d\n", ist->file_index, ost->source_index,
                               nb_output_files - 1, ost->st->index);
                        exit_program(1);
                    }
                }
    
            /* set the filter output constraints */
            if (ost->filter) {
                OutputFilter *f = ost->filter;
                int count;
                switch (ost->enc_ctx->codec_type) {
                case AVMEDIA_TYPE_VIDEO:
                    f->frame_rate = ost->frame_rate;
                    f->width      = ost->enc_ctx->width;
                    f->height     = ost->enc_ctx->height;
                    if (ost->enc_ctx->pix_fmt != AV_PIX_FMT_NONE) {
                        f->format = ost->enc_ctx->pix_fmt;
                    } else if (ost->enc->pix_fmts) {
                        count = 0;
                        while (ost->enc->pix_fmts[count] != AV_PIX_FMT_NONE)
                            count++;
                        f->formats = av_mallocz_array(count + 1, sizeof(*f->formats));
                        if (!f->formats)
                            exit_program(1);
                        memcpy(f->formats, ost->enc->pix_fmts, (count + 1) * sizeof(*f->formats));
                    }
                    break;
                case AVMEDIA_TYPE_AUDIO:
                    if (ost->enc_ctx->sample_fmt != AV_SAMPLE_FMT_NONE) {
                        f->format = ost->enc_ctx->sample_fmt;
                    } else if (ost->enc->sample_fmts) {
                        count = 0;
                        while (ost->enc->sample_fmts[count] != AV_SAMPLE_FMT_NONE)
                            count++;
                        f->formats = av_mallocz_array(count + 1, sizeof(*f->formats));
                        if (!f->formats)
                            exit_program(1);
                        memcpy(f->formats, ost->enc->sample_fmts, (count + 1) * sizeof(*f->formats));
                    }
                    if (ost->enc_ctx->sample_rate) {
                        f->sample_rate = ost->enc_ctx->sample_rate;
                    } else if (ost->enc->supported_samplerates) {
                        count = 0;
                        while (ost->enc->supported_samplerates[count])
                            count++;
                        f->sample_rates = av_mallocz_array(count + 1, sizeof(*f->sample_rates));
                        if (!f->sample_rates)
                            exit_program(1);
                        memcpy(f->sample_rates, ost->enc->supported_samplerates,
                               (count + 1) * sizeof(*f->sample_rates));
                    }
                    if (ost->enc_ctx->channels) {
                        f->channel_layout = av_get_default_channel_layout(ost->enc_ctx->channels);
                    } else if (ost->enc->channel_layouts) {
                        count = 0;
                        while (ost->enc->channel_layouts[count])
                            count++;
                        f->channel_layouts = av_mallocz_array(count + 1, sizeof(*f->channel_layouts));
                        if (!f->channel_layouts)
                            exit_program(1);
                        memcpy(f->channel_layouts, ost->enc->channel_layouts,
                               (count + 1) * sizeof(*f->channel_layouts));
                    }
                    break;
                }
            }
    
        /* 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));
    
        if (!(oc->oformat->flags & AVFMT_NOSTREAMS) && !input_stream_potentially_available) {
            av_log(NULL, AV_LOG_ERROR,
                   "No input streams but output needs an input stream\n");
            exit_program(1);
        }
    
    
        if (!(oc->oformat->flags & AVFMT_NOFILE)) {
            /* test if it already exists to avoid losing precious files */
            assert_file_overwrite(filename);
    
            /* open the file */
            if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE,
                                  &oc->interrupt_callback,
    
                print_error(filename, err);
    
        } else if (strcmp(oc->oformat->name, "image2")==0 && !av_filename_number_test(filename))
            assert_file_overwrite(filename);
    
            av_dict_set_int(&of->opts, "preload", o->mux_preload*AV_TIME_BASE, 0);
    
        }
        oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE);
    
        /* copy metadata */
        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 >= nb_input_files) {
                av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d while processing metadata maps\n", in_file_index);
    
            copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc,
                          in_file_index >= 0 ?
                          input_files[in_file_index]->ctx : NULL, o);
    
        }
    
        /* copy chapters */
        if (o->chapters_input_file >= nb_input_files) {
            if (o->chapters_input_file == INT_MAX) {
                /* copy chapters from the first input file that has them*/
                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);
    
            }
        }
        if (o->chapters_input_file >= 0)
    
            copy_chapters(input_files[o->chapters_input_file], of,
    
                          !o->metadata_chapters_manual);
    
        /* copy global metadata by default */
    
        if (!o->metadata_global_manual && nb_input_files){
    
            av_dict_copy(&oc->metadata, input_files[0]->ctx->metadata,
                         AV_DICT_DONT_OVERWRITE);
    
            if(o->recording_time != INT64_MAX)
                av_dict_set(&oc->metadata, "duration", NULL, 0);
            av_dict_set(&oc->metadata, "creation_time", NULL, 0);
        }
    
        if (!o->metadata_streams_manual)
    
            for (i = of->ost_index; i < nb_output_streams; i++) {
    
                InputStream *ist;
                if (output_streams[i]->source_index < 0)         /* this is true e.g. for attached files */
                    continue;
                ist = input_streams[output_streams[i]->source_index];
                av_dict_copy(&output_streams[i]->st->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE);
    
                if (!output_streams[i]->stream_copy) {
    
                    av_dict_set(&output_streams[i]->st->metadata, "encoder", NULL, 0);
    
                    if (ist->autorotate)
                        av_dict_set(&output_streams[i]->st->metadata, "rotate", NULL, 0);
                }
    
        /* process manually set programs */
        for (i = 0; i < o->nb_program; i++) {
            const char *p = o->program[i].u.str;
            int progid = i+1;
            AVProgram *program;
    
            while(*p) {
                const char *p2 = av_get_token(&p, ":");
    
                if (!key || !*p2) {
                    av_freep(&to_dealloc);
                    av_freep(&key);
    
                p2++;
    
                if (!strcmp(key, "program_num"))
                    progid = strtol(p2, NULL, 0);
    
                av_freep(&to_dealloc);
                av_freep(&key);
    
            }
    
            program = av_new_program(oc, progid);
    
            p = o->program[i].u.str;
            while(*p) {
                const char *p2 = av_get_token(&p, ":");
    
                char *key;
                if (!p2)
                    break;
                if(*p) p++;
    
                key = av_get_token(&p2, "=");
                if (!key) {
                    av_log(NULL, AV_LOG_FATAL,
                           "No '=' character in program string %s.\n",
                           p2);
                    exit_program(1);
                }
                if (!*p2)
                    exit_program(1);
                p2++;
    
                if (!strcmp(key, "title")) {
                    av_dict_set(&program->metadata, "title", p2, 0);
                } else if (!strcmp(key, "program_num")) {
                } else if (!strcmp(key, "st")) {
                    int st_num = strtol(p2, NULL, 0);
                    av_program_add_stream_index(oc, progid, st_num);
                } else {
                    av_log(NULL, AV_LOG_FATAL, "Unknown program key %s.\n", key);
                    exit_program(1);
                }
    
                av_freep(&to_dealloc);
                av_freep(&key);
    
        /* process manually set metadata */
        for (i = 0; i < o->nb_metadata; i++) {
            AVDictionary **m;
            char type, *val;
            const char *stream_spec;
    
            int index = 0, j, ret = 0;
    
    
            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);
    
            }
            *val++ = 0;
    
            parse_meta_type(o->metadata[i].specifier, &type, &index, &stream_spec);
            if (type == 's') {
                for (j = 0; j < oc->nb_streams; j++) {
    
                    ost = output_streams[nb_output_streams - 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);
    
                        if (!strcmp(o->metadata[i].u.str, "rotate")) {
                            ost->rotate_overridden = 1;
                        }
    
                }
            }
            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);
    
                    }
                    m = &oc->chapters[index]->metadata;
                    break;
    
                case 'p':
                    if (index < 0 || index >= oc->nb_programs) {
                        av_log(NULL, AV_LOG_FATAL, "Invalid program index %d in metadata specifier.\n", index);
                        exit_program(1);
                    }
                    m = &oc->programs[index]->metadata;
                    break;
    
                default:
                    av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata[i].specifier);
    
                }
                av_dict_set(m, o->metadata[i].u.str, *val ? val : NULL, 0);
            }
        }
    
    
        return 0;
    
    static int opt_target(void *optctx, const char *opt, const char *arg)
    
        OptionsContext *o = optctx;
    
        enum { PAL, NTSC, FILM, UNKNOWN } norm = UNKNOWN;
        static const char *const frame_rates[] = { "25", "30000/1001", "24000/1001" };
    
        if (!strncmp(arg, "pal-", 4)) {
            norm = PAL;
            arg += 4;
        } else if (!strncmp(arg, "ntsc-", 5)) {
            norm = NTSC;
            arg += 5;
        } else if (!strncmp(arg, "film-", 5)) {
            norm = FILM;
            arg += 5;
        } else {
            /* Try to determine PAL/NTSC by peeking in the input files */
            if (nb_input_files) {
                int i, j, fr;
                for (j = 0; j < nb_input_files; j++) {
                    for (i = 0; i < input_files[j]->nb_streams; i++) {
    
                        AVStream *st = input_files[j]->ctx->streams[i];
                        if (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)
    
                        fr = st->time_base.den * 1000 / st->time_base.num;
    
                        if (fr == 25000) {
                            norm = PAL;
                            break;
                        } else if ((fr == 29970) || (fr == 23976)) {
                            norm = NTSC;
                            break;
                        }
                    }
                    if (norm != UNKNOWN)
                        break;
                }
            }
            if (norm != UNKNOWN)
                av_log(NULL, AV_LOG_INFO, "Assuming %s for target.\n", norm == PAL ? "PAL" : "NTSC");
        }
    
        if (norm == UNKNOWN) {
            av_log(NULL, AV_LOG_FATAL, "Could not determine norm (PAL/NTSC/NTSC-Film) for target.\n");
            av_log(NULL, AV_LOG_FATAL, "Please prefix target with \"pal-\", \"ntsc-\" or \"film-\",\n");
            av_log(NULL, AV_LOG_FATAL, "or set a framerate with \"-r xxx\".\n");
    
        }
    
        if (!strcmp(arg, "vcd")) {
            opt_video_codec(o, "c:v", "mpeg1video");
            opt_audio_codec(o, "c:a", "mp2");
            parse_option(o, "f", "vcd", options);
    
            parse_option(o, "s", norm == PAL ? "352x288" : "352x240", options);
            parse_option(o, "r", frame_rates[norm], options);
    
            opt_default(NULL, "g", norm == PAL ? "15" : "18");
    
            opt_default(NULL, "b:v", "1150000");
    
            opt_default(NULL, "maxrate:v", "1150000");
            opt_default(NULL, "minrate:v", "1150000");
            opt_default(NULL, "bufsize:v", "327680"); // 40*1024*8;
    
            opt_default(NULL, "b:a", "224000");
    
            parse_option(o, "ar", "44100", options);
            parse_option(o, "ac", "2", options);
    
    
            opt_default(NULL, "packetsize", "2324");
            opt_default(NULL, "muxrate", "1411200"); // 2352 * 75 * 8;
    
    
            /* We have to offset the PTS, so that it is consistent with the SCR.
               SCR starts at 36000, but the first two packs contain only padding
               and the first pack from the other stream, respectively, may also have
               been written before.
               So the real data starts at SCR 36000+3*1200. */
            o->mux_preload = (36000 + 3 * 1200) / 90000.0; // 0.44
        } else if (!strcmp(arg, "svcd")) {
    
            opt_video_codec(o, "c:v", "mpeg2video");
            opt_audio_codec(o, "c:a", "mp2");
            parse_option(o, "f", "svcd", options);
    
            parse_option(o, "s", norm == PAL ? "480x576" : "480x480", options);
            parse_option(o, "r", frame_rates[norm], options);
    
            parse_option(o, "pix_fmt", "yuv420p", options);
    
            opt_default(NULL, "g", norm == PAL ? "15" : "18");
    
            opt_default(NULL, "b:v", "2040000");
    
            opt_default(NULL, "maxrate:v", "2516000");
            opt_default(NULL, "minrate:v", "0"); // 1145000;
            opt_default(NULL, "bufsize:v", "1835008"); // 224*1024*8;
    
            opt_default(NULL, "scan_offset", "1");
    
            opt_default(NULL, "b:a", "224000");
    
            parse_option(o, "ar", "44100", options);
    
    
            opt_default(NULL, "packetsize", "2324");
    
    
        } else if (!strcmp(arg, "dvd")) {
    
            opt_video_codec(o, "c:v", "mpeg2video");
            opt_audio_codec(o, "c:a", "ac3");
            parse_option(o, "f", "dvd", options);
    
            parse_option(o, "s", norm == PAL ? "720x576" : "720x480", options);
            parse_option(o, "r", frame_rates[norm], options);
    
            parse_option(o, "pix_fmt", "yuv420p", options);
    
            opt_default(NULL, "g", norm == PAL ? "15" : "18");
    
            opt_default(NULL, "b:v", "6000000");
    
            opt_default(NULL, "maxrate:v", "9000000");
            opt_default(NULL, "minrate:v", "0"); // 1500000;
            opt_default(NULL, "bufsize:v", "1835008"); // 224*1024*8;
    
            opt_default(NULL, "packetsize", "2048");  // from www.mpucoder.com: DVD sectors contain 2048 bytes of data, this is also the size of one pack.
            opt_default(NULL, "muxrate", "10080000"); // from mplex project: data_rate = 1260000. mux_rate = data_rate * 8
    
            opt_default(NULL, "b:a", "448000");
    
            parse_option(o, "ar", "48000", options);
    
        } else if (!strncmp(arg, "dv", 2)) {
    
            parse_option(o, "f", "dv", options);
    
            parse_option(o, "s", norm == PAL ? "720x576" : "720x480", options);
            parse_option(o, "pix_fmt", !strncmp(arg, "dv50", 4) ? "yuv422p" :
                              norm == PAL ? "yuv420p" : "yuv411p", options);
            parse_option(o, "r", frame_rates[norm], options);
    
            parse_option(o, "ar", "48000", options);
            parse_option(o, "ac", "2", options);
    
        } else {
            av_log(NULL, AV_LOG_ERROR, "Unknown target: %s\n", arg);
            return AVERROR(EINVAL);
        }
    
        av_dict_copy(&o->g->codec_opts,  codec_opts, AV_DICT_DONT_OVERWRITE);
        av_dict_copy(&o->g->format_opts, format_opts, AV_DICT_DONT_OVERWRITE);
    
    static int opt_vstats_file(void *optctx, const char *opt, const char *arg)
    
    {
        av_free (vstats_filename);
        vstats_filename = av_strdup (arg);
        return 0;
    }
    
    
    static int opt_vstats(void *optctx, const char *opt, const char *arg)
    
    {
        char filename[40];
        time_t today2 = time(NULL);
        struct tm *today = localtime(&today2);
    
    
        if (!today) { // maybe tomorrow
    
            av_log(NULL, AV_LOG_FATAL, "Unable to get current time: %s\n", strerror(errno));
    
        snprintf(filename, sizeof(filename), "vstats_%02d%02d%02d.log", today->tm_hour, today->tm_min,
                 today->tm_sec);
    
        return opt_vstats_file(NULL, opt, filename);
    
    static int opt_video_frames(void *optctx, const char *opt, const char *arg)
    
        OptionsContext *o = optctx;
    
        return parse_option(o, "frames:v", arg, options);
    }
    
    
    static int opt_audio_frames(void *optctx, const char *opt, const char *arg)
    
        OptionsContext *o = optctx;
    
        return parse_option(o, "frames:a", arg, options);
    }
    
    
    static int opt_data_frames(void *optctx, const char *opt, const char *arg)
    
        OptionsContext *o = optctx;
    
        return parse_option(o, "frames:d", arg, options);
    }
    
    
    static int opt_default_new(OptionsContext *o, const char *opt, const char *arg)
    {
        int ret;
    
        AVDictionary *cbak = codec_opts;
        AVDictionary *fbak = format_opts;
    
        codec_opts = NULL;
        format_opts = NULL;
    
        ret = opt_default(NULL, opt, arg);
    
        av_dict_copy(&o->g->codec_opts , codec_opts, 0);
        av_dict_copy(&o->g->format_opts, format_opts, 0);
        av_dict_free(&codec_opts);
        av_dict_free(&format_opts);
        codec_opts = cbak;
        format_opts = fbak;
    
        return ret;
    }
    
    
    static int opt_preset(void *optctx, const char *opt, const char *arg)
    
        OptionsContext *o = optctx;
    
        FILE *f=NULL;
        char filename[1000], line[1000], tmp_line[1000];
    
        const char *codec_name = NULL;
    
        tmp_line[0] = *opt;
        tmp_line[1] = 0;
        MATCH_PER_TYPE_OPT(codec_names, str, codec_name, NULL, tmp_line);
    
    
        if (!(f = get_preset_file(filename, sizeof(filename), arg, *opt == 'f', codec_name))) {
            if(!strncmp(arg, "libx264-lossless", strlen("libx264-lossless"))){
                av_log(NULL, AV_LOG_FATAL, "Please use -preset <speed> -qp 0\n");
            }else
                av_log(NULL, AV_LOG_FATAL, "File for preset '%s' not found\n", arg);
    
    
        while (fgets(line, sizeof(line), f)) {
            char *key = tmp_line, *value, *endptr;
    
            if (strcspn(line, "#\n\r") == 0)
                continue;
    
            av_strlcpy(tmp_line, line, sizeof(tmp_line));
    
            if (!av_strtok(key,   "=",    &value) ||
                !av_strtok(value, "\r\n", &endptr)) {
                av_log(NULL, AV_LOG_FATAL, "%s: Invalid syntax: '%s'\n", filename, line);
    
            }
            av_log(NULL, AV_LOG_DEBUG, "ffpreset[%s]: set '%s' = '%s'\n", filename, key, value);
    
            if      (!strcmp(key, "acodec")) opt_audio_codec   (o, key, value);
            else if (!strcmp(key, "vcodec")) opt_video_codec   (o, key, value);
            else if (!strcmp(key, "scodec")) opt_subtitle_codec(o, key, value);
            else if (!strcmp(key, "dcodec")) opt_data_codec    (o, key, value);
    
            else if (opt_default_new(o, key, value) < 0) {
    
                av_log(NULL, AV_LOG_FATAL, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n",
                       filename, line, key, value);
    
    static int opt_old2new(void *optctx, const char *opt, const char *arg)
    
        OptionsContext *o = optctx;
    
        char *s = av_asprintf("%s:%c", opt + 1, *opt);
        int ret = parse_option(o, s, arg, options);
        av_free(s);
        return ret;
    
    static int opt_bitrate(void *optctx, const char *opt, const char *arg)
    
        OptionsContext *o = optctx;
    
    
        if(!strcmp(opt, "ab")){
            av_dict_set(&o->g->codec_opts, "b:a", arg, 0);
            return 0;
        } else if(!strcmp(opt, "b")){
    
            av_log(NULL, AV_LOG_WARNING, "Please use -b:a or -b:v, -b is ambiguous\n");
    
            av_dict_set(&o->g->codec_opts, "b:v", arg, 0);
            return 0;
    
        av_dict_set(&o->g->codec_opts, opt, arg, 0);
        return 0;
    
    static int opt_qscale(void *optctx, const char *opt, const char *arg)
    
        OptionsContext *o = optctx;
    
        char *s;
        int ret;
        if(!strcmp(opt, "qscale")){
            av_log(NULL, AV_LOG_WARNING, "Please use -q:a or -q:v, -qscale is ambiguous\n");
            return parse_option(o, "q:v", arg, options);
        }
        s = av_asprintf("q%s", opt + 6);
        ret = parse_option(o, s, arg, options);
        av_free(s);
        return ret;
    }
    
    
    static int opt_profile(void *optctx, const char *opt, const char *arg)
    
        OptionsContext *o = optctx;
    
        if(!strcmp(opt, "profile")){
            av_log(NULL, AV_LOG_WARNING, "Please use -profile:a or -profile:v, -profile is ambiguous\n");
    
            av_dict_set(&o->g->codec_opts, "profile:v", arg, 0);
            return 0;
    
        av_dict_set(&o->g->codec_opts, opt, arg, 0);
        return 0;
    
    static int opt_video_filters(void *optctx, const char *opt, const char *arg)
    
        OptionsContext *o = optctx;