bink.c 9.16 KB
Newer Older
Peter Ross's avatar
Peter Ross committed
1 2 3 4 5
/*
 * Bink demuxer
 * Copyright (c) 2008-2010 Peter Ross (pross@xvid.org)
 * Copyright (c) 2009 Daniel Verkamp (daniel@drv.nu)
 *
6
 * This file is part of Libav.
Peter Ross's avatar
Peter Ross committed
7
 *
8
 * Libav is free software; you can redistribute it and/or
Peter Ross's avatar
Peter Ross committed
9 10 11 12
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
13
 * Libav is distributed in the hope that it will be useful,
Peter Ross's avatar
Peter Ross committed
14 15 16 17 18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with Libav; if not, write to the Free Software
Peter Ross's avatar
Peter Ross committed
20 21 22 23
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
24
 * @file
Peter Ross's avatar
Peter Ross committed
25 26 27 28 29 30
 * Bink demuxer
 *
 * Technical details here:
 *  http://wiki.multimedia.cx/index.php?title=Bink_Container
 */

31 32
#include <inttypes.h>

33
#include "libavutil/channel_layout.h"
Peter Ross's avatar
Peter Ross committed
34 35
#include "libavutil/intreadwrite.h"
#include "avformat.h"
36
#include "internal.h"
Peter Ross's avatar
Peter Ross committed
37 38 39 40 41 42 43 44 45 46 47 48

enum BinkAudFlags {
    BINK_AUD_16BITS = 0x4000, ///< prefer 16-bit output
    BINK_AUD_STEREO = 0x2000,
    BINK_AUD_USEDCT = 0x1000,
};

#define BINK_EXTRADATA_SIZE     1
#define BINK_MAX_AUDIO_TRACKS   256
#define BINK_MAX_WIDTH          7680
#define BINK_MAX_HEIGHT         4800

49
typedef struct BinkDemuxContext {
Peter Ross's avatar
Peter Ross committed
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
    uint32_t file_size;

    uint32_t num_audio_tracks;
    int current_track;      ///< audio track to return in next packet
    int64_t video_pts;
    int64_t audio_pts[BINK_MAX_AUDIO_TRACKS];

    uint32_t remain_packet_size;
} BinkDemuxContext;

static int probe(AVProbeData *p)
{
    const uint8_t *b = p->buf;

    if ( b[0] == 'B' && b[1] == 'I' && b[2] == 'K' &&
        (b[3] == 'b' || b[3] == 'f' || b[3] == 'g' || b[3] == 'h' || b[3] == 'i') &&
        AV_RL32(b+8) > 0 &&  // num_frames
        AV_RL32(b+20) > 0 && AV_RL32(b+20) <= BINK_MAX_WIDTH &&
        AV_RL32(b+24) > 0 && AV_RL32(b+24) <= BINK_MAX_HEIGHT &&
        AV_RL32(b+28) > 0 && AV_RL32(b+32) > 0)  // fps num,den
        return AVPROBE_SCORE_MAX;
    return 0;
}

