Libav 0.7.1
|
00001 /* 00002 * Bink demuxer 00003 * Copyright (c) 2008-2010 Peter Ross (pross@xvid.org) 00004 * Copyright (c) 2009 Daniel Verkamp (daniel@drv.nu) 00005 * 00006 * This file is part of Libav. 00007 * 00008 * Libav is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * Libav is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with Libav; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00031 #include "libavutil/intreadwrite.h" 00032 #include "avformat.h" 00033 00034 enum BinkAudFlags { 00035 BINK_AUD_16BITS = 0x4000, 00036 BINK_AUD_STEREO = 0x2000, 00037 BINK_AUD_USEDCT = 0x1000, 00038 }; 00039 00040 #define BINK_EXTRADATA_SIZE 1 00041 #define BINK_MAX_AUDIO_TRACKS 256 00042 #define BINK_MAX_WIDTH 7680 00043 #define BINK_MAX_HEIGHT 4800 00044 00045 typedef struct { 00046 uint32_t file_size; 00047 00048 uint32_t num_audio_tracks; 00049 int current_track; 00050 int64_t video_pts; 00051 int64_t audio_pts[BINK_MAX_AUDIO_TRACKS]; 00052 00053 uint32_t remain_packet_size; 00054 } BinkDemuxContext; 00055 00056 static int probe(AVProbeData *p) 00057 { 00058 const uint8_t *b = p->buf; 00059 00060 if ( b[0] == 'B' && b[1] == 'I' && b[2] == 'K' && 00061 (b[3] == 'b' || b[3] == 'f' || b[3] == 'g' || b[3] == 'h' || b[3] == 'i') && 00062 AV_RL32(b+8) > 0 && // num_frames 00063 AV_RL32(b+20) > 0 && AV_RL32(b+20) <= BINK_MAX_WIDTH && 00064 AV_RL32(b+24) > 0 && AV_RL32(b+24) <= BINK_MAX_HEIGHT && 00065 AV_RL32(b+28) > 0 && AV_RL32(b+32) > 0) // fps num,den 00066 return AVPROBE_SCORE_MAX; 00067 return 0; 00068 } 00069 00070 static int read_header(AVFormatContext *s, AVFormatParameters *ap) 00071 { 00072 BinkDemuxContext *bink = s->priv_data; 00073 AVIOContext *pb = s->pb; 00074 uint32_t fps_num, fps_den; 00075 AVStream *vst, *ast; 00076 unsigned int i; 00077 uint32_t pos, next_pos; 00078 uint16_t flags; 00079 int keyframe; 00080 00081 vst = av_new_stream(s, 0); 00082 if (!vst) 00083 return AVERROR(ENOMEM); 00084 00085 vst->codec->codec_tag = avio_rl32(pb); 00086 00087 bink->file_size = avio_rl32(pb) + 8; 00088 vst->duration = avio_rl32(pb); 00089 00090 if (vst->duration > 1000000) { 00091 av_log(s, AV_LOG_ERROR, "invalid header: more than 1000000 frames\n"); 00092 return AVERROR(EIO); 00093 } 00094 00095 if (avio_rl32(pb) > bink->file_size) { 00096 av_log(s, AV_LOG_ERROR, 00097 "invalid header: largest frame size greater than file size\n"); 00098 return AVERROR(EIO); 00099 } 00100 00101 avio_skip(pb, 4); 00102 00103 vst->codec->width = avio_rl32(pb); 00104 vst->codec->height = avio_rl32(pb); 00105 00106 fps_num = avio_rl32(pb); 00107 fps_den = avio_rl32(pb); 00108 if (fps_num == 0 || fps_den == 0) { 00109 av_log(s, AV_LOG_ERROR, "invalid header: invalid fps (%d/%d)\n", fps_num, fps_den); 00110 return AVERROR(EIO); 00111 } 00112 av_set_pts_info(vst, 64, fps_den, fps_num); 00113 00114 vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; 00115 vst->codec->codec_id = CODEC_ID_BINKVIDEO; 00116 vst->codec->extradata = av_mallocz(4 + FF_INPUT_BUFFER_PADDING_SIZE); 00117 vst->codec->extradata_size = 4; 00118 avio_read(pb, vst->codec->extradata, 4); 00119 00120 bink->num_audio_tracks = avio_rl32(pb); 00121 00122 if (bink->num_audio_tracks > BINK_MAX_AUDIO_TRACKS) { 00123 av_log(s, AV_LOG_ERROR, 00124 "invalid header: more than "AV_STRINGIFY(BINK_MAX_AUDIO_TRACKS)" audio tracks (%d)\n", 00125 bink->num_audio_tracks); 00126 return AVERROR(EIO); 00127 } 00128 00129 if (bink->num_audio_tracks) { 00130 avio_skip(pb, 4 * bink->num_audio_tracks); 00131 00132 for (i = 0; i < bink->num_audio_tracks; i++) { 00133 ast = av_new_stream(s, 1); 00134 if (!ast) 00135 return AVERROR(ENOMEM); 00136 ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; 00137 ast->codec->codec_tag = vst->codec->codec_tag; 00138 ast->codec->sample_rate = avio_rl16(pb); 00139 av_set_pts_info(ast, 64, 1, ast->codec->sample_rate); 00140 flags = avio_rl16(pb); 00141 ast->codec->codec_id = flags & BINK_AUD_USEDCT ? 00142 CODEC_ID_BINKAUDIO_DCT : CODEC_ID_BINKAUDIO_RDFT; 00143 ast->codec->channels = flags & BINK_AUD_STEREO ? 2 : 1; 00144 } 00145 00146 for (i = 0; i < bink->num_audio_tracks; i++) 00147 s->streams[i + 1]->id = avio_rl32(pb); 00148 } 00149 00150 /* frame index table */ 00151 next_pos = avio_rl32(pb); 00152 for (i = 0; i < vst->duration; i++) { 00153 pos = next_pos; 00154 if (i == vst->duration - 1) { 00155 next_pos = bink->file_size; 00156 keyframe = 0; 00157 } else { 00158 next_pos = avio_rl32(pb); 00159 keyframe = pos & 1; 00160 } 00161 pos &= ~1; 00162 next_pos &= ~1; 00163 00164 if (next_pos <= pos) { 00165 av_log(s, AV_LOG_ERROR, "invalid frame index table\n"); 00166 return AVERROR(EIO); 00167 } 00168 av_add_index_entry(vst, pos, i, next_pos - pos, 0, 00169 keyframe ? AVINDEX_KEYFRAME : 0); 00170 } 00171 00172 avio_skip(pb, 4); 00173 00174 bink->current_track = -1; 00175 return 0; 00176 } 00177 00178 static int read_packet(AVFormatContext *s, AVPacket *pkt) 00179 { 00180 BinkDemuxContext *bink = s->priv_data; 00181 AVIOContext *pb = s->pb; 00182 int ret; 00183 00184 if (bink->current_track < 0) { 00185 int index_entry; 00186 AVStream *st = s->streams[0]; // stream 0 is video stream with index 00187 00188 if (bink->video_pts >= st->duration) 00189 return AVERROR(EIO); 00190 00191 index_entry = av_index_search_timestamp(st, bink->video_pts, 00192 AVSEEK_FLAG_ANY); 00193 if (index_entry < 0) { 00194 av_log(s, AV_LOG_ERROR, 00195 "could not find index entry for frame %"PRId64"\n", 00196 bink->video_pts); 00197 return AVERROR(EIO); 00198 } 00199 00200 bink->remain_packet_size = st->index_entries[index_entry].size; 00201 bink->current_track = 0; 00202 } 00203 00204 while (bink->current_track < bink->num_audio_tracks) { 00205 uint32_t audio_size = avio_rl32(pb); 00206 if (audio_size > bink->remain_packet_size - 4) { 00207 av_log(s, AV_LOG_ERROR, 00208 "frame %"PRId64": audio size in header (%u) > size of packet left (%u)\n", 00209 bink->video_pts, audio_size, bink->remain_packet_size); 00210 return AVERROR(EIO); 00211 } 00212 bink->remain_packet_size -= 4 + audio_size; 00213 bink->current_track++; 00214 if (audio_size >= 4) { 00215 /* get one audio packet per track */ 00216 if ((ret = av_get_packet(pb, pkt, audio_size)) < 0) 00217 return ret; 00218 pkt->stream_index = bink->current_track; 00219 pkt->pts = bink->audio_pts[bink->current_track - 1]; 00220 00221 /* Each audio packet reports the number of decompressed samples 00222 (in bytes). We use this value to calcuate the audio PTS */ 00223 if (pkt->size >= 4) 00224 bink->audio_pts[bink->current_track -1] += 00225 AV_RL32(pkt->data) / (2 * s->streams[bink->current_track]->codec->channels); 00226 return 0; 00227 } else { 00228 avio_skip(pb, audio_size); 00229 } 00230 } 00231 00232 /* get video packet */ 00233 if ((ret = av_get_packet(pb, pkt, bink->remain_packet_size)) < 0) 00234 return ret; 00235 pkt->stream_index = 0; 00236 pkt->pts = bink->video_pts++; 00237 pkt->flags |= AV_PKT_FLAG_KEY; 00238 00239 /* -1 instructs the next call to read_packet() to read the next frame */ 00240 bink->current_track = -1; 00241 00242 return 0; 00243 } 00244 00245 static int read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) 00246 { 00247 BinkDemuxContext *bink = s->priv_data; 00248 AVStream *vst = s->streams[0]; 00249 00250 if (!s->pb->seekable) 00251 return -1; 00252 00253 /* seek to the first frame */ 00254 avio_seek(s->pb, vst->index_entries[0].pos, SEEK_SET); 00255 bink->video_pts = 0; 00256 memset(bink->audio_pts, 0, sizeof(bink->audio_pts)); 00257 bink->current_track = -1; 00258 return 0; 00259 } 00260 00261 AVInputFormat ff_bink_demuxer = { 00262 "bink", 00263 NULL_IF_CONFIG_SMALL("Bink"), 00264 sizeof(BinkDemuxContext), 00265 probe, 00266 read_header, 00267 read_packet, 00268 NULL, 00269 read_seek, 00270 };