~ubuntu-branches/debian/wheezy/vlc/wheezy

« back to all changes in this revision

Viewing changes to extras/ffmpeg/libavformat/sierravmd.c

Tags: upstream-0.7.2.final
ImportĀ upstreamĀ versionĀ 0.7.2.final

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Sierra VMD Format Demuxer
 
3
 * Copyright (c) 2004 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 sierravmd.c
 
22
 * Sierra VMD file demuxer
 
23
 * by Vladimir "VAG" Gneushev (vagsoft at mail.ru)
 
24
 * for more information on the Sierra VMD file format, visit:
 
25
 *   http://www.pcisys.net/~melanson/codecs/
 
26
 */
 
27
 
 
28
#include "avformat.h"
 
29
 
 
30
#define VMD_HEADER_SIZE 0x0330
 
31
#define BYTES_PER_FRAME_RECORD 16
 
32
 
 
33
typedef struct {
 
34
  int stream_index;
 
35
  offset_t frame_offset;
 
36
  unsigned int frame_size;
 
37
  int64_t pts;
 
38
  int keyframe;
 
39
  unsigned char frame_record[BYTES_PER_FRAME_RECORD];
 
40
} vmd_frame_t;
 
41
 
 
42
typedef struct VmdDemuxContext {
 
43
    int video_stream_index;
 
44
    int audio_stream_index;
 
45
 
 
46
    unsigned int audio_type;
 
47
    unsigned int audio_samplerate;
 
48
    unsigned int audio_bits;
 
49
    unsigned int audio_channels;
 
50
 
 
51
    unsigned int frame_count;
 
52
    vmd_frame_t *frame_table;
 
53
    unsigned int current_frame;
 
54
 
 
55
    int sample_rate;
 
56
    int64_t audio_sample_counter;
 
57
    int audio_frame_divisor;
 
58
    int audio_block_align;
 
59
 
 
60
    unsigned char vmd_header[VMD_HEADER_SIZE];
 
61
} VmdDemuxContext;
 
62
 
 
63
static int vmd_probe(AVProbeData *p)
 
64
{
 
65
    if (p->buf_size < 2)
 
66
        return 0;
 
67
 
 
68
    /* check if the first 2 bytes of the file contain the appropriate size
 
69
     * of a VMD header chunk */
 
70
    if (LE_16(&p->buf[0]) != VMD_HEADER_SIZE - 2)
 
71
        return 0;
 
72
 
 
73
    /* only return half certainty since this check is a bit sketchy */
 
74
    return AVPROBE_SCORE_MAX / 2;
 
75
}
 
76
 
 
77
/* This is a support function to determine the duration, in sample
 
78
 * frames, of a particular audio chunk, taking into account silent
 
79
 * encodings. */
 
80
static int vmd_calculate_audio_duration(unsigned char *audio_chunk,
 
81
    int audio_chunk_size, int block_align)
 
82
{
 
83
    unsigned char *p = audio_chunk + 16;
 
84
    unsigned char *p_end = audio_chunk + audio_chunk_size;
 
85
    int total_samples = 0;
 
86
    unsigned int sound_flags;
 
87
 
 
88
    if (audio_chunk_size < 16)
 
89
        return 0;
 
90
 
 
91
    sound_flags = LE_32(p);
 
92
    p += 4;
 
93
    while (p < p_end) {
 
94
        total_samples += block_align;
 
95
        if ((sound_flags & 0x01) == 0)
 
96
            p += block_align;
 
97
        sound_flags >>= 1;
 
98
    }
 
99
 
 
100
    return total_samples;
 
101
}
 
102
 
 
103
static int vmd_read_header(AVFormatContext *s,
 
104
                           AVFormatParameters *ap)
 
