diff options
Diffstat (limited to 'common/av_common.c')
-rw-r--r-- | common/av_common.c | 128 |
1 files changed, 81 insertions, 47 deletions
diff --git a/common/av_common.c b/common/av_common.c index f2f43498e3..5c58f3fea8 100644 --- a/common/av_common.c +++ b/common/av_common.c @@ -33,6 +33,7 @@ #include "common/msg.h" #include "demux/packet.h" #include "demux/stheader.h" +#include "video/fmt-conversion.h" #include "av_common.h" #include "codecs.h" @@ -41,7 +42,7 @@ int mp_lavc_set_extradata(AVCodecContext *avctx, void *ptr, int size) if (size) { av_free(avctx->extradata); avctx->extradata_size = 0; - avctx->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE); + avctx->extradata = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE); if (!avctx->extradata) return -1; avctx->extradata_size = size; @@ -50,35 +51,81 @@ int mp_lavc_set_extradata(AVCodecContext *avctx, void *ptr, int size) return 0; } -// Copy the codec-related fields from st into avctx. This does not set the -// codec itself, only codec related header data provided by libavformat. -// The goal is to initialize a new decoder with the header data provided by -// libavformat, and unlike avcodec_copy_context(), allow the user to create -// a clean AVCodecContext for a manually selected AVCodec. -// This is strictly for decoding only. -void mp_copy_lav_codec_headers(AVCodecContext *avctx, AVCodecContext *st) +enum AVMediaType mp_to_av_stream_type(int type) { - mp_lavc_set_extradata(avctx, st->extradata, st->extradata_size); - avctx->codec_tag = st->codec_tag; - avctx->bit_rate = st->bit_rate; - avctx->width = st->width; - avctx->height = st->height; - avctx->pix_fmt = st->pix_fmt; - avctx->chroma_sample_location = st->chroma_sample_location; - avctx->sample_rate = st->sample_rate; - avctx->channels = st->channels; - avctx->block_align = st->block_align; - avctx->channel_layout = st->channel_layout; - avctx->bits_per_coded_sample = st->bits_per_coded_sample; - avctx->has_b_frames = st->has_b_frames; + switch (type) { + case STREAM_VIDEO: return AVMEDIA_TYPE_VIDEO; + case STREAM_AUDIO: return AVMEDIA_TYPE_AUDIO; + case STREAM_SUB: return AVMEDIA_TYPE_SUBTITLE; + default: return AVMEDIA_TYPE_UNKNOWN; + } } -// This only copies ffmpeg-native codec parameters. Parameters produced by -// other demuxers must be handled manually. -void mp_set_lav_codec_headers(AVCodecContext *avctx, struct mp_codec_params *c) +AVCodecParameters *mp_codec_params_to_av(struct mp_codec_params *c) { - if (c->lav_codecpar) - avcodec_parameters_to_context(avctx, c->lav_codecpar); + AVCodecParameters *avp = avcodec_parameters_alloc(); + if (!avp) + return NULL; + + // If we have lavf demuxer params, they overwrite by definition any others. + if (c->lav_codecpar) { + if (avcodec_parameters_copy(avp, c->lav_codecpar) < 0) + goto error; + return avp; + } + + avp->codec_type = mp_to_av_stream_type(c->type); + avp->codec_id = mp_codec_to_av_codec_id(c->codec); + avp->codec_tag = c->codec_tag; + if (c->extradata_size) { + avp->extradata = + av_mallocz(c->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!avp->extradata) + goto error; + avp->extradata_size = c->extradata_size; + memcpy(avp->extradata, c->extradata, avp->extradata_size); + } + avp->bits_per_coded_sample = c->bits_per_coded_sample; + + // Video only + avp->width = c->disp_w; + avp->height = c->disp_h; + if (c->codec && strcmp(c->codec, "mp-rawvideo") == 0) { + avp->format = imgfmt2pixfmt(c->codec_tag); + avp->codec_tag = 0; + } + + // Audio only + avp->sample_rate = c->samplerate; + avp->bit_rate = c->bitrate; + avp->block_align = c->block_align; + avp->channels = c->channels.num; + if (!mp_chmap_is_unknown(&c->channels)) + avp->channel_layout = mp_chmap_to_lavc(&c->channels); + + return avp; +error: + avcodec_parameters_free(&avp); + return NULL; +} + +// Set avctx codec headers for decoding. Returns <0 on failure. +int mp_set_avctx_codec_headers(AVCodecContext *avctx, struct mp_codec_params *c) +{ + enum AVMediaType codec_type = avctx->codec_type; + enum AVCodecID codec_id = avctx->codec_id; + AVCodecParameters *avp = mp_codec_params_to_av(c); + if (!avp) + return -1; + + int r = avcodec_parameters_to_context(avctx, avp) < 0 ? -1 : 0; + avcodec_parameters_free(&avp); + + if (avctx->codec_type != AVMEDIA_TYPE_UNKNOWN) + avctx->codec_type = codec_type; + if (avctx->codec_id != AV_CODEC_ID_NONE) + avctx->codec_id = codec_id; + return r; } // Pick a "good" timebase, which will be used to convert double timestamps @@ -108,37 +155,24 @@ AVRational mp_get_codec_timebase(struct mp_codec_params *c) return tb; } -// We merely pass-through our PTS/DTS as an int64_t; libavcodec won't use it. -union pts { int64_t i; double d; }; +static AVRational get_def_tb(AVRational *tb) +{ + return tb && tb->num > 0 && tb->den > 0 ? *tb : AV_TIME_BASE_Q; +} // Convert the mpv style timestamp (seconds as double) to a libavcodec style // timestamp (integer units in a given timebase). -// -// If the given timebase is NULL or invalid, pass through the mpv timestamp by -// reinterpret casting them to int64_t. In this case, the timestamps will be -// non-sense for libavcodec, but we expect that it doesn't interpret them, -// and treats them as opaque. int64_t mp_pts_to_av(double mp_pts, AVRational *tb) { - assert(sizeof(int64_t) >= sizeof(double)); - if (tb && tb->num > 0 && tb->den > 0) { - return mp_pts == MP_NOPTS_VALUE ? - AV_NOPTS_VALUE : llrint(mp_pts / av_q2d(*tb)); - } - // The + 0.0 is to squash possible negative zero mp_pts, which would - // happen to end up as AV_NOPTS_VALUE. - return (union pts){.d = mp_pts + 0.0}.i; + AVRational b = get_def_tb(tb); + return mp_pts == MP_NOPTS_VALUE ? AV_NOPTS_VALUE : llrint(mp_pts / av_q2d(b)); } // Inverse of mp_pts_to_av(). (The timebases must be exactly the same.) double mp_pts_from_av(int64_t av_pts, AVRational *tb) { - assert(sizeof(int64_t) >= sizeof(double)); - if (tb && tb->num > 0 && tb->den > 0) - return av_pts == AV_NOPTS_VALUE ? MP_NOPTS_VALUE : av_pts * av_q2d(*tb); - // Should libavcodec set the PTS to AV_NOPTS_VALUE, it would end up as - // non-sense (usually negative zero) when unwrapped to double. - return av_pts == AV_NOPTS_VALUE ? MP_NOPTS_VALUE : (union pts){.i = av_pts}.d; + AVRational b = get_def_tb(tb); + return av_pts == AV_NOPTS_VALUE ? MP_NOPTS_VALUE : av_pts * av_q2d(b); } // Set dst from mpkt. Note that dst is not refcountable. |