libavformat/smacker.c
Go to the documentation of this file.
00001 /*
00002  * Smacker demuxer
00003  * Copyright (c) 2006 Konstantin Shishkov
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00022 /*
00023  * Based on http://wiki.multimedia.cx/index.php?title=Smacker
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     /* Smacker file header */
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     /* frame info */
00056     uint32_t *frm_size;
00057     uint8_t  *frm_flags;
00058     /* internal variables */
00059     int cur_frame;
00060     int is_ver4;
00061     int64_t cur_pts;
00062     /* current frame for demuxing */
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 /* palette used in Smacker */
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     /* read and check header */
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){ // smk->treesize + 16 must not overflow (this check is probably redundant)
00125         av_log(s, AV_LOG_ERROR, "treesize too large\n");
00126         return -1;
00127     }
00128 
00129 //FIXME remove extradata "rebuilding"
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     /* setup data */
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     /* read frame info */
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     /* init video codec */
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     /* Smacker uses 100000 as internal timebase */
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     /* handle possible audio streams */
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     /* load trees to extradata, they will be unpacked by decoder */
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     /* if we demuxed all streams, pass another frame */
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         /* handle palette change event */
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){ /* skip palette entries */
00267                     sz += (t & 0x7F) + 1;
00268                     pal += ((t & 0x7F) + 1) * 3;
00269                 } else if(t & 0x40){ /* copy with offset */
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 { /* new entries */
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         /* if audio chunks are present, put them to stack and retrieve later */
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 };