utvideodec.c 18.3 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 27 28 29 30 31 32 33
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

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

#include <stdlib.h>

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

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

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

54 55 56 57 58
    if (!he[0].len) {
        *fsym = he[0].sym;
        return 0;
    }
    if (he[0].len > 32)
Kostya Shishkov's avatar
Kostya Shishkov committed
59 60 61 62 63 64 65 66 67 68 69 70 71 72
        return -1;

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

    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);
    }

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

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

91
    if (build_huff(src, &vlc, &fsym)) {
Kostya Shishkov's avatar
Kostya Shishkov committed
92 93 94
        av_log(c->avctx, AV_LOG_ERROR, "Cannot build Huffman codes\n");
        return AVERROR_INVALIDDATA;
    }
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
    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
119 120 121 122 123 124 125 126 127

    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;
128
        send   = (height * (slice + 1) / c->slices) & cmask;
Kostya Shishkov's avatar
Kostya Shishkov committed
129 130 131 132 133 134 135 136
        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) {
137 138 139
            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
140 141
        }

142 143
        memcpy(c->slice_bits, src + slice_data_start + c->slices * 4,
               slice_size);
Kostya Shishkov's avatar
Kostya Shishkov committed
144
        memset(c->slice_bits + slice_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
145
        c->dsp.bswap_buf((uint32_t *) c->slice_bits, (uint32_t *) c->slice_bits,
Kostya Shishkov's avatar
Kostya Shishkov committed
146 147 148 149 150 151 152
                         (slice_data_end - slice_data_start + 3) >> 2);
        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) {
153 154
                    av_log(c->avctx, AV_LOG_ERROR,
                           "Slice decoding ran out of bits\n");
Kostya Shishkov's avatar
Kostya Shishkov committed
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
                    goto fail;
                }
                pix = get_vlc2(&gb, vlc.table, vlc.bits, 4);
                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)
171 172
            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
173 174
    }

175
    ff_free_vlc(&vlc);
Kostya Shishkov's avatar
Kostya Shishkov committed
176 177 178

    return 0;
fail:
179
    ff_free_vlc(&vlc);
Kostya Shishkov's avatar
Kostya Shishkov committed
180 181 182
    return AVERROR_INVALIDDATA;
}

183 184
static void restore_rgb_planes(uint8_t *src, int step, int stride, int width,
                               int height)
Kostya Shishkov's avatar
Kostya Shishkov committed
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
{
    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,
202
                           int width, int height, int slices, int rmode)
Kostya Shishkov's avatar
Kostya Shishkov committed
203 204 205 206 207
{
    int i, j, slice;
    int A, B, C;
    uint8_t *bsrc;
    int slice_start, slice_height;
208
    const int cmask = ~rmode;
Kostya Shishkov's avatar
Kostya Shishkov committed
209 210

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

        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;
222
            A        = bsrc[i];
Kostya Shishkov's avatar
Kostya Shishkov committed
223 224 225 226
        }
        bsrc += stride;
        if (slice_height == 1)
            continue;
227 228
        // second line - first element has top prediction, the rest uses median
        C        = bsrc[-stride];
Kostya Shishkov's avatar
Kostya Shishkov committed
229
        bsrc[0] += C;
230
        A        = bsrc[0];
Kostya Shishkov's avatar
Kostya Shishkov committed
231
        for (i = step; i < width * step; i += step) {
232
            B        = bsrc[i - stride];
Kostya Shishkov's avatar
Kostya Shishkov committed
233
            bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C));
234 235
            C        = B;
            A        = bsrc[i];
Kostya Shishkov's avatar
Kostya Shishkov committed
236 237 238 239 240
        }
        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) {
241
                B        = bsrc[i - stride];
Kostya Shishkov's avatar
Kostya Shishkov committed
242
                bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C));
243 244
                C        = B;
                A        = bsrc[i];
Kostya Shishkov's avatar
Kostya Shishkov committed
245 246 247 248 249 250
            }
            bsrc += stride;
        }
    }
}

