| @@ -0,0 +1,247 @@ |
| | 1 | /* |
| | 2 | * Bink demuxer |
| | 3 | * Copyright (c) 2008-2010 Peter Ross (pross@xvid.org) |
| | 4 | * Copyright (c) 2009 Daniel Verkamp (daniel@drv.nu) |
| | 5 | * |
| | 6 | * This file is part of FFmpeg. |
| | 7 | * |
| | 8 | * FFmpeg is free software; you can redistribute it and/or |
| | 9 | * modify it under the terms of the GNU Lesser General Public |
| | 10 | * License as published by the Free Software Foundation; either |
| | 11 | * version 2.1 of the License, or (at your option) any later version. |
| | 12 | * |
| | 13 | * FFmpeg is distributed in the hope that it will be useful, |
| | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | 16 | * Lesser General Public License for more details. |
| | 17 | * |
| | 18 | * You should have received a copy of the GNU Lesser General Public |
| | 19 | * License along with FFmpeg; if not, write to the Free Software |
| | 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| | 21 | */ |
| | 22 | |
| | 23 | /** |
| | 24 | * @file libavformat/bink.c |
| | 25 | * Bink demuxer |
| | 26 | * |
| | 27 | * Technical details here: |
| | 28 | * http://wiki.multimedia.cx/index.php?title=Bink_Container |
| | 29 | */ |
| | 30 | |
| | 31 | #include "libavutil/intreadwrite.h" |
| | 32 | #include "avformat.h" |
| | 33 | |
| | 34 | enum BinkAudFlags { |
| | 35 | BINK_AUD_16BITS = 0x4000, ///< prefer 16-bit output |
| | 36 | BINK_AUD_STEREO = 0x2000, |
| | 37 | BINK_AUD_USEDCT = 0x1000, |
| | 38 | }; |
| | 39 | |
| | 40 | #define BINK_EXTRADATA_SIZE 1 |
| | 41 | #define BINK_MAX_AUDIO_TRACKS 256 |
| | 42 | #define BINK_MAX_WIDTH 7680 |
| | 43 | #define BINK_MAX_HEIGHT 4800 |
| | 44 | |
| | 45 | typedef struct { |
| | 46 | uint32_t file_size; |
| | 47 | uint32_t total_frames; |
| | 48 | |
| | 49 | uint32_t num_audio_tracks; |
| | 50 | int current_track; ///< audio track to return in next packet |
| | 51 | int64_t video_pts; |
| | 52 | int64_t audio_pts[BINK_MAX_AUDIO_TRACKS]; |
| | 53 | |
| | 54 | uint32_t remain_packet_size; |
| | 55 | } BinkDemuxContext; |
| | 56 | |
| | 57 | static int probe(AVProbeData *p) |
| | 58 | { |
| | 59 | const uint8_t *b = p->buf; |
| | 60 | |
| | 61 | if ( b[0] == 'B' && b[1] == 'I' && b[2] == 'K' && |
| | 62 | (b[3] == 'b' || b[3] == 'f' || b[3] == 'g' || b[3] == 'h' || b[3] == 'i') && |
| | 63 | AV_RL32(b+8) > 0 && // num_frames |
| | 64 | AV_RL32(b+20) > 0 && AV_RL32(b+20) <= BINK_MAX_WIDTH && |
| | 65 | AV_RL32(b+24) > 0 && AV_RL32(b+24) <= BINK_MAX_HEIGHT && |
| | 66 | AV_RL32(b+28) > 0 && AV_RL32(b+32) > 0) // fps num,den |
| | 67 | return AVPROBE_SCORE_MAX; |
| | 68 | return 0; |
| | 69 | } |
| | 70 | |
| | 71 | static int read_header(AVFormatContext *s, AVFormatParameters *ap) |
| | 72 | { |
| | 73 | BinkDemuxContext *bink = s->priv_data; |
| | 74 | ByteIOContext *pb = s->pb; |
| | 75 | uint32_t fps_num, fps_den; |
| | 76 | AVStream *vst, *ast; |
| | 77 | unsigned int i; |
| | 78 | uint32_t pos, prev_pos; |
| | 79 | uint16_t flags; |
| | 80 | int keyframe; |
| | 81 | |
| | 82 | vst = av_new_stream(s, 0); |
| | 83 | if (!vst) |
| | 84 | return AVERROR(ENOMEM); |
| | 85 | |
| | 86 | vst->codec->codec_tag = get_le32(pb); |
| | 87 | |
| | 88 | bink->file_size = get_le32(pb) + 8; |
| | 89 | bink->total_frames = get_le32(pb); |
| | 90 | |
| | 91 | if (bink->total_frames > 1000000) { |
| | 92 | av_log(s, AV_LOG_ERROR, "invalid header: more than 1000000 frames\n"); |
| | 93 | return AVERROR(EIO); |
| | 94 | } |
| | 95 | |
| | 96 | if (get_le32(pb) > bink->file_size) { |
| | 97 | av_log(s, AV_LOG_ERROR, |
| | 98 | "invalid header: largest frame size greater than file size\n"); |
| | 99 | return AVERROR(EIO); |
| | 100 | } |
| | 101 | |
| | 102 | url_fskip(pb, 4); |
| | 103 | |
| | 104 | vst->codec->width = get_le32(pb); |
| | 105 | vst->codec->height = get_le32(pb); |
| | 106 | |
| | 107 | fps_num = get_le32(pb); |
| | 108 | fps_den = get_le32(pb); |
| | 109 | if (fps_num == 0 || fps_den == 0) { |
| | 110 | av_log(s, AV_LOG_ERROR, "invalid header: invalid fps (%d/%d)\n", fps_num, fps_den); |
| | 111 | return AVERROR(EIO); |
| | 112 | } |
| | 113 | av_set_pts_info(vst, 64, fps_den, fps_num); |
| | 114 | |
| | 115 | url_fskip(pb, 4); |
| | 116 | |
| | 117 | vst->codec->codec_type = CODEC_TYPE_VIDEO; |
| | 118 | vst->codec->codec_id = 0; /* FIXME: CODEC_ID_BINKVIDEO */ |
| | 119 | bink->num_audio_tracks = get_le32(pb); |
| | 120 | |
| | 121 | if (bink->num_audio_tracks > BINK_MAX_AUDIO_TRACKS) { |
| | 122 | av_log(s, AV_LOG_ERROR, |
| | 123 | "invalid header: more than "AV_STRINGIFY(BINK_MAX_AUDIO_TRACKS)" audio tracks (%d)\n", |
| | 124 | bink->num_audio_tracks); |
| | 125 | return AVERROR(EIO); |
| | 126 | } |
| | 127 | |
| | 128 | if (bink->num_audio_tracks) { |
| | 129 | url_fskip(pb, 4 * bink->num_audio_tracks); |
| | 130 | |
| | 131 | for (i = 0; i < bink->num_audio_tracks; i++) { |
| | 132 | ast = av_new_stream(s, 1); |
| | 133 | if (!ast) |
| | 134 | return AVERROR(ENOMEM); |
| | 135 | ast->codec->codec_type = CODEC_TYPE_AUDIO; |
| | 136 | ast->codec->codec_tag = 0; |
| | 137 | ast->codec->sample_rate = get_le16(pb); |
| | 138 | av_set_pts_info(ast, 64, 1, ast->codec->sample_rate); |
| | 139 | flags = get_le16(pb); |
| | 140 | ast->codec->codec_id = flags & BINK_AUD_USEDCT ? |
| | 141 | CODEC_ID_BINKAUDIO_DCT : CODEC_ID_BINKAUDIO_RDFT; |
| | 142 | ast->codec->channels = flags & BINK_AUD_STEREO ? 2 : 1; |
| | 143 | } |
| | 144 | |
| | 145 | url_fskip(pb, 4 * bink->num_audio_tracks); |
| | 146 | } |
| | 147 | |
| | 148 | /* frame index table */ |
| | 149 | pos = get_le32(pb) & ~1; |
| | 150 | for (i = 0; i < bink->total_frames; i++) { |
| | 151 | prev_pos = pos; |
| | 152 | if (i == bink->total_frames - 1) { |
| | 153 | pos = bink->file_size; |
| | 154 | keyframe = 0; |
| | 155 | } else { |
| | 156 | pos = get_le32(pb); |
| | 157 | keyframe = pos & 1; |
| | 158 | pos &= ~1; |
| | 159 | } |
| | 160 | if (pos <= prev_pos) { |
| | 161 | av_log(s, AV_LOG_ERROR, "invalid frame index table\n"); |
| | 162 | return AVERROR(EIO); |
| | 163 | } |
| | 164 | av_add_index_entry(vst, pos, i, pos - prev_pos, 0, |
| | 165 | keyframe ? AVINDEX_KEYFRAME : 0); |
| | 166 | } |
| | 167 | |
| | 168 | url_fskip(pb, 4); |
| | 169 | |
| | 170 | bink->current_track = -1; |
| | 171 | return 0; |
| | 172 | } |
| | 173 | |
| | 174 | static int read_packet(AVFormatContext *s, AVPacket *pkt) |
| | 175 | { |
| | 176 | BinkDemuxContext *bink = s->priv_data; |
| | 177 | ByteIOContext *pb = s->pb; |
| | 178 | int ret; |
| | 179 | |
| | 180 | if (bink->current_track < 0) { |
| | 181 | int index_entry; |
| | 182 | AVStream *st = s->streams[0]; // stream 0 is video stream with index |
| | 183 | |
| | 184 | if (bink->video_pts >= bink->total_frames) |
| | 185 | return AVERROR(EIO); |
| | 186 | |
| | 187 | index_entry = av_index_search_timestamp(st, bink->video_pts, |
| | 188 | AVSEEK_FLAG_ANY); |
| | 189 | if (index_entry < 0) { |
| | 190 | av_log(s, AV_LOG_ERROR, |
| | 191 | "could not find index entry for frame %"PRId64"\n", |
| | 192 | bink->video_pts); |
| | 193 | return AVERROR(EIO); |
| | 194 | } |
| | 195 | |
| | 196 | bink->remain_packet_size = st->index_entries[index_entry].size; |
| | 197 | bink->current_track = 0; |
| | 198 | } |
| | 199 | |
| | 200 | if (bink->current_track < bink->num_audio_tracks) { |
| | 201 | uint32_t audio_size = get_le32(pb); |
| | 202 | if (audio_size > bink->remain_packet_size - 4) { |
| | 203 | av_log(s, AV_LOG_ERROR, |
| | 204 | "frame %"PRId64": audio size in header (%u) > size of packet left (%u)\n", |
| | 205 | bink->video_pts, audio_size, bink->remain_packet_size); |
| | 206 | return AVERROR(EIO); |
| | 207 | } |
| | 208 | bink->remain_packet_size -= 4 + audio_size; |
| | 209 | bink->current_track++; |
| | 210 | if (audio_size > 0) { |
| | 211 | /* Each audio packet reports the number of decompressed samples |
| | 212 | (in bytes). We use this value to calcuate the audio PTS */ |
| | 213 | int reported_size = get_le32(pb) / (2 * s->streams[bink->current_track]->codec->channels); |
| | 214 | url_fseek(pb, -4, SEEK_CUR); |
| | 215 | |
| | 216 | /* get one audio packet per track */ |
| | 217 | if ((ret = av_get_packet(pb, pkt, audio_size)) |
| | 218 | != audio_size) |
| | 219 | return ret; |
| | 220 | pkt->stream_index = bink->current_track; |
| | 221 | pkt->pts = bink->audio_pts[bink->current_track - 1] += reported_size; |
| | 222 | return 0; |
| | 223 | } |
| | 224 | } |
| | 225 | |
| | 226 | /* get video packet */ |
| | 227 | if ((ret = av_get_packet(pb, pkt, bink->remain_packet_size)) |
| | 228 | != bink->remain_packet_size) |
| | 229 | return ret; |
| | 230 | pkt->stream_index = 0; |
| | 231 | pkt->pts = bink->video_pts++; |
| | 232 | pkt->flags |= PKT_FLAG_KEY; |
| | 233 | |
| | 234 | /* -1 instructs the next call to read_packet() to read the next frame */ |
| | 235 | bink->current_track = -1; |
| | 236 | |
| | 237 | return 0; |
| | 238 | } |
| | 239 | |
| | 240 | AVInputFormat bink_demuxer = { |
| | 241 | "bink", |
| | 242 | NULL_IF_CONFIG_SMALL("Bink"), |
| | 243 | sizeof(BinkDemuxContext), |
| | 244 | probe, |
| | 245 | read_header, |
| | 246 | read_packet, |
| | 247 | }; |