74
static int read_header(AVFormatContext *s)
Peter Ross's avatar
Peter Ross committed
75 76
{
    BinkDemuxContext *bink = s->priv_data;
77
    AVIOContext *pb = s->pb;
Peter Ross's avatar
Peter Ross committed
78 79 80
    uint32_t fps_num, fps_den;
    AVStream *vst, *ast;
    unsigned int i;
81
    uint32_t pos, next_pos;
Peter Ross's avatar
Peter Ross committed
82 83 84
    uint16_t flags;
    int keyframe;

85
    vst = avformat_new_stream(s, NULL);
Peter Ross's avatar
Peter Ross committed
86 87 88
    if (!vst)
        return AVERROR(ENOMEM);

89
    vst->codec->codec_tag = avio_rl32(pb);
Peter Ross's avatar
Peter Ross committed
90

91 92
    bink->file_size = avio_rl32(pb) + 8;
    vst->duration   = avio_rl32(pb);
Peter Ross's avatar
Peter Ross committed
93

94
    if (vst->duration > 1000000) {
Peter Ross's avatar
Peter Ross committed
95 96 97 98
        av_log(s, AV_LOG_ERROR, "invalid header: more than 1000000 frames\n");
        return AVERROR(EIO);
    }

99
    if (avio_rl32(pb) > bink->file_size) {
Peter Ross's avatar
Peter Ross committed
100 101 102 103 104
        av_log(s, AV_LOG_ERROR,
               "invalid header: largest frame size greater than file size\n");
        return AVERROR(EIO);
    }

105
    avio_skip(pb, 4);
Peter Ross's avatar
Peter Ross committed
106

107 108
    vst->codec->width  = avio_rl32(pb);
    vst->codec->height = avio_rl32(pb);
Peter Ross's avatar
Peter Ross committed
109

110 111
    fps_num = avio_rl32(pb);
    fps_den = avio_rl32(pb);
Peter Ross's avatar
Peter Ross committed
112
    if (fps_num == 0 || fps_den == 0) {
113 114 115
        av_log(s, AV_LOG_ERROR,
               "invalid header: invalid fps (%"PRIu32"/%"PRIu32")\n",
               fps_num, fps_den);
Peter Ross's avatar
Peter Ross committed
116 117
        return AVERROR(EIO);
    }
118
    avpriv_set_pts_info(vst, 64, fps_den, fps_num);
119
    vst->avg_frame_rate = av_inv_q(vst->time_base);
Peter Ross's avatar
Peter Ross committed
120

121
    vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
122
    vst->codec->codec_id   = AV_CODEC_ID_BINKVIDEO;
123
    vst->codec->extradata  = av_mallocz(4 + AV_INPUT_BUFFER_PADDING_SIZE);
124 125
    if (!vst->codec->extradata)
        return AVERROR(ENOMEM);
126
    vst->codec->extradata_size = 4;
127
    avio_read(pb, vst->codec->extradata, 4);
128

129
    bink->num_audio_tracks = avio_rl32(pb);
Peter Ross's avatar
Peter Ross committed
130 131 132

    if (bink->num_audio_tracks > BINK_MAX_AUDIO_TRACKS) {
        av_log(s, AV_LOG_ERROR,
133
               "invalid header: more than "AV_STRINGIFY(BINK_MAX_AUDIO_TRACKS)" audio tracks (%"PRIu32")\n",
Peter Ross's avatar
Peter Ross committed
134 135 136 137 138
               bink->num_audio_tracks);
        return AVERROR(EIO);
    }

    if (bink->num_audio_tracks) {
139
        avio_skip(pb, 4 * bink->num_audio_tracks);
Peter Ross's avatar
Peter Ross committed
140 141

        for (i = 0; i < bink->num_audio_tracks; i++) {
142
            ast = avformat_new_stream(s, NULL);
Peter Ross's avatar
Peter Ross committed
143 144
            if (!ast)
                return AVERROR(ENOMEM);
145
            ast->codec->codec_type  = AVMEDIA_TYPE_AUDIO;
146
            ast->codec->codec_tag   = 0;
147
            ast->codec->sample_rate = avio_rl16(pb);
148
            avpriv_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
149
            flags = avio_rl16(pb);
Peter Ross's avatar
Peter Ross committed
150
            ast->codec->codec_id = flags & BINK_AUD_USEDCT ?
151
                                   AV_CODEC_ID_BINKAUDIO_DCT : AV_CODEC_ID_BINKAUDIO_RDFT;
152 153 154 155 156 157 158
            if (flags & BINK_AUD_STEREO) {
                ast->codec->channels       = 2;
                ast->codec->channel_layout = AV_CH_LAYOUT_STEREO;
            } else {
                ast->codec->channels       = 1;
                ast->codec->channel_layout = AV_CH_LAYOUT_MONO;
            }
159
            ast->codec->extradata = av_mallocz(4 + AV_INPUT_BUFFER_PADDING_SIZE);
160 161 162 163
            if (!ast->codec->extradata)
                return AVERROR(ENOMEM);
            ast->codec->extradata_size = 4;
            AV_WL32(ast->codec->extradata, vst->codec->codec_tag);
Peter Ross's avatar
Peter Ross committed
164 165
        }

166 167
        for (i = 0; i < bink->num_audio_tracks; i++)
            s->streams[i + 1]->id = avio_rl32(pb);
Peter Ross's avatar
Peter Ross committed
168 169 170
    }

    /* frame index table */
171
    next_pos = avio_rl32(pb);
172
    for (i = 0; i < vst->duration; i++) {
173
        pos = next_pos;
174
        if (i == vst->duration - 1) {
175
            next_pos = bink->file_size;
Peter Ross's avatar
Peter Ross committed
176 177
            keyframe = 0;
        } else {
178
            next_pos = avio_rl32(pb);
Peter Ross's avatar
Peter Ross committed
179 180
            keyframe = pos & 1;
        }
181 182 183 184
        pos &= ~1;
        next_pos &= ~1;

        if (next_pos <= pos) {
Peter Ross's avatar
Peter Ross committed
185 186 187
            av_log(s, AV_LOG_ERROR, "invalid frame index table\n");
            return AVERROR(EIO);
        }
188
        av_add_index_entry(vst, pos, i, next_pos - pos, 0,
Peter Ross's avatar
Peter Ross committed
189 190 191
                           keyframe ? AVINDEX_KEYFRAME : 0);
    }

192
    avio_skip(pb, 4);
Peter Ross's avatar
Peter Ross committed
193 194 195 196 197 198 199 200

    bink->current_track = -1;
    return 0;
}

