Mercurial > libavcodec.hg
comparison nuv.c @ 3224:28aaf0a0135e libavcodec
NuppelVideo/MythTVVideo support, including rtjpeg decoder
author | reimar |
---|---|
date | Mon, 27 Mar 2006 22:22:50 +0000 |
parents | |
children | c8c591fe26f8 |
comparison
equal
deleted
inserted
replaced
3223:8f048c3295ff | 3224:28aaf0a0135e |
---|---|
1 /* | |
2 * NuppelVideo decoder | |
3 * Copyright (c) 2006 Reimar Doeffinger | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
18 */ | |
19 #include <stdio.h> | |
20 #include <stdlib.h> | |
21 | |
22 #include "common.h" | |
23 #include "avcodec.h" | |
24 | |
25 #include "bswap.h" | |
26 #include "dsputil.h" | |
27 #include "lzo.h" | |
28 #include "rtjpeg.h" | |
29 | |
30 typedef struct { | |
31 AVFrame pic; | |
32 int width, height; | |
33 unsigned int decomp_size; | |
34 unsigned char* decomp_buf; | |
35 uint32_t lq[64], cq[64]; | |
36 RTJpegContext rtj; | |
37 DSPContext dsp; | |
38 } NuvContext; | |
39 | |
40 /** | |
41 * \brief copy frame data from buffer to AVFrame, handling stride. | |
42 * \param f destination AVFrame | |
43 * \param src source buffer, does not use any line-stride | |
44 * \param width width of the video frame | |
45 * \param height height of the video frame | |
46 */ | |
47 static void copy_frame(AVFrame *f, uint8_t *src, | |
48 int width, int height) { | |
49 AVPicture pic; | |
50 avpicture_fill(&pic, src, PIX_FMT_YUV420P, width, height); | |
51 img_copy((AVPicture *)f, &pic, PIX_FMT_YUV420P, width, height); | |
52 } | |
53 | |
54 /** | |
55 * \brief extract quantization tables from codec data into our context | |
56 */ | |
57 static int get_quant(AVCodecContext *avctx, NuvContext *c, | |
58 uint8_t *buf, int size) { | |
59 int i; | |
60 if (size < 2 * 64 * 4) { | |
61 av_log(avctx, AV_LOG_ERROR, "insufficient rtjpeg quant data\n"); | |
62 return -1; | |
63 } | |
64 for (i = 0; i < 64; i++, buf += 4) | |
65 c->lq[i] = LE_32(buf); | |
66 for (i = 0; i < 64; i++, buf += 4) | |
67 c->cq[i] = LE_32(buf); | |
68 return 0; | |
69 } | |
70 | |
71 static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, | |
72 uint8_t *buf, int buf_size) { | |
73 NuvContext *c = (NuvContext *)avctx->priv_data; | |
74 AVFrame *picture = data; | |
75 int orig_size = buf_size; | |
76 enum {NUV_UNCOMPRESSED = '0', NUV_RTJPEG = '1', | |
77 NUV_RTJPEG_IN_LZO = '2', NUV_LZO = '3', | |
78 NUV_BLACK = 'N', NUV_COPY_LAST = 'L'} comptype; | |
79 | |
80 if (buf_size < 12) { | |
81 av_log(avctx, AV_LOG_ERROR, "coded frame too small\n"); | |
82 return -1; | |
83 } | |
84 | |
85 if (c->pic.data[0]) | |
86 avctx->release_buffer(avctx, &c->pic); | |
87 c->pic.reference = 1; | |
88 c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_READABLE | | |
89 FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; | |
90 if (avctx->get_buffer(avctx, &c->pic) < 0) { | |
91 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); | |
92 return -1; | |
93 } | |
94 | |
95 // codec data (rtjpeg quant tables) | |
96 if (buf[0] == 'D' && buf[1] == 'R') { | |
97 int ret; | |
98 // skip rest of the frameheader. | |
99 buf = &buf[12]; | |
100 buf_size -= 12; | |
101 ret = get_quant(avctx, c, buf, buf_size); | |
102 if (ret < 0) | |
103 return ret; | |
104 rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq); | |
105 return orig_size; | |
106 } | |
107 | |
108 if (buf[0] != 'V' || buf_size < 12) { | |
109 av_log(avctx, AV_LOG_ERROR, "not a nuv video frame\n"); | |
110 return -1; | |
111 } | |
112 comptype = buf[1]; | |
113 // skip rest of the frameheader. | |
114 buf = &buf[12]; | |
115 buf_size -= 12; | |
116 | |
117 c->pic.pict_type = FF_I_TYPE; | |
118 c->pic.key_frame = 1; | |
119 // decompress/copy/whatever data | |
120 switch (comptype) { | |
121 case NUV_UNCOMPRESSED: { | |
122 int height = c->height; | |
123 if (buf_size < c->width * height * 3 / 2) { | |
124 av_log(avctx, AV_LOG_ERROR, "uncompressed frame too short\n"); | |
125 height = buf_size / c->width / 3 * 2; | |
126 } | |
127 copy_frame(&c->pic, buf, c->width, height); | |
128 break; | |
129 } | |
130 case NUV_RTJPEG: { | |
131 rtjpeg_decode_frame_yuv420(&c->rtj, &c->pic, buf, buf_size); | |
132 break; | |
133 } | |
134 case NUV_RTJPEG_IN_LZO: { | |
135 int outlen = c->decomp_size, inlen = buf_size; | |
136 if (lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen)) | |
137 av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n"); | |
138 rtjpeg_decode_frame_yuv420(&c->rtj, &c->pic, c->decomp_buf, c->decomp_size); | |
139 break; | |
140 } | |
141 case NUV_LZO: { | |
142 int outlen = c->decomp_size, inlen = buf_size; | |
143 if (lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen)) | |
144 av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n"); | |
145 copy_frame(&c->pic, c->decomp_buf, c->width, c->height); | |
146 break; | |
147 } | |
148 case NUV_BLACK: { | |
149 memset(c->pic.data[0], 0, c->width * c->height); | |
150 memset(c->pic.data[1], 128, c->width * c->height / 4); | |
151 memset(c->pic.data[2], 128, c->width * c->height / 4); | |
152 break; | |
153 } | |
154 case NUV_COPY_LAST: { | |
155 c->pic.pict_type = FF_P_TYPE; | |
156 c->pic.key_frame = 0; | |
157 /* nothing more to do here */ | |
158 break; | |
159 } | |
160 default: | |
161 av_log(avctx, AV_LOG_ERROR, "unknown compression\n"); | |
162 return -1; | |
163 } | |
164 | |
165 *picture = c->pic; | |
166 *data_size = sizeof(AVFrame); | |
167 return orig_size; | |
168 } | |
169 | |
170 static int decode_init(AVCodecContext *avctx) { | |
171 NuvContext *c = (NuvContext *)avctx->priv_data; | |
172 avctx->width = (avctx->width + 1) & ~1; | |
173 avctx->height = (avctx->height + 1) & ~1; | |
174 if (avcodec_check_dimensions(avctx, avctx->height, avctx->width) < 0) { | |
175 return 1; | |
176 } | |
177 avctx->has_b_frames = 0; | |
178 avctx->pix_fmt = PIX_FMT_YUV420P; | |
179 c->pic.data[0] = NULL; | |
180 c->width = avctx->width; | |
181 c->height = avctx->height; | |
182 c->decomp_size = c->height * c->width * 3 / 2; | |
183 c->decomp_buf = av_malloc(c->decomp_size + LZO_OUTPUT_PADDING); | |
184 if (!c->decomp_buf) { | |
185 av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n"); | |
186 return 1; | |
187 } | |
188 dsputil_init(&c->dsp, avctx); | |
189 if (avctx->extradata_size) | |
190 get_quant(avctx, c, avctx->extradata, avctx->extradata_size); | |
191 rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq); | |
192 return 0; | |
193 } | |
194 | |
195 static int decode_end(AVCodecContext *avctx) { | |
196 NuvContext *c = (NuvContext *)avctx->priv_data; | |
197 av_freep(&c->decomp_buf); | |
198 if (c->pic.data[0]) | |
199 avctx->release_buffer(avctx, &c->pic); | |
200 return 0; | |
201 } | |
202 | |
203 AVCodec nuv_decoder = { | |
204 "nuv", | |
205 CODEC_TYPE_VIDEO, | |
206 CODEC_ID_NUV, | |
207 sizeof(NuvContext), | |
208 decode_init, | |
209 NULL, | |
210 decode_end, | |
211 decode_frame, | |
212 CODEC_CAP_DR1, | |
213 }; | |
214 |