utvideodec.c 18.5 KB
Newer Older
Kostya Shishkov's avatar
Kostya Shishkov committed
1 2 3 4
/*
 * Ut Video decoder
 * Copyright (c) 2011 Konstantin Shishkov
 *
5
 * This file is part of FFmpeg.
Kostya Shishkov's avatar
Kostya Shishkov committed
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
Kostya Shishkov's avatar
Kostya Shishkov committed
8 9 10 11
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
Kostya Shishkov's avatar
Kostya Shishkov committed
13 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
Kostya Shishkov's avatar
Kostya Shishkov committed
19 20 21 22 23 24 25 26
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
 * @file
 * Ut Video decoder
 */

27
#include <inttypes.h>
Kostya Shishkov's avatar
Kostya Shishkov committed
28 29 30 31
#include <stdlib.h>

#include "libavutil/intreadwrite.h"
#include "avcodec.h"
32
#include "bswapdsp.h"
Kostya Shishkov's avatar
Kostya Shishkov committed
33 34
#include "bytestream.h"
#include "get_bits.h"
35
#include "thread.h"
36
#include "utvideo.h"
Kostya Shishkov's avatar
Kostya Shishkov committed
37

38
static int build_huff(const uint8_t *src, VLC *vlc, int *fsym)
Kostya Shishkov's avatar
Kostya Shishkov committed
39 40 41 42 43 44 45 46 47
{
    int i;
    HuffEntry he[256];
    int last;
    uint32_t codes[256];
    uint8_t bits[256];
    uint8_t syms[256];
    uint32_t code;

48
    *fsym = -1;
Kostya Shishkov's avatar
Kostya Shishkov committed
49 50 51 52
    for (i = 0; i < 256; i++) {
        he[i].sym = i;
        he[i].len = *src++;
    }
53
    qsort(he, 256, sizeof(*he), ff_ut_huff_cmp_len);
Kostya Shishkov's avatar
Kostya Shishkov committed
54

55 56 57 58
    if (!he[0].len) {
        *fsym = he[0].sym;
        return 0;
    }
Kostya Shishkov's avatar
Kostya Shishkov committed
59 60 61 62 63

    last = 255;
    while (he[last].len == 255 && last)
        last--;

64 65 66
    if (he[last].len > 32)
        return -1;

Kostya Shishkov's avatar
Kostya Shishkov committed
67 68 69 70 71 72 73 74
    code = 1;
    for (i = last; i >= 0; i--) {
        codes[i] = code >> (32 - he[i].len);
        bits[i]  = he[i].len;
        syms[i]  = he[i].sym;
        code += 0x80000000u >> (he[i].len - 1);
    }

75
    return ff_init_vlc_sparse(vlc, FFMIN(he[last].len, 11), last + 1,
76 77 78
                              bits,  sizeof(*bits),  sizeof(*bits),
                              codes, sizeof(*codes), sizeof(*codes),
                              syms,  sizeof(*syms),  sizeof(*syms), 0);
Kostya Shishkov's avatar
Kostya Shishkov committed
79 80 81 82 83
}

static int decode_plane(UtvideoContext *c, int plane_no,
                        uint8_t *dst, int step, int stride,
                        int width, int height,
84
                        const uint8_t *src, int use_pred)
