3 * Copyright (c) 2006 Konstantin Shishkov
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * Based on http://wiki.multimedia.cx/index.php?title=Smacker
28 #include "libavutil/channel_layout.h"
29 #include "libavutil/intreadwrite.h"
30 #include "libavutil/mem.h"
32 #include "avio_internal.h"
36 #define SMACKER_PAL 0x01
37 #define SMACKER_FLAG_RING_FRAME 0x01
38 #define SMACKER_FLAG_Y_INTERLACE (1 << 1)
39 #define SMACKER_FLAG_Y_DOUBLE (1 << 2)
42 SMK_AUD_PACKED
= 0x80,
43 SMK_AUD_16BITS
= 0x20,
44 SMK_AUD_STEREO
= 0x10,
45 SMK_AUD_BINKAUD
= 0x08,
49 typedef struct SmackerContext
{
54 /* internal variables */
55 int64_t next_frame_pos
;
60 /* current frame for demuxing */
69 /* palette used in Smacker */
70 static const uint8_t smk_pal
[64] = {
71 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C,
72 0x20, 0x24, 0x28, 0x2C, 0x30, 0x34, 0x38, 0x3C,
73 0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D,
74 0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D,
75 0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E,
76 0xA2, 0xA6, 0xAA, 0xAE, 0xB2, 0xB6, 0xBA, 0xBE,
77 0xC3, 0xC7, 0xCB, 0xCF, 0xD3, 0xD7, 0xDB, 0xDF,
78 0xE3, 0xE7, 0xEB, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF
82 static int smacker_probe(const AVProbeData
*p
)
84 if ( AV_RL32(p
->buf
) != MKTAG('S', 'M', 'K', '2')
85 && AV_RL32(p
->buf
) != MKTAG('S', 'M', 'K', '4'))
88 if (AV_RL32(p
->buf
+4) > 32768U || AV_RL32(p
->buf
+8) > 32768U)
89 return AVPROBE_SCORE_MAX
/4;
91 return AVPROBE_SCORE_MAX
;
94 static int smacker_read_header(AVFormatContext
*s
)
96 AVIOContext
*pb
= s
->pb
;
97 SmackerContext
*smk
= s
->priv_data
;
99 AVCodecParameters
*par
;
100 uint32_t magic
, width
, height
, flags
, treesize
;
105 /* read and check header */
106 magic
= avio_rl32(pb
);
107 if (magic
!= MKTAG('S', 'M', 'K', '2') && magic
!= MKTAG('S', 'M', 'K', '4'))
108 return AVERROR_INVALIDDATA
;
109 width
= avio_rl32(pb
);
110 height
= avio_rl32(pb
);
111 smk
->frames
= avio_rl32(pb
);
112 pts_inc
= avio_rl32(pb
);
113 if (pts_inc
> INT_MAX
/ 100 || pts_inc
== INT_MIN
) {
114 av_log(s
, AV_LOG_ERROR
, "pts_inc %d is invalid\n", pts_inc
);
115 return AVERROR_INVALIDDATA
;
118 flags
= avio_rl32(pb
);
119 if (flags
& SMACKER_FLAG_RING_FRAME
)
121 if (smk
->frames
> 0xFFFFFF) {
122 av_log(s
, AV_LOG_ERROR
, "Too many frames: %"PRIu32
"\n", smk
->frames
);
123 return AVERROR_INVALIDDATA
;
126 avio_skip(pb
, 28); /* Unused audio related data */
128 treesize
= avio_rl32(pb
);
129 if (treesize
>= UINT_MAX
/4) {
130 // treesize + 16 must not overflow (this check is probably redundant)
131 av_log(s
, AV_LOG_ERROR
, "treesize too large\n");
132 return AVERROR_INVALIDDATA
;
135 st
= avformat_new_stream(s
, NULL
);
137 return AVERROR(ENOMEM
);
139 smk
->videoindex
= st
->index
;
140 /* Smacker uses 100000 as internal timebase */
146 av_reduce(&tbase
, &pts_inc
, tbase
, pts_inc
, (1UL << 31) - 1);
147 avpriv_set_pts_info(st
, 33, pts_inc
, tbase
);
148 st
->duration
= smk
->frames
;
150 st
->sample_aspect_ratio
= (AVRational
){ 1, 1 +
151 !!(flags
& (SMACKER_FLAG_Y_INTERLACE
| SMACKER_FLAG_Y_DOUBLE
)) };
153 /* init video codec */
156 par
->height
= height
;
157 par
->format
= AV_PIX_FMT_PAL8
;
158 par
->codec_type
= AVMEDIA_TYPE_VIDEO
;
159 par
->codec_id
= AV_CODEC_ID_SMACKVIDEO
;
160 par
->codec_tag
= magic
;
162 if ((ret
= ff_alloc_extradata(par
, treesize
+ 16)) < 0) {
163 av_log(s
, AV_LOG_ERROR
,
164 "Cannot allocate %"PRIu32
" bytes of extradata\n",
168 if ((ret
= ffio_read_size(pb
, par
->extradata
, 16)) < 0)
171 /* handle possible audio streams */
172 for (i
= 0; i
< 7; i
++) {
173 uint32_t rate
= avio_rl24(pb
);
174 uint8_t aflag
= avio_r8(pb
);
176 smk
->indexes
[i
] = -1;
179 AVStream
*ast
= avformat_new_stream(s
, NULL
);
180 AVCodecParameters
*par
;
182 return AVERROR(ENOMEM
);
184 smk
->indexes
[i
] = ast
->index
;
186 par
->codec_type
= AVMEDIA_TYPE_AUDIO
;
187 if (aflag
& SMK_AUD_BINKAUD
) {
188 par
->codec_id
= AV_CODEC_ID_BINKAUDIO_RDFT
;
189 } else if (aflag
& SMK_AUD_USEDCT
) {
190 par
->codec_id
= AV_CODEC_ID_BINKAUDIO_DCT
;
191 } else if (aflag
& SMK_AUD_PACKED
) {
192 par
->codec_id
= AV_CODEC_ID_SMACKAUDIO
;
193 par
->codec_tag
= MKTAG('S', 'M', 'K', 'A');
195 par
->codec_id
= AV_CODEC_ID_PCM_U8
;
197 av_channel_layout_default(&par
->ch_layout
,
198 !!(aflag
& SMK_AUD_STEREO
) + 1);
199 par
->sample_rate
= rate
;
200 par
->bits_per_coded_sample
= (aflag
& SMK_AUD_16BITS
) ? 16 : 8;
201 if (par
->bits_per_coded_sample
== 16 &&
202 par
->codec_id
== AV_CODEC_ID_PCM_U8
)
203 par
->codec_id
= AV_CODEC_ID_PCM_S16LE
;
205 smk
->duration_size
[i
] = 4;
206 avpriv_set_pts_info(ast
, 64, 1, par
->sample_rate
* par
->ch_layout
.nb_channels
207 * par
->bits_per_coded_sample
/ 8);
211 avio_rl32(pb
); /* padding */
214 st
->priv_data
= av_malloc_array(smk
->frames
, sizeof(*smk
->frm_size
) +
215 sizeof(*smk
->frm_flags
));
217 return AVERROR(ENOMEM
);
218 smk
->frm_size
= st
->priv_data
;
219 smk
->frm_flags
= (void*)(smk
->frm_size
+ smk
->frames
);
221 /* read frame info */
223 for (i
= 0; i
< smk
->frames
; i
++) {
224 smk
->frm_size
[i
] = avio_rl32(pb
);
225 if ((ret
= av_add_index_entry(st
, pos
, i
, smk
->frm_size
[i
], 0,
226 (i
== 0 || (smk
->frm_size
[i
] & 1)) ? AVINDEX_KEYFRAME
: 0)) < 0)
228 pos
+= smk
->frm_size
[i
];
230 if ((ret
= ffio_read_size(pb
, smk
->frm_flags
, smk
->frames
)) < 0 ||
231 /* load trees to extradata, they will be unpacked by decoder */
232 (ret
= ffio_read_size(pb
, par
->extradata
+ 16,
233 par
->extradata_size
- 16)) < 0) {
240 static int smacker_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
242 SmackerContext
*smk
= s
->priv_data
;
246 if (avio_feof(s
->pb
) || smk
->cur_frame
>= smk
->frames
)
249 /* if we demuxed all streams, pass another frame */
250 if (!smk
->next_audio_index
) {
251 smk
->frame_size
= smk
->frm_size
[smk
->cur_frame
] & (~3);
252 smk
->next_frame_pos
= avio_tell(s
->pb
) + smk
->frame_size
;
253 flags
= smk
->frm_flags
[smk
->cur_frame
];
254 smk
->flags
= flags
>> 1;
255 /* handle palette change event */
256 if (flags
& SMACKER_PAL
) {
257 int size
, sz
, t
, off
, j
, pos
;
258 uint8_t *pal
= smk
->pal
;
261 memcpy(oldpal
, pal
, 768);
262 size
= avio_r8(s
->pb
);
264 if (size
> smk
->frame_size
) {
265 ret
= AVERROR_INVALIDDATA
;
268 smk
->frame_size
-= size
--;
270 pos
= avio_tell(s
->pb
) + size
;
273 if (t
& 0x80) { /* skip palette entries */
274 sz
+= (t
& 0x7F) + 1;
275 pal
+= ((t
& 0x7F) + 1) * 3;
276 } else if (t
& 0x40) { /* copy with offset */
277 off
= avio_r8(s
->pb
);
279 if (off
+ j
> 0x100) {
280 av_log(s
, AV_LOG_ERROR
,
281 "Invalid palette update, offset=%d length=%d extends beyond palette size\n",
283 ret
= AVERROR_INVALIDDATA
;
287 while (j
-- && sz
< 256) {
288 *pal
++ = oldpal
[off
+ 0];
289 *pal
++ = oldpal
[off
+ 1];
290 *pal
++ = oldpal
[off
+ 2];
294 } else { /* new entries */
296 *pal
++ = smk_pal
[avio_r8(s
->pb
) & 0x3F];
297 *pal
++ = smk_pal
[avio_r8(s
->pb
) & 0x3F];
301 avio_seek(s
->pb
, pos
, 0);
302 smk
->new_palette
= 1;
306 for (int i
= smk
->next_audio_index
; i
< 7; i
++) {
307 if (smk
->flags
& (1 << i
)) {
310 size
= avio_rl32(s
->pb
);
311 if ((int)size
< 4 + smk
->duration_size
[i
] || size
> smk
->frame_size
) {
312 av_log(s
, AV_LOG_ERROR
, "Invalid audio part size\n");
313 ret
= AVERROR_INVALIDDATA
;
316 smk
->frame_size
-= size
;
319 if (smk
->indexes
[i
] < 0 ||
320 s
->streams
[smk
->indexes
[i
]]->discard
>= AVDISCARD_ALL
) {
321 smk
->aud_pts
[i
] += smk
->duration_size
[i
] ? avio_rl32(s
->pb
)
323 avio_skip(s
->pb
, size
- smk
->duration_size
[i
]);
326 if ((ret
= av_get_packet(s
->pb
, pkt
, size
)) != size
) {
327 ret
= ret
< 0 ? ret
: AVERROR_INVALIDDATA
;
330 pkt
->stream_index
= smk
->indexes
[i
];
331 pkt
->pts
= smk
->aud_pts
[i
];
332 pkt
->duration
= smk
->duration_size
[i
] ? AV_RL32(pkt
->data
)
334 smk
->aud_pts
[i
] += pkt
->duration
;
335 smk
->next_audio_index
= i
+ 1;
340 if (s
->streams
[smk
->videoindex
]->discard
>= AVDISCARD_ALL
) {
344 if (smk
->frame_size
>= INT_MAX
/2) {
345 ret
= AVERROR_INVALIDDATA
;
348 if ((ret
= av_new_packet(pkt
, smk
->frame_size
+ 769)) < 0)
350 flags
= smk
->new_palette
;
351 if ((smk
->frm_size
[smk
->cur_frame
] & 1) || smk
->cur_frame
== 0)
353 pkt
->data
[0] = flags
;
354 memcpy(pkt
->data
+ 1, smk
->pal
, 768);
355 ret
= ffio_read_size(s
->pb
, pkt
->data
+ 769, smk
->frame_size
);
358 pkt
->stream_index
= smk
->videoindex
;
359 pkt
->pts
= smk
->cur_frame
;
362 pkt
->flags
|= AV_PKT_FLAG_KEY
;
363 smk
->next_audio_index
= 0;
364 smk
->new_palette
= 0;
369 avio_seek(s
->pb
, smk
->next_frame_pos
, SEEK_SET
);
370 smk
->next_audio_index
= 0;
375 static int smacker_read_seek(AVFormatContext
*s
, int stream_index
,
376 int64_t timestamp
, int flags
)
378 AVStream
*st
= s
->streams
[stream_index
];
379 SmackerContext
*smk
= s
->priv_data
;
383 if (!(s
->pb
->seekable
& AVIO_SEEKABLE_NORMAL
))
386 if (timestamp
< 0 || timestamp
>= smk
->frames
)
387 return AVERROR(EINVAL
);
389 ret
= av_index_search_timestamp(st
, timestamp
, flags
);
393 pos
= ffformatcontext(s
)->data_offset
;
394 pos
+= ffstream(st
)->index_entries
[ret
].pos
;
395 pos
= avio_seek(s
->pb
, pos
, SEEK_SET
);
399 smk
->cur_frame
= ret
;
400 smk
->next_audio_index
= 0;
401 smk
->new_palette
= 0;
402 memset(smk
->pal
, 0, sizeof(smk
->pal
));
403 memset(smk
->aud_pts
, 0, sizeof(smk
->aud_pts
));
408 const FFInputFormat ff_smacker_demuxer
= {
410 .p
.long_name
= NULL_IF_CONFIG_SMALL("Smacker"),
411 .priv_data_size
= sizeof(SmackerContext
),
412 .read_probe
= smacker_probe
,
413 .read_header
= smacker_read_header
,
414 .read_packet
= smacker_read_packet
,
415 .read_seek
= smacker_read_seek
,