static int read_packet(AVFormatContext *s, AVPacket *pkt)
{
    BinkDemuxContext *bink = s->priv_data;
201
    AVIOContext *pb = s->pb;
Peter Ross's avatar
Peter Ross committed
202 203 204 205 206 207
    int ret;

    if (bink->current_track < 0) {
        int index_entry;
        AVStream *st = s->streams[0]; // stream 0 is video stream with index

208
        if (bink->video_pts >= st->duration)
Peter Ross's avatar
Peter Ross committed
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
            return AVERROR(EIO);

        index_entry = av_index_search_timestamp(st, bink->video_pts,
                                                AVSEEK_FLAG_ANY);
        if (index_entry < 0) {
            av_log(s, AV_LOG_ERROR,
                   "could not find index entry for frame %"PRId64"\n",
                   bink->video_pts);
            return AVERROR(EIO);
        }

        bink->remain_packet_size = st->index_entries[index_entry].size;
        bink->current_track = 0;
    }

224
    while (bink->current_track < bink->num_audio_tracks) {
225
        uint32_t audio_size = avio_rl32(pb);
Peter Ross's avatar
Peter Ross committed
226 227
        if (audio_size > bink->remain_packet_size - 4) {
            av_log(s, AV_LOG_ERROR,
228
                   "frame %"PRId64": audio size in header (%"PRIu32") > size of packet left (%"PRIu32")\n",
Peter Ross's avatar
Peter Ross committed
229 230 231 232 233
                   bink->video_pts, audio_size, bink->remain_packet_size);
            return AVERROR(EIO);
        }
        bink->remain_packet_size -= 4 + audio_size;
        bink->current_track++;
234
        if (audio_size >= 4) {
Peter Ross's avatar
Peter Ross committed
235
            /* get one audio packet per track */
236 237
            if ((ret = av_get_packet(pb, pkt, audio_size)) < 0)
                return ret;
Peter Ross's avatar
Peter Ross committed
238
            pkt->stream_index = bink->current_track;
239
            pkt->pts = bink->audio_pts[bink->current_track - 1];
240 241 242

            /* Each audio packet reports the number of decompressed samples
               (in bytes). We use this value to calcuate the audio PTS */
243 244 245
            if (pkt->size >= 4)
                bink->audio_pts[bink->current_track -1] +=
                    AV_RL32(pkt->data) / (2 * s->streams[bink->current_track]->codec->channels);
Peter Ross's avatar
Peter Ross committed
246
            return 0;
247
        } else {
248
            avio_skip(pb, audio_size);
Peter Ross's avatar
Peter Ross committed
249 250 251 252
        }
    }

    /* get video packet */
253 254
    if ((ret = av_get_packet(pb, pkt, bink->remain_packet_size)) < 0)
        return ret;
Peter Ross's avatar
Peter Ross committed
255 256
    pkt->stream_index = 0;
    pkt->pts = bink->video_pts++;
257
    pkt->flags |= AV_PKT_FLAG_KEY;
Peter Ross's avatar
Peter Ross committed
258 259 260 261 262 263 264

    /* -1 instructs the next call to read_packet() to read the next frame */
    bink->current_track = -1;

    return 0;
}

265 266 267 268 269
static int read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
{
    BinkDemuxContext *bink = s->priv_data;
    AVStream *vst = s->streams[0];

270
    if (!s->pb->seekable)
271 272
        return -1;

273
    /* seek to the first frame */
274 275 276
    if (avio_seek(s->pb, vst->index_entries[0].pos, SEEK_SET) < 0)
        return -1;

277 278 279 280 281 282
    bink->video_pts = 0;
    memset(bink->audio_pts, 0, sizeof(bink->audio_pts));
    bink->current_track = -1;
    return 0;
}

283
AVInputFormat ff_bink_demuxer = {
284 285 286 287 288 289 290
    .name           = "bink",
    .long_name      = NULL_IF_CONFIG_SMALL("Bink"),
    .priv_data_size = sizeof(BinkDemuxContext),
    .read_probe     = probe,
    .read_header    = read_header,
    .read_packet    = read_packet,
    .read_seek      = read_seek,
Peter Ross's avatar
Peter Ross committed
291
};