Kostya Shishkov's avatar
Kostya Shishkov committed
85 86 87 88 89
{
    int i, j, slice, pix;
    int sstart, send;
    VLC vlc;
    GetBitContext gb;
90
    int prev, fsym;
91
    const int cmask = ~(!plane_no && c->avctx->pix_fmt == AV_PIX_FMT_YUV420P);
Kostya Shishkov's avatar
Kostya Shishkov committed
92

93
    if (build_huff(src, &vlc, &fsym)) {
Kostya Shishkov's avatar
Kostya Shishkov committed
94 95 96
        av_log(c->avctx, AV_LOG_ERROR, "Cannot build Huffman codes\n");
        return AVERROR_INVALIDDATA;
    }
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
    if (fsym >= 0) { // build_huff reported a symbol to fill slices with
        send = 0;
        for (slice = 0; slice < c->slices; slice++) {
            uint8_t *dest;

            sstart = send;
            send   = (height * (slice + 1) / c->slices) & cmask;
            dest   = dst + sstart * stride;

            prev = 0x80;
            for (j = sstart; j < send; j++) {
                for (i = 0; i < width * step; i += step) {
                    pix = fsym;
                    if (use_pred) {
                        prev += pix;
                        pix   = prev;
                    }
                    dest[i] = pix;
                }
                dest += stride;
            }
        }
        return 0;
    }
Kostya Shishkov's avatar
Kostya Shishkov committed
121 122 123 124 125 126 127 128 129

    src      += 256;

    send = 0;
    for (slice = 0; slice < c->slices; slice++) {
        uint8_t *dest;
        int slice_data_start, slice_data_end, slice_size;

        sstart = send;
130
        send   = (height * (slice + 1) / c->slices) & cmask;
Kostya Shishkov's avatar
Kostya Shishkov committed
131 132 133 134 135 136 137 138
        dest   = dst + sstart * stride;

        // slice offset and size validation was done earlier
        slice_data_start = slice ? AV_RL32(src + slice * 4 - 4) : 0;
        slice_data_end   = AV_RL32(src + slice * 4);
        slice_size       = slice_data_end - slice_data_start;

        if (!slice_size) {
139 140 141
            av_log(c->avctx, AV_LOG_ERROR, "Plane has more than one symbol "
                   "yet a slice has a length of zero.\n");
            goto fail;
Kostya Shishkov's avatar
Kostya Shishkov committed
142 143
        }

144 145
        memcpy(c->slice_bits, src + slice_data_start + c->slices * 4,
               slice_size);
Kostya Shishkov's avatar
Kostya Shishkov committed
146
        memset(c->slice_bits + slice_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
147 148 149
        c->bdsp.bswap_buf((uint32_t *) c->slice_bits,
                          (uint32_t *) c->slice_bits,
                          (slice_data_end - slice_data_start + 3) >> 2);
Kostya Shishkov's avatar
Kostya Shishkov committed
150 151 152 153 154 155
        init_get_bits(&gb, c->slice_bits, slice_size * 8);

        prev = 0x80;
        for (j = sstart; j < send; j++) {
            for (i = 0; i < width * step; i += step) {
                if (get_bits_left(&gb) <= 0) {
156 157
                    av_log(c->avctx, AV_LOG_ERROR,
                           "Slice decoding ran out of bits\n");
Kostya Shishkov's avatar
Kostya Shishkov committed
158 159
                    goto fail;
                }
160
                pix = get_vlc2(&gb, vlc.table, vlc.bits, 3);
Kostya Shishkov's avatar
Kostya Shishkov committed
161 162 163 164 165 166 167 168 169 170 171 172 173
                if (pix < 0) {
                    av_log(c->avctx, AV_LOG_ERROR, "Decoding error\n");
                    goto fail;
                }
                if (use_pred) {
                    prev += pix;
                    pix   = prev;
                }
                dest[i] = pix;
            }
            dest += stride;
        }
        if (get_bits_left(&gb) > 32)
174 175
            av_log(c->avctx, AV_LOG_WARNING,
                   "%d bits left after decoding slice\n", get_bits_left(&gb));
Kostya Shishkov's avatar
Kostya Shishkov committed
176 177
    }

178
    ff_free_vlc(&vlc);
Kostya Shishkov's avatar
Kostya Shishkov committed
179 180 181

    return 0;
fail:
182
    ff_free_vlc(&vlc);
Kostya Shishkov's avatar
Kostya Shishkov committed
183 184 185
    return AVERROR_INVALIDDATA;
}

186 187
static void restore_rgb_planes(uint8_t *src, int step, int stride, int width,
                               int height)
Kostya Shishkov's avatar
Kostya Shishkov committed
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
{
    int i, j;
    uint8_t r, g, b;

    for (j = 0; j < height; j++) {
        for (i = 0; i < width * step; i += step) {
            r = src[i];
            g = src[i + 1];
            b = src[i + 2];
            src[i]     = r + g - 0x80;
            src[i + 2] = b + g - 0x80;
        }
        src += stride;
    }
}

static void restore_median(uint8_t *src, int step, int stride,
205
                           int width, int height, int slices, int rmode)
Kostya Shishkov's avatar
Kostya Shishkov committed
206 207 208 209 210
{
    int i, j, slice;
    int A, B, C;
    uint8_t *bsrc;
    int slice_start, slice_height;
211
    const int cmask = ~rmode;
Kostya Shishkov's avatar
Kostya Shishkov committed
212 213

    for (slice = 0; slice < slices; slice++) {
214 215 216
        slice_start  = ((slice * height) / slices) & cmask;
        slice_height = ((((slice + 1) * height) / slices) & cmask) -
                       slice_start;
Kostya Shishkov's avatar
Kostya Shishkov committed
217

218 219
        if (!slice_height)
            continue;
Kostya Shishkov's avatar
Kostya Shishkov committed
220 221 222 223 224 225 226
        bsrc = src + slice_start * stride;

        // first line - left neighbour prediction
        bsrc[0] += 0x80;
        A = bsrc[0];
        for (i = step; i < width * step; i += step) {
            bsrc[i] += A;
227
            A        = bsrc[i];
Kostya Shishkov's avatar
Kostya Shishkov committed
228 229
        }
        bsrc += stride;
230
        if (slice_height <= 1)
Kostya Shishkov's avatar
Kostya Shishkov committed
231
            continue;
232 233
        // second line - first element has top prediction, the rest uses median
        C        = bsrc[-stride];
Kostya Shishkov's avatar
Kostya Shishkov committed
234
        bsrc[0] += C;
235
        A        = bsrc[0];
Kostya Shishkov's avatar
Kostya Shishkov committed
236
        for (i = step; i < width * step; i += step) {
237
            B        = bsrc[i - stride];
Kostya Shishkov's avatar
Kostya Shishkov committed
238
            bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C));
239 240
            C        = B;
            A        = bsrc[i];
Kostya Shishkov's avatar
Kostya Shishkov committed
241 242 243 244 245
        }
        bsrc += stride;
        // the rest of lines use continuous median prediction
        for (j = 2; j < slice_height; j++) {
            for (i = 0; i < width * step; i += step) {
246
                B        = bsrc[i - stride];
Kostya Shishkov's avatar
Kostya Shishkov committed
247
                bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C));
248 249
                C        = B;
                A        = bsrc[i];
Kostya Shishkov's avatar
Kostya Shishkov committed
250 251 252 253 254 255
            }
            bsrc += stride;
        }
    }
}

