2 * 4X Technologies .4xm File Demuxer (no muxer)
3 * Copyright (c) 2003 The ffmpeg Project
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * 4X Technologies file demuxer
23 * by Mike Melanson (melanson@pcisys.net)
24 * for more information on the .4xm file format, visit:
25 * http://www.pcisys.net/~melanson/codecs/
30 #define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0])
31 #define LE_32(x) ((((uint8_t*)(x))[3] << 24) | \
32 (((uint8_t*)(x))[2] << 16) | \
33 (((uint8_t*)(x))[1] << 8) | \
35 #define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1])
36 #define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \
37 (((uint8_t*)(x))[1] << 16) | \
38 (((uint8_t*)(x))[2] << 8) | \
41 #define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \
42 ( (long)(unsigned char)(ch3) | \
43 ( (long)(unsigned char)(ch2) << 8 ) | \
44 ( (long)(unsigned char)(ch1) << 16 ) | \
45 ( (long)(unsigned char)(ch0) << 24 ) )
47 #define RIFF_TAG FOURCC_TAG('R', 'I', 'F', 'F')
48 #define _4XMV_TAG FOURCC_TAG('4', 'X', 'M', 'V')
49 #define LIST_TAG FOURCC_TAG('L', 'I', 'S', 'T')
50 #define HEAD_TAG FOURCC_TAG('H', 'E', 'A', 'D')
51 #define TRK__TAG FOURCC_TAG('T', 'R', 'K', '_')
52 #define MOVI_TAG FOURCC_TAG('M', 'O', 'V', 'I')
53 #define VTRK_TAG FOURCC_TAG('V', 'T', 'R', 'K')
54 #define STRK_TAG FOURCC_TAG('S', 'T', 'R', 'K')
55 #define name_TAG FOURCC_TAG('n', 'a', 'm', 'e')
56 #define vtrk_TAG FOURCC_TAG('v', 't', 'r', 'k')
57 #define strk_TAG FOURCC_TAG('s', 't', 'r', 'k')
58 #define ifrm_TAG FOURCC_TAG('i', 'f', 'r', 'm')
59 #define pfrm_TAG FOURCC_TAG('p', 'f', 'r', 'm')
60 #define cfrm_TAG FOURCC_TAG('c', 'f', 'r', 'm')
61 #define snd__TAG FOURCC_TAG('s', 'n', 'd', '_')
62 #define _TAG FOURCC_TAG('', '', '', '')
64 #define vtrk_SIZE 0x44
65 #define strk_SIZE 0x28
67 #define GET_LIST_HEADER() \
68 fourcc_tag = get_be32(pb); \
69 size = get_le32(pb); \
70 if (fourcc_tag != LIST_TAG) \
71 return AVERROR_INVALIDDATA; \
72 fourcc_tag = get_be32(pb);
74 typedef struct AudioTrack
{
80 typedef struct FourxmDemuxContext
{
88 static int fourxm_probe(AVProbeData
*p
)
90 if ((BE_32(&p
->buf
[0]) != RIFF_TAG
) ||
91 (BE_32(&p
->buf
[8]) != _4XMV_TAG
))
94 printf (" detected .4xm file\n");
96 return AVPROBE_SCORE_MAX
;
99 static int fourxm_read_header(AVFormatContext
*s
,
100 AVFormatParameters
*ap
)
102 ByteIOContext
*pb
= &s
->pb
;
103 unsigned int fourcc_tag
;
106 FourxmDemuxContext
*fourxm
= (FourxmDemuxContext
*)s
->priv_data
;
107 unsigned char *header
;
109 int current_track
= -1;
112 fourxm
->track_count
= 0;
113 fourxm
->tracks
= NULL
;
114 fourxm
->selected_track
= 0;
116 /* skip the first 3 32-bit numbers */
117 url_fseek(pb
, 12, SEEK_CUR
);
119 /* check for LIST-HEAD */
121 header_size
= size
- 4;
122 if (fourcc_tag
!= HEAD_TAG
)
123 return AVERROR_INVALIDDATA
;
125 /* allocate space for the header and load the whole thing */
126 header
= av_malloc(header_size
);
128 return AVERROR_NOMEM
;
129 if (get_buffer(pb
, header
, header_size
) != header_size
)
132 /* take the lazy approach and search for any and all vtrk and strk chunks */
133 for (i
= 0; i
< header_size
- 8; i
++) {
134 fourcc_tag
= BE_32(&header
[i
]);
135 size
= LE_32(&header
[i
+ 4]);
137 if (fourcc_tag
== vtrk_TAG
) {
138 /* check that there is enough data */
139 if (size
!= vtrk_SIZE
) {
141 return AVERROR_INVALIDDATA
;
143 fourxm
->width
= LE_32(&header
[i
+ 36]);
144 fourxm
->height
= LE_32(&header
[i
+ 40]);
146 } else if (fourcc_tag
== strk_TAG
) {
147 /* check that there is enough data */
148 if (size
!= strk_SIZE
) {
150 return AVERROR_INVALIDDATA
;
152 current_track
= LE_32(&header
[i
+ 8]);
153 if (current_track
+ 1 > fourxm
->track_count
) {
154 fourxm
->track_count
++;
155 fourxm
->tracks
= av_realloc(fourxm
->tracks
, fourxm
->track_count
);
156 if (!fourxm
->tracks
) {
158 return AVERROR_NOMEM
;
161 fourxm
->tracks
[current_track
].channels
= LE_32(&header
[i
+ 36]);
162 fourxm
->tracks
[current_track
].sample_rate
= LE_32(&header
[i
+ 40]);
163 fourxm
->tracks
[current_track
].bits
= LE_32(&header
[i
+ 44]);
170 /* skip over the LIST-MOVI chunk (which is where the stream should be */
172 if (fourcc_tag
!= MOVI_TAG
)
173 return AVERROR_INVALIDDATA
;
175 if (current_track
> -1) {
176 st
= av_new_stream(s
, 0);
178 return AVERROR_NOMEM
;
180 st
->codec
.codec_type
= CODEC_TYPE_AUDIO
;
181 st
->codec
.codec_tag
= 1;
182 st
->codec
.channels
= fourxm
->tracks
[current_track
].channels
;
183 st
->codec
.sample_rate
= fourxm
->tracks
[current_track
].sample_rate
;
184 st
->codec
.bits_per_sample
= fourxm
->tracks
[current_track
].bits
;
185 st
->codec
.bit_rate
= st
->codec
.channels
* st
->codec
.sample_rate
*
186 st
->codec
.bits_per_sample
;
187 st
->codec
.block_align
= st
->codec
.channels
* st
->codec
.bits_per_sample
;
188 if (st
->codec
.bits_per_sample
== 8)
189 st
->codec
.codec_id
= CODEC_ID_PCM_U8
;
191 st
->codec
.codec_id
= CODEC_ID_PCM_S16LE
;
197 static int fourxm_read_packet(AVFormatContext
*s
,
200 FourxmDemuxContext
*fourxm
= s
->priv_data
;
201 ByteIOContext
*pb
= &s
->pb
;
202 unsigned int fourcc_tag
;
208 while (!packet_read
) {
210 fourcc_tag
= get_be32(pb
);
212 if (fourcc_tag
== LIST_TAG
) {
213 /* skip the LIST-FRAM tag and get the next fourcc */
215 fourcc_tag
= get_be32(pb
);
222 switch (fourcc_tag
) {
225 printf (" %cfrm chunk\n", (char)(fourcc_tag
>> 24) & 0xFF);
226 url_fseek(pb
, size
, SEEK_CUR
);
229 printf (" %cfrm chunk\n", (char)(fourcc_tag
>> 24) & 0xFF);
230 url_fseek(pb
, size
, SEEK_CUR
);
233 int unknown
= get_le32(pb
);
234 int id
= get_le32(pb
);
235 int whole
= get_le32(pb
);
236 static int stats
[1000];
237 stats
[id
] += size
- 12;
238 printf(" cfrm chunk id:%d size:%d whole:%d until now:%d\n", id
, size
, whole
, stats
[id
]);
239 url_fseek(pb
, size
-12, SEEK_CUR
);
243 printf (" snd_ chunk, ");
244 track_number
= get_le32(pb
);
246 if (track_number
== fourxm
->selected_track
) {
247 printf ("correct track, dispatching...\n");
248 if (av_new_packet(pkt
, size
))
250 ret
= get_buffer(&s
->pb
, pkt
->data
, size
);
255 printf ("wrong track, skipping...\n");
256 url_fseek(pb
, size
, SEEK_CUR
);
261 url_fseek(pb
, size
, SEEK_CUR
);
269 static int fourxm_read_close(AVFormatContext
*s
)
271 FourxmDemuxContext
*fourxm
= (FourxmDemuxContext
*)s
->priv_data
;
273 av_free(fourxm
->tracks
);
278 static AVInputFormat fourxm_iformat
= {
280 "4X Technologies format",
281 sizeof(FourxmDemuxContext
),
288 int fourxm_init(void)
290 av_register_input_format(&fourxm_iformat
);