Browse code

add GXF demuxer

Originally committed as revision 5598 to svn://svn.ffmpeg.org/ffmpeg/trunk

Reimar Döffinger authored on 2006/07/04 01:32:57
Showing 7 changed files
... ...
@@ -48,6 +48,7 @@ version <next>
48 48
 - MPEG-2 intra vlc support
49 49
 - MPEG-2 4:2:2 encoder
50 50
 - Flash Screen Video decoder
51
+- GXF demuxer
51 52
 
52 53
 version 0.4.9-pre1:
53 54
 
... ...
@@ -190,6 +190,7 @@ Muxers/Demuxers:
190 190
   dc1394.c, dv.c                        Roman Shaposhnik
191 191
   flic.c                                Mike Melanson
192 192
   flvdec.c, flvenc.c                    Michael Niedermayer
193
+  gxf.c                                 Reimar Doeffinger
193 194
   idcin.c                               Mike Melanson
194 195
   idroq.c                               Mike Melanson
195 196
   ipmovie.c                             Mike Melanson
... ...
@@ -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)
... ...
@@ -122,6 +122,7 @@ void av_register_all(void)
122 122
     tta_init();
123 123
     avs_init();
124 124
     nuv_init();
125
+    gxf_init();
125 126
 
126 127
 #ifdef CONFIG_MUXERS
127 128
     /* image formats */
... ...
@@ -141,6 +141,9 @@ int daud_init(void);
141 141
 /* nuv.c */
142 142
 int nuv_init(void);
143 143
 
144
+/* gxf.c */
145
+int gxf_init(void);
146
+
144 147
 /* aiff.c */
145 148
 int ff_aiff_init(void);
146 149
 
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
+