~siretart/libav/trusty

« back to all changes in this revision

Viewing changes to libavformat/bethsoftvid.c

  • Committer: Reinhard Tartler
  • Date: 2013-10-23 03:04:17 UTC
  • mfrom: (1.3.36 sid)
  • Revision ID: siretart@tauware.de-20131023030417-1o6mpkl1l0raifjt
mergeĀ fromĀ debian

Show diffs side-by-side

added added

removed removed

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