X-Git-Url: https://git.piment-noir.org/?p=deb_ffmpeg.git;a=blobdiff_plain;f=ffmpeg%2Flibavformat%2Fffmenc.c;h=e6d1a31dd390b488c7d0199b9eb5d7907011fb91;hp=eb809eb64cee031ff66cbc0a56bf2746b12d1748;hb=f6fa7814ccfe3e76514b36cf04f5cd3cb657c8cf;hpb=2ba45a602cbfa7b771effba9b11bb4245c21bc00 diff --git a/ffmpeg/libavformat/ffmenc.c b/ffmpeg/libavformat/ffmenc.c index eb809eb..e6d1a31 100644 --- a/ffmpeg/libavformat/ffmenc.c +++ b/ffmpeg/libavformat/ffmenc.c @@ -23,6 +23,7 @@ #include "libavutil/intfloat.h" #include "libavutil/avassert.h" #include "libavutil/parseutils.h" +#include "libavutil/opt.h" #include "avformat.h" #include "internal.h" #include "ffm.h" @@ -93,6 +94,128 @@ static void write_header_chunk(AVIOContext *pb, AVIOContext *dpb, unsigned id) av_free(dyn_buf); } +static int ffm_write_header_codec_private_ctx(AVIOContext *pb, AVCodecContext *ctx, int type) +{ + AVIOContext *tmp; + char *buf = NULL; + int ret; + const AVCodec *enc = ctx->codec ? ctx->codec : avcodec_find_encoder(ctx->codec_id); + + if (!enc) + return AVERROR(EINVAL); + if (ctx->priv_data && enc->priv_class && enc->priv_data_size) { + if ((ret = av_opt_serialize(ctx->priv_data, AV_OPT_FLAG_ENCODING_PARAM | type, + AV_OPT_SERIALIZE_SKIP_DEFAULTS, &buf, '=', ',')) < 0) + return ret; + if (buf && strlen(buf)) { + if (avio_open_dyn_buf(&tmp) < 0) { + av_free(buf); + return AVERROR(ENOMEM); + } + avio_put_str(tmp, buf); + write_header_chunk(pb, tmp, MKBETAG('C', 'P', 'R', 'V')); + } + av_free(buf); + } + return 0; +} + +static int ffm_write_header_codec_ctx(AVIOContext *pb, AVCodecContext *ctx, unsigned tag, int type) +{ + AVIOContext *tmp; + char *buf = NULL; + uint8_t *p = NULL; + int ret, need_coma = 0; + +#define SKIP_DEFAULTS AV_OPT_SERIALIZE_SKIP_DEFAULTS +#define OPT_FLAGS_EXACT AV_OPT_SERIALIZE_OPT_FLAGS_EXACT +#define ENC AV_OPT_FLAG_ENCODING_PARAM + + if (avio_open_dyn_buf(&tmp) < 0) + return AVERROR(ENOMEM); + if ((ret = av_opt_serialize(ctx, ENC | type, SKIP_DEFAULTS, &buf, '=', ',')) < 0) + goto fail; + if (buf && strlen(buf)) { + avio_write(tmp, buf, strlen(buf)); + av_free(buf); + need_coma = 1; + } + if ((ret = av_opt_serialize(ctx, 0, SKIP_DEFAULTS | OPT_FLAGS_EXACT, &buf, '=', ',')) < 0) + goto fail; + if (buf && strlen(buf)) { + if (need_coma) + avio_w8(tmp, ','); + avio_write(tmp, buf, strlen(buf)); + av_free(buf); + } + avio_w8(tmp, 0); + write_header_chunk(pb, tmp, tag); + return 0; + fail: + av_free(buf); + avio_close_dyn_buf(tmp, &p); + av_free(p); + return ret; + +#undef SKIP_DEFAULTS +#undef OPT_FLAGS_EXACT +#undef ENC +} + +static int ffm_write_recommended_config(AVIOContext *pb, AVCodecContext *ctx, unsigned tag, + const char *configuration) +{ + int ret; + const AVCodec *enc = ctx->codec ? ctx->codec : avcodec_find_encoder(ctx->codec_id); + AVIOContext *tmp; + AVDictionaryEntry *t = NULL; + AVDictionary *all = NULL, *comm = NULL, *prv = NULL; + char *buf = NULL; + + if (!enc || !enc->priv_class || !enc->priv_data_size) { + /* codec is not known/has no private options, so save everything as common options */ + if (avio_open_dyn_buf(&tmp) < 0) + return AVERROR(ENOMEM); + avio_put_str(tmp, configuration); + write_header_chunk(pb, tmp, tag); + return 0; + } + + if ((ret = av_dict_parse_string(&all, configuration, "=", ",", 0)) < 0) + return ret; + + while ((t = av_dict_get(all, "", t, AV_DICT_IGNORE_SUFFIX))) { + if (av_opt_find((void *)&enc->priv_class, t->key, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ)) { + if ((ret = av_dict_set(&prv, t->key, t->value, 0)) < 0) + goto fail; + } else if ((ret = av_dict_set(&comm, t->key, t->value, 0)) < 0) + goto fail; + } + + if (comm) { + if ((ret = av_dict_get_string(comm, &buf, '=', ',')) < 0 || + (ret = avio_open_dyn_buf(&tmp)) < 0) + goto fail; + avio_put_str(tmp, buf); + av_freep(&buf); + write_header_chunk(pb, tmp, tag); + } + if (prv) { + if ((ret = av_dict_get_string(prv, &buf, '=', ',')) < 0 || + (ret = avio_open_dyn_buf(&tmp)) < 0) + goto fail; + avio_put_str(tmp, buf); + write_header_chunk(pb, tmp, MKBETAG('C', 'P', 'R', 'V')); + } + + fail: + av_free(buf); + av_dict_free(&all); + av_dict_free(&comm); + av_dict_free(&prv); + return ret; +} + static int ffm_write_header(AVFormatContext *s) { FFMContext *ffm = s->priv_data; @@ -100,10 +223,10 @@ static int ffm_write_header(AVFormatContext *s) AVStream *st; AVIOContext *pb = s->pb; AVCodecContext *codec; - int bit_rate, i; + int bit_rate, i, ret; if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) { - int ret = av_parse_time(&ffm->start_time, t->value, 0); + ret = av_parse_time(&ffm->start_time, t->value, 0); if (ret < 0) return ret; } @@ -148,61 +271,29 @@ static int ffm_write_header(AVFormatContext *s) avio_write(pb, codec->extradata, codec->extradata_size); } write_header_chunk(s->pb, pb, MKBETAG('C', 'O', 'M', 'M')); - if(avio_open_dyn_buf(&pb) < 0) - return AVERROR(ENOMEM); /* specific info */ switch(codec->codec_type) { case AVMEDIA_TYPE_VIDEO: - avio_wb32(pb, codec->time_base.num); - avio_wb32(pb, codec->time_base.den); - avio_wb16(pb, codec->width); - avio_wb16(pb, codec->height); - avio_wb16(pb, codec->gop_size); - avio_wb32(pb, codec->pix_fmt); - avio_w8(pb, codec->qmin); - avio_w8(pb, codec->qmax); - avio_w8(pb, codec->max_qdiff); - avio_wb16(pb, (int) (codec->qcompress * 10000.0)); - avio_wb16(pb, (int) (codec->qblur * 10000.0)); - avio_wb32(pb, codec->bit_rate_tolerance); - avio_put_str(pb, codec->rc_eq ? codec->rc_eq : "tex^qComp"); - avio_wb32(pb, codec->rc_max_rate); - avio_wb32(pb, codec->rc_min_rate); - avio_wb32(pb, codec->rc_buffer_size); - avio_wb64(pb, av_double2int(codec->i_quant_factor)); - avio_wb64(pb, av_double2int(codec->b_quant_factor)); - avio_wb64(pb, av_double2int(codec->i_quant_offset)); - avio_wb64(pb, av_double2int(codec->b_quant_offset)); - avio_wb32(pb, codec->dct_algo); - avio_wb32(pb, codec->strict_std_compliance); - avio_wb32(pb, codec->max_b_frames); - avio_wb32(pb, codec->mpeg_quant); - avio_wb32(pb, codec->intra_dc_precision); - avio_wb32(pb, codec->me_method); - avio_wb32(pb, codec->mb_decision); - avio_wb32(pb, codec->nsse_weight); - avio_wb32(pb, codec->frame_skip_cmp); - avio_wb64(pb, av_double2int(codec->rc_buffer_aggressivity)); - avio_wb32(pb, codec->codec_tag); - avio_w8(pb, codec->thread_count); - avio_wb32(pb, codec->coder_type); - avio_wb32(pb, codec->me_cmp); - avio_wb32(pb, codec->me_subpel_quality); - avio_wb32(pb, codec->me_range); - avio_wb32(pb, codec->keyint_min); - avio_wb32(pb, codec->scenechange_threshold); - avio_wb32(pb, codec->b_frame_strategy); - avio_wb64(pb, av_double2int(codec->qcompress)); - avio_wb64(pb, av_double2int(codec->qblur)); - avio_wb32(pb, codec->max_qdiff); - avio_wb32(pb, codec->refs); - write_header_chunk(s->pb, pb, MKBETAG('S', 'T', 'V', 'I')); + if (st->recommended_encoder_configuration) { + av_log(NULL, AV_LOG_DEBUG, "writing recommended configuration: %s\n", + st->recommended_encoder_configuration); + if ((ret = ffm_write_recommended_config(s->pb, codec, MKBETAG('S', '2', 'V', 'I'), + st->recommended_encoder_configuration)) < 0) + return ret; + } else if ((ret = ffm_write_header_codec_ctx(s->pb, codec, MKBETAG('S', '2', 'V', 'I'), AV_OPT_FLAG_VIDEO_PARAM)) < 0 || + (ret = ffm_write_header_codec_private_ctx(s->pb, codec, AV_OPT_FLAG_VIDEO_PARAM)) < 0) + return ret; break; case AVMEDIA_TYPE_AUDIO: - avio_wb32(pb, codec->sample_rate); - avio_wl16(pb, codec->channels); - avio_wl16(pb, codec->frame_size); - write_header_chunk(s->pb, pb, MKBETAG('S', 'T', 'A', 'U')); + if (st->recommended_encoder_configuration) { + av_log(NULL, AV_LOG_DEBUG, "writing recommended configuration: %s\n", + st->recommended_encoder_configuration); + if ((ret = ffm_write_recommended_config(s->pb, codec, MKBETAG('S', '2', 'A', 'U'), + st->recommended_encoder_configuration)) < 0) + return ret; + } else if ((ret = ffm_write_header_codec_ctx(s->pb, codec, MKBETAG('S', '2', 'A', 'U'), AV_OPT_FLAG_AUDIO_PARAM)) < 0 || + (ret = ffm_write_header_codec_private_ctx(s->pb, codec, AV_OPT_FLAG_AUDIO_PARAM)) < 0) + return ret; break; default: return -1;