diff options
author | James Almer <jamrial@gmail.com> | 2022-11-11 12:44:41 -0300 |
---|---|---|
committer | James Almer <jamrial@gmail.com> | 2022-11-17 10:05:49 -0300 |
commit | cb925c0bc059ce54cb6f8d858d43378ec516f548 (patch) | |
tree | 83b26f54c6270c4dbb478add051cbe333d7b41e1 /libavformat/vpcc.c | |
parent | e9a67ababacb0c66481a17f5648b3594789e8914 (diff) |
avformat/vpcc: parse bitstream data to get profile and bitdepth
Profile can be derived from values codecpar pixel format only with software
formats. For hardware formats, we're forced to parse a frame header to get
the required information.
Signed-off-by: James Almer <jamrial@gmail.com>
Diffstat (limited to 'libavformat/vpcc.c')
-rw-r--r-- | libavformat/vpcc.c | 55 |
1 files changed, 53 insertions, 2 deletions
diff --git a/libavformat/vpcc.c b/libavformat/vpcc.c index 8b4f913b5d..ea66959abf 100644 --- a/libavformat/vpcc.c +++ b/libavformat/vpcc.c @@ -22,8 +22,11 @@ #include "libavutil/pixdesc.h" #include "libavutil/pixfmt.h" #include "libavcodec/avcodec.h" +#include "libavcodec/get_bits.h" #include "vpcc.h" +#define VP9_SYNCCODE 0x498342 + enum VPX_CHROMA_SUBSAMPLING { VPX_SUBSAMPLING_420_VERTICAL = 0, @@ -114,7 +117,41 @@ static int get_vp9_level(AVCodecParameters *par, AVRational *frame_rate) { } } +static void parse_bitstream(GetBitContext *gb, int *profile, int *bit_depth) { + int keyframe, invisible; + + if (get_bits(gb, 2) != 0x2) // frame marker + return; + *profile = get_bits1(gb); + *profile |= get_bits1(gb) << 1; + if (*profile == 3) + *profile += get_bits1(gb); + + if (get_bits1(gb)) + return; + + keyframe = !get_bits1(gb); + invisible = !get_bits1(gb); + get_bits1(gb); + + if (keyframe) { + if (get_bits(gb, 24) != VP9_SYNCCODE) + return; + } else { + int intraonly = invisible ? get_bits1(gb) : 0; + if (!intraonly || get_bits(gb, 24) != VP9_SYNCCODE) + return; + if (*profile < 1) { + *bit_depth = 8; + return; + } + } + + *bit_depth = *profile <= 1 ? 8 : 10 + get_bits1(gb) * 2; +} + int ff_isom_get_vpcc_features(AVFormatContext *s, AVCodecParameters *par, + const uint8_t *data, int len, AVRational *frame_rate, VPCC *vpcc) { int profile = par->profile; @@ -129,7 +166,17 @@ int ff_isom_get_vpcc_features(AVFormatContext *s, AVCodecParameters *par, if (bit_depth < 0 || vpx_chroma_subsampling < 0) return AVERROR_INVALIDDATA; - if (profile == FF_PROFILE_UNKNOWN) { + if (len && (profile == FF_PROFILE_UNKNOWN || !bit_depth)) { + GetBitContext gb; + + int ret = init_get_bits8(&gb, data, len); + if (ret < 0) + return ret; + + parse_bitstream(&gb, &profile, &bit_depth); + } + + if (profile == FF_PROFILE_UNKNOWN && bit_depth) { if (vpx_chroma_subsampling == VPX_SUBSAMPLING_420_VERTICAL || vpx_chroma_subsampling == VPX_SUBSAMPLING_420_COLLOCATED_WITH_LUMA) { profile = (bit_depth == 8) ? FF_PROFILE_VP9_0 : FF_PROFILE_VP9_2; @@ -138,6 +185,9 @@ int ff_isom_get_vpcc_features(AVFormatContext *s, AVCodecParameters *par, } } + if (profile == FF_PROFILE_UNKNOWN || !bit_depth) + av_log(s, AV_LOG_WARNING, "VP9 profile and/or bit depth not set or could not be derived\n"); + vpcc->profile = profile; vpcc->level = level; vpcc->bitdepth = bit_depth; @@ -148,12 +198,13 @@ int ff_isom_get_vpcc_features(AVFormatContext *s, AVCodecParameters *par, } int ff_isom_write_vpcc(AVFormatContext *s, AVIOContext *pb, + const uint8_t *data, int len, AVCodecParameters *par) { VPCC vpcc; int ret; - ret = ff_isom_get_vpcc_features(s, par, NULL, &vpcc); + ret = ff_isom_get_vpcc_features(s, par, data, len, NULL, &vpcc); if (ret < 0) return ret; |