Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/*
2
 * Bethsoft VID format Demuxer
3
 * Copyright (c) 2007 Nicholas Tung
4
 *
5
 * This file is part of FFmpeg.
6
 *
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.
11
 *
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.
16
 *
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
20
 */
21
 
22
/**
23
 * @file
24
 * @brief Bethesda Softworks VID (.vid) file demuxer
25
 * @author Nicholas Tung [ntung (at. ntung com] (2007-03)
26
 * @see http://wiki.multimedia.cx/index.php?title=Bethsoft_VID
27
 * @see http://www.svatopluk.com/andux/docs/dfvid.html
28
 */
29
 
30
#include "libavutil/channel_layout.h"
31
#include "libavutil/intreadwrite.h"
32
#include "avformat.h"
33
#include "internal.h"
34
#include "libavcodec/bethsoftvideo.h"
35
 
36
#define BVID_PALETTE_SIZE 3 * 256
37
 
38
#define DEFAULT_SAMPLE_RATE 11111
39
 
40
typedef struct BVID_DemuxContext
41
{
42
    int nframes;
43
    int sample_rate;        /**< audio sample rate */
44
    int width;              /**< video width       */
45
    int height;             /**< video height      */
46
    /** delay value between frames, added to individual frame delay.
47
     * custom units, which will be added to other custom units (~=16ms according
48
     * to free, unofficial documentation) */
49
    int bethsoft_global_delay;
50
    int video_index;        /**< video stream index */
51
    int audio_index;        /**< audio stream index */
52
    uint8_t *palette;
53
 
54
    int is_finished;
55
 
56
} BVID_DemuxContext;
57
 
58
static int vid_probe(AVProbeData *p)
59
{
60
    // little-endian VID tag, file starts with "VID\0"
61
    if (AV_RL32(p->buf) != MKTAG('V', 'I', 'D', 0))
62
        return 0;
63
 
64
    return AVPROBE_SCORE_MAX;
65
}
66
 
67
static int vid_read_header(AVFormatContext *s)
68
{
69
    BVID_DemuxContext *vid = s->priv_data;
70
    AVIOContext *pb = s->pb;
71
 
72
    /* load main header. Contents:
73
    *    bytes: 'V' 'I' 'D'
74
    *    int16s: always_512, nframes, width, height, delay, always_14
75
    */
76
    avio_skip(pb, 5);
77
    vid->nframes = avio_rl16(pb);
78
    vid->width   = avio_rl16(pb);
79
    vid->height  = avio_rl16(pb);
80
    vid->bethsoft_global_delay = avio_rl16(pb);
81
    avio_rl16(pb);
82
 
83
    // wait until the first packet to create each stream
84
    vid->video_index = -1;
85
    vid->audio_index = -1;
86
    vid->sample_rate = DEFAULT_SAMPLE_RATE;
87
    s->ctx_flags |= AVFMTCTX_NOHEADER;
88
 
89
    return 0;
90
}
91
 
92
#define BUFFER_PADDING_SIZE 1000
93
static int read_frame(BVID_DemuxContext *vid, AVIOContext *pb, AVPacket *pkt,
94
                      uint8_t block_type, AVFormatContext *s)
