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_mallocz(smk->treesize + 16 +
00207 FF_INPUT_BUFFER_PADDING_SIZE);
00208 st->codec->extradata_size = smk->treesize + 16;
00209 if(!st->codec->extradata){
00210 av_log(s, AV_LOG_ERROR, "Cannot allocate %i bytes of extradata\n", smk->treesize + 16);
00211 av_free(smk->frm_size);
00212 av_free(smk->frm_flags);
00213 return -1;
00214 }
00215 ret = avio_read(pb, st->codec->extradata + 16, st->codec->extradata_size - 16);
00216 if(ret != st->codec->extradata_size - 16){
00217 av_free(smk->frm_size);
00218 av_free(smk->frm_flags);
00219 return AVERROR(EIO);
00220 }
00221 ((int32_t*)st->codec->extradata)[0] = av_le2ne32(smk->mmap_size);
00222 ((int32_t*)st->codec->extradata)[1] = av_le2ne32(smk->mclr_size);
00223 ((int32_t*)st->codec->extradata)[2] = av_le2ne32(smk->full_size);
00224 ((int32_t*)st->codec->extradata)[3] = av_le2ne32(smk->type_size);
00225
00226 smk->curstream = -1;
00227 smk->nextpos = avio_tell(pb);
00228
00229 return 0;
00230 }
00231
00232
00233 static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt)
00234 {
00235 SmackerContext *smk = s->priv_data;
00236 int flags;
00237 int ret;
00238 int i;
00239 int frame_size = 0;
00240 int palchange = 0;
00241
00242 if (s->pb->eof_reached || smk->cur_frame >= smk->frames)
00243 return AVERROR_EOF;
00244
00245
00246 if(smk->curstream < 0) {
00247 avio_seek(s->pb, smk->nextpos, 0);
00248 frame_size = smk->frm_size[smk->cur_frame] & (~3);
00249 flags = smk->frm_flags[smk->cur_frame];
00250
00251 if(flags & SMACKER_PAL){
00252 int size, sz, t, off, j, pos;
00253 uint8_t *pal = smk->pal;
00254 uint8_t oldpal[768];
00255
00256 memcpy(oldpal, pal, 768);
00257 size = avio_r8(s->pb);
00258 size = size * 4 - 1;
00259 frame_size -= size;
00260 frame_size--;
00261 sz = 0;
00262 pos = avio_tell(s->pb) + size;
00263 while(sz < 256){
00264 t = avio_r8(s->pb);
00265 if(t & 0x80){
00266 sz += (t & 0x7F) + 1;
00267 pal += ((t & 0x7F) + 1) * 3;
00268 } else if(t & 0x40){
00269 off = avio_r8(s->pb);
00270 j = (t & 0x3F) + 1;
00271 if (off + j > 0xff) {
00272 av_log(s, AV_LOG_ERROR,
00273 "Invalid palette update, offset=%d length=%d extends beyond palette size\n",
00274 off, j);
00275 return AVERROR_INVALIDDATA;
00276 }
00277 off *= 3;
00278 while(j-- && sz < 256) {
00279 *pal++ = oldpal[off + 0];
00280 *pal++ = oldpal[off + 1];
00281 *pal++ = oldpal[off + 2];
00282 sz++;
00283 off += 3;
00284 }
00285 } else {
00286 *pal++ = smk_pal[t];
00287 *pal++ = smk_pal[avio_r8(s->pb) & 0x3F];
00288 *pal++ = smk_pal[avio_r8(s->pb) & 0x3F];
00289 sz++;
00290 }
00291 }
00292 avio_seek(s->pb, pos, 0);
00293 palchange |= 1;
00294 }
00295 flags >>= 1;
00296 smk->curstream = -1;
00297
00298 for(i = 0; i < 7; i++) {
00299 if(flags & 1) {
00300 uint32_t size;
00301 uint8_t *tmpbuf;
00302
00303 size = avio_rl32(s->pb) - 4;
00304 if (!size || size > frame_size) {
00305 av_log(s, AV_LOG_ERROR, "Invalid audio part size\n");
00306 return AVERROR_INVALIDDATA;
00307 }
00308 frame_size -= size;
00309 frame_size -= 4;
00310 smk->curstream++;
00311 tmpbuf = av_realloc(smk->bufs[smk->curstream], size);
00312 if (!tmpbuf)
00313 return AVERROR(ENOMEM);
00314 smk->bufs[smk->curstream] = tmpbuf;
00315 smk->buf_sizes[smk->curstream] = size;
00316 ret = avio_read(s->pb, smk->bufs[smk->curstream], size);
00317 if(ret != size)
00318 return AVERROR(EIO);
00319 smk->stream_id[smk->curstream] = smk->indexes[i];
00320 }
00321 flags >>= 1;
00322 }
00323 if (frame_size < 0)
00324 return AVERROR_INVALIDDATA;
00325 if (av_new_packet(pkt, frame_size + 769))
00326 return AVERROR(ENOMEM);
00327 if(smk->frm_size[smk->cur_frame] & 1)
00328 palchange |= 2;
00329 pkt->data[0] = palchange;
00330 memcpy(pkt->data + 1, smk->pal, 768);
00331 ret = avio_read(s->pb, pkt->data + 769, frame_size);
00332 if(ret != frame_size)
00333 return AVERROR(EIO);
00334 pkt->stream_index = smk->videoindex;
00335 pkt->size = ret + 769;
00336 smk->cur_frame++;
00337 smk->nextpos = avio_tell(s->pb);
00338 } else {
00339 if (av_new_packet(pkt, smk->buf_sizes[smk->curstream]))
00340 return AVERROR(ENOMEM);
00341 memcpy(pkt->data, smk->bufs[smk->curstream], smk->buf_sizes[smk->curstream]);
00342 pkt->size = smk->buf_sizes[smk->curstream];
00343 pkt->stream_index = smk->stream_id[smk->curstream];
00344 pkt->pts = smk->aud_pts[smk->curstream];
00345 smk->aud_pts[smk->curstream] += AV_RL32(pkt->data);
00346 smk->curstream--;
00347 }
00348
00349 return 0;
00350 }
00351
00352 static int smacker_read_close(AVFormatContext *s)
00353 {
00354 SmackerContext *smk = s->priv_data;
00355 int i;
00356
00357 for(i = 0; i < 7; i++)
00358 av_free(smk->bufs[i]);
00359 av_free(smk->frm_size);
00360 av_free(smk->frm_flags);
00361
00362 return 0;
00363 }
00364
00365 AVInputFormat ff_smacker_demuxer = {
00366 .name = "smk",
00367 .long_name = NULL_IF_CONFIG_SMALL("Smacker video"),
00368 .priv_data_size = sizeof(SmackerContext),
00369 .read_probe = smacker_probe,
00370 .read_header = smacker_read_header,
00371 .read_packet = smacker_read_packet,
00372 .read_close = smacker_read_close,
00373 };