1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Smacker demuxer
3cabdff1aSopenharmony_ci * Copyright (c) 2006 Konstantin Shishkov
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * This file is part of FFmpeg.
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15cabdff1aSopenharmony_ci * Lesser General Public License for more details.
16cabdff1aSopenharmony_ci *
17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20cabdff1aSopenharmony_ci */
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci/*
23cabdff1aSopenharmony_ci * Based on http://wiki.multimedia.cx/index.php?title=Smacker
24cabdff1aSopenharmony_ci */
25cabdff1aSopenharmony_ci
26cabdff1aSopenharmony_ci#include <inttypes.h>
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_ci#include "libavutil/channel_layout.h"
29cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
30cabdff1aSopenharmony_ci#include "avformat.h"
31cabdff1aSopenharmony_ci#include "avio_internal.h"
32cabdff1aSopenharmony_ci#include "demux.h"
33cabdff1aSopenharmony_ci#include "internal.h"
34cabdff1aSopenharmony_ci
35cabdff1aSopenharmony_ci#define SMACKER_PAL 0x01
36cabdff1aSopenharmony_ci#define SMACKER_FLAG_RING_FRAME 0x01
37cabdff1aSopenharmony_ci
38cabdff1aSopenharmony_cienum SAudFlags {
39cabdff1aSopenharmony_ci    SMK_AUD_PACKED  = 0x80,
40cabdff1aSopenharmony_ci    SMK_AUD_16BITS  = 0x20,
41cabdff1aSopenharmony_ci    SMK_AUD_STEREO  = 0x10,
42cabdff1aSopenharmony_ci    SMK_AUD_BINKAUD = 0x08,
43cabdff1aSopenharmony_ci    SMK_AUD_USEDCT  = 0x04
44cabdff1aSopenharmony_ci};
45cabdff1aSopenharmony_ci
46cabdff1aSopenharmony_citypedef struct SmackerContext {
47cabdff1aSopenharmony_ci    uint32_t frames;
48cabdff1aSopenharmony_ci    /* frame info */
49cabdff1aSopenharmony_ci    uint32_t *frm_size;
50cabdff1aSopenharmony_ci    uint8_t  *frm_flags;
51cabdff1aSopenharmony_ci    /* internal variables */
52cabdff1aSopenharmony_ci    int64_t next_frame_pos;
53cabdff1aSopenharmony_ci    int cur_frame;
54cabdff1aSopenharmony_ci    int videoindex;
55cabdff1aSopenharmony_ci    int indexes[7];
56cabdff1aSopenharmony_ci    int duration_size[7];
57cabdff1aSopenharmony_ci    /* current frame for demuxing */
58cabdff1aSopenharmony_ci    uint32_t frame_size;
59cabdff1aSopenharmony_ci    int flags;
60cabdff1aSopenharmony_ci    int next_audio_index;
61cabdff1aSopenharmony_ci    int new_palette;
62cabdff1aSopenharmony_ci    uint8_t pal[768];
63cabdff1aSopenharmony_ci    int64_t aud_pts[7];
64cabdff1aSopenharmony_ci} SmackerContext;
65cabdff1aSopenharmony_ci
66cabdff1aSopenharmony_ci/* palette used in Smacker */
67cabdff1aSopenharmony_cistatic const uint8_t smk_pal[64] = {
68cabdff1aSopenharmony_ci    0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C,
69cabdff1aSopenharmony_ci    0x20, 0x24, 0x28, 0x2C, 0x30, 0x34, 0x38, 0x3C,
70cabdff1aSopenharmony_ci    0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D,
71cabdff1aSopenharmony_ci    0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D,
72cabdff1aSopenharmony_ci    0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E,
73cabdff1aSopenharmony_ci    0xA2, 0xA6, 0xAA, 0xAE, 0xB2, 0xB6, 0xBA, 0xBE,
74cabdff1aSopenharmony_ci    0xC3, 0xC7, 0xCB, 0xCF, 0xD3, 0xD7, 0xDB, 0xDF,
75cabdff1aSopenharmony_ci    0xE3, 0xE7, 0xEB, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF
76cabdff1aSopenharmony_ci};
77cabdff1aSopenharmony_ci
78cabdff1aSopenharmony_ci
79cabdff1aSopenharmony_cistatic int smacker_probe(const AVProbeData *p)
80cabdff1aSopenharmony_ci{
81cabdff1aSopenharmony_ci    if (   AV_RL32(p->buf) != MKTAG('S', 'M', 'K', '2')
82cabdff1aSopenharmony_ci        && AV_RL32(p->buf) != MKTAG('S', 'M', 'K', '4'))
83cabdff1aSopenharmony_ci        return 0;
84cabdff1aSopenharmony_ci
85cabdff1aSopenharmony_ci    if (AV_RL32(p->buf+4) > 32768U || AV_RL32(p->buf+8) > 32768U)
86cabdff1aSopenharmony_ci        return AVPROBE_SCORE_MAX/4;
87cabdff1aSopenharmony_ci
88cabdff1aSopenharmony_ci    return AVPROBE_SCORE_MAX;
89cabdff1aSopenharmony_ci}
90cabdff1aSopenharmony_ci
91cabdff1aSopenharmony_cistatic int smacker_read_header(AVFormatContext *s)
92cabdff1aSopenharmony_ci{
93cabdff1aSopenharmony_ci    AVIOContext *pb = s->pb;
94cabdff1aSopenharmony_ci    SmackerContext *smk = s->priv_data;
95cabdff1aSopenharmony_ci    AVStream *st;
96cabdff1aSopenharmony_ci    AVCodecParameters *par;
97cabdff1aSopenharmony_ci    uint32_t magic, width, height, flags, treesize;
98cabdff1aSopenharmony_ci    int64_t pos;
99cabdff1aSopenharmony_ci    int i, ret, pts_inc;
100cabdff1aSopenharmony_ci    int tbase;
101cabdff1aSopenharmony_ci
102cabdff1aSopenharmony_ci    /* read and check header */
103cabdff1aSopenharmony_ci    magic  = avio_rl32(pb);
104cabdff1aSopenharmony_ci    if (magic != MKTAG('S', 'M', 'K', '2') && magic != MKTAG('S', 'M', 'K', '4'))
105cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
106cabdff1aSopenharmony_ci    width  = avio_rl32(pb);
107cabdff1aSopenharmony_ci    height = avio_rl32(pb);
108cabdff1aSopenharmony_ci    smk->frames = avio_rl32(pb);
109cabdff1aSopenharmony_ci    pts_inc = avio_rl32(pb);
110cabdff1aSopenharmony_ci    if (pts_inc > INT_MAX / 100 || pts_inc == INT_MIN) {
111cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "pts_inc %d is invalid\n", pts_inc);
112cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
113cabdff1aSopenharmony_ci    }
114cabdff1aSopenharmony_ci
115cabdff1aSopenharmony_ci    flags = avio_rl32(pb);
116cabdff1aSopenharmony_ci    if (flags & SMACKER_FLAG_RING_FRAME)
117cabdff1aSopenharmony_ci        smk->frames++;
118cabdff1aSopenharmony_ci    if (smk->frames > 0xFFFFFF) {
119cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Too many frames: %"PRIu32"\n", smk->frames);
120cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
121cabdff1aSopenharmony_ci    }
122cabdff1aSopenharmony_ci
123cabdff1aSopenharmony_ci    avio_skip(pb, 28); /* Unused audio related data */
124cabdff1aSopenharmony_ci
125cabdff1aSopenharmony_ci    treesize = avio_rl32(pb);
126cabdff1aSopenharmony_ci    if (treesize >= UINT_MAX/4) {
127cabdff1aSopenharmony_ci        // treesize + 16 must not overflow (this check is probably redundant)
128cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "treesize too large\n");
129cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
130cabdff1aSopenharmony_ci    }
131cabdff1aSopenharmony_ci
132cabdff1aSopenharmony_ci    st = avformat_new_stream(s, NULL);
133cabdff1aSopenharmony_ci    if (!st)
134cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
135cabdff1aSopenharmony_ci
136cabdff1aSopenharmony_ci    smk->videoindex = st->index;
137cabdff1aSopenharmony_ci    /* Smacker uses 100000 as internal timebase */
138cabdff1aSopenharmony_ci    if (pts_inc < 0)
139cabdff1aSopenharmony_ci        pts_inc = -pts_inc;
140cabdff1aSopenharmony_ci    else
141cabdff1aSopenharmony_ci        pts_inc *= 100;
142cabdff1aSopenharmony_ci    tbase = 100000;
143cabdff1aSopenharmony_ci    av_reduce(&tbase, &pts_inc, tbase, pts_inc, (1UL << 31) - 1);
144cabdff1aSopenharmony_ci    avpriv_set_pts_info(st, 33, pts_inc, tbase);
145cabdff1aSopenharmony_ci    st->duration = smk->frames;
146cabdff1aSopenharmony_ci
147cabdff1aSopenharmony_ci    /* init video codec */
148cabdff1aSopenharmony_ci    par = st->codecpar;
149cabdff1aSopenharmony_ci    par->width      = width;
150cabdff1aSopenharmony_ci    par->height     = height;
151cabdff1aSopenharmony_ci    par->format     = AV_PIX_FMT_PAL8;
152cabdff1aSopenharmony_ci    par->codec_type = AVMEDIA_TYPE_VIDEO;
153cabdff1aSopenharmony_ci    par->codec_id   = AV_CODEC_ID_SMACKVIDEO;
154cabdff1aSopenharmony_ci    par->codec_tag  = magic;
155cabdff1aSopenharmony_ci
156cabdff1aSopenharmony_ci    if ((ret = ff_alloc_extradata(par, treesize + 16)) < 0) {
157cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR,
158cabdff1aSopenharmony_ci               "Cannot allocate %"PRIu32" bytes of extradata\n",
159cabdff1aSopenharmony_ci               treesize + 16);
160cabdff1aSopenharmony_ci        return ret;
161cabdff1aSopenharmony_ci    }
162cabdff1aSopenharmony_ci    if ((ret = ffio_read_size(pb, par->extradata, 16)) < 0)
163cabdff1aSopenharmony_ci        return ret;
164cabdff1aSopenharmony_ci
165cabdff1aSopenharmony_ci    /* handle possible audio streams */
166cabdff1aSopenharmony_ci    for (i = 0; i < 7; i++) {
167cabdff1aSopenharmony_ci        uint32_t rate = avio_rl24(pb);
168cabdff1aSopenharmony_ci        uint8_t aflag = avio_r8(pb);
169cabdff1aSopenharmony_ci
170cabdff1aSopenharmony_ci        smk->indexes[i] = -1;
171cabdff1aSopenharmony_ci
172cabdff1aSopenharmony_ci        if (rate) {
173cabdff1aSopenharmony_ci            AVStream *ast = avformat_new_stream(s, NULL);
174cabdff1aSopenharmony_ci            AVCodecParameters *par;
175cabdff1aSopenharmony_ci            if (!ast)
176cabdff1aSopenharmony_ci                return AVERROR(ENOMEM);
177cabdff1aSopenharmony_ci
178cabdff1aSopenharmony_ci            smk->indexes[i] = ast->index;
179cabdff1aSopenharmony_ci            par = ast->codecpar;
180cabdff1aSopenharmony_ci            par->codec_type = AVMEDIA_TYPE_AUDIO;
181cabdff1aSopenharmony_ci            if (aflag & SMK_AUD_BINKAUD) {
182cabdff1aSopenharmony_ci                par->codec_id  = AV_CODEC_ID_BINKAUDIO_RDFT;
183cabdff1aSopenharmony_ci            } else if (aflag & SMK_AUD_USEDCT) {
184cabdff1aSopenharmony_ci                par->codec_id  = AV_CODEC_ID_BINKAUDIO_DCT;
185cabdff1aSopenharmony_ci            } else if (aflag & SMK_AUD_PACKED) {
186cabdff1aSopenharmony_ci                par->codec_id  = AV_CODEC_ID_SMACKAUDIO;
187cabdff1aSopenharmony_ci                par->codec_tag = MKTAG('S', 'M', 'K', 'A');
188cabdff1aSopenharmony_ci            } else {
189cabdff1aSopenharmony_ci                par->codec_id  = AV_CODEC_ID_PCM_U8;
190cabdff1aSopenharmony_ci            }
191cabdff1aSopenharmony_ci            av_channel_layout_default(&par->ch_layout,
192cabdff1aSopenharmony_ci                                      !!(aflag & SMK_AUD_STEREO) + 1);
193cabdff1aSopenharmony_ci            par->sample_rate = rate;
194cabdff1aSopenharmony_ci            par->bits_per_coded_sample = (aflag & SMK_AUD_16BITS) ? 16 : 8;
195cabdff1aSopenharmony_ci            if (par->bits_per_coded_sample == 16 &&
196cabdff1aSopenharmony_ci                par->codec_id == AV_CODEC_ID_PCM_U8)
197cabdff1aSopenharmony_ci                par->codec_id = AV_CODEC_ID_PCM_S16LE;
198cabdff1aSopenharmony_ci            else
199cabdff1aSopenharmony_ci                smk->duration_size[i] = 4;
200cabdff1aSopenharmony_ci            avpriv_set_pts_info(ast, 64, 1, par->sample_rate * par->ch_layout.nb_channels
201cabdff1aSopenharmony_ci                                            * par->bits_per_coded_sample / 8);
202cabdff1aSopenharmony_ci        }
203cabdff1aSopenharmony_ci    }
204cabdff1aSopenharmony_ci
205cabdff1aSopenharmony_ci    avio_rl32(pb); /* padding */
206cabdff1aSopenharmony_ci
207cabdff1aSopenharmony_ci    /* setup data */
208cabdff1aSopenharmony_ci    st->priv_data  = av_malloc_array(smk->frames, sizeof(*smk->frm_size) +
209cabdff1aSopenharmony_ci                                                  sizeof(*smk->frm_flags));
210cabdff1aSopenharmony_ci    if (!st->priv_data)
211cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
212cabdff1aSopenharmony_ci    smk->frm_size  = st->priv_data;
213cabdff1aSopenharmony_ci    smk->frm_flags = (void*)(smk->frm_size + smk->frames);
214cabdff1aSopenharmony_ci
215cabdff1aSopenharmony_ci    /* read frame info */
216cabdff1aSopenharmony_ci    pos = 0;
217cabdff1aSopenharmony_ci    for (i = 0; i < smk->frames; i++) {
218cabdff1aSopenharmony_ci        smk->frm_size[i] = avio_rl32(pb);
219cabdff1aSopenharmony_ci        if ((ret = av_add_index_entry(st, pos, i, smk->frm_size[i], 0,
220cabdff1aSopenharmony_ci                                      (i == 0 || (smk->frm_size[i] & 1)) ? AVINDEX_KEYFRAME : 0)) < 0)
221cabdff1aSopenharmony_ci            return ret;
222cabdff1aSopenharmony_ci        pos += smk->frm_size[i];
223cabdff1aSopenharmony_ci    }
224cabdff1aSopenharmony_ci    if ((ret = ffio_read_size(pb, smk->frm_flags, smk->frames)) < 0 ||
225cabdff1aSopenharmony_ci        /* load trees to extradata, they will be unpacked by decoder */
226cabdff1aSopenharmony_ci        (ret = ffio_read_size(pb, par->extradata + 16,
227cabdff1aSopenharmony_ci                              par->extradata_size - 16)) < 0) {
228cabdff1aSopenharmony_ci        return ret;
229cabdff1aSopenharmony_ci    }
230cabdff1aSopenharmony_ci
231cabdff1aSopenharmony_ci    return 0;
232cabdff1aSopenharmony_ci}
233cabdff1aSopenharmony_ci
234cabdff1aSopenharmony_cistatic int smacker_read_packet(AVFormatContext *s, AVPacket *pkt)
235cabdff1aSopenharmony_ci{
236cabdff1aSopenharmony_ci    SmackerContext *smk = s->priv_data;
237cabdff1aSopenharmony_ci    int flags;
238cabdff1aSopenharmony_ci    int ret;
239cabdff1aSopenharmony_ci
240cabdff1aSopenharmony_ci    if (avio_feof(s->pb) || smk->cur_frame >= smk->frames)
241cabdff1aSopenharmony_ci        return AVERROR_EOF;
242cabdff1aSopenharmony_ci
243cabdff1aSopenharmony_ci    /* if we demuxed all streams, pass another frame */
244cabdff1aSopenharmony_ci    if (!smk->next_audio_index) {
245cabdff1aSopenharmony_ci        smk->frame_size = smk->frm_size[smk->cur_frame] & (~3);
246cabdff1aSopenharmony_ci        smk->next_frame_pos = avio_tell(s->pb) + smk->frame_size;
247cabdff1aSopenharmony_ci        flags = smk->frm_flags[smk->cur_frame];
248cabdff1aSopenharmony_ci        smk->flags = flags >> 1;
249cabdff1aSopenharmony_ci        /* handle palette change event */
250cabdff1aSopenharmony_ci        if (flags & SMACKER_PAL) {
251cabdff1aSopenharmony_ci            int size, sz, t, off, j, pos;
252cabdff1aSopenharmony_ci            uint8_t *pal = smk->pal;
253cabdff1aSopenharmony_ci            uint8_t oldpal[768];
254cabdff1aSopenharmony_ci
255cabdff1aSopenharmony_ci            memcpy(oldpal, pal, 768);
256cabdff1aSopenharmony_ci            size = avio_r8(s->pb);
257cabdff1aSopenharmony_ci            size = size * 4;
258cabdff1aSopenharmony_ci            if (size > smk->frame_size) {
259cabdff1aSopenharmony_ci                ret = AVERROR_INVALIDDATA;
260cabdff1aSopenharmony_ci                goto next_frame;
261cabdff1aSopenharmony_ci            }
262cabdff1aSopenharmony_ci            smk->frame_size -= size--;
263cabdff1aSopenharmony_ci            sz = 0;
264cabdff1aSopenharmony_ci            pos = avio_tell(s->pb) + size;
265cabdff1aSopenharmony_ci            while (sz < 256) {
266cabdff1aSopenharmony_ci                t = avio_r8(s->pb);
267cabdff1aSopenharmony_ci                if (t & 0x80) { /* skip palette entries */
268cabdff1aSopenharmony_ci                    sz  +=  (t & 0x7F) + 1;
269cabdff1aSopenharmony_ci                    pal += ((t & 0x7F) + 1) * 3;
270cabdff1aSopenharmony_ci                } else if (t & 0x40) { /* copy with offset */
271cabdff1aSopenharmony_ci                    off = avio_r8(s->pb);
272cabdff1aSopenharmony_ci                    j = (t & 0x3F) + 1;
273cabdff1aSopenharmony_ci                    if (off + j > 0x100) {
274cabdff1aSopenharmony_ci                        av_log(s, AV_LOG_ERROR,
275cabdff1aSopenharmony_ci                               "Invalid palette update, offset=%d length=%d extends beyond palette size\n",
276cabdff1aSopenharmony_ci                               off, j);
277cabdff1aSopenharmony_ci                        ret = AVERROR_INVALIDDATA;
278cabdff1aSopenharmony_ci                        goto next_frame;
279cabdff1aSopenharmony_ci                    }
280cabdff1aSopenharmony_ci                    off *= 3;
281cabdff1aSopenharmony_ci                    while (j-- && sz < 256) {
282cabdff1aSopenharmony_ci                        *pal++ = oldpal[off + 0];
283cabdff1aSopenharmony_ci                        *pal++ = oldpal[off + 1];
284cabdff1aSopenharmony_ci                        *pal++ = oldpal[off + 2];
285cabdff1aSopenharmony_ci                        sz++;
286cabdff1aSopenharmony_ci                        off += 3;
287cabdff1aSopenharmony_ci                    }
288cabdff1aSopenharmony_ci                } else { /* new entries */
289cabdff1aSopenharmony_ci                    *pal++ = smk_pal[t];
290cabdff1aSopenharmony_ci                    *pal++ = smk_pal[avio_r8(s->pb) & 0x3F];
291cabdff1aSopenharmony_ci                    *pal++ = smk_pal[avio_r8(s->pb) & 0x3F];
292cabdff1aSopenharmony_ci                    sz++;
293cabdff1aSopenharmony_ci                }
294cabdff1aSopenharmony_ci            }
295cabdff1aSopenharmony_ci            avio_seek(s->pb, pos, 0);
296cabdff1aSopenharmony_ci            smk->new_palette = 1;
297cabdff1aSopenharmony_ci        }
298cabdff1aSopenharmony_ci    }
299cabdff1aSopenharmony_ci
300cabdff1aSopenharmony_ci    for (int i = smk->next_audio_index; i < 7; i++) {
301cabdff1aSopenharmony_ci        if (smk->flags & (1 << i)) {
302cabdff1aSopenharmony_ci            uint32_t size;
303cabdff1aSopenharmony_ci
304cabdff1aSopenharmony_ci            size = avio_rl32(s->pb);
305cabdff1aSopenharmony_ci            if ((int)size < 4 + smk->duration_size[i] || size > smk->frame_size) {
306cabdff1aSopenharmony_ci                av_log(s, AV_LOG_ERROR, "Invalid audio part size\n");
307cabdff1aSopenharmony_ci                ret = AVERROR_INVALIDDATA;
308cabdff1aSopenharmony_ci                goto next_frame;
309cabdff1aSopenharmony_ci            }
310cabdff1aSopenharmony_ci            smk->frame_size -= size;
311cabdff1aSopenharmony_ci            size            -= 4;
312cabdff1aSopenharmony_ci
313cabdff1aSopenharmony_ci            if (smk->indexes[i] < 0 ||
314cabdff1aSopenharmony_ci                s->streams[smk->indexes[i]]->discard >= AVDISCARD_ALL) {
315cabdff1aSopenharmony_ci                smk->aud_pts[i] += smk->duration_size[i] ? avio_rl32(s->pb)
316cabdff1aSopenharmony_ci                                                         : size;
317cabdff1aSopenharmony_ci                avio_skip(s->pb, size - smk->duration_size[i]);
318cabdff1aSopenharmony_ci                continue;
319cabdff1aSopenharmony_ci            }
320cabdff1aSopenharmony_ci            if ((ret = av_get_packet(s->pb, pkt, size)) != size) {
321cabdff1aSopenharmony_ci                ret = ret < 0 ? ret : AVERROR_INVALIDDATA;
322cabdff1aSopenharmony_ci                goto next_frame;
323cabdff1aSopenharmony_ci            }
324cabdff1aSopenharmony_ci            pkt->stream_index = smk->indexes[i];
325cabdff1aSopenharmony_ci            pkt->pts          = smk->aud_pts[i];
326cabdff1aSopenharmony_ci            pkt->duration     = smk->duration_size[i] ? AV_RL32(pkt->data)
327cabdff1aSopenharmony_ci                                                      : size;
328cabdff1aSopenharmony_ci            smk->aud_pts[i]  += pkt->duration;
329cabdff1aSopenharmony_ci            smk->next_audio_index = i + 1;
330cabdff1aSopenharmony_ci            return 0;
331cabdff1aSopenharmony_ci        }
332cabdff1aSopenharmony_ci    }
333cabdff1aSopenharmony_ci
334cabdff1aSopenharmony_ci    if (s->streams[smk->videoindex]->discard >= AVDISCARD_ALL) {
335cabdff1aSopenharmony_ci        ret = FFERROR_REDO;
336cabdff1aSopenharmony_ci        goto next_frame;
337cabdff1aSopenharmony_ci    }
338cabdff1aSopenharmony_ci    if (smk->frame_size >= INT_MAX/2) {
339cabdff1aSopenharmony_ci        ret = AVERROR_INVALIDDATA;
340cabdff1aSopenharmony_ci        goto next_frame;
341cabdff1aSopenharmony_ci    }
342cabdff1aSopenharmony_ci    if ((ret = av_new_packet(pkt, smk->frame_size + 769)) < 0)
343cabdff1aSopenharmony_ci        goto next_frame;
344cabdff1aSopenharmony_ci    flags = smk->new_palette;
345cabdff1aSopenharmony_ci    if ((smk->frm_size[smk->cur_frame] & 1) || smk->cur_frame == 0)
346cabdff1aSopenharmony_ci        flags |= 2;
347cabdff1aSopenharmony_ci    pkt->data[0] = flags;
348cabdff1aSopenharmony_ci    memcpy(pkt->data + 1, smk->pal, 768);
349cabdff1aSopenharmony_ci    ret = ffio_read_size(s->pb, pkt->data + 769, smk->frame_size);
350cabdff1aSopenharmony_ci    if (ret < 0)
351cabdff1aSopenharmony_ci        goto next_frame;
352cabdff1aSopenharmony_ci    pkt->stream_index = smk->videoindex;
353cabdff1aSopenharmony_ci    pkt->pts          = smk->cur_frame;
354cabdff1aSopenharmony_ci    pkt->duration = 1;
355cabdff1aSopenharmony_ci    if (flags & 2)
356cabdff1aSopenharmony_ci        pkt->flags |= AV_PKT_FLAG_KEY;
357cabdff1aSopenharmony_ci    smk->next_audio_index = 0;
358cabdff1aSopenharmony_ci    smk->new_palette = 0;
359cabdff1aSopenharmony_ci    smk->cur_frame++;
360cabdff1aSopenharmony_ci
361cabdff1aSopenharmony_ci    return 0;
362cabdff1aSopenharmony_cinext_frame:
363cabdff1aSopenharmony_ci    avio_seek(s->pb, smk->next_frame_pos, SEEK_SET);
364cabdff1aSopenharmony_ci    smk->next_audio_index = 0;
365cabdff1aSopenharmony_ci    smk->cur_frame++;
366cabdff1aSopenharmony_ci    return ret;
367cabdff1aSopenharmony_ci}
368cabdff1aSopenharmony_ci
369cabdff1aSopenharmony_cistatic int smacker_read_seek(AVFormatContext *s, int stream_index,
370cabdff1aSopenharmony_ci                             int64_t timestamp, int flags)
371cabdff1aSopenharmony_ci{
372cabdff1aSopenharmony_ci    AVStream *st = s->streams[stream_index];
373cabdff1aSopenharmony_ci    SmackerContext *smk = s->priv_data;
374cabdff1aSopenharmony_ci    int64_t pos;
375cabdff1aSopenharmony_ci    int ret;
376cabdff1aSopenharmony_ci
377cabdff1aSopenharmony_ci    if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
378cabdff1aSopenharmony_ci        return -1;
379cabdff1aSopenharmony_ci
380cabdff1aSopenharmony_ci    if (timestamp < 0 || timestamp >= smk->frames)
381cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
382cabdff1aSopenharmony_ci
383cabdff1aSopenharmony_ci    ret = av_index_search_timestamp(st, timestamp, flags);
384cabdff1aSopenharmony_ci    if (ret < 0)
385cabdff1aSopenharmony_ci        return ret;
386cabdff1aSopenharmony_ci
387cabdff1aSopenharmony_ci    pos  = ffformatcontext(s)->data_offset;
388cabdff1aSopenharmony_ci    pos += ffstream(st)->index_entries[ret].pos;
389cabdff1aSopenharmony_ci    pos  = avio_seek(s->pb, pos, SEEK_SET);
390cabdff1aSopenharmony_ci    if (pos < 0)
391cabdff1aSopenharmony_ci        return pos;
392cabdff1aSopenharmony_ci
393cabdff1aSopenharmony_ci    smk->cur_frame = ret;
394cabdff1aSopenharmony_ci    smk->next_audio_index = 0;
395cabdff1aSopenharmony_ci    smk->new_palette = 0;
396cabdff1aSopenharmony_ci    memset(smk->pal, 0, sizeof(smk->pal));
397cabdff1aSopenharmony_ci    memset(smk->aud_pts, 0, sizeof(smk->aud_pts));
398cabdff1aSopenharmony_ci
399cabdff1aSopenharmony_ci    return 0;
400cabdff1aSopenharmony_ci}
401cabdff1aSopenharmony_ci
402cabdff1aSopenharmony_ciconst AVInputFormat ff_smacker_demuxer = {
403cabdff1aSopenharmony_ci    .name           = "smk",
404cabdff1aSopenharmony_ci    .long_name      = NULL_IF_CONFIG_SMALL("Smacker"),
405cabdff1aSopenharmony_ci    .priv_data_size = sizeof(SmackerContext),
406cabdff1aSopenharmony_ci    .read_probe     = smacker_probe,
407cabdff1aSopenharmony_ci    .read_header    = smacker_read_header,
408cabdff1aSopenharmony_ci    .read_packet    = smacker_read_packet,
409cabdff1aSopenharmony_ci    .read_seek      = smacker_read_seek,
410cabdff1aSopenharmony_ci};
411