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