Libav 0.7.1
|
00001 /* 00002 * Smacker demuxer 00003 * Copyright (c) 2006 Konstantin Shishkov 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00022 /* 00023 * Based on http://wiki.multimedia.cx/index.php?title=Smacker 00024 */ 00025 00026 #include "libavutil/bswap.h" 00027 #include "libavutil/intreadwrite.h" 00028 #include "avformat.h" 00029 00030 #define SMACKER_PAL 0x01 00031 #define SMACKER_FLAG_RING_FRAME 0x01 00032 00033 enum SAudFlags { 00034 SMK_AUD_PACKED = 0x80000000, 00035 SMK_AUD_16BITS = 0x20000000, 00036 SMK_AUD_STEREO = 0x10000000, 00037 SMK_AUD_BINKAUD = 0x08000000, 00038 SMK_AUD_USEDCT = 0x04000000 00039 }; 00040 00041 typedef struct SmackerContext { 00042 /* Smacker file header */ 00043 uint32_t magic; 00044 uint32_t width, height; 00045 uint32_t frames; 00046 int pts_inc; 00047 uint32_t flags; 00048 uint32_t audio[7]; 00049 uint32_t treesize; 00050 uint32_t mmap_size, mclr_size, full_size, type_size; 00051 uint32_t rates[7]; 00052 uint32_t pad; 00053 /* frame info */ 00054 uint32_t *frm_size; 00055 uint8_t *frm_flags; 00056 /* internal variables */ 00057 int cur_frame; 00058 int is_ver4; 00059 int64_t cur_pts; 00060 /* current frame for demuxing */ 00061 uint8_t pal[768]; 00062 int indexes[7]; 00063 int videoindex; 00064 uint8_t *bufs[7]; 00065 int buf_sizes[7]; 00066 int stream_id[7]; 00067 int curstream; 00068 int64_t nextpos; 00069 int64_t aud_pts[7]; 00070 } SmackerContext; 00071 00072 typedef struct SmackerFrame { 00073 int64_t pts; 00074 int stream; 00075 } SmackerFrame; 00076 00077 /* palette used in Smacker */ 00078 static const uint8_t smk_pal[64] = { 00079 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 00080 0x20, 0x24, 0x28, 0x2C, 0x30, 0x34, 0x38, 0x3C, 00081 0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D, 00082 0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D, 00083 0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E, 00084 0xA2, 0xA6, 0xAA, 0xAE, 0xB2, 0xB6, 0xBA, 0xBE, 00085 0xC3, 0xC7, 0xCB, 0xCF, 0xD3, 0xD7, 0xDB, 0xDF, 00086 0xE3, 0xE7, 0xEB, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF 00087 }; 00088 00089 00090 static int smacker_probe(AVProbeData *p) 00091 { 00092 if(p->buf[0] == 'S' && p->buf[1] == 'M' && p->buf[2] == 'K' 00093 && (p->buf[3] == '2' || p->buf[3] == '4')) 00094 return AVPROBE_SCORE_MAX; 00095 else 00096 return 0; 00097 } 00098 00099 static int smacker_read_header(AVFormatContext *s, AVFormatParameters *ap) 00100 { 00101 AVIOContext *pb = s->pb; 00102 SmackerContext *smk = s->priv_data; 00103 AVStream *st, *ast[7]; 00104 int i, ret; 00105 int tbase; 00106 00107 /* read and check header */ 00108 smk->magic = avio_rl32(pb); 00109 if (smk->magic != MKTAG('S', 'M', 'K', '2') && smk->magic != MKTAG('S', 'M', 'K', '4')) 00110 return -1; 00111 smk->width = avio_rl32(pb); 00112 smk->height = avio_rl32(pb); 00113 smk->frames = avio_rl32(pb); 00114 smk->pts_inc = (int32_t)avio_rl32(pb); 00115 smk->flags = avio_rl32(pb); 00116 if(smk->flags & SMACKER_FLAG_RING_FRAME) 00117 smk->frames++; 00118 for(i = 0; i < 7; i++) 00119 smk->audio[i] = avio_rl32(pb); 00120 smk->treesize = avio_rl32(pb); 00121 00122 if(smk->treesize >= UINT_MAX/4){ // smk->treesize + 16 must not overflow (this check is probably redundant) 00123 av_log(s, AV_LOG_ERROR, "treesize too large\n"); 00124 return -1; 00125 } 00126 00127 //FIXME remove extradata "rebuilding" 00128 smk->mmap_size = avio_rl32(pb); 00129 smk->mclr_size = avio_rl32(pb); 00130 smk->full_size = avio_rl32(pb); 00131 smk->type_size = avio_rl32(pb); 00132 for(i = 0; i < 7; i++) 00133 smk->rates[i] = avio_rl32(pb); 00134 smk->pad = avio_rl32(pb); 00135 /* setup data */ 00136 if(smk->frames > 0xFFFFFF) { 00137 av_log(s, AV_LOG_ERROR, "Too many frames: %i\n", smk->frames); 00138 return -1; 00139 } 00140 smk->frm_size = av_malloc(smk->frames * 4); 00141 smk->frm_flags = av_malloc(smk->frames); 00142 00143 smk->is_ver4 = (smk->magic != MKTAG('S', 'M', 'K', '2')); 00144 00145 /* read frame info */ 00146 for(i = 0; i < smk->frames; i++) { 00147 smk->frm_size[i] = avio_rl32(pb); 00148 } 00149 for(i = 0; i < smk->frames; i++) { 00150 smk->frm_flags[i] = avio_r8(pb); 00151 } 00152 00153 /* init video codec */ 00154 st = av_new_stream(s, 0); 00155 if (!st) 00156 return -1; 00157 smk->videoindex = st->index; 00158 st->codec->width = smk->width; 00159 st->codec->height = smk->height; 00160 st->codec->pix_fmt = PIX_FMT_PAL8; 00161 st->codec->codec_type = AVMEDIA_TYPE_VIDEO; 00162 st->codec->codec_id = CODEC_ID_SMACKVIDEO; 00163 st->codec->codec_tag = smk->magic; 00164 /* Smacker uses 100000 as internal timebase */ 00165 if(smk->pts_inc < 0) 00166 smk->pts_inc = -smk->pts_inc; 00167 else 00168 smk->pts_inc *= 100; 00169 tbase = 100000; 00170 av_reduce(&tbase, &smk->pts_inc, tbase, smk->pts_inc, (1UL<<31)-1); 00171 av_set_pts_info(st, 33, smk->pts_inc, tbase); 00172 st->duration = smk->frames; 00173 /* handle possible audio streams */ 00174 for(i = 0; i < 7; i++) { 00175 smk->indexes[i] = -1; 00176 if(smk->rates[i] & 0xFFFFFF){ 00177 ast[i] = av_new_stream(s, 0); 00178 smk->indexes[i] = ast[i]->index; 00179 ast[i]->codec->codec_type = AVMEDIA_TYPE_AUDIO; 00180 if (smk->rates[i] & SMK_AUD_BINKAUD) { 00181 ast[i]->codec->codec_id = CODEC_ID_BINKAUDIO_RDFT; 00182 } else if (smk->rates[i] & SMK_AUD_USEDCT) { 00183 ast[i]->codec->codec_id = CODEC_ID_BINKAUDIO_DCT; 00184 } else if (smk->rates[i] & SMK_AUD_PACKED){ 00185 ast[i]->codec->codec_id = CODEC_ID_SMACKAUDIO; 00186 ast[i]->codec->codec_tag = MKTAG('S', 'M', 'K', 'A'); 00187 } else { 00188 ast[i]->codec->codec_id = CODEC_ID_PCM_U8; 00189 } 00190 ast[i]->codec->channels = (smk->rates[i] & SMK_AUD_STEREO) ? 2 : 1; 00191 ast[i]->codec->sample_rate = smk->rates[i] & 0xFFFFFF; 00192 ast[i]->codec->bits_per_coded_sample = (smk->rates[i] & SMK_AUD_16BITS) ? 16 : 8; 00193 if(ast[i]->codec->bits_per_coded_sample == 16 && ast[i]->codec->codec_id == CODEC_ID_PCM_U8) 00194 ast[i]->codec->codec_id = CODEC_ID_PCM_S16LE; 00195 av_set_pts_info(ast[i], 64, 1, ast[i]->codec->sample_rate 00196 * ast[i]->codec->channels * ast[i]->codec->bits_per_coded_sample / 8); 00197 } 00198 } 00199 00200 00201 /* load trees to extradata, they will be unpacked by decoder */ 00202 st->codec->extradata = av_malloc(smk->treesize + 16); 00203 st->codec->extradata_size = smk->treesize + 16; 00204 if(!st->codec->extradata){ 00205 av_log(s, AV_LOG_ERROR, "Cannot allocate %i bytes of extradata\n", smk->treesize + 16); 00206 av_free(smk->frm_size); 00207 av_free(smk->frm_flags); 00208 return -1; 00209 } 00210 ret = avio_read(pb, st->codec->extradata + 16, st->codec->extradata_size - 16); 00211 if(ret != st->codec->extradata_size - 16){ 00212 av_free(smk->frm_size); 00213 av_free(smk->frm_flags); 00214 return AVERROR(EIO); 00215 } 00216 ((int32_t*)st->codec->extradata)[0] = av_le2ne32(smk->mmap_size); 00217 ((int32_t*)st->codec->extradata)[1] = av_le2ne32(smk->mclr_size); 00218 ((int32_t*)st->codec->extradata)[2] = av_le2ne32(smk->full_size); 00219 ((int32_t*)st->codec->extradata)[3] = av_le2ne32(smk->type_size); 00220 00221 smk->curstream = -1; 00222 smk->nextpos = avio_tell(pb); 00223 00224 return 0; 00225 } 00226 00227 00228 static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) 00229 { 00230 SmackerContext *smk = s->priv_data; 00231 int flags; 00232 int ret; 00233 int i; 00234 int frame_size = 0; 00235 int palchange = 0; 00236 00237 if (s->pb->eof_reached || smk->cur_frame >= smk->frames) 00238 return AVERROR_EOF; 00239 00240 /* if we demuxed all streams, pass another frame */ 00241 if(smk->curstream < 0) { 00242 avio_seek(s->pb, smk->nextpos, 0); 00243 frame_size = smk->frm_size[smk->cur_frame] & (~3); 00244 flags = smk->frm_flags[smk->cur_frame]; 00245 /* handle palette change event */ 00246 if(flags & SMACKER_PAL){ 00247 int size, sz, t, off, j, pos; 00248 uint8_t *pal = smk->pal; 00249 uint8_t oldpal[768]; 00250 00251 memcpy(oldpal, pal, 768); 00252 size = avio_r8(s->pb); 00253 size = size * 4 - 1; 00254 frame_size -= size; 00255 frame_size--; 00256 sz = 0; 00257 pos = avio_tell(s->pb) + size; 00258 while(sz < 256){ 00259 t = avio_r8(s->pb); 00260 if(t & 0x80){ /* skip palette entries */ 00261 sz += (t & 0x7F) + 1; 00262 pal += ((t & 0x7F) + 1) * 3; 00263 } else if(t & 0x40){ /* copy with offset */ 00264 off = avio_r8(s->pb); 00265 j = (t & 0x3F) + 1; 00266 if (off + j > 0xff) { 00267 av_log(s, AV_LOG_ERROR, 00268 "Invalid palette update, offset=%d length=%d extends beyond palette size\n", 00269 off, j); 00270 return AVERROR_INVALIDDATA; 00271 } 00272 off *= 3; 00273 while(j-- && sz < 256) { 00274 *pal++ = oldpal[off + 0]; 00275 *pal++ = oldpal[off + 1]; 00276 *pal++ = oldpal[off + 2]; 00277 sz++; 00278 off += 3; 00279 } 00280 } else { /* new entries */ 00281 *pal++ = smk_pal[t]; 00282 *pal++ = smk_pal[avio_r8(s->pb) & 0x3F]; 00283 *pal++ = smk_pal[avio_r8(s->pb) & 0x3F]; 00284 sz++; 00285 } 00286 } 00287 avio_seek(s->pb, pos, 0); 00288 palchange |= 1; 00289 } 00290 flags >>= 1; 00291 smk->curstream = -1; 00292 /* if audio chunks are present, put them to stack and retrieve later */ 00293 for(i = 0; i < 7; i++) { 00294 if(flags & 1) { 00295 int size; 00296 uint8_t *tmpbuf; 00297 00298 size = avio_rl32(s->pb) - 4; 00299 frame_size -= size; 00300 frame_size -= 4; 00301 smk->curstream++; 00302 tmpbuf = av_realloc(smk->bufs[smk->curstream], size); 00303 if (!tmpbuf) 00304 return AVERROR(ENOMEM); 00305 smk->bufs[smk->curstream] = tmpbuf; 00306 smk->buf_sizes[smk->curstream] = size; 00307 ret = avio_read(s->pb, smk->bufs[smk->curstream], size); 00308 if(ret != size) 00309 return AVERROR(EIO); 00310 smk->stream_id[smk->curstream] = smk->indexes[i]; 00311 } 00312 flags >>= 1; 00313 } 00314 if (frame_size < 0) 00315 return AVERROR_INVALIDDATA; 00316 if (av_new_packet(pkt, frame_size + 769)) 00317 return AVERROR(ENOMEM); 00318 if(smk->frm_size[smk->cur_frame] & 1) 00319 palchange |= 2; 00320 pkt->data[0] = palchange; 00321 memcpy(pkt->data + 1, smk->pal, 768); 00322 ret = avio_read(s->pb, pkt->data + 769, frame_size); 00323 if(ret != frame_size) 00324 return AVERROR(EIO); 00325 pkt->stream_index = smk->videoindex; 00326 pkt->size = ret + 769; 00327 smk->cur_frame++; 00328 smk->nextpos = avio_tell(s->pb); 00329 } else { 00330 if (av_new_packet(pkt, smk->buf_sizes[smk->curstream])) 00331 return AVERROR(ENOMEM); 00332 memcpy(pkt->data, smk->bufs[smk->curstream], smk->buf_sizes[smk->curstream]); 00333 pkt->size = smk->buf_sizes[smk->curstream]; 00334 pkt->stream_index = smk->stream_id[smk->curstream]; 00335 pkt->pts = smk->aud_pts[smk->curstream]; 00336 smk->aud_pts[smk->curstream] += AV_RL32(pkt->data); 00337 smk->curstream--; 00338 } 00339 00340 return 0; 00341 } 00342 00343 static int smacker_read_close(AVFormatContext *s) 00344 { 00345 SmackerContext *smk = s->priv_data; 00346 int i; 00347 00348 for(i = 0; i < 7; i++) 00349 av_free(smk->bufs[i]); 00350 av_free(smk->frm_size); 00351 av_free(smk->frm_flags); 00352 00353 return 0; 00354 } 00355 00356 AVInputFormat ff_smacker_demuxer = { 00357 "smk", 00358 NULL_IF_CONFIG_SMALL("Smacker video"), 00359 sizeof(SmackerContext), 00360 smacker_probe, 00361 smacker_read_header, 00362 smacker_read_packet, 00363 smacker_read_close, 00364 };