| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * MagicYUV decoder | ||
| 3 | * Copyright (c) 2016 Paul B Mahol | ||
| 4 | * | ||
| 5 | * This file is part of FFmpeg. | ||
| 6 | * | ||
| 7 | * FFmpeg is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU Lesser General Public | ||
| 9 | * License as published by the Free Software Foundation; either | ||
| 10 | * version 2.1 of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public | ||
| 18 | * License along with FFmpeg; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <stdlib.h> | ||
| 23 | #include <string.h> | ||
| 24 | |||
| 25 | #define CACHED_BITSTREAM_READER !ARCH_X86_32 | ||
| 26 | |||
| 27 | #include "libavutil/mem.h" | ||
| 28 | #include "libavutil/pixdesc.h" | ||
| 29 | |||
| 30 | #include "avcodec.h" | ||
| 31 | #include "bytestream.h" | ||
| 32 | #include "codec_internal.h" | ||
| 33 | #include "decode.h" | ||
| 34 | #include "get_bits.h" | ||
| 35 | #include "lossless_videodsp.h" | ||
| 36 | #include "thread.h" | ||
| 37 | |||
| 38 | #define VLC_BITS 12 | ||
| 39 | |||
| 40 | typedef struct Slice { | ||
| 41 | uint32_t start; | ||
| 42 | uint32_t size; | ||
| 43 | } Slice; | ||
| 44 | |||
| 45 | typedef enum Prediction { | ||
| 46 | LEFT = 1, | ||
| 47 | GRADIENT, | ||
| 48 | MEDIAN, | ||
| 49 | } Prediction; | ||
| 50 | |||
| 51 | typedef struct HuffEntry { | ||
| 52 | uint8_t len; | ||
| 53 | uint16_t sym; | ||
| 54 | } HuffEntry; | ||
| 55 | |||
| 56 | typedef struct MagicYUVContext { | ||
| 57 | AVFrame *p; | ||
| 58 | int max; | ||
| 59 | int bps; | ||
| 60 | int slice_height; | ||
| 61 | int nb_slices; | ||
| 62 | int planes; // number of encoded planes in bitstream | ||
| 63 | int decorrelate; // postprocessing work | ||
| 64 | int color_matrix; // video color matrix | ||
| 65 | int flags; | ||
| 66 | int interlaced; // video is interlaced | ||
| 67 | const uint8_t *buf; // pointer to AVPacket->data | ||
| 68 | int hshift[4]; | ||
| 69 | int vshift[4]; | ||
| 70 | Slice *slices[4]; // slice bitstream positions for each plane | ||
| 71 | unsigned int slices_size[4]; // slice sizes for each plane | ||
| 72 | VLC vlc[4]; // VLC for each plane | ||
| 73 | VLC_MULTI multi[4]; // Buffer for joint VLC data | ||
| 74 | int (*magy_decode_slice)(AVCodecContext *avctx, void *tdata, | ||
| 75 | int j, int threadnr); | ||
| 76 | LLVidDSPContext llviddsp; | ||
| 77 | HuffEntry he[1 << 14]; | ||
| 78 | uint8_t len[1 << 14]; | ||
| 79 | } MagicYUVContext; | ||
| 80 | |||
| 81 | 552 | static int huff_build(AVCodecContext *avctx, | |
| 82 | const uint8_t len[], uint16_t codes_pos[33], | ||
| 83 | VLC *vlc, VLC_MULTI *multi, int nb_elems, void *logctx) | ||
| 84 | { | ||
| 85 | 552 | MagicYUVContext *s = avctx->priv_data; | |
| 86 | 552 | HuffEntry *he = s->he; | |
| 87 | |||
| 88 |
2/2✓ Branch 0 taken 17112 times.
✓ Branch 1 taken 552 times.
|
17664 | for (int i = 31; i > 0; i--) |
| 89 | 17112 | codes_pos[i] += codes_pos[i + 1]; | |
| 90 | |||
| 91 |
2/2✓ Branch 0 taken 141312 times.
✓ Branch 1 taken 552 times.
|
141864 | for (unsigned i = nb_elems; i-- > 0;) |
| 92 | 141312 | he[--codes_pos[len[i]]] = (HuffEntry){ len[i], i }; | |
| 93 | |||
| 94 | 552 | ff_vlc_free(vlc); | |
| 95 | 552 | ff_vlc_free_multi(multi); | |
| 96 | 1104 | return ff_vlc_init_multi_from_lengths(vlc, multi, FFMIN(he[0].len, VLC_BITS), nb_elems, nb_elems, | |
| 97 | 552 | &he[0].len, sizeof(he[0]), | |
| 98 | 552 | &he[0].sym, sizeof(he[0]), sizeof(he[0].sym), | |
| 99 | 0, 0, logctx); | ||
| 100 | } | ||
| 101 | |||
| 102 | ✗ | static void magicyuv_median_pred16(uint16_t *dst, const uint16_t *src1, | |
| 103 | const uint16_t *diff, intptr_t w, | ||
| 104 | int *left, int *left_top, int max) | ||
| 105 | { | ||
| 106 | int i; | ||
| 107 | uint16_t l, lt; | ||
| 108 | |||
| 109 | ✗ | l = *left; | |
| 110 | ✗ | lt = *left_top; | |
| 111 | |||
| 112 | ✗ | for (i = 0; i < w; i++) { | |
| 113 | ✗ | l = mid_pred(l, src1[i], (l + src1[i] - lt)) + diff[i]; | |
| 114 | ✗ | l &= max; | |
| 115 | ✗ | lt = src1[i]; | |
| 116 | ✗ | dst[i] = l; | |
| 117 | } | ||
| 118 | |||
| 119 | ✗ | *left = l; | |
| 120 | ✗ | *left_top = lt; | |
| 121 | ✗ | } | |
| 122 | |||
| 123 | #define READ_PLANE(dst, plane, b, c) \ | ||
| 124 | { \ | ||
| 125 | x = 0; \ | ||
| 126 | for (; CACHED_BITSTREAM_READER && x < width-c && get_bits_left(&gb) > 0;) {\ | ||
| 127 | ret = get_vlc_multi(&gb, (uint8_t *)dst + x * b, multi, \ | ||
| 128 | vlc, vlc_bits, 3, b); \ | ||
| 129 | if (ret <= 0) \ | ||
| 130 | return AVERROR_INVALIDDATA; \ | ||
| 131 | x += ret; \ | ||
| 132 | } \ | ||
| 133 | for (; x < width && get_bits_left(&gb) > 0; x++) \ | ||
| 134 | dst[x] = get_vlc2(&gb, vlc, vlc_bits, 3); \ | ||
| 135 | dst += stride; \ | ||
| 136 | } | ||
| 137 | |||
| 138 | ✗ | static int magy_decode_slice10(AVCodecContext *avctx, void *tdata, | |
| 139 | int j, int threadnr) | ||
| 140 | { | ||
| 141 | ✗ | const MagicYUVContext *s = avctx->priv_data; | |
| 142 | ✗ | int interlaced = s->interlaced; | |
| 143 | ✗ | const int bps = s->bps; | |
| 144 | ✗ | const int max = s->max - 1; | |
| 145 | ✗ | AVFrame *p = s->p; | |
| 146 | int i, k, x; | ||
| 147 | GetBitContext gb; | ||
| 148 | uint16_t *dst; | ||
| 149 | |||
| 150 | ✗ | for (i = 0; i < s->planes; i++) { | |
| 151 | int left, lefttop, top; | ||
| 152 | ✗ | int height = AV_CEIL_RSHIFT(FFMIN(s->slice_height, avctx->coded_height - j * s->slice_height), s->vshift[i]); | |
| 153 | ✗ | int width = AV_CEIL_RSHIFT(avctx->coded_width, s->hshift[i]); | |
| 154 | ✗ | int sheight = AV_CEIL_RSHIFT(s->slice_height, s->vshift[i]); | |
| 155 | ✗ | ptrdiff_t fake_stride = (p->linesize[i] / 2) * (1 + interlaced); | |
| 156 | ✗ | ptrdiff_t stride = p->linesize[i] / 2; | |
| 157 | ✗ | const VLC_MULTI_ELEM *const multi = s->multi[i].table; | |
| 158 | ✗ | const VLCElem *const vlc = s->vlc[i].table; | |
| 159 | ✗ | const int vlc_bits = s->vlc[i].bits; | |
| 160 | int flags, pred; | ||
| 161 | ✗ | int ret = init_get_bits8(&gb, s->buf + s->slices[i][j].start, | |
| 162 | ✗ | s->slices[i][j].size); | |
| 163 | |||
| 164 | ✗ | if (ret < 0) | |
| 165 | ✗ | return ret; | |
| 166 | |||
| 167 | ✗ | flags = get_bits(&gb, 8); | |
| 168 | ✗ | pred = get_bits(&gb, 8); | |
| 169 | |||
| 170 | ✗ | dst = (uint16_t *)p->data[i] + j * sheight * stride; | |
| 171 | ✗ | if (flags & 1) { | |
| 172 | ✗ | if (get_bits_left(&gb) < bps * width * height) | |
| 173 | ✗ | return AVERROR_INVALIDDATA; | |
| 174 | ✗ | for (k = 0; k < height; k++) { | |
| 175 | ✗ | for (x = 0; x < width; x++) | |
| 176 | ✗ | dst[x] = get_bits(&gb, bps); | |
| 177 | |||
| 178 | ✗ | dst += stride; | |
| 179 | } | ||
| 180 | } else { | ||
| 181 | ✗ | for (k = 0; k < height; k++) | |
| 182 | ✗ | READ_PLANE(dst, i, 2, 3) | |
| 183 | } | ||
| 184 | |||
| 185 | ✗ | switch (pred) { | |
| 186 | ✗ | case LEFT: | |
| 187 | ✗ | dst = (uint16_t *)p->data[i] + j * sheight * stride; | |
| 188 | ✗ | s->llviddsp.add_left_pred_int16(dst, dst, max, width, 0); | |
| 189 | ✗ | dst += stride; | |
| 190 | ✗ | if (interlaced) { | |
| 191 | ✗ | s->llviddsp.add_left_pred_int16(dst, dst, max, width, 0); | |
| 192 | ✗ | dst += stride; | |
| 193 | } | ||
| 194 | ✗ | for (k = 1 + interlaced; k < height; k++) { | |
| 195 | ✗ | s->llviddsp.add_left_pred_int16(dst, dst, max, width, dst[-fake_stride]); | |
| 196 | ✗ | dst += stride; | |
| 197 | } | ||
| 198 | ✗ | break; | |
| 199 | ✗ | case GRADIENT: | |
| 200 | ✗ | dst = (uint16_t *)p->data[i] + j * sheight * stride; | |
| 201 | ✗ | s->llviddsp.add_left_pred_int16(dst, dst, max, width, 0); | |
| 202 | ✗ | dst += stride; | |
| 203 | ✗ | if (interlaced) { | |
| 204 | ✗ | s->llviddsp.add_left_pred_int16(dst, dst, max, width, 0); | |
| 205 | ✗ | dst += stride; | |
| 206 | } | ||
| 207 | ✗ | for (k = 1 + interlaced; k < height; k++) { | |
| 208 | ✗ | top = dst[-fake_stride]; | |
| 209 | ✗ | left = top + dst[0]; | |
| 210 | ✗ | dst[0] = left & max; | |
| 211 | ✗ | for (x = 1; x < width; x++) { | |
| 212 | ✗ | top = dst[x - fake_stride]; | |
| 213 | ✗ | lefttop = dst[x - (fake_stride + 1)]; | |
| 214 | ✗ | left += top - lefttop + dst[x]; | |
| 215 | ✗ | dst[x] = left & max; | |
| 216 | } | ||
| 217 | ✗ | dst += stride; | |
| 218 | } | ||
| 219 | ✗ | break; | |
| 220 | ✗ | case MEDIAN: | |
| 221 | ✗ | dst = (uint16_t *)p->data[i] + j * sheight * stride; | |
| 222 | ✗ | s->llviddsp.add_left_pred_int16(dst, dst, max, width, 0); | |
| 223 | ✗ | dst += stride; | |
| 224 | ✗ | if (interlaced) { | |
| 225 | ✗ | s->llviddsp.add_left_pred_int16(dst, dst, max, width, 0); | |
| 226 | ✗ | dst += stride; | |
| 227 | } | ||
| 228 | ✗ | lefttop = left = dst[0]; | |
| 229 | ✗ | for (k = 1 + interlaced; k < height; k++) { | |
| 230 | ✗ | magicyuv_median_pred16(dst, dst - fake_stride, dst, width, &left, &lefttop, max); | |
| 231 | ✗ | lefttop = left = dst[0]; | |
| 232 | ✗ | dst += stride; | |
| 233 | } | ||
| 234 | ✗ | break; | |
| 235 | ✗ | default: | |
| 236 | ✗ | avpriv_request_sample(avctx, "Unknown prediction: %d", pred); | |
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | ✗ | if (s->decorrelate) { | |
| 241 | ✗ | int height = FFMIN(s->slice_height, avctx->coded_height - j * s->slice_height); | |
| 242 | ✗ | int width = avctx->coded_width; | |
| 243 | ✗ | uint16_t *r = (uint16_t *)p->data[0] + j * s->slice_height * p->linesize[0] / 2; | |
| 244 | ✗ | uint16_t *g = (uint16_t *)p->data[1] + j * s->slice_height * p->linesize[1] / 2; | |
| 245 | ✗ | uint16_t *b = (uint16_t *)p->data[2] + j * s->slice_height * p->linesize[2] / 2; | |
| 246 | |||
| 247 | ✗ | for (i = 0; i < height; i++) { | |
| 248 | ✗ | for (k = 0; k < width; k++) { | |
| 249 | ✗ | b[k] = (b[k] + g[k]) & max; | |
| 250 | ✗ | r[k] = (r[k] + g[k]) & max; | |
| 251 | } | ||
| 252 | ✗ | b += p->linesize[0] / 2; | |
| 253 | ✗ | g += p->linesize[1] / 2; | |
| 254 | ✗ | r += p->linesize[2] / 2; | |
| 255 | } | ||
| 256 | } | ||
| 257 | |||
| 258 | ✗ | return 0; | |
| 259 | } | ||
| 260 | |||
| 261 | 738 | static int magy_decode_slice(AVCodecContext *avctx, void *tdata, | |
| 262 | int j, int threadnr) | ||
| 263 | { | ||
| 264 | 738 | const MagicYUVContext *s = avctx->priv_data; | |
| 265 | 738 | int interlaced = s->interlaced; | |
| 266 | 738 | AVFrame *p = s->p; | |
| 267 | int i, k, x, min_width; | ||
| 268 | GetBitContext gb; | ||
| 269 | uint8_t *dst; | ||
| 270 | |||
| 271 |
2/2✓ Branch 0 taken 1908 times.
✓ Branch 1 taken 738 times.
|
2646 | for (i = 0; i < s->planes; i++) { |
| 272 | int left, lefttop, top; | ||
| 273 | 1908 | int height = AV_CEIL_RSHIFT(FFMIN(s->slice_height, avctx->coded_height - j * s->slice_height), s->vshift[i]); | |
| 274 | 1908 | int width = AV_CEIL_RSHIFT(avctx->coded_width, s->hshift[i]); | |
| 275 | 1908 | int sheight = AV_CEIL_RSHIFT(s->slice_height, s->vshift[i]); | |
| 276 | 1908 | ptrdiff_t fake_stride = p->linesize[i] * (1 + interlaced); | |
| 277 | 1908 | ptrdiff_t stride = p->linesize[i]; | |
| 278 | 1908 | const uint8_t *slice = s->buf + s->slices[i][j].start; | |
| 279 | 1908 | const VLC_MULTI_ELEM *const multi = s->multi[i].table; | |
| 280 | 1908 | const VLCElem *const vlc = s->vlc[i].table; | |
| 281 | 1908 | const int vlc_bits = s->vlc[i].bits; | |
| 282 | int flags, pred; | ||
| 283 | |||
| 284 | 1908 | flags = bytestream_get_byte(&slice); | |
| 285 | 1908 | pred = bytestream_get_byte(&slice); | |
| 286 | |||
| 287 | 1908 | dst = p->data[i] + j * sheight * stride; | |
| 288 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1908 times.
|
1908 | if (flags & 1) { |
| 289 | ✗ | if (s->slices[i][j].size - 2 < width * height) | |
| 290 | ✗ | return AVERROR_INVALIDDATA; | |
| 291 | ✗ | for (k = 0; k < height; k++) { | |
| 292 | ✗ | bytestream_get_buffer(&slice, dst, width); | |
| 293 | ✗ | dst += stride; | |
| 294 | } | ||
| 295 | } else { | ||
| 296 | 1908 | int ret = init_get_bits8(&gb, slice, s->slices[i][j].size - 2); | |
| 297 | |||
| 298 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1908 times.
|
1908 | if (ret < 0) |
| 299 | ✗ | return ret; | |
| 300 | |||
| 301 |
2/2✓ Branch 0 taken 102610 times.
✓ Branch 1 taken 1908 times.
|
104518 | for (k = 0; k < height; k++) |
| 302 |
7/10✗ Branch 1 not taken.
✓ Branch 2 taken 13557862 times.
✓ Branch 3 taken 13557862 times.
✓ Branch 4 taken 102610 times.
✓ Branch 6 taken 13557862 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 590042 times.
✓ Branch 10 taken 102610 times.
✓ Branch 12 taken 590042 times.
✗ Branch 13 not taken.
|
14250514 | READ_PLANE(dst, i, 1, 7) |
| 303 | } | ||
| 304 | |||
| 305 |
3/4✓ Branch 0 taken 1350 times.
✓ Branch 1 taken 243 times.
✓ Branch 2 taken 315 times.
✗ Branch 3 not taken.
|
1908 | switch (pred) { |
| 306 | 1350 | case LEFT: | |
| 307 | 1350 | dst = p->data[i] + j * sheight * stride; | |
| 308 | 1350 | s->llviddsp.add_left_pred(dst, dst, width, 0); | |
| 309 | 1350 | dst += stride; | |
| 310 |
2/2✓ Branch 0 taken 72 times.
✓ Branch 1 taken 1278 times.
|
1350 | if (interlaced) { |
| 311 | 72 | s->llviddsp.add_left_pred(dst, dst, width, 0); | |
| 312 | 72 | dst += stride; | |
| 313 | } | ||
| 314 |
2/2✓ Branch 0 taken 45890 times.
✓ Branch 1 taken 1350 times.
|
47240 | for (k = 1 + interlaced; k < height; k++) { |
| 315 | 45890 | s->llviddsp.add_left_pred(dst, dst, width, dst[-fake_stride]); | |
| 316 | 45890 | dst += stride; | |
| 317 | } | ||
| 318 | 1350 | break; | |
| 319 | 243 | case GRADIENT: | |
| 320 | 243 | dst = p->data[i] + j * sheight * stride; | |
| 321 | 243 | s->llviddsp.add_left_pred(dst, dst, width, 0); | |
| 322 | 243 | dst += stride; | |
| 323 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 225 times.
|
243 | if (interlaced) { |
| 324 | 18 | s->llviddsp.add_left_pred(dst, dst, width, 0); | |
| 325 | 18 | dst += stride; | |
| 326 | } | ||
| 327 | 243 | min_width = FFMIN(width, 32); | |
| 328 |
2/2✓ Branch 0 taken 46123 times.
✓ Branch 1 taken 243 times.
|
46366 | for (k = 1 + interlaced; k < height; k++) { |
| 329 | 46123 | top = dst[-fake_stride]; | |
| 330 | 46123 | left = top + dst[0]; | |
| 331 | 46123 | dst[0] = left; | |
| 332 |
2/2✓ Branch 0 taken 1429813 times.
✓ Branch 1 taken 46123 times.
|
1475936 | for (x = 1; x < min_width; x++) { /* dsp need aligned 32 */ |
| 333 | 1429813 | top = dst[x - fake_stride]; | |
| 334 | 1429813 | lefttop = dst[x - (fake_stride + 1)]; | |
| 335 | 1429813 | left += top - lefttop + dst[x]; | |
| 336 | 1429813 | dst[x] = left; | |
| 337 | } | ||
| 338 |
1/2✓ Branch 0 taken 46123 times.
✗ Branch 1 not taken.
|
46123 | if (width > 32) |
| 339 | 46123 | s->llviddsp.add_gradient_pred(dst + 32, fake_stride, width - 32); | |
| 340 | 46123 | dst += stride; | |
| 341 | } | ||
| 342 | 243 | break; | |
| 343 | 315 | case MEDIAN: | |
| 344 | 315 | dst = p->data[i] + j * sheight * stride; | |
| 345 | 315 | s->llviddsp.add_left_pred(dst, dst, width, 0); | |
| 346 | 315 | dst += stride; | |
| 347 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 261 times.
|
315 | if (interlaced) { |
| 348 | 54 | s->llviddsp.add_left_pred(dst, dst, width, 0); | |
| 349 | 54 | dst += stride; | |
| 350 | } | ||
| 351 | 315 | lefttop = left = dst[0]; | |
| 352 |
2/2✓ Branch 0 taken 8545 times.
✓ Branch 1 taken 315 times.
|
8860 | for (k = 1 + interlaced; k < height; k++) { |
| 353 | 8545 | s->llviddsp.add_median_pred(dst, dst - fake_stride, | |
| 354 | dst, width, &left, &lefttop); | ||
| 355 | 8545 | lefttop = left = dst[0]; | |
| 356 | 8545 | dst += stride; | |
| 357 | } | ||
| 358 | 315 | break; | |
| 359 | ✗ | default: | |
| 360 | ✗ | avpriv_request_sample(avctx, "Unknown prediction: %d", pred); | |
| 361 | } | ||
| 362 | } | ||
| 363 | |||
| 364 |
2/2✓ Branch 0 taken 87 times.
✓ Branch 1 taken 651 times.
|
738 | if (s->decorrelate) { |
| 365 | 87 | int height = FFMIN(s->slice_height, avctx->coded_height - j * s->slice_height); | |
| 366 | 87 | int width = avctx->coded_width; | |
| 367 | 87 | uint8_t *b = p->data[0] + j * s->slice_height * p->linesize[0]; | |
| 368 | 87 | uint8_t *g = p->data[1] + j * s->slice_height * p->linesize[1]; | |
| 369 | 87 | uint8_t *r = p->data[2] + j * s->slice_height * p->linesize[2]; | |
| 370 | |||
| 371 |
2/2✓ Branch 0 taken 15616 times.
✓ Branch 1 taken 87 times.
|
15703 | for (i = 0; i < height; i++) { |
| 372 | 15616 | s->llviddsp.add_bytes(b, g, width); | |
| 373 | 15616 | s->llviddsp.add_bytes(r, g, width); | |
| 374 | 15616 | b += p->linesize[0]; | |
| 375 | 15616 | g += p->linesize[1]; | |
| 376 | 15616 | r += p->linesize[2]; | |
| 377 | } | ||
| 378 | } | ||
| 379 | |||
| 380 | 738 | return 0; | |
| 381 | } | ||
| 382 | |||
| 383 | 218 | static int build_huffman(AVCodecContext *avctx, const uint8_t *table, | |
| 384 | int table_size, int max) | ||
| 385 | { | ||
| 386 | 218 | MagicYUVContext *s = avctx->priv_data; | |
| 387 | GetByteContext gb; | ||
| 388 | 218 | uint8_t *len = s->len; | |
| 389 | 218 | uint16_t length_count[33] = { 0 }; | |
| 390 | 218 | int i = 0, j = 0, k; | |
| 391 | |||
| 392 | 218 | bytestream2_init(&gb, table, table_size); | |
| 393 | |||
| 394 |
1/2✓ Branch 1 taken 131596 times.
✗ Branch 2 not taken.
|
131814 | while (bytestream2_get_bytes_left(&gb) > 0) { |
| 395 | 131596 | int b = bytestream2_peek_byteu(&gb) & 0x80; | |
| 396 | 131596 | int x = bytestream2_get_byteu(&gb) & ~0x80; | |
| 397 | 131596 | int l = 1; | |
| 398 | |||
| 399 |
2/2✓ Branch 0 taken 424 times.
✓ Branch 1 taken 131172 times.
|
131596 | if (b) { |
| 400 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 424 times.
|
424 | if (bytestream2_get_bytes_left(&gb) <= 0) |
| 401 | ✗ | break; | |
| 402 | 424 | l += bytestream2_get_byteu(&gb); | |
| 403 | } | ||
| 404 | 131596 | k = j + l; | |
| 405 |
3/6✓ Branch 0 taken 131596 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 131596 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 131596 times.
|
131596 | if (k > max || x == 0 || x > 32) { |
| 406 | ✗ | av_log(avctx, AV_LOG_ERROR, "Invalid Huffman codes\n"); | |
| 407 | ✗ | return AVERROR_INVALIDDATA; | |
| 408 | } | ||
| 409 | |||
| 410 | 131596 | length_count[x] += l; | |
| 411 |
2/2✓ Branch 0 taken 141312 times.
✓ Branch 1 taken 131596 times.
|
272908 | for (; j < k; j++) |
| 412 | 141312 | len[j] = x; | |
| 413 | |||
| 414 |
2/2✓ Branch 0 taken 131044 times.
✓ Branch 1 taken 552 times.
|
131596 | if (j == max) { |
| 415 | 552 | j = 0; | |
| 416 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 552 times.
|
552 | if (huff_build(avctx, len, length_count, &s->vlc[i], &s->multi[i], max, avctx)) { |
| 417 | ✗ | av_log(avctx, AV_LOG_ERROR, "Cannot build Huffman codes\n"); | |
| 418 | ✗ | return AVERROR_INVALIDDATA; | |
| 419 | } | ||
| 420 | 552 | i++; | |
| 421 |
2/2✓ Branch 0 taken 218 times.
✓ Branch 1 taken 334 times.
|
552 | if (i == s->planes) { |
| 422 | 218 | break; | |
| 423 | } | ||
| 424 | 334 | memset(length_count, 0, sizeof(length_count)); | |
| 425 | } | ||
| 426 | } | ||
| 427 | |||
| 428 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 218 times.
|
218 | if (i != s->planes) { |
| 429 | ✗ | av_log(avctx, AV_LOG_ERROR, "Huffman tables too short\n"); | |
| 430 | ✗ | return AVERROR_INVALIDDATA; | |
| 431 | } | ||
| 432 | |||
| 433 | 218 | return 0; | |
| 434 | } | ||
| 435 | |||
| 436 | 218 | static int magy_decode_frame(AVCodecContext *avctx, AVFrame *p, | |
| 437 | int *got_frame, AVPacket *avpkt) | ||
| 438 | { | ||
| 439 | 218 | MagicYUVContext *s = avctx->priv_data; | |
| 440 | GetByteContext gb; | ||
| 441 | uint32_t first_offset, offset, next_offset, header_size, slice_width; | ||
| 442 | int width, height, format, version, table_size; | ||
| 443 | int ret, i, j; | ||
| 444 | |||
| 445 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 218 times.
|
218 | if (avpkt->size < 36) |
| 446 | ✗ | return AVERROR_INVALIDDATA; | |
| 447 | |||
| 448 | 218 | bytestream2_init(&gb, avpkt->data, avpkt->size); | |
| 449 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 218 times.
|
218 | if (bytestream2_get_le32u(&gb) != MKTAG('M', 'A', 'G', 'Y')) |
| 450 | ✗ | return AVERROR_INVALIDDATA; | |
| 451 | |||
| 452 | 218 | header_size = bytestream2_get_le32u(&gb); | |
| 453 |
2/4✓ Branch 0 taken 218 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 218 times.
|
218 | if (header_size < 32 || header_size >= avpkt->size) { |
| 454 | ✗ | av_log(avctx, AV_LOG_ERROR, | |
| 455 | "header or packet too small %"PRIu32"\n", header_size); | ||
| 456 | ✗ | return AVERROR_INVALIDDATA; | |
| 457 | } | ||
| 458 | |||
| 459 | 218 | version = bytestream2_get_byteu(&gb); | |
| 460 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 218 times.
|
218 | if (version != 7) { |
| 461 | ✗ | avpriv_request_sample(avctx, "Version %d", version); | |
| 462 | ✗ | return AVERROR_PATCHWELCOME; | |
| 463 | } | ||
| 464 | |||
| 465 | 218 | format = bytestream2_get_byteu(&gb); | |
| 466 |
7/18✓ Branch 0 taken 53 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 53 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 53 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 53 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
218 | switch (format) { |
| 467 | 53 | case 0x65: | |
| 468 | 53 | avctx->pix_fmt = AV_PIX_FMT_GBRP; | |
| 469 | 53 | break; | |
| 470 | 2 | case 0x66: | |
| 471 | 2 | avctx->pix_fmt = AV_PIX_FMT_GBRAP; | |
| 472 | 2 | break; | |
| 473 | 53 | case 0x67: | |
| 474 | 53 | avctx->pix_fmt = AV_PIX_FMT_YUV444P; | |
| 475 | 53 | break; | |
| 476 | 2 | case 0x68: | |
| 477 | 2 | avctx->pix_fmt = AV_PIX_FMT_YUV422P; | |
| 478 | 2 | break; | |
| 479 | 53 | case 0x69: | |
| 480 | 53 | avctx->pix_fmt = AV_PIX_FMT_YUV420P; | |
| 481 | 53 | break; | |
| 482 | 2 | case 0x6a: | |
| 483 | 2 | avctx->pix_fmt = AV_PIX_FMT_YUVA444P; | |
| 484 | 2 | break; | |
| 485 | 53 | case 0x6b: | |
| 486 | 53 | avctx->pix_fmt = AV_PIX_FMT_GRAY8; | |
| 487 | 53 | break; | |
| 488 | ✗ | case 0x6c: | |
| 489 | ✗ | avctx->pix_fmt = AV_PIX_FMT_YUV422P10; | |
| 490 | ✗ | break; | |
| 491 | ✗ | case 0x76: | |
| 492 | ✗ | avctx->pix_fmt = AV_PIX_FMT_YUV444P10; | |
| 493 | ✗ | break; | |
| 494 | ✗ | case 0x6d: | |
| 495 | ✗ | avctx->pix_fmt = AV_PIX_FMT_GBRP10; | |
| 496 | ✗ | break; | |
| 497 | ✗ | case 0x6e: | |
| 498 | ✗ | avctx->pix_fmt = AV_PIX_FMT_GBRAP10; | |
| 499 | ✗ | break; | |
| 500 | ✗ | case 0x6f: | |
| 501 | ✗ | avctx->pix_fmt = AV_PIX_FMT_GBRP12; | |
| 502 | ✗ | break; | |
| 503 | ✗ | case 0x70: | |
| 504 | ✗ | avctx->pix_fmt = AV_PIX_FMT_GBRAP12; | |
| 505 | ✗ | break; | |
| 506 | ✗ | case 0x71: | |
| 507 | ✗ | avctx->pix_fmt = AV_PIX_FMT_GBRP14; | |
| 508 | ✗ | break; | |
| 509 | ✗ | case 0x72: | |
| 510 | ✗ | avctx->pix_fmt = AV_PIX_FMT_GBRAP14; | |
| 511 | ✗ | break; | |
| 512 | ✗ | case 0x73: | |
| 513 | ✗ | avctx->pix_fmt = AV_PIX_FMT_GRAY10; | |
| 514 | ✗ | break; | |
| 515 | ✗ | case 0x7b: | |
| 516 | ✗ | avctx->pix_fmt = AV_PIX_FMT_YUV420P10; | |
| 517 | ✗ | break; | |
| 518 | ✗ | default: | |
| 519 | ✗ | avpriv_request_sample(avctx, "Format 0x%X", format); | |
| 520 | ✗ | return AVERROR_PATCHWELCOME; | |
| 521 | } | ||
| 522 | 218 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); | |
| 523 | av_assert1(desc); | ||
| 524 | 218 | int is_rgb = s->decorrelate = !!(desc->flags & AV_PIX_FMT_FLAG_RGB); | |
| 525 | 218 | s->hshift[1] = s->hshift[2] = desc->log2_chroma_w; | |
| 526 | 218 | s->vshift[1] = s->vshift[2] = desc->log2_chroma_h; | |
| 527 | 218 | s->bps = desc->comp[0].depth; | |
| 528 | 218 | s->max = 1 << s->bps; | |
| 529 |
1/2✓ Branch 0 taken 218 times.
✗ Branch 1 not taken.
|
218 | s->magy_decode_slice = s->bps == 8 ? magy_decode_slice : magy_decode_slice10; |
| 530 | 218 | s->planes = av_pix_fmt_count_planes(avctx->pix_fmt); | |
| 531 | |||
| 532 | 218 | bytestream2_skipu(&gb, 1); | |
| 533 | 218 | s->color_matrix = bytestream2_get_byteu(&gb); | |
| 534 | 218 | s->flags = bytestream2_get_byteu(&gb); | |
| 535 | 218 | s->interlaced = !!(s->flags & 2); | |
| 536 | 218 | bytestream2_skipu(&gb, 3); | |
| 537 | |||
| 538 | 218 | width = bytestream2_get_le32u(&gb); | |
| 539 | 218 | height = bytestream2_get_le32u(&gb); | |
| 540 | 218 | ret = ff_set_dimensions(avctx, width, height); | |
| 541 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 218 times.
|
218 | if (ret < 0) |
| 542 | ✗ | return ret; | |
| 543 | |||
| 544 | 218 | slice_width = bytestream2_get_le32u(&gb); | |
| 545 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 218 times.
|
218 | if (slice_width != avctx->coded_width) { |
| 546 | ✗ | avpriv_request_sample(avctx, "Slice width %"PRIu32, slice_width); | |
| 547 | ✗ | return AVERROR_PATCHWELCOME; | |
| 548 | } | ||
| 549 | 218 | s->slice_height = bytestream2_get_le32u(&gb); | |
| 550 |
2/4✓ Branch 0 taken 218 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 218 times.
|
218 | if (s->slice_height <= 0 || s->slice_height > INT_MAX - avctx->coded_height) { |
| 551 | ✗ | av_log(avctx, AV_LOG_ERROR, | |
| 552 | "invalid slice height: %d\n", s->slice_height); | ||
| 553 | ✗ | return AVERROR_INVALIDDATA; | |
| 554 | } | ||
| 555 | |||
| 556 | 218 | bytestream2_skipu(&gb, 4); | |
| 557 | |||
| 558 | 218 | s->nb_slices = (avctx->coded_height + s->slice_height - 1) / s->slice_height; | |
| 559 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 218 times.
|
218 | if (s->nb_slices > INT_MAX / FFMAX(sizeof(Slice), 4 * 5)) { |
| 560 | ✗ | av_log(avctx, AV_LOG_ERROR, | |
| 561 | "invalid number of slices: %d\n", s->nb_slices); | ||
| 562 | ✗ | return AVERROR_INVALIDDATA; | |
| 563 | } | ||
| 564 | |||
| 565 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 212 times.
|
218 | if (s->interlaced) { |
| 566 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if ((s->slice_height >> s->vshift[1]) < 2) { |
| 567 | ✗ | av_log(avctx, AV_LOG_ERROR, "impossible slice height\n"); | |
| 568 | ✗ | return AVERROR_INVALIDDATA; | |
| 569 | } | ||
| 570 |
2/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
|
6 | if ((avctx->coded_height % s->slice_height) && ((avctx->coded_height % s->slice_height) >> s->vshift[1]) < 2) { |
| 571 | ✗ | av_log(avctx, AV_LOG_ERROR, "impossible height\n"); | |
| 572 | ✗ | return AVERROR_INVALIDDATA; | |
| 573 | } | ||
| 574 | } | ||
| 575 | |||
| 576 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 218 times.
|
218 | if (bytestream2_get_bytes_left(&gb) <= s->nb_slices * s->planes * 5) |
| 577 | ✗ | return AVERROR_INVALIDDATA; | |
| 578 |
2/2✓ Branch 0 taken 552 times.
✓ Branch 1 taken 218 times.
|
770 | for (i = 0; i < s->planes; i++) { |
| 579 | 552 | av_fast_malloc(&s->slices[i], &s->slices_size[i], s->nb_slices * sizeof(Slice)); | |
| 580 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 552 times.
|
552 | if (!s->slices[i]) |
| 581 | ✗ | return AVERROR(ENOMEM); | |
| 582 | |||
| 583 | 552 | offset = bytestream2_get_le32u(&gb); | |
| 584 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 552 times.
|
552 | if (offset >= avpkt->size - header_size) |
| 585 | ✗ | return AVERROR_INVALIDDATA; | |
| 586 | |||
| 587 |
2/2✓ Branch 0 taken 218 times.
✓ Branch 1 taken 334 times.
|
552 | if (i == 0) |
| 588 | 218 | first_offset = offset; | |
| 589 | |||
| 590 |
2/2✓ Branch 0 taken 1356 times.
✓ Branch 1 taken 552 times.
|
1908 | for (j = 0; j < s->nb_slices - 1; j++) { |
| 591 | 1356 | s->slices[i][j].start = offset + header_size; | |
| 592 | |||
| 593 | 1356 | next_offset = bytestream2_get_le32u(&gb); | |
| 594 |
2/4✓ Branch 0 taken 1356 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1356 times.
|
1356 | if (next_offset <= offset || next_offset >= avpkt->size - header_size) |
| 595 | ✗ | return AVERROR_INVALIDDATA; | |
| 596 | |||
| 597 | 1356 | s->slices[i][j].size = next_offset - offset; | |
| 598 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1356 times.
|
1356 | if (s->slices[i][j].size < 2) |
| 599 | ✗ | return AVERROR_INVALIDDATA; | |
| 600 | 1356 | offset = next_offset; | |
| 601 | } | ||
| 602 | |||
| 603 | 552 | s->slices[i][j].start = offset + header_size; | |
| 604 | 552 | s->slices[i][j].size = avpkt->size - s->slices[i][j].start; | |
| 605 | |||
| 606 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 552 times.
|
552 | if (s->slices[i][j].size < 2) |
| 607 | ✗ | return AVERROR_INVALIDDATA; | |
| 608 | } | ||
| 609 | |||
| 610 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 218 times.
|
218 | if (bytestream2_get_byteu(&gb) != s->planes) |
| 611 | ✗ | return AVERROR_INVALIDDATA; | |
| 612 | |||
| 613 | 218 | bytestream2_skipu(&gb, s->nb_slices * s->planes); | |
| 614 | |||
| 615 | 218 | table_size = header_size + first_offset - bytestream2_tell(&gb); | |
| 616 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 218 times.
|
218 | if (table_size < 2) |
| 617 | ✗ | return AVERROR_INVALIDDATA; | |
| 618 | |||
| 619 | 218 | ret = build_huffman(avctx, avpkt->data + bytestream2_tell(&gb), | |
| 620 | table_size, s->max); | ||
| 621 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 218 times.
|
218 | if (ret < 0) |
| 622 | ✗ | return ret; | |
| 623 | |||
| 624 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 218 times.
|
218 | if ((ret = ff_thread_get_buffer(avctx, p, 0)) < 0) |
| 625 | ✗ | return ret; | |
| 626 | |||
| 627 | 218 | s->buf = avpkt->data; | |
| 628 | 218 | s->p = p; | |
| 629 | 218 | avctx->execute2(avctx, s->magy_decode_slice, NULL, NULL, s->nb_slices); | |
| 630 | |||
| 631 |
2/2✓ Branch 0 taken 55 times.
✓ Branch 1 taken 163 times.
|
218 | if (is_rgb) { |
| 632 | 55 | FFSWAP(uint8_t*, p->data[0], p->data[1]); | |
| 633 | 55 | FFSWAP(int, p->linesize[0], p->linesize[1]); | |
| 634 | } else { | ||
| 635 |
2/3✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 153 times.
|
163 | switch (s->color_matrix) { |
| 636 | ✗ | case 1: | |
| 637 | ✗ | p->colorspace = AVCOL_SPC_BT470BG; | |
| 638 | ✗ | break; | |
| 639 | 10 | case 2: | |
| 640 | 10 | p->colorspace = AVCOL_SPC_BT709; | |
| 641 | 10 | break; | |
| 642 | } | ||
| 643 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 155 times.
|
163 | p->color_range = (s->flags & 4) ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; |
| 644 | } | ||
| 645 | |||
| 646 | 218 | *got_frame = 1; | |
| 647 | |||
| 648 | 218 | return avpkt->size; | |
| 649 | } | ||
| 650 | |||
| 651 | 22 | static av_cold int magy_decode_init(AVCodecContext *avctx) | |
| 652 | { | ||
| 653 | 22 | MagicYUVContext *s = avctx->priv_data; | |
| 654 | 22 | ff_llviddsp_init(&s->llviddsp); | |
| 655 | 22 | return 0; | |
| 656 | } | ||
| 657 | |||
| 658 | 22 | static av_cold int magy_decode_end(AVCodecContext *avctx) | |
| 659 | { | ||
| 660 | 22 | MagicYUVContext * const s = avctx->priv_data; | |
| 661 | int i; | ||
| 662 | |||
| 663 |
2/2✓ Branch 0 taken 88 times.
✓ Branch 1 taken 22 times.
|
110 | for (i = 0; i < FF_ARRAY_ELEMS(s->slices); i++) { |
| 664 | 88 | av_freep(&s->slices[i]); | |
| 665 | 88 | s->slices_size[i] = 0; | |
| 666 | 88 | ff_vlc_free(&s->vlc[i]); | |
| 667 | 88 | ff_vlc_free_multi(&s->multi[i]); | |
| 668 | } | ||
| 669 | |||
| 670 | 22 | return 0; | |
| 671 | } | ||
| 672 | |||
| 673 | const FFCodec ff_magicyuv_decoder = { | ||
| 674 | .p.name = "magicyuv", | ||
| 675 | CODEC_LONG_NAME("MagicYUV video"), | ||
| 676 | .p.type = AVMEDIA_TYPE_VIDEO, | ||
| 677 | .p.id = AV_CODEC_ID_MAGICYUV, | ||
| 678 | .priv_data_size = sizeof(MagicYUVContext), | ||
| 679 | .init = magy_decode_init, | ||
| 680 | .close = magy_decode_end, | ||
| 681 | FF_CODEC_DECODE_CB(magy_decode_frame), | ||
| 682 | .p.capabilities = AV_CODEC_CAP_DR1 | | ||
| 683 | AV_CODEC_CAP_FRAME_THREADS | | ||
| 684 | AV_CODEC_CAP_SLICE_THREADS, | ||
| 685 | }; | ||
| 686 |