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 Libav.
00006  *
00007  * Libav 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  * Libav 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 Libav; 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_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     /* if we demuxed all streams, pass another frame */
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         /* handle palette change event */
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){ /* skip palette entries */
00266                     sz += (t & 0x7F) + 1;
00267                     pal += ((t & 0x7F) + 1) * 3;
00268                 } else if(t & 0x40){ /* copy with offset */
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 { /* new entries */
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         /* if audio chunks are present, put them to stack and retrieve later */
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 || frame_size >= INT_MAX/2)
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 (smk->stream_id[smk->curstream] < 0)
00340             return AVERROR_INVALIDDATA;
00341         if (av_new_packet(pkt, smk->buf_sizes[smk->curstream]))
00342             return AVERROR(ENOMEM);
00343         memcpy(pkt->data, smk->bufs[smk->curstream], smk->buf_sizes[smk->curstream]);
00344         pkt->size = smk->buf_sizes[smk->curstream];
00345         pkt->stream_index = smk->stream_id[smk->curstream];
00346         pkt->pts = smk->aud_pts[smk->curstream];
00347         smk->aud_pts[smk->curstream] += AV_RL32(pkt->data);
00348         smk->curstream--;
00349     }
00350 
00351     return 0;
00352 }
00353 
00354 static int smacker_read_close(AVFormatContext *s)
00355 {
00356     SmackerContext *smk = s->priv_data;
00357     int i;
00358 
00359     for(i = 0; i < 7; i++)
00360         av_free(smk->bufs[i]);
00361     av_free(smk->frm_size);
00362     av_free(smk->frm_flags);
00363 
00364     return 0;
00365 }
00366 
00367 AVInputFormat ff_smacker_demuxer = {
00368     .name           = "smk",
00369     .long_name      = NULL_IF_CONFIG_SMALL("Smacker video"),
00370     .priv_data_size = sizeof(SmackerContext),
00371     .read_probe     = smacker_probe,
00372     .read_header    = smacker_read_header,
00373     .read_packet    = smacker_read_packet,
00374     .read_close     = smacker_read_close,
00375 };