Originally committed as revision 5232 to svn://svn.ffmpeg.org/ffmpeg/trunk
Reimar Döffinger authored on 2006/03/28 07:22:50... | ... |
@@ -134,6 +134,7 @@ Codecs: |
134 | 134 |
msmpeg4.c, msmpeg4data.h Michael Niedermayer |
135 | 135 |
msrle.c Mike Melanson |
136 | 136 |
msvideo1.c Mike Melanson |
137 |
+ nuv.c Reimar Doeffinger |
|
137 | 138 |
oggtheora.c Mans Rullgard |
138 | 139 |
qdm2.c, qdm2data.h Roberto Togni |
139 | 140 |
qdrw.c Kostya Shishkov |
... | ... |
@@ -142,6 +143,7 @@ Codecs: |
142 | 142 |
ra144.c, ra144.h, ra288.c, ra288.h Roberto Togni |
143 | 143 |
resample2.c Michael Niedermayer |
144 | 144 |
rpza.c Roberto Togni |
145 |
+ rtjpeg.c, rtjpeg.h Reimar Doeffinger |
|
145 | 146 |
rv10.c Michael Niedermayer |
146 | 147 |
smc.c Mike Melanson |
147 | 148 |
snow.c Michael Niedermayer, Loren Merritt |
... | ... |
@@ -191,6 +193,7 @@ Muxers/Demuxers: |
191 | 191 |
mpegts* Mans Rullgard |
192 | 192 |
nsvdec.c Francois Revol |
193 | 193 |
nut.c Alex Beregszaszi |
194 |
+ nuv.c Reimar Doeffinger |
|
194 | 195 |
ogg2.c, ogg2.h Mans Rullgard |
195 | 196 |
oggparsevorbis.c Mans Rullgard |
196 | 197 |
psxstr.c Mike Melanson |
... | ... |
@@ -799,6 +799,7 @@ following image formats are supported: |
799 | 799 |
@item ZMBV @tab @tab X @tab |
800 | 800 |
@item AVS Video @tab @tab X @tab Video encoding used by the Creature Shock game. |
801 | 801 |
@item Smacker Video @tab @tab X @tab Video encoding used in Smacker. |
802 |
+@item RTjpeg @tab @tab X @tab Video encoding used in NuppelVideo files. |
|
802 | 803 |
@end multitable |
803 | 804 |
|
804 | 805 |
@code{X} means that encoding (resp. decoding) is supported. |
... | ... |
@@ -180,6 +180,11 @@ ifeq ($(CONFIG_CSCD_DECODER),yes) |
180 | 180 |
OBJS+= cscd.o |
181 | 181 |
OBJS+= lzo.o |
182 | 182 |
endif |
183 |
+ifeq ($(CONFIG_NUV_DECODER),yes) |
|
184 |
+ OBJS+= nuv.o |
|
185 |
+ OBJS+= rtjpeg.o |
|
186 |
+ OBJS+= lzo.o |
|
187 |
+endif |
|
183 | 188 |
ifeq ($(CONFIG_ULTI_DECODER),yes) |
184 | 189 |
OBJS+= ulti.o |
185 | 190 |
endif |
... | ... |
@@ -267,6 +267,9 @@ void avcodec_register_all(void) |
267 | 267 |
#ifdef CONFIG_CSCD_DECODER |
268 | 268 |
register_avcodec(&cscd_decoder); |
269 | 269 |
#endif //CONFIG_CSCD_DECODER |
270 |
+#ifdef CONFIG_NUV_DECODER |
|
271 |
+ register_avcodec(&nuv_decoder); |
|
272 |
+#endif //CONFIG_NUV_DECODER |
|
270 | 273 |
#ifdef CONFIG_ULTI_DECODER |
271 | 274 |
register_avcodec(&ulti_decoder); |
272 | 275 |
#endif //CONFIG_ULTI_DECODER |
... | ... |
@@ -119,6 +119,7 @@ enum CodecID { |
119 | 119 |
CODEC_ID_ZMBV, |
120 | 120 |
CODEC_ID_AVS, |
121 | 121 |
CODEC_ID_SMACKVIDEO, |
122 |
+ CODEC_ID_NUV, |
|
122 | 123 |
|
123 | 124 |
/* various pcm "codecs" */ |
124 | 125 |
CODEC_ID_PCM_S16LE= 0x10000, |
... | ... |
@@ -2221,6 +2222,7 @@ extern AVCodec qtrle_decoder; |
2221 | 2221 |
extern AVCodec flac_decoder; |
2222 | 2222 |
extern AVCodec tscc_decoder; |
2223 | 2223 |
extern AVCodec cscd_decoder; |
2224 |
+extern AVCodec nuv_decoder; |
|
2224 | 2225 |
extern AVCodec ulti_decoder; |
2225 | 2226 |
extern AVCodec qdraw_decoder; |
2226 | 2227 |
extern AVCodec xl_decoder; |
2227 | 2228 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,214 @@ |
0 |
+/* |
|
1 |
+ * NuppelVideo decoder |
|
2 |
+ * Copyright (c) 2006 Reimar Doeffinger |
|
3 |
+ * |
|
4 |
+ * This library is free software; you can redistribute it and/or |
|
5 |
+ * modify it under the terms of the GNU Lesser General Public |
|
6 |
+ * License as published by the Free Software Foundation; either |
|
7 |
+ * version 2 of the License, or (at your option) any later version. |
|
8 |
+ * |
|
9 |
+ * This library is distributed in the hope that it will be useful, |
|
10 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
12 |
+ * Lesser General Public License for more details. |
|
13 |
+ * |
|
14 |
+ * You should have received a copy of the GNU Lesser General Public |
|
15 |
+ * License along with this library; if not, write to the Free Software |
|
16 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
17 |
+ */ |
|
18 |
+#include <stdio.h> |
|
19 |
+#include <stdlib.h> |
|
20 |
+ |
|
21 |
+#include "common.h" |
|
22 |
+#include "avcodec.h" |
|
23 |
+ |
|
24 |
+#include "bswap.h" |
|
25 |
+#include "dsputil.h" |
|
26 |
+#include "lzo.h" |
|
27 |
+#include "rtjpeg.h" |
|
28 |
+ |
|
29 |
+typedef struct { |
|
30 |
+ AVFrame pic; |
|
31 |
+ int width, height; |
|
32 |
+ unsigned int decomp_size; |
|
33 |
+ unsigned char* decomp_buf; |
|
34 |
+ uint32_t lq[64], cq[64]; |
|
35 |
+ RTJpegContext rtj; |
|
36 |
+ DSPContext dsp; |
|
37 |
+} NuvContext; |
|
38 |
+ |
|
39 |
+/** |
|
40 |
+ * \brief copy frame data from buffer to AVFrame, handling stride. |
|
41 |
+ * \param f destination AVFrame |
|
42 |
+ * \param src source buffer, does not use any line-stride |
|
43 |
+ * \param width width of the video frame |
|
44 |
+ * \param height height of the video frame |
|
45 |
+ */ |
|
46 |
+static void copy_frame(AVFrame *f, uint8_t *src, |
|
47 |
+ int width, int height) { |
|
48 |
+ AVPicture pic; |
|
49 |
+ avpicture_fill(&pic, src, PIX_FMT_YUV420P, width, height); |
|
50 |
+ img_copy((AVPicture *)f, &pic, PIX_FMT_YUV420P, width, height); |
|
51 |
+} |
|
52 |
+ |
|
53 |
+/** |
|
54 |
+ * \brief extract quantization tables from codec data into our context |
|
55 |
+ */ |
|
56 |
+static int get_quant(AVCodecContext *avctx, NuvContext *c, |
|
57 |
+ uint8_t *buf, int size) { |
|
58 |
+ int i; |
|
59 |
+ if (size < 2 * 64 * 4) { |
|
60 |
+ av_log(avctx, AV_LOG_ERROR, "insufficient rtjpeg quant data\n"); |
|
61 |
+ return -1; |
|
62 |
+ } |
|
63 |
+ for (i = 0; i < 64; i++, buf += 4) |
|
64 |
+ c->lq[i] = LE_32(buf); |
|
65 |
+ for (i = 0; i < 64; i++, buf += 4) |
|
66 |
+ c->cq[i] = LE_32(buf); |
|
67 |
+ return 0; |
|
68 |
+} |
|
69 |
+ |
|
70 |
+static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, |
|
71 |
+ uint8_t *buf, int buf_size) { |
|
72 |
+ NuvContext *c = (NuvContext *)avctx->priv_data; |
|
73 |
+ AVFrame *picture = data; |
|
74 |
+ int orig_size = buf_size; |
|
75 |
+ enum {NUV_UNCOMPRESSED = '0', NUV_RTJPEG = '1', |
|
76 |
+ NUV_RTJPEG_IN_LZO = '2', NUV_LZO = '3', |
|
77 |
+ NUV_BLACK = 'N', NUV_COPY_LAST = 'L'} comptype; |
|
78 |
+ |
|
79 |
+ if (buf_size < 12) { |
|
80 |
+ av_log(avctx, AV_LOG_ERROR, "coded frame too small\n"); |
|
81 |
+ return -1; |
|
82 |
+ } |
|
83 |
+ |
|
84 |
+ if (c->pic.data[0]) |
|
85 |
+ avctx->release_buffer(avctx, &c->pic); |
|
86 |
+ c->pic.reference = 1; |
|
87 |
+ c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_READABLE | |
|
88 |
+ FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; |
|
89 |
+ if (avctx->get_buffer(avctx, &c->pic) < 0) { |
|
90 |
+ av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); |
|
91 |
+ return -1; |
|
92 |
+ } |
|
93 |
+ |
|
94 |
+ // codec data (rtjpeg quant tables) |
|
95 |
+ if (buf[0] == 'D' && buf[1] == 'R') { |
|
96 |
+ int ret; |
|
97 |
+ // skip rest of the frameheader. |
|
98 |
+ buf = &buf[12]; |
|
99 |
+ buf_size -= 12; |
|
100 |
+ ret = get_quant(avctx, c, buf, buf_size); |
|
101 |
+ if (ret < 0) |
|
102 |
+ return ret; |
|
103 |
+ rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq); |
|
104 |
+ return orig_size; |
|
105 |
+ } |
|
106 |
+ |
|
107 |
+ if (buf[0] != 'V' || buf_size < 12) { |
|
108 |
+ av_log(avctx, AV_LOG_ERROR, "not a nuv video frame\n"); |
|
109 |
+ return -1; |
|
110 |
+ } |
|
111 |
+ comptype = buf[1]; |
|
112 |
+ // skip rest of the frameheader. |
|
113 |
+ buf = &buf[12]; |
|
114 |
+ buf_size -= 12; |
|
115 |
+ |
|
116 |
+ c->pic.pict_type = FF_I_TYPE; |
|
117 |
+ c->pic.key_frame = 1; |
|
118 |
+ // decompress/copy/whatever data |
|
119 |
+ switch (comptype) { |
|
120 |
+ case NUV_UNCOMPRESSED: { |
|
121 |
+ int height = c->height; |
|
122 |
+ if (buf_size < c->width * height * 3 / 2) { |
|
123 |
+ av_log(avctx, AV_LOG_ERROR, "uncompressed frame too short\n"); |
|
124 |
+ height = buf_size / c->width / 3 * 2; |
|
125 |
+ } |
|
126 |
+ copy_frame(&c->pic, buf, c->width, height); |
|
127 |
+ break; |
|
128 |
+ } |
|
129 |
+ case NUV_RTJPEG: { |
|
130 |
+ rtjpeg_decode_frame_yuv420(&c->rtj, &c->pic, buf, buf_size); |
|
131 |
+ break; |
|
132 |
+ } |
|
133 |
+ case NUV_RTJPEG_IN_LZO: { |
|
134 |
+ int outlen = c->decomp_size, inlen = buf_size; |
|
135 |
+ if (lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen)) |
|
136 |
+ av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n"); |
|
137 |
+ rtjpeg_decode_frame_yuv420(&c->rtj, &c->pic, c->decomp_buf, c->decomp_size); |
|
138 |
+ break; |
|
139 |
+ } |
|
140 |
+ case NUV_LZO: { |
|
141 |
+ int outlen = c->decomp_size, inlen = buf_size; |
|
142 |
+ if (lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen)) |
|
143 |
+ av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n"); |
|
144 |
+ copy_frame(&c->pic, c->decomp_buf, c->width, c->height); |
|
145 |
+ break; |
|
146 |
+ } |
|
147 |
+ case NUV_BLACK: { |
|
148 |
+ memset(c->pic.data[0], 0, c->width * c->height); |
|
149 |
+ memset(c->pic.data[1], 128, c->width * c->height / 4); |
|
150 |
+ memset(c->pic.data[2], 128, c->width * c->height / 4); |
|
151 |
+ break; |
|
152 |
+ } |
|
153 |
+ case NUV_COPY_LAST: { |
|
154 |
+ c->pic.pict_type = FF_P_TYPE; |
|
155 |
+ c->pic.key_frame = 0; |
|
156 |
+ /* nothing more to do here */ |
|
157 |
+ break; |
|
158 |
+ } |
|
159 |
+ default: |
|
160 |
+ av_log(avctx, AV_LOG_ERROR, "unknown compression\n"); |
|
161 |
+ return -1; |
|
162 |
+ } |
|
163 |
+ |
|
164 |
+ *picture = c->pic; |
|
165 |
+ *data_size = sizeof(AVFrame); |
|
166 |
+ return orig_size; |
|
167 |
+} |
|
168 |
+ |
|
169 |
+static int decode_init(AVCodecContext *avctx) { |
|
170 |
+ NuvContext *c = (NuvContext *)avctx->priv_data; |
|
171 |
+ avctx->width = (avctx->width + 1) & ~1; |
|
172 |
+ avctx->height = (avctx->height + 1) & ~1; |
|
173 |
+ if (avcodec_check_dimensions(avctx, avctx->height, avctx->width) < 0) { |
|
174 |
+ return 1; |
|
175 |
+ } |
|
176 |
+ avctx->has_b_frames = 0; |
|
177 |
+ avctx->pix_fmt = PIX_FMT_YUV420P; |
|
178 |
+ c->pic.data[0] = NULL; |
|
179 |
+ c->width = avctx->width; |
|
180 |
+ c->height = avctx->height; |
|
181 |
+ c->decomp_size = c->height * c->width * 3 / 2; |
|
182 |
+ c->decomp_buf = av_malloc(c->decomp_size + LZO_OUTPUT_PADDING); |
|
183 |
+ if (!c->decomp_buf) { |
|
184 |
+ av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n"); |
|
185 |
+ return 1; |
|
186 |
+ } |
|
187 |
+ dsputil_init(&c->dsp, avctx); |
|
188 |
+ if (avctx->extradata_size) |
|
189 |
+ get_quant(avctx, c, avctx->extradata, avctx->extradata_size); |
|
190 |
+ rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq); |
|
191 |
+ return 0; |
|
192 |
+} |
|
193 |
+ |
|
194 |
+static int decode_end(AVCodecContext *avctx) { |
|
195 |
+ NuvContext *c = (NuvContext *)avctx->priv_data; |
|
196 |
+ av_freep(&c->decomp_buf); |
|
197 |
+ if (c->pic.data[0]) |
|
198 |
+ avctx->release_buffer(avctx, &c->pic); |
|
199 |
+ return 0; |
|
200 |
+} |
|
201 |
+ |
|
202 |
+AVCodec nuv_decoder = { |
|
203 |
+ "nuv", |
|
204 |
+ CODEC_TYPE_VIDEO, |
|
205 |
+ CODEC_ID_NUV, |
|
206 |
+ sizeof(NuvContext), |
|
207 |
+ decode_init, |
|
208 |
+ NULL, |
|
209 |
+ decode_end, |
|
210 |
+ decode_frame, |
|
211 |
+ CODEC_CAP_DR1, |
|
212 |
+}; |
|
213 |
+ |
0 | 214 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,162 @@ |
0 |
+/* |
|
1 |
+ * RTJpeg decoding functions |
|
2 |
+ * Copyright (c) 2006 Reimar Doeffinger |
|
3 |
+ * |
|
4 |
+ * This library is free software; you can redistribute it and/or |
|
5 |
+ * modify it under the terms of the GNU Lesser General Public |
|
6 |
+ * License as published by the Free Software Foundation; either |
|
7 |
+ * version 2 of the License, or (at your option) any later version. |
|
8 |
+ * |
|
9 |
+ * This library is distributed in the hope that it will be useful, |
|
10 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
12 |
+ * Lesser General Public License for more details. |
|
13 |
+ * |
|
14 |
+ * You should have received a copy of the GNU Lesser General Public |
|
15 |
+ * License along with this library; if not, write to the Free Software |
|
16 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
17 |
+ */ |
|
18 |
+#include "common.h" |
|
19 |
+#include "bitstream.h" |
|
20 |
+#include "dsputil.h" |
|
21 |
+#include "rtjpeg.h" |
|
22 |
+ |
|
23 |
+#define PUT_COEFF(c) \ |
|
24 |
+ i = scan[coeff--]; \ |
|
25 |
+ block[i] = (c) * quant[i]; |
|
26 |
+ |
|
27 |
+//! aligns the bitstream to the give power of two |
|
28 |
+#define ALIGN(a) \ |
|
29 |
+ n = (-get_bits_count(gb)) & (a - 1); \ |
|
30 |
+ if (n) {skip_bits(gb, n);} |
|
31 |
+ |
|
32 |
+/** |
|
33 |
+ * \brief read one block from stream |
|
34 |
+ * \param gb contains stream data |
|
35 |
+ * \param block where data is written to |
|
36 |
+ * \param scan array containing the mapping stream address -> block position |
|
37 |
+ * \param quant quantization factors |
|
38 |
+ * |
|
39 |
+ * Note: GetBitContext is used to make the code simpler, since all data is |
|
40 |
+ * aligned this could be done faster in a different way, e.g. as it is done |
|
41 |
+ * in MPlayer libmpcodecs/native/RTjpegN.c |
|
42 |
+ */ |
|
43 |
+static inline int get_block(GetBitContext *gb, DCTELEM *block, uint8_t *scan, |
|
44 |
+ uint32_t *quant) { |
|
45 |
+ int coeff, i, n; |
|
46 |
+ int8_t ac; |
|
47 |
+ uint8_t dc = get_bits(gb, 8); |
|
48 |
+ |
|
49 |
+ // block not coded |
|
50 |
+ if (dc == 255) |
|
51 |
+ return 0; |
|
52 |
+ |
|
53 |
+ // number of non-zero coefficients |
|
54 |
+ coeff = get_bits(gb, 6); |
|
55 |
+ // normally we would only need to clear the (63 - coeff) last values, |
|
56 |
+ // but since we do not know where they are we just clear the whole block |
|
57 |
+ memset(block, 0, 64 * sizeof(DCTELEM)); |
|
58 |
+ |
|
59 |
+ // 2 bits per coefficient |
|
60 |
+ while (coeff) { |
|
61 |
+ ac = get_sbits(gb, 2); |
|
62 |
+ if (ac == -2) |
|
63 |
+ break; // continue with more bits |
|
64 |
+ PUT_COEFF(ac); |
|
65 |
+ } |
|
66 |
+ |
|
67 |
+ // 4 bits per coefficient |
|
68 |
+ ALIGN(4); |
|
69 |
+ while (coeff) { |
|
70 |
+ ac = get_sbits(gb, 4); |
|
71 |
+ if (ac == -8) |
|
72 |
+ break; // continue with more bits |
|
73 |
+ PUT_COEFF(ac); |
|
74 |
+ } |
|
75 |
+ |
|
76 |
+ // 8 bits per coefficient |
|
77 |
+ ALIGN(8); |
|
78 |
+ while (coeff) { |
|
79 |
+ ac = get_sbits(gb, 8); |
|
80 |
+ PUT_COEFF(ac); |
|
81 |
+ } |
|
82 |
+ |
|
83 |
+ PUT_COEFF(dc); |
|
84 |
+ return 1; |
|
85 |
+} |
|
86 |
+ |
|
87 |
+/** |
|
88 |
+ * \brief decode one rtjpeg YUV420 frame |
|
89 |
+ * \param c context, must be initialized via rtjpeg_decode_init |
|
90 |
+ * \param f AVFrame to place decoded frame into. If parts of the frame |
|
91 |
+ * are not coded they are left unchanged, so consider initializing it |
|
92 |
+ * \param buf buffer containing input data |
|
93 |
+ * \param buf_size length of input data in bytes |
|
94 |
+ * \return number of bytes consumed from the input buffer |
|
95 |
+ */ |
|
96 |
+int rtjpeg_decode_frame_yuv420(RTJpegContext *c, AVFrame *f, |
|
97 |
+ uint8_t *buf, int buf_size) { |
|
98 |
+ GetBitContext gb; |
|
99 |
+ int w = c->w / 16, h = c->h / 16; |
|
100 |
+ int x, y; |
|
101 |
+ void *y1 = f->data[0], *y2 = f->data[0] + 8 * f->linesize[0]; |
|
102 |
+ void *u = f->data[1], *v = f->data[2]; |
|
103 |
+ init_get_bits(&gb, buf, buf_size * 8); |
|
104 |
+ for (y = 0; y < h; y++) { |
|
105 |
+ for (x = 0; x < w; x++) { |
|
106 |
+ if (get_block(&gb, c->block, c->scan, c->lquant)) |
|
107 |
+ c->dsp->idct_put(y1, f->linesize[0], c->block); |
|
108 |
+ y1 += 8; |
|
109 |
+ if (get_block(&gb, c->block, c->scan, c->lquant)) |
|
110 |
+ c->dsp->idct_put(y1, f->linesize[0], c->block); |
|
111 |
+ y1 += 8; |
|
112 |
+ if (get_block(&gb, c->block, c->scan, c->lquant)) |
|
113 |
+ c->dsp->idct_put(y2, f->linesize[0], c->block); |
|
114 |
+ y2 += 8; |
|
115 |
+ if (get_block(&gb, c->block, c->scan, c->lquant)) |
|
116 |
+ c->dsp->idct_put(y2, f->linesize[0], c->block); |
|
117 |
+ y2 += 8; |
|
118 |
+ if (get_block(&gb, c->block, c->scan, c->cquant)) |
|
119 |
+ c->dsp->idct_put(u, f->linesize[1], c->block); |
|
120 |
+ u += 8; |
|
121 |
+ if (get_block(&gb, c->block, c->scan, c->cquant)) |
|
122 |
+ c->dsp->idct_put(v, f->linesize[2], c->block); |
|
123 |
+ v += 8; |
|
124 |
+ } |
|
125 |
+ y1 += 2 * 8 * (f->linesize[0] - w); |
|
126 |
+ y2 += 2 * 8 * (f->linesize[0] - w); |
|
127 |
+ u += 8 * (f->linesize[1] - w); |
|
128 |
+ v += 8 * (f->linesize[2] - w); |
|
129 |
+ } |
|
130 |
+ return get_bits_count(&gb) / 8; |
|
131 |
+} |
|
132 |
+ |
|
133 |
+/** |
|
134 |
+ * \brief initialize an RTJpegContext, may be called multiple times |
|
135 |
+ * \param c context to initialize |
|
136 |
+ * \param dsp specifies the idct to use for decoding |
|
137 |
+ * \param width width of image, will be rounded down to the nearest multiple |
|
138 |
+ * of 16 for decoding |
|
139 |
+ * \param height height of image, will be rounded down to the nearest multiple |
|
140 |
+ * of 16 for decoding |
|
141 |
+ * \param lquant luma quantization table to use |
|
142 |
+ * \param cquant chroma quantization table to use |
|
143 |
+ */ |
|
144 |
+void rtjpeg_decode_init(RTJpegContext *c, DSPContext *dsp, |
|
145 |
+ int width, int height, |
|
146 |
+ uint32_t *lquant, uint32_t *cquant) { |
|
147 |
+ int i; |
|
148 |
+ c->dsp = dsp; |
|
149 |
+ for (i = 0; i < 64; i++) { |
|
150 |
+ int z = ff_zigzag_direct[i]; |
|
151 |
+ int p = c->dsp->idct_permutation[i]; |
|
152 |
+ z = ((z << 3) | (z >> 3)) & 63; // rtjpeg uses a transposed variant |
|
153 |
+ |
|
154 |
+ // permute the scan and quantization tables for the chosen idct |
|
155 |
+ c->scan[i] = c->dsp->idct_permutation[z]; |
|
156 |
+ c->lquant[p] = lquant[i]; |
|
157 |
+ c->cquant[p] = cquant[i]; |
|
158 |
+ } |
|
159 |
+ c->w = width; |
|
160 |
+ c->h = height; |
|
161 |
+} |
0 | 162 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,19 @@ |
0 |
+#ifndef RTJPEG_H |
|
1 |
+#define RTJPEG_H |
|
2 |
+ |
|
3 |
+typedef struct { |
|
4 |
+ int w, h; |
|
5 |
+ DSPContext *dsp; |
|
6 |
+ DCTELEM block[64]; |
|
7 |
+ uint8_t scan[64]; |
|
8 |
+ uint32_t lquant[64]; |
|
9 |
+ uint32_t cquant[64]; |
|
10 |
+} RTJpegContext; |
|
11 |
+ |
|
12 |
+void rtjpeg_decode_init(RTJpegContext *c, DSPContext *dsp, |
|
13 |
+ int width, int height, |
|
14 |
+ uint32_t *lquant, uint32_t *cquant); |
|
15 |
+ |
|
16 |
+int rtjpeg_decode_frame_yuv420(RTJpegContext *c, AVFrame *f, |
|
17 |
+ uint8_t *buf, int buf_size); |
|
18 |
+#endif |
... | ... |
@@ -18,7 +18,7 @@ OBJS+=mpeg.o mpegts.o mpegtsenc.o ffm.o crc.o img.o img2.o raw.o rm.o \ |
18 | 18 |
nut.o wc3movie.o mp3.o westwood.o segafilm.o idcin.o flic.o \ |
19 | 19 |
sierravmd.o matroska.o sol.o electronicarts.o nsvdec.o asf.o \ |
20 | 20 |
ogg2.o oggparsevorbis.o oggparsetheora.o oggparseflac.o daud.o aiff.o \ |
21 |
- voc.o tta.o mm.o avs.o smacker.o |
|
21 |
+ voc.o tta.o mm.o avs.o smacker.o nuv.o |
|
22 | 22 |
|
23 | 23 |
# muxers |
24 | 24 |
ifeq ($(CONFIG_MUXERS),yes) |
555 | 558 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,245 @@ |
0 |
+/* |
|
1 |
+ * NuppelVideo demuxer. |
|
2 |
+ * Copyright (c) 2006 Reimar Doeffinger. |
|
3 |
+ * |
|
4 |
+ * This library is free software; you can redistribute it and/or |
|
5 |
+ * modify it under the terms of the GNU Lesser General Public |
|
6 |
+ * License as published by the Free Software Foundation; either |
|
7 |
+ * version 2 of the License, or (at your option) any later version. |
|
8 |
+ * |
|
9 |
+ * This library is distributed in the hope that it will be useful, |
|
10 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
12 |
+ * Lesser General Public License for more details. |
|
13 |
+ * |
|
14 |
+ * You should have received a copy of the GNU Lesser General Public |
|
15 |
+ * License along with this library; if not, write to the Free Software |
|
16 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
17 |
+ */ |
|
18 |
+#include "avformat.h" |
|
19 |
+#include "avi.h" |
|
20 |
+ |
|
21 |
+typedef struct { |
|
22 |
+ int v_id; |
|
23 |
+ int a_id; |
|
24 |
+} NUVContext; |
|
25 |
+ |
|
26 |
+typedef enum { |
|
27 |
+ NUV_VIDEO = 'V', |
|
28 |
+ NUV_EXTRADATA = 'D', |
|
29 |
+ NUV_AUDIO = 'A', |
|
30 |
+ NUV_SEEKP = 'R', |
|
31 |
+ NUV_MYTHEXT = 'X' |
|
32 |
+} frametype_t; |
|
33 |
+ |
|
34 |
+static int nuv_probe(AVProbeData *p) { |
|
35 |
+ if (p->buf_size < 12) |
|
36 |
+ return 0; |
|
37 |
+ if (!memcmp(p->buf, "NuppelVideo", 12)) |
|
38 |
+ return AVPROBE_SCORE_MAX; |
|
39 |
+ if (!memcmp(p->buf, "MythTVVideo", 12)) |
|
40 |
+ return AVPROBE_SCORE_MAX; |
|
41 |
+ return 0; |
|
42 |
+} |
|
43 |
+ |
|
44 |
+//! little macro to sanitize packet size |
|
45 |
+#define PKTSIZE(s) (s & 0xffffff) |
|
46 |
+ |
|
47 |
+/** |
|
48 |
+ * \brief read until we found all data needed for decoding |
|
49 |
+ * \param vst video stream of which to change parameters |
|
50 |
+ * \param ast video stream of which to change parameters |
|
51 |
+ * \param myth set if this is a MythTVVideo format file |
|
52 |
+ * \return 1 if all required codec data was found |
|
53 |
+ */ |
|
54 |
+static int get_codec_data(ByteIOContext *pb, AVStream *vst, |
|
55 |
+ AVStream *ast, int myth) { |
|
56 |
+ frametype_t frametype; |
|
57 |
+ if (!vst && !myth) |
|
58 |
+ return 1; // no codec data needed |
|
59 |
+ while (!url_feof(pb)) { |
|
60 |
+ int size, subtype; |
|
61 |
+ frametype = get_byte(pb); |
|
62 |
+ switch (frametype) { |
|
63 |
+ case NUV_EXTRADATA: |
|
64 |
+ subtype = get_byte(pb); |
|
65 |
+ url_fskip(pb, 6); |
|
66 |
+ size = PKTSIZE(get_le32(pb)); |
|
67 |
+ if (subtype == 'R') { |
|
68 |
+ vst->codec->extradata_size = size; |
|
69 |
+ vst->codec->extradata = av_malloc(size); |
|
70 |
+ get_buffer(pb, vst->codec->extradata, size); |
|
71 |
+ size = 0; |
|
72 |
+ if (!myth) |
|
73 |
+ return 1; |
|
74 |
+ } |
|
75 |
+ break; |
|
76 |
+ case NUV_MYTHEXT: |
|
77 |
+ url_fskip(pb, 7); |
|
78 |
+ size = PKTSIZE(get_le32(pb)); |
|
79 |
+ if (size != 128 * 4) |
|
80 |
+ break; |
|
81 |
+ get_le32(pb); // version |
|
82 |
+ if (vst) { |
|
83 |
+ vst->codec->codec_tag = get_le32(pb); |
|
84 |
+ vst->codec->codec_id = |
|
85 |
+ codec_get_id(codec_bmp_tags, vst->codec->codec_tag); |
|
86 |
+ } else |
|
87 |
+ url_fskip(pb, 4); |
|
88 |
+ |
|
89 |
+ if (ast) { |
|
90 |
+ ast->codec->codec_tag = get_le32(pb); |
|
91 |
+ ast->codec->sample_rate = get_le32(pb); |
|
92 |
+ ast->codec->bits_per_sample = get_le32(pb); |
|
93 |
+ ast->codec->channels = get_le32(pb); |
|
94 |
+ ast->codec->codec_id = |
|
95 |
+ wav_codec_get_id(ast->codec->codec_tag, |
|
96 |
+ ast->codec->bits_per_sample); |
|
97 |
+ } else |
|
98 |
+ url_fskip(pb, 4 * 4); |
|
99 |
+ |
|
100 |
+ size -= 6 * 4; |
|
101 |
+ url_fskip(pb, size); |
|
102 |
+ return 1; |
|
103 |
+ case NUV_SEEKP: |
|
104 |
+ size = 11; |
|
105 |
+ break; |
|
106 |
+ default: |
|
107 |
+ url_fskip(pb, 7); |
|
108 |
+ size = PKTSIZE(get_le32(pb)); |
|
109 |
+ break; |
|
110 |
+ } |
|
111 |
+ url_fskip(pb, size); |
|
112 |
+ } |
|
113 |
+ return 0; |
|
114 |
+} |
|
115 |
+ |
|
116 |
+static int nuv_header(AVFormatContext *s, AVFormatParameters *ap) { |
|
117 |
+ NUVContext *ctx = (NUVContext *)s->priv_data; |
|
118 |
+ ByteIOContext *pb = &s->pb; |
|
119 |
+ char id_string[12], version_string[5]; |
|
120 |
+ double aspect, fps; |
|
121 |
+ int is_mythtv, width, height, v_packs, a_packs; |
|
122 |
+ int stream_nr = 0; |
|
123 |
+ AVStream *vst = NULL, *ast = NULL; |
|
124 |
+ get_buffer(pb, id_string, 12); |
|
125 |
+ is_mythtv = !memcmp(id_string, "MythTVVideo", 12); |
|
126 |
+ get_buffer(pb, version_string, 5); |
|
127 |
+ url_fskip(pb, 3); // padding |
|
128 |
+ width = get_le32(pb); |
|
129 |
+ height = get_le32(pb); |
|
130 |
+ get_le32(pb); // unused, "desiredwidth" |
|
131 |
+ get_le32(pb); // unused, "desiredheight" |
|
132 |
+ get_byte(pb); // 'P' == progressive, 'I' == interlaced |
|
133 |
+ url_fskip(pb, 3); // padding |
|
134 |
+ aspect = av_int2dbl(get_le64(pb)); |
|
135 |
+ fps = av_int2dbl(get_le64(pb)); |
|
136 |
+ |
|
137 |
+ // number of packets per stream type, -1 means unknown, e.g. streaming |
|
138 |
+ v_packs = get_le32(pb); |
|
139 |
+ a_packs = get_le32(pb); |
|
140 |
+ get_le32(pb); // text |
|
141 |
+ |
|
142 |
+ get_le32(pb); // keyframe distance (?) |
|
143 |
+ |
|
144 |
+ if (v_packs) { |
|
145 |
+ ctx->v_id = stream_nr++; |
|
146 |
+ vst = av_new_stream(s, ctx->v_id); |
|
147 |
+ vst->codec->codec_type = CODEC_TYPE_VIDEO; |
|
148 |
+ vst->codec->codec_id = CODEC_ID_NUV; |
|
149 |
+ vst->codec->codec_tag = MKTAG('R', 'J', 'P', 'G'); |
|
150 |
+ vst->codec->width = width; |
|
151 |
+ vst->codec->height = height; |
|
152 |
+ vst->codec->bits_per_sample = 10; |
|
153 |
+ vst->codec->sample_aspect_ratio = av_d2q(aspect, 10000); |
|
154 |
+ vst->r_frame_rate = av_d2q(1.0 / fps, 10000); |
|
155 |
+ av_set_pts_info(vst, 32, 1, 1000); |
|
156 |
+ } else |
|
157 |
+ ctx->v_id = -1; |
|
158 |
+ |
|
159 |
+ if (a_packs) { |
|
160 |
+ ctx->a_id = stream_nr++; |
|
161 |
+ ast = av_new_stream(s, ctx->a_id); |
|
162 |
+ ast->codec->codec_type = CODEC_TYPE_AUDIO; |
|
163 |
+ ast->codec->codec_id = CODEC_ID_PCM_S16LE; |
|
164 |
+ ast->codec->channels = 2; |
|
165 |
+ ast->codec->sample_rate = 44100; |
|
166 |
+ ast->codec->bit_rate = 2 * 2 * 44100 * 8; |
|
167 |
+ ast->codec->block_align = 2 * 2; |
|
168 |
+ ast->codec->bits_per_sample = 16; |
|
169 |
+ av_set_pts_info(ast, 32, 1, 1000); |
|
170 |
+ } else |
|
171 |
+ ctx->a_id = -1; |
|
172 |
+ |
|
173 |
+ get_codec_data(pb, vst, ast, is_mythtv); |
|
174 |
+ return 0; |
|
175 |
+} |
|
176 |
+ |
|
177 |
+#define HDRSIZE 12 |
|
178 |
+ |
|
179 |
+static int nuv_packet(AVFormatContext *s, AVPacket *pkt) { |
|
180 |
+ NUVContext *ctx = (NUVContext *)s->priv_data; |
|
181 |
+ ByteIOContext *pb = &s->pb; |
|
182 |
+ uint8_t hdr[HDRSIZE]; |
|
183 |
+ frametype_t frametype; |
|
184 |
+ int ret, size; |
|
185 |
+ while (!url_feof(pb)) { |
|
186 |
+ ret = get_buffer(pb, hdr, HDRSIZE); |
|
187 |
+ if (ret <= 0) |
|
188 |
+ return ret; |
|
189 |
+ frametype = hdr[0]; |
|
190 |
+ size = PKTSIZE(LE_32(&hdr[8])); |
|
191 |
+ switch (frametype) { |
|
192 |
+ case NUV_VIDEO: |
|
193 |
+ case NUV_EXTRADATA: |
|
194 |
+ if (ctx->v_id < 0) { |
|
195 |
+ av_log(s, AV_LOG_ERROR, "Video packet in file without video stream!\n"); |
|
196 |
+ url_fskip(pb, size); |
|
197 |
+ break; |
|
198 |
+ } |
|
199 |
+ ret = av_new_packet(pkt, HDRSIZE + size); |
|
200 |
+ if (ret < 0) |
|
201 |
+ return ret; |
|
202 |
+ pkt->pos = url_ftell(pb); |
|
203 |
+ pkt->pts = LE_32(&hdr[4]); |
|
204 |
+ pkt->stream_index = ctx->v_id; |
|
205 |
+ memcpy(pkt->data, hdr, HDRSIZE); |
|
206 |
+ ret = get_buffer(pb, pkt->data + HDRSIZE, size); |
|
207 |
+ return ret; |
|
208 |
+ case NUV_AUDIO: |
|
209 |
+ if (ctx->a_id < 0) { |
|
210 |
+ av_log(s, AV_LOG_ERROR, "Audio packet in file without audio stream!\n"); |
|
211 |
+ url_fskip(pb, size); |
|
212 |
+ break; |
|
213 |
+ } |
|
214 |
+ ret = av_get_packet(pb, pkt, size); |
|
215 |
+ pkt->pts = LE_32(&hdr[4]); |
|
216 |
+ pkt->stream_index = ctx->a_id; |
|
217 |
+ return ret; |
|
218 |
+ case NUV_SEEKP: |
|
219 |
+ // contains no data, size value is invalid |
|
220 |
+ break; |
|
221 |
+ default: |
|
222 |
+ url_fskip(pb, size); |
|
223 |
+ break; |
|
224 |
+ } |
|
225 |
+ } |
|
226 |
+ return AVERROR_IO; |
|
227 |
+} |
|
228 |
+ |
|
229 |
+static AVInputFormat nuv_iformat = { |
|
230 |
+ "nuv", |
|
231 |
+ "NuppelVideo format", |
|
232 |
+ sizeof(NUVContext), |
|
233 |
+ nuv_probe, |
|
234 |
+ nuv_header, |
|
235 |
+ nuv_packet, |
|
236 |
+ NULL, |
|
237 |
+ NULL, |
|
238 |
+}; |
|
239 |
+ |
|
240 |
+int nuv_init(void) { |
|
241 |
+ av_register_input_format(&nuv_iformat); |
|
242 |
+ return 0; |
|
243 |
+} |
|
244 |
+ |
... | ... |
@@ -45,6 +45,10 @@ const CodecTag codec_wav_tags[] = { |
45 | 45 |
{ CODEC_ID_ADPCM_CT, 0x200 }, |
46 | 46 |
{ CODEC_ID_ADPCM_SWF, ('S'<<8)+'F' }, |
47 | 47 |
{ CODEC_ID_TRUESPEECH, 0x22 }, |
48 |
+ |
|
49 |
+ // for NuppelVideo (nuv.c) |
|
50 |
+ { CODEC_ID_PCM_S16LE, MKTAG('R', 'A', 'W', 'A') }, |
|
51 |
+ { CODEC_ID_MP3, MKTAG('L', 'A', 'M', 'E') }, |
|
48 | 52 |
{ 0, 0 }, |
49 | 53 |
}; |
50 | 54 |
|