blob: 9900e7ab1f796d3171ad2688c2662b081f61a6ac
1 | /* |
2 | * VP9 compatible video decoder |
3 | * |
4 | * Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com> |
5 | * Copyright (C) 2013 Clément Bœsch <u pkh me> |
6 | * |
7 | * This file is part of FFmpeg. |
8 | * |
9 | * FFmpeg is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU Lesser General Public |
11 | * License as published by the Free Software Foundation; either |
12 | * version 2.1 of the License, or (at your option) any later version. |
13 | * |
14 | * FFmpeg is distributed in the hope that it will be useful, |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | * Lesser General Public License for more details. |
18 | * |
19 | * You should have received a copy of the GNU Lesser General Public |
20 | * License along with FFmpeg; if not, write to the Free Software |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
22 | */ |
23 | |
24 | #include "libavutil/intreadwrite.h" |
25 | #include "libavcodec/get_bits.h" |
26 | #include "parser.h" |
27 | |
28 | typedef struct VP9ParseContext { |
29 | int n_frames; // 1-8 |
30 | int size[8]; |
31 | int marker_size; |
32 | int64_t pts; |
33 | } VP9ParseContext; |
34 | |
35 | static int parse_frame(AVCodecParserContext *ctx, const uint8_t *buf, int size) |
36 | { |
37 | VP9ParseContext *s = ctx->priv_data; |
38 | GetBitContext gb; |
39 | int res, profile, keyframe, invisible; |
40 | |
41 | if ((res = init_get_bits8(&gb, buf, size)) < 0) |
42 | return res; |
43 | get_bits(&gb, 2); // frame marker |
44 | profile = get_bits1(&gb); |
45 | profile |= get_bits1(&gb) << 1; |
46 | if (profile == 3) profile += get_bits1(&gb); |
47 | |
48 | if (get_bits1(&gb)) { |
49 | keyframe = 0; |
50 | invisible = 0; |
51 | } else { |
52 | keyframe = !get_bits1(&gb); |
53 | invisible = !get_bits1(&gb); |
54 | } |
55 | |
56 | if (!keyframe) { |
57 | ctx->pict_type = AV_PICTURE_TYPE_P; |
58 | ctx->key_frame = 0; |
59 | } else { |
60 | ctx->pict_type = AV_PICTURE_TYPE_I; |
61 | ctx->key_frame = 1; |
62 | } |
63 | |
64 | if (!invisible) { |
65 | if (ctx->pts == AV_NOPTS_VALUE) |
66 | ctx->pts = s->pts; |
67 | s->pts = AV_NOPTS_VALUE; |
68 | } else if (ctx->pts != AV_NOPTS_VALUE) { |
69 | s->pts = ctx->pts; |
70 | ctx->pts = AV_NOPTS_VALUE; |
71 | } |
72 | |
73 | return 0; |
74 | } |
75 | |
76 | static int parse(AVCodecParserContext *ctx, |
77 | AVCodecContext *avctx, |
78 | const uint8_t **out_data, int *out_size, |
79 | const uint8_t *data, int size) |
80 | { |
81 | VP9ParseContext *s = ctx->priv_data; |
82 | int full_size = size; |
83 | int marker; |
84 | |
85 | if (size <= 0) { |
86 | *out_size = 0; |
87 | *out_data = data; |
88 | |
89 | return 0; |
90 | } |
91 | |
92 | if (s->n_frames > 0) { |
93 | int i; |
94 | int size_sum = 0; |
95 | |
96 | for (i = 0; i < s->n_frames ;i++) |
97 | size_sum += s->size[i]; |
98 | size_sum += s->marker_size; |
99 | |
100 | if (size_sum != size) { |
101 | av_log(avctx, AV_LOG_ERROR, "Inconsistent input frame sizes %d %d\n", |
102 | size_sum, size); |
103 | s->n_frames = 0; |
104 | } |
105 | } |
106 | |
107 | if (s->n_frames > 0) { |
108 | *out_data = data; |
109 | *out_size = s->size[--s->n_frames]; |
110 | parse_frame(ctx, *out_data, *out_size); |
111 | |
112 | return s->n_frames > 0 ? *out_size : size /* i.e. include idx tail */; |
113 | } |
114 | |
115 | marker = data[size - 1]; |
116 | if ((marker & 0xe0) == 0xc0) { |
117 | int nbytes = 1 + ((marker >> 3) & 0x3); |
118 | int n_frames = 1 + (marker & 0x7), idx_sz = 2 + n_frames * nbytes; |
119 | |
120 | if (size >= idx_sz && data[size - idx_sz] == marker) { |
121 | const uint8_t *idx = data + size + 1 - idx_sz; |
122 | int first = 1; |
123 | |
124 | switch (nbytes) { |
125 | #define case_n(a, rd) \ |
126 | case a: \ |
127 | while (n_frames--) { \ |
128 | unsigned sz = rd; \ |
129 | idx += a; \ |
130 | if (sz == 0 || sz > size) { \ |
131 | s->n_frames = 0; \ |
132 | *out_size = size; \ |
133 | *out_data = data; \ |
134 | av_log(avctx, AV_LOG_ERROR, \ |
135 | "Invalid superframe packet size: %u frame size: %d\n", \ |
136 | sz, size); \ |
137 | return full_size; \ |
138 | } \ |
139 | if (first) { \ |
140 | first = 0; \ |
141 | *out_data = data; \ |
142 | *out_size = sz; \ |
143 | s->n_frames = n_frames; \ |
144 | } else { \ |
145 | s->size[n_frames] = sz; \ |
146 | } \ |
147 | data += sz; \ |
148 | size -= sz; \ |
149 | } \ |
150 | s->marker_size = size; \ |
151 | parse_frame(ctx, *out_data, *out_size); \ |
152 | return s->n_frames > 0 ? *out_size : full_size |
153 | |
154 | case_n(1, *idx); |
155 | case_n(2, AV_RL16(idx)); |
156 | case_n(3, AV_RL24(idx)); |
157 | case_n(4, AV_RL32(idx)); |
158 | } |
159 | } |
160 | } |
161 | |
162 | *out_data = data; |
163 | *out_size = size; |
164 | parse_frame(ctx, data, size); |
165 | |
166 | return size; |
167 | } |
168 | |
169 | AVCodecParser ff_vp9_parser = { |
170 | .codec_ids = { AV_CODEC_ID_VP9 }, |
171 | .priv_data_size = sizeof(VP9ParseContext), |
172 | .parser_parse = parse, |
173 | }; |
174 |