• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

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 
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     /* Smacker file header */
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     /* frame info */
00054     uint32_t *frm_size;
00055     uint8_t  *frm_flags;
00056     /* internal variables */
00057     int cur_frame;
00058     int is_ver4;
00059     int64_t cur_pts;
00060     /* current frame for demuxing */
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 /* palette used in Smacker */
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     /* read and check header */
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){ // smk->treesize + 16 must not overflow (this check is probably redundant)
00123         av_log(s, AV_LOG_ERROR, "treesize too large\n");
00124         return -1;
00125     }
00126 
00127 //FIXME remove extradata "rebuilding"
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     /* setup data */
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     /* read frame info */
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     /* init video codec */
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     /* Smacker uses 100000 as internal timebase */
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     /* handle possible audio streams */
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     /* load trees to extradata, they will be unpacked by decoder */
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     /* if we demuxed all streams, pass another frame */
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         /* handle palette change event */
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){ /* skip palette entries */
00254                     sz += (t & 0x7F) + 1;
00255                     pal += ((t & 0x7F) + 1) * 3;
00256                 } else if(t & 0x40){ /* copy with offset */
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 { /* new entries */
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         /* if audio chunks are present, put them to stack and retrieve later */
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                 smk->buf_sizes[smk->curstream] = size;
00288                 ret = get_buffer(s->pb, smk->bufs[smk->curstream], size);
00289                 if(ret != size)
00290                     return AVERROR(EIO);
00291                 smk->stream_id[smk->curstream] = smk->indexes[i];
00292             }
00293             flags >>= 1;
00294         }
00295         if (av_new_packet(pkt, frame_size + 768))
00296             return AVERROR(ENOMEM);
00297         if(smk->frm_size[smk->cur_frame] & 1)
00298             palchange |= 2;
00299         pkt->data[0] = palchange;
00300         memcpy(pkt->data + 1, smk->pal, 768);
00301         ret = get_buffer(s->pb, pkt->data + 769, frame_size);
00302         if(ret != frame_size)
00303             return AVERROR(EIO);
00304         pkt->stream_index = smk->videoindex;
00305         pkt->size = ret + 769;
00306         smk->cur_frame++;
00307         smk->nextpos = url_ftell(s->pb);
00308     } else {
00309         if (av_new_packet(pkt, smk->buf_sizes[smk->curstream]))
00310             return AVERROR(ENOMEM);
00311         memcpy(pkt->data, smk->bufs[smk->curstream], smk->buf_sizes[smk->curstream]);
00312         pkt->size = smk->buf_sizes[smk->curstream];
00313         pkt->stream_index = smk->stream_id[smk->curstream];
00314         pkt->pts = smk->aud_pts[smk->curstream];
00315         smk->aud_pts[smk->curstream] += AV_RL32(pkt->data);
00316         smk->curstream--;
00317     }
00318 
00319     return 0;
00320 }
00321 
00322 static int smacker_read_close(AVFormatContext *s)
00323 {
00324     SmackerContext *smk = s->priv_data;
00325     int i;
00326 
00327     for(i = 0; i < 7; i++)
00328         if(smk->bufs[i])
00329             av_free(smk->bufs[i]);
00330     if(smk->frm_size)
00331         av_free(smk->frm_size);
00332     if(smk->frm_flags)
00333         av_free(smk->frm_flags);
00334 
00335     return 0;
00336 }
00337 
00338 AVInputFormat smacker_demuxer = {
00339     "smk",
00340     NULL_IF_CONFIG_SMALL("Smacker video"),
00341     sizeof(SmackerContext),
00342     smacker_probe,
00343     smacker_read_header,
00344     smacker_read_packet,
00345     smacker_read_close,
00346 };

Generated on Tue Nov 4 2014 12:59:22 for ffmpeg by  doxygen 1.7.1