95
{
96
    uint8_t * vidbuf_start = NULL;
97
    int vidbuf_nbytes = 0;
98
    int code;
99
    int bytes_copied = 0;
100
    int position, duration, npixels;
101
    unsigned int vidbuf_capacity;
102
    int ret = 0;
103
    AVStream *st;
104
 
105
    if (vid->video_index < 0) {
106
        st = avformat_new_stream(s, NULL);
107
        if (!st)
108
            return AVERROR(ENOMEM);
109
        vid->video_index = st->index;
110
        if (vid->audio_index < 0) {
111
            avpriv_request_sample(s, "Using default video time base since "
112
                                  "having no audio packet before the first "
113
                                  "video packet");
114
        }
115
        avpriv_set_pts_info(st, 64, 185, vid->sample_rate);
116
        st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
117
        st->codec->codec_id   = AV_CODEC_ID_BETHSOFTVID;
118
        st->codec->width      = vid->width;
119
        st->codec->height     = vid->height;
120
    }
121
    st      = s->streams[vid->video_index];
122
    npixels = st->codec->width * st->codec->height;
123
 
124
    vidbuf_start = av_malloc(vidbuf_capacity = BUFFER_PADDING_SIZE);
125
    if(!vidbuf_start)
126
        return AVERROR(ENOMEM);
127
 
128
    // save the file position for the packet, include block type
129
    position = avio_tell(pb) - 1;
130
 
131
    vidbuf_start[vidbuf_nbytes++] = block_type;
132
 
133
    // get the current packet duration
134
    duration = vid->bethsoft_global_delay + avio_rl16(pb);
135
 
136
    // set the y offset if it exists (decoder header data should be in data section)
137
    if(block_type == VIDEO_YOFF_P_FRAME){
138
        if (avio_read(pb, &vidbuf_start[vidbuf_nbytes], 2) != 2) {
139
            ret = AVERROR(EIO);
140
            goto fail;
141
        }
142
        vidbuf_nbytes += 2;
143
    }
144
 
145
    do{
146
        vidbuf_start = av_fast_realloc(vidbuf_start, &vidbuf_capacity, vidbuf_nbytes + BUFFER_PADDING_SIZE);
147
        if(!vidbuf_start)
148
            return AVERROR(ENOMEM);
149
 
150
        code = avio_r8(pb);
151
        vidbuf_start[vidbuf_nbytes++] = code;
152
 
153
        if(code >= 0x80){ // rle sequence
154
            if(block_type == VIDEO_I_FRAME)
155
                vidbuf_start[vidbuf_nbytes++] = avio_r8(pb);
156
        } else if(code){ // plain sequence
157
            if (avio_read(pb, &vidbuf_start[vidbuf_nbytes], code) != code) {
158
                ret = AVERROR(EIO);
159
                goto fail;
160
            }
161
            vidbuf_nbytes += code;
162
        }
163
        bytes_copied += code & 0x7F;
164
        if(bytes_copied == npixels){ // sometimes no stop character is given, need to keep track of bytes copied
165
            // may contain a 0 byte even if read all pixels
166
            if(avio_r8(pb))
167
                avio_seek(pb, -1, SEEK_CUR);
168
            break;
169
        }
170
        if (bytes_copied > npixels) {
171
            ret = AVERROR_INVALIDDATA;
172
            goto fail;
173
        }
174
    } while(code);
175
 
176
    // copy data into packet
177
    if ((ret = av_new_packet(pkt, vidbuf_nbytes)) < 0)
178
        goto fail;
179
    memcpy(pkt->data, vidbuf_start, vidbuf_nbytes);
180
    av_free(vidbuf_start);
181
 
182
    pkt->pos = position;
183
    pkt->stream_index = vid->video_index;
184
    pkt->duration = duration;
185
    if (block_type == VIDEO_I_FRAME)
186
        pkt->flags |= AV_PKT_FLAG_KEY;
187
 
188
    /* if there is a new palette available, add it to packet side data */
189
    if (vid->palette) {
190
        uint8_t *pdata = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE,
191
                                                 BVID_PALETTE_SIZE);
192
        if (pdata)
193
            memcpy(pdata, vid->palette, BVID_PALETTE_SIZE);
194
        av_freep(&vid->palette);
195
    }
196
 
197
    vid->nframes--;  // used to check if all the frames were read
198
    return 0;
199
fail:
200
    av_free(vidbuf_start);
201
    return ret;
202
}
203
 
204
static int vid_read_packet(AVFormatContext *s,
205
                           AVPacket *pkt)
