xref: /third_party/ffmpeg/libavcodec/nuv.c (revision cabdff1a)
1/*
2 * NuppelVideo decoder
3 * Copyright (c) 2006 Reimar Doeffinger
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 <stdio.h>
23#include <stdlib.h>
24#include <limits.h>
25
26#include "libavutil/bswap.h"
27#include "libavutil/common.h"
28#include "libavutil/intreadwrite.h"
29#include "libavutil/lzo.h"
30#include "libavutil/imgutils.h"
31#include "avcodec.h"
32#include "codec_internal.h"
33#include "idctdsp.h"
34#include "internal.h"
35#include "rtjpeg.h"
36
37typedef struct NuvContext {
38    AVFrame *pic;
39    int codec_frameheader;
40    int quality;
41    int width, height;
42    unsigned int decomp_size;
43    unsigned char *decomp_buf;
44    uint32_t lq[64], cq[64];
45    RTJpegContext rtj;
46} NuvContext;
47
48static const uint8_t fallback_lquant[] = {
49    16,  11,  10,  16,  24,  40,  51,  61,
50    12,  12,  14,  19,  26,  58,  60,  55,
51    14,  13,  16,  24,  40,  57,  69,  56,
52    14,  17,  22,  29,  51,  87,  80,  62,
53    18,  22,  37,  56,  68, 109, 103,  77,
54    24,  35,  55,  64,  81, 104, 113,  92,
55    49,  64,  78,  87, 103, 121, 120, 101,
56    72,  92,  95,  98, 112, 100, 103,  99
57};
58
59static const uint8_t fallback_cquant[] = {
60    17, 18, 24, 47, 99, 99, 99, 99,
61    18, 21, 26, 66, 99, 99, 99, 99,
62    24, 26, 56, 99, 99, 99, 99, 99,
63    47, 66, 99, 99, 99, 99, 99, 99,
64    99, 99, 99, 99, 99, 99, 99, 99,
65    99, 99, 99, 99, 99, 99, 99, 99,
66    99, 99, 99, 99, 99, 99, 99, 99,
67    99, 99, 99, 99, 99, 99, 99, 99
68};
69
70/**
71 * @brief copy frame data from buffer to AVFrame, handling stride.
72 * @param f destination AVFrame
73 * @param src source buffer, does not use any line-stride
74 * @param width width of the video frame
75 * @param height height of the video frame
76 */
77static void copy_frame(AVFrame *f, const uint8_t *src, int width, int height)
78{
79    uint8_t *src_data[4];
80    int src_linesize[4];
81    av_image_fill_arrays(src_data, src_linesize, src,
82                         f->format, width, height, 1);
83    av_image_copy(f->data, f->linesize, (const uint8_t **)src_data, src_linesize,
84                  f->format, width, height);
85}
86
87/**
88 * @brief extract quantization tables from codec data into our context
89 */
90static int get_quant(AVCodecContext *avctx, NuvContext *c, const uint8_t *buf,
91                     int size)
92{
93    int i;
94    if (size < 2 * 64 * 4) {
95        av_log(avctx, AV_LOG_ERROR, "insufficient rtjpeg quant data\n");
96        return AVERROR_INVALIDDATA;
97    }
98    for (i = 0; i < 64; i++, buf += 4)
99        c->lq[i] = AV_RL32(buf);
100    for (i = 0; i < 64; i++, buf += 4)
101        c->cq[i] = AV_RL32(buf);
102    return 0;
103}
104
105/**
106 * @brief set quantization tables from a quality value
107 */
108static void get_quant_quality(NuvContext *c, int quality)
109{
110    int i;
111    quality = FFMAX(quality, 1);
112    for (i = 0; i < 64; i++) {
113        c->lq[i] = (fallback_lquant[i] << 7) / quality;
114        c->cq[i] = (fallback_cquant[i] << 7) / quality;
115    }
116}
117
118static int codec_reinit(AVCodecContext *avctx, int width, int height,
119                        int quality)
120{
121    NuvContext *c = avctx->priv_data;
122    int ret;
123
124    width  = FFALIGN(width,  2);
125    height = FFALIGN(height, 2);
126    if (quality >= 0)
127        get_quant_quality(c, quality);
128    if (width != c->width || height != c->height) {
129        // also reserve space for a possible additional header
130        int64_t buf_size = height * (int64_t)width * 3 / 2
131                     + FFMAX(AV_LZO_OUTPUT_PADDING, AV_INPUT_BUFFER_PADDING_SIZE)
132                     + RTJPEG_HEADER_SIZE;
133        if (buf_size > INT_MAX/8)
134            return -1;
135        if ((ret = ff_set_dimensions(avctx, width, height)) < 0)
136            return ret;
137        c->width  = width;
138        c->height = height;
139        av_fast_malloc(&c->decomp_buf, &c->decomp_size,
140                       buf_size);
141        if (!c->decomp_buf) {
142            av_log(avctx, AV_LOG_ERROR,
143                   "Can't allocate decompression buffer.\n");
144            return AVERROR(ENOMEM);
145        }
146        ff_rtjpeg_decode_init(&c->rtj, c->width, c->height, c->lq, c->cq);
147        av_frame_unref(c->pic);
148        return 1;
149    } else if (quality != c->quality)
150        ff_rtjpeg_decode_init(&c->rtj, c->width, c->height, c->lq, c->cq);
151
152    return 0;
153}
154
155static int decode_frame(AVCodecContext *avctx, AVFrame *picture,
156                        int *got_frame, AVPacket *avpkt)
157{
158    const uint8_t *buf = avpkt->data;
159    int buf_size       = avpkt->size;
160    NuvContext *c      = avctx->priv_data;
161    int orig_size      = buf_size;
162    int keyframe, ret;
163    int size_change = 0;
164    int minsize = 0;
165    int flags = 0;
166    int result, init_frame = !avctx->frame_number;
167    enum {
168        NUV_UNCOMPRESSED  = '0',
169        NUV_RTJPEG        = '1',
170        NUV_RTJPEG_IN_LZO = '2',
171        NUV_LZO           = '3',
172        NUV_BLACK         = 'N',
173        NUV_COPY_LAST     = 'L'
174    } comptype;
175
176    if (buf_size < 12) {
177        av_log(avctx, AV_LOG_ERROR, "coded frame too small\n");
178        return AVERROR_INVALIDDATA;
179    }
180
181    // codec data (rtjpeg quant tables)
182    if (buf[0] == 'D' && buf[1] == 'R') {
183        int ret;
184        // Skip the rest of the frame header.
185        buf       = &buf[12];
186        buf_size -= 12;
187        ret       = get_quant(avctx, c, buf, buf_size);
188        if (ret < 0)
189            return ret;
190        ff_rtjpeg_decode_init(&c->rtj, c->width, c->height, c->lq, c->cq);
191        return orig_size;
192    }
193
194    if (buf_size < 12 || buf[0] != 'V') {
195        av_log(avctx, AV_LOG_ERROR, "not a nuv video frame\n");
196        return AVERROR_INVALIDDATA;
197    }
198    comptype = buf[1];
199    switch (comptype) {
200    case NUV_RTJPEG_IN_LZO:
201    case NUV_RTJPEG:
202        keyframe = !buf[2];
203        if (c->width < 16 || c->height < 16) {
204            return AVERROR_INVALIDDATA;
205        }
206        break;
207    case NUV_COPY_LAST:
208        flags |= FF_REGET_BUFFER_FLAG_READONLY;
209        keyframe = 0;
210        break;
211    default:
212        keyframe = 1;
213        break;
214    }
215    switch (comptype) {
216    case NUV_UNCOMPRESSED:
217        minsize = c->width * c->height * 3 / 2;
218        break;
219    case NUV_RTJPEG:
220        minsize = c->width/16 * (c->height/16) * 6;
221        break;
222    case NUV_BLACK:
223    case NUV_COPY_LAST:
224    case NUV_LZO:
225    case NUV_RTJPEG_IN_LZO:
226        break;
227    default:
228        av_log(avctx, AV_LOG_ERROR, "unknown compression\n");
229        return AVERROR_INVALIDDATA;
230    }
231    if (buf_size < minsize / 4)
232        return AVERROR_INVALIDDATA;
233retry:
234    // Skip the rest of the frame header.
235    buf       = &buf[12];
236    buf_size -= 12;
237    if (comptype == NUV_RTJPEG_IN_LZO || comptype == NUV_LZO) {
238        int outlen = c->decomp_size - FFMAX(AV_INPUT_BUFFER_PADDING_SIZE, AV_LZO_OUTPUT_PADDING);
239        int inlen  = buf_size;
240        if (av_lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen)) {
241            av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n");
242            return AVERROR_INVALIDDATA;
243        }
244        buf      = c->decomp_buf;
245        buf_size = c->decomp_size - FFMAX(AV_INPUT_BUFFER_PADDING_SIZE, AV_LZO_OUTPUT_PADDING) - outlen;
246        memset(c->decomp_buf + buf_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
247    }
248    if (c->codec_frameheader) {
249        int w, h, q;
250        if (buf_size < RTJPEG_HEADER_SIZE) {
251            av_log(avctx, AV_LOG_ERROR, "Too small NUV video frame\n");
252            return AVERROR_INVALIDDATA;
253        }
254        // There seem to exist two variants of this header: one starts with 'V'
255        // and 5 bytes unknown, the other matches current MythTV and is 4 bytes size,
256        // 1 byte header size (== 12), 1 byte version (== 0)
257        if (buf[0] != 'V' && AV_RL16(&buf[4]) != 0x000c) {
258            av_log(avctx, AV_LOG_ERROR, "Unknown secondary frame header (wrong codec_tag?)\n");
259            return AVERROR_INVALIDDATA;
260        }
261        w = AV_RL16(&buf[6]);
262        h = AV_RL16(&buf[8]);
263        q = buf[10];
264        if ((result = codec_reinit(avctx, w, h, q)) < 0)
265            return result;
266        if (result) {
267            buf = avpkt->data;
268            buf_size = avpkt->size;
269            size_change = 1;
270            goto retry;
271        }
272        buf       = &buf[RTJPEG_HEADER_SIZE];
273        buf_size -= RTJPEG_HEADER_SIZE;
274    }
275
276    if (size_change || keyframe) {
277        av_frame_unref(c->pic);
278        init_frame = 1;
279    }
280
281    if ((result = ff_reget_buffer(avctx, c->pic, flags)) < 0)
282        return result;
283    if (init_frame) {
284        memset(c->pic->data[0], 0,    avctx->height * c->pic->linesize[0]);
285        memset(c->pic->data[1], 0x80, avctx->height * c->pic->linesize[1] / 2);
286        memset(c->pic->data[2], 0x80, avctx->height * c->pic->linesize[2] / 2);
287    }
288
289    c->pic->pict_type = keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
290    c->pic->key_frame = keyframe;
291    // decompress/copy/whatever data
292    switch (comptype) {
293    case NUV_LZO:
294    case NUV_UNCOMPRESSED: {
295        int height = c->height;
296        if (buf_size < c->width * height * 3 / 2) {
297            av_log(avctx, AV_LOG_ERROR, "uncompressed frame too short\n");
298            height = buf_size / c->width / 3 * 2;
299        }
300        if(height > 0)
301            copy_frame(c->pic, buf, c->width, height);
302        break;
303    }
304    case NUV_RTJPEG_IN_LZO:
305    case NUV_RTJPEG:
306        ret = ff_rtjpeg_decode_frame_yuv420(&c->rtj, c->pic, buf, buf_size);
307        if (ret < 0)
308            return ret;
309        break;
310    case NUV_BLACK:
311        memset(c->pic->data[0], 0, c->width * c->height);
312        memset(c->pic->data[1], 128, c->width * c->height / 4);
313        memset(c->pic->data[2], 128, c->width * c->height / 4);
314        break;
315    case NUV_COPY_LAST:
316        /* nothing more to do here */
317        break;
318    }
319
320    if ((result = av_frame_ref(picture, c->pic)) < 0)
321        return result;
322
323    *got_frame = 1;
324    return orig_size;
325}
326
327static av_cold int decode_init(AVCodecContext *avctx)
328{
329    NuvContext *c  = avctx->priv_data;
330    int ret;
331
332    c->pic = av_frame_alloc();
333    if (!c->pic)
334        return AVERROR(ENOMEM);
335
336    avctx->pix_fmt = AV_PIX_FMT_YUV420P;
337    c->decomp_buf  = NULL;
338    c->quality     = -1;
339    c->width       = 0;
340    c->height      = 0;
341
342    c->codec_frameheader = avctx->codec_tag == MKTAG('R', 'J', 'P', 'G');
343
344    if (avctx->extradata_size)
345        get_quant(avctx, c, avctx->extradata, avctx->extradata_size);
346
347    ff_rtjpeg_init(&c->rtj, avctx);
348
349    if ((ret = codec_reinit(avctx, avctx->width, avctx->height, -1)) < 0)
350        return ret;
351
352    return 0;
353}
354
355static av_cold int decode_end(AVCodecContext *avctx)
356{
357    NuvContext *c = avctx->priv_data;
358
359    av_freep(&c->decomp_buf);
360    av_frame_free(&c->pic);
361
362    return 0;
363}
364
365const FFCodec ff_nuv_decoder = {
366    .p.name         = "nuv",
367    .p.long_name    = NULL_IF_CONFIG_SMALL("NuppelVideo/RTJPEG"),
368    .p.type         = AVMEDIA_TYPE_VIDEO,
369    .p.id           = AV_CODEC_ID_NUV,
370    .priv_data_size = sizeof(NuvContext),
371    .init           = decode_init,
372    .close          = decode_end,
373    FF_CODEC_DECODE_CB(decode_frame),
374    .p.capabilities = AV_CODEC_CAP_DR1,
375    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
376};
377