Libav
|
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 FFmpeg. 00007 * 00008 * FFmpeg 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 * FFmpeg 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 FFmpeg; 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 ByteIOContext *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 = get_le32(pb); 00086 00087 bink->file_size = get_le32(pb) + 8; 00088 vst->duration = get_le32(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 (get_le32(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 url_fskip(pb, 4); 00102 00103 vst->codec->width = get_le32(pb); 00104 vst->codec->height = get_le32(pb); 00105 00106 fps_num = get_le32(pb); 00107 fps_den = get_le32(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 get_buffer(pb, vst->codec->extradata, 4); 00119 00120 bink->num_audio_tracks = get_le32(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 url_fskip(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 = 0; 00138 ast->codec->sample_rate = get_le16(pb); 00139 av_set_pts_info(ast, 64, 1, ast->codec->sample_rate); 00140 flags = get_le16(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 url_fskip(pb, 4 * bink->num_audio_tracks); 00147 } 00148 00149 /* frame index table */ 00150 next_pos = get_le32(pb); 00151 for (i = 0; i < vst->duration; i++) { 00152 pos = next_pos; 00153 if (i == vst->duration - 1) { 00154 next_pos = bink->file_size; 00155 keyframe = 0; 00156 } else { 00157 next_pos = get_le32(pb); 00158 keyframe = pos & 1; 00159 } 00160 pos &= ~1; 00161 next_pos &= ~1; 00162 00163 if (next_pos <= pos) { 00164 av_log(s, AV_LOG_ERROR, "invalid frame index table\n"); 00165 return AVERROR(EIO); 00166 } 00167 av_add_index_entry(vst, pos, i, next_pos - pos, 0, 00168 keyframe ? AVINDEX_KEYFRAME : 0); 00169 } 00170 00171 url_fskip(pb, 4); 00172 00173 bink->current_track = -1; 00174 return 0; 00175 } 00176 00177 static int read_packet(AVFormatContext *s, AVPacket *pkt) 00178 { 00179 BinkDemuxContext *bink = s->priv_data; 00180 ByteIOContext *pb = s->pb; 00181 int ret; 00182 00183 if (bink->current_track < 0) { 00184 int index_entry; 00185 AVStream *st = s->streams[0]; // stream 0 is video stream with index 00186 00187 if (bink->video_pts >= st->duration) 00188 return AVERROR(EIO); 00189 00190 index_entry = av_index_search_timestamp(st, bink->video_pts, 00191 AVSEEK_FLAG_ANY); 00192 if (index_entry < 0) { 00193 av_log(s, AV_LOG_ERROR, 00194 "could not find index entry for frame %"PRId64"\n", 00195 bink->video_pts); 00196 return AVERROR(EIO); 00197 } 00198 00199 bink->remain_packet_size = st->index_entries[index_entry].size; 00200 bink->current_track = 0; 00201 } 00202 00203 while (bink->current_track < bink->num_audio_tracks) { 00204 uint32_t audio_size = get_le32(pb); 00205 if (audio_size > bink->remain_packet_size - 4) { 00206 av_log(s, AV_LOG_ERROR, 00207 "frame %"PRId64": audio size in header (%u) > size of packet left (%u)\n", 00208 bink->video_pts, audio_size, bink->remain_packet_size); 00209 return AVERROR(EIO); 00210 } 00211 bink->remain_packet_size -= 4 + audio_size; 00212 bink->current_track++; 00213 if (audio_size >= 4) { 00214 /* get one audio packet per track */ 00215 if ((ret = av_get_packet(pb, pkt, audio_size)) < 0) 00216 return ret; 00217 pkt->stream_index = bink->current_track; 00218 pkt->pts = bink->audio_pts[bink->current_track - 1]; 00219 00220 /* Each audio packet reports the number of decompressed samples 00221 (in bytes). We use this value to calcuate the audio PTS */ 00222 if (pkt->size >= 4) 00223 bink->audio_pts[bink->current_track -1] += 00224 AV_RL32(pkt->data) / (2 * s->streams[bink->current_track]->codec->channels); 00225 return 0; 00226 } else { 00227 url_fseek(pb, audio_size, SEEK_CUR); 00228 } 00229 } 00230 00231 /* get video packet */ 00232 if ((ret = av_get_packet(pb, pkt, bink->remain_packet_size)) < 0) 00233 return ret; 00234 pkt->stream_index = 0; 00235 pkt->pts = bink->video_pts++; 00236 pkt->flags |= AV_PKT_FLAG_KEY; 00237 00238 /* -1 instructs the next call to read_packet() to read the next frame */ 00239 bink->current_track = -1; 00240 00241 return 0; 00242 } 00243 00244 static int read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) 00245 { 00246 BinkDemuxContext *bink = s->priv_data; 00247 AVStream *vst = s->streams[0]; 00248 00249 if (url_is_streamed(s->pb)) 00250 return -1; 00251 00252 /* seek to the first frame */ 00253 url_fseek(s->pb, vst->index_entries[0].pos, SEEK_SET); 00254 bink->video_pts = 0; 00255 memset(bink->audio_pts, 0, sizeof(bink->audio_pts)); 00256 bink->current_track = -1; 00257 return 0; 00258 } 00259 00260 AVInputFormat bink_demuxer = { 00261 "bink", 00262 NULL_IF_CONFIG_SMALL("Bink"), 00263 sizeof(BinkDemuxContext), 00264 probe, 00265 read_header, 00266 read_packet, 00267 NULL, 00268 read_seek, 00269 };