206
{
207
    BVID_DemuxContext *vid = s->priv_data;
208
    AVIOContext *pb = s->pb;
209
    unsigned char block_type;
210
    int audio_length;
211
    int ret_value;
212
 
213
    if(vid->is_finished || url_feof(pb))
214
        return AVERROR_EOF;
215
 
216
    block_type = avio_r8(pb);
217
    switch(block_type){
218
        case PALETTE_BLOCK:
219
            if (vid->palette) {
220
                av_log(s, AV_LOG_WARNING, "discarding unused palette\n");
221
                av_freep(&vid->palette);
222
            }
223
            vid->palette = av_malloc(BVID_PALETTE_SIZE);
224
            if (!vid->palette)
225
                return AVERROR(ENOMEM);
226
            if (avio_read(pb, vid->palette, BVID_PALETTE_SIZE) != BVID_PALETTE_SIZE) {
227
                av_freep(&vid->palette);
228
                return AVERROR(EIO);
229
            }
230
            return vid_read_packet(s, pkt);
231
 
232
        case FIRST_AUDIO_BLOCK:
233
            avio_rl16(pb);
234
            // soundblaster DAC used for sample rate, as on specification page (link above)
235
            vid->sample_rate = 1000000 / (256 - avio_r8(pb));
236
        case AUDIO_BLOCK:
237
            if (vid->audio_index < 0) {
238
                AVStream *st = avformat_new_stream(s, NULL);
239
                if (!st)
240
                    return AVERROR(ENOMEM);
241
                vid->audio_index                 = st->index;
242
                st->codec->codec_type            = AVMEDIA_TYPE_AUDIO;
243
                st->codec->codec_id              = AV_CODEC_ID_PCM_U8;
244
                st->codec->channels              = 1;
245
                st->codec->channel_layout        = AV_CH_LAYOUT_MONO;
246
                st->codec->bits_per_coded_sample = 8;
247
                st->codec->sample_rate           = vid->sample_rate;
248
                st->codec->bit_rate              = 8 * st->codec->sample_rate;
249
                st->start_time                   = 0;
250
                avpriv_set_pts_info(st, 64, 1, vid->sample_rate);
251
            }
252
            audio_length = avio_rl16(pb);
253
            if ((ret_value = av_get_packet(pb, pkt, audio_length)) != audio_length) {
254
                if (ret_value < 0)
255
                    return ret_value;
256
                av_log(s, AV_LOG_ERROR, "incomplete audio block\n");
257
                return AVERROR(EIO);
258
            }
259
            pkt->stream_index = vid->audio_index;
260
            pkt->duration     = audio_length;
261
            pkt->flags |= AV_PKT_FLAG_KEY;
262
            return 0;
263
 
264
        case VIDEO_P_FRAME:
265
        case VIDEO_YOFF_P_FRAME:
266
        case VIDEO_I_FRAME:
267
            return read_frame(vid, pb, pkt, block_type, s);
268
 
269
        case EOF_BLOCK:
270
            if(vid->nframes != 0)
271
                av_log(s, AV_LOG_VERBOSE, "reached terminating character but not all frames read.\n");
272
            vid->is_finished = 1;
273
            return AVERROR(EIO);
274
        default:
275
            av_log(s, AV_LOG_ERROR, "unknown block (character = %c, decimal = %d, hex = %x)!!!\n",
276
                   block_type, block_type, block_type);
277
            return AVERROR_INVALIDDATA;
278
    }
279
}
280
 
281
static int vid_read_close(AVFormatContext *s)
282
{
283
    BVID_DemuxContext *vid = s->priv_data;
284
    av_freep(&vid->palette);
285
    return 0;
286
}
287
 
288
AVInputFormat ff_bethsoftvid_demuxer = {
289
    .name           = "bethsoftvid",
290
    .long_name      = NULL_IF_CONFIG_SMALL("Bethesda Softworks VID"),
291
    .priv_data_size = sizeof(BVID_DemuxContext),
292
    .read_probe     = vid_probe,
293
    .read_header    = vid_read_header,
294
    .read_packet    = vid_read_packet,
295
    .read_close     = vid_read_close,
296
};