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"
32 #include "libavcodec/internal.h"
36 #define RIFF_TAG MKTAG('R', 'I', 'F', 'F')
37 #define FOURXMV_TAG MKTAG('4', 'X', 'M', 'V')
38 #define LIST_TAG MKTAG('L', 'I', 'S', 'T')
39 #define HEAD_TAG MKTAG('H', 'E', 'A', 'D')
40 #define TRK__TAG MKTAG('T', 'R', 'K', '_')
41 #define MOVI_TAG MKTAG('M', 'O', 'V', 'I')
42 #define VTRK_TAG MKTAG('V', 'T', 'R', 'K')
43 #define STRK_TAG MKTAG('S', 'T', 'R', 'K')
44 #define std__TAG MKTAG('s', 't', 'd', '_')
45 #define name_TAG MKTAG('n', 'a', 'm', 'e')
46 #define vtrk_TAG MKTAG('v', 't', 'r', 'k')
47 #define strk_TAG MKTAG('s', 't', 'r', 'k')
48 #define ifrm_TAG MKTAG('i', 'f', 'r', 'm')
49 #define pfrm_TAG MKTAG('p', 'f', 'r', 'm')
50 #define cfrm_TAG MKTAG('c', 'f', 'r', 'm')
51 #define ifr2_TAG MKTAG('i', 'f', 'r', '2')
52 #define pfr2_TAG MKTAG('p', 'f', 'r', '2')
53 #define cfr2_TAG MKTAG('c', 'f', 'r', '2')
54 #define snd__TAG MKTAG('s', 'n', 'd', '_')
56 #define vtrk_SIZE 0x44
57 #define strk_SIZE 0x28
59 #define GET_LIST_HEADER() \
60 fourcc_tag = avio_rl32(pb); \
61 size = avio_rl32(pb); \
62 if (fourcc_tag != LIST_TAG) { \
63 ret = AVERROR_INVALIDDATA; \
66 fourcc_tag = avio_rl32(pb);
68 typedef struct AudioTrack
{
77 typedef struct FourxmDemuxContext
{
78 int video_stream_index
;
86 static int fourxm_probe(const AVProbeData
*p
)
88 if ((AV_RL32(&p
->buf
[0]) != RIFF_TAG
) ||
89 (AV_RL32(&p
->buf
[8]) != FOURXMV_TAG
))
92 return AVPROBE_SCORE_MAX
;
95 static int parse_vtrk(AVFormatContext
*s
,
96 FourxmDemuxContext
*fourxm
, uint8_t *buf
, int size
,
100 /* check that there is enough data */
101 if (size
!= vtrk_SIZE
|| left
< size
+ 8) {
102 return AVERROR_INVALIDDATA
;
105 /* allocate a new AVStream */
106 st
= avformat_new_stream(s
, NULL
);
108 return AVERROR(ENOMEM
);
110 avpriv_set_pts_info(st
, 60, fourxm
->fps
.den
, fourxm
->fps
.num
);
112 fourxm
->video_stream_index
= st
->index
;
114 st
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
115 st
->codecpar
->codec_id
= AV_CODEC_ID_4XM
;
117 st
->codecpar
->extradata
= av_mallocz(4 + AV_INPUT_BUFFER_PADDING_SIZE
);
118 if (!st
->codecpar
->extradata
)
119 return AVERROR(ENOMEM
);
120 st
->codecpar
->extradata_size
= 4;
121 AV_WL32(st
->codecpar
->extradata
, AV_RL32(buf
+ 16));
122 st
->codecpar
->width
= AV_RL32(buf
+ 36);
123 st
->codecpar
->height
= AV_RL32(buf
+ 40);
129 static int parse_strk(AVFormatContext
*s
,
130 FourxmDemuxContext
*fourxm
, uint8_t *buf
, int size
,
135 /* check that there is enough data */
136 if (size
!= strk_SIZE
|| left
< size
+ 8)
137 return AVERROR_INVALIDDATA
;
139 track
= AV_RL32(buf
+ 8);
140 if ((unsigned)track
>= UINT_MAX
/ sizeof(AudioTrack
) - 1 ||
141 track
>= s
->max_streams
) {
142 av_log(s
, AV_LOG_ERROR
, "current_track too large\n");
143 return AVERROR_INVALIDDATA
;
146 if (track
+ 1 > fourxm
->track_count
) {
147 if (av_reallocp_array(&fourxm
->tracks
, track
+ 1, sizeof(AudioTrack
)))
148 return AVERROR(ENOMEM
);
149 memset(&fourxm
->tracks
[fourxm
->track_count
], 0,
150 sizeof(AudioTrack
) * (track
+ 1 - fourxm
->track_count
));
151 fourxm
->track_count
= track
+ 1;
153 if (fourxm
->tracks
[track
].bits
)
154 return AVERROR_INVALIDDATA
;
156 fourxm
->tracks
[track
].adpcm
= AV_RL32(buf
+ 12);
157 fourxm
->tracks
[track
].channels
= AV_RL32(buf
+ 36);
158 fourxm
->tracks
[track
].sample_rate
= AV_RL32(buf
+ 40);
159 fourxm
->tracks
[track
].bits
= AV_RL32(buf
+ 44);
160 fourxm
->tracks
[track
].audio_pts
= 0;
162 if (fourxm
->tracks
[track
].channels
<= 0 ||
163 fourxm
->tracks
[track
].channels
> FF_SANE_NB_CHANNELS
||
164 fourxm
->tracks
[track
].sample_rate
<= 0 ||
165 fourxm
->tracks
[track
].bits
<= 0 ||
166 fourxm
->tracks
[track
].bits
> INT_MAX
/ FF_SANE_NB_CHANNELS
) {
167 av_log(s
, AV_LOG_ERROR
, "audio header invalid\n");
168 return AVERROR_INVALIDDATA
;
170 if (!fourxm
->tracks
[track
].adpcm
&& fourxm
->tracks
[track
].bits
<8) {
171 av_log(s
, AV_LOG_ERROR
, "bits unspecified for non ADPCM\n");
172 return AVERROR_INVALIDDATA
;
175 if (fourxm
->tracks
[track
].sample_rate
> INT64_MAX
/ fourxm
->tracks
[track
].bits
/ fourxm
->tracks
[track
].channels
) {
176 av_log(s
, AV_LOG_ERROR
, "Overflow during bit rate calculation %d * %d * %d\n",
177 fourxm
->tracks
[track
].sample_rate
, fourxm
->tracks
[track
].bits
, fourxm
->tracks
[track
].channels
);
178 return AVERROR_INVALIDDATA
;
181 /* allocate a new AVStream */
182 st
= avformat_new_stream(s
, NULL
);
184 return AVERROR(ENOMEM
);
187 avpriv_set_pts_info(st
, 60, 1, fourxm
->tracks
[track
].sample_rate
);
189 fourxm
->tracks
[track
].stream_index
= st
->index
;
191 st
->codecpar
->codec_type
= AVMEDIA_TYPE_AUDIO
;
192 st
->codecpar
->codec_tag
= 0;
193 st
->codecpar
->channels
= fourxm
->tracks
[track
].channels
;
194 st
->codecpar
->sample_rate
= fourxm
->tracks
[track
].sample_rate
;
195 st
->codecpar
->bits_per_coded_sample
= fourxm
->tracks
[track
].bits
;
196 st
->codecpar
->bit_rate
= (int64_t)st
->codecpar
->channels
*
197 st
->codecpar
->sample_rate
*
198 st
->codecpar
->bits_per_coded_sample
;
199 st
->codecpar
->block_align
= st
->codecpar
->channels
*
200 st
->codecpar
->bits_per_coded_sample
;
202 if (fourxm
->tracks
[track
].adpcm
){
203 st
->codecpar
->codec_id
= AV_CODEC_ID_ADPCM_4XM
;
204 } else if (st
->codecpar
->bits_per_coded_sample
== 8) {
205 st
->codecpar
->codec_id
= AV_CODEC_ID_PCM_U8
;
207 st
->codecpar
->codec_id
= AV_CODEC_ID_PCM_S16LE
;
212 static int fourxm_read_header(AVFormatContext
*s
)
214 AVIOContext
*pb
= s
->pb
;
215 unsigned int fourcc_tag
;
218 FourxmDemuxContext
*fourxm
= s
->priv_data
;
219 unsigned char *header
= NULL
;
222 fourxm
->track_count
= 0;
223 fourxm
->tracks
= NULL
;
224 fourxm
->fps
= (AVRational
){1,1};
225 fourxm
->video_stream_index
= -1;
227 /* skip the first 3 32-bit numbers */
230 /* check for LIST-HEAD */
232 header_size
= size
- 4;
233 if (fourcc_tag
!= HEAD_TAG
|| header_size
< 0)
234 return AVERROR_INVALIDDATA
;
236 /* allocate space for the header and load the whole thing */
237 header
= av_malloc(header_size
);
239 return AVERROR(ENOMEM
);
240 if (avio_read(pb
, header
, header_size
) != header_size
) {
245 /* take the lazy approach and search for any and all vtrk and strk chunks */
246 for (i
= 0; i
< header_size
- 8; i
++) {
247 fourcc_tag
= AV_RL32(&header
[i
]);
248 size
= AV_RL32(&header
[i
+ 4]);
249 if (size
> header_size
- i
- 8 && (fourcc_tag
== vtrk_TAG
|| fourcc_tag
== strk_TAG
)) {
250 av_log(s
, AV_LOG_ERROR
, "chunk larger than array %d>%d\n", size
, header_size
- i
- 8);
251 ret
= AVERROR_INVALIDDATA
;
255 if (fourcc_tag
== std__TAG
) {
256 if (header_size
- i
< 16) {
257 av_log(s
, AV_LOG_ERROR
, "std TAG truncated\n");
258 ret
= AVERROR_INVALIDDATA
;
261 fourxm
->fps
= av_d2q(av_int2float(AV_RL32(&header
[i
+ 12])), 10000);
262 } else if (fourcc_tag
== vtrk_TAG
) {
263 if ((ret
= parse_vtrk(s
, fourxm
, header
+ i
, size
,
264 header_size
- i
)) < 0)
268 } else if (fourcc_tag
== strk_TAG
) {
269 if ((ret
= parse_strk(s
, fourxm
, header
+ i
, size
,
270 header_size
- i
)) < 0)
277 /* skip over the LIST-MOVI chunk (which is where the stream should be */
279 if (fourcc_tag
!= MOVI_TAG
) {
280 ret
= AVERROR_INVALIDDATA
;
285 /* initialize context members */
286 fourxm
->video_pts
= -1; /* first frame will push to 0 */
290 av_freep(&fourxm
->tracks
);
295 static int fourxm_read_packet(AVFormatContext
*s
,
298 FourxmDemuxContext
*fourxm
= s
->priv_data
;
299 AVIOContext
*pb
= s
->pb
;
300 unsigned int fourcc_tag
;
303 unsigned int track_number
;
305 unsigned char header
[8];
306 int64_t audio_frame_count
;
308 while (!packet_read
) {
309 if ((ret
= avio_read(s
->pb
, header
, 8)) < 0)
311 fourcc_tag
= AV_RL32(&header
[0]);
312 size
= AV_RL32(&header
[4]);
315 switch (fourcc_tag
) {
317 /* this is a good time to bump the video pts */
320 /* skip the LIST-* tag and move on to the next fourcc */
330 /* allocate 8 more bytes than 'size' to account for fourcc
332 if (size
> INT_MAX
- AV_INPUT_BUFFER_PADDING_SIZE
- 8)
333 return AVERROR_INVALIDDATA
;
334 if (fourxm
->video_stream_index
< 0)
335 return AVERROR_INVALIDDATA
;
336 if ((ret
= av_new_packet(pkt
, size
+ 8)) < 0)
338 pkt
->stream_index
= fourxm
->video_stream_index
;
339 pkt
->pts
= fourxm
->video_pts
;
340 pkt
->pos
= avio_tell(s
->pb
);
341 memcpy(pkt
->data
, header
, 8);
342 ret
= avio_read(s
->pb
, &pkt
->data
[8], size
);
345 av_packet_unref(pkt
);
348 av_shrink_packet(pkt
, ret
+ 8);
353 track_number
= avio_rl32(pb
);
357 if (track_number
< fourxm
->track_count
&&
358 fourxm
->tracks
[track_number
].channels
> 0) {
359 ret
= av_get_packet(s
->pb
, pkt
, size
);
363 fourxm
->tracks
[track_number
].stream_index
;
364 pkt
->pts
= fourxm
->tracks
[track_number
].audio_pts
;
368 audio_frame_count
= size
;
369 if (fourxm
->tracks
[track_number
].adpcm
)
370 audio_frame_count
-= 2 * (fourxm
->tracks
[track_number
].channels
);
371 audio_frame_count
/= fourxm
->tracks
[track_number
].channels
;
372 if (fourxm
->tracks
[track_number
].adpcm
) {
373 audio_frame_count
*= 2;
376 (fourxm
->tracks
[track_number
].bits
/ 8);
377 fourxm
->tracks
[track_number
].audio_pts
+= audio_frame_count
;
391 static int fourxm_read_close(AVFormatContext
*s
)
393 FourxmDemuxContext
*fourxm
= s
->priv_data
;
395 av_freep(&fourxm
->tracks
);
400 AVInputFormat ff_fourxm_demuxer
= {
402 .long_name
= NULL_IF_CONFIG_SMALL("4X Technologies"),
403 .priv_data_size
= sizeof(FourxmDemuxContext
),
404 .read_probe
= fourxm_probe
,
405 .read_header
= fourxm_read_header
,
406 .read_packet
= fourxm_read_packet
,
407 .read_close
= fourxm_read_close
,