Originally committed as revision 5598 to svn://svn.ffmpeg.org/ffmpeg/trunk
Reimar Döffinger authored on 2006/07/04 01:32:57... | ... |
@@ -704,6 +704,7 @@ library: |
704 | 704 |
@tab Multimedia format used by the Creature Shock game. |
705 | 705 |
@item Smacker @tab @tab X |
706 | 706 |
@tab Multimedia format used by many games. |
707 |
+@item GXF @tab @tab X |
|
707 | 708 |
@end multitable |
708 | 709 |
|
709 | 710 |
@code{X} means that encoding (resp. decoding) is supported. |
... | ... |
@@ -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 nuv.o oggparseogm.o |
|
21 |
+ voc.o tta.o mm.o avs.o smacker.o nuv.o gxf.o oggparseogm.o |
|
22 | 22 |
|
23 | 23 |
# muxers |
24 | 24 |
ifeq ($(CONFIG_MUXERS),yes) |
147 | 150 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,259 @@ |
0 |
+/* |
|
1 |
+ * GXF 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 enum { |
|
22 |
+ PKT_MAP = 0xbc, |
|
23 |
+ PKT_MEDIA = 0xbf, |
|
24 |
+ PKT_EOS = 0xfb, |
|
25 |
+ PKT_FLT = 0xfc, |
|
26 |
+ PKT_UMF = 0xfd |
|
27 |
+} pkt_type_t; |
|
28 |
+ |
|
29 |
+/** |
|
30 |
+ * \brief parses a packet header, extracting type and length |
|
31 |
+ * \param pb ByteIOContext to read header from |
|
32 |
+ * \param type detected packet type is stored here |
|
33 |
+ * \param length detected packet length, excluding header is stored here |
|
34 |
+ * \return 0 if header not found or contains invalid data, 1 otherwise |
|
35 |
+ */ |
|
36 |
+static int parse_packet_header(ByteIOContext *pb, pkt_type_t *type, int *length) { |
|
37 |
+ if (get_be32(pb)) |
|
38 |
+ return 0; |
|
39 |
+ if (get_byte(pb) != 1) |
|
40 |
+ return 0; |
|
41 |
+ *type = get_byte(pb); |
|
42 |
+ *length = get_be32(pb); |
|
43 |
+ if ((*length >> 24) || *length < 16) |
|
44 |
+ return 0; |
|
45 |
+ *length -= 16; |
|
46 |
+ if (get_be32(pb)) |
|
47 |
+ return 0; |
|
48 |
+ if (get_byte(pb) != 0xe1) |
|
49 |
+ return 0; |
|
50 |
+ if (get_byte(pb) != 0xe2) |
|
51 |
+ return 0; |
|
52 |
+ return 1; |
|
53 |
+} |
|
54 |
+ |
|
55 |
+/** |
|
56 |
+ * \brief check if file starts with a PKT_MAP header |
|
57 |
+ */ |
|
58 |
+static int gxf_probe(AVProbeData *p) { |
|
59 |
+ static const uint8_t startcode[] = {0, 0, 0, 0, 1, 0xbc}; // start with map packet |
|
60 |
+ static const uint8_t endcode[] = {0, 0, 0, 0, 0xe1, 0xe2}; |
|
61 |
+ if (p->buf_size < 16) |
|
62 |
+ return 0; |
|
63 |
+ if (!memcmp(p->buf, startcode, sizeof(startcode)) && |
|
64 |
+ !memcmp(&p->buf[16 - sizeof(endcode)], endcode, sizeof(endcode))) |
|
65 |
+ return AVPROBE_SCORE_MAX; |
|
66 |
+ return 0; |
|
67 |
+} |
|
68 |
+ |
|
69 |
+/** |
|
70 |
+ * \brief gets the stream index for the track with the specified id, creates new |
|
71 |
+ * stream if not found |
|
72 |
+ * \param stream id of stream to find / add |
|
73 |
+ * \param format stream format identifier |
|
74 |
+ */ |
|
75 |
+static int get_sindex(AVFormatContext *s, int id, int format) { |
|
76 |
+ int i; |
|
77 |
+ AVStream *st = NULL; |
|
78 |
+ for (i = 0; i < s->nb_streams; i++) { |
|
79 |
+ if (s->streams[i]->id == id) |
|
80 |
+ return i; |
|
81 |
+ } |
|
82 |
+ st = av_new_stream(s, id); |
|
83 |
+ switch (format) { |
|
84 |
+ case 3: |
|
85 |
+ case 4: |
|
86 |
+ st->codec->codec_type = CODEC_TYPE_VIDEO; |
|
87 |
+ st->codec->codec_id = CODEC_ID_MJPEG; |
|
88 |
+ st->codec->codec_tag = MKTAG('M', 'J', 'P', 'G'); |
|
89 |
+ break; |
|
90 |
+ case 13: |
|
91 |
+ case 15: |
|
92 |
+ st->codec->codec_type = CODEC_TYPE_VIDEO; |
|
93 |
+ st->codec->codec_id = CODEC_ID_DVVIDEO; |
|
94 |
+ st->codec->codec_tag = MKTAG('d', 'v', 'c', ' '); |
|
95 |
+ break; |
|
96 |
+ case 14: |
|
97 |
+ case 16: |
|
98 |
+ st->codec->codec_type = CODEC_TYPE_VIDEO; |
|
99 |
+ st->codec->codec_id = CODEC_ID_DVVIDEO; |
|
100 |
+ st->codec->codec_tag = MKTAG('d', 'v', 'c', 'p'); |
|
101 |
+ break; |
|
102 |
+ case 11: |
|
103 |
+ case 12: |
|
104 |
+ case 20: |
|
105 |
+ st->codec->codec_type = CODEC_TYPE_VIDEO; |
|
106 |
+ st->codec->codec_id = CODEC_ID_MPEG2VIDEO; |
|
107 |
+ st->codec->codec_tag = MKTAG('M', 'P', 'G', '2'); |
|
108 |
+ break; |
|
109 |
+ case 22: |
|
110 |
+ case 23: |
|
111 |
+ st->codec->codec_type = CODEC_TYPE_VIDEO; |
|
112 |
+ st->codec->codec_id = CODEC_ID_MPEG1VIDEO; |
|
113 |
+ st->codec->codec_tag = MKTAG('M', 'P', 'G', '1'); |
|
114 |
+ break; |
|
115 |
+ case 9: |
|
116 |
+ st->codec->codec_type = CODEC_TYPE_AUDIO; |
|
117 |
+ st->codec->codec_id = CODEC_ID_PCM_S24LE; |
|
118 |
+ st->codec->codec_tag = 0x1; |
|
119 |
+ st->codec->channels = 1; |
|
120 |
+ st->codec->sample_rate = 48000; |
|
121 |
+ st->codec->bit_rate = 3 * 1 * 48000 * 8; |
|
122 |
+ st->codec->block_align = 3 * 1; |
|
123 |
+ st->codec->bits_per_sample = 24; |
|
124 |
+ break; |
|
125 |
+ case 10: |
|
126 |
+ st->codec->codec_type = CODEC_TYPE_AUDIO; |
|
127 |
+ st->codec->codec_id = CODEC_ID_PCM_S16LE; |
|
128 |
+ st->codec->codec_tag = 0x1; |
|
129 |
+ st->codec->channels = 1; |
|
130 |
+ st->codec->sample_rate = 48000; |
|
131 |
+ st->codec->bit_rate = 2 * 1 * 48000 * 8; |
|
132 |
+ st->codec->block_align = 2 * 1; |
|
133 |
+ st->codec->bits_per_sample = 16; |
|
134 |
+ break; |
|
135 |
+ case 17: |
|
136 |
+ st->codec->codec_type = CODEC_TYPE_AUDIO; |
|
137 |
+ st->codec->codec_id = CODEC_ID_AC3; |
|
138 |
+ st->codec->codec_tag = 0x2000; |
|
139 |
+ st->codec->channels = 2; |
|
140 |
+ st->codec->sample_rate = 48000; |
|
141 |
+ break; |
|
142 |
+ default: |
|
143 |
+ st->codec->codec_type = CODEC_TYPE_UNKNOWN; |
|
144 |
+ st->codec->codec_id = CODEC_ID_NONE; |
|
145 |
+ break; |
|
146 |
+ } |
|
147 |
+ return s->nb_streams - 1; |
|
148 |
+} |
|
149 |
+ |
|
150 |
+static int gxf_header(AVFormatContext *s, AVFormatParameters *ap) { |
|
151 |
+ ByteIOContext *pb = &s->pb; |
|
152 |
+ pkt_type_t pkt_type; |
|
153 |
+ int map_len; |
|
154 |
+ int len; |
|
155 |
+ if (!parse_packet_header(pb, &pkt_type, &map_len) || pkt_type != PKT_MAP) { |
|
156 |
+ av_log(s, AV_LOG_ERROR, "GXF: map packet not found\n"); |
|
157 |
+ return 0; |
|
158 |
+ } |
|
159 |
+ map_len -= 2; |
|
160 |
+ if (get_byte(pb) != 0x0e0 || get_byte(pb) != 0xff) { |
|
161 |
+ av_log(s, AV_LOG_ERROR, "GXF: unknown version or invalid map preamble\n"); |
|
162 |
+ return 0; |
|
163 |
+ } |
|
164 |
+ map_len -= 2; |
|
165 |
+ len = get_be16(pb); // length of material data section |
|
166 |
+ if (len > map_len) { |
|
167 |
+ av_log(s, AV_LOG_ERROR, "GXF: material data longer than map data\n"); |
|
168 |
+ return 0; |
|
169 |
+ } |
|
170 |
+ map_len -= len; |
|
171 |
+ url_fskip(pb, len); |
|
172 |
+ map_len -= 2; |
|
173 |
+ len = get_be16(pb); // length of track description |
|
174 |
+ if (len > map_len) { |
|
175 |
+ av_log(s, AV_LOG_ERROR, "GXF: track description longer than map data\n"); |
|
176 |
+ return 0; |
|
177 |
+ } |
|
178 |
+ map_len -= len; |
|
179 |
+ while (len > 0) { |
|
180 |
+ int track_type, track_id, track_len; |
|
181 |
+ len -= 4; |
|
182 |
+ track_type = get_byte(pb); |
|
183 |
+ track_id = get_byte(pb); |
|
184 |
+ track_len = get_be16(pb); |
|
185 |
+ len -= track_len; |
|
186 |
+ url_fskip(pb, track_len); |
|
187 |
+ if (!(track_type & 0x80)) { |
|
188 |
+ av_log(s, AV_LOG_ERROR, "GXF: invalid track type %x\n", track_type); |
|
189 |
+ continue; |
|
190 |
+ } |
|
191 |
+ track_type &= 0x7f; |
|
192 |
+ if ((track_id & 0xc0) != 0xc0) { |
|
193 |
+ av_log(s, AV_LOG_ERROR, "GXF: invalid track id %x\n", track_id); |
|
194 |
+ continue; |
|
195 |
+ } |
|
196 |
+ track_id &= 0x3f; |
|
197 |
+ get_sindex(s, track_id, track_type); |
|
198 |
+ } |
|
199 |
+ if (len < 0) |
|
200 |
+ av_log(s, AV_LOG_ERROR, "GXF: invalid track description length specified\n"); |
|
201 |
+ if (map_len) |
|
202 |
+ url_fskip(pb, map_len); |
|
203 |
+ return 0; |
|
204 |
+} |
|
205 |
+ |
|
206 |
+static int gxf_packet(AVFormatContext *s, AVPacket *pkt) { |
|
207 |
+ ByteIOContext *pb = &s->pb; |
|
208 |
+ pkt_type_t pkt_type; |
|
209 |
+ int pkt_len; |
|
210 |
+ while (!url_feof(pb)) { |
|
211 |
+ int track_type, track_id, ret; |
|
212 |
+ if (!parse_packet_header(pb, &pkt_type, &pkt_len)) { |
|
213 |
+ if (!url_feof(pb)) |
|
214 |
+ av_log(s, AV_LOG_ERROR, "GXF: sync lost\n"); |
|
215 |
+ return -1; |
|
216 |
+ } |
|
217 |
+ if (pkt_type != PKT_MEDIA) { |
|
218 |
+ url_fskip(pb, pkt_len); |
|
219 |
+ continue; |
|
220 |
+ } |
|
221 |
+ if (pkt_len < 16) { |
|
222 |
+ av_log(s, AV_LOG_ERROR, "GXF: invalid media packet length\n"); |
|
223 |
+ continue; |
|
224 |
+ } |
|
225 |
+ pkt_len -= 16; |
|
226 |
+ track_type = get_byte(pb); |
|
227 |
+ track_id = get_byte(pb); |
|
228 |
+ get_be32(pb); // field number |
|
229 |
+ get_be32(pb); // field information |
|
230 |
+ get_be32(pb); // "timeline" field number |
|
231 |
+ get_byte(pb); // flags |
|
232 |
+ get_byte(pb); // reserved |
|
233 |
+ // NOTE: there is also data length information in the |
|
234 |
+ // field information, it might be better to take this int account |
|
235 |
+ // as well. |
|
236 |
+ ret = av_get_packet(pb, pkt, pkt_len); |
|
237 |
+ pkt->stream_index = get_sindex(s, track_id, track_type); |
|
238 |
+ return ret; |
|
239 |
+ } |
|
240 |
+ return AVERROR_IO; |
|
241 |
+} |
|
242 |
+ |
|
243 |
+static AVInputFormat gxf_iformat = { |
|
244 |
+ "gxf", |
|
245 |
+ "GXF format", |
|
246 |
+ 0, |
|
247 |
+ gxf_probe, |
|
248 |
+ gxf_header, |
|
249 |
+ gxf_packet, |
|
250 |
+ NULL, |
|
251 |
+ NULL, |
|
252 |
+}; |
|
253 |
+ |
|
254 |
+int gxf_init(void) { |
|
255 |
+ av_register_input_format(&gxf_iformat); |
|
256 |
+ return 0; |
|
257 |
+} |
|
258 |
+ |