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
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
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
00054 uint32_t *frm_size;
00055 uint8_t *frm_flags;
00056
00057 int cur_frame;
00058 int is_ver4;
00059 int64_t cur_pts;
00060
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
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 ByteIOContext *pb = s->pb;
00102 SmackerContext *smk = s->priv_data;
00103 AVStream *st, *ast[7];
00104 int i, ret;
00105 int tbase;
00106
00107
00108 smk->magic = get_le32(pb);
00109 if (smk->magic != MKTAG('S', 'M', 'K', '2') && smk->magic != MKTAG('S', 'M', 'K', '4'))
00110 return -1;
00111 smk->width = get_le32(pb);
00112 smk->height = get_le32(pb);
00113 smk->frames = get_le32(pb);
00114 smk->pts_inc = (int32_t)get_le32(pb);
00115 smk->flags = get_le32(pb);
00116 if(smk->flags & SMACKER_FLAG_RING_FRAME)
00117 smk->frames++;
00118 for(i = 0; i < 7; i++)
00119 smk->audio[i] = get_le32(pb);
00120 smk->treesize = get_le32(pb);
00121
00122 if(smk->treesize >= UINT_MAX/4){
00123 av_log(s, AV_LOG_ERROR, "treesize too large\n");
00124 return -1;
00125 }
00126
00127
00128 smk->mmap_size = get_le32(pb);
00129 smk->mclr_size = get_le32(pb);
00130 smk->full_size = get_le32(pb);
00131 smk->type_size = get_le32(pb);
00132 for(i = 0; i < 7; i++)
00133 smk->rates[i] = get_le32(pb);
00134 smk->pad = get_le32(pb);
00135
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
00146 for(i = 0; i < smk->frames; i++) {
00147 smk->frm_size[i] = get_le32(pb);
00148 }
00149 for(i = 0; i < smk->frames; i++) {
00150 smk->frm_flags[i] = get_byte(pb);
00151 }
00152
00153
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 = CODEC_TYPE_VIDEO;
00162 st->codec->codec_id = CODEC_ID_SMACKVIDEO;
00163 st->codec->codec_tag = smk->magic;
00164
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
00173 for(i = 0; i < 7; i++) {
00174 smk->indexes[i] = -1;
00175 if((smk->rates[i] & 0xFFFFFF) && !(smk->rates[i] & SMK_AUD_BINKAUD)){
00176 ast[i] = av_new_stream(s, 0);
00177 smk->indexes[i] = ast[i]->index;
00178 ast[i]->codec->codec_type = CODEC_TYPE_AUDIO;
00179 ast[i]->codec->codec_id = (smk->rates[i] & SMK_AUD_PACKED) ? CODEC_ID_SMACKAUDIO : CODEC_ID_PCM_U8;
00180 ast[i]->codec->codec_tag = MKTAG('S', 'M', 'K', 'A');
00181 ast[i]->codec->channels = (smk->rates[i] & SMK_AUD_STEREO) ? 2 : 1;
00182 ast[i]->codec->sample_rate = smk->rates[i] & 0xFFFFFF;
00183 ast[i]->codec->bits_per_coded_sample = (smk->rates[i] & SMK_AUD_16BITS) ? 16 : 8;
00184 if(ast[i]->codec->bits_per_coded_sample == 16 && ast[i]->codec->codec_id == CODEC_ID_PCM_U8)
00185 ast[i]->codec->codec_id = CODEC_ID_PCM_S16LE;
00186 av_set_pts_info(ast[i], 64, 1, ast[i]->codec->sample_rate
00187 * ast[i]->codec->channels * ast[i]->codec->bits_per_coded_sample / 8);
00188 }
00189 }
00190
00191
00192
00193 st->codec->extradata = av_malloc(smk->treesize + 16);
00194 st->codec->extradata_size = smk->treesize + 16;
00195 if(!st->codec->extradata){
00196 av_log(s, AV_LOG_ERROR, "Cannot allocate %i bytes of extradata\n", smk->treesize + 16);
00197 av_free(smk->frm_size);
00198 av_free(smk->frm_flags);
00199 return -1;
00200 }
00201 ret = get_buffer(pb, st->codec->extradata + 16, st->codec->extradata_size - 16);
00202 if(ret != st->codec->extradata_size - 16){
00203 av_free(smk->frm_size);
00204 av_free(smk->frm_flags);
00205 return AVERROR(EIO);
00206 }
00207 ((int32_t*)st->codec->extradata)[0] = le2me_32(smk->mmap_size);
00208 ((int32_t*)st->codec->extradata)[1] = le2me_32(smk->mclr_size);
00209 ((int32_t*)st->codec->extradata)[2] = le2me_32(smk->full_size);
00210 ((int32_t*)st->codec->extradata)[3] = le2me_32(smk->type_size);
00211
00212 smk->curstream = -1;
00213 smk->nextpos = url_ftell(pb);
00214
00215 return 0;
00216 }
00217
00218
00219 static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt)
00220 {
00221 SmackerContext *smk = s->priv_data;
00222 int flags;
00223 int ret;
00224 int i;
00225 int frame_size = 0;
00226 int palchange = 0;
00227 int pos;
00228
00229 if (url_feof(s->pb) || smk->cur_frame >= smk->frames)
00230 return AVERROR(EIO);
00231
00232
00233 if(smk->curstream < 0) {
00234 url_fseek(s->pb, smk->nextpos, 0);
00235 frame_size = smk->frm_size[smk->cur_frame] & (~3);
00236 flags = smk->frm_flags[smk->cur_frame];
00237
00238 pos = url_ftell(s->pb);
00239 if(flags & SMACKER_PAL){
00240 int size, sz, t, off, j, pos;
00241 uint8_t *pal = smk->pal;
00242 uint8_t oldpal[768];
00243
00244 memcpy(oldpal, pal, 768);
00245 size = get_byte(s->pb);
00246 size = size * 4 - 1;
00247 frame_size -= size;
00248 frame_size--;
00249 sz = 0;
00250 pos = url_ftell(s->pb) + size;
00251 while(sz < 256){
00252 t = get_byte(s->pb);
00253 if(t & 0x80){
00254 sz += (t & 0x7F) + 1;
00255 pal += ((t & 0x7F) + 1) * 3;
00256 } else if(t & 0x40){
00257 off = get_byte(s->pb) * 3;
00258 j = (t & 0x3F) + 1;
00259 while(j-- && sz < 256) {
00260 *pal++ = oldpal[off + 0];
00261 *pal++ = oldpal[off + 1];
00262 *pal++ = oldpal[off + 2];
00263 sz++;
00264 off += 3;
00265 }
00266 } else {
00267 *pal++ = smk_pal[t];
00268 *pal++ = smk_pal[get_byte(s->pb) & 0x3F];
00269 *pal++ = smk_pal[get_byte(s->pb) & 0x3F];
00270 sz++;
00271 }
00272 }
00273 url_fseek(s->pb, pos, 0);
00274 palchange |= 1;
00275 }
00276 flags >>= 1;
00277 smk->curstream = -1;
00278
00279 for(i = 0; i < 7; i++) {
00280 if(flags & 1) {
00281 int size;
00282 size = get_le32(s->pb) - 4;
00283 frame_size -= size;
00284 frame_size -= 4;
00285 smk->curstream++;
00286 smk->bufs[smk->curstream] = av_realloc(smk->bufs[smk->curstream], size);
00287 if (!smk->bufs[smk->curstream]) {
00288 smk->buf_sizes[smk->curstream] = 0;
00289 return AVERROR(ENOMEM);
00290 }
00291 smk->buf_sizes[smk->curstream] = size;
00292 ret = get_buffer(s->pb, smk->bufs[smk->curstream], size);
00293 if(ret != size)
00294 return AVERROR(EIO);
00295 smk->stream_id[smk->curstream] = smk->indexes[i];
00296 }
00297 flags >>= 1;
00298 }
00299 if (frame_size < 0)
00300 return AVERROR_INVALIDDATA;
00301 if (av_new_packet(pkt, frame_size + 769))
00302 return AVERROR(ENOMEM);
00303 if(smk->frm_size[smk->cur_frame] & 1)
00304 palchange |= 2;
00305 pkt->data[0] = palchange;
00306 memcpy(pkt->data + 1, smk->pal, 768);
00307 ret = get_buffer(s->pb, pkt->data + 769, frame_size);
00308 if(ret != frame_size)
00309 return AVERROR(EIO);
00310 pkt->stream_index = smk->videoindex;
00311 pkt->size = ret + 769;
00312 smk->cur_frame++;
00313 smk->nextpos = url_ftell(s->pb);
00314 } else {
00315 if (av_new_packet(pkt, smk->buf_sizes[smk->curstream]))
00316 return AVERROR(ENOMEM);
00317 memcpy(pkt->data, smk->bufs[smk->curstream], smk->buf_sizes[smk->curstream]);
00318 pkt->size = smk->buf_sizes[smk->curstream];
00319 pkt->stream_index = smk->stream_id[smk->curstream];
00320 pkt->pts = smk->aud_pts[smk->curstream];
00321 smk->aud_pts[smk->curstream] += AV_RL32(pkt->data);
00322 smk->curstream--;
00323 }
00324
00325 return 0;
00326 }
00327
00328 static int smacker_read_close(AVFormatContext *s)
00329 {
00330 SmackerContext *smk = s->priv_data;
00331 int i;
00332
00333 for(i = 0; i < 7; i++)
00334 if(smk->bufs[i])
00335 av_free(smk->bufs[i]);
00336 if(smk->frm_size)
00337 av_free(smk->frm_size);
00338 if(smk->frm_flags)
00339 av_free(smk->frm_flags);
00340
00341 return 0;
00342 }
00343
00344 AVInputFormat smacker_demuxer = {
00345 "smk",
00346 NULL_IF_CONFIG_SMALL("Smacker video"),
00347 sizeof(SmackerContext),
00348 smacker_probe,
00349 smacker_read_header,
00350 smacker_read_packet,
00351 smacker_read_close,
00352 };