256 257 258 259 260 261 262 263 264 265 266
/* UtVideo interlaced mode treats every two lines as a single one,
 * so restoring function should take care of possible padding between
 * two parts of the same "line".
 */
static void restore_median_il(uint8_t *src, int step, int stride,
                              int width, int height, int slices, int rmode)
{
    int i, j, slice;
    int A, B, C;
    uint8_t *bsrc;
    int slice_start, slice_height;
267
    const int cmask   = ~(rmode ? 3 : 1);
268 269 270 271
    const int stride2 = stride << 1;

    for (slice = 0; slice < slices; slice++) {
        slice_start    = ((slice * height) / slices) & cmask;
272 273
        slice_height   = ((((slice + 1) * height) / slices) & cmask) -
                         slice_start;
274
        slice_height >>= 1;
275 276
        if (!slice_height)
            continue;
277 278 279 280 281

        bsrc = src + slice_start * stride;

        // first line - left neighbour prediction
        bsrc[0] += 0x80;
282
        A        = bsrc[0];
283 284
        for (i = step; i < width * step; i += step) {
            bsrc[i] += A;
285
            A        = bsrc[i];
286 287 288
        }
        for (i = 0; i < width * step; i += step) {
            bsrc[stride + i] += A;
289
            A                 = bsrc[stride + i];
290 291
        }
        bsrc += stride2;
292
        if (slice_height <= 1)
293
            continue;
294 295
        // second line - first element has top prediction, the rest uses median
        C        = bsrc[-stride2];
296
        bsrc[0] += C;
297
        A        = bsrc[0];
298
        for (i = step; i < width * step; i += step) {
299
            B        = bsrc[i - stride2];
300
            bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C));
301 302
            C        = B;
            A        = bsrc[i];
303 304
        }
        for (i = 0; i < width * step; i += step) {
305
            B                 = bsrc[i - stride];
306
            bsrc[stride + i] += mid_pred(A, B, (uint8_t)(A + B - C));
307 308
            C                 = B;
            A                 = bsrc[stride + i];
309 310 311 312 313
        }
        bsrc += stride2;
        // the rest of lines use continuous median prediction
        for (j = 2; j < slice_height; j++) {
            for (i = 0; i < width * step; i += step) {
314
                B        = bsrc[i - stride2];
315
                bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C));
