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) * 3;
00271 j = (t & 0x3F) + 1;
00272 while(j-- && sz < 256) {
00273 *pal++ = oldpal[off + 0];
00274 *pal++ = oldpal[off + 1];
00275 *pal++ = oldpal[off + 2];
00276 sz++;
00277 off += 3;
00278 }
00279 } else {
00280 *pal++ = smk_pal[t];
00281 *pal++ = smk_pal[avio_r8(s->pb) & 0x3F];
00282 *pal++ = smk_pal[avio_r8(s->pb) & 0x3F];
00283 sz++;
00284 }
00285 }
00286 avio_seek(s->pb, pos, 0);
00287 palchange |= 1;
00288 }
00289 flags >>= 1;
00290 smk->curstream = -1;
00291
00292 for(i = 0; i < 7; i++) {
00293 if(flags & 1) {
00294 unsigned int size;
00295 uint8_t *tmpbuf;
00296
00297 size = avio_rl32(s->pb) - 4;
00298 if(size + 4L > frame_size)
00299 return AVERROR_INVALIDDATA;
00300 frame_size -= size;
00301 frame_size -= 4;
00302 smk->curstream++;
00303 tmpbuf = av_realloc(smk->bufs[smk->curstream], size);
00304 if (!tmpbuf)
00305 return AVERROR(ENOMEM);
00306 smk->bufs[smk->curstream] = tmpbuf;
00307 smk->buf_sizes[smk->curstream] = size;
00308 ret = avio_read(s->pb, smk->bufs[smk->curstream], size);
00309 if(ret != size)
00310 return AVERROR(EIO);
00311 smk->stream_id[smk->curstream] = smk->indexes[i];
00312 }
00313 flags >>= 1;
00314 }
00315 if (frame_size < 0)
00316 return AVERROR_INVALIDDATA;
00317 if (av_new_packet(pkt, frame_size + 769))
00318 return AVERROR(ENOMEM);
00319 if(smk->frm_size[smk->cur_frame] & 1)
00320 palchange |= 2;
00321 pkt->data[0] = palchange;
00322 memcpy(pkt->data + 1, smk->pal, 768);
00323 ret = avio_read(s->pb, pkt->data + 769, frame_size);
00324 if(ret != frame_size)
00325 return AVERROR(EIO);
00326 pkt->stream_index = smk->videoindex;
00327 pkt->size = ret + 769;
00328 smk->cur_frame++;
00329 smk->nextpos = avio_tell(s->pb);
00330 } else {
00331 if (av_new_packet(pkt, smk->buf_sizes[smk->curstream]))
00332 return AVERROR(ENOMEM);
00333 memcpy(pkt->data, smk->bufs[smk->curstream], smk->buf_sizes[smk->curstream]);
00334 pkt->size = smk->buf_sizes[smk->curstream];
00335 pkt->stream_index = smk->stream_id[smk->curstream];
00336 pkt->pts = smk->aud_pts[smk->curstream];
00337 smk->aud_pts[smk->curstream] += AV_RL32(pkt->data);
00338 smk->curstream--;
00339 }
00340
00341 return 0;
00342 }
00343
00344 static int smacker_read_close(AVFormatContext *s)
00345 {
00346 SmackerContext *smk = s->priv_data;
00347 int i;
00348
00349 for(i = 0; i < 7; i++)
00350 av_free(smk->bufs[i]);
00351 av_free(smk->frm_size);
00352 av_free(smk->frm_flags);
00353
00354 return 0;
00355 }
00356
00357 AVInputFormat ff_smacker_demuxer = {
00358 .name = "smk",
00359 .long_name = NULL_IF_CONFIG_SMALL("Smacker video"),
00360 .priv_data_size = sizeof(SmackerContext),
00361 .read_probe = smacker_probe,
00362 .read_header = smacker_read_header,
00363 .read_packet = smacker_read_packet,
00364 .read_close = smacker_read_close,
00365 };