ffmpeg / libavcodec / nuv.c @ e4141433
History | View | Annotate | Download (6.72 KB)
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 |
|
24 |
#include "common.h" |
25 |
#include "avcodec.h" |
26 |
|
27 |
#include "bswap.h" |
28 |
#include "dsputil.h" |
29 |
#include "lzo.h" |
30 |
#include "rtjpeg.h" |
31 |
|
32 |
typedef struct { |
33 |
AVFrame pic; |
34 |
int width, height;
|
35 |
unsigned int decomp_size; |
36 |
unsigned char* decomp_buf; |
37 |
uint32_t lq[64], cq[64]; |
38 |
RTJpegContext rtj; |
39 |
DSPContext dsp; |
40 |
} NuvContext; |
41 |
|
42 |
/**
|
43 |
* \brief copy frame data from buffer to AVFrame, handling stride.
|
44 |
* \param f destination AVFrame
|
45 |
* \param src source buffer, does not use any line-stride
|
46 |
* \param width width of the video frame
|
47 |
* \param height height of the video frame
|
48 |
*/
|
49 |
static void copy_frame(AVFrame *f, uint8_t *src, |
50 |
int width, int height) { |
51 |
AVPicture pic; |
52 |
avpicture_fill(&pic, src, PIX_FMT_YUV420P, width, height); |
53 |
av_picture_copy((AVPicture *)f, &pic, PIX_FMT_YUV420P, width, height); |
54 |
} |
55 |
|
56 |
/**
|
57 |
* \brief extract quantization tables from codec data into our context
|
58 |
*/
|
59 |
static int get_quant(AVCodecContext *avctx, NuvContext *c, |
60 |
uint8_t *buf, int size) {
|
61 |
int i;
|
62 |
if (size < 2 * 64 * 4) { |
63 |
av_log(avctx, AV_LOG_ERROR, "insufficient rtjpeg quant data\n");
|
64 |
return -1; |
65 |
} |
66 |
for (i = 0; i < 64; i++, buf += 4) |
67 |
c->lq[i] = AV_RL32(buf); |
68 |
for (i = 0; i < 64; i++, buf += 4) |
69 |
c->cq[i] = AV_RL32(buf); |
70 |
return 0; |
71 |
} |
72 |
|
73 |
static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, |
74 |
uint8_t *buf, int buf_size) {
|
75 |
NuvContext *c = avctx->priv_data; |
76 |
AVFrame *picture = data; |
77 |
int orig_size = buf_size;
|
78 |
enum {NUV_UNCOMPRESSED = '0', NUV_RTJPEG = '1', |
79 |
NUV_RTJPEG_IN_LZO = '2', NUV_LZO = '3', |
80 |
NUV_BLACK = 'N', NUV_COPY_LAST = 'L'} comptype; |
81 |
|
82 |
if (buf_size < 12) { |
83 |
av_log(avctx, AV_LOG_ERROR, "coded frame too small\n");
|
84 |
return -1; |
85 |
} |
86 |
|
87 |
if (c->pic.data[0]) |
88 |
avctx->release_buffer(avctx, &c->pic); |
89 |
c->pic.reference = 1;
|
90 |
c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_READABLE | |
91 |
FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; |
92 |
if (avctx->get_buffer(avctx, &c->pic) < 0) { |
93 |
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
|
94 |
return -1; |
95 |
} |
96 |
|
97 |
// codec data (rtjpeg quant tables)
|
98 |
if (buf[0] == 'D' && buf[1] == 'R') { |
99 |
int ret;
|
100 |
// skip rest of the frameheader.
|
101 |
buf = &buf[12];
|
102 |
buf_size -= 12;
|
103 |
ret = get_quant(avctx, c, buf, buf_size); |
104 |
if (ret < 0) |
105 |
return ret;
|
106 |
rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq); |
107 |
return orig_size;
|
108 |
} |
109 |
|
110 |
if (buf[0] != 'V' || buf_size < 12) { |
111 |
av_log(avctx, AV_LOG_ERROR, "not a nuv video frame\n");
|
112 |
return -1; |
113 |
} |
114 |
comptype = buf[1];
|
115 |
// skip rest of the frameheader.
|
116 |
buf = &buf[12];
|
117 |
buf_size -= 12;
|
118 |
|
119 |
c->pic.pict_type = FF_I_TYPE; |
120 |
c->pic.key_frame = 1;
|
121 |
// decompress/copy/whatever data
|
122 |
switch (comptype) {
|
123 |
case NUV_UNCOMPRESSED: {
|
124 |
int height = c->height;
|
125 |
if (buf_size < c->width * height * 3 / 2) { |
126 |
av_log(avctx, AV_LOG_ERROR, "uncompressed frame too short\n");
|
127 |
height = buf_size / c->width / 3 * 2; |
128 |
} |
129 |
copy_frame(&c->pic, buf, c->width, height); |
130 |
break;
|
131 |
} |
132 |
case NUV_RTJPEG: {
|
133 |
rtjpeg_decode_frame_yuv420(&c->rtj, &c->pic, buf, buf_size); |
134 |
break;
|
135 |
} |
136 |
case NUV_RTJPEG_IN_LZO: {
|
137 |
int outlen = c->decomp_size, inlen = buf_size;
|
138 |
if (lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen))
|
139 |
av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n");
|
140 |
rtjpeg_decode_frame_yuv420(&c->rtj, &c->pic, c->decomp_buf, c->decomp_size); |
141 |
break;
|
142 |
} |
143 |
case NUV_LZO: {
|
144 |
int outlen = c->decomp_size, inlen = buf_size;
|
145 |
if (lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen))
|
146 |
av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n");
|
147 |
copy_frame(&c->pic, c->decomp_buf, c->width, c->height); |
148 |
break;
|
149 |
} |
150 |
case NUV_BLACK: {
|
151 |
memset(c->pic.data[0], 0, c->width * c->height); |
152 |
memset(c->pic.data[1], 128, c->width * c->height / 4); |
153 |
memset(c->pic.data[2], 128, c->width * c->height / 4); |
154 |
break;
|
155 |
} |
156 |
case NUV_COPY_LAST: {
|
157 |
c->pic.pict_type = FF_P_TYPE; |
158 |
c->pic.key_frame = 0;
|
159 |
/* nothing more to do here */
|
160 |
break;
|
161 |
} |
162 |
default:
|
163 |
av_log(avctx, AV_LOG_ERROR, "unknown compression\n");
|
164 |
return -1; |
165 |
} |
166 |
|
167 |
*picture = c->pic; |
168 |
*data_size = sizeof(AVFrame);
|
169 |
return orig_size;
|
170 |
} |
171 |
|
172 |
static int decode_init(AVCodecContext *avctx) { |
173 |
NuvContext *c = avctx->priv_data; |
174 |
avctx->width = (avctx->width + 1) & ~1; |
175 |
avctx->height = (avctx->height + 1) & ~1; |
176 |
if (avcodec_check_dimensions(avctx, avctx->height, avctx->width) < 0) { |
177 |
return 1; |
178 |
} |
179 |
avctx->pix_fmt = PIX_FMT_YUV420P; |
180 |
c->pic.data[0] = NULL; |
181 |
c->width = avctx->width; |
182 |
c->height = avctx->height; |
183 |
c->decomp_size = c->height * c->width * 3 / 2; |
184 |
c->decomp_buf = av_malloc(c->decomp_size + LZO_OUTPUT_PADDING); |
185 |
if (!c->decomp_buf) {
|
186 |
av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n");
|
187 |
return 1; |
188 |
} |
189 |
dsputil_init(&c->dsp, avctx); |
190 |
if (avctx->extradata_size)
|
191 |
get_quant(avctx, c, avctx->extradata, avctx->extradata_size); |
192 |
rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq); |
193 |
return 0; |
194 |
} |
195 |
|
196 |
static int decode_end(AVCodecContext *avctx) { |
197 |
NuvContext *c = avctx->priv_data; |
198 |
av_freep(&c->decomp_buf); |
199 |
if (c->pic.data[0]) |
200 |
avctx->release_buffer(avctx, &c->pic); |
201 |
return 0; |
202 |
} |
203 |
|
204 |
AVCodec nuv_decoder = { |
205 |
"nuv",
|
206 |
CODEC_TYPE_VIDEO, |
207 |
CODEC_ID_NUV, |
208 |
sizeof(NuvContext),
|
209 |
decode_init, |
210 |
NULL,
|
211 |
decode_end, |
212 |
decode_frame, |
213 |
CODEC_CAP_DR1, |
214 |
}; |
215 |
|