| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * This file is part of FFmpeg. | ||
| 3 | * | ||
| 4 | * FFmpeg is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU Lesser General Public | ||
| 6 | * License as published by the Free Software Foundation; either | ||
| 7 | * version 2.1 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 12 | * Lesser General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU Lesser General Public | ||
| 15 | * License along with FFmpeg; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include "libavutil/avassert.h" | ||
| 20 | |||
| 21 | #include "cbs.h" | ||
| 22 | #include "cbs_internal.h" | ||
| 23 | #include "cbs_vp8.h" | ||
| 24 | |||
| 25 | #include <stdbool.h> | ||
| 26 | |||
| 27 | #define DEFAULT_PROB 0x80 | ||
| 28 | |||
| 29 | // The probability table is defined in 'vp8data.c'. | ||
| 30 | extern const uint8_t ff_vp8_token_update_probs[4][8][3][11]; | ||
| 31 | |||
| 32 | // Implements VP8 boolean decoder using GetBitContext to read the bitstream. | ||
| 33 | typedef struct CBSVP8BoolDecoder { | ||
| 34 | GetBitContext *gbc; | ||
| 35 | |||
| 36 | uint8_t value; | ||
| 37 | uint8_t range; | ||
| 38 | |||
| 39 | uint8_t count; // Store the number of bits in the `value` buffer. | ||
| 40 | |||
| 41 | } CBSVP8BoolDecoder; | ||
| 42 | |||
| 43 | ✗ | static int cbs_vp8_bool_decoder_init(CBSVP8BoolDecoder *decoder, GetBitContext *gbc) | |
| 44 | { | ||
| 45 | ✗ | av_assert0(decoder); | |
| 46 | ✗ | av_assert0(gbc); | |
| 47 | |||
| 48 | ✗ | decoder->gbc = gbc; | |
| 49 | ✗ | decoder->value = 0; | |
| 50 | ✗ | decoder->range = 255; | |
| 51 | |||
| 52 | ✗ | decoder->count = 0; | |
| 53 | |||
| 54 | ✗ | return 0; | |
| 55 | } | ||
| 56 | |||
| 57 | ✗ | static bool cbs_vp8_bool_decoder_fill_value(CBSVP8BoolDecoder *decoder) | |
| 58 | { | ||
| 59 | ✗ | int bits = 8 - decoder->count; | |
| 60 | |||
| 61 | ✗ | av_assert0(decoder->count <= 8); | |
| 62 | ✗ | if (decoder->count == 8) { | |
| 63 | ✗ | return true; | |
| 64 | } | ||
| 65 | |||
| 66 | ✗ | if (get_bits_left(decoder->gbc) >= bits) { | |
| 67 | ✗ | decoder->value |= get_bits(decoder->gbc, bits); | |
| 68 | ✗ | decoder->count += bits; | |
| 69 | } | ||
| 70 | |||
| 71 | ✗ | return (decoder->count == 8); | |
| 72 | } | ||
| 73 | |||
| 74 | ✗ | static int cbs_vp8_bool_decoder_read_bool(CBSVP8BoolDecoder *decoder, | |
| 75 | const uint8_t prob, uint8_t *output) | ||
| 76 | { | ||
| 77 | ✗ | uint8_t split = 1 + (((decoder->range - 1) * prob) >> 8); | |
| 78 | |||
| 79 | ✗ | if (!cbs_vp8_bool_decoder_fill_value(decoder)) { | |
| 80 | ✗ | return AVERROR_INVALIDDATA; | |
| 81 | } | ||
| 82 | |||
| 83 | ✗ | av_assert0(decoder->count == 8); | |
| 84 | ✗ | if (decoder->value >= split) { | |
| 85 | ✗ | *output = 1; | |
| 86 | ✗ | decoder->range -= split; | |
| 87 | ✗ | decoder->value -= split; | |
| 88 | } else { | ||
| 89 | ✗ | *output = 0; | |
| 90 | ✗ | decoder->range = split; | |
| 91 | } | ||
| 92 | |||
| 93 | ✗ | while (decoder->range < 128) { | |
| 94 | ✗ | decoder->value <<= 1; | |
| 95 | ✗ | decoder->range <<= 1; | |
| 96 | ✗ | --decoder->count; | |
| 97 | } | ||
| 98 | |||
| 99 | ✗ | return 0; | |
| 100 | } | ||
| 101 | |||
| 102 | ✗ | static int cbs_vp8_bool_decoder_read_literal(CBSVP8BoolDecoder *decoder, | |
| 103 | const uint8_t prob, | ||
| 104 | uint32_t num_bits, | ||
| 105 | uint32_t *output) | ||
| 106 | { | ||
| 107 | ✗ | int ret = 0; | |
| 108 | |||
| 109 | ✗ | av_assert0(num_bits <= 32); | |
| 110 | |||
| 111 | ✗ | *output = 0; | |
| 112 | ✗ | for (; num_bits > 0; --num_bits) { | |
| 113 | ✗ | uint8_t bit_output = 0; | |
| 114 | ✗ | if ((ret = cbs_vp8_bool_decoder_read_bool(decoder, prob, | |
| 115 | &bit_output)) != 0) { | ||
| 116 | ✗ | return ret; | |
| 117 | } | ||
| 118 | |||
| 119 | ✗ | *output = (*output << 1) | bit_output; | |
| 120 | } | ||
| 121 | |||
| 122 | ✗ | return 0; | |
| 123 | } | ||
| 124 | |||
| 125 | ✗ | static int cbs_vp8_bool_decoder_read_unsigned( | |
| 126 | CodedBitstreamContext *ctx, CBSVP8BoolDecoder *bool_decoder, int width, | ||
| 127 | uint8_t prob, const char *name, const int *subscripts, uint32_t *write_to, | ||
| 128 | bool trace_enable) | ||
| 129 | { | ||
| 130 | ✗ | int ret = 0; | |
| 131 | ✗ | GetBitContext *gbc = bool_decoder->gbc; | |
| 132 | uint32_t value; | ||
| 133 | |||
| 134 | ✗ | CBS_TRACE_READ_START(); | |
| 135 | |||
| 136 | ✗ | av_assert0(width >= 0 && width <= 8); | |
| 137 | |||
| 138 | ✗ | ret = cbs_vp8_bool_decoder_read_literal(bool_decoder, prob, width, &value); | |
| 139 | ✗ | if (ret != 0) { | |
| 140 | ✗ | return ret; | |
| 141 | } | ||
| 142 | |||
| 143 | ✗ | if (trace_enable) { | |
| 144 | ✗ | CBS_TRACE_READ_END(); | |
| 145 | } | ||
| 146 | |||
| 147 | ✗ | *write_to = value; | |
| 148 | ✗ | return 0; | |
| 149 | } | ||
| 150 | |||
| 151 | ✗ | static int cbs_vp8_bool_decoder_read_signed( | |
| 152 | CodedBitstreamContext *ctx, CBSVP8BoolDecoder *bool_decoder, int width, | ||
| 153 | uint8_t prob, const char *name, const int *subscripts, int32_t *write_to) | ||
| 154 | { | ||
| 155 | ✗ | int ret = 0; | |
| 156 | ✗ | GetBitContext *gbc = bool_decoder->gbc; | |
| 157 | int32_t value; | ||
| 158 | ✗ | uint8_t sign = 0; | |
| 159 | |||
| 160 | ✗ | CBS_TRACE_READ_START(); | |
| 161 | |||
| 162 | ✗ | av_assert0(width >= 0 && width <= 8); | |
| 163 | |||
| 164 | ✗ | ret = cbs_vp8_bool_decoder_read_literal(bool_decoder, prob, width, &value); | |
| 165 | ✗ | if (ret != 0) { | |
| 166 | ✗ | return ret; | |
| 167 | } | ||
| 168 | |||
| 169 | ✗ | ret = cbs_vp8_bool_decoder_read_bool(bool_decoder, prob, &sign); | |
| 170 | ✗ | if (ret != 0) { | |
| 171 | ✗ | return ret; | |
| 172 | } | ||
| 173 | |||
| 174 | ✗ | if (sign) { | |
| 175 | ✗ | value = -value; | |
| 176 | } | ||
| 177 | |||
| 178 | ✗ | CBS_TRACE_READ_END(); | |
| 179 | |||
| 180 | ✗ | *write_to = value; | |
| 181 | ✗ | return 0; | |
| 182 | } | ||
| 183 | |||
| 184 | ✗ | static int cbs_vp8_read_unsigned_le(CodedBitstreamContext *ctx, | |
| 185 | GetBitContext *gbc, int width, | ||
| 186 | const char *name, const int *subscripts, | ||
| 187 | uint32_t *write_to, uint32_t range_min, | ||
| 188 | uint32_t range_max) | ||
| 189 | { | ||
| 190 | int32_t value; | ||
| 191 | |||
| 192 | ✗ | CBS_TRACE_READ_START(); | |
| 193 | |||
| 194 | ✗ | av_assert0(width > 0 && width <= 24); | |
| 195 | |||
| 196 | ✗ | if (get_bits_left(gbc) < width) { | |
| 197 | ✗ | av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid value: bitstream ended.\n"); | |
| 198 | ✗ | return AVERROR_INVALIDDATA; | |
| 199 | } | ||
| 200 | |||
| 201 | ✗ | value = get_bits_le(gbc, width); | |
| 202 | |||
| 203 | ✗ | CBS_TRACE_READ_END(); | |
| 204 | |||
| 205 | ✗ | if (value < range_min || value > range_max) { | |
| 206 | ✗ | av_log(ctx->log_ctx, AV_LOG_ERROR, | |
| 207 | "%s out of range: " | ||
| 208 | "%" PRIu32 ", but must be in [%" PRIu32 ",%" PRIu32 "].\n", | ||
| 209 | name, value, range_min, range_max); | ||
| 210 | ✗ | return AVERROR_INVALIDDATA; | |
| 211 | } | ||
| 212 | |||
| 213 | ✗ | *write_to = value; | |
| 214 | ✗ | return 0; | |
| 215 | } | ||
| 216 | |||
| 217 | #define HEADER(name) \ | ||
| 218 | do { \ | ||
| 219 | ff_cbs_trace_header(ctx, name); \ | ||
| 220 | } while (0) | ||
| 221 | |||
| 222 | #define CHECK(call) \ | ||
| 223 | do { \ | ||
| 224 | int err = (call); \ | ||
| 225 | if (err < 0) \ | ||
| 226 | return err; \ | ||
| 227 | } while (0) | ||
| 228 | |||
| 229 | #define FUNC_NAME(rw, codec, name) cbs_##codec##_##rw##_##name | ||
| 230 | #define FUNC_VP8(rw, name) FUNC_NAME(rw, vp8, name) | ||
| 231 | #define FUNC(name) FUNC_VP8(READWRITE, name) | ||
| 232 | |||
| 233 | #define SUBSCRIPTS(subs, ...) \ | ||
| 234 | (subs > 0 ? ((int[subs + 1]){subs, __VA_ARGS__}) : NULL) | ||
| 235 | |||
| 236 | #define f(width, name) xf(width, name, 0, ) | ||
| 237 | |||
| 238 | // bool [de|en]coder methods. | ||
| 239 | #define bc_f(width, name) bc_unsigned_subs(width, DEFAULT_PROB, true, name, 0, ) | ||
| 240 | #define bc_s(width, name) bc_signed_subs(width, DEFAULT_PROB, name, 0, ) | ||
| 241 | #define bc_fs(width, name, subs, ...) \ | ||
| 242 | bc_unsigned_subs(width, DEFAULT_PROB, true, name, subs, __VA_ARGS__) | ||
| 243 | #define bc_ss(width, name, subs, ...) \ | ||
| 244 | bc_signed_subs(width, DEFAULT_PROB, name, subs, __VA_ARGS__) | ||
| 245 | |||
| 246 | // bool [de|en]coder methods for boolean value and disable tracing. | ||
| 247 | #define bc_b(name) bc_unsigned_subs(1, DEFAULT_PROB, false, name, 0, ) | ||
| 248 | #define bc_b_prob(prob, name) bc_unsigned_subs(1, prob, false, name, 0, ) | ||
| 249 | |||
| 250 | #define READ | ||
| 251 | #define READWRITE read | ||
| 252 | #define RWContext GetBitContext | ||
| 253 | #define CBSVP8BoolCodingRW CBSVP8BoolDecoder | ||
| 254 | |||
| 255 | #define xf(width, name, subs, ...) \ | ||
| 256 | do { \ | ||
| 257 | uint32_t value; \ | ||
| 258 | CHECK(cbs_vp8_read_unsigned_le(ctx, rw, width, #name, \ | ||
| 259 | SUBSCRIPTS(subs, __VA_ARGS__), &value, \ | ||
| 260 | 0, MAX_UINT_BITS(width))); \ | ||
| 261 | current->name = value; \ | ||
| 262 | } while (0) | ||
| 263 | |||
| 264 | #define fixed(width, name, value) \ | ||
| 265 | do { \ | ||
| 266 | uint32_t fixed_value; \ | ||
| 267 | CHECK(cbs_vp8_read_unsigned_le(ctx, rw, width, #name, 0, &fixed_value, \ | ||
| 268 | value, value)); \ | ||
| 269 | } while (0) | ||
| 270 | |||
| 271 | #define bc_unsigned_subs(width, prob, enable_trace, name, subs, ...) \ | ||
| 272 | do { \ | ||
| 273 | uint32_t value; \ | ||
| 274 | CHECK(cbs_vp8_bool_decoder_read_unsigned( \ | ||
| 275 | ctx, bool_coding_rw, width, prob, #name, \ | ||
| 276 | SUBSCRIPTS(subs, __VA_ARGS__), &value, enable_trace)); \ | ||
| 277 | current->name = value; \ | ||
| 278 | } while (0) | ||
| 279 | |||
| 280 | #define bc_signed_subs(width, prob, name, subs, ...) \ | ||
| 281 | do { \ | ||
| 282 | int32_t value; \ | ||
| 283 | CHECK(cbs_vp8_bool_decoder_read_signed( \ | ||
| 284 | ctx, bool_coding_rw, width, prob, #name, \ | ||
| 285 | SUBSCRIPTS(subs, __VA_ARGS__), &value)); \ | ||
| 286 | current->name = value; \ | ||
| 287 | } while (0) | ||
| 288 | |||
| 289 | #include "cbs_vp8_syntax_template.c" | ||
| 290 | |||
| 291 | ✗ | static int cbs_vp8_split_fragment(CodedBitstreamContext *ctx, | |
| 292 | CodedBitstreamFragment *frag, int header) | ||
| 293 | { | ||
| 294 | int err; | ||
| 295 | |||
| 296 | ✗ | if (frag->data_size == 0) | |
| 297 | ✗ | return AVERROR_INVALIDDATA; | |
| 298 | |||
| 299 | ✗ | err = ff_cbs_append_unit_data(frag, 0, frag->data, frag->data_size, | |
| 300 | frag->data_ref); | ||
| 301 | ✗ | if (err < 0) | |
| 302 | ✗ | return err; | |
| 303 | |||
| 304 | ✗ | return 0; | |
| 305 | } | ||
| 306 | |||
| 307 | ✗ | static int cbs_vp8_read_unit(CodedBitstreamContext *ctx, | |
| 308 | CodedBitstreamUnit *unit) | ||
| 309 | { | ||
| 310 | VP8RawFrame *frame; | ||
| 311 | GetBitContext gbc; | ||
| 312 | CBSVP8BoolDecoder bool_decoder; | ||
| 313 | int err, pos; | ||
| 314 | |||
| 315 | ✗ | err = ff_cbs_alloc_unit_content(ctx, unit); | |
| 316 | ✗ | if (err < 0) | |
| 317 | ✗ | return err; | |
| 318 | ✗ | frame = unit->content; | |
| 319 | |||
| 320 | // Create GetBitContext for uncompressed header. | ||
| 321 | ✗ | err = init_get_bits8_le(&gbc, unit->data, unit->data_size); | |
| 322 | ✗ | if (err < 0) | |
| 323 | ✗ | return err; | |
| 324 | |||
| 325 | ✗ | err = cbs_vp8_read_uncompressed_header(ctx, &gbc, frame); | |
| 326 | ✗ | if (err < 0) | |
| 327 | ✗ | return err; | |
| 328 | |||
| 329 | ✗ | pos = get_bits_count(&gbc); | |
| 330 | ✗ | av_assert0(pos % 8 == 0); | |
| 331 | |||
| 332 | // Create boolean decoder for compressed header. | ||
| 333 | ✗ | err = cbs_vp8_bool_decoder_init(&bool_decoder, &gbc); | |
| 334 | ✗ | if (err < 0) | |
| 335 | ✗ | return err; | |
| 336 | |||
| 337 | ✗ | err = cbs_vp8_read_compressed_header(ctx, &bool_decoder, frame); | |
| 338 | ✗ | if (err < 0) | |
| 339 | ✗ | return err; | |
| 340 | |||
| 341 | ✗ | pos = get_bits_count(&gbc); | |
| 342 | // Position may not be byte-aligned after compressed header; Round up byte | ||
| 343 | // count for accurate data positioning. | ||
| 344 | ✗ | pos = (pos + 7) / 8; | |
| 345 | ✗ | av_assert0(pos <= unit->data_size); | |
| 346 | |||
| 347 | ✗ | frame->data_ref = av_buffer_ref(unit->data_ref); | |
| 348 | ✗ | if (!frame->data_ref) | |
| 349 | ✗ | return AVERROR(ENOMEM); | |
| 350 | |||
| 351 | ✗ | frame->data = unit->data + pos; | |
| 352 | ✗ | frame->data_size = unit->data_size - pos; | |
| 353 | |||
| 354 | ✗ | return 0; | |
| 355 | } | ||
| 356 | |||
| 357 | ✗ | static int cbs_vp8_write_unit(CodedBitstreamContext *ctx, | |
| 358 | CodedBitstreamUnit *unit, PutBitContext *pbc) | ||
| 359 | { | ||
| 360 | ✗ | return AVERROR_PATCHWELCOME; | |
| 361 | } | ||
| 362 | |||
| 363 | ✗ | static int cbs_vp8_assemble_fragment(CodedBitstreamContext *ctx, | |
| 364 | CodedBitstreamFragment *frag) | ||
| 365 | { | ||
| 366 | ✗ | return AVERROR_PATCHWELCOME; | |
| 367 | } | ||
| 368 | |||
| 369 | static CodedBitstreamUnitTypeDescriptor cbs_vp8_unit_types[] = { | ||
| 370 | CBS_UNIT_TYPE_INTERNAL_REF(0, VP8RawFrame, data), | ||
| 371 | CBS_UNIT_TYPE_END_OF_LIST, | ||
| 372 | }; | ||
| 373 | |||
| 374 | const CodedBitstreamType ff_cbs_type_vp8 = { | ||
| 375 | .codec_id = AV_CODEC_ID_VP8, | ||
| 376 | |||
| 377 | .priv_data_size = 0, | ||
| 378 | |||
| 379 | .unit_types = cbs_vp8_unit_types, | ||
| 380 | |||
| 381 | .split_fragment = &cbs_vp8_split_fragment, | ||
| 382 | .read_unit = &cbs_vp8_read_unit, | ||
| 383 | .write_unit = &cbs_vp8_write_unit, | ||
| 384 | |||
| 385 | .assemble_fragment = &cbs_vp8_assemble_fragment, | ||
| 386 | }; | ||
| 387 |