2 * 4X Technologies .4xm File Demuxer (no muxer)
3 * Copyright (c) 2003 The FFmpeg Project
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 * 4X Technologies file demuxer
25 * by Mike Melanson (melanson@pcisys.net)
26 * for more information on the .4xm file format, visit:
27 * http://www.pcisys.net/~melanson/codecs/
30 #include "libavutil/intreadwrite.h"
31 #include "libavutil/intfloat.h"
35 #define RIFF_TAG MKTAG('R', 'I', 'F', 'F')
36 #define FOURXMV_TAG MKTAG('4', 'X', 'M', 'V')
37 #define LIST_TAG MKTAG('L', 'I', 'S', 'T')
38 #define HEAD_TAG MKTAG('H', 'E', 'A', 'D')
39 #define TRK__TAG MKTAG('T', 'R', 'K', '_')
40 #define MOVI_TAG MKTAG('M', 'O', 'V', 'I')
41 #define VTRK_TAG MKTAG('V', 'T', 'R', 'K')
42 #define STRK_TAG MKTAG('S', 'T', 'R', 'K')
43 #define std__TAG MKTAG('s', 't', 'd', '_')
44 #define name_TAG MKTAG('n', 'a', 'm', 'e')
45 #define vtrk_TAG MKTAG('v', 't', 'r', 'k')
46 #define strk_TAG MKTAG('s', 't', 'r', 'k')
47 #define ifrm_TAG MKTAG('i', 'f', 'r', 'm')
48 #define pfrm_TAG MKTAG('p', 'f', 'r', 'm')
49 #define cfrm_TAG MKTAG('c', 'f', 'r', 'm')
50 #define ifr2_TAG MKTAG('i', 'f', 'r', '2')
51 #define pfr2_TAG MKTAG('p', 'f', 'r', '2')
52 #define cfr2_TAG MKTAG('c', 'f', 'r', '2')
53 #define snd__TAG MKTAG('s', 'n', 'd', '_')
55 #define vtrk_SIZE 0x44
56 #define strk_SIZE 0x28
58 #define GET_LIST_HEADER() \
59 fourcc_tag = avio_rl32(pb); \
60 size = avio_rl32(pb); \
61 if (fourcc_tag != LIST_TAG) \
62 return AVERROR_INVALIDDATA; \
63 fourcc_tag = avio_rl32(pb);
65 typedef struct AudioTrack
{
74 typedef struct FourxmDemuxContext
{
75 int video_stream_index
;
83 static int fourxm_probe(AVProbeData
*p
)
85 if ((AV_RL32(&p
->buf
[0]) != RIFF_TAG
) ||
86 (AV_RL32(&p
->buf
[8]) != FOURXMV_TAG
))
89 return AVPROBE_SCORE_MAX
;
92 static int parse_vtrk(AVFormatContext
*s
,
93 FourxmDemuxContext
*fourxm
, uint8_t *buf
, int size
,
97 /* check that there is enough data */
98 if (size
!= vtrk_SIZE
|| left
< size
+ 8) {
99 return AVERROR_INVALIDDATA
;
102 /* allocate a new AVStream */
103 st
= avformat_new_stream(s
, NULL
);
105 return AVERROR(ENOMEM
);
107 avpriv_set_pts_info(st
, 60, 1, fourxm
->fps
);
109 fourxm
->video_stream_index
= st
->index
;
111 st
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
112 st
->codec
->codec_id
= AV_CODEC_ID_4XM
;
114 st
->codec
->extradata
= av_mallocz(4 + FF_INPUT_BUFFER_PADDING_SIZE
);
115 if (!st
->codec
->extradata
)
116 return AVERROR(ENOMEM
);
117 st
->codec
->extradata_size
= 4;
118 AV_WL32(st
->codec
->extradata
, AV_RL32(buf
+ 16));
119 st
->codec
->width
= AV_RL32(buf
+ 36);
120 st
->codec
->height
= AV_RL32(buf
+ 40);
126 static int parse_strk(AVFormatContext
*s
,
127 FourxmDemuxContext
*fourxm
, uint8_t *buf
, int size
,
132 /* check that there is enough data */
133 if (size
!= strk_SIZE
|| left
< size
+ 8)
134 return AVERROR_INVALIDDATA
;
136 track
= AV_RL32(buf
+ 8);
137 if ((unsigned)track
>= UINT_MAX
/ sizeof(AudioTrack
) - 1) {
138 av_log(s
, AV_LOG_ERROR
, "current_track too large\n");
139 return AVERROR_INVALIDDATA
;
142 if (track
+ 1 > fourxm
->track_count
) {
143 if (av_reallocp_array(&fourxm
->tracks
, track
+ 1, sizeof(AudioTrack
)))
144 return AVERROR(ENOMEM
);
145 memset(&fourxm
->tracks
[fourxm
->track_count
], 0,
146 sizeof(AudioTrack
) * (track
+ 1 - fourxm
->track_count
));
147 fourxm
->track_count
= track
+ 1;
149 fourxm
->tracks
[track
].adpcm
= AV_RL32(buf
+ 12);
150 fourxm
->tracks
[track
].channels
= AV_RL32(buf
+ 36);
151 fourxm
->tracks
[track
].sample_rate
= AV_RL32(buf
+ 40);
152 fourxm
->tracks
[track
].bits
= AV_RL32(buf
+ 44);
153 fourxm
->tracks
[track
].audio_pts
= 0;
155 if (fourxm
->tracks
[track
].channels
<= 0 ||
156 fourxm
->tracks
[track
].sample_rate
<= 0 ||
157 fourxm
->tracks
[track
].bits
<= 0) {
158 av_log(s
, AV_LOG_ERROR
, "audio header invalid\n");
159 return AVERROR_INVALIDDATA
;
161 if (!fourxm
->tracks
[track
].adpcm
&& fourxm
->tracks
[track
].bits
<8) {
162 av_log(s
, AV_LOG_ERROR
, "bits unspecified for non ADPCM\n");
163 return AVERROR_INVALIDDATA
;
166 /* allocate a new AVStream */
167 st
= avformat_new_stream(s
, NULL
);
169 return AVERROR(ENOMEM
);
172 avpriv_set_pts_info(st
, 60, 1, fourxm
->tracks
[track
].sample_rate
);
174 fourxm
->tracks
[track
].stream_index
= st
->index
;
176 st
->codec
->codec_type
= AVMEDIA_TYPE_AUDIO
;
177 st
->codec
->codec_tag
= 0;
178 st
->codec
->channels
= fourxm
->tracks
[track
].channels
;
179 st
->codec
->sample_rate
= fourxm
->tracks
[track
].sample_rate
;
180 st
->codec
->bits_per_coded_sample
= fourxm
->tracks
[track
].bits
;
181 st
->codec
->bit_rate
= st
->codec
->channels
*
182 st
->codec
->sample_rate
*
183 st
->codec
->bits_per_coded_sample
;
184 st
->codec
->block_align
= st
->codec
->channels
*
185 st
->codec
->bits_per_coded_sample
;
187 if (fourxm
->tracks
[track
].adpcm
){
188 st
->codec
->codec_id
= AV_CODEC_ID_ADPCM_4XM
;
189 } else if (st
->codec
->bits_per_coded_sample
== 8) {
190 st
->codec
->codec_id
= AV_CODEC_ID_PCM_U8
;
192 st
->codec
->codec_id
= AV_CODEC_ID_PCM_S16LE
;
197 static int fourxm_read_header(AVFormatContext
*s
)
199 AVIOContext
*pb
= s
->pb
;
200 unsigned int fourcc_tag
;
203 FourxmDemuxContext
*fourxm
= s
->priv_data
;
204 unsigned char *header
;
207 fourxm
->track_count
= 0;
208 fourxm
->tracks
= NULL
;
211 /* skip the first 3 32-bit numbers */
214 /* check for LIST-HEAD */
216 header_size
= size
- 4;
217 if (fourcc_tag
!= HEAD_TAG
|| header_size
< 0)
218 return AVERROR_INVALIDDATA
;
220 /* allocate space for the header and load the whole thing */
221 header
= av_malloc(header_size
);
223 return AVERROR(ENOMEM
);
224 if (avio_read(pb
, header
, header_size
) != header_size
) {
229 /* take the lazy approach and search for any and all vtrk and strk chunks */
230 for (i
= 0; i
< header_size
- 8; i
++) {
231 fourcc_tag
= AV_RL32(&header
[i
]);
232 size
= AV_RL32(&header
[i
+ 4]);
233 if (size
> header_size
- i
- 8 && (fourcc_tag
== vtrk_TAG
|| fourcc_tag
== strk_TAG
)) {
234 av_log(s
, AV_LOG_ERROR
, "chunk larger than array %d>%d\n", size
, header_size
- i
- 8);
235 return AVERROR_INVALIDDATA
;
238 if (fourcc_tag
== std__TAG
) {
239 if (header_size
- i
< 16) {
240 av_log(s
, AV_LOG_ERROR
, "std TAG truncated\n");
241 ret
= AVERROR_INVALIDDATA
;
244 fourxm
->fps
= av_int2float(AV_RL32(&header
[i
+ 12]));
245 } else if (fourcc_tag
== vtrk_TAG
) {
246 if ((ret
= parse_vtrk(s
, fourxm
, header
+ i
, size
,
247 header_size
- i
)) < 0)
251 } else if (fourcc_tag
== strk_TAG
) {
252 if ((ret
= parse_strk(s
, fourxm
, header
+ i
, size
,
253 header_size
- i
)) < 0)
260 /* skip over the LIST-MOVI chunk (which is where the stream should be */
262 if (fourcc_tag
!= MOVI_TAG
) {
263 ret
= AVERROR_INVALIDDATA
;
268 /* initialize context members */
269 fourxm
->video_pts
= -1; /* first frame will push to 0 */
273 av_freep(&fourxm
->tracks
);
278 static int fourxm_read_packet(AVFormatContext
*s
,
281 FourxmDemuxContext
*fourxm
= s
->priv_data
;
282 AVIOContext
*pb
= s
->pb
;
283 unsigned int fourcc_tag
;
286 unsigned int track_number
;
288 unsigned char header
[8];
289 int audio_frame_count
;
291 while (!packet_read
) {
292 if ((ret
= avio_read(s
->pb
, header
, 8)) < 0)
294 fourcc_tag
= AV_RL32(&header
[0]);
295 size
= AV_RL32(&header
[4]);
298 switch (fourcc_tag
) {
300 /* this is a good time to bump the video pts */
303 /* skip the LIST-* tag and move on to the next fourcc */
313 /* allocate 8 more bytes than 'size' to account for fourcc
315 if (size
+ 8 < size
|| av_new_packet(pkt
, size
+ 8))
317 pkt
->stream_index
= fourxm
->video_stream_index
;
318 pkt
->pts
= fourxm
->video_pts
;
319 pkt
->pos
= avio_tell(s
->pb
);
320 memcpy(pkt
->data
, header
, 8);
321 ret
= avio_read(s
->pb
, &pkt
->data
[8], size
);
327 av_shrink_packet(pkt
, ret
+ 8);
332 track_number
= avio_rl32(pb
);
336 if (track_number
< fourxm
->track_count
&&
337 fourxm
->tracks
[track_number
].channels
> 0) {
338 ret
= av_get_packet(s
->pb
, pkt
, size
);
342 fourxm
->tracks
[track_number
].stream_index
;
343 pkt
->pts
= fourxm
->tracks
[track_number
].audio_pts
;
347 audio_frame_count
= size
;
348 if (fourxm
->tracks
[track_number
].adpcm
)
349 audio_frame_count
-= 2 * (fourxm
->tracks
[track_number
].channels
);
350 audio_frame_count
/= fourxm
->tracks
[track_number
].channels
;
351 if (fourxm
->tracks
[track_number
].adpcm
) {
352 audio_frame_count
*= 2;
355 (fourxm
->tracks
[track_number
].bits
/ 8);
356 fourxm
->tracks
[track_number
].audio_pts
+= audio_frame_count
;
370 static int fourxm_read_close(AVFormatContext
*s
)
372 FourxmDemuxContext
*fourxm
= s
->priv_data
;
374 av_freep(&fourxm
->tracks
);
379 AVInputFormat ff_fourxm_demuxer
= {
381 .long_name
= NULL_IF_CONFIG_SMALL("4X Technologies"),
382 .priv_data_size
= sizeof(FourxmDemuxContext
),
383 .read_probe
= fourxm_probe
,
384 .read_header
= fourxm_read_header
,
385 .read_packet
= fourxm_read_packet
,
386 .read_close
= fourxm_read_close
,