3 * Copyright (c) 2006 Konstantin Shishkov.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * Based on http://wiki.multimedia.cx/index.php?title=Smacker
28 #define SMACKER_PAL 0x01
31 SMK_AUD_PACKED
= 0x80000000,
32 SMK_AUD_16BITS
= 0x20000000,
33 SMK_AUD_STEREO
= 0x10000000,
34 SMK_AUD_BINKAUD
= 0x08000000,
35 SMK_AUD_USEDCT
= 0x04000000
38 typedef struct SmackerContext
{
39 /* Smacker file header */
41 uint32_t width
, height
;
47 uint32_t mmap_size
, mclr_size
, full_size
, type_size
;
53 /* internal variables */
57 /* current frame for demuxing */
69 typedef struct SmackerFrame
{
74 /* palette used in Smacker */
75 static const uint8_t smk_pal
[64] = {
76 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C,
77 0x20, 0x24, 0x28, 0x2C, 0x30, 0x34, 0x38, 0x3C,
78 0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D,
79 0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D,
80 0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E,
81 0xA2, 0xA6, 0xAA, 0xAE, 0xB2, 0xB6, 0xBA, 0xBE,
82 0xC3, 0xC7, 0xCB, 0xCF, 0xD3, 0xD7, 0xDB, 0xDF,
83 0xE3, 0xE7, 0xEB, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF
87 static int smacker_probe(AVProbeData
*p
)
91 if(p
->buf
[0] == 'S' && p
->buf
[1] == 'M' && p
->buf
[2] == 'K'
92 && (p
->buf
[3] == '2' || p
->buf
[3] == '4'))
93 return AVPROBE_SCORE_MAX
;
98 static int smacker_read_header(AVFormatContext
*s
, AVFormatParameters
*ap
)
100 ByteIOContext
*pb
= &s
->pb
;
101 SmackerContext
*smk
= (SmackerContext
*)s
->priv_data
;
102 AVStream
*st
, *ast
[7];
106 /* read and check header */
107 smk
->magic
= get_le32(pb
);
108 if (smk
->magic
!= MKTAG('S', 'M', 'K', '2') && smk
->magic
!= MKTAG('S', 'M', 'K', '4'))
110 smk
->width
= get_le32(pb
);
111 smk
->height
= get_le32(pb
);
112 smk
->frames
= get_le32(pb
);
113 smk
->pts_inc
= (int32_t)get_le32(pb
);
114 smk
->flags
= get_le32(pb
);
115 for(i
= 0; i
< 7; i
++)
116 smk
->audio
[i
] = get_le32(pb
);
117 smk
->treesize
= get_le32(pb
);
119 if(smk
->treesize
>= UINT_MAX
/4){ // smk->treesize + 16 must not overflow (this check is probably redundant)
120 av_log(s
, AV_LOG_ERROR
, "treesize too large\n");
124 //FIXME remove extradata "rebuilding"
125 smk
->mmap_size
= get_le32(pb
);
126 smk
->mclr_size
= get_le32(pb
);
127 smk
->full_size
= get_le32(pb
);
128 smk
->type_size
= get_le32(pb
);
129 for(i
= 0; i
< 7; i
++)
130 smk
->rates
[i
] = get_le32(pb
);
131 smk
->pad
= get_le32(pb
);
133 if(smk
->frames
> 0xFFFFFF) {
134 av_log(s
, AV_LOG_ERROR
, "Too many frames: %i\n", smk
->frames
);
137 smk
->frm_size
= av_malloc(smk
->frames
* 4);
138 smk
->frm_flags
= av_malloc(smk
->frames
);
140 smk
->is_ver4
= (smk
->magic
!= MKTAG('S', 'M', 'K', '2'));
142 /* read frame info */
143 for(i
= 0; i
< smk
->frames
; i
++) {
144 smk
->frm_size
[i
] = get_le32(pb
);
146 for(i
= 0; i
< smk
->frames
; i
++) {
147 smk
->frm_flags
[i
] = get_byte(pb
);
150 /* init video codec */
151 st
= av_new_stream(s
, 0);
154 smk
->videoindex
= st
->index
;
155 st
->codec
->width
= smk
->width
;
156 st
->codec
->height
= smk
->height
;
157 st
->codec
->pix_fmt
= PIX_FMT_PAL8
;
158 st
->codec
->codec_type
= CODEC_TYPE_VIDEO
;
159 st
->codec
->codec_id
= CODEC_ID_SMACKVIDEO
;
160 st
->codec
->codec_tag
= smk
->magic
;
161 /* Smacker uses 100000 as internal timebase */
163 smk
->pts_inc
= -smk
->pts_inc
;
167 av_reduce(&tbase
, &smk
->pts_inc
, tbase
, smk
->pts_inc
, (1UL<<31)-1);
168 av_set_pts_info(st
, 33, smk
->pts_inc
, tbase
);
169 /* handle possible audio streams */
170 for(i
= 0; i
< 7; i
++) {
171 smk
->indexes
[i
] = -1;
172 if((smk
->rates
[i
] & 0xFFFFFF) && !(smk
->rates
[i
] & SMK_AUD_BINKAUD
)){
173 ast
[i
] = av_new_stream(s
, 0);
174 smk
->indexes
[i
] = ast
[i
]->index
;
175 ast
[i
]->codec
->codec_type
= CODEC_TYPE_AUDIO
;
176 ast
[i
]->codec
->codec_id
= (smk
->rates
[i
] & SMK_AUD_PACKED
) ? CODEC_ID_SMACKAUDIO
: CODEC_ID_PCM_U8
;
177 ast
[i
]->codec
->codec_tag
= MKTAG('S', 'M', 'K', 'A');
178 ast
[i
]->codec
->channels
= (smk
->rates
[i
] & SMK_AUD_STEREO
) ? 2 : 1;
179 ast
[i
]->codec
->sample_rate
= smk
->rates
[i
] & 0xFFFFFF;
180 ast
[i
]->codec
->bits_per_sample
= (smk
->rates
[i
] & SMK_AUD_16BITS
) ? 16 : 8;
181 if(ast
[i
]->codec
->bits_per_sample
== 16 && ast
[i
]->codec
->codec_id
== CODEC_ID_PCM_U8
)
182 ast
[i
]->codec
->codec_id
= CODEC_ID_PCM_S16LE
;
183 av_set_pts_info(ast
[i
], 64, 1, ast
[i
]->codec
->sample_rate
184 * ast
[i
]->codec
->channels
* ast
[i
]->codec
->bits_per_sample
/ 8);
189 /* load trees to extradata, they will be unpacked by decoder */
190 st
->codec
->extradata
= av_malloc(smk
->treesize
+ 16);
191 st
->codec
->extradata_size
= smk
->treesize
+ 16;
192 if(!st
->codec
->extradata
){
193 av_log(s
, AV_LOG_ERROR
, "Cannot allocate %i bytes of extradata\n", smk
->treesize
+ 16);
194 av_free(smk
->frm_size
);
195 av_free(smk
->frm_flags
);
198 ret
= get_buffer(pb
, st
->codec
->extradata
+ 16, st
->codec
->extradata_size
- 16);
199 if(ret
!= st
->codec
->extradata_size
- 16){
200 av_free(smk
->frm_size
);
201 av_free(smk
->frm_flags
);
204 ((int32_t*)st
->codec
->extradata
)[0] = le2me_32(smk
->mmap_size
);
205 ((int32_t*)st
->codec
->extradata
)[1] = le2me_32(smk
->mclr_size
);
206 ((int32_t*)st
->codec
->extradata
)[2] = le2me_32(smk
->full_size
);
207 ((int32_t*)st
->codec
->extradata
)[3] = le2me_32(smk
->type_size
);
210 smk
->nextpos
= url_ftell(pb
);
216 static int smacker_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
218 SmackerContext
*smk
= (SmackerContext
*)s
->priv_data
;
226 if (url_feof(&s
->pb
) || smk
->cur_frame
>= smk
->frames
)
229 /* if we demuxed all streams, pass another frame */
230 if(smk
->curstream
< 0) {
231 url_fseek(&s
->pb
, smk
->nextpos
, 0);
232 frame_size
= smk
->frm_size
[smk
->cur_frame
] & (~3);
233 flags
= smk
->frm_flags
[smk
->cur_frame
];
234 /* handle palette change event */
235 pos
= url_ftell(&s
->pb
);
236 if(flags
& SMACKER_PAL
){
237 int size
, sz
, t
, off
, j
, pos
;
238 uint8_t *pal
= smk
->pal
;
241 memcpy(oldpal
, pal
, 768);
242 size
= get_byte(&s
->pb
);
247 pos
= url_ftell(&s
->pb
) + size
;
249 t
= get_byte(&s
->pb
);
250 if(t
& 0x80){ /* skip palette entries */
251 sz
+= (t
& 0x7F) + 1;
252 pal
+= ((t
& 0x7F) + 1) * 3;
253 } else if(t
& 0x40){ /* copy with offset */
254 off
= get_byte(&s
->pb
) * 3;
256 while(j
-- && sz
< 256) {
257 *pal
++ = oldpal
[off
+ 0];
258 *pal
++ = oldpal
[off
+ 1];
259 *pal
++ = oldpal
[off
+ 2];
263 } else { /* new entries */
265 *pal
++ = smk_pal
[get_byte(&s
->pb
) & 0x3F];
266 *pal
++ = smk_pal
[get_byte(&s
->pb
) & 0x3F];
270 url_fseek(&s
->pb
, pos
, 0);
275 /* if audio chunks are present, put them to stack and retrieve later */
276 for(i
= 0; i
< 7; i
++) {
279 size
= get_le32(&s
->pb
) - 4;
283 smk
->bufs
[smk
->curstream
] = av_realloc(smk
->bufs
[smk
->curstream
], size
);
284 smk
->buf_sizes
[smk
->curstream
] = size
;
285 ret
= get_buffer(&s
->pb
, smk
->bufs
[smk
->curstream
], size
);
288 smk
->stream_id
[smk
->curstream
] = smk
->indexes
[i
];
292 if (av_new_packet(pkt
, frame_size
+ 768))
293 return AVERROR_NOMEM
;
294 if(smk
->frm_size
[smk
->cur_frame
] & 1)
296 pkt
->data
[0] = palchange
;
297 memcpy(pkt
->data
+ 1, smk
->pal
, 768);
298 ret
= get_buffer(&s
->pb
, pkt
->data
+ 769, frame_size
);
299 if(ret
!= frame_size
)
301 pkt
->stream_index
= smk
->videoindex
;
302 pkt
->size
= ret
+ 769;
304 smk
->nextpos
= url_ftell(&s
->pb
);
306 if (av_new_packet(pkt
, smk
->buf_sizes
[smk
->curstream
]))
307 return AVERROR_NOMEM
;
308 memcpy(pkt
->data
, smk
->bufs
[smk
->curstream
], smk
->buf_sizes
[smk
->curstream
]);
309 pkt
->size
= smk
->buf_sizes
[smk
->curstream
];
310 pkt
->stream_index
= smk
->stream_id
[smk
->curstream
];
311 pkt
->pts
= smk
->aud_pts
[smk
->curstream
];
312 smk
->aud_pts
[smk
->curstream
] += LE_32(pkt
->data
);
319 static int smacker_read_close(AVFormatContext
*s
)
321 SmackerContext
*smk
= (SmackerContext
*)s
->priv_data
;
324 for(i
= 0; i
< 7; i
++)
326 av_free(smk
->bufs
[i
]);
328 av_free(smk
->frm_size
);
330 av_free(smk
->frm_flags
);
335 AVInputFormat smacker_demuxer
= {
338 sizeof(SmackerContext
),