00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "libavutil/bswap.h"
00027 #include "libavutil/channel_layout.h"
00028 #include "libavutil/intreadwrite.h"
00029 #include "avformat.h"
00030 #include "internal.h"
00031
00032 #define SMACKER_PAL 0x01
00033 #define SMACKER_FLAG_RING_FRAME 0x01
00034
00035 enum SAudFlags {
00036 SMK_AUD_PACKED = 0x80,
00037 SMK_AUD_16BITS = 0x20,
00038 SMK_AUD_STEREO = 0x10,
00039 SMK_AUD_BINKAUD = 0x08,
00040 SMK_AUD_USEDCT = 0x04
00041 };
00042
00043 typedef struct SmackerContext {
00044
00045 uint32_t magic;
00046 uint32_t width, height;
00047 uint32_t frames;
00048 int pts_inc;
00049 uint32_t flags;
00050 uint32_t audio[7];
00051 uint32_t treesize;
00052 uint32_t mmap_size, mclr_size, full_size, type_size;
00053 uint8_t aflags[7];
00054 uint32_t rates[7];
00055 uint32_t pad;
00056
00057 uint32_t *frm_size;
00058 uint8_t *frm_flags;
00059
00060 int cur_frame;
00061 int is_ver4;
00062 int64_t cur_pts;
00063
00064 uint8_t pal[768];
00065 int indexes[7];
00066 int videoindex;
00067 uint8_t *bufs[7];
00068 int buf_sizes[7];
00069 int stream_id[7];
00070 int curstream;
00071 int64_t nextpos;
00072 int64_t aud_pts[7];
00073 } SmackerContext;
00074
00075 typedef struct SmackerFrame {
00076 int64_t pts;
00077 int stream;
00078 } SmackerFrame;
00079
00080
00081 static const uint8_t smk_pal[64] = {
00082 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C,
00083 0x20, 0x24, 0x28, 0x2C, 0x30, 0x34, 0x38, 0x3C,
00084 0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D,
00085 0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D,
00086 0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E,
00087 0xA2, 0xA6, 0xAA, 0xAE, 0xB2, 0xB6, 0xBA, 0xBE,
00088 0xC3, 0xC7, 0xCB, 0xCF, 0xD3, 0xD7, 0xDB, 0xDF,
00089 0xE3, 0xE7, 0xEB, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF
00090 };
00091
00092
00093 static int smacker_probe(AVProbeData *p)
00094 {
00095 if(p->buf[0] == 'S' && p->buf[1] == 'M' && p->buf[2] == 'K'
00096 && (p->buf[3] == '2' || p->buf[3] == '4'))
00097 return AVPROBE_SCORE_MAX;
00098 else
00099 return 0;
00100 }
00101
00102 static int smacker_read_header(AVFormatContext *s)
00103 {
00104 AVIOContext *pb = s->pb;
00105 SmackerContext *smk = s->priv_data;
00106 AVStream *st, *ast[7];
00107 int i, ret;
00108 int tbase;
00109
00110
00111 smk->magic = avio_rl32(pb);
00112 if (smk->magic != MKTAG('S', 'M', 'K', '2') && smk->magic != MKTAG('S', 'M', 'K', '4'))
00113 return AVERROR_INVALIDDATA;
00114 smk->width = avio_rl32(pb);
00115 smk->height = avio_rl32(pb);
00116 smk->frames = avio_rl32(pb);
00117 smk->pts_inc = (int32_t)avio_rl32(pb);
00118 smk->flags = avio_rl32(pb);
00119 if(smk->flags & SMACKER_FLAG_RING_FRAME)
00120 smk->frames++;
00121 for(i = 0; i < 7; i++)
00122 smk->audio[i] = avio_rl32(pb);
00123 smk->treesize = avio_rl32(pb);
00124
00125 if(smk->treesize >= UINT_MAX/4){
00126 av_log(s, AV_LOG_ERROR, "treesize too large\n");
00127 return AVERROR_INVALIDDATA;
00128 }
00129
00130
00131 smk->mmap_size = avio_rl32(pb);
00132 smk->mclr_size = avio_rl32(pb);
00133 smk->full_size = avio_rl32(pb);
00134 smk->type_size = avio_rl32(pb);
00135 for(i = 0; i < 7; i++) {
00136 smk->rates[i] = avio_rl24(pb);
00137 smk->aflags[i] = avio_r8(pb);
00138 }
00139 smk->pad = avio_rl32(pb);
00140
00141 if(smk->frames > 0xFFFFFF) {
00142 av_log(s, AV_LOG_ERROR, "Too many frames: %i\n", smk->frames);
00143 return AVERROR_INVALIDDATA;
00144 }
00145 smk->frm_size = av_malloc(smk->frames * 4);
00146 smk->frm_flags = av_malloc(smk->frames);
00147
00148 smk->is_ver4 = (smk->magic != MKTAG('S', 'M', 'K', '2'));
00149
00150
00151 for(i = 0; i < smk->frames; i++) {
00152 smk->frm_size[i] = avio_rl32(pb);
00153 }
00154 for(i = 0; i < smk->frames; i++) {
00155 smk->frm_flags[i] = avio_r8(pb);
00156 }
00157
00158
00159 st = avformat_new_stream(s, NULL);
00160 if (!st)
00161 return AVERROR(ENOMEM);
00162 smk->videoindex = st->index;
00163 st->codec->width = smk->width;
00164 st->codec->height = smk->height;
00165 st->codec->pix_fmt = AV_PIX_FMT_PAL8;
00166 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00167 st->codec->codec_id = AV_CODEC_ID_SMACKVIDEO;
00168 st->codec->codec_tag = smk->magic;
00169
00170 if(smk->pts_inc < 0)
00171 smk->pts_inc = -smk->pts_inc;
00172 else
00173 smk->pts_inc *= 100;
00174 tbase = 100000;
00175 av_reduce(&tbase, &smk->pts_inc, tbase, smk->pts_inc, (1UL<<31)-1);
00176 avpriv_set_pts_info(st, 33, smk->pts_inc, tbase);
00177 st->duration = smk->frames;
00178
00179 for(i = 0; i < 7; i++) {
00180 smk->indexes[i] = -1;
00181 if (smk->rates[i]) {
00182 ast[i] = avformat_new_stream(s, NULL);
00183 smk->indexes[i] = ast[i]->index;
00184 ast[i]->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00185 if (smk->aflags[i] & SMK_AUD_BINKAUD) {
00186 ast[i]->codec->codec_id = AV_CODEC_ID_BINKAUDIO_RDFT;
00187 } else if (smk->aflags[i] & SMK_AUD_USEDCT) {
00188 ast[i]->codec->codec_id = AV_CODEC_ID_BINKAUDIO_DCT;
00189 } else if (smk->aflags[i] & SMK_AUD_PACKED){
00190 ast[i]->codec->codec_id = AV_CODEC_ID_SMACKAUDIO;
00191 ast[i]->codec->codec_tag = MKTAG('S', 'M', 'K', 'A');
00192 } else {
00193 ast[i]->codec->codec_id = AV_CODEC_ID_PCM_U8;
00194 }
00195 if (smk->aflags[i] & SMK_AUD_STEREO) {
00196 ast[i]->codec->channels = 2;
00197 ast[i]->codec->channel_layout = AV_CH_LAYOUT_STEREO;
00198 } else {
00199 ast[i]->codec->channels = 1;
00200 ast[i]->codec->channel_layout = AV_CH_LAYOUT_MONO;
00201 }
00202 ast[i]->codec->sample_rate = smk->rates[i];
00203 ast[i]->codec->bits_per_coded_sample = (smk->aflags[i] & SMK_AUD_16BITS) ? 16 : 8;
00204 if(ast[i]->codec->bits_per_coded_sample == 16 && ast[i]->codec->codec_id == AV_CODEC_ID_PCM_U8)
00205 ast[i]->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
00206 avpriv_set_pts_info(ast[i], 64, 1, ast[i]->codec->sample_rate
00207 * ast[i]->codec->channels * ast[i]->codec->bits_per_coded_sample / 8);
00208 }
00209 }
00210
00211
00212
00213 st->codec->extradata = av_malloc(smk->treesize + 16 + FF_INPUT_BUFFER_PADDING_SIZE);
00214 st->codec->extradata_size = smk->treesize + 16;
00215 if(!st->codec->extradata){
00216 av_log(s, AV_LOG_ERROR, "Cannot allocate %i bytes of extradata\n", smk->treesize + 16);
00217 av_free(smk->frm_size);
00218 av_free(smk->frm_flags);
00219 return AVERROR(ENOMEM);
00220 }
00221 ret = avio_read(pb, st->codec->extradata + 16, st->codec->extradata_size - 16);
00222 if(ret != st->codec->extradata_size - 16){
00223 av_free(smk->frm_size);
00224 av_free(smk->frm_flags);
00225 return AVERROR(EIO);
00226 }
00227 ((int32_t*)st->codec->extradata)[0] = av_le2ne32(smk->mmap_size);
00228 ((int32_t*)st->codec->extradata)[1] = av_le2ne32(smk->mclr_size);
00229 ((int32_t*)st->codec->extradata)[2] = av_le2ne32(smk->full_size);
00230 ((int32_t*)st->codec->extradata)[3] = av_le2ne32(smk->type_size);
00231
00232 smk->curstream = -1;
00233 smk->nextpos = avio_tell(pb);
00234
00235 return 0;
00236 }
00237
00238
00239 static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt)
00240 {
00241 SmackerContext *smk = s->priv_data;
00242 int flags;
00243 int ret;
00244 int i;
00245 int frame_size = 0;
00246 int palchange = 0;
00247
00248 if (url_feof(s->pb) || smk->cur_frame >= smk->frames)
00249 return AVERROR_EOF;
00250
00251
00252 if(smk->curstream < 0) {
00253 avio_seek(s->pb, smk->nextpos, 0);
00254 frame_size = smk->frm_size[smk->cur_frame] & (~3);
00255 flags = smk->frm_flags[smk->cur_frame];
00256
00257 if(flags & SMACKER_PAL){
00258 int size, sz, t, off, j, pos;
00259 uint8_t *pal = smk->pal;
00260 uint8_t oldpal[768];
00261
00262 memcpy(oldpal, pal, 768);
00263 size = avio_r8(s->pb);
00264 size = size * 4 - 1;
00265 if(size + 1 > frame_size)
00266 return AVERROR_INVALIDDATA;
00267 frame_size -= size;
00268 frame_size--;
00269 sz = 0;
00270 pos = avio_tell(s->pb) + size;
00271 while(sz < 256){
00272 t = avio_r8(s->pb);
00273 if(t & 0x80){
00274 sz += (t & 0x7F) + 1;
00275 pal += ((t & 0x7F) + 1) * 3;
00276 } else if(t & 0x40){
00277 off = avio_r8(s->pb);
00278 j = (t & 0x3F) + 1;
00279 if (off + j > 0xff) {
00280 av_log(s, AV_LOG_ERROR,
00281 "Invalid palette update, offset=%d length=%d extends beyond palette size\n",
00282 off, j);
00283 return AVERROR_INVALIDDATA;
00284 }
00285 off *= 3;
00286 while(j-- && sz < 256) {
00287 *pal++ = oldpal[off + 0];
00288 *pal++ = oldpal[off + 1];
00289 *pal++ = oldpal[off + 2];
00290 sz++;
00291 off += 3;
00292 }
00293 } else {
00294 *pal++ = smk_pal[t];
00295 *pal++ = smk_pal[avio_r8(s->pb) & 0x3F];
00296 *pal++ = smk_pal[avio_r8(s->pb) & 0x3F];
00297 sz++;
00298 }
00299 }
00300 avio_seek(s->pb, pos, 0);
00301 palchange |= 1;
00302 }
00303 flags >>= 1;
00304 smk->curstream = -1;
00305
00306 for(i = 0; i < 7; i++) {
00307 if(flags & 1) {
00308 unsigned int size;
00309 uint8_t *tmpbuf;
00310
00311 size = avio_rl32(s->pb) - 4;
00312 if(size + 4L > frame_size)
00313 return AVERROR_INVALIDDATA;
00314 frame_size -= size;
00315 frame_size -= 4;
00316 smk->curstream++;
00317 tmpbuf = av_realloc(smk->bufs[smk->curstream], size);
00318 if (!tmpbuf)
00319 return AVERROR(ENOMEM);
00320 smk->bufs[smk->curstream] = tmpbuf;
00321 smk->buf_sizes[smk->curstream] = size;
00322 ret = avio_read(s->pb, smk->bufs[smk->curstream], size);
00323 if(ret != size)
00324 return AVERROR(EIO);
00325 smk->stream_id[smk->curstream] = smk->indexes[i];
00326 }
00327 flags >>= 1;
00328 }
00329 if (frame_size < 0)
00330 return AVERROR_INVALIDDATA;
00331 if (av_new_packet(pkt, frame_size + 769))
00332 return AVERROR(ENOMEM);
00333 if(smk->frm_size[smk->cur_frame] & 1)
00334 palchange |= 2;
00335 pkt->data[0] = palchange;
00336 memcpy(pkt->data + 1, smk->pal, 768);
00337 ret = avio_read(s->pb, pkt->data + 769, frame_size);
00338 if(ret != frame_size)
00339 return AVERROR(EIO);
00340 pkt->stream_index = smk->videoindex;
00341 pkt->size = ret + 769;
00342 smk->cur_frame++;
00343 smk->nextpos = avio_tell(s->pb);
00344 } else {
00345 if (av_new_packet(pkt, smk->buf_sizes[smk->curstream]))
00346 return AVERROR(ENOMEM);
00347 memcpy(pkt->data, smk->bufs[smk->curstream], smk->buf_sizes[smk->curstream]);
00348 pkt->size = smk->buf_sizes[smk->curstream];
00349 pkt->stream_index = smk->stream_id[smk->curstream];
00350 pkt->pts = smk->aud_pts[smk->curstream];
00351 smk->aud_pts[smk->curstream] += AV_RL32(pkt->data);
00352 smk->curstream--;
00353 }
00354
00355 return 0;
00356 }
00357
00358 static int smacker_read_close(AVFormatContext *s)
00359 {
00360 SmackerContext *smk = s->priv_data;
00361 int i;
00362
00363 for(i = 0; i < 7; i++)
00364 av_free(smk->bufs[i]);
00365 av_free(smk->frm_size);
00366 av_free(smk->frm_flags);
00367
00368 return 0;
00369 }
00370
00371 AVInputFormat ff_smacker_demuxer = {
00372 .name = "smk",
00373 .long_name = NULL_IF_CONFIG_SMALL("Smacker"),
00374 .priv_data_size = sizeof(SmackerContext),
00375 .read_probe = smacker_probe,
00376 .read_header = smacker_read_header,
00377 .read_packet = smacker_read_packet,
00378 .read_close = smacker_read_close,
00379 };