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