]> git.sesse.net Git - ffmpeg/blob - libavcodec/nuv.c
timecode: fix typo
[ffmpeg] / libavcodec / nuv.c
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 #include <stdio.h>
22 #include <stdlib.h>
23 #include <limits.h>
24
25 #include "libavutil/bswap.h"
26 #include "libavutil/lzo.h"
27 #include "libavutil/imgutils.h"
28 #include "avcodec.h"
29 #include "dsputil.h"
30 #include "rtjpeg.h"
31
32 typedef struct {
33     AVFrame pic;
34     int codec_frameheader;
35     int quality;
36     int width, height;
37     unsigned int decomp_size;
38     unsigned char* decomp_buf;
39     uint32_t lq[64], cq[64];
40     RTJpegContext rtj;
41     DSPContext dsp;
42 } NuvContext;
43
44 static const uint8_t fallback_lquant[] = {
45     16,  11,  10,  16,  24,  40,  51,  61,
46     12,  12,  14,  19,  26,  58,  60,  55,
47     14,  13,  16,  24,  40,  57,  69,  56,
48     14,  17,  22,  29,  51,  87,  80,  62,
49     18,  22,  37,  56,  68, 109, 103,  77,
50     24,  35,  55,  64,  81, 104, 113,  92,
51     49,  64,  78,  87, 103, 121, 120, 101,
52     72,  92,  95,  98, 112, 100, 103,  99
53 };
54
55 static const uint8_t fallback_cquant[] = {
56     17, 18, 24, 47, 99, 99, 99, 99,
57     18, 21, 26, 66, 99, 99, 99, 99,
58     24, 26, 56, 99, 99, 99, 99, 99,
59     47, 66, 99, 99, 99, 99, 99, 99,
60     99, 99, 99, 99, 99, 99, 99, 99,
61     99, 99, 99, 99, 99, 99, 99, 99,
62     99, 99, 99, 99, 99, 99, 99, 99,
63     99, 99, 99, 99, 99, 99, 99, 99
64 };
65
66 /**
67  * @brief copy frame data from buffer to AVFrame, handling stride.
68  * @param f destination AVFrame
69  * @param src source buffer, does not use any line-stride
70  * @param width width of the video frame
71  * @param height height of the video frame
72  */
73 static void copy_frame(AVFrame *f, const uint8_t *src,
74                        int width, int height) {
75     AVPicture pic;
76     avpicture_fill(&pic, src, PIX_FMT_YUV420P, width, height);
77     av_picture_copy((AVPicture *)f, &pic, PIX_FMT_YUV420P, width, height);
78 }
79
80 /**
81  * @brief extract quantization tables from codec data into our context
82  */
83 static int get_quant(AVCodecContext *avctx, NuvContext *c,
84                      const uint8_t *buf, int size) {
85     int i;
86     if (size < 2 * 64 * 4) {
87         av_log(avctx, AV_LOG_ERROR, "insufficient rtjpeg quant data\n");
88         return -1;
89     }
90     for (i = 0; i < 64; i++, buf += 4)
91         c->lq[i] = AV_RL32(buf);
92     for (i = 0; i < 64; i++, buf += 4)
93         c->cq[i] = AV_RL32(buf);
94     return 0;
95 }
96
97 /**
98  * @brief set quantization tables from a quality value
99  */
100 static void get_quant_quality(NuvContext *c, int quality) {
101     int i;
102     quality = FFMAX(quality, 1);
103     for (i = 0; i < 64; i++) {
104         c->lq[i] = (fallback_lquant[i] << 7) / quality;
105         c->cq[i] = (fallback_cquant[i] << 7) / quality;
106     }
107 }
108
109 static int codec_reinit(AVCodecContext *avctx, int width, int height, int quality) {
110     NuvContext *c = avctx->priv_data;
111     width  = FFALIGN(width,  2);
112     height = FFALIGN(height, 2);
113     if (quality >= 0)
114         get_quant_quality(c, quality);
115     if (width != c->width || height != c->height) {
116         // also reserve space for a possible additional header
117         int buf_size = 24 + height * width * 3 / 2 + AV_LZO_OUTPUT_PADDING;
118         if (av_image_check_size(height, width, 0, avctx) < 0 ||
119             buf_size > INT_MAX/8)
120             return -1;
121         avctx->width = c->width = width;
122         avctx->height = c->height = height;
123         av_fast_malloc(&c->decomp_buf, &c->decomp_size, buf_size);
124         if (!c->decomp_buf) {
125             av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n");
126             return AVERROR(ENOMEM);
127         }
128         rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq);
129         return 1;
130     } else if (quality != c->quality)
131         rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq);
132     return 0;
133 }
134
135 static int decode_frame(AVCodecContext *avctx, void *data, int *data_size,
136                         AVPacket *avpkt) {
137     const uint8_t *buf = avpkt->data;
138     int buf_size = avpkt->size;
139     NuvContext *c = avctx->priv_data;
140     AVFrame *picture = data;
141     int orig_size = buf_size;
142     int keyframe;
143     int size_change = 0;
144     int result;
145     enum {NUV_UNCOMPRESSED = '0', NUV_RTJPEG = '1',
146           NUV_RTJPEG_IN_LZO = '2', NUV_LZO = '3',
147           NUV_BLACK = 'N', NUV_COPY_LAST = 'L'} comptype;
148
149     if (buf_size < 12) {
150         av_log(avctx, AV_LOG_ERROR, "coded frame too small\n");
151         return -1;
152     }
153
154     // codec data (rtjpeg quant tables)
155     if (buf[0] == 'D' && buf[1] == 'R') {
156         int ret;
157         // skip rest of the frameheader.
158         buf = &buf[12];
159         buf_size -= 12;
160         ret = get_quant(avctx, c, buf, buf_size);
161         if (ret < 0)
162             return ret;
163         rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq);
164         return orig_size;
165     }
166
167     if (buf[0] != 'V' || buf_size < 12) {
168         av_log(avctx, AV_LOG_ERROR, "not a nuv video frame\n");
169         return -1;
170     }
171     comptype = buf[1];
172     switch (comptype) {
173         case NUV_RTJPEG_IN_LZO:
174         case NUV_RTJPEG:
175             keyframe = !buf[2]; break;
176         case NUV_COPY_LAST:
177             keyframe = 0; break;
178         default:
179             keyframe = 1; break;
180     }
181 retry:
182     // skip rest of the frameheader.
183     buf = &buf[12];
184     buf_size -= 12;
185     if (comptype == NUV_RTJPEG_IN_LZO || comptype == NUV_LZO) {
186         int outlen = c->decomp_size - AV_LZO_OUTPUT_PADDING, inlen = buf_size;
187         if (av_lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen))
188             av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n");
189         buf = c->decomp_buf;
190         buf_size = c->decomp_size - AV_LZO_OUTPUT_PADDING - outlen;
191     }
192     if (c->codec_frameheader) {
193         int w, h, q, res;
194         if (buf[0] != 'V' || buf_size < 12) {
195             av_log(avctx, AV_LOG_ERROR, "invalid nuv video frame (wrong codec_tag?)\n");
196             return AVERROR_INVALIDDATA;
197         }
198         w = AV_RL16(&buf[6]);
199         h = AV_RL16(&buf[8]);
200         q = buf[10];
201         res = codec_reinit(avctx, w, h, q);
202         if (res < 0)
203             return res;
204         if (res) {
205             buf = avpkt->data;
206             buf_size = avpkt->size;
207             size_change = 1;
208             goto retry;
209         }
210         buf = &buf[12];
211         buf_size -= 12;
212     }
213
214     if ((size_change || keyframe) && c->pic.data[0])
215         avctx->release_buffer(avctx, &c->pic);
216     c->pic.reference = 3;
217     c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_READABLE |
218                           FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
219     result = avctx->reget_buffer(avctx, &c->pic);
220     if (result < 0) {
221         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
222         return -1;
223     }
224
225     c->pic.pict_type = keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
226     c->pic.key_frame = keyframe;
227     // decompress/copy/whatever data
228     switch (comptype) {
229         case NUV_LZO:
230         case NUV_UNCOMPRESSED: {
231             int height = c->height;
232             if (buf_size < c->width * height * 3 / 2) {
233                 av_log(avctx, AV_LOG_ERROR, "uncompressed frame too short\n");
234                 height = buf_size / c->width / 3 * 2;
235             }
236             copy_frame(&c->pic, buf, c->width, height);
237             break;
238         }
239         case NUV_RTJPEG_IN_LZO:
240         case NUV_RTJPEG: {
241             rtjpeg_decode_frame_yuv420(&c->rtj, &c->pic, buf, buf_size);
242             break;
243         }
244         case NUV_BLACK: {
245             memset(c->pic.data[0], 0, c->width * c->height);
246             memset(c->pic.data[1], 128, c->width * c->height / 4);
247             memset(c->pic.data[2], 128, c->width * c->height / 4);
248             break;
249         }
250         case NUV_COPY_LAST: {
251             /* nothing more to do here */
252             break;
253         }
254         default:
255             av_log(avctx, AV_LOG_ERROR, "unknown compression\n");
256             return -1;
257     }
258
259     *picture = c->pic;
260     *data_size = sizeof(AVFrame);
261     return orig_size;
262 }
263
264 static av_cold int decode_init(AVCodecContext *avctx) {
265     NuvContext *c = avctx->priv_data;
266     avctx->pix_fmt = PIX_FMT_YUV420P;
267     c->pic.data[0] = NULL;
268     c->decomp_buf = NULL;
269     c->quality = -1;
270     c->width = 0;
271     c->height = 0;
272     c->codec_frameheader = avctx->codec_tag == MKTAG('R', 'J', 'P', 'G');
273     if (avctx->extradata_size)
274         get_quant(avctx, c, avctx->extradata, avctx->extradata_size);
275     dsputil_init(&c->dsp, avctx);
276     if (codec_reinit(avctx, avctx->width, avctx->height, -1) < 0)
277         return 1;
278     return 0;
279 }
280
281 static av_cold int decode_end(AVCodecContext *avctx) {
282     NuvContext *c = avctx->priv_data;
283     av_freep(&c->decomp_buf);
284     if (c->pic.data[0])
285         avctx->release_buffer(avctx, &c->pic);
286     return 0;
287 }
288
289 AVCodec ff_nuv_decoder = {
290     .name           = "nuv",
291     .type           = AVMEDIA_TYPE_VIDEO,
292     .id             = CODEC_ID_NUV,
293     .priv_data_size = sizeof(NuvContext),
294     .init           = decode_init,
295     .close          = decode_end,
296     .decode         = decode_frame,
297     .capabilities   = CODEC_CAP_DR1,
298     .long_name = NULL_IF_CONFIG_SMALL("NuppelVideo/RTJPEG"),
299 };
300