105
{
 
106
    VmdDemuxContext *vmd = (VmdDemuxContext *)s->priv_data;
 
107
    ByteIOContext *pb = &s->pb;
 
108
    AVStream *st;
 
109
    unsigned int toc_offset;
 
110
    unsigned char *raw_frame_table;
 
111
    int raw_frame_table_size;
 
112
    unsigned char *current_frame_record;
 
113
    offset_t current_offset;
 
114
    int i;
 
115
    unsigned int total_frames;
 
116
    int64_t video_pts_inc;
 
117
    int64_t current_video_pts = 0;
 
118
 
 
119
    /* fetch the main header, including the 2 header length bytes */
 
120
    url_fseek(pb, 0, SEEK_SET);
 
121
    if (get_buffer(pb, vmd->vmd_header, VMD_HEADER_SIZE) != VMD_HEADER_SIZE)
 
122
        return -EIO;
 
123
 
 
124
    vmd->audio_sample_counter = 0;
 
125
    vmd->audio_frame_divisor = 1;
 
126
    vmd->audio_block_align = 1;
 
127
 
 
128
    /* start up the decoders */
 
129
    st = av_new_stream(s, 0);
 
130
    if (!st)
 
131
        return AVERROR_NOMEM;
 
132
    vmd->video_stream_index = st->index;
 
133
    st->codec.codec_type = CODEC_TYPE_VIDEO;
 
134
    st->codec.codec_id = CODEC_ID_VMDVIDEO;
 
135
    st->codec.codec_tag = 0;  /* no fourcc */
 
136
    st->codec.width = LE_16(&vmd->vmd_header[12]);
 
137
    st->codec.height = LE_16(&vmd->vmd_header[14]);
 
138
    st->codec.extradata_size = VMD_HEADER_SIZE;
 
139
    st->codec.extradata = av_malloc(VMD_HEADER_SIZE);
 
140
    memcpy(st->codec.extradata, vmd->vmd_header, VMD_HEADER_SIZE);
 
141
 
 
142
    /* if sample rate is 0, assume no audio */
 
143
    vmd->sample_rate = LE_16(&vmd->vmd_header[804]);
 
144
    if (vmd->sample_rate) {
 
145
        st = av_new_stream(s, 0);
 
146
        if (!st)
 
147
            return AVERROR_NOMEM;
 
148
        vmd->audio_stream_index = st->index;
 
149
        st->codec.codec_type = CODEC_TYPE_AUDIO;
 
150
        st->codec.codec_id = CODEC_ID_VMDAUDIO;
 
151
        st->codec.codec_tag = 0;  /* no codec tag */
 
152
        st->codec.channels = (vmd->vmd_header[811] & 0x80) ? 2 : 1;
 
153
        st->codec.sample_rate = vmd->sample_rate;
 
154
        st->codec.block_align = vmd->audio_block_align = 
 
155
            LE_16(&vmd->vmd_header[806]);
 
156
        if (st->codec.block_align & 0x8000) {
 
157
            st->codec.bits_per_sample = 16;
 
158
            st->codec.block_align = -(st->codec.block_align - 0x10000);
 
159
        } else
 
160
            st->codec.bits_per_sample = 16;
 
161
//            st->codec.bits_per_sample = 8;
 
162
        st->codec.bit_rate = st->codec.sample_rate * 
 
163
            st->codec.bits_per_sample * st->codec.channels;
 
164
 
 
165
        /* for calculating pts */
 
166
        vmd->audio_frame_divisor = st->codec.bits_per_sample / 8 / 
 
167
            st->codec.channels;
 
168
 
 
169
        video_pts_inc = 90000;
 
170
        video_pts_inc *= st->codec.block_align;
 
171
        video_pts_inc /= st->codec.sample_rate;
 
172
    } else {
 
173
        /* if no audio, assume 10 frames/second */
 
174
        video_pts_inc = 90000 / 10;
 
175
    }
 
176
 
 
177
    /* skip over the offset table and load the table of contents; don't 
 
178
     * care about the offset table since demuxer will calculate those 
 
179
     * independently */
 
180
    toc_offset = LE_32(&vmd->vmd_header[812]);
 
181
    vmd->frame_count = LE_16(&vmd->vmd_header[6]);
 
182
    url_fseek(pb, toc_offset + vmd->frame_count * 6, SEEK_SET);
 
183
 
 
184
    /* each on-disk VMD frame has an audio part and a video part; demuxer
 
185
     * accounts them separately */
 
186
    vmd->frame_count *= 2;
 
187
    raw_frame_table = NULL;
 
188
    vmd->frame_table = NULL;
 
189
    raw_frame_table_size = vmd->frame_count * BYTES_PER_FRAME_RECORD;
 
190
    raw_frame_table = av_malloc(raw_frame_table_size);
 
191
    vmd->frame_table = av_malloc(vmd->frame_count * sizeof(vmd_frame_t));
 
192
    if (!raw_frame_table || !vmd->frame_table) {
 
193
        av_free(raw_frame_table);
 
194
        av_free(vmd->frame_table);
 
195
        return AVERROR_NOMEM;
 
196
    }
 
197
    if (get_buffer(pb, raw_frame_table, raw_frame_table_size) != 
 
198
        raw_frame_table_size) {
 
199
        av_free(raw_frame_table);
 
200
        av_free(vmd->frame_table);
 
201
        return -EIO;
 
202
    }
 
203
 
 
204
    current_offset = LE_32(&vmd->vmd_header[20]);
 
205
    current_frame_record = raw_frame_table;
 
206
    total_frames = vmd->frame_count;
 
207
    i = 0;
 
208
    while (total_frames--) {
 
209
 
 
210
        /* if the frame size is 0, do not count the frame and bring the
 
211
         * total frame count down */
 
212
        vmd->frame_table[i].frame_size = LE_32(&current_frame_record[2]);
 
213
 
 
214
        /* this logic is present so that 0-length audio chunks are not
 
215
         * accounted */
 
216
        if (!vmd->frame_table[i].frame_size) {
 
217
            vmd->frame_count--;  /* one less frame to count */
 
218
            current_frame_record += BYTES_PER_FRAME_RECORD;
 
219
            continue;
 
220
        }
 
221
 
 
222
        if (current_frame_record[0] == 0x02)
 
223
            vmd->frame_table[i].stream_index = vmd->video_stream_index;
 
224
        else
 
225
            vmd->frame_table[i].stream_index = vmd->audio_stream_index;
 
226
        vmd->frame_table[i].frame_offset = current_offset;
 
227
        current_offset += vmd->frame_table[i].frame_size;
 
228
        memcpy(vmd->frame_table[i].frame_record, current_frame_record,
 
229
            BYTES_PER_FRAME_RECORD);
 
230
 
 
231
        /* figure out the pts for this frame */
 
232
        if (current_frame_record[0] == 0x02) {
 
233
            vmd->frame_table[i].pts = current_video_pts;
 
234
            current_video_pts += video_pts_inc;
 
235
        } else if (current_frame_record[0] == 0x01) {
 
236
            /* figure out the pts during the dispatch phase */
 
237
            vmd->frame_table[i].pts = 0;
 
238
        }
 
239
 
 
240
        current_frame_record += BYTES_PER_FRAME_RECORD;
 
241
        i++;
 
242
    }
 
243
 
 
244
    av_free(raw_frame_table);
 
245
 
 
246
    /* set the pts reference at 1 pts = 1/90000 sec */
 
247
    s->pts_num = 1;
 
248
    s->pts_den = 90000;
 
249
 
 
250
    vmd->current_frame = 0;
 
251
 
 
252
    return 0;
 
253
}
 
