/src/libvpx/vp9/vp9_dx_iface.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2010 The WebM project authors. All Rights Reserved. |
3 | | * |
4 | | * Use of this source code is governed by a BSD-style license |
5 | | * that can be found in the LICENSE file in the root of the source |
6 | | * tree. An additional intellectual property rights grant can be found |
7 | | * in the file PATENTS. All contributing project authors may |
8 | | * be found in the AUTHORS file in the root of the source tree. |
9 | | */ |
10 | | |
11 | | #include <stdlib.h> |
12 | | #include <string.h> |
13 | | |
14 | | #include "./vpx_config.h" |
15 | | #include "./vpx_version.h" |
16 | | |
17 | | #include "vpx/internal/vpx_codec_internal.h" |
18 | | #include "vpx/vp8dx.h" |
19 | | #include "vpx/vpx_decoder.h" |
20 | | #include "vpx_dsp/bitreader_buffer.h" |
21 | | #include "vpx_dsp/vpx_dsp_common.h" |
22 | | |
23 | | #include "vp9/common/vp9_alloccommon.h" |
24 | | #include "vp9/common/vp9_frame_buffers.h" |
25 | | |
26 | | #include "vp9/decoder/vp9_decodeframe.h" |
27 | | |
28 | | #include "vp9/vp9_dx_iface.h" |
29 | | #include "vp9/vp9_iface_common.h" |
30 | | |
31 | | #define VP9_CAP_POSTPROC (CONFIG_VP9_POSTPROC ? VPX_CODEC_CAP_POSTPROC : 0) |
32 | | |
33 | | static vpx_codec_err_t decoder_init(vpx_codec_ctx_t *ctx, |
34 | 13.3k | vpx_codec_priv_enc_mr_cfg_t *data) { |
35 | | // This function only allocates space for the vpx_codec_alg_priv_t |
36 | | // structure. More memory may be required at the time the stream |
37 | | // information becomes known. |
38 | 13.3k | (void)data; |
39 | | |
40 | 13.3k | if (!ctx->priv) { |
41 | 13.3k | vpx_codec_alg_priv_t *const priv = |
42 | 13.3k | (vpx_codec_alg_priv_t *)vpx_calloc(1, sizeof(*priv)); |
43 | 13.3k | if (priv == NULL) return VPX_CODEC_MEM_ERROR; |
44 | | |
45 | 13.3k | ctx->priv = (vpx_codec_priv_t *)priv; |
46 | 13.3k | ctx->priv->init_flags = ctx->init_flags; |
47 | 13.3k | priv->si.sz = sizeof(priv->si); |
48 | 13.3k | priv->flushed = 0; |
49 | 13.3k | if (ctx->config.dec) { |
50 | 13.3k | priv->cfg = *ctx->config.dec; |
51 | 13.3k | ctx->config.dec = &priv->cfg; |
52 | 13.3k | } |
53 | 13.3k | } |
54 | | |
55 | 13.3k | return VPX_CODEC_OK; |
56 | 13.3k | } |
57 | | |
58 | 13.3k | static vpx_codec_err_t decoder_destroy(vpx_codec_alg_priv_t *ctx) { |
59 | 13.3k | if (ctx->pbi != NULL) { |
60 | 13.2k | vp9_decoder_remove(ctx->pbi); |
61 | 13.2k | } |
62 | | |
63 | 13.3k | if (ctx->buffer_pool) { |
64 | 13.2k | vp9_free_ref_frame_buffers(ctx->buffer_pool); |
65 | 13.2k | vp9_free_internal_frame_buffers(&ctx->buffer_pool->int_frame_buffers); |
66 | 13.2k | } |
67 | | |
68 | 13.3k | vpx_free(ctx->buffer_pool); |
69 | 13.3k | vpx_free(ctx); |
70 | 13.3k | return VPX_CODEC_OK; |
71 | 13.3k | } |
72 | | |
73 | | static int parse_bitdepth_colorspace_sampling(BITSTREAM_PROFILE profile, |
74 | 12.5k | struct vpx_read_bit_buffer *rb) { |
75 | 12.5k | vpx_color_space_t color_space; |
76 | 12.5k | if (profile >= PROFILE_2) rb->bit_offset += 1; // Bit-depth 10 or 12. |
77 | 12.5k | color_space = (vpx_color_space_t)vpx_rb_read_literal(rb, 3); |
78 | 12.5k | if (color_space != VPX_CS_SRGB) { |
79 | 12.0k | rb->bit_offset += 1; // [16,235] (including xvycc) vs [0,255] range. |
80 | 12.0k | if (profile == PROFILE_1 || profile == PROFILE_3) { |
81 | 6.17k | rb->bit_offset += 2; // subsampling x/y. |
82 | 6.17k | rb->bit_offset += 1; // unused. |
83 | 6.17k | } |
84 | 12.0k | } else { |
85 | 490 | if (profile == PROFILE_1 || profile == PROFILE_3) { |
86 | 41 | rb->bit_offset += 1; // unused |
87 | 449 | } else { |
88 | | // RGB is only available in version 1. |
89 | 449 | return 0; |
90 | 449 | } |
91 | 490 | } |
92 | 12.1k | return 1; |
93 | 12.5k | } |
94 | | |
95 | | static vpx_codec_err_t decoder_peek_si_internal( |
96 | | const uint8_t *data, unsigned int data_sz, vpx_codec_stream_info_t *si, |
97 | 64.2k | int *is_intra_only, vpx_decrypt_cb decrypt_cb, void *decrypt_state) { |
98 | 64.2k | int intra_only_flag = 0; |
99 | 64.2k | uint8_t clear_buffer[11]; |
100 | | |
101 | 64.2k | if (data + data_sz <= data) return VPX_CODEC_INVALID_PARAM; |
102 | | |
103 | 64.0k | si->is_kf = 0; |
104 | 64.0k | si->w = si->h = 0; |
105 | | |
106 | 64.0k | if (decrypt_cb) { |
107 | 0 | data_sz = VPXMIN(sizeof(clear_buffer), data_sz); |
108 | 0 | decrypt_cb(decrypt_state, data, clear_buffer, data_sz); |
109 | 0 | data = clear_buffer; |
110 | 0 | } |
111 | | |
112 | | // A maximum of 6 bits are needed to read the frame marker, profile and |
113 | | // show_existing_frame. |
114 | 64.0k | if (data_sz < 1) return VPX_CODEC_UNSUP_BITSTREAM; |
115 | | |
116 | 64.0k | { |
117 | 64.0k | int show_frame; |
118 | 64.0k | int error_resilient; |
119 | 64.0k | struct vpx_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL }; |
120 | 64.0k | const int frame_marker = vpx_rb_read_literal(&rb, 2); |
121 | 64.0k | const BITSTREAM_PROFILE profile = vp9_read_profile(&rb); |
122 | | |
123 | 64.0k | if (frame_marker != VP9_FRAME_MARKER) return VPX_CODEC_UNSUP_BITSTREAM; |
124 | | |
125 | 31.5k | if (profile >= MAX_PROFILES) return VPX_CODEC_UNSUP_BITSTREAM; |
126 | | |
127 | 31.2k | if (vpx_rb_read_bit(&rb)) { // show an existing frame |
128 | | // If profile is > 2 and show_existing_frame is true, then at least 1 more |
129 | | // byte (6+3=9 bits) is needed. |
130 | 4.60k | if (profile > 2 && data_sz < 2) return VPX_CODEC_UNSUP_BITSTREAM; |
131 | 1.01k | vpx_rb_read_literal(&rb, 3); // Frame buffer to show. |
132 | 1.01k | return VPX_CODEC_OK; |
133 | 4.60k | } |
134 | | |
135 | | // For the rest of the function, a maximum of 9 more bytes are needed |
136 | | // (computed by taking the maximum possible bits needed in each case). Note |
137 | | // that this has to be updated if we read any more bits in this function. |
138 | 26.6k | if (data_sz < 10) return VPX_CODEC_UNSUP_BITSTREAM; |
139 | | |
140 | 16.7k | si->is_kf = !vpx_rb_read_bit(&rb); |
141 | 16.7k | show_frame = vpx_rb_read_bit(&rb); |
142 | 16.7k | error_resilient = vpx_rb_read_bit(&rb); |
143 | | |
144 | 16.7k | if (si->is_kf) { |
145 | 11.1k | if (!vp9_read_sync_code(&rb)) return VPX_CODEC_UNSUP_BITSTREAM; |
146 | | |
147 | 10.6k | if (!parse_bitdepth_colorspace_sampling(profile, &rb)) |
148 | 448 | return VPX_CODEC_UNSUP_BITSTREAM; |
149 | 10.1k | vp9_read_frame_size(&rb, (int *)&si->w, (int *)&si->h); |
150 | 10.1k | } else { |
151 | 5.53k | intra_only_flag = show_frame ? 0 : vpx_rb_read_bit(&rb); |
152 | | |
153 | 5.53k | rb.bit_offset += error_resilient ? 0 : 2; // reset_frame_context |
154 | | |
155 | 5.53k | if (intra_only_flag) { |
156 | 4.99k | if (!vp9_read_sync_code(&rb)) return VPX_CODEC_UNSUP_BITSTREAM; |
157 | 2.56k | if (profile > PROFILE_0) { |
158 | 1.92k | if (!parse_bitdepth_colorspace_sampling(profile, &rb)) |
159 | 1 | return VPX_CODEC_UNSUP_BITSTREAM; |
160 | | // The colorspace info may cause vp9_read_frame_size() to need 11 |
161 | | // bytes. |
162 | 1.92k | if (data_sz < 11) return VPX_CODEC_UNSUP_BITSTREAM; |
163 | 1.92k | } |
164 | 2.51k | rb.bit_offset += REF_FRAMES; // refresh_frame_flags |
165 | 2.51k | vp9_read_frame_size(&rb, (int *)&si->w, (int *)&si->h); |
166 | 2.51k | } |
167 | 5.53k | } |
168 | 16.7k | } |
169 | 13.2k | if (is_intra_only != NULL) *is_intra_only = intra_only_flag; |
170 | 13.2k | return VPX_CODEC_OK; |
171 | 16.7k | } |
172 | | |
173 | | static vpx_codec_err_t decoder_peek_si(const uint8_t *data, |
174 | | unsigned int data_sz, |
175 | 0 | vpx_codec_stream_info_t *si) { |
176 | 0 | return decoder_peek_si_internal(data, data_sz, si, NULL, NULL, NULL); |
177 | 0 | } |
178 | | |
179 | | static vpx_codec_err_t decoder_get_si(vpx_codec_alg_priv_t *ctx, |
180 | 0 | vpx_codec_stream_info_t *si) { |
181 | 0 | const size_t sz = (si->sz >= sizeof(vp9_stream_info_t)) |
182 | 0 | ? sizeof(vp9_stream_info_t) |
183 | 0 | : sizeof(vpx_codec_stream_info_t); |
184 | 0 | memcpy(si, &ctx->si, sz); |
185 | 0 | si->sz = (unsigned int)sz; |
186 | |
|
187 | 0 | return VPX_CODEC_OK; |
188 | 0 | } |
189 | | |
190 | | static void set_error_detail(vpx_codec_alg_priv_t *ctx, |
191 | 378k | const char *const error) { |
192 | 378k | ctx->base.err_detail = error; |
193 | 378k | } |
194 | | |
195 | | static vpx_codec_err_t update_error_state( |
196 | 374k | vpx_codec_alg_priv_t *ctx, const struct vpx_internal_error_info *error) { |
197 | 374k | if (error->error_code) |
198 | 374k | set_error_detail(ctx, error->has_detail ? error->detail : NULL); |
199 | | |
200 | 374k | return error->error_code; |
201 | 374k | } |
202 | | |
203 | 13.2k | static vpx_codec_err_t init_buffer_callbacks(vpx_codec_alg_priv_t *ctx) { |
204 | 13.2k | VP9_COMMON *const cm = &ctx->pbi->common; |
205 | 13.2k | BufferPool *const pool = cm->buffer_pool; |
206 | | |
207 | 13.2k | cm->new_fb_idx = INVALID_IDX; |
208 | 13.2k | cm->byte_alignment = ctx->byte_alignment; |
209 | 13.2k | cm->skip_loop_filter = ctx->skip_loop_filter; |
210 | | |
211 | 13.2k | if (ctx->get_ext_fb_cb != NULL && ctx->release_ext_fb_cb != NULL) { |
212 | 13.2k | pool->get_fb_cb = ctx->get_ext_fb_cb; |
213 | 13.2k | pool->release_fb_cb = ctx->release_ext_fb_cb; |
214 | 13.2k | pool->cb_priv = ctx->ext_priv; |
215 | 13.2k | } else { |
216 | 0 | pool->get_fb_cb = vp9_get_frame_buffer; |
217 | 0 | pool->release_fb_cb = vp9_release_frame_buffer; |
218 | |
|
219 | 0 | if (vp9_alloc_internal_frame_buffers(&pool->int_frame_buffers)) { |
220 | 0 | vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR, |
221 | 0 | "Failed to initialize internal frame buffers"); |
222 | 0 | return VPX_CODEC_MEM_ERROR; |
223 | 0 | } |
224 | | |
225 | 0 | pool->cb_priv = &pool->int_frame_buffers; |
226 | 0 | } |
227 | | |
228 | 13.2k | return VPX_CODEC_OK; |
229 | 13.2k | } |
230 | | |
231 | 0 | static void set_default_ppflags(vp8_postproc_cfg_t *cfg) { |
232 | 0 | cfg->post_proc_flag = VP8_DEBLOCK | VP8_DEMACROBLOCK; |
233 | 0 | cfg->deblocking_level = 4; |
234 | 0 | cfg->noise_level = 0; |
235 | 0 | } |
236 | | |
237 | 0 | static void set_ppflags(const vpx_codec_alg_priv_t *ctx, vp9_ppflags_t *flags) { |
238 | 0 | flags->post_proc_flag = ctx->postproc_cfg.post_proc_flag; |
239 | |
|
240 | 0 | flags->deblocking_level = ctx->postproc_cfg.deblocking_level; |
241 | 0 | flags->noise_level = ctx->postproc_cfg.noise_level; |
242 | 0 | } |
243 | | |
244 | | #undef ERROR |
245 | | #define ERROR(str) \ |
246 | 0 | do { \ |
247 | 0 | ctx->base.err_detail = str; \ |
248 | 0 | return VPX_CODEC_INVALID_PARAM; \ |
249 | 0 | } while (0) |
250 | | |
251 | | #define RANGE_CHECK(p, memb, lo, hi) \ |
252 | 26.5k | do { \ |
253 | 26.5k | if (!(((p)->memb == (lo) || (p)->memb > (lo)) && (p)->memb <= (hi))) \ |
254 | 26.5k | ERROR(#memb " out of range [" #lo ".." #hi "]"); \ |
255 | 26.5k | } while (0) |
256 | | |
257 | 13.2k | static vpx_codec_err_t init_decoder(vpx_codec_alg_priv_t *ctx) { |
258 | 13.2k | vpx_codec_err_t res; |
259 | 13.2k | ctx->last_show_frame = -1; |
260 | 13.2k | ctx->need_resync = 1; |
261 | 13.2k | ctx->flushed = 0; |
262 | | |
263 | 13.2k | ctx->buffer_pool = (BufferPool *)vpx_calloc(1, sizeof(BufferPool)); |
264 | 13.2k | if (ctx->buffer_pool == NULL) return VPX_CODEC_MEM_ERROR; |
265 | | |
266 | 13.2k | ctx->pbi = vp9_decoder_create(ctx->buffer_pool); |
267 | 13.2k | if (ctx->pbi == NULL) { |
268 | 0 | vpx_free(ctx->buffer_pool); |
269 | 0 | ctx->buffer_pool = NULL; |
270 | 0 | set_error_detail(ctx, "Failed to allocate decoder"); |
271 | 0 | return VPX_CODEC_MEM_ERROR; |
272 | 0 | } |
273 | 13.2k | ctx->pbi->max_threads = ctx->cfg.threads; |
274 | 13.2k | ctx->pbi->inv_tile_order = ctx->invert_tile_order; |
275 | | |
276 | 13.2k | RANGE_CHECK(ctx, row_mt, 0, 1); |
277 | 13.2k | ctx->pbi->row_mt = ctx->row_mt; |
278 | | |
279 | 13.2k | RANGE_CHECK(ctx, lpf_opt, 0, 1); |
280 | 13.2k | ctx->pbi->lpf_mt_opt = ctx->lpf_opt; |
281 | | |
282 | | // If postprocessing was enabled by the application and a |
283 | | // configuration has not been provided, default it. |
284 | 13.2k | if (!ctx->postproc_cfg_set && (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)) |
285 | 0 | set_default_ppflags(&ctx->postproc_cfg); |
286 | | |
287 | 13.2k | res = init_buffer_callbacks(ctx); |
288 | 13.2k | if (res != VPX_CODEC_OK) { |
289 | 0 | vpx_free(ctx->buffer_pool); |
290 | 0 | ctx->buffer_pool = NULL; |
291 | 0 | vp9_decoder_remove(ctx->pbi); |
292 | 0 | ctx->pbi = NULL; |
293 | 0 | } |
294 | 13.2k | return res; |
295 | 13.2k | } |
296 | | |
297 | | static INLINE void check_resync(vpx_codec_alg_priv_t *const ctx, |
298 | 140k | const VP9Decoder *const pbi) { |
299 | | // Clear resync flag if the decoder got a key frame or intra only frame. |
300 | 140k | if (ctx->need_resync == 1 && pbi->need_resync == 0 && |
301 | 140k | (pbi->common.intra_only || pbi->common.frame_type == KEY_FRAME)) |
302 | 44.1k | ctx->need_resync = 0; |
303 | 140k | } |
304 | | |
305 | | static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx, |
306 | | const uint8_t **data, unsigned int data_sz, |
307 | 566k | void *user_priv) { |
308 | | // Determine the stream parameters. Note that we rely on peek_si to |
309 | | // validate that we have a buffer that does not wrap around the top |
310 | | // of the heap. |
311 | 566k | if (!ctx->si.h) { |
312 | 64.2k | int is_intra_only = 0; |
313 | 64.2k | const vpx_codec_err_t res = |
314 | 64.2k | decoder_peek_si_internal(*data, data_sz, &ctx->si, &is_intra_only, |
315 | 64.2k | ctx->decrypt_cb, ctx->decrypt_state); |
316 | 64.2k | if (res != VPX_CODEC_OK) return res; |
317 | | |
318 | 14.2k | if (!ctx->si.is_kf && !is_intra_only) return VPX_CODEC_ERROR; |
319 | 14.2k | } |
320 | | |
321 | 515k | ctx->user_priv = user_priv; |
322 | | |
323 | | // Set these even if already initialized. The caller may have changed the |
324 | | // decrypt config between frames. |
325 | 515k | ctx->pbi->decrypt_cb = ctx->decrypt_cb; |
326 | 515k | ctx->pbi->decrypt_state = ctx->decrypt_state; |
327 | | |
328 | 515k | if (vp9_receive_compressed_data(ctx->pbi, data_sz, data)) { |
329 | 374k | ctx->pbi->cur_buf->buf.corrupted = 1; |
330 | 374k | ctx->pbi->need_resync = 1; |
331 | 374k | ctx->need_resync = 1; |
332 | 374k | return update_error_state(ctx, &ctx->pbi->common.error); |
333 | 374k | } |
334 | | |
335 | 140k | check_resync(ctx, ctx->pbi); |
336 | | |
337 | 140k | return VPX_CODEC_OK; |
338 | 515k | } |
339 | | |
340 | | static vpx_codec_err_t decoder_decode(vpx_codec_alg_priv_t *ctx, |
341 | | const uint8_t *data, unsigned int data_sz, |
342 | 444k | void *user_priv) { |
343 | 444k | const uint8_t *data_start = data; |
344 | 444k | vpx_codec_err_t res; |
345 | 444k | uint32_t frame_sizes[8]; |
346 | 444k | int frame_count; |
347 | | |
348 | 444k | if (data == NULL && data_sz == 0) { |
349 | 0 | ctx->flushed = 1; |
350 | 0 | return VPX_CODEC_OK; |
351 | 0 | } |
352 | | |
353 | | // Reset flushed when receiving a valid frame. |
354 | 444k | ctx->flushed = 0; |
355 | | |
356 | | // Initialize the decoder on the first frame. |
357 | 444k | if (ctx->pbi == NULL) { |
358 | 13.2k | res = init_decoder(ctx); |
359 | 13.2k | if (res != VPX_CODEC_OK) return res; |
360 | 13.2k | } |
361 | | |
362 | 444k | res = vp9_parse_superframe_index(data, data_sz, frame_sizes, &frame_count, |
363 | 444k | ctx->decrypt_cb, ctx->decrypt_state); |
364 | 444k | if (res != VPX_CODEC_OK) return res; |
365 | | |
366 | 438k | if (ctx->svc_decoding && ctx->svc_spatial_layer < frame_count - 1) |
367 | 0 | frame_count = ctx->svc_spatial_layer + 1; |
368 | | |
369 | | // Decode in serial mode. |
370 | 438k | if (frame_count > 0) { |
371 | 5.60k | const uint8_t *const data_end = data + data_sz; |
372 | 5.60k | int i; |
373 | | |
374 | 5.69k | for (i = 0; i < frame_count; ++i) { |
375 | 5.69k | const uint8_t *data_start_copy = data_start; |
376 | 5.69k | const uint32_t frame_size = frame_sizes[i]; |
377 | 5.69k | if (data_start < data || frame_size > (uint32_t)(data_end - data_start)) { |
378 | 4.28k | set_error_detail(ctx, "Invalid frame size in index"); |
379 | 4.28k | return VPX_CODEC_CORRUPT_FRAME; |
380 | 4.28k | } |
381 | | |
382 | 1.40k | res = decode_one(ctx, &data_start_copy, frame_size, user_priv); |
383 | 1.40k | if (res != VPX_CODEC_OK) return res; |
384 | | |
385 | 88 | data_start += frame_size; |
386 | 88 | } |
387 | 433k | } else { |
388 | 433k | const uint8_t *const data_end = data + data_sz; |
389 | 574k | while (data_start < data_end) { |
390 | 565k | const uint32_t frame_size = (uint32_t)(data_end - data_start); |
391 | 565k | res = decode_one(ctx, &data_start, frame_size, user_priv); |
392 | 565k | if (res != VPX_CODEC_OK) return res; |
393 | | |
394 | | // Account for suboptimal termination by the encoder. |
395 | 1.31M | while (data_start < data_end) { |
396 | 1.30M | const uint8_t marker = |
397 | 1.30M | read_marker(ctx->decrypt_cb, ctx->decrypt_state, data_start); |
398 | 1.30M | if (marker) break; |
399 | 1.17M | ++data_start; |
400 | 1.17M | } |
401 | 140k | } |
402 | 433k | } |
403 | | |
404 | 8.76k | return res; |
405 | 438k | } |
406 | | |
407 | | static vpx_image_t *decoder_get_frame(vpx_codec_alg_priv_t *ctx, |
408 | 8.76k | vpx_codec_iter_t *iter) { |
409 | 8.76k | vpx_image_t *img = NULL; |
410 | | |
411 | | // Legacy parameter carried over from VP8. Has no effect for VP9 since we |
412 | | // always return only 1 frame per decode call. |
413 | 8.76k | (void)iter; |
414 | | |
415 | 8.76k | if (ctx->pbi != NULL) { |
416 | 8.76k | YV12_BUFFER_CONFIG sd; |
417 | 8.76k | vp9_ppflags_t flags = { 0, 0, 0 }; |
418 | 8.76k | if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) set_ppflags(ctx, &flags); |
419 | 8.76k | if (vp9_get_raw_frame(ctx->pbi, &sd, &flags) == 0) { |
420 | 7.71k | VP9_COMMON *const cm = &ctx->pbi->common; |
421 | 7.71k | RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs; |
422 | 7.71k | ctx->last_show_frame = ctx->pbi->common.new_fb_idx; |
423 | 7.71k | if (ctx->need_resync) return NULL; |
424 | 7.27k | yuvconfig2image(&ctx->img, &sd, ctx->user_priv); |
425 | 7.27k | ctx->img.fb_priv = frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv; |
426 | 7.27k | img = &ctx->img; |
427 | 7.27k | return img; |
428 | 7.71k | } |
429 | 8.76k | } |
430 | 1.04k | return NULL; |
431 | 8.76k | } |
432 | | |
433 | | static vpx_codec_err_t decoder_set_fb_fn( |
434 | | vpx_codec_alg_priv_t *ctx, vpx_get_frame_buffer_cb_fn_t cb_get, |
435 | 13.3k | vpx_release_frame_buffer_cb_fn_t cb_release, void *cb_priv) { |
436 | 13.3k | if (cb_get == NULL || cb_release == NULL) { |
437 | 0 | return VPX_CODEC_INVALID_PARAM; |
438 | 13.3k | } else if (ctx->pbi == NULL) { |
439 | | // If the decoder has already been initialized, do not accept changes to |
440 | | // the frame buffer functions. |
441 | 13.3k | ctx->get_ext_fb_cb = cb_get; |
442 | 13.3k | ctx->release_ext_fb_cb = cb_release; |
443 | 13.3k | ctx->ext_priv = cb_priv; |
444 | 13.3k | return VPX_CODEC_OK; |
445 | 13.3k | } |
446 | | |
447 | 0 | return VPX_CODEC_ERROR; |
448 | 13.3k | } |
449 | | |
450 | | static vpx_codec_err_t ctrl_set_reference(vpx_codec_alg_priv_t *ctx, |
451 | 0 | va_list args) { |
452 | 0 | vpx_ref_frame_t *const data = va_arg(args, vpx_ref_frame_t *); |
453 | |
|
454 | 0 | if (data) { |
455 | 0 | vpx_ref_frame_t *const frame = (vpx_ref_frame_t *)data; |
456 | 0 | YV12_BUFFER_CONFIG sd; |
457 | 0 | image2yuvconfig(&frame->img, &sd); |
458 | 0 | return vp9_set_reference_dec( |
459 | 0 | &ctx->pbi->common, ref_frame_to_vp9_reframe(frame->frame_type), &sd); |
460 | 0 | } else { |
461 | 0 | return VPX_CODEC_INVALID_PARAM; |
462 | 0 | } |
463 | 0 | } |
464 | | |
465 | | static vpx_codec_err_t ctrl_copy_reference(vpx_codec_alg_priv_t *ctx, |
466 | 0 | va_list args) { |
467 | 0 | vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *); |
468 | |
|
469 | 0 | if (data) { |
470 | 0 | vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data; |
471 | 0 | YV12_BUFFER_CONFIG sd; |
472 | 0 | image2yuvconfig(&frame->img, &sd); |
473 | 0 | return vp9_copy_reference_dec(ctx->pbi, (VP9_REFFRAME)frame->frame_type, |
474 | 0 | &sd); |
475 | 0 | } else { |
476 | 0 | return VPX_CODEC_INVALID_PARAM; |
477 | 0 | } |
478 | 0 | } |
479 | | |
480 | | static vpx_codec_err_t ctrl_get_reference(vpx_codec_alg_priv_t *ctx, |
481 | 0 | va_list args) { |
482 | 0 | vp9_ref_frame_t *data = va_arg(args, vp9_ref_frame_t *); |
483 | |
|
484 | 0 | if (data) { |
485 | 0 | if (ctx->pbi) { |
486 | 0 | const int fb_idx = ctx->pbi->common.cur_show_frame_fb_idx; |
487 | 0 | YV12_BUFFER_CONFIG *fb = get_buf_frame(&ctx->pbi->common, fb_idx); |
488 | 0 | if (fb == NULL) return VPX_CODEC_ERROR; |
489 | 0 | yuvconfig2image(&data->img, fb, NULL); |
490 | 0 | return VPX_CODEC_OK; |
491 | 0 | } else { |
492 | 0 | return VPX_CODEC_ERROR; |
493 | 0 | } |
494 | 0 | } else { |
495 | 0 | return VPX_CODEC_INVALID_PARAM; |
496 | 0 | } |
497 | 0 | } |
498 | | |
499 | | static vpx_codec_err_t ctrl_set_postproc(vpx_codec_alg_priv_t *ctx, |
500 | 0 | va_list args) { |
501 | | #if CONFIG_VP9_POSTPROC |
502 | | vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *); |
503 | | |
504 | | if (data) { |
505 | | ctx->postproc_cfg_set = 1; |
506 | | ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data); |
507 | | return VPX_CODEC_OK; |
508 | | } else { |
509 | | return VPX_CODEC_INVALID_PARAM; |
510 | | } |
511 | | #else |
512 | 0 | (void)ctx; |
513 | 0 | (void)args; |
514 | 0 | return VPX_CODEC_INCAPABLE; |
515 | 0 | #endif |
516 | 0 | } |
517 | | |
518 | | static vpx_codec_err_t ctrl_get_quantizer(vpx_codec_alg_priv_t *ctx, |
519 | 0 | va_list args) { |
520 | 0 | int *const arg = va_arg(args, int *); |
521 | 0 | if (arg == NULL || ctx->pbi == NULL) return VPX_CODEC_INVALID_PARAM; |
522 | 0 | *arg = ctx->pbi->common.base_qindex; |
523 | 0 | return VPX_CODEC_OK; |
524 | 0 | } |
525 | | |
526 | | static vpx_codec_err_t ctrl_get_last_ref_updates(vpx_codec_alg_priv_t *ctx, |
527 | 0 | va_list args) { |
528 | 0 | int *const update_info = va_arg(args, int *); |
529 | |
|
530 | 0 | if (update_info) { |
531 | 0 | if (ctx->pbi != NULL) { |
532 | 0 | *update_info = ctx->pbi->refresh_frame_flags; |
533 | 0 | return VPX_CODEC_OK; |
534 | 0 | } else { |
535 | 0 | return VPX_CODEC_ERROR; |
536 | 0 | } |
537 | 0 | } |
538 | | |
539 | 0 | return VPX_CODEC_INVALID_PARAM; |
540 | 0 | } |
541 | | |
542 | | static vpx_codec_err_t ctrl_get_frame_corrupted(vpx_codec_alg_priv_t *ctx, |
543 | 0 | va_list args) { |
544 | 0 | int *corrupted = va_arg(args, int *); |
545 | |
|
546 | 0 | if (corrupted) { |
547 | 0 | if (ctx->pbi != NULL) { |
548 | 0 | RefCntBuffer *const frame_bufs = ctx->pbi->common.buffer_pool->frame_bufs; |
549 | 0 | if (ctx->pbi->common.frame_to_show == NULL) return VPX_CODEC_ERROR; |
550 | 0 | if (ctx->last_show_frame >= 0) |
551 | 0 | *corrupted = frame_bufs[ctx->last_show_frame].buf.corrupted; |
552 | 0 | return VPX_CODEC_OK; |
553 | 0 | } else { |
554 | 0 | return VPX_CODEC_ERROR; |
555 | 0 | } |
556 | 0 | } |
557 | | |
558 | 0 | return VPX_CODEC_INVALID_PARAM; |
559 | 0 | } |
560 | | |
561 | | static vpx_codec_err_t ctrl_get_frame_size(vpx_codec_alg_priv_t *ctx, |
562 | 0 | va_list args) { |
563 | 0 | int *const frame_size = va_arg(args, int *); |
564 | |
|
565 | 0 | if (frame_size) { |
566 | 0 | if (ctx->pbi != NULL) { |
567 | 0 | const VP9_COMMON *const cm = &ctx->pbi->common; |
568 | 0 | frame_size[0] = cm->width; |
569 | 0 | frame_size[1] = cm->height; |
570 | 0 | return VPX_CODEC_OK; |
571 | 0 | } else { |
572 | 0 | return VPX_CODEC_ERROR; |
573 | 0 | } |
574 | 0 | } |
575 | | |
576 | 0 | return VPX_CODEC_INVALID_PARAM; |
577 | 0 | } |
578 | | |
579 | | static vpx_codec_err_t ctrl_get_render_size(vpx_codec_alg_priv_t *ctx, |
580 | 0 | va_list args) { |
581 | 0 | int *const render_size = va_arg(args, int *); |
582 | |
|
583 | 0 | if (render_size) { |
584 | 0 | if (ctx->pbi != NULL) { |
585 | 0 | const VP9_COMMON *const cm = &ctx->pbi->common; |
586 | 0 | render_size[0] = cm->render_width; |
587 | 0 | render_size[1] = cm->render_height; |
588 | 0 | return VPX_CODEC_OK; |
589 | 0 | } else { |
590 | 0 | return VPX_CODEC_ERROR; |
591 | 0 | } |
592 | 0 | } |
593 | | |
594 | 0 | return VPX_CODEC_INVALID_PARAM; |
595 | 0 | } |
596 | | |
597 | | static vpx_codec_err_t ctrl_get_bit_depth(vpx_codec_alg_priv_t *ctx, |
598 | 0 | va_list args) { |
599 | 0 | unsigned int *const bit_depth = va_arg(args, unsigned int *); |
600 | |
|
601 | 0 | if (bit_depth) { |
602 | 0 | if (ctx->pbi != NULL) { |
603 | 0 | const VP9_COMMON *const cm = &ctx->pbi->common; |
604 | 0 | *bit_depth = cm->bit_depth; |
605 | 0 | return VPX_CODEC_OK; |
606 | 0 | } else { |
607 | 0 | return VPX_CODEC_ERROR; |
608 | 0 | } |
609 | 0 | } |
610 | | |
611 | 0 | return VPX_CODEC_INVALID_PARAM; |
612 | 0 | } |
613 | | |
614 | | static vpx_codec_err_t ctrl_set_invert_tile_order(vpx_codec_alg_priv_t *ctx, |
615 | 0 | va_list args) { |
616 | 0 | ctx->invert_tile_order = va_arg(args, int); |
617 | 0 | return VPX_CODEC_OK; |
618 | 0 | } |
619 | | |
620 | | static vpx_codec_err_t ctrl_set_decryptor(vpx_codec_alg_priv_t *ctx, |
621 | 0 | va_list args) { |
622 | 0 | vpx_decrypt_init *init = va_arg(args, vpx_decrypt_init *); |
623 | 0 | ctx->decrypt_cb = init ? init->decrypt_cb : NULL; |
624 | 0 | ctx->decrypt_state = init ? init->decrypt_state : NULL; |
625 | 0 | return VPX_CODEC_OK; |
626 | 0 | } |
627 | | |
628 | | static vpx_codec_err_t ctrl_set_byte_alignment(vpx_codec_alg_priv_t *ctx, |
629 | 0 | va_list args) { |
630 | 0 | const int legacy_byte_alignment = 0; |
631 | 0 | const int min_byte_alignment = 32; |
632 | 0 | const int max_byte_alignment = 1024; |
633 | 0 | const int byte_alignment = va_arg(args, int); |
634 | |
|
635 | 0 | if (byte_alignment != legacy_byte_alignment && |
636 | 0 | (byte_alignment < min_byte_alignment || |
637 | 0 | byte_alignment > max_byte_alignment || |
638 | 0 | (byte_alignment & (byte_alignment - 1)) != 0)) |
639 | 0 | return VPX_CODEC_INVALID_PARAM; |
640 | | |
641 | 0 | ctx->byte_alignment = byte_alignment; |
642 | 0 | if (ctx->pbi != NULL) { |
643 | 0 | ctx->pbi->common.byte_alignment = byte_alignment; |
644 | 0 | } |
645 | 0 | return VPX_CODEC_OK; |
646 | 0 | } |
647 | | |
648 | | static vpx_codec_err_t ctrl_set_skip_loop_filter(vpx_codec_alg_priv_t *ctx, |
649 | 0 | va_list args) { |
650 | 0 | ctx->skip_loop_filter = va_arg(args, int); |
651 | |
|
652 | 0 | if (ctx->pbi != NULL) { |
653 | 0 | ctx->pbi->common.skip_loop_filter = ctx->skip_loop_filter; |
654 | 0 | } |
655 | |
|
656 | 0 | return VPX_CODEC_OK; |
657 | 0 | } |
658 | | |
659 | | static vpx_codec_err_t ctrl_set_spatial_layer_svc(vpx_codec_alg_priv_t *ctx, |
660 | 0 | va_list args) { |
661 | 0 | ctx->svc_decoding = 1; |
662 | 0 | ctx->svc_spatial_layer = va_arg(args, int); |
663 | 0 | if (ctx->svc_spatial_layer < 0) |
664 | 0 | return VPX_CODEC_INVALID_PARAM; |
665 | 0 | else |
666 | 0 | return VPX_CODEC_OK; |
667 | 0 | } |
668 | | |
669 | | static vpx_codec_err_t ctrl_set_row_mt(vpx_codec_alg_priv_t *ctx, |
670 | 0 | va_list args) { |
671 | 0 | ctx->row_mt = va_arg(args, int); |
672 | |
|
673 | 0 | return VPX_CODEC_OK; |
674 | 0 | } |
675 | | |
676 | | static vpx_codec_err_t ctrl_enable_lpf_opt(vpx_codec_alg_priv_t *ctx, |
677 | 0 | va_list args) { |
678 | 0 | ctx->lpf_opt = va_arg(args, int); |
679 | |
|
680 | 0 | return VPX_CODEC_OK; |
681 | 0 | } |
682 | | |
683 | | static vpx_codec_ctrl_fn_map_t decoder_ctrl_maps[] = { |
684 | | { VP8_COPY_REFERENCE, ctrl_copy_reference }, |
685 | | |
686 | | // Setters |
687 | | { VP8_SET_REFERENCE, ctrl_set_reference }, |
688 | | { VP8_SET_POSTPROC, ctrl_set_postproc }, |
689 | | { VP9_INVERT_TILE_DECODE_ORDER, ctrl_set_invert_tile_order }, |
690 | | { VPXD_SET_DECRYPTOR, ctrl_set_decryptor }, |
691 | | { VP9_SET_BYTE_ALIGNMENT, ctrl_set_byte_alignment }, |
692 | | { VP9_SET_SKIP_LOOP_FILTER, ctrl_set_skip_loop_filter }, |
693 | | { VP9_DECODE_SVC_SPATIAL_LAYER, ctrl_set_spatial_layer_svc }, |
694 | | { VP9D_SET_ROW_MT, ctrl_set_row_mt }, |
695 | | { VP9D_SET_LOOP_FILTER_OPT, ctrl_enable_lpf_opt }, |
696 | | |
697 | | // Getters |
698 | | { VPXD_GET_LAST_QUANTIZER, ctrl_get_quantizer }, |
699 | | { VP8D_GET_LAST_REF_UPDATES, ctrl_get_last_ref_updates }, |
700 | | { VP8D_GET_FRAME_CORRUPTED, ctrl_get_frame_corrupted }, |
701 | | { VP9_GET_REFERENCE, ctrl_get_reference }, |
702 | | { VP9D_GET_DISPLAY_SIZE, ctrl_get_render_size }, |
703 | | { VP9D_GET_BIT_DEPTH, ctrl_get_bit_depth }, |
704 | | { VP9D_GET_FRAME_SIZE, ctrl_get_frame_size }, |
705 | | |
706 | | { -1, NULL }, |
707 | | }; |
708 | | |
709 | | #ifndef VERSION_STRING |
710 | | #define VERSION_STRING |
711 | | #endif |
712 | | CODEC_INTERFACE(vpx_codec_vp9_dx) = { |
713 | | "WebM Project VP9 Decoder" VERSION_STRING, |
714 | | VPX_CODEC_INTERNAL_ABI_VERSION, |
715 | | #if CONFIG_VP9_HIGHBITDEPTH |
716 | | VPX_CODEC_CAP_HIGHBITDEPTH | |
717 | | #endif |
718 | | VPX_CODEC_CAP_DECODER | VP9_CAP_POSTPROC | |
719 | | VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER, // vpx_codec_caps_t |
720 | | decoder_init, // vpx_codec_init_fn_t |
721 | | decoder_destroy, // vpx_codec_destroy_fn_t |
722 | | decoder_ctrl_maps, // vpx_codec_ctrl_fn_map_t |
723 | | { |
724 | | // NOLINT |
725 | | decoder_peek_si, // vpx_codec_peek_si_fn_t |
726 | | decoder_get_si, // vpx_codec_get_si_fn_t |
727 | | decoder_decode, // vpx_codec_decode_fn_t |
728 | | decoder_get_frame, // vpx_codec_frame_get_fn_t |
729 | | decoder_set_fb_fn, // vpx_codec_set_fb_fn_t |
730 | | }, |
731 | | { |
732 | | // NOLINT |
733 | | 0, |
734 | | NULL, // vpx_codec_enc_cfg_map_t |
735 | | NULL, // vpx_codec_encode_fn_t |
736 | | NULL, // vpx_codec_get_cx_data_fn_t |
737 | | NULL, // vpx_codec_enc_config_set_fn_t |
738 | | NULL, // vpx_codec_get_global_headers_fn_t |
739 | | NULL, // vpx_codec_get_preview_frame_fn_t |
740 | | NULL, // vpx_codec_enc_mr_get_mem_loc_fn_t |
741 | | NULL // vpx_codec_enc_mr_free_mem_loc_fn_t |
742 | | } |
743 | | }; |