Skip to content

Commit e13b361

Browse files
committed
avcodec/vp9_parser: parse size and colorspace values from frame headers
Improves remuxing support when vp9 decoder is not compiled in. Signed-off-by: James Almer <jamrial@gmail.com>
1 parent fb3fd4d commit e13b361

File tree

1 file changed

+97
-1
lines changed

1 file changed

+97
-1
lines changed

libavcodec/vp9_parser.c

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,69 @@
2323

2424
#include "libavutil/intreadwrite.h"
2525
#include "libavcodec/get_bits.h"
26+
#include "libavcodec/internal.h"
2627
#include "parser.h"
2728

29+
#define VP9_SYNCCODE 0x498342
30+
31+
static int read_colorspace_details(AVCodecParserContext *ctx, AVCodecContext *avctx,
32+
GetBitContext *gb)
33+
{
34+
static const enum AVColorSpace colorspaces[8] = {
35+
AVCOL_SPC_UNSPECIFIED, AVCOL_SPC_BT470BG, AVCOL_SPC_BT709, AVCOL_SPC_SMPTE170M,
36+
AVCOL_SPC_SMPTE240M, AVCOL_SPC_BT2020_NCL, AVCOL_SPC_RESERVED, AVCOL_SPC_RGB,
37+
};
38+
int bits = avctx->profile <= 1 ? 0 : 1 + get_bits1(gb); // 0:8, 1:10, 2:12
39+
40+
avctx->colorspace = colorspaces[get_bits(gb, 3)];
41+
if (avctx->colorspace == AVCOL_SPC_RGB) { // RGB = profile 1
42+
static const enum AVPixelFormat pix_fmt_rgb[3] = {
43+
AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12
44+
};
45+
if (avctx->profile & 1) {
46+
if (get_bits1(gb)) // reserved bit
47+
return AVERROR_INVALIDDATA;
48+
} else
49+
return AVERROR_INVALIDDATA;
50+
avctx->color_range = AVCOL_RANGE_JPEG;
51+
ctx->format = pix_fmt_rgb[bits];
52+
} else {
53+
static const enum AVPixelFormat pix_fmt_for_ss[3][2 /* v */][2 /* h */] = {
54+
{ { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P },
55+
{ AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV420P } },
56+
{ { AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10 },
57+
{ AV_PIX_FMT_YUV440P10, AV_PIX_FMT_YUV420P10 } },
58+
{ { AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12 },
59+
{ AV_PIX_FMT_YUV440P12, AV_PIX_FMT_YUV420P12 } }
60+
};
61+
avctx->color_range = get_bits1(gb) ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
62+
if (avctx->profile & 1) {
63+
int ss_h, ss_v, format;
64+
65+
ss_h = get_bits1(gb);
66+
ss_v = get_bits1(gb);
67+
format = pix_fmt_for_ss[bits][ss_v][ss_h];
68+
if (format == AV_PIX_FMT_YUV420P)
69+
// YUV 4:2:0 not supported in profiles 1 and 3
70+
return AVERROR_INVALIDDATA;
71+
else if (get_bits1(gb)) // color details reserved bit
72+
return AVERROR_INVALIDDATA;
73+
ctx->format = format;
74+
} else {
75+
ctx->format = pix_fmt_for_ss[bits][1][1];
76+
}
77+
}
78+
79+
return 0;
80+
}
81+
2882
static int parse(AVCodecParserContext *ctx,
2983
AVCodecContext *avctx,
3084
const uint8_t **out_data, int *out_size,
3185
const uint8_t *data, int size)
3286
{
3387
GetBitContext gb;
34-
int res, profile, keyframe;
88+
int res, profile, keyframe, invisible, errorres;
3589

3690
*out_data = data;
3791
*out_size = size;
@@ -42,21 +96,63 @@ static int parse(AVCodecParserContext *ctx,
4296
profile = get_bits1(&gb);
4397
profile |= get_bits1(&gb) << 1;
4498
if (profile == 3) profile += get_bits1(&gb);
99+
if (profile > 3)
100+
return size;
45101

46102
if (get_bits1(&gb)) {
47103
keyframe = 0;
104+
skip_bits(&gb, 3);
48105
} else {
49106
keyframe = !get_bits1(&gb);
50107
}
51108

109+
invisible = !get_bits1(&gb);
110+
errorres = get_bits1(&gb);
111+
52112
if (!keyframe) {
113+
int intraonly = invisible ? get_bits1(&gb) : 0;
114+
if (!errorres)
115+
skip_bits(&gb, 2);
116+
if (intraonly) {
117+
if (get_bits_long(&gb, 24) != VP9_SYNCCODE) // synccode
118+
return size;
119+
avctx->profile = profile;
120+
if (profile >= 1) {
121+
if ((read_colorspace_details(ctx, avctx, &gb)) < 0)
122+
return size;
123+
} else {
124+
ctx->format = AV_PIX_FMT_YUV420P;
125+
avctx->colorspace = AVCOL_SPC_BT470BG;
126+
avctx->color_range = AVCOL_RANGE_MPEG;
127+
}
128+
skip_bits(&gb, 8); // refreshrefmask
129+
ctx->width = get_bits(&gb, 16) + 1;
130+
ctx->height = get_bits(&gb, 16) + 1;
131+
if (get_bits1(&gb)) // display size
132+
skip_bits(&gb, 32);
133+
}
134+
53135
ctx->pict_type = AV_PICTURE_TYPE_P;
54136
ctx->key_frame = 0;
55137
} else {
138+
if (get_bits_long(&gb, 24) != VP9_SYNCCODE) // synccode
139+
return size;
140+
avctx->profile = profile;
141+
if (read_colorspace_details(ctx, avctx, &gb) < 0)
142+
return size;
143+
ctx->width = get_bits(&gb, 16) + 1;
144+
ctx->height = get_bits(&gb, 16) + 1;
145+
if (get_bits1(&gb)) // display size
146+
skip_bits(&gb, 32);
147+
56148
ctx->pict_type = AV_PICTURE_TYPE_I;
57149
ctx->key_frame = 1;
58150
}
59151

152+
if (ctx->width && (!avctx->width || !avctx->height ||
153+
!avctx->coded_width || !avctx->coded_height))
154+
ff_set_dimensions(avctx, ctx->width, ctx->height);
155+
60156
return size;
61157
}
62158

0 commit comments

Comments
 (0)