Originally committed as revision 2195 to svn://svn.ffmpeg.org/ffmpeg/trunk
Mike Melanson authored on 2003/09/02 13:32:02... | ... |
@@ -17,7 +17,8 @@ OBJS= common.o utils.o mem.o allcodecs.o \ |
17 | 17 |
mpeg12.o mpegaudiodec.o pcm.o simple_idct.o \ |
18 | 18 |
ratecontrol.o adpcm.o eval.o dv.o error_resilience.o \ |
19 | 19 |
fft.o mdct.o mace.o huffyuv.o cyuv.o opts.o raw.o h264.o golomb.o \ |
20 |
- vp3.o asv1.o 4xm.o cabac.o ffv1.o ra144.o ra288.o vcr1.o cljr.o |
|
20 |
+ vp3.o asv1.o 4xm.o cabac.o ffv1.o ra144.o ra288.o vcr1.o cljr.o \ |
|
21 |
+ roqvideo.o dpcm.o interplayvideo.o |
|
21 | 22 |
|
22 | 23 |
ifeq ($(AMR_NB),yes) |
23 | 24 |
ifeq ($(AMR_NB_FIXED),yes) |
... | ... |
@@ -121,11 +121,15 @@ void avcodec_register_all(void) |
121 | 121 |
register_avcodec(&cljr_decoder); |
122 | 122 |
register_avcodec(&fourxm_decoder); |
123 | 123 |
register_avcodec(&mdec_decoder); |
124 |
+ register_avcodec(&roq_decoder); |
|
125 |
+ register_avcodec(&interplay_video_decoder); |
|
124 | 126 |
#ifdef CONFIG_AC3 |
125 | 127 |
register_avcodec(&ac3_decoder); |
126 | 128 |
#endif |
127 | 129 |
register_avcodec(&ra_144_decoder); |
128 | 130 |
register_avcodec(&ra_288_decoder); |
131 |
+ register_avcodec(&roq_dpcm_decoder); |
|
132 |
+ register_avcodec(&interplay_dpcm_decoder); |
|
129 | 133 |
#endif /* CONFIG_DECODERS */ |
130 | 134 |
|
131 | 135 |
#ifdef AMR_NB |
... | ... |
@@ -66,6 +66,8 @@ enum CodecID { |
66 | 66 |
CODEC_ID_VCR1, |
67 | 67 |
CODEC_ID_CLJR, |
68 | 68 |
CODEC_ID_MDEC, |
69 |
+ CODEC_ID_ROQ, |
|
70 |
+ CODEC_ID_INTERPLAY_VIDEO, |
|
69 | 71 |
|
70 | 72 |
/* various pcm "codecs" */ |
71 | 73 |
CODEC_ID_PCM_S16LE, |
... | ... |
@@ -88,6 +90,10 @@ enum CodecID { |
88 | 88 |
/* RealAudio codecs*/ |
89 | 89 |
CODEC_ID_RA_144, |
90 | 90 |
CODEC_ID_RA_288, |
91 |
+ |
|
92 |
+ /* various DPCM codecs */ |
|
93 |
+ CODEC_ID_ROQ_DPCM, |
|
94 |
+ CODEC_ID_INTERPLAY_DPCM, |
|
91 | 95 |
}; |
92 | 96 |
|
93 | 97 |
enum CodecType { |
... | ... |
@@ -1347,8 +1353,12 @@ extern AVCodec cljr_decoder; |
1347 | 1347 |
extern AVCodec ffv1_decoder; |
1348 | 1348 |
extern AVCodec fourxm_decoder; |
1349 | 1349 |
extern AVCodec mdec_decoder; |
1350 |
+extern AVCodec roq_decoder; |
|
1351 |
+extern AVCodec interplay_video_decoder; |
|
1350 | 1352 |
extern AVCodec ra_144_decoder; |
1351 | 1353 |
extern AVCodec ra_288_decoder; |
1354 |
+extern AVCodec roq_dpcm_decoder; |
|
1355 |
+extern AVCodec interplay_dpcm_decoder; |
|
1352 | 1356 |
|
1353 | 1357 |
/* pcm codecs */ |
1354 | 1358 |
#define PCM_CODEC(id, name) \ |
1355 | 1359 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,200 @@ |
0 |
+/* |
|
1 |
+ * Assorted DPCM codecs |
|
2 |
+ * Copyright (c) 2003 The ffmpeg Project. |
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
17 |
+ */ |
|
18 |
+ |
|
19 |
+/** |
|
20 |
+ * @file: dpcm.c |
|
21 |
+ * Assorted DPCM (differential pulse code modulation) audio codecs |
|
22 |
+ * by Mike Melanson (melanson@pcisys.net) |
|
23 |
+ * for more information on the specific data formats, visit: |
|
24 |
+ * http://www.pcisys.net/~melanson/codecs/simpleaudio.html |
|
25 |
+ */ |
|
26 |
+ |
|
27 |
+#include "avcodec.h" |
|
28 |
+ |
|
29 |
+typedef struct DPCMContext { |
|
30 |
+ int channels; |
|
31 |
+ short roq_square_array[256]; |
|
32 |
+ int last_delta[2]; |
|
33 |
+} DPCMContext; |
|
34 |
+ |
|
35 |
+#define SATURATE_S16(x) if (x < -32768) x = -32768; \ |
|
36 |
+ else if (x > 32767) x = 32767; |
|
37 |
+#define SE_16BIT(x) if (x & 0x8000) x -= 0x10000; |
|
38 |
+#define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0]) |
|
39 |
+#define LE_32(x) ((((uint8_t*)(x))[3] << 24) | \ |
|
40 |
+ (((uint8_t*)(x))[2] << 16) | \ |
|
41 |
+ (((uint8_t*)(x))[1] << 8) | \ |
|
42 |
+ ((uint8_t*)(x))[0]) |
|
43 |
+ |
|
44 |
+static int interplay_delta_table[] = { |
|
45 |
+ 0, 1, 2, 3, 4, 5, 6, 7, |
|
46 |
+ 8, 9, 10, 11, 12, 13, 14, 15, |
|
47 |
+ 16, 17, 18, 19, 20, 21, 22, 23, |
|
48 |
+ 24, 25, 26, 27, 28, 29, 30, 31, |
|
49 |
+ 32, 33, 34, 35, 36, 37, 38, 39, |
|
50 |
+ 40, 41, 42, 43, 47, 51, 56, 61, |
|
51 |
+ 66, 72, 79, 86, 94, 102, 112, 122, |
|
52 |
+ 133, 145, 158, 173, 189, 206, 225, 245, |
|
53 |
+ 267, 292, 318, 348, 379, 414, 452, 493, |
|
54 |
+ 538, 587, 640, 699, 763, 832, 908, 991, |
|
55 |
+ 1081, 1180, 1288, 1405, 1534, 1673, 1826, 1993, |
|
56 |
+ 2175, 2373, 2590, 2826, 3084, 3365, 3672, 4008, |
|
57 |
+ 4373, 4772, 5208, 5683, 6202, 6767, 7385, 8059, |
|
58 |
+ 8794, 9597, 10472, 11428, 12471, 13609, 14851, 16206, |
|
59 |
+ 17685, 19298, 21060, 22981, 25078, 27367, 29864, 32589, |
|
60 |
+ -29973, -26728, -23186, -19322, -15105, -10503, -5481, -1, |
|
61 |
+ 1, 1, 5481, 10503, 15105, 19322, 23186, 26728, |
|
62 |
+ 29973, -32589, -29864, -27367, -25078, -22981, -21060, -19298, |
|
63 |
+ -17685, -16206, -14851, -13609, -12471, -11428, -10472, -9597, |
|
64 |
+ -8794, -8059, -7385, -6767, -6202, -5683, -5208, -4772, |
|
65 |
+ -4373, -4008, -3672, -3365, -3084, -2826, -2590, -2373, |
|
66 |
+ -2175, -1993, -1826, -1673, -1534, -1405, -1288, -1180, |
|
67 |
+ -1081, -991, -908, -832, -763, -699, -640, -587, |
|
68 |
+ -538, -493, -452, -414, -379, -348, -318, -292, |
|
69 |
+ -267, -245, -225, -206, -189, -173, -158, -145, |
|
70 |
+ -133, -122, -112, -102, -94, -86, -79, -72, |
|
71 |
+ -66, -61, -56, -51, -47, -43, -42, -41, |
|
72 |
+ -40, -39, -38, -37, -36, -35, -34, -33, |
|
73 |
+ -32, -31, -30, -29, -28, -27, -26, -25, |
|
74 |
+ -24, -23, -22, -21, -20, -19, -18, -17, |
|
75 |
+ -16, -15, -14, -13, -12, -11, -10, -9, |
|
76 |
+ -8, -7, -6, -5, -4, -3, -2, -1 |
|
77 |
+ |
|
78 |
+}; |
|
79 |
+ |
|
80 |
+static int dpcm_decode_init(AVCodecContext *avctx) |
|
81 |
+{ |
|
82 |
+ DPCMContext *s = avctx->priv_data; |
|
83 |
+ int i; |
|
84 |
+ short square; |
|
85 |
+ |
|
86 |
+ s->channels = avctx->channels; |
|
87 |
+ |
|
88 |
+ switch(avctx->codec->id) { |
|
89 |
+ |
|
90 |
+ case CODEC_ID_ROQ_DPCM: |
|
91 |
+ /* initialize square table */ |
|
92 |
+ for (i = 0; i < 128; i++) { |
|
93 |
+ square = i * i; |
|
94 |
+ s->roq_square_array[i] = square; |
|
95 |
+ s->roq_square_array[i + 128] = -square; |
|
96 |
+ } |
|
97 |
+ break; |
|
98 |
+ |
|
99 |
+ default: |
|
100 |
+ break; |
|
101 |
+ } |
|
102 |
+ |
|
103 |
+ return 0; |
|
104 |
+} |
|
105 |
+ |
|
106 |
+static int dpcm_decode_frame(AVCodecContext *avctx, |
|
107 |
+ void *data, int *data_size, |
|
108 |
+ uint8_t *buf, int buf_size) |
|
109 |
+{ |
|
110 |
+ DPCMContext *s = avctx->priv_data; |
|
111 |
+ int in, out = 0; |
|
112 |
+ int i; |
|
113 |
+ int predictor[2]; |
|
114 |
+ int channel_number = 0; |
|
115 |
+ short *output_samples = data; |
|
116 |
+ int sequence_number; |
|
117 |
+ |
|
118 |
+ switch(avctx->codec->id) { |
|
119 |
+ |
|
120 |
+ case CODEC_ID_ROQ_DPCM: |
|
121 |
+ if (s->channels == 1) |
|
122 |
+ predictor[0] = LE_16(&buf[6]); |
|
123 |
+ else { |
|
124 |
+ predictor[0] = buf[7] << 8; |
|
125 |
+ predictor[1] = buf[6] << 8; |
|
126 |
+ } |
|
127 |
+ SE_16BIT(predictor[0]); |
|
128 |
+ SE_16BIT(predictor[1]); |
|
129 |
+ |
|
130 |
+ /* decode the samples */ |
|
131 |
+ for (in = 8, out = 0; in < buf_size; in++, out++) { |
|
132 |
+ predictor[channel_number] += s->roq_square_array[buf[in]]; |
|
133 |
+ SATURATE_S16(predictor[channel_number]); |
|
134 |
+ output_samples[out] = predictor[channel_number]; |
|
135 |
+ |
|
136 |
+ /* toggle channel */ |
|
137 |
+ channel_number ^= s->channels - 1; |
|
138 |
+ } |
|
139 |
+ break; |
|
140 |
+ |
|
141 |
+ case CODEC_ID_INTERPLAY_DPCM: |
|
142 |
+ in = 0; |
|
143 |
+ sequence_number = LE_16(&buf[in]); |
|
144 |
+ in += 6; /* skip over the stream mask and stream length */ |
|
145 |
+ if (sequence_number == 1) { |
|
146 |
+ predictor[0] = LE_16(&buf[in]); |
|
147 |
+ in += 2; |
|
148 |
+ SE_16BIT(predictor[0]) |
|
149 |
+ if (s->channels == 2) { |
|
150 |
+ predictor[1] = LE_16(&buf[in]); |
|
151 |
+ SE_16BIT(predictor[1]) |
|
152 |
+ in += 2; |
|
153 |
+ } |
|
154 |
+ } else { |
|
155 |
+ for (i = 0; i < s->channels; i++) |
|
156 |
+ predictor[i] = s->last_delta[i]; |
|
157 |
+ } |
|
158 |
+ |
|
159 |
+ while (in < buf_size) { |
|
160 |
+ predictor[channel_number] += interplay_delta_table[buf[in++]]; |
|
161 |
+ SATURATE_S16(predictor[channel_number]); |
|
162 |
+ output_samples[out++] = predictor[channel_number]; |
|
163 |
+ |
|
164 |
+ /* toggle channel */ |
|
165 |
+ channel_number ^= s->channels - 1; |
|
166 |
+ } |
|
167 |
+ |
|
168 |
+ /* save predictors for next round */ |
|
169 |
+ for (i = 0; i < s->channels; i++) |
|
170 |
+ s->last_delta[i] = predictor[i]; |
|
171 |
+ |
|
172 |
+ break; |
|
173 |
+ } |
|
174 |
+ |
|
175 |
+ *data_size = out * sizeof(short); |
|
176 |
+ return buf_size; |
|
177 |
+} |
|
178 |
+ |
|
179 |
+AVCodec roq_dpcm_decoder = { |
|
180 |
+ "roq_dpcm", |
|
181 |
+ CODEC_TYPE_AUDIO, |
|
182 |
+ CODEC_ID_ROQ_DPCM, |
|
183 |
+ sizeof(DPCMContext), |
|
184 |
+ dpcm_decode_init, |
|
185 |
+ NULL, |
|
186 |
+ NULL, |
|
187 |
+ dpcm_decode_frame, |
|
188 |
+}; |
|
189 |
+ |
|
190 |
+AVCodec interplay_dpcm_decoder = { |
|
191 |
+ "interplay_dpcm", |
|
192 |
+ CODEC_TYPE_AUDIO, |
|
193 |
+ CODEC_ID_INTERPLAY_DPCM, |
|
194 |
+ sizeof(DPCMContext), |
|
195 |
+ dpcm_decode_init, |
|
196 |
+ NULL, |
|
197 |
+ NULL, |
|
198 |
+ dpcm_decode_frame, |
|
199 |
+}; |
0 | 200 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,145 @@ |
0 |
+/* |
|
1 |
+ * Interplay MVE Video Decoder |
|
2 |
+ * Copyright (C) 2003 the ffmpeg project |
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
17 |
+ * |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+/** |
|
21 |
+ * @file roqvideo.c |
|
22 |
+ * Interplay MVE Video Decoder by Mike Melanson |
|
23 |
+ * For more information about the Interplay MVE format, visit: |
|
24 |
+ * http://www.pcisys.net/~melanson/codecs/ |
|
25 |
+ */ |
|
26 |
+ |
|
27 |
+#include <stdio.h> |
|
28 |
+#include <stdlib.h> |
|
29 |
+#include <string.h> |
|
30 |
+#include <unistd.h> |
|
31 |
+ |
|
32 |
+#include "common.h" |
|
33 |
+#include "avcodec.h" |
|
34 |
+#include "dsputil.h" |
|
35 |
+ |
|
36 |
+typedef struct IpvideoContext { |
|
37 |
+ |
|
38 |
+ AVCodecContext *avctx; |
|
39 |
+ DSPContext dsp; |
|
40 |
+ AVFrame last_frame; |
|
41 |
+ AVFrame current_frame; |
|
42 |
+ int first_frame; |
|
43 |
+ int receiving_decoding_map; |
|
44 |
+ unsigned char *decoding_map; |
|
45 |
+ int decoding_map_size; |
|
46 |
+ |
|
47 |
+ unsigned char *buf; |
|
48 |
+ int size; |
|
49 |
+ |
|
50 |
+} IpvideoContext; |
|
51 |
+ |
|
52 |
+static int ipvideo_decode_init(AVCodecContext *avctx) |
|
53 |
+{ |
|
54 |
+ IpvideoContext *s = avctx->priv_data; |
|
55 |
+ |
|
56 |
+ s->avctx = avctx; |
|
57 |
+ avctx->pix_fmt = PIX_FMT_YUV444P; |
|
58 |
+ avctx->has_b_frames = 0; |
|
59 |
+ dsputil_init(&s->dsp, avctx); |
|
60 |
+ |
|
61 |
+ s->first_frame = 1; |
|
62 |
+ s->receiving_decoding_map = 1; /* decoding map will be received first */ |
|
63 |
+ |
|
64 |
+ /* decoding map contains 4 bits of information per 8x8 block */ |
|
65 |
+ s->decoding_map_size = avctx->width * avctx->height / (8 * 8 * 2); |
|
66 |
+ s->decoding_map = av_malloc(s->decoding_map_size); |
|
67 |
+ |
|
68 |
+ return 0; |
|
69 |
+} |
|
70 |
+ |
|
71 |
+static int ipvideo_decode_frame(AVCodecContext *avctx, |
|
72 |
+ void *data, int *data_size, |
|
73 |
+ uint8_t *buf, int buf_size) |
|
74 |
+{ |
|
75 |
+ IpvideoContext *s = avctx->priv_data; |
|
76 |
+ |
|
77 |
+ if (s->receiving_decoding_map) { |
|
78 |
+ /* receiving the decoding map on this iteration */ |
|
79 |
+ s->receiving_decoding_map = 0; |
|
80 |
+ |
|
81 |
+ if (buf_size != s->decoding_map_size) |
|
82 |
+ printf (" Interplay video: buf_size != decoding_map_size (%d != %d)\n", |
|
83 |
+ buf_size, s->decoding_map_size); |
|
84 |
+ else |
|
85 |
+ memcpy(s->decoding_map, buf, buf_size); |
|
86 |
+ |
|
87 |
+ *data_size = 0; |
|
88 |
+ *(AVFrame*)data = s->last_frame; |
|
89 |
+ } else { |
|
90 |
+ /* receiving the compressed video data on this iteration */ |
|
91 |
+ s->receiving_decoding_map = 1; |
|
92 |
+ s->buf = buf; |
|
93 |
+ s->size = buf_size; |
|
94 |
+ |
|
95 |
+ if (avctx->get_buffer(avctx, &s->current_frame)) { |
|
96 |
+ printf (" Interplay Video: get_buffer() failed\n"); |
|
97 |
+ return -1; |
|
98 |
+ } |
|
99 |
+ |
|
100 |
+// ipvideo_decode_frame(s); |
|
101 |
+memset(s->current_frame.data[0], 0x80, s->current_frame.linesize[0] * avctx->height); |
|
102 |
+memset(s->current_frame.data[1], 0x80, s->current_frame.linesize[1] * avctx->height / 4); |
|
103 |
+memset(s->current_frame.data[2], 0x80, s->current_frame.linesize[2] * avctx->height / 4); |
|
104 |
+ |
|
105 |
+ /* release the last frame if it is allocated */ |
|
106 |
+ if (s->first_frame) |
|
107 |
+ s->first_frame = 0; |
|
108 |
+ else |
|
109 |
+ avctx->release_buffer(avctx, &s->last_frame); |
|
110 |
+ |
|
111 |
+ /* shuffle frames */ |
|
112 |
+ s->last_frame = s->current_frame; |
|
113 |
+ |
|
114 |
+ *data_size = sizeof(AVFrame); |
|
115 |
+ *(AVFrame*)data = s->current_frame; |
|
116 |
+ } |
|
117 |
+ |
|
118 |
+ /* always report that the buffer was completely consumed */ |
|
119 |
+ return buf_size; |
|
120 |
+} |
|
121 |
+ |
|
122 |
+static int ipvideo_decode_end(AVCodecContext *avctx) |
|
123 |
+{ |
|
124 |
+ IpvideoContext *s = avctx->priv_data; |
|
125 |
+ |
|
126 |
+ /* release the last frame */ |
|
127 |
+ avctx->release_buffer(avctx, &s->last_frame); |
|
128 |
+ |
|
129 |
+ av_free(s->decoding_map); |
|
130 |
+ |
|
131 |
+ return 0; |
|
132 |
+} |
|
133 |
+ |
|
134 |
+AVCodec interplay_video_decoder = { |
|
135 |
+ "interplayvideo", |
|
136 |
+ CODEC_TYPE_VIDEO, |
|
137 |
+ CODEC_ID_INTERPLAY_VIDEO, |
|
138 |
+ sizeof(IpvideoContext), |
|
139 |
+ ipvideo_decode_init, |
|
140 |
+ NULL, |
|
141 |
+ ipvideo_decode_end, |
|
142 |
+ ipvideo_decode_frame, |
|
143 |
+ CODEC_CAP_DR1, |
|
144 |
+}; |
0 | 145 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,406 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2003 the ffmpeg project |
|
2 |
+ * |
|
3 |
+ * This library is free software; you can redistribute it and/or |
|
4 |
+ * modify it under the terms of the GNU Lesser General Public |
|
5 |
+ * License as published by the Free Software Foundation; either |
|
6 |
+ * version 2 of the License, or (at your option) any later version. |
|
7 |
+ * |
|
8 |
+ * This library is distributed in the hope that it will be useful, |
|
9 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
11 |
+ * Lesser General Public License for more details. |
|
12 |
+ * |
|
13 |
+ * You should have received a copy of the GNU Lesser General Public |
|
14 |
+ * License along with this library; if not, write to the Free Software |
|
15 |
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
16 |
+ * |
|
17 |
+ */ |
|
18 |
+ |
|
19 |
+/** |
|
20 |
+ * @file roqvideo.c |
|
21 |
+ * Id RoQ Video Decoder by Dr. Tim Ferguson |
|
22 |
+ * For more information about the Id RoQ format, visit: |
|
23 |
+ * http://www.csse.monash.edu.au/~timf/ |
|
24 |
+ */ |
|
25 |
+ |
|
26 |
+#include <stdio.h> |
|
27 |
+#include <stdlib.h> |
|
28 |
+#include <string.h> |
|
29 |
+#include <unistd.h> |
|
30 |
+ |
|
31 |
+#include "common.h" |
|
32 |
+#include "avcodec.h" |
|
33 |
+#include "dsputil.h" |
|
34 |
+ |
|
35 |
+typedef struct { |
|
36 |
+ unsigned char y0, y1, y2, y3, u, v; |
|
37 |
+} roq_cell; |
|
38 |
+ |
|
39 |
+typedef struct { |
|
40 |
+ int idx[4]; |
|
41 |
+} roq_qcell; |
|
42 |
+ |
|
43 |
+ |
|
44 |
+typedef struct RoqContext { |
|
45 |
+ |
|
46 |
+ AVCodecContext *avctx; |
|
47 |
+ DSPContext dsp; |
|
48 |
+ AVFrame last_frame; |
|
49 |
+ AVFrame current_frame; |
|
50 |
+ int first_frame; |
|
51 |
+ int y_stride; |
|
52 |
+ int c_stride; |
|
53 |
+ |
|
54 |
+ roq_cell cells[256]; |
|
55 |
+ roq_qcell qcells[256]; |
|
56 |
+ |
|
57 |
+ unsigned char *buf; |
|
58 |
+ int size; |
|
59 |
+ |
|
60 |
+} RoqContext; |
|
61 |
+ |
|
62 |
+#define RoQ_INFO 0x1001 |
|
63 |
+#define RoQ_QUAD_CODEBOOK 0x1002 |
|
64 |
+#define RoQ_QUAD_VQ 0x1011 |
|
65 |
+#define RoQ_SOUND_MONO 0x1020 |
|
66 |
+#define RoQ_SOUND_STEREO 0x1021 |
|
67 |
+ |
|
68 |
+#define RoQ_ID_MOT 0x00 |
|
69 |
+#define RoQ_ID_FCC 0x01 |
|
70 |
+#define RoQ_ID_SLD 0x02 |
|
71 |
+#define RoQ_ID_CCC 0x03 |
|
72 |
+ |
|
73 |
+#define get_byte(in_buffer) *(in_buffer++) |
|
74 |
+#define get_word(in_buffer) ((unsigned short)(in_buffer += 2, \ |
|
75 |
+ (in_buffer[-1] << 8 | in_buffer[-2]))) |
|
76 |
+#define get_long(in_buffer) ((unsigned long)(in_buffer += 4, \ |
|
77 |
+ (in_buffer[-1] << 24 | in_buffer[-2] << 16 | in_buffer[-3] << 8 | in_buffer[-4]))) |
|
78 |
+ |
|
79 |
+ |
|
80 |
+static void apply_vector_2x2(RoqContext *ri, int x, int y, roq_cell *cell) |
|
81 |
+{ |
|
82 |
+ unsigned char *yptr; |
|
83 |
+ |
|
84 |
+ yptr = ri->current_frame.data[0] + (y * ri->y_stride) + x; |
|
85 |
+ *yptr++ = cell->y0; |
|
86 |
+ *yptr++ = cell->y1; |
|
87 |
+ yptr += (ri->y_stride - 2); |
|
88 |
+ *yptr++ = cell->y2; |
|
89 |
+ *yptr++ = cell->y3; |
|
90 |
+ ri->current_frame.data[1][(y/2) * (ri->c_stride) + x/2] = cell->u; |
|
91 |
+ ri->current_frame.data[2][(y/2) * (ri->c_stride) + x/2] = cell->v; |
|
92 |
+} |
|
93 |
+ |
|
94 |
+static void apply_vector_4x4(RoqContext *ri, int x, int y, roq_cell *cell) |
|
95 |
+{ |
|
96 |
+ unsigned long row_inc, c_row_inc; |
|
97 |
+ register unsigned char y0, y1, u, v; |
|
98 |
+ unsigned char *yptr, *uptr, *vptr; |
|
99 |
+ |
|
100 |
+ yptr = ri->current_frame.data[0] + (y * ri->y_stride) + x; |
|
101 |
+ uptr = ri->current_frame.data[1] + (y/2) * (ri->c_stride) + x/2; |
|
102 |
+ vptr = ri->current_frame.data[2] + (y/2) * (ri->c_stride) + x/2; |
|
103 |
+ |
|
104 |
+ row_inc = ri->y_stride - 4; |
|
105 |
+ c_row_inc = (ri->c_stride) - 2; |
|
106 |
+ *yptr++ = y0 = cell->y0; *uptr++ = u = cell->u; *vptr++ = v = cell->v; |
|
107 |
+ *yptr++ = y0; |
|
108 |
+ *yptr++ = y1 = cell->y1; *uptr++ = u; *vptr++ = v; |
|
109 |
+ *yptr++ = y1; |
|
110 |
+ |
|
111 |
+ yptr += row_inc; |
|
112 |
+ |
|
113 |
+ *yptr++ = y0; |
|
114 |
+ *yptr++ = y0; |
|
115 |
+ *yptr++ = y1; |
|
116 |
+ *yptr++ = y1; |
|
117 |
+ |
|
118 |
+ yptr += row_inc; uptr += c_row_inc; vptr += c_row_inc; |
|
119 |
+ |
|
120 |
+ *yptr++ = y0 = cell->y2; *uptr++ = u; *vptr++ = v; |
|
121 |
+ *yptr++ = y0; |
|
122 |
+ *yptr++ = y1 = cell->y3; *uptr++ = u; *vptr++ = v; |
|
123 |
+ *yptr++ = y1; |
|
124 |
+ |
|
125 |
+ yptr += row_inc; |
|
126 |
+ |
|
127 |
+ *yptr++ = y0; |
|
128 |
+ *yptr++ = y0; |
|
129 |
+ *yptr++ = y1; |
|
130 |
+ *yptr++ = y1; |
|
131 |
+} |
|
132 |
+ |
|
133 |
+static void apply_motion_4x4(RoqContext *ri, int x, int y, unsigned char mv, |
|
134 |
+ char mean_x, char mean_y) |
|
135 |
+{ |
|
136 |
+ int i, mx, my; |
|
137 |
+ unsigned char *pa, *pb; |
|
138 |
+ |
|
139 |
+ mx = x + 8 - (mv >> 4) - mean_x; |
|
140 |
+ my = y + 8 - (mv & 0xf) - mean_y; |
|
141 |
+ |
|
142 |
+ pa = ri->current_frame.data[0] + (y * ri->y_stride) + x; |
|
143 |
+ pb = ri->last_frame.data[0] + (my * ri->y_stride) + mx; |
|
144 |
+ for(i = 0; i < 4; i++) { |
|
145 |
+ pa[0] = pb[0]; |
|
146 |
+ pa[1] = pb[1]; |
|
147 |
+ pa[2] = pb[2]; |
|
148 |
+ pa[3] = pb[3]; |
|
149 |
+ pa += ri->y_stride; |
|
150 |
+ pb += ri->y_stride; |
|
151 |
+ } |
|
152 |
+ |
|
153 |
+ pa = ri->current_frame.data[1] + (y/2) * (ri->c_stride) + x/2; |
|
154 |
+ pb = ri->last_frame.data[1] + (my/2) * (ri->c_stride) + (mx + 1)/2; |
|
155 |
+ for(i = 0; i < 2; i++) { |
|
156 |
+ pa[0] = pb[0]; |
|
157 |
+ pa[1] = pb[1]; |
|
158 |
+ pa += ri->c_stride; |
|
159 |
+ pb += ri->c_stride; |
|
160 |
+ } |
|
161 |
+ |
|
162 |
+ pa = ri->current_frame.data[2] + (y/2) * (ri->c_stride) + x/2; |
|
163 |
+ pb = ri->last_frame.data[2] + (my/2) * (ri->c_stride) + (mx + 1)/2; |
|
164 |
+ for(i = 0; i < 2; i++) { |
|
165 |
+ pa[0] = pb[0]; |
|
166 |
+ pa[1] = pb[1]; |
|
167 |
+ pa += ri->c_stride; |
|
168 |
+ pb += ri->c_stride; |
|
169 |
+ } |
|
170 |
+} |
|
171 |
+ |
|
172 |
+static void apply_motion_8x8(RoqContext *ri, int x, int y, |
|
173 |
+ unsigned char mv, char mean_x, char mean_y) |
|
174 |
+{ |
|
175 |
+ int mx, my, i; |
|
176 |
+ unsigned char *pa, *pb; |
|
177 |
+ |
|
178 |
+ mx = x + 8 - (mv >> 4) - mean_x; |
|
179 |
+ my = y + 8 - (mv & 0xf) - mean_y; |
|
180 |
+ |
|
181 |
+ pa = ri->current_frame.data[0] + (y * ri->y_stride) + x; |
|
182 |
+ pb = ri->last_frame.data[0] + (my * ri->y_stride) + mx; |
|
183 |
+ for(i = 0; i < 8; i++) { |
|
184 |
+ pa[0] = pb[0]; |
|
185 |
+ pa[1] = pb[1]; |
|
186 |
+ pa[2] = pb[2]; |
|
187 |
+ pa[3] = pb[3]; |
|
188 |
+ pa[4] = pb[4]; |
|
189 |
+ pa[5] = pb[5]; |
|
190 |
+ pa[6] = pb[6]; |
|
191 |
+ pa[7] = pb[7]; |
|
192 |
+ pa += ri->y_stride; |
|
193 |
+ pb += ri->y_stride; |
|
194 |
+ } |
|
195 |
+ |
|
196 |
+ pa = ri->current_frame.data[1] + (y/2) * (ri->c_stride) + x/2; |
|
197 |
+ pb = ri->last_frame.data[1] + (my/2) * (ri->c_stride) + (mx + 1)/2; |
|
198 |
+ for(i = 0; i < 4; i++) { |
|
199 |
+ pa[0] = pb[0]; |
|
200 |
+ pa[1] = pb[1]; |
|
201 |
+ pa[2] = pb[2]; |
|
202 |
+ pa[3] = pb[3]; |
|
203 |
+ pa += ri->c_stride; |
|
204 |
+ pb += ri->c_stride; |
|
205 |
+ } |
|
206 |
+ |
|
207 |
+ pa = ri->current_frame.data[2] + (y/2) * (ri->c_stride) + x/2; |
|
208 |
+ pb = ri->last_frame.data[2] + (my/2) * (ri->c_stride) + (mx + 1)/2; |
|
209 |
+ for(i = 0; i < 4; i++) { |
|
210 |
+ pa[0] = pb[0]; |
|
211 |
+ pa[1] = pb[1]; |
|
212 |
+ pa[2] = pb[2]; |
|
213 |
+ pa[3] = pb[3]; |
|
214 |
+ pa += ri->c_stride; |
|
215 |
+ pb += ri->c_stride; |
|
216 |
+ } |
|
217 |
+} |
|
218 |
+ |
|
219 |
+static void roqvideo_decode_frame(RoqContext *ri) |
|
220 |
+{ |
|
221 |
+ unsigned int chunk_id = 0, chunk_arg = 0; |
|
222 |
+ unsigned long chunk_size = 0; |
|
223 |
+ int i, j, k, nv1, nv2, vqflg = 0, vqflg_pos = -1; |
|
224 |
+ int vqid, bpos, xpos, ypos, xp, yp, x, y; |
|
225 |
+ int frame_stats[2][4] = {{0},{0}}; |
|
226 |
+ roq_qcell *qcell; |
|
227 |
+ unsigned char *buf = ri->buf; |
|
228 |
+ unsigned char *buf_end = ri->buf + ri->size; |
|
229 |
+ |
|
230 |
+ while (buf < buf_end) { |
|
231 |
+ chunk_id = get_word(buf); |
|
232 |
+ chunk_size = get_long(buf); |
|
233 |
+ chunk_arg = get_word(buf); |
|
234 |
+ |
|
235 |
+ if(chunk_id == RoQ_QUAD_VQ) |
|
236 |
+ break; |
|
237 |
+ if(chunk_id == RoQ_QUAD_CODEBOOK) { |
|
238 |
+ if((nv1 = chunk_arg >> 8) == 0) |
|
239 |
+ nv1 = 256; |
|
240 |
+ if((nv2 = chunk_arg & 0xff) == 0 && nv1 * 6 < chunk_size) |
|
241 |
+ nv2 = 256; |
|
242 |
+ for(i = 0; i < nv1; i++) { |
|
243 |
+ ri->cells[i].y0 = get_byte(buf); |
|
244 |
+ ri->cells[i].y1 = get_byte(buf); |
|
245 |
+ ri->cells[i].y2 = get_byte(buf); |
|
246 |
+ ri->cells[i].y3 = get_byte(buf); |
|
247 |
+ ri->cells[i].u = get_byte(buf); |
|
248 |
+ ri->cells[i].v = get_byte(buf); |
|
249 |
+ } |
|
250 |
+ for(i = 0; i < nv2; i++) |
|
251 |
+ for(j = 0; j < 4; j++) |
|
252 |
+ ri->qcells[i].idx[j] = get_byte(buf); |
|
253 |
+ } |
|
254 |
+ } |
|
255 |
+ |
|
256 |
+ bpos = xpos = ypos = 0; |
|
257 |
+ while(bpos < chunk_size) { |
|
258 |
+ for (yp = ypos; yp < ypos + 16; yp += 8) |
|
259 |
+ for (xp = xpos; xp < xpos + 16; xp += 8) { |
|
260 |
+ if (vqflg_pos < 0) { |
|
261 |
+ vqflg = buf[bpos++]; vqflg |= (buf[bpos++] << 8); |
|
262 |
+ vqflg_pos = 7; |
|
263 |
+ } |
|
264 |
+ vqid = (vqflg >> (vqflg_pos * 2)) & 0x3; |
|
265 |
+ frame_stats[0][vqid]++; |
|
266 |
+ vqflg_pos--; |
|
267 |
+ |
|
268 |
+ switch(vqid) { |
|
269 |
+ case RoQ_ID_MOT: |
|
270 |
+ apply_motion_8x8(ri, xp, yp, 0, 8, 8); |
|
271 |
+ break; |
|
272 |
+ case RoQ_ID_FCC: |
|
273 |
+ apply_motion_8x8(ri, xp, yp, buf[bpos++], chunk_arg >> 8, |
|
274 |
+ chunk_arg & 0xff); |
|
275 |
+ break; |
|
276 |
+ case RoQ_ID_SLD: |
|
277 |
+ qcell = ri->qcells + buf[bpos++]; |
|
278 |
+ apply_vector_4x4(ri, xp, yp, ri->cells + qcell->idx[0]); |
|
279 |
+ apply_vector_4x4(ri, xp+4, yp, ri->cells + qcell->idx[1]); |
|
280 |
+ apply_vector_4x4(ri, xp, yp+4, ri->cells + qcell->idx[2]); |
|
281 |
+ apply_vector_4x4(ri, xp+4, yp+4, ri->cells + qcell->idx[3]); |
|
282 |
+ break; |
|
283 |
+ case RoQ_ID_CCC: |
|
284 |
+ for (k = 0; k < 4; k++) { |
|
285 |
+ x = xp; y = yp; |
|
286 |
+ if(k & 0x01) x += 4; |
|
287 |
+ if(k & 0x02) y += 4; |
|
288 |
+ |
|
289 |
+ if (vqflg_pos < 0) { |
|
290 |
+ vqflg = buf[bpos++]; |
|
291 |
+ vqflg |= (buf[bpos++] << 8); |
|
292 |
+ vqflg_pos = 7; |
|
293 |
+ } |
|
294 |
+ vqid = (vqflg >> (vqflg_pos * 2)) & 0x3; |
|
295 |
+ frame_stats[1][vqid]++; |
|
296 |
+ vqflg_pos--; |
|
297 |
+ switch(vqid) { |
|
298 |
+ case RoQ_ID_MOT: |
|
299 |
+ apply_motion_4x4(ri, x, y, 0, 8, 8); |
|
300 |
+ break; |
|
301 |
+ case RoQ_ID_FCC: |
|
302 |
+ apply_motion_4x4(ri, x, y, buf[bpos++], |
|
303 |
+ chunk_arg >> 8, chunk_arg & 0xff); |
|
304 |
+ break; |
|
305 |
+ case RoQ_ID_SLD: |
|
306 |
+ qcell = ri->qcells + buf[bpos++]; |
|
307 |
+ apply_vector_2x2(ri, x, y, ri->cells + qcell->idx[0]); |
|
308 |
+ apply_vector_2x2(ri, x+2, y, ri->cells + qcell->idx[1]); |
|
309 |
+ apply_vector_2x2(ri, x, y+2, ri->cells + qcell->idx[2]); |
|
310 |
+ apply_vector_2x2(ri, x+2, y+2, ri->cells + qcell->idx[3]); |
|
311 |
+ break; |
|
312 |
+ case RoQ_ID_CCC: |
|
313 |
+ apply_vector_2x2(ri, x, y, ri->cells + buf[bpos]); |
|
314 |
+ apply_vector_2x2(ri, x+2, y, ri->cells + buf[bpos+1]); |
|
315 |
+ apply_vector_2x2(ri, x, y+2, ri->cells + buf[bpos+2]); |
|
316 |
+ apply_vector_2x2(ri, x+2, y+2, ri->cells + buf[bpos+3]); |
|
317 |
+ bpos += 4; |
|
318 |
+ break; |
|
319 |
+ } |
|
320 |
+ } |
|
321 |
+ break; |
|
322 |
+ default: |
|
323 |
+ printf("Unknown vq code: %d\n", vqid); |
|
324 |
+ } |
|
325 |
+ } |
|
326 |
+ |
|
327 |
+ xpos += 16; |
|
328 |
+ if (xpos >= ri->avctx->width) { |
|
329 |
+ xpos -= ri->avctx->width; |
|
330 |
+ ypos += 16; |
|
331 |
+ } |
|
332 |
+ if(ypos >= ri->avctx->height) |
|
333 |
+ break; |
|
334 |
+ } |
|
335 |
+} |
|
336 |
+ |
|
337 |
+ |
|
338 |
+static int roq_decode_init(AVCodecContext *avctx) |
|
339 |
+{ |
|
340 |
+ RoqContext *s = avctx->priv_data; |
|
341 |
+ |
|
342 |
+ s->avctx = avctx; |
|
343 |
+ s->first_frame = 1; |
|
344 |
+ avctx->pix_fmt = PIX_FMT_YUV420P; |
|
345 |
+ avctx->has_b_frames = 0; |
|
346 |
+ dsputil_init(&s->dsp, avctx); |
|
347 |
+ |
|
348 |
+ return 0; |
|
349 |
+} |
|
350 |
+ |
|
351 |
+static int roq_decode_frame(AVCodecContext *avctx, |
|
352 |
+ void *data, int *data_size, |
|
353 |
+ uint8_t *buf, int buf_size) |
|
354 |
+{ |
|
355 |
+ RoqContext *s = avctx->priv_data; |
|
356 |
+ |
|
357 |
+ *data_size = 0; |
|
358 |
+ |
|
359 |
+ if (avctx->get_buffer(avctx, &s->current_frame)) { |
|
360 |
+ printf (" RoQ: get_buffer() failed\n"); |
|
361 |
+ return -1; |
|
362 |
+ } |
|
363 |
+ s->y_stride = s->current_frame.linesize[0]; |
|
364 |
+ s->c_stride = s->current_frame.linesize[1]; |
|
365 |
+ |
|
366 |
+ s->buf = buf; |
|
367 |
+ s->size = buf_size; |
|
368 |
+ roqvideo_decode_frame(s); |
|
369 |
+ |
|
370 |
+ /* release the last frame if it is allocated */ |
|
371 |
+ if (s->first_frame) |
|
372 |
+ s->first_frame = 0; |
|
373 |
+ else |
|
374 |
+ avctx->release_buffer(avctx, &s->last_frame); |
|
375 |
+ |
|
376 |
+ /* shuffle frames */ |
|
377 |
+ s->last_frame = s->current_frame; |
|
378 |
+ |
|
379 |
+ *data_size = sizeof(AVFrame); |
|
380 |
+ *(AVFrame*)data = s->current_frame; |
|
381 |
+ |
|
382 |
+ return buf_size; |
|
383 |
+} |
|
384 |
+ |
|
385 |
+static int roq_decode_end(AVCodecContext *avctx) |
|
386 |
+{ |
|
387 |
+ RoqContext *s = avctx->priv_data; |
|
388 |
+ |
|
389 |
+ /* release the last frame */ |
|
390 |
+ avctx->release_buffer(avctx, &s->last_frame); |
|
391 |
+ |
|
392 |
+ return 0; |
|
393 |
+} |
|
394 |
+ |
|
395 |
+AVCodec roq_decoder = { |
|
396 |
+ "roqvideo", |
|
397 |
+ CODEC_TYPE_VIDEO, |
|
398 |
+ CODEC_ID_ROQ, |
|
399 |
+ sizeof(RoqContext), |
|
400 |
+ roq_decode_init, |
|
401 |
+ NULL, |
|
402 |
+ roq_decode_end, |
|
403 |
+ roq_decode_frame, |
|
404 |
+ CODEC_CAP_DR1, |
|
405 |
+}; |
... | ... |
@@ -14,7 +14,7 @@ PPOBJS= |
14 | 14 |
# mux and demuxes |
15 | 15 |
OBJS+=mpeg.o mpegts.o mpegtsenc.o ffm.o crc.o img.o raw.o rm.o \ |
16 | 16 |
avienc.o avidec.o wav.o swf.o au.o gif.o mov.o mpjpeg.o dvcore.o dv.o \ |
17 |
- yuv4mpeg.o 4xm.o flvenc.o flvdec.o movenc.o psxstr.o |
|
17 |
+ yuv4mpeg.o 4xm.o flvenc.o flvdec.o movenc.o psxstr.o idroq.o ipmovie.o |
|
18 | 18 |
|
19 | 19 |
ifeq ($(CONFIG_RISKY),yes) |
20 | 20 |
OBJS+= asf.o |
389 | 395 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,299 @@ |
0 |
+/* |
|
1 |
+ * Id RoQ (.roq) File Demuxer |
|
2 |
+ * Copyright (c) 2003 The ffmpeg Project |
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
17 |
+ */ |
|
18 |
+ |
|
19 |
+/** |
|
20 |
+ * @file idroq.c |
|
21 |
+ * Id RoQ format file demuxer |
|
22 |
+ * by Mike Melanson (melanson@pcisys.net) |
|
23 |
+ * for more information on the .roq file format, visit: |
|
24 |
+ * http://www.csse.monash.edu.au/~timf/ |
|
25 |
+ */ |
|
26 |
+ |
|
27 |
+#include "avformat.h" |
|
28 |
+ |
|
29 |
+#define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0]) |
|
30 |
+#define LE_32(x) ((((uint8_t*)(x))[3] << 24) | \ |
|
31 |
+ (((uint8_t*)(x))[2] << 16) | \ |
|
32 |
+ (((uint8_t*)(x))[1] << 8) | \ |
|
33 |
+ ((uint8_t*)(x))[0]) |
|
34 |
+ |
|
35 |
+#define RoQ_MAGIC_NUMBER 0x1084 |
|
36 |
+#define RoQ_CHUNK_PREAMBLE_SIZE 8 |
|
37 |
+#define RoQ_AUDIO_SAMPLE_RATE 22050 |
|
38 |
+#define RoQ_CHUNKS_TO_SCAN 30 |
|
39 |
+ |
|
40 |
+#define RoQ_INFO 0x1001 |
|
41 |
+#define RoQ_QUAD_CODEBOOK 0x1002 |
|
42 |
+#define RoQ_QUAD_VQ 0x1011 |
|
43 |
+#define RoQ_SOUND_MONO 0x1020 |
|
44 |
+#define RoQ_SOUND_STEREO 0x1021 |
|
45 |
+ |
|
46 |
+typedef struct RoqDemuxContext { |
|
47 |
+ |
|
48 |
+ int width; |
|
49 |
+ int height; |
|
50 |
+ int audio_channels; |
|
51 |
+ int framerate; |
|
52 |
+ int frame_pts_inc; |
|
53 |
+ |
|
54 |
+ int video_stream_index; |
|
55 |
+ int audio_stream_index; |
|
56 |
+ |
|
57 |
+ int64_t video_pts; |
|
58 |
+ unsigned int audio_frame_count; |
|
59 |
+ |
|
60 |
+} RoqDemuxContext; |
|
61 |
+ |
|
62 |
+static int roq_probe(AVProbeData *p) |
|
63 |
+{ |
|
64 |
+ if ((LE_16(&p->buf[0]) != RoQ_MAGIC_NUMBER) || |
|
65 |
+ (LE_32(&p->buf[2]) != 0xFFFFFFFF)) |
|
66 |
+ return 0; |
|
67 |
+ |
|
68 |
+ return AVPROBE_SCORE_MAX; |
|
69 |
+} |
|
70 |
+ |
|
71 |
+static int roq_read_header(AVFormatContext *s, |
|
72 |
+ AVFormatParameters *ap) |
|
73 |
+{ |
|
74 |
+ RoqDemuxContext *roq = s->priv_data; |
|
75 |
+ ByteIOContext *pb = &s->pb; |
|
76 |
+ AVStream *st; |
|
77 |
+ unsigned char preamble[RoQ_CHUNK_PREAMBLE_SIZE]; |
|
78 |
+ int i; |
|
79 |
+ unsigned int chunk_size; |
|
80 |
+ unsigned int chunk_type; |
|
81 |
+ |
|
82 |
+ /* get the main header */ |
|
83 |
+ if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != |
|
84 |
+ RoQ_CHUNK_PREAMBLE_SIZE) |
|
85 |
+ return AVERROR_IO; |
|
86 |
+ roq->framerate = LE_16(&preamble[6]); |
|
87 |
+ roq->frame_pts_inc = 90000 / roq->framerate; |
|
88 |
+ |
|
89 |
+ /* set the pts reference (1 pts = 1/90000) */ |
|
90 |
+ s->pts_num = 1; |
|
91 |
+ s->pts_den = 90000; |
|
92 |
+ |
|
93 |
+ /* init private context parameters */ |
|
94 |
+ roq->width = roq->height = roq->audio_channels = roq->video_pts = |
|
95 |
+ roq->audio_frame_count = 0; |
|
96 |
+ |
|
97 |
+ /* scan the first n chunks searching for A/V parameters */ |
|
98 |
+ for (i = 0; i < RoQ_CHUNKS_TO_SCAN; i++) { |
|
99 |
+ if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != |
|
100 |
+ RoQ_CHUNK_PREAMBLE_SIZE) |
|
101 |
+ return AVERROR_IO; |
|
102 |
+ |
|
103 |
+ chunk_type = LE_16(&preamble[0]); |
|
104 |
+ chunk_size = LE_32(&preamble[2]); |
|
105 |
+ |
|
106 |
+ switch (chunk_type) { |
|
107 |
+ |
|
108 |
+ case RoQ_INFO: |
|
109 |
+ /* fetch the width and height; reuse the preamble bytes */ |
|
110 |
+ if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != |
|
111 |
+ RoQ_CHUNK_PREAMBLE_SIZE) |
|
112 |
+ return AVERROR_IO; |
|
113 |
+ roq->width = LE_16(&preamble[0]); |
|
114 |
+ roq->height = LE_16(&preamble[2]); |
|
115 |
+ break; |
|
116 |
+ |
|
117 |
+ case RoQ_QUAD_CODEBOOK: |
|
118 |
+ case RoQ_QUAD_VQ: |
|
119 |
+ /* ignore during this scan */ |
|
120 |
+ url_fseek(pb, chunk_size, SEEK_CUR); |
|
121 |
+ break; |
|
122 |
+ |
|
123 |
+ case RoQ_SOUND_MONO: |
|
124 |
+ roq->audio_channels = 1; |
|
125 |
+ url_fseek(pb, chunk_size, SEEK_CUR); |
|
126 |
+ break; |
|
127 |
+ |
|
128 |
+ case RoQ_SOUND_STEREO: |
|
129 |
+ roq->audio_channels = 2; |
|
130 |
+ url_fseek(pb, chunk_size, SEEK_CUR); |
|
131 |
+ break; |
|
132 |
+ |
|
133 |
+ default: |
|
134 |
+ printf (" unknown RoQ chunk type (%04X)\n", LE_16(&preamble[0])); |
|
135 |
+ return AVERROR_INVALIDDATA; |
|
136 |
+ break; |
|
137 |
+ } |
|
138 |
+ |
|
139 |
+ /* if all necessary parameters have been gathered, exit early */ |
|
140 |
+ if ((roq->width && roq->height) && roq->audio_channels) |
|
141 |
+ break; |
|
142 |
+ } |
|
143 |
+ |
|
144 |
+ /* seek back to the first chunk */ |
|
145 |
+ url_fseek(pb, RoQ_CHUNK_PREAMBLE_SIZE, SEEK_SET); |
|
146 |
+ |
|
147 |
+ /* initialize the decoders */ |
|
148 |
+ st = av_new_stream(s, 0); |
|
149 |
+ if (!st) |
|
150 |
+ return AVERROR_NOMEM; |
|
151 |
+ roq->video_stream_index = st->index; |
|
152 |
+ st->codec.codec_type = CODEC_TYPE_VIDEO; |
|
153 |
+ st->codec.codec_id = CODEC_ID_ROQ; |
|
154 |
+ st->codec.codec_tag = 0; /* no fourcc */ |
|
155 |
+ st->codec.width = roq->width; |
|
156 |
+ st->codec.height = roq->height; |
|
157 |
+ |
|
158 |
+ if (roq->audio_channels) { |
|
159 |
+ st = av_new_stream(s, 0); |
|
160 |
+ if (!st) |
|
161 |
+ return AVERROR_NOMEM; |
|
162 |
+ roq->audio_stream_index = st->index; |
|
163 |
+ st->codec.codec_type = CODEC_TYPE_AUDIO; |
|
164 |
+ st->codec.codec_id = CODEC_ID_ROQ_DPCM; |
|
165 |
+ st->codec.codec_tag = 0; /* no tag */ |
|
166 |
+ st->codec.channels = roq->audio_channels; |
|
167 |
+ st->codec.sample_rate = RoQ_AUDIO_SAMPLE_RATE; |
|
168 |
+ st->codec.bits_per_sample = 16; |
|
169 |
+ st->codec.bit_rate = st->codec.channels * st->codec.sample_rate * |
|
170 |
+ st->codec.bits_per_sample; |
|
171 |
+ st->codec.block_align = st->codec.channels * st->codec.bits_per_sample; |
|
172 |
+ } |
|
173 |
+printf (" video is %d x %d, audio is %d channels\n", |
|
174 |
+ roq->width, roq->height, roq->audio_channels); |
|
175 |
+ |
|
176 |
+ return 0; |
|
177 |
+} |
|
178 |
+ |
|
179 |
+static int roq_read_packet(AVFormatContext *s, |
|
180 |
+ AVPacket *pkt) |
|
181 |
+{ |
|
182 |
+ RoqDemuxContext *roq = s->priv_data; |
|
183 |
+ ByteIOContext *pb = &s->pb; |
|
184 |
+ int ret = 0; |
|
185 |
+ unsigned int chunk_size; |
|
186 |
+ unsigned int chunk_type; |
|
187 |
+ unsigned int codebook_size; |
|
188 |
+ unsigned char preamble[RoQ_CHUNK_PREAMBLE_SIZE]; |
|
189 |
+ int packet_read = 0; |
|
190 |
+ offset_t codebook_offset; |
|
191 |
+ |
|
192 |
+ while (!packet_read) { |
|
193 |
+ |
|
194 |
+ if (url_feof(&s->pb)) |
|
195 |
+ return -EIO; |
|
196 |
+ |
|
197 |
+ /* get the next chunk preamble */ |
|
198 |
+ if ((ret = get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE)) != |
|
199 |
+ RoQ_CHUNK_PREAMBLE_SIZE) |
|
200 |
+ return -EIO; |
|
201 |
+ |
|
202 |
+ chunk_type = LE_16(&preamble[0]); |
|
203 |
+ chunk_size = LE_32(&preamble[2]); |
|
204 |
+ |
|
205 |
+ switch (chunk_type) { |
|
206 |
+ |
|
207 |
+ case RoQ_INFO: |
|
208 |
+ /* don't care about this chunk anymore */ |
|
209 |
+ url_fseek(pb, RoQ_CHUNK_PREAMBLE_SIZE, SEEK_CUR); |
|
210 |
+ break; |
|
211 |
+ |
|
212 |
+ case RoQ_QUAD_CODEBOOK: |
|
213 |
+ /* packet needs to contain both this codebook and next VQ chunk */ |
|
214 |
+ codebook_offset = url_ftell(pb) - RoQ_CHUNK_PREAMBLE_SIZE; |
|
215 |
+ codebook_size = chunk_size; |
|
216 |
+ url_fseek(pb, codebook_size, SEEK_CUR); |
|
217 |
+ if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != |
|
218 |
+ RoQ_CHUNK_PREAMBLE_SIZE) |
|
219 |
+ return -EIO; |
|
220 |
+ chunk_size = LE_32(&preamble[2]) + RoQ_CHUNK_PREAMBLE_SIZE * 2 + |
|
221 |
+ codebook_size; |
|
222 |
+ |
|
223 |
+ /* rewind */ |
|
224 |
+ url_fseek(pb, codebook_offset, SEEK_SET); |
|
225 |
+ |
|
226 |
+ /* load up the packet */ |
|
227 |
+ if (av_new_packet(pkt, chunk_size)) |
|
228 |
+ return -EIO; |
|
229 |
+ pkt->stream_index = roq->video_stream_index; |
|
230 |
+ pkt->pts = roq->video_pts; |
|
231 |
+ ret = get_buffer(pb, pkt->data, chunk_size); |
|
232 |
+ if (ret != chunk_size) |
|
233 |
+ ret = -EIO; |
|
234 |
+ |
|
235 |
+ roq->video_pts += roq->frame_pts_inc; |
|
236 |
+ packet_read = 1; |
|
237 |
+ break; |
|
238 |
+ |
|
239 |
+ case RoQ_SOUND_MONO: |
|
240 |
+ case RoQ_SOUND_STEREO: |
|
241 |
+ case RoQ_QUAD_VQ: |
|
242 |
+ /* load up the packet */ |
|
243 |
+ if (av_new_packet(pkt, chunk_size + RoQ_CHUNK_PREAMBLE_SIZE)) |
|
244 |
+ return -EIO; |
|
245 |
+ /* copy over preamble */ |
|
246 |
+ memcpy(pkt->data, preamble, RoQ_CHUNK_PREAMBLE_SIZE); |
|
247 |
+ |
|
248 |
+ if (chunk_type == RoQ_QUAD_VQ) { |
|
249 |
+ pkt->stream_index = roq->video_stream_index; |
|
250 |
+ pkt->pts = roq->video_pts; |
|
251 |
+ roq->video_pts += roq->frame_pts_inc; |
|
252 |
+ } else { |
|
253 |
+ pkt->stream_index = roq->audio_stream_index; |
|
254 |
+ pkt->pts = roq->audio_frame_count; |
|
255 |
+ pkt->pts *= 90000; |
|
256 |
+ pkt->pts /= RoQ_AUDIO_SAMPLE_RATE; |
|
257 |
+ roq->audio_frame_count += (chunk_size / roq->audio_channels); |
|
258 |
+ } |
|
259 |
+ |
|
260 |
+ ret = get_buffer(pb, pkt->data, chunk_size); |
|
261 |
+ if (ret != chunk_size) |
|
262 |
+ ret = -EIO; |
|
263 |
+ |
|
264 |
+ packet_read = 1; |
|
265 |
+ break; |
|
266 |
+ |
|
267 |
+ default: |
|
268 |
+ printf (" unknown RoQ chunk (%04X)\n", chunk_type); |
|
269 |
+ return AVERROR_INVALIDDATA; |
|
270 |
+ break; |
|
271 |
+ } |
|
272 |
+ } |
|
273 |
+ |
|
274 |
+ return ret; |
|
275 |
+} |
|
276 |
+ |
|
277 |
+static int roq_read_close(AVFormatContext *s) |
|
278 |
+{ |
|
279 |
+// RoqDemuxContext *roq = (RoqDemuxContext *)s->priv_data; |
|
280 |
+ |
|
281 |
+ return 0; |
|
282 |
+} |
|
283 |
+ |
|
284 |
+static AVInputFormat roq_iformat = { |
|
285 |
+ "RoQ", |
|
286 |
+ "Id RoQ format", |
|
287 |
+ sizeof(RoqDemuxContext), |
|
288 |
+ roq_probe, |
|
289 |
+ roq_read_header, |
|
290 |
+ roq_read_packet, |
|
291 |
+ roq_read_close, |
|
292 |
+}; |
|
293 |
+ |
|
294 |
+int roq_init(void) |
|
295 |
+{ |
|
296 |
+ av_register_input_format(&roq_iformat); |
|
297 |
+ return 0; |
|
298 |
+} |
0 | 299 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,618 @@ |
0 |
+/* |
|
1 |
+ * Interplay MVE File Demuxer |
|
2 |
+ * Copyright (c) 2003 The ffmpeg Project |
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
17 |
+ */ |
|
18 |
+ |
|
19 |
+/** |
|
20 |
+ * @file ipmovie.c |
|
21 |
+ * Interplay MVE file demuxer |
|
22 |
+ * by Mike Melanson (melanson@pcisys.net) |
|
23 |
+ * For more information regarding the Interplay MVE file format, visit: |
|
24 |
+ * http://www.pcisys.net/~melanson/codecs/ |
|
25 |
+ * The aforementioned site also contains a command line utility for parsing |
|
26 |
+ * IP MVE files so that you can get a good idea of the typical structure of |
|
27 |
+ * such files. This demuxer is not the best example to use if you are trying |
|
28 |
+ * to write your own as it uses a rather roundabout approach for splitting |
|
29 |
+ * up and sending out the chunks. |
|
30 |
+ */ |
|
31 |
+ |
|
32 |
+#include "avformat.h" |
|
33 |
+ |
|
34 |
+/* debugging support: #define DEBUG_IPMOVIE as non-zero to see extremely |
|
35 |
+ * verbose information about the demux process */ |
|
36 |
+#define DEBUG_IPMOVIE 0 |
|
37 |
+ |
|
38 |
+#if DEBUG_IPMOVIE |
|
39 |
+#define debug_ipmovie printf |
|
40 |
+#else |
|
41 |
+static inline void debug_ipmovie(const char *format, ...) { } |
|
42 |
+#endif |
|
43 |
+ |
|
44 |
+ |
|
45 |
+#define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0]) |
|
46 |
+#define LE_32(x) ((((uint8_t*)(x))[3] << 24) | \ |
|
47 |
+ (((uint8_t*)(x))[2] << 16) | \ |
|
48 |
+ (((uint8_t*)(x))[1] << 8) | \ |
|
49 |
+ ((uint8_t*)(x))[0]) |
|
50 |
+ |
|
51 |
+#define IPMOVIE_SIGNATURE "Interplay MVE File\x1A\0" |
|
52 |
+#define IPMOVIE_SIGNATURE_SIZE 20 |
|
53 |
+#define CHUNK_PREAMBLE_SIZE 4 |
|
54 |
+#define OPCODE_PREAMBLE_SIZE 4 |
|
55 |
+ |
|
56 |
+#define CHUNK_INIT_AUDIO 0x0000 |
|
57 |
+#define CHUNK_AUDIO_ONLY 0x0001 |
|
58 |
+#define CHUNK_INIT_VIDEO 0x0002 |
|
59 |
+#define CHUNK_VIDEO 0x0003 |
|
60 |
+#define CHUNK_SHUTDOWN 0x0004 |
|
61 |
+#define CHUNK_END 0x0005 |
|
62 |
+/* these last types are used internally */ |
|
63 |
+#define CHUNK_DONE 0xFFFC |
|
64 |
+#define CHUNK_NOMEM 0xFFFD |
|
65 |
+#define CHUNK_EOF 0xFFFE |
|
66 |
+#define CHUNK_BAD 0xFFFF |
|
67 |
+ |
|
68 |
+#define OPCODE_END_OF_STREAM 0x00 |
|
69 |
+#define OPCODE_END_OF_CHUNK 0x01 |
|
70 |
+#define OPCODE_CREATE_TIMER 0x02 |
|
71 |
+#define OPCODE_INIT_AUDIO_BUFFERS 0x03 |
|
72 |
+#define OPCODE_START_STOP_AUDIO 0x04 |
|
73 |
+#define OPCODE_INIT_VIDEO_BUFFERS 0x05 |
|
74 |
+#define OPCODE_UNKNOWN_06 0x06 |
|
75 |
+#define OPCODE_SEND_BUFFER 0x07 |
|
76 |
+#define OPCODE_AUDIO_FRAME 0x08 |
|
77 |
+#define OPCODE_SILENCE_FRAME 0x09 |
|
78 |
+#define OPCODE_INIT_VIDEO_MODE 0x0A |
|
79 |
+#define OPCODE_CREATE_GRADIENT 0x0B |
|
80 |
+#define OPCODE_SET_PALETTE 0x0C |
|
81 |
+#define OPCODE_SET_PALETTE_COMPRESSED 0x0D |
|
82 |
+#define OPCODE_UNKNOWN_0E 0x0E |
|
83 |
+#define OPCODE_SET_DECODING_MAP 0x0F |
|
84 |
+#define OPCODE_UNKNOWN_10 0x10 |
|
85 |
+#define OPCODE_VIDEO_DATA 0x11 |
|
86 |
+#define OPCODE_UNKNOWN_12 0x12 |
|
87 |
+#define OPCODE_UNKNOWN_13 0x13 |
|
88 |
+#define OPCODE_UNKNOWN_14 0x14 |
|
89 |
+#define OPCODE_UNKNOWN_15 0x15 |
|
90 |
+ |
|
91 |
+#define PALETTE_COUNT 256 |
|
92 |
+ |
|
93 |
+typedef struct IPMVEContext { |
|
94 |
+ |
|
95 |
+ unsigned char *buf; |
|
96 |
+ int buf_size; |
|
97 |
+ |
|
98 |
+ int fps; |
|
99 |
+ int frame_pts_inc; |
|
100 |
+ |
|
101 |
+ unsigned int video_width; |
|
102 |
+ unsigned int video_height; |
|
103 |
+ int64_t video_pts; |
|
104 |
+ |
|
105 |
+ unsigned int audio_bits; |
|
106 |
+ unsigned int audio_channels; |
|
107 |
+ unsigned int audio_sample_rate; |
|
108 |
+ unsigned int audio_type; |
|
109 |
+ unsigned int audio_frame_count; |
|
110 |
+ |
|
111 |
+ int video_stream_index; |
|
112 |
+ int audio_stream_index; |
|
113 |
+ |
|
114 |
+ offset_t audio_chunk_offset; |
|
115 |
+ int audio_chunk_size; |
|
116 |
+ offset_t video_chunk_offset; |
|
117 |
+ int video_chunk_size; |
|
118 |
+ offset_t decode_map_chunk_offset; |
|
119 |
+ int decode_map_chunk_size; |
|
120 |
+ |
|
121 |
+ offset_t next_chunk_offset; |
|
122 |
+ |
|
123 |
+} IPMVEContext; |
|
124 |
+ |
|
125 |
+static int load_ipmovie_packet(IPMVEContext *s, ByteIOContext *pb, |
|
126 |
+ AVPacket *pkt) { |
|
127 |
+ |
|
128 |
+ int chunk_type; |
|
129 |
+ int64_t audio_pts = 0; |
|
130 |
+ |
|
131 |
+ if (s->audio_chunk_offset) { |
|
132 |
+ |
|
133 |
+ url_fseek(pb, s->audio_chunk_offset, SEEK_SET); |
|
134 |
+ s->audio_chunk_offset = 0; |
|
135 |
+ |
|
136 |
+ /* figure out the audio pts */ |
|
137 |
+ audio_pts = 90000; |
|
138 |
+ audio_pts *= s->audio_frame_count; |
|
139 |
+ audio_pts /= s->audio_sample_rate; |
|
140 |
+ |
|
141 |
+ if (av_new_packet(pkt, s->audio_chunk_size)) |
|
142 |
+ return CHUNK_NOMEM; |
|
143 |
+ |
|
144 |
+ pkt->stream_index = s->audio_stream_index; |
|
145 |
+ pkt->pts = audio_pts; |
|
146 |
+ if (get_buffer(pb, pkt->data, s->audio_chunk_size) != |
|
147 |
+ s->audio_chunk_size) { |
|
148 |
+ av_free_packet(pkt); |
|
149 |
+ return CHUNK_EOF; |
|
150 |
+ } |
|
151 |
+ |
|
152 |
+ /* audio frame maintenance */ |
|
153 |
+ if (s->audio_type != CODEC_ID_INTERPLAY_DPCM) |
|
154 |
+ s->audio_frame_count += |
|
155 |
+ (s->audio_chunk_size / s->audio_channels / (s->audio_bits / 8)); |
|
156 |
+ else |
|
157 |
+ s->audio_frame_count += |
|
158 |
+ (s->audio_chunk_size - 6) / s->audio_channels; |
|
159 |
+ |
|
160 |
+ debug_ipmovie("sending audio frame with pts %lld (%d audio frames)\n", |
|
161 |
+ audio_pts, s->audio_frame_count); |
|
162 |
+ |
|
163 |
+ chunk_type = CHUNK_VIDEO; |
|
164 |
+ |
|
165 |
+ } else if (s->decode_map_chunk_offset) { |
|
166 |
+ |
|
167 |
+ url_fseek(pb, s->decode_map_chunk_offset, SEEK_SET); |
|
168 |
+ s->decode_map_chunk_offset = 0; |
|
169 |
+ |
|
170 |
+ if (av_new_packet(pkt, s->decode_map_chunk_size)) |
|
171 |
+ return CHUNK_NOMEM; |
|
172 |
+ |
|
173 |
+ pkt->stream_index = s->video_stream_index; |
|
174 |
+ pkt->pts = s->video_pts; |
|
175 |
+ if (get_buffer(pb, pkt->data, s->decode_map_chunk_size) != |
|
176 |
+ s->decode_map_chunk_size) { |
|
177 |
+ av_free_packet(pkt); |
|
178 |
+ return CHUNK_EOF; |
|
179 |
+ } |
|
180 |
+ |
|
181 |
+ chunk_type = CHUNK_VIDEO; |
|
182 |
+ |
|
183 |
+ } else if (s->video_chunk_offset) { |
|
184 |
+ |
|
185 |
+ url_fseek(pb, s->video_chunk_offset, SEEK_SET); |
|
186 |
+ s->video_chunk_offset = 0; |
|
187 |
+ |
|
188 |
+ if (av_new_packet(pkt, s->video_chunk_size)) |
|
189 |
+ return CHUNK_NOMEM; |
|
190 |
+ |
|
191 |
+ pkt->stream_index = s->video_stream_index; |
|
192 |
+ pkt->pts = s->video_pts; |
|
193 |
+ if (get_buffer(pb, pkt->data, s->video_chunk_size) != |
|
194 |
+ s->video_chunk_size) { |
|
195 |
+ av_free_packet(pkt); |
|
196 |
+ return CHUNK_EOF; |
|
197 |
+ } |
|
198 |
+ |
|
199 |
+ s->video_pts += s->frame_pts_inc; |
|
200 |
+ |
|
201 |
+ chunk_type = CHUNK_VIDEO; |
|
202 |
+ |
|
203 |
+ } else { |
|
204 |
+ |
|
205 |
+ url_fseek(pb, s->next_chunk_offset, SEEK_SET); |
|
206 |
+ chunk_type = CHUNK_DONE; |
|
207 |
+ |
|
208 |
+ } |
|
209 |
+ |
|
210 |
+ return chunk_type; |
|
211 |
+} |
|
212 |
+ |
|
213 |
+/* This function loads and processes a single chunk in an IP movie file. |
|
214 |
+ * It returns the type of chunk that was processed. */ |
|
215 |
+static int process_ipmovie_chunk(IPMVEContext *s, ByteIOContext *pb, |
|
216 |
+ AVPacket *pkt) |
|
217 |
+{ |
|
218 |
+ unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE]; |
|
219 |
+ int chunk_type; |
|
220 |
+ int chunk_size; |
|
221 |
+ unsigned char opcode_preamble[OPCODE_PREAMBLE_SIZE]; |
|
222 |
+ unsigned char opcode_type; |
|
223 |
+ unsigned char opcode_version; |
|
224 |
+ int opcode_size; |
|
225 |
+ unsigned char scratch[1024]; |
|
226 |
+ int j; |
|
227 |
+ int first_color, last_color; |
|
228 |
+ int audio_flags; |
|
229 |
+ |
|
230 |
+ /* see if there are any pending packets */ |
|
231 |
+ chunk_type = load_ipmovie_packet(s, pb, pkt); |
|
232 |
+ if ((chunk_type == CHUNK_VIDEO) && (chunk_type != CHUNK_DONE)) |
|
233 |
+ return chunk_type; |
|
234 |
+ |
|
235 |
+ /* read the next chunk, wherever the file happens to be pointing */ |
|
236 |
+ if (url_feof(pb)) |
|
237 |
+ return CHUNK_EOF; |
|
238 |
+ if (get_buffer(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) != |
|
239 |
+ CHUNK_PREAMBLE_SIZE) |
|
240 |
+ return CHUNK_BAD; |
|
241 |
+ chunk_size = LE_16(&chunk_preamble[0]); |
|
242 |
+ chunk_type = LE_16(&chunk_preamble[2]); |
|
243 |
+ |
|
244 |
+ debug_ipmovie("chunk type 0x%04X, 0x%04X bytes: ", chunk_type, chunk_size); |
|
245 |
+ |
|
246 |
+ switch (chunk_type) { |
|
247 |
+ |
|
248 |
+ case CHUNK_INIT_AUDIO: |
|
249 |
+ debug_ipmovie("initialize audio\n"); |
|
250 |
+ break; |
|
251 |
+ |
|
252 |
+ case CHUNK_AUDIO_ONLY: |
|
253 |
+ debug_ipmovie("audio only\n"); |
|
254 |
+ break; |
|
255 |
+ |
|
256 |
+ case CHUNK_INIT_VIDEO: |
|
257 |
+ debug_ipmovie("initialize video\n"); |
|
258 |
+ break; |
|
259 |
+ |
|
260 |
+ case CHUNK_VIDEO: |
|
261 |
+ debug_ipmovie("video (and audio)\n"); |
|
262 |
+ break; |
|
263 |
+ |
|
264 |
+ case CHUNK_SHUTDOWN: |
|
265 |
+ debug_ipmovie("shutdown\n"); |
|
266 |
+ break; |
|
267 |
+ |
|
268 |
+ case CHUNK_END: |
|
269 |
+ debug_ipmovie("end\n"); |
|
270 |
+ break; |
|
271 |
+ |
|
272 |
+ default: |
|
273 |
+ debug_ipmovie("invalid chunk\n"); |
|
274 |
+ chunk_type = CHUNK_BAD; |
|
275 |
+ break; |
|
276 |
+ |
|
277 |
+ } |
|
278 |
+ |
|
279 |
+ while ((chunk_size > 0) && (chunk_type != CHUNK_BAD)) { |
|
280 |
+ |
|
281 |
+ /* read the next chunk, wherever the file happens to be pointing */ |
|
282 |
+ if (url_feof(pb)) { |
|
283 |
+ chunk_type = CHUNK_EOF; |
|
284 |
+ break; |
|
285 |
+ } |
|
286 |
+ if (get_buffer(pb, opcode_preamble, CHUNK_PREAMBLE_SIZE) != |
|
287 |
+ CHUNK_PREAMBLE_SIZE) { |
|
288 |
+ chunk_type = CHUNK_BAD; |
|
289 |
+ break; |
|
290 |
+ } |
|
291 |
+ |
|
292 |
+ opcode_size = LE_16(&opcode_preamble[0]); |
|
293 |
+ opcode_type = opcode_preamble[2]; |
|
294 |
+ opcode_version = opcode_preamble[3]; |
|
295 |
+ |
|
296 |
+ chunk_size -= OPCODE_PREAMBLE_SIZE; |
|
297 |
+ chunk_size -= opcode_size; |
|
298 |
+ if (chunk_size < 0) { |
|
299 |
+ debug_ipmovie("chunk_size countdown just went negative\n"); |
|
300 |
+ chunk_type = CHUNK_BAD; |
|
301 |
+ break; |
|
302 |
+ } |
|
303 |
+ |
|
304 |
+ debug_ipmovie(" opcode type %02X, version %d, 0x%04X bytes: ", |
|
305 |
+ opcode_type, opcode_version, opcode_size); |
|
306 |
+ switch (opcode_type) { |
|
307 |
+ |
|
308 |
+ case OPCODE_END_OF_STREAM: |
|
309 |
+ debug_ipmovie("end of stream\n"); |
|
310 |
+ url_fseek(pb, opcode_size, SEEK_CUR); |
|
311 |
+ break; |
|
312 |
+ |
|
313 |
+ case OPCODE_END_OF_CHUNK: |
|
314 |
+ debug_ipmovie("end of chunk\n"); |
|
315 |
+ url_fseek(pb, opcode_size, SEEK_CUR); |
|
316 |
+ break; |
|
317 |
+ |
|
318 |
+ case OPCODE_CREATE_TIMER: |
|
319 |
+ debug_ipmovie("create timer\n"); |
|
320 |
+ if ((opcode_version > 0) || (opcode_size > 6)) { |
|
321 |
+ debug_ipmovie("bad create_timer opcode\n"); |
|
322 |
+ chunk_type = CHUNK_BAD; |
|
323 |
+ break; |
|
324 |
+ } |
|
325 |
+ if (get_buffer(pb, scratch, opcode_size) != |
|
326 |
+ opcode_size) { |
|
327 |
+ chunk_type = CHUNK_BAD; |
|
328 |
+ break; |
|
329 |
+ } |
|
330 |
+ s->fps = 1000000 / (LE_32(&scratch[0]) * LE_16(&scratch[4])); |
|
331 |
+ s->fps++; /* above calculation usually yields 14.9; we need 15 */ |
|
332 |
+ s->frame_pts_inc = 90000 / s->fps; |
|
333 |
+ debug_ipmovie("%d frames/second (timer div = %d, subdiv = %d)\n", |
|
334 |
+ s->fps, LE_32(&scratch[0]), LE_16(&scratch[4])); |
|
335 |
+ break; |
|
336 |
+ |
|
337 |
+ case OPCODE_INIT_AUDIO_BUFFERS: |
|
338 |
+ debug_ipmovie("initialize audio buffers\n"); |
|
339 |
+ if ((opcode_version > 1) || (opcode_size > 10)) { |
|
340 |
+ debug_ipmovie("bad init_audio_buffers opcode\n"); |
|
341 |
+ chunk_type = CHUNK_BAD; |
|
342 |
+ break; |
|
343 |
+ } |
|
344 |
+ if (get_buffer(pb, scratch, opcode_size) != |
|
345 |
+ opcode_size) { |
|
346 |
+ chunk_type = CHUNK_BAD; |
|
347 |
+ break; |
|
348 |
+ } |
|
349 |
+ s->audio_sample_rate = LE_16(&scratch[4]); |
|
350 |
+ audio_flags = LE_16(&scratch[2]); |
|
351 |
+ /* bit 0 of the flags: 0 = mono, 1 = stereo */ |
|
352 |
+ s->audio_channels = (audio_flags & 1) + 1; |
|
353 |
+ /* bit 1 of the flags: 0 = 8 bit, 1 = 16 bit */ |
|
354 |
+ s->audio_bits = (((audio_flags >> 1) & 1) + 1) * 8; |
|
355 |
+ /* bit 2 indicates compressed audio in version 1 opcode */ |
|
356 |
+ if ((opcode_version == 1) && (audio_flags & 0x4)) |
|
357 |
+ s->audio_type = CODEC_ID_INTERPLAY_DPCM; |
|
358 |
+ else if (s->audio_bits == 16) |
|
359 |
+ s->audio_type = CODEC_ID_PCM_S16LE; |
|
360 |
+ else |
|
361 |
+ s->audio_type = CODEC_ID_PCM_U8; |
|
362 |
+ debug_ipmovie("audio: %d bits, %d Hz, %s, %s format\n", |
|
363 |
+ s->audio_bits, |
|
364 |
+ s->audio_sample_rate, |
|
365 |
+ (s->audio_channels == 2) ? "stereo" : "mono", |
|
366 |
+ (s->audio_type == CODEC_ID_INTERPLAY_DPCM) ? |
|
367 |
+ "Interplay audio" : "PCM"); |
|
368 |
+ break; |
|
369 |
+ |
|
370 |
+ case OPCODE_START_STOP_AUDIO: |
|
371 |
+ debug_ipmovie("start/stop audio\n"); |
|
372 |
+ url_fseek(pb, opcode_size, SEEK_CUR); |
|
373 |
+ break; |
|
374 |
+ |
|
375 |
+ case OPCODE_INIT_VIDEO_BUFFERS: |
|
376 |
+ debug_ipmovie("initialize video buffers\n"); |
|
377 |
+ if ((opcode_version > 2) || (opcode_size > 8)) { |
|
378 |
+ debug_ipmovie("bad init_video_buffers opcode\n"); |
|
379 |
+ chunk_type = CHUNK_BAD; |
|
380 |
+ break; |
|
381 |
+ } |
|
382 |
+ if (get_buffer(pb, scratch, opcode_size) != |
|
383 |
+ opcode_size) { |
|
384 |
+ chunk_type = CHUNK_BAD; |
|
385 |
+ break; |
|
386 |
+ } |
|
387 |
+ s->video_width = LE_16(&scratch[0]) * 8; |
|
388 |
+ s->video_height = LE_16(&scratch[2]) * 8; |
|
389 |
+ debug_ipmovie("video resolution: %d x %d\n", |
|
390 |
+ s->video_width, s->video_height); |
|
391 |
+ break; |
|
392 |
+ |
|
393 |
+ case OPCODE_UNKNOWN_06: |
|
394 |
+ case OPCODE_UNKNOWN_0E: |
|
395 |
+ case OPCODE_UNKNOWN_10: |
|
396 |
+ case OPCODE_UNKNOWN_12: |
|
397 |
+ case OPCODE_UNKNOWN_13: |
|
398 |
+ case OPCODE_UNKNOWN_14: |
|
399 |
+ case OPCODE_UNKNOWN_15: |
|
400 |
+ debug_ipmovie("unknown (but documented) opcode %02X\n", opcode_type); |
|
401 |
+ url_fseek(pb, opcode_size, SEEK_CUR); |
|
402 |
+ break; |
|
403 |
+ |
|
404 |
+ case OPCODE_SEND_BUFFER: |
|
405 |
+ debug_ipmovie("send buffer\n"); |
|
406 |
+ url_fseek(pb, opcode_size, SEEK_CUR); |
|
407 |
+ break; |
|
408 |
+ |
|
409 |
+ case OPCODE_AUDIO_FRAME: |
|
410 |
+ debug_ipmovie("audio frame\n"); |
|
411 |
+ |
|
412 |
+ /* log position and move on for now */ |
|
413 |
+ s->audio_chunk_offset = url_ftell(pb); |
|
414 |
+ s->audio_chunk_size = opcode_size; |
|
415 |
+ url_fseek(pb, opcode_size, SEEK_CUR); |
|
416 |
+ break; |
|
417 |
+ |
|
418 |
+ case OPCODE_SILENCE_FRAME: |
|
419 |
+ debug_ipmovie("silence frame\n"); |
|
420 |
+ url_fseek(pb, opcode_size, SEEK_CUR); |
|
421 |
+ break; |
|
422 |
+ |
|
423 |
+ case OPCODE_INIT_VIDEO_MODE: |
|
424 |
+ debug_ipmovie("initialize video mode\n"); |
|
425 |
+ url_fseek(pb, opcode_size, SEEK_CUR); |
|
426 |
+ break; |
|
427 |
+ |
|
428 |
+ case OPCODE_CREATE_GRADIENT: |
|
429 |
+ debug_ipmovie("create gradient\n"); |
|
430 |
+ url_fseek(pb, opcode_size, SEEK_CUR); |
|
431 |
+ break; |
|
432 |
+ |
|
433 |
+ case OPCODE_SET_PALETTE: |
|
434 |
+ debug_ipmovie("set palette\n"); |
|
435 |
+ /* check for the logical maximum palette size |
|
436 |
+ * (3 * 256 + 4 bytes) */ |
|
437 |
+ if (opcode_size > 0x304) { |
|
438 |
+ debug_ipmovie("demux_ipmovie: set_palette opcode too large\n"); |
|
439 |
+ chunk_type = CHUNK_BAD; |
|
440 |
+ break; |
|
441 |
+ } |
|
442 |
+ if (get_buffer(pb, scratch, opcode_size) != opcode_size) { |
|
443 |
+ chunk_type = CHUNK_BAD; |
|
444 |
+ break; |
|
445 |
+ } |
|
446 |
+ |
|
447 |
+ /* load the palette into internal data structure */ |
|
448 |
+ first_color = LE_16(&scratch[0]); |
|
449 |
+ last_color = LE_16(&scratch[2]); |
|
450 |
+ /* sanity check (since they are 16 bit values) */ |
|
451 |
+ if ((first_color > 0xFF) || (last_color > 0xFF)) { |
|
452 |
+ debug_ipmovie("demux_ipmovie: set_palette indices out of range (%d -> %d)\n", |
|
453 |
+ first_color, last_color); |
|
454 |
+ chunk_type = CHUNK_BAD; |
|
455 |
+ break; |
|
456 |
+ } |
|
457 |
+ j = 4; /* offset of first palette data */ |
|
458 |
+#if 0 |
|
459 |
+ for (i = first_color; i <= last_color; i++) { |
|
460 |
+ s->palette[i].r = scratch[j++] * 4; |
|
461 |
+ s->palette[i].g = scratch[j++] * 4; |
|
462 |
+ s->palette[i].b = scratch[j++] * 4; |
|
463 |
+ } |
|
464 |
+#endif |
|
465 |
+ break; |
|
466 |
+ |
|
467 |
+ case OPCODE_SET_PALETTE_COMPRESSED: |
|
468 |
+ debug_ipmovie("set palette compressed\n"); |
|
469 |
+ url_fseek(pb, opcode_size, SEEK_CUR); |
|
470 |
+ break; |
|
471 |
+ |
|
472 |
+ case OPCODE_SET_DECODING_MAP: |
|
473 |
+ debug_ipmovie("set decoding map\n"); |
|
474 |
+ |
|
475 |
+ /* log position and move on for now */ |
|
476 |
+ s->decode_map_chunk_offset = url_ftell(pb); |
|
477 |
+ s->decode_map_chunk_size = opcode_size; |
|
478 |
+ url_fseek(pb, opcode_size, SEEK_CUR); |
|
479 |
+ break; |
|
480 |
+ |
|
481 |
+ case OPCODE_VIDEO_DATA: |
|
482 |
+ debug_ipmovie("set video data\n"); |
|
483 |
+ |
|
484 |
+ /* log position and move on for now */ |
|
485 |
+ s->video_chunk_offset = url_ftell(pb); |
|
486 |
+ s->video_chunk_size = opcode_size; |
|
487 |
+ url_fseek(pb, opcode_size, SEEK_CUR); |
|
488 |
+ break; |
|
489 |
+ |
|
490 |
+ default: |
|
491 |
+ debug_ipmovie("*** unknown opcode type\n"); |
|
492 |
+ chunk_type = CHUNK_BAD; |
|
493 |
+ break; |
|
494 |
+ |
|
495 |
+ } |
|
496 |
+ } |
|
497 |
+ |
|
498 |
+ /* make a note of where the stream is sitting */ |
|
499 |
+ s->next_chunk_offset = url_ftell(pb); |
|
500 |
+ |
|
501 |
+ /* dispatch the first of any pending packets */ |
|
502 |
+ if ((chunk_type == CHUNK_VIDEO) || (chunk_type == CHUNK_AUDIO_ONLY)) |
|
503 |
+ chunk_type = load_ipmovie_packet(s, pb, pkt); |
|
504 |
+ |
|
505 |
+ return chunk_type; |
|
506 |
+} |
|
507 |
+ |
|
508 |
+static int ipmovie_probe(AVProbeData *p) |
|
509 |
+{ |
|
510 |
+ if (p->buf_size < IPMOVIE_SIGNATURE_SIZE) |
|
511 |
+ return 0; |
|
512 |
+ if (strncmp(p->buf, IPMOVIE_SIGNATURE, IPMOVIE_SIGNATURE_SIZE) != 0) |
|
513 |
+ return 0; |
|
514 |
+ |
|
515 |
+ return AVPROBE_SCORE_MAX; |
|
516 |
+} |
|
517 |
+ |
|
518 |
+static int ipmovie_read_header(AVFormatContext *s, |
|
519 |
+ AVFormatParameters *ap) |
|
520 |
+{ |
|
521 |
+ IPMVEContext *ipmovie = (IPMVEContext *)s->priv_data; |
|
522 |
+ ByteIOContext *pb = &s->pb; |
|
523 |
+ AVPacket pkt; |
|
524 |
+ AVStream *st; |
|
525 |
+ |
|
526 |
+ /* initialize private context members */ |
|
527 |
+ ipmovie->video_pts = ipmovie->audio_frame_count = 0; |
|
528 |
+ ipmovie->audio_chunk_offset = ipmovie->video_chunk_offset = |
|
529 |
+ ipmovie->decode_map_chunk_offset = 0; |
|
530 |
+ |
|
531 |
+ /* on the first read, this will position the stream at the first chunk */ |
|
532 |
+ ipmovie->next_chunk_offset = IPMOVIE_SIGNATURE_SIZE + 6; |
|
533 |
+ |
|
534 |
+ /* process the first chunk which should be CHUNK_INIT_VIDEO */ |
|
535 |
+ if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_VIDEO) |
|
536 |
+ return AVERROR_INVALIDDATA; |
|
537 |
+ |
|
538 |
+ /* process the next chunk which should be CHUNK_INIT_AUDIO */ |
|
539 |
+ if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_AUDIO) |
|
540 |
+ return AVERROR_INVALIDDATA; |
|
541 |
+ |
|
542 |
+ /* set the pts reference (1 pts = 1/90000) */ |
|
543 |
+ s->pts_num = 1; |
|
544 |
+ s->pts_den = 90000; |
|
545 |
+ |
|
546 |
+ /* initialize the stream decoders */ |
|
547 |
+ st = av_new_stream(s, 0); |
|
548 |
+ if (!st) |
|
549 |
+ return AVERROR_NOMEM; |
|
550 |
+ ipmovie->video_stream_index = st->index; |
|
551 |
+ st->codec.codec_type = CODEC_TYPE_VIDEO; |
|
552 |
+ st->codec.codec_id = CODEC_ID_INTERPLAY_VIDEO; |
|
553 |
+ st->codec.codec_tag = 0; /* no fourcc */ |
|
554 |
+ st->codec.width = ipmovie->video_width; |
|
555 |
+ st->codec.height = ipmovie->video_height; |
|
556 |
+ |
|
557 |
+ st = av_new_stream(s, 0); |
|
558 |
+ if (!st) |
|
559 |
+ return AVERROR_NOMEM; |
|
560 |
+ ipmovie->audio_stream_index = st->index; |
|
561 |
+ st->codec.codec_type = CODEC_TYPE_AUDIO; |
|
562 |
+ st->codec.codec_id = ipmovie->audio_type; |
|
563 |
+ st->codec.codec_tag = 0; /* no tag */ |
|
564 |
+ st->codec.channels = ipmovie->audio_channels; |
|
565 |
+ st->codec.sample_rate = ipmovie->audio_sample_rate; |
|
566 |
+ st->codec.bits_per_sample = ipmovie->audio_bits; |
|
567 |
+ st->codec.bit_rate = st->codec.channels * st->codec.sample_rate * |
|
568 |
+ st->codec.bits_per_sample / |
|
569 |
+ (st->codec.codec_id == CODEC_ID_INTERPLAY_DPCM) ? 2 : 1; |
|
570 |
+ st->codec.block_align = st->codec.channels * st->codec.bits_per_sample; |
|
571 |
+ |
|
572 |
+ return 0; |
|
573 |
+} |
|
574 |
+ |
|
575 |
+static int ipmovie_read_packet(AVFormatContext *s, |
|
576 |
+ AVPacket *pkt) |
|
577 |
+{ |
|
578 |
+ IPMVEContext *ipmovie = (IPMVEContext *)s->priv_data; |
|
579 |
+ ByteIOContext *pb = &s->pb; |
|
580 |
+ int ret; |
|
581 |
+ |
|
582 |
+ ret = process_ipmovie_chunk(ipmovie, pb, pkt); |
|
583 |
+ if (ret == CHUNK_BAD) |
|
584 |
+ ret = AVERROR_INVALIDDATA; |
|
585 |
+ else if (ret == CHUNK_EOF) |
|
586 |
+ ret = -EIO; |
|
587 |
+ else if (ret == CHUNK_NOMEM) |
|
588 |
+ ret = AVERROR_NOMEM; |
|
589 |
+ else |
|
590 |
+ ret = 0; |
|
591 |
+ |
|
592 |
+ return ret; |
|
593 |
+} |
|
594 |
+ |
|
595 |
+static int ipmovie_read_close(AVFormatContext *s) |
|
596 |
+{ |
|
597 |
+// IPMVEContext *ipmovie = (IPMVEContext *)s->priv_data; |
|
598 |
+ |
|
599 |
+ return 0; |
|
600 |
+} |
|
601 |
+ |
|
602 |
+static AVInputFormat ipmovie_iformat = { |
|
603 |
+ "ipmovie", |
|
604 |
+ "Interplay MVE format", |
|
605 |
+ sizeof(IPMVEContext), |
|
606 |
+ ipmovie_probe, |
|
607 |
+ ipmovie_read_header, |
|
608 |
+ ipmovie_read_packet, |
|
609 |
+ ipmovie_read_close, |
|
610 |
+}; |
|
611 |
+ |
|
612 |
+int ipmovie_init(void) |
|
613 |
+{ |
|
614 |
+ av_register_input_format(&ipmovie_iformat); |
|
615 |
+ return 0; |
|
616 |
+} |
|
617 |
+ |