Statistics
| Branch: | Revision:

ffmpeg / libavformat / 4xm.c @ cef4ba9e

History | View | Annotate | Download (8.45 KB)

1
/*
2
 * 4X Technologies .4xm File Demuxer (no muxer)
3
 * Copyright (c) 2003  The ffmpeg Project
4
 *
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.
9
 *
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.
14
 *
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
18
 */
19

    
20
/**
21
 * @file 4xm.c
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/
26
 */
27

    
28
#include "avformat.h"
29

    
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) | \
34
                    ((uint8_t*)(x))[0])
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) | \
39
                    ((uint8_t*)(x))[3])
40

    
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 ) )
46

    
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('', '', '', '')
63

    
64
#define vtrk_SIZE 0x44
65
#define strk_SIZE 0x28
66

    
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);
73

    
74
typedef struct AudioTrack {
75
    int sample_rate;
76
    int bits;
77
    int channels;
78
} AudioTrack;
79

    
80
typedef struct FourxmDemuxContext {
81
    int width;
82
    int height;
83
    int track_count;
84
    AudioTrack *tracks;
85
    int selected_track;
86
} FourxmDemuxContext;
87

    
88
static int fourxm_probe(AVProbeData *p)
89
{
90
    if ((BE_32(&p->buf[0]) != RIFF_TAG) ||
91
        (BE_32(&p->buf[8]) != _4XMV_TAG))
92
        return 0;
93

    
94
printf ("  detected .4xm file\n");
95

    
96
    return AVPROBE_SCORE_MAX;
97
}
98

    
99
static int fourxm_read_header(AVFormatContext *s,
100
                             AVFormatParameters *ap)
101
{
102
    ByteIOContext *pb = &s->pb;
103
    unsigned int fourcc_tag;
104
    unsigned int size;
105
    int header_size;
106
    FourxmDemuxContext *fourxm = (FourxmDemuxContext *)s->priv_data;
107
    unsigned char *header;
108
    int i;
109
    int current_track = -1;
110
    AVStream *st;
111

    
112
    fourxm->track_count = 0;
113
    fourxm->tracks = NULL;
114
    fourxm->selected_track = 0;
115

    
116
    /* skip the first 3 32-bit numbers */
117
    url_fseek(pb, 12, SEEK_CUR);
118

    
119
    /* check for LIST-HEAD */
120
    GET_LIST_HEADER();
121
    header_size = size - 4;
122
    if (fourcc_tag != HEAD_TAG)
123
        return AVERROR_INVALIDDATA;
124

    
125
    /* allocate space for the header and load the whole thing */
126
    header = av_malloc(header_size);
127
    if (!header)
128
        return AVERROR_NOMEM;
129
    if (get_buffer(pb, header, header_size) != header_size)
130
        return AVERROR_IO;
131

    
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]);
136

    
137
        if (fourcc_tag == vtrk_TAG) {
138
            /* check that there is enough data */
139
            if (size != vtrk_SIZE) {
140
                av_free(header);
141
                return AVERROR_INVALIDDATA;
142
            }
143
            fourxm->width = LE_32(&header[i + 36]);
144
            fourxm->height = LE_32(&header[i + 40]);
145
            i += 8 + size;
146
        } else if (fourcc_tag == strk_TAG) {
147
            /* check that there is enough data */
148
            if (size != strk_SIZE) {
149
                av_free(header);
150
                return AVERROR_INVALIDDATA;
151
            }
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) {
157
                    av_free(header);
158
                    return AVERROR_NOMEM;
159
                }
160
            }
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]);
164
            i += 8 + size;
165
        }
166
    }
167

    
168
    av_free(header);
169

    
170
    /* skip over the LIST-MOVI chunk (which is where the stream should be */
171
    GET_LIST_HEADER();
172
    if (fourcc_tag != MOVI_TAG)
173
        return AVERROR_INVALIDDATA;
174

    
175
    if (current_track > -1) {
176
        st = av_new_stream(s, 0);
177
        if (!st)
178
            return AVERROR_NOMEM;
179

    
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;
190
        else
191
            st->codec.codec_id = CODEC_ID_PCM_S16LE;
192
    }
193

    
194
    return 0;
195
}
196

    
197
static int fourxm_read_packet(AVFormatContext *s,
198
                             AVPacket *pkt)
199
{
200
    FourxmDemuxContext *fourxm = s->priv_data;
201
    ByteIOContext *pb = &s->pb;
202
    unsigned int fourcc_tag;
203
    unsigned int size;
204
    int ret = 0;
205
    int track_number;
206
    int packet_read = 0;
207

    
208
    while (!packet_read) {
209

    
210
        fourcc_tag = get_be32(pb);
211
        size = get_le32(pb);
212
        if (fourcc_tag == LIST_TAG) {
213
            /* skip the LIST-FRAM tag and get the next fourcc */
214
            get_be32(pb);
215
            fourcc_tag = get_be32(pb);
216
            size = get_le32(pb);
217
        }
218

    
219
        if (url_feof(pb))
220
            return -EIO;
221

    
222
        switch (fourcc_tag) {
223

    
224
        case ifrm_TAG:
225
        case pfrm_TAG:
226
        case cfrm_TAG:
227
printf (" %cfrm chunk\n", (char)(fourcc_tag >> 24) & 0xFF);
228
url_fseek(pb, size, SEEK_CUR);
229
            break;
230

    
231
        case snd__TAG:
232
printf (" snd_ chunk, ");
233
            track_number = get_le32(pb);
234
            size = get_le32(pb);
235
            if (track_number == fourxm->selected_track) {
236
printf ("correct track, dispatching...\n");
237
                if (av_new_packet(pkt, size))
238
                    return -EIO;
239
                ret = get_buffer(&s->pb, pkt->data, size);
240
                if (ret < 0)
241
                    av_free_packet(pkt);
242
                packet_read = 1;
243
            } else {
244
printf ("wrong track, skipping...\n");
245
                url_fseek(pb, size, SEEK_CUR);
246
            }
247
            break;
248

    
249
        default:
250
            url_fseek(pb, size, SEEK_CUR);
251
            break;
252
        }
253
    }
254

    
255
    return ret;
256
}
257

    
258
static int fourxm_read_close(AVFormatContext *s)
259
{
260
    FourxmDemuxContext *fourxm = (FourxmDemuxContext *)s->priv_data;
261

    
262
    av_free(fourxm->tracks);
263

    
264
    return 0;
265
}
266

    
267
static AVInputFormat fourxm_iformat = {
268
    "4xm",
269
    "4X Technologies format",
270
    sizeof(FourxmDemuxContext),
271
    fourxm_probe,
272
    fourxm_read_header,
273
    fourxm_read_packet,
274
    fourxm_read_close,
275
};
276

    
277
int fourxm_init(void)
278
{
279
    av_register_input_format(&fourxm_iformat);
280
    return 0;
281
}