316 317
                C        = B;
                A        = bsrc[i];
318 319
            }
            for (i = 0; i < width * step; i += step) {
320
                B                 = bsrc[i - stride];
321
                bsrc[i + stride] += mid_pred(A, B, (uint8_t)(A + B - C));
322 323
                C                 = B;
                A                 = bsrc[i + stride];
324 325 326 327 328 329
            }
            bsrc += stride2;
        }
    }
}

330
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
331
                        AVPacket *avpkt)
Kostya Shishkov's avatar
Kostya Shishkov committed
332 333 334 335 336 337 338 339
{
    const uint8_t *buf = avpkt->data;
    int buf_size = avpkt->size;
    UtvideoContext *c = avctx->priv_data;
    int i, j;
    const uint8_t *plane_start[5];
    int plane_size, max_slice_size = 0, slice_start, slice_end, slice_size;
    int ret;
340
    GetByteContext gb;
341
    ThreadFrame frame = { .f = data };
Kostya Shishkov's avatar
Kostya Shishkov committed
342

343
    if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
Kostya Shishkov's avatar
Kostya Shishkov committed
344 345
        return ret;

346
    /* parse plane structure to get frame flags and validate slice offsets */
347
    bytestream2_init(&gb, buf, buf_size);
Kostya Shishkov's avatar
Kostya Shishkov committed
348
    for (i = 0; i < c->planes; i++) {
349 350
        plane_start[i] = gb.buffer;
        if (bytestream2_get_bytes_left(&gb) < 256 + 4 * c->slices) {
Kostya Shishkov's avatar
Kostya Shishkov committed
351 352 353
            av_log(avctx, AV_LOG_ERROR, "Insufficient data for a plane\n");
            return AVERROR_INVALIDDATA;
        }
354
        bytestream2_skipu(&gb, 256);
Kostya Shishkov's avatar
Kostya Shishkov committed
355 356 357
        slice_start = 0;
        slice_end   = 0;
        for (j = 0; j < c->slices; j++) {
358
            slice_end   = bytestream2_get_le32u(&gb);
Kostya Shishkov's avatar
Kostya Shishkov committed
359
            slice_size  = slice_end - slice_start;
360
            if (slice_end < 0 || slice_size < 0 ||
361
                bytestream2_get_bytes_left(&gb) < slice_end) {
Kostya Shishkov's avatar
Kostya Shishkov committed
362 363 364 365 366 367 368
                av_log(avctx, AV_LOG_ERROR, "Incorrect slice size\n");
                return AVERROR_INVALIDDATA;
            }
            slice_start = slice_end;
            max_slice_size = FFMAX(max_slice_size, slice_size);
        }
        plane_size = slice_end;
369
        bytestream2_skipu(&gb, plane_size);
Kostya Shishkov's avatar
Kostya Shishkov committed
370
    }
371 372
    plane_start[c->planes] = gb.buffer;
    if (bytestream2_get_bytes_left(&gb) < c->frame_info_size) {
Kostya Shishkov's avatar
Kostya Shishkov committed
373 374 375
        av_log(avctx, AV_LOG_ERROR, "Not enough data for frame information\n");
        return AVERROR_INVALIDDATA;
    }
376
    c->frame_info = bytestream2_get_le32u(&gb);
377 378
    av_log(avctx, AV_LOG_DEBUG, "frame information flags %"PRIX32"\n",
           c->frame_info);
Kostya Shishkov's avatar
Kostya Shishkov committed
379 380 381 382

    c->frame_pred = (c->frame_info >> 8) & 3;

    if (c->frame_pred == PRED_GRADIENT) {
383
        avpriv_request_sample(avctx, "Frame with gradient prediction");
Kostya Shishkov's avatar
Kostya Shishkov committed
384 385 386 387 388 389 390 391 392 393 394 395
        return AVERROR_PATCHWELCOME;
    }

    av_fast_malloc(&c->slice_bits, &c->slice_bits_size,
                   max_slice_size + FF_INPUT_BUFFER_PADDING_SIZE);

    if (!c->slice_bits) {
        av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer\n");
        return AVERROR(ENOMEM);
    }

    switch (c->avctx->pix_fmt) {
396 397
    case AV_PIX_FMT_RGB24:
    case AV_PIX_FMT_RGBA:
Kostya Shishkov's avatar
Kostya Shishkov committed
398
        for (i = 0; i < c->planes; i++) {
399 400
            ret = decode_plane(c, i, frame.f->data[0] + ff_ut_rgb_order[i],
                               c->planes, frame.f->linesize[0], avctx->width,
401 402
                               avctx->height, plane_start[i],
                               c->frame_pred == PRED_LEFT);
Kostya Shishkov's avatar
Kostya Shishkov committed
403 404
            if (ret)
                return ret;
405
            if (c->frame_pred == PRED_MEDIAN) {
406
                if (!c->interlaced) {
407 408
                    restore_median(frame.f->data[0] + ff_ut_rgb_order[i],
                                   c->planes, frame.f->linesize[0], avctx->width,
409
                                   avctx->height, c->slices, 0);
410
                } else {
411 412
                    restore_median_il(frame.f->data[0] + ff_ut_rgb_order[i],
                                      c->planes, frame.f->linesize[0],
413 414
                                      avctx->width, avctx->height, c->slices,
                                      0);
415
                }
416
            }
Kostya Shishkov's avatar
Kostya Shishkov committed
417
        }
418
        restore_rgb_planes(frame.f->data[0], c->planes, frame.f->linesize[0],
Kostya Shishkov's avatar
Kostya Shishkov committed
419 420
                           avctx->width, avctx->height);
        break;
421
    case AV_PIX_FMT_YUV420P:
Kostya Shishkov's avatar
Kostya Shishkov committed
422
        for (i = 0; i < 3; i++) {
423
            ret = decode_plane(c, i, frame.f->data[i], 1, frame.f->linesize[i],
424
                               avctx->width >> !!i, avctx->height >> !!i,
425
                               plane_start[i], c->frame_pred == PRED_LEFT);
Kostya Shishkov's avatar
Kostya Shishkov committed
426 427
            if (ret)
                return ret;
428 429
            if (c->frame_pred == PRED_MEDIAN) {
                if (!c->interlaced) {
430
                    restore_median(frame.f->data[i], 1, frame.f->linesize[i],
431 432 433
                                   avctx->width >> !!i, avctx->height >> !!i,
                                   c->slices, !i);
                } else {
434
                    restore_median_il(frame.f->data[i], 1, frame.f->linesize[i],
435 436 437 438 439
                                      avctx->width  >> !!i,
                                      avctx->height >> !!i,
                                      c->slices, !i);
                }
            }
Kostya Shishkov's avatar
Kostya Shishkov committed
440 441
        }
        break;
442
    case AV_PIX_FMT_YUV422P:
Kostya Shishkov's avatar
Kostya Shishkov committed
443
        for (i = 0; i < 3; i++) {
444
            ret = decode_plane(c, i, frame.f->data[i], 1, frame.f->linesize[i],
445
                               avctx->width >> !!i, avctx->height,
446
                               plane_start[i], c->frame_pred == PRED_LEFT);
Kostya Shishkov's avatar
Kostya Shishkov committed
447 448
            if (ret)
                return ret;
449 450
            if (c->frame_pred == PRED_MEDIAN) {
                if (!c->interlaced) {
451
                    restore_median(frame.f->data[i], 1, frame.f->linesize[i],
452 453 454
                                   avctx->width >> !!i, avctx->height,
                                   c->slices, 0);
                } else {
455
                    restore_median_il(frame.f->data[i], 1, frame.f->linesize[i],
456 457 458 459
                                      avctx->width >> !!i, avctx->height,
                                      c->slices, 0);
                }
            }
Kostya Shishkov's avatar
Kostya Shishkov committed
460 461 462 463
        }
        break;
    }

464 465 466
    frame.f->key_frame = 1;
    frame.f->pict_type = AV_PICTURE_TYPE_I;
    frame.f->interlaced_frame = !!c->interlaced;
467

468
    *got_frame = 1;
Kostya Shishkov's avatar
Kostya Shishkov committed
469 470 471 472 473 474 475 476 477 478 479

    /* always report that the buffer was completely consumed */
    return buf_size;
}