254
 
 
255
static int vmd_read_packet(AVFormatContext *s,
 
256
                           AVPacket *pkt)
 
257
{
 
258
    VmdDemuxContext *vmd = (VmdDemuxContext *)s->priv_data;
 
259
    ByteIOContext *pb = &s->pb;
 
260
    int ret = 0;
 
261
    vmd_frame_t *frame;
 
262
 
 
263
    if (vmd->current_frame >= vmd->frame_count)
 
264
        return -EIO;
 
265
 
 
266
    frame = &vmd->frame_table[vmd->current_frame];
 
267
    /* position the stream (will probably be there already) */
 
268
    url_fseek(pb, frame->frame_offset, SEEK_SET);
 
269
 
 
270
    if (av_new_packet(pkt, frame->frame_size + BYTES_PER_FRAME_RECORD))
 
271
        return AVERROR_NOMEM;
 
272
    memcpy(pkt->data, frame->frame_record, BYTES_PER_FRAME_RECORD);
 
273
    ret = get_buffer(pb, pkt->data + BYTES_PER_FRAME_RECORD, 
 
274
        frame->frame_size);
 
275
 
 
276
    if (ret != frame->frame_size) {
 
277
        av_free_packet(pkt);
 
278
        ret = -EIO;
 
279
    }
 
280
    pkt->stream_index = frame->stream_index;
 
281
    if (frame->frame_record[0] == 0x02)
 
282
        pkt->pts = frame->pts;
 
283
    else {
 
284
        pkt->pts = vmd->audio_sample_counter;
 
285
        pkt->pts *= 90000;
 
286
        pkt->pts /= vmd->sample_rate;
 
287
//        pkt->pts /= vmd->audio_frame_divisor;
 
288
        vmd->audio_sample_counter += vmd_calculate_audio_duration(
 
289
            pkt->data, pkt->size, vmd->audio_block_align);
 
290
 
 
291
    }
 
292
printf (" dispatching %s frame with %d bytes and pts %lld (%0.1f sec)\n",
 
293
  (frame->frame_record[0] == 0x02) ? "video" : "audio",
 
294
  frame->frame_size + BYTES_PER_FRAME_RECORD,
 
295
  pkt->pts, (float)(pkt->pts / 90000.0));
 
296
 
 
297
    vmd->current_frame++;
 
298
 
 
299
    return ret;
 
300
}
 
301
 
 
302
static int vmd_read_close(AVFormatContext *s)
 
303
{
 
304
    VmdDemuxContext *vmd = (VmdDemuxContext *)s->priv_data;
 
305
 
 
306
    av_free(vmd->frame_table);
 
307
 
 
308
    return 0;
 
309
}
 
310
 
 
311
static AVInputFormat vmd_iformat = {
 
312
    "vmd",
 
313
    "Sierra VMD format",
 
314
    sizeof(VmdDemuxContext),
 
315
    vmd_probe,
 
316
    vmd_read_header,
 
317
    vmd_read_packet,
 
318
    vmd_read_close,
 
319
};
 
320
 
 
321
int vmd_init(void)
 
322
{
 
323
    av_register_input_format(&vmd_iformat);
 
324
    return 0;
 
325
}