251 252 253 254 255 256 257 258 259 260 261
/* 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;
262
    const int cmask   = ~(rmode ? 3 : 1);
263 264 265 266
    const int stride2 = stride << 1;

    for (slice = 0; slice < slices; slice++) {
        slice_start    = ((slice * height) / slices) & cmask;
267 268
        slice_height   = ((((slice + 1) * height) / slices) & cmask) -
                         slice_start;
269 270 271 272 273 274
        slice_height >>= 1;

        bsrc = src + slice_start * stride;

        // first line - left neighbour prediction
        bsrc[0] += 0x80;
275
        A        = bsrc[0];
276 277
        for (i = step; i < width * step; i += step) {
            bsrc[i] += A;
278
            A        = bsrc[i];
279 280 281
        }
        for (i = 0; i < width * step; i += step) {
            bsrc[stride + i] += A;
282
            A                 = bsrc[stride + i];
283 284 285 286
        }
        bsrc += stride2;
        if (slice_height == 1)
            continue;
287 288
        // second line - first element has top prediction, the rest uses median
        C        = bsrc[-stride2];
289
        bsrc[0] += C;
290
        A        = bsrc[0];
291
        for (i = step; i < width * step; i += step) {
292
            B        = bsrc[i - stride2];
293
            bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C));
294 295
            C        = B;
            A        = bsrc[i];
296 297
        }
        for (i = 0; i < width * step; i += step) {
298
            B                 = bsrc[i - stride];
299
            bsrc[stride + i] += mid_pred(A, B, (uint8_t)(A + B - C));
300 301
            C                 = B;
            A                 = bsrc[stride + i];
302 303 304 305 306
        }
        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) {
307
                B        = bsrc[i - stride2];
308
                bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C));
309 310
                C        = B;
                A        = bsrc[i];
311 312
            }
            for (i = 0; i < width * step; i += step) {
313
                B                 = bsrc[i - stride];
314
                bsrc[i + stride] += mid_pred(A, B, (uint8_t)(A + B - C));
315 316
                C                 = B;
                A                 = bsrc[i + stride];
317 318 319 320 321 322
            }
            bsrc += stride2;
        }
    }
}

323
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
324
                        AVPacket *avpkt)
Kostya Shishkov's avatar
Kostya Shishkov committed
325 326 327 328 329 330 331 332
{
    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;
333
    GetByteContext gb;
334
    ThreadFrame frame = { .f = data };
Kostya Shishkov's avatar
Kostya Shishkov committed
335

336
    if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
Kostya Shishkov's avatar
Kostya Shishkov committed
337 338
        return ret;

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

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

    if (c->frame_pred == PRED_GRADIENT) {
375
        avpriv_request_sample(avctx, "Frame with gradient prediction");
Kostya Shishkov's avatar
Kostya Shishkov committed
376 377 378 379 380 381 382 383 384 385 386 387
        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) {
388 389
    case AV_PIX_FMT_RGB24:
    case AV_PIX_FMT_RGBA:
Kostya Shishkov's avatar
Kostya Shishkov committed
390
        for (i = 0; i < c->planes; i++) {
391 392
            ret = decode_plane(c, i, frame.f->data[0] + ff_ut_rgb_order[i],
                               c->planes, frame.f->linesize[0], avctx->width,
393 394
                               avctx->height, plane_start[i],
                               c->frame_pred == PRED_LEFT);
Kostya Shishkov's avatar
Kostya Shishkov committed
395 396
            if (ret)
                return ret;
397
            if (c->frame_pred == PRED_MEDIAN) {
398
                if (!c->interlaced) {
399 400
                    restore_median(frame.f->data[0] + ff_ut_rgb_order[i],
                                   c->planes, frame.f->linesize[0], avctx->width,
401
                                   avctx->height, c->slices, 0);
402
                } else {
403 404
                    restore_median_il(frame.f->data[0] + ff_ut_rgb_order[i],
                                      c->planes, frame.f->linesize[0],
405 406
                                      avctx->width, avctx->height, c->slices,
                                      0);
407
                }
408
            }
Kostya Shishkov's avatar
Kostya Shishkov committed
409
        }
410
        restore_rgb_planes(frame.f->data[0], c->planes, frame.f->linesize[0],
Kostya Shishkov's avatar
Kostya Shishkov committed
411 412
                           avctx->width, avctx->height);
        break;
413
    case AV_PIX_FMT_YUV420P:
Kostya Shishkov's avatar
Kostya Shishkov committed
414
        for (i = 0; i < 3; i++) {
415
            ret = decode_plane(c, i, frame.f->data[i], 1, frame.f->linesize[i],
416
                               avctx->width >> !!i, avctx->height >> !!i,
417
                               plane_start[i], c->frame_pred == PRED_LEFT);
Kostya Shishkov's avatar
Kostya Shishkov committed
418 419
            if (ret)
                return ret;
420 421
            if (c->frame_pred == PRED_MEDIAN) {
                if (!c->interlaced) {
422
                    restore_median(frame.f->data[i], 1, frame.f->linesize[i],
423 424 425
                                   avctx->width >> !!i, avctx->height >> !!i,
                                   c->slices, !i);
                } else {
426
                    restore_median_il(frame.f->data[i], 1, frame.f->linesize[i],
427 428 429 430 431
                                      avctx->width  >> !!i,
                                      avctx->height >> !!i,
                                      c->slices, !i);
                }
            }
Kostya Shishkov's avatar
Kostya Shishkov committed
432 433
        }
        break;
434
    case AV_PIX_FMT_YUV422P:
Kostya Shishkov's avatar
Kostya Shishkov committed
435
        for (i = 0; i < 3; i++) {
436
            ret = decode_plane(c, i, frame.f->data[i], 1, frame.f->linesize[i],
437
                               avctx->width >> !!i, avctx->height,
438
                               plane_start[i], c->frame_pred == PRED_LEFT);
Kostya Shishkov's avatar
Kostya Shishkov committed
439 440
            if (ret)
                return ret;
441 442
            if (c->frame_pred == PRED_MEDIAN) {
                if (!c->interlaced) {
443
                    restore_median(frame.f->data[i], 1, frame.f->linesize[i],
444 445 446
                                   avctx->width >> !!i, avctx->height,
                                   c->slices, 0);
                } else {
447
                    restore_median_il(frame.f->data[i], 1, frame.f->linesize[i],
448 449 450 451
                                      avctx->width >> !!i, avctx->height,
                                      c->slices, 0);
                }
            }
Kostya Shishkov's avatar
Kostya Shishkov committed
452 453 454 455
        }
        break;
    }

456 457 458
    frame.f->key_frame = 1;
    frame.f->pict_type = AV_PICTURE_TYPE_I;
    frame.f->interlaced_frame = !!c->interlaced;
459

460
    *got_frame = 1;
Kostya Shishkov's avatar
Kostya Shishkov committed
461 462 463 464 465 466 467 468 469 470 471

    /* 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;

472
    ff_dsputil_init(&c->dsp, avctx);
Kostya Shishkov's avatar
Kostya Shishkov committed
473 474

    if (avctx->extradata_size < 16) {
475 476
        av_log(avctx, AV_LOG_ERROR,
               "Insufficient extradata size %d, should be at least 16\n",
Kostya Shishkov's avatar
Kostya Shishkov committed
477 478 479 480 481 482 483
               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]);
484 485
    av_log(avctx, AV_LOG_DEBUG, "Original format %X\n",
           AV_RB32(avctx->extradata + 4));
Kostya Shishkov's avatar
Kostya Shishkov committed
486 487 488 489
    c->frame_info_size = AV_RL32(avctx->extradata + 8);
    c->flags           = AV_RL32(avctx->extradata + 12);

    if (c->frame_info_size != 4)
490
        avpriv_request_sample(avctx, "Frame info not 4 bytes");
Kostya Shishkov's avatar
Kostya Shishkov committed
491 492 493 494 495 496 497 498 499 500
    av_log(avctx, AV_LOG_DEBUG, "Encoding parameters %08X\n", c->flags);
    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;
501
        avctx->pix_fmt = AV_PIX_FMT_RGB24;
Kostya Shishkov's avatar
Kostya Shishkov committed
502 503 504
        break;
    case MKTAG('U', 'L', 'R', 'A'):
        c->planes      = 4;
505
        avctx->pix_fmt = AV_PIX_FMT_RGBA;
Kostya Shishkov's avatar
Kostya Shishkov committed
506 507 508
        break;
    case MKTAG('U', 'L', 'Y', '0'):
        c->planes      = 3;
509
        avctx->pix_fmt = AV_PIX_FMT_YUV420P;
510
        avctx->colorspace = AVCOL_SPC_BT470BG;
Kostya Shishkov's avatar
Kostya Shishkov committed
511 512 513
        break;
    case MKTAG('U', 'L', 'Y', '2'):
        c->planes      = 3;
514
        avctx->pix_fmt = AV_PIX_FMT_YUV422P;
515
        avctx->colorspace = AVCOL_SPC_BT470BG;
Kostya Shishkov's avatar
Kostya Shishkov committed
516
        break;
517 518
    case MKTAG('U', 'L', 'H', '0'):
        c->planes      = 3;
519
        avctx->pix_fmt = AV_PIX_FMT_YUV420P;
520 521 522 523
        avctx->colorspace = AVCOL_SPC_BT709;
        break;
    case MKTAG('U', 'L', 'H', '2'):
        c->planes      = 3;
524
        avctx->pix_fmt = AV_PIX_FMT_YUV422P;
525 526
        avctx->colorspace = AVCOL_SPC_BT709;
        break;
Kostya Shishkov's avatar
Kostya Shishkov committed
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
    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",
547
    .long_name      = NULL_IF_CONFIG_SMALL("Ut Video"),
Kostya Shishkov's avatar
Kostya Shishkov committed
548
    .type           = AVMEDIA_TYPE_VIDEO,
549
    .id             = AV_CODEC_ID_UTVIDEO,
Kostya Shishkov's avatar
Kostya Shishkov committed
550 551 552 553
    .priv_data_size = sizeof(UtvideoContext),
    .init           = decode_init,
    .close          = decode_end,
    .decode         = decode_frame,
554
    .capabilities   = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS,
Kostya Shishkov's avatar
Kostya Shishkov committed
555
};