static av_cold int decode_init(AVCodecContext *avctx)
{
    UtvideoContext * const c = avctx->priv_data;

    c->avctx = avctx;

480
    ff_bswapdsp_init(&c->bdsp);
Kostya Shishkov's avatar
Kostya Shishkov committed
481 482

    if (avctx->extradata_size < 16) {
483 484
        av_log(avctx, AV_LOG_ERROR,
               "Insufficient extradata size %d, should be at least 16\n",
Kostya Shishkov's avatar
Kostya Shishkov committed
485 486 487 488 489 490 491
               avctx->extradata_size);
        return AVERROR_INVALIDDATA;
    }

    av_log(avctx, AV_LOG_DEBUG, "Encoder version %d.%d.%d.%d\n",
           avctx->extradata[3], avctx->extradata[2],
           avctx->extradata[1], avctx->extradata[0]);
492
    av_log(avctx, AV_LOG_DEBUG, "Original format %"PRIX32"\n",
493
           AV_RB32(avctx->extradata + 4));
Kostya Shishkov's avatar
Kostya Shishkov committed
494 495 496 497
    c->frame_info_size = AV_RL32(avctx->extradata + 8);
    c->flags           = AV_RL32(avctx->extradata + 12);

    if (c->frame_info_size != 4)
498
        avpriv_request_sample(avctx, "Frame info not 4 bytes");
499
    av_log(avctx, AV_LOG_DEBUG, "Encoding parameters %08"PRIX32"\n", c->flags);
Kostya Shishkov's avatar
Kostya Shishkov committed
500 501 502 503 504 505 506 507 508
    c->slices      = (c->flags >> 24) + 1;
    c->compression = c->flags & 1;
    c->interlaced  = c->flags & 0x800;

    c->slice_bits_size = 0;

    switch (avctx->codec_tag) {
    case MKTAG('U', 'L', 'R', 'G'):
        c->planes      = 3;
509
        avctx->pix_fmt = AV_PIX_FMT_RGB24;
Kostya Shishkov's avatar
Kostya Shishkov committed
510 511 512
        break;
    case MKTAG('U', 'L', 'R', 'A'):
        c->planes      = 4;
513
        avctx->pix_fmt = AV_PIX_FMT_RGBA;
Kostya Shishkov's avatar
Kostya Shishkov committed
514 515 516
        break;
    case MKTAG('U', 'L', 'Y', '0'):
        c->planes      = 3;
517
        avctx->pix_fmt = AV_PIX_FMT_YUV420P;
518
        avctx->colorspace = AVCOL_SPC_BT470BG;
Kostya Shishkov's avatar
Kostya Shishkov committed
519 520 521
        break;
    case MKTAG('U', 'L', 'Y', '2'):
        c->planes      = 3;
522
        avctx->pix_fmt = AV_PIX_FMT_YUV422P;
523
        avctx->colorspace = AVCOL_SPC_BT470BG;
Kostya Shishkov's avatar
Kostya Shishkov committed
524
        break;
525 526
    case MKTAG('U', 'L', 'H', '0'):
        c->planes      = 3;
527
        avctx->pix_fmt = AV_PIX_FMT_YUV420P;
528 529 530 531
        avctx->colorspace = AVCOL_SPC_BT709;
        break;
    case MKTAG('U', 'L', 'H', '2'):
        c->planes      = 3;
532
        avctx->pix_fmt = AV_PIX_FMT_YUV422P;
533 534
        avctx->colorspace = AVCOL_SPC_BT709;
        break;
Kostya Shishkov's avatar
Kostya Shishkov committed
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
    default:
        av_log(avctx, AV_LOG_ERROR, "Unknown Ut Video FOURCC provided (%08X)\n",
               avctx->codec_tag);
        return AVERROR_INVALIDDATA;
    }

    return 0;
}

static av_cold int decode_end(AVCodecContext *avctx)
{
    UtvideoContext * const c = avctx->priv_data;

    av_freep(&c->slice_bits);

    return 0;
}

AVCodec ff_utvideo_decoder = {
    .name           = "utvideo",
555
    .long_name      = NULL_IF_CONFIG_SMALL("Ut Video"),
Kostya Shishkov's avatar
Kostya Shishkov committed
556
    .type           = AVMEDIA_TYPE_VIDEO,
557
    .id             = AV_CODEC_ID_UTVIDEO,
Kostya Shishkov's avatar
Kostya Shishkov committed
558 559 560 561
    .priv_data_size = sizeof(UtvideoContext),
    .init           = decode_init,
    .close          = decode_end,
    .decode         = decode_frame,
562
    .capabilities   = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS,
Kostya Shishkov's avatar
Kostya Shishkov committed
563
};