utvideodec.c 18.4 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 220 221 222 223 224

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

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

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

        bsrc = src + slice_start * stride;

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

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

339
    if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
Kostya Shishkov's avatar
Kostya Shishkov committed
340 341
        return ret;

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

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

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

460 461 462
    frame.f->key_frame = 1;
    frame.f->pict_type = AV_PICTURE_TYPE_I;
    frame.f->interlaced_frame = !!c->interlaced;
463

464
    *got_frame = 1;
Kostya Shishkov's avatar
Kostya Shishkov committed
465 466 467 468 469 470 471 472 473 474 475

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

476
    ff_bswapdsp_init(&c->bdsp);
Kostya Shishkov's avatar
Kostya Shishkov committed
477 478

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

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