Revision 23fe14bb libavformat/sierravmd.c

View differences:

libavformat/sierravmd.c
21 21
 * @file sierravmd.c
22 22
 * Sierra VMD file demuxer
23 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/
24 26
 */
25 27

  
26 28
#include "avformat.h"
27 29

  
28
#define LE_16(x)  ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0])
29
#define LE_32(x)  ((((uint8_t*)(x))[3] << 24) | \
30
                   (((uint8_t*)(x))[2] << 16) | \
31
                   (((uint8_t*)(x))[1] << 8) | \
32
                    ((uint8_t*)(x))[0])
33

  
34 30
#define VMD_HEADER_SIZE 0x0330
35 31
#define BYTES_PER_FRAME_RECORD 16
36 32

  
......
56 52
    vmd_frame_t *frame_table;
57 53
    unsigned int current_frame;
58 54

  
55
    int sample_rate;
56
    int64_t audio_sample_counter;
57
    int audio_frame_divisor;
58
    int audio_block_align;
59

  
59 60
    unsigned char vmd_header[VMD_HEADER_SIZE];
60 61
} VmdDemuxContext;
61 62

  
......
73 74
    return AVPROBE_SCORE_MAX / 2;
74 75
}
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

  
76 103
static int vmd_read_header(AVFormatContext *s,
77 104
                           AVFormatParameters *ap)
78 105
{
......
85 112
    unsigned char *current_frame_record;
86 113
    offset_t current_offset;
87 114
    int i;
88
    int sample_rate;
89 115
    unsigned int total_frames;
90
int video_frame_count = 0;
116
    int64_t video_pts_inc;
117
    int64_t current_video_pts = 0;
91 118

  
92 119
    /* fetch the main header, including the 2 header length bytes */
93 120
    url_fseek(pb, 0, SEEK_SET);
94 121
    if (get_buffer(pb, vmd->vmd_header, VMD_HEADER_SIZE) != VMD_HEADER_SIZE)
95 122
        return -EIO;
96 123

  
124
    vmd->audio_sample_counter = 0;
125
    vmd->audio_frame_divisor = 1;
126
    vmd->audio_block_align = 1;
127

  
97 128
    /* start up the decoders */
98 129
    st = av_new_stream(s, 0);
99 130
    if (!st)
......
109 140
    memcpy(st->codec.extradata, vmd->vmd_header, VMD_HEADER_SIZE);
110 141

  
111 142
    /* if sample rate is 0, assume no audio */
112
    sample_rate = LE_16(&vmd->vmd_header[804]);
113
    if (sample_rate) {
143
    vmd->sample_rate = LE_16(&vmd->vmd_header[804]);
144
    if (vmd->sample_rate) {
114 145
        st = av_new_stream(s, 0);
115 146
        if (!st)
116 147
            return AVERROR_NOMEM;
......
119 150
        st->codec.codec_id = CODEC_ID_VMDAUDIO;
120 151
        st->codec.codec_tag = 0;  /* no codec tag */
121 152
        st->codec.channels = (vmd->vmd_header[811] & 0x80) ? 2 : 1;
122
        st->codec.sample_rate = sample_rate;
123
        st->codec.bit_rate = st->codec.sample_rate * 
124
            st->codec.bits_per_sample * st->codec.channels;
125
        st->codec.block_align = LE_16(&vmd->vmd_header[806]);
153
        st->codec.sample_rate = vmd->sample_rate;
154
        st->codec.block_align = vmd->audio_block_align = 
155
            LE_16(&vmd->vmd_header[806]);
126 156
        if (st->codec.block_align & 0x8000) {
127 157
            st->codec.bits_per_sample = 16;
128 158
            st->codec.block_align = -(st->codec.block_align - 0x10000);
129 159
        } else
130
            st->codec.bits_per_sample = 8;
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;
131 175
    }
132 176

  
133 177
    /* skip over the offset table and load the table of contents; don't 
......
184 228
        memcpy(vmd->frame_table[i].frame_record, current_frame_record,
185 229
            BYTES_PER_FRAME_RECORD);
186 230

  
187
if (current_frame_record[0] == 0x02) {
188
  /* assume 15 fps for now */
189
  vmd->frame_table[i].pts = video_frame_count++;
190
  vmd->frame_table[i].pts *= 90000;
191
  vmd->frame_table[i].pts /= 15;
192
}
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
        }
193 239

  
194 240
        current_frame_record += BYTES_PER_FRAME_RECORD;
195 241
        i++;
......
227 273
    ret = get_buffer(pb, pkt->data + BYTES_PER_FRAME_RECORD, 
228 274
        frame->frame_size);
229 275

  
230
    if (ret != frame->frame_size)
276
    if (ret != frame->frame_size) {
277
        av_free_packet(pkt);
231 278
        ret = -EIO;
279
    }
232 280
    pkt->stream_index = frame->stream_index;
233
    pkt->pts = frame->pts;
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));
234 296

  
235 297
    vmd->current_frame++;
236 298

  

Also available in: Unified diff