X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=avconv_opt.c;h=16254299e227d2d4e5035ede67054e047a93fc9b;hb=453642f8afe9f979fcc813a246b1ec656ec36a93;hp=70cbd719cd7b263e859749d35613cee7348733ae;hpb=f825d42bccdb9f89669a586951de7f66a81e80a5;p=ffmpeg diff --git a/avconv_opt.c b/avconv_opt.c index 70cbd719cd7..16254299e22 100644 --- a/avconv_opt.c +++ b/avconv_opt.c @@ -53,6 +53,19 @@ }\ } +const HWAccel hwaccels[] = { +#if HAVE_VDPAU_X11 + { "vdpau", vdpau_init, HWACCEL_VDPAU, AV_PIX_FMT_VDPAU }, +#endif +#if HAVE_DXVA2_LIB + { "dxva2", dxva2_init, HWACCEL_DXVA2, AV_PIX_FMT_DXVA2_VLD }, +#endif +#if CONFIG_VDA + { "vda", vda_init, HWACCEL_VDA, AV_PIX_FMT_VDA }, +#endif + { 0 }, +}; + char *vstats_filename; float audio_drift_threshold = 0.1; @@ -200,6 +213,8 @@ static int opt_map(void *optctx, const char *opt, const char *arg) arg++; } map = av_strdup(arg); + if (!map) + return AVERROR(ENOMEM); /* parse sync stream first, just pick first matching stream */ if (sync = strchr(map, ',')) { @@ -449,13 +464,15 @@ static AVCodec *choose_decoder(OptionsContext *o, AVFormatContext *s, AVStream * * list of input streams. */ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) { - int i; + int i, ret; for (i = 0; i < ic->nb_streams; i++) { AVStream *st = ic->streams[i]; AVCodecContext *dec = st->codec; InputStream *ist = av_mallocz(sizeof(*ist)); - char *framerate = NULL; + char *framerate = NULL, *hwaccel = NULL, *hwaccel_device = NULL; + char *codec_tag = NULL; + char *next; if (!ist) exit_program(1); @@ -471,14 +488,34 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) 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); - ist->opts = filter_codec_opts(o->g->codec_opts, ist->st->codec->codec_id, ic, st, ist->dec); + ist->decoder_opts = filter_codec_opts(o->g->codec_opts, ist->st->codec->codec_id, ic, st, ist->dec); + + ist->dec_ctx = avcodec_alloc_context3(ist->dec); + if (!ist->dec_ctx) { + av_log(NULL, AV_LOG_ERROR, "Error allocating the decoder context.\n"); + exit_program(1); + } + + ret = avcodec_copy_context(ist->dec_ctx, dec); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Error initializing the decoder context.\n"); + exit_program(1); + } switch (dec->codec_type) { case AVMEDIA_TYPE_VIDEO: - ist->resample_height = dec->height; - ist->resample_width = dec->width; - ist->resample_pix_fmt = dec->pix_fmt; + ist->resample_height = ist->dec_ctx->height; + ist->resample_width = ist->dec_ctx->width; + ist->resample_pix_fmt = ist->dec_ctx->pix_fmt; MATCH_PER_STREAM_OPT(frame_rates, str, framerate, ic, st); if (framerate && av_parse_video_rate(&ist->framerate, @@ -488,14 +525,49 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) exit_program(1); } + MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st); + if (hwaccel) { + if (!strcmp(hwaccel, "none")) + ist->hwaccel_id = HWACCEL_NONE; + else if (!strcmp(hwaccel, "auto")) + ist->hwaccel_id = HWACCEL_AUTO; + else { + int i; + for (i = 0; hwaccels[i].name; i++) { + if (!strcmp(hwaccels[i].name, hwaccel)) { + ist->hwaccel_id = hwaccels[i].id; + break; + } + } + + if (!ist->hwaccel_id) { + av_log(NULL, AV_LOG_FATAL, "Unrecognized hwaccel: %s.\n", + hwaccel); + av_log(NULL, AV_LOG_FATAL, "Supported hwaccels: "); + for (i = 0; hwaccels[i].name; i++) + av_log(NULL, AV_LOG_FATAL, "%s ", hwaccels[i].name); + av_log(NULL, AV_LOG_FATAL, "\n"); + exit_program(1); + } + } + } + + MATCH_PER_STREAM_OPT(hwaccel_devices, str, hwaccel_device, ic, st); + if (hwaccel_device) { + ist->hwaccel_device = av_strdup(hwaccel_device); + if (!ist->hwaccel_device) + exit_program(1); + } + ist->hwaccel_pix_fmt = AV_PIX_FMT_NONE; + break; case AVMEDIA_TYPE_AUDIO: guess_input_channel_layout(ist); - ist->resample_sample_fmt = dec->sample_fmt; - ist->resample_sample_rate = dec->sample_rate; - ist->resample_channels = dec->channels; - ist->resample_channel_layout = dec->channel_layout; + ist->resample_sample_fmt = ist->dec_ctx->sample_fmt; + ist->resample_sample_rate = ist->dec_ctx->sample_rate; + ist->resample_channels = ist->dec_ctx->channels; + ist->resample_channel_layout = ist->dec_ctx->channel_layout; break; case AVMEDIA_TYPE_DATA: @@ -517,7 +589,7 @@ static void assert_file_overwrite(const char *filename) } if (!file_overwrite && - (strchr(filename, ':') == NULL || filename[1] == ':' || + (!strchr(filename, ':') || filename[1] == ':' || av_strstart(filename, "file:", NULL))) { if (avio_check(filename, 0) == 0) { if (!using_stdin && !file_skip) { @@ -699,7 +771,7 @@ static int open_input_file(OptionsContext *o, const char *filename) unused_opts = strip_specifiers(o->g->codec_opts); for (i = f->ist_index; i < nb_input_streams; i++) { e = NULL; - while ((e = av_dict_get(input_streams[i]->opts, "", e, + while ((e = av_dict_get(input_streams[i]->decoder_opts, "", e, AV_DICT_IGNORE_SUFFIX))) av_dict_set(&unused_opts, e->key, NULL, 0); } @@ -767,14 +839,14 @@ static uint8_t *get_line(AVIOContext *s) static int get_preset_file_2(const char *preset_name, const char *codec_name, AVIOContext **s) { - int i, ret = 1; + 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++) { + for (i = 0; i < FF_ARRAY_ELEMS(base) && ret < 0; i++) { if (!base[i]) continue; if (codec_name) { @@ -782,7 +854,7 @@ static int get_preset_file_2(const char *preset_name, const char *codec_name, AV i != 1 ? "" : "/.avconv", codec_name, preset_name); ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL); } - if (ret) { + if (ret < 0) { snprintf(filename, sizeof(filename), "%s%s/%s.avpreset", base[i], i != 1 ? "" : "/.avconv", preset_name); ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL); @@ -835,11 +907,19 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e ost->st = st; st->codec->codec_type = type; choose_encoder(o, oc, ost); + + ost->enc_ctx = avcodec_alloc_context3(ost->enc); + if (!ost->enc_ctx) { + av_log(NULL, AV_LOG_ERROR, "Error allocating the encoding context.\n"); + exit_program(1); + } + ost->enc_ctx->codec_type = type; + if (ost->enc) { AVIOContext *s = NULL; char *buf = NULL, *arg = NULL, *preset = NULL; - ost->opts = filter_codec_opts(o->g->codec_opts, ost->enc->id, oc, st, ost->enc); + ost->encoder_opts = filter_codec_opts(o->g->codec_opts, ost->enc->id, oc, st, ost->enc); MATCH_PER_STREAM_OPT(presets, str, preset, oc, st); if (preset && (!(ret = get_preset_file_2(preset, ost->enc->name, &s)))) { @@ -854,7 +934,7 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e exit_program(1); } *arg++ = 0; - av_dict_set(&ost->opts, buf, arg, AV_DICT_DONT_OVERWRITE); + av_dict_set(&ost->encoder_opts, buf, arg, AV_DICT_DONT_OVERWRITE); av_free(buf); } while (!s->eof_reached); avio_close(s); @@ -866,12 +946,9 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e exit_program(1); } } else { - ost->opts = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL); + ost->encoder_opts = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL); } - 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 - ost->max_frames = INT64_MAX; MATCH_PER_STREAM_OPT(max_frames, i64, ost->max_frames, oc, st); @@ -897,17 +974,17 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e uint32_t tag = strtol(codec_tag, &next, 0); if (*next) tag = AV_RL32(codec_tag); - st->codec->codec_tag = tag; + ost->enc_ctx->codec_tag = tag; } MATCH_PER_STREAM_OPT(qscale, dbl, qscale, oc, st); if (qscale >= 0) { - st->codec->flags |= CODEC_FLAG_QSCALE; - st->codec->global_quality = FF_QP2LAMBDA * qscale; + ost->enc_ctx->flags |= CODEC_FLAG_QSCALE; + ost->enc_ctx->global_quality = FF_QP2LAMBDA * qscale; } if (oc->oformat->flags & AVFMT_GLOBALHEADER) - st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; + ost->enc_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; av_opt_get_int(o->g->sws_opts, "sws_flags", 0, &ost->sws_flags); @@ -998,7 +1075,7 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc) ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO); st = ost->st; - video_enc = st->codec; + video_enc = ost->enc_ctx; MATCH_PER_STREAM_OPT(frame_aspect_ratios, str, frame_aspect_ratio, oc, st); if (frame_aspect_ratio) @@ -1059,6 +1136,10 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc) video_enc->rc_override = av_realloc(video_enc->rc_override, sizeof(RcOverride) * (i + 1)); + if (!video_enc->rc_override) { + av_log(NULL, AV_LOG_FATAL, "Could not (re)allocate memory for rc_override.\n"); + exit_program(1); + } video_enc->rc_override[i].start_frame = start; video_enc->rc_override[i].end_frame = end; if (q > 0) { @@ -1119,7 +1200,7 @@ static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc) ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO); st = ost->st; - audio_enc = st->codec; + audio_enc = ost->enc_ctx; audio_enc->codec_type = AVMEDIA_TYPE_AUDIO; if (!ost->stream_copy) { @@ -1167,13 +1248,11 @@ static OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *o static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc) { - AVStream *st; OutputStream *ost; AVCodecContext *subtitle_enc; ost = new_output_stream(o, oc, AVMEDIA_TYPE_SUBTITLE); - st = ost->st; - subtitle_enc = st->codec; + subtitle_enc = ost->enc_ctx; subtitle_enc->codec_type = AVMEDIA_TYPE_SUBTITLE; @@ -1510,7 +1589,7 @@ loop_end: 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]->opts, "", e, + while ((e = av_dict_get(output_streams[i]->encoder_opts, "", e, AV_DICT_IGNORE_SUFFIX))) av_dict_set(&unused_opts, e->key, NULL, 0); } @@ -1684,7 +1763,8 @@ static int opt_target(void *optctx, const char *opt, const char *arg) for (j = 0; j < nb_input_files; j++) { for (i = 0; i < input_files[j]->nb_streams; i++) { AVCodecContext *c = input_files[j]->ctx->streams[i]->codec; - if (c->codec_type != AVMEDIA_TYPE_VIDEO) + if (c->codec_type != AVMEDIA_TYPE_VIDEO || + !c->time_base.num) continue; fr = c->time_base.den * 1000 / c->time_base.num; if (fr == 25000) { @@ -1729,7 +1809,7 @@ static int opt_target(void *optctx, const char *opt, const char *arg) parse_option(o, "ac", "2", options); opt_default(NULL, "packetsize", "2324"); - opt_default(NULL, "muxrate", "1411200"); // 2352 * 75 * 8; + opt_default(NULL, "muxrate", "3528"); // 2352 * 75 / 50; /* 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 @@ -1751,7 +1831,7 @@ static int opt_target(void *optctx, const char *opt, const char *arg) opt_default(NULL, "maxrate", "2516000"); opt_default(NULL, "minrate", "0"); // 1145000; opt_default(NULL, "bufsize", "1835008"); // 224*1024*8; - opt_default(NULL, "flags", "+scan_offset"); + opt_default(NULL, "scan_offset", "1"); opt_default(NULL, "b:a", "224000"); @@ -1775,7 +1855,7 @@ static int opt_target(void *optctx, const char *opt, const char *arg) opt_default(NULL, "bufsize", "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, "muxrate", "25200"); // from mplex project: data_rate = 1260000. mux_rate = data_rate / 50 opt_default(NULL, "b:a", "448000"); parse_option(o, "ar", "48000", options); @@ -1796,6 +1876,10 @@ static int opt_target(void *optctx, const char *opt, const char *arg) av_log(NULL, AV_LOG_ERROR, "Unknown target: %s\n", arg); return AVERROR(EINVAL); } + + av_dict_copy(&o->g->codec_opts, codec_opts, 0); + av_dict_copy(&o->g->format_opts, format_opts, 0); + return 0; } @@ -2196,7 +2280,7 @@ const OptionDef options[] = { { "frames", OPT_INT64 | HAS_ARG | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(max_frames) }, "set the number of frames to record", "number" }, { "tag", OPT_STRING | HAS_ARG | OPT_SPEC | - OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(codec_tags) }, + OPT_EXPERT | OPT_OUTPUT | OPT_INPUT, { .off = OFFSET(codec_tags) }, "force codec tag/fourcc", "fourcc/tag" }, { "q", HAS_ARG | OPT_EXPERT | OPT_DOUBLE | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(qscale) }, @@ -2282,6 +2366,12 @@ const OptionDef options[] = { { "force_key_frames", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(forced_key_frames) }, "force key frames at specified timestamps", "timestamps" }, + { "hwaccel", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT | + OPT_SPEC | OPT_INPUT, { .off = OFFSET(hwaccels) }, + "use HW accelerated decoding", "hwaccel name" }, + { "hwaccel_device", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT | + OPT_SPEC | OPT_INPUT, { .off = OFFSET(hwaccel_devices) }, + "select a device for HW acceleration" "devicename" }, /* audio options */ { "aframes", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_frames },