xref: /third_party/ffmpeg/libavformat/sga.c (revision cabdff1a)
1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Digital Pictures SGA game demuxer
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * Copyright (C) 2021 Paul B Mahol
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * This file is part of FFmpeg.
7cabdff1aSopenharmony_ci *
8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
9cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
10cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
11cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
12cabdff1aSopenharmony_ci *
13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16cabdff1aSopenharmony_ci * Lesser General Public License for more details.
17cabdff1aSopenharmony_ci *
18cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
19cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21cabdff1aSopenharmony_ci */
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
24cabdff1aSopenharmony_ci#include "libavutil/avassert.h"
25cabdff1aSopenharmony_ci#include "libavutil/channel_layout.h"
26cabdff1aSopenharmony_ci#include "libavutil/internal.h"
27cabdff1aSopenharmony_ci#include "avformat.h"
28cabdff1aSopenharmony_ci#include "internal.h"
29cabdff1aSopenharmony_ci#include "avio_internal.h"
30cabdff1aSopenharmony_ci
31cabdff1aSopenharmony_ci#define SEGA_CD_PCM_NUM 12500000
32cabdff1aSopenharmony_ci#define SEGA_CD_PCM_DEN 786432
33cabdff1aSopenharmony_ci
34cabdff1aSopenharmony_citypedef struct SGADemuxContext {
35cabdff1aSopenharmony_ci    int video_stream_index;
36cabdff1aSopenharmony_ci    int audio_stream_index;
37cabdff1aSopenharmony_ci
38cabdff1aSopenharmony_ci    uint8_t sector[65536 * 2];
39cabdff1aSopenharmony_ci    int sector_headers;
40cabdff1aSopenharmony_ci    int sample_rate;
41cabdff1aSopenharmony_ci    int first_audio_size;
42cabdff1aSopenharmony_ci    int payload_size;
43cabdff1aSopenharmony_ci    int packet_type;
44cabdff1aSopenharmony_ci    int flags;
45cabdff1aSopenharmony_ci    int idx;
46cabdff1aSopenharmony_ci    int left;
47cabdff1aSopenharmony_ci    int64_t pkt_pos;
48cabdff1aSopenharmony_ci} SGADemuxContext;
49cabdff1aSopenharmony_ci
50cabdff1aSopenharmony_cistatic int sga_probe(const AVProbeData *p)
51cabdff1aSopenharmony_ci{
52cabdff1aSopenharmony_ci    const uint8_t *src = p->buf;
53cabdff1aSopenharmony_ci    int score = 0, sectors = 1;
54cabdff1aSopenharmony_ci    int last_left = 0;
55cabdff1aSopenharmony_ci    int sample_rate = -1;
56cabdff1aSopenharmony_ci
57cabdff1aSopenharmony_ci    if (p->buf_size < 2048)
58cabdff1aSopenharmony_ci        return 0;
59cabdff1aSopenharmony_ci
60cabdff1aSopenharmony_ci    for (int i = 0; i + 2 < p->buf_size; i += 2048) {
61cabdff1aSopenharmony_ci        int header = AV_RB16(src + i);
62cabdff1aSopenharmony_ci
63cabdff1aSopenharmony_ci        if ((header > 0x07FE && header < 0x8100) ||
64cabdff1aSopenharmony_ci            (header > 0x8200 && header < 0xA100) ||
65cabdff1aSopenharmony_ci            (header > 0xA200 && header < 0xC100)) {
66cabdff1aSopenharmony_ci            sectors = 0;
67cabdff1aSopenharmony_ci            break;
68cabdff1aSopenharmony_ci        }
69cabdff1aSopenharmony_ci    }
70cabdff1aSopenharmony_ci
71cabdff1aSopenharmony_ci    for (int i = 0; i + 4 < p->buf_size;) {
72cabdff1aSopenharmony_ci        int header = AV_RB16(src + i);
73cabdff1aSopenharmony_ci        int left   = AV_RB16(src + i + 2);
74cabdff1aSopenharmony_ci        int offset, type, size;
75cabdff1aSopenharmony_ci
76cabdff1aSopenharmony_ci        if (last_left < 0)
77cabdff1aSopenharmony_ci            return 0;
78cabdff1aSopenharmony_ci        if (sectors && header && last_left == 0) {
79cabdff1aSopenharmony_ci            if (header >> 12) {
80cabdff1aSopenharmony_ci                last_left = left;
81cabdff1aSopenharmony_ci            } else {
82cabdff1aSopenharmony_ci                last_left = left = header;
83cabdff1aSopenharmony_ci            }
84cabdff1aSopenharmony_ci        } else if (sectors && header) {
85cabdff1aSopenharmony_ci            left = header;
86cabdff1aSopenharmony_ci            last_left -= left;
87cabdff1aSopenharmony_ci            if (header != 0x7FE && left < 7)
88cabdff1aSopenharmony_ci                return 0;
89cabdff1aSopenharmony_ci        } else if (sectors) {
90cabdff1aSopenharmony_ci            if (left <= 8)
91cabdff1aSopenharmony_ci                return 0;
92cabdff1aSopenharmony_ci            i += sectors ? 2048 : left + 4;
93cabdff1aSopenharmony_ci            last_left = 0;
94cabdff1aSopenharmony_ci            continue;
95cabdff1aSopenharmony_ci        }
96cabdff1aSopenharmony_ci
97cabdff1aSopenharmony_ci        if (sectors && (i > 0 && left < 0x7fe) &&
98cabdff1aSopenharmony_ci            (i + left + 14 < p->buf_size)) {
99cabdff1aSopenharmony_ci            offset = i + left + 2;
100cabdff1aSopenharmony_ci        } else if (sectors && i > 0) {
101cabdff1aSopenharmony_ci            i += 2048;
102cabdff1aSopenharmony_ci            last_left -= FFMIN(last_left, 2046);
103cabdff1aSopenharmony_ci            continue;
104cabdff1aSopenharmony_ci        } else {
105cabdff1aSopenharmony_ci            offset = 0;
106cabdff1aSopenharmony_ci            last_left = left;
107cabdff1aSopenharmony_ci        }
108cabdff1aSopenharmony_ci
109cabdff1aSopenharmony_ci        header = AV_RB16(src + offset);
110cabdff1aSopenharmony_ci        size   = AV_RB16(src + offset + 2) + 4;
111cabdff1aSopenharmony_ci
112cabdff1aSopenharmony_ci        while ((header & 0xFF00) == 0) {
113cabdff1aSopenharmony_ci            offset++;
114cabdff1aSopenharmony_ci            if (offset + 4 >= p->buf_size)
115cabdff1aSopenharmony_ci                break;
116cabdff1aSopenharmony_ci            header = AV_RB16(src + offset);
117cabdff1aSopenharmony_ci            size   = AV_RB16(src + offset + 2) + 4;
118cabdff1aSopenharmony_ci        }
119cabdff1aSopenharmony_ci
120cabdff1aSopenharmony_ci        if (offset + 12 >= p->buf_size)
121cabdff1aSopenharmony_ci            break;
122cabdff1aSopenharmony_ci        if ((header & 0xFF) > 1)
123cabdff1aSopenharmony_ci            return 0;
124cabdff1aSopenharmony_ci        type = header >> 8;
125cabdff1aSopenharmony_ci
126cabdff1aSopenharmony_ci        if (type == 0xAA ||
127cabdff1aSopenharmony_ci            type == 0xA1 ||
128cabdff1aSopenharmony_ci            type == 0xA2 ||
129cabdff1aSopenharmony_ci            type == 0xA3) {
130cabdff1aSopenharmony_ci            int new_rate;
131cabdff1aSopenharmony_ci
132cabdff1aSopenharmony_ci            if (size <= 12)
133cabdff1aSopenharmony_ci                return 0;
134cabdff1aSopenharmony_ci            new_rate = AV_RB16(src + offset + 8);
135cabdff1aSopenharmony_ci            if (sample_rate < 0)
136cabdff1aSopenharmony_ci                sample_rate = new_rate;
137cabdff1aSopenharmony_ci            if (sample_rate == 0 || new_rate != sample_rate)
138cabdff1aSopenharmony_ci                return 0;
139cabdff1aSopenharmony_ci            if (src[offset + 10] != 1)
140cabdff1aSopenharmony_ci                return 0;
141cabdff1aSopenharmony_ci
142cabdff1aSopenharmony_ci            score += 10;
143cabdff1aSopenharmony_ci        } else if (type == 0xC1 ||
144cabdff1aSopenharmony_ci                   type == 0xC6 ||
145cabdff1aSopenharmony_ci                   type == 0xC7 ||
146cabdff1aSopenharmony_ci                   type == 0xC8 ||
147cabdff1aSopenharmony_ci                   type == 0xC9 ||
148cabdff1aSopenharmony_ci                   type == 0xCB ||
149cabdff1aSopenharmony_ci                   type == 0xCD ||
150cabdff1aSopenharmony_ci                   type == 0xE7) {
151cabdff1aSopenharmony_ci            int nb_pals = src[offset + 9];
152cabdff1aSopenharmony_ci            int tiles_w = src[offset + 10];
153cabdff1aSopenharmony_ci            int tiles_h = src[offset + 11];
154cabdff1aSopenharmony_ci
155cabdff1aSopenharmony_ci            if (size <= 12)
156cabdff1aSopenharmony_ci                return 0;
157cabdff1aSopenharmony_ci            if (nb_pals == 0 || nb_pals > 4)
158cabdff1aSopenharmony_ci                return 0;
159cabdff1aSopenharmony_ci            if (tiles_w == 0 || tiles_w > 80)
160cabdff1aSopenharmony_ci                return 0;
161cabdff1aSopenharmony_ci            if (tiles_h == 0 || tiles_h > 60)
162cabdff1aSopenharmony_ci                return 0;
163cabdff1aSopenharmony_ci
164cabdff1aSopenharmony_ci            score += 10;
165cabdff1aSopenharmony_ci        } else if (header == 0x7FE) {
166cabdff1aSopenharmony_ci            ;
167cabdff1aSopenharmony_ci        } else {
168cabdff1aSopenharmony_ci            return 0;
169cabdff1aSopenharmony_ci        }
170cabdff1aSopenharmony_ci
171cabdff1aSopenharmony_ci        i += sectors ? 2048 : size + 4;
172cabdff1aSopenharmony_ci        last_left -= FFMIN(last_left, 2046);
173cabdff1aSopenharmony_ci
174cabdff1aSopenharmony_ci        if (score < 0)
175cabdff1aSopenharmony_ci            break;
176cabdff1aSopenharmony_ci    }
177cabdff1aSopenharmony_ci
178cabdff1aSopenharmony_ci    return av_clip(score, 0, AVPROBE_SCORE_MAX);
179cabdff1aSopenharmony_ci}
180cabdff1aSopenharmony_ci
181cabdff1aSopenharmony_cistatic int sga_read_header(AVFormatContext *s)
182cabdff1aSopenharmony_ci{
183cabdff1aSopenharmony_ci    SGADemuxContext *sga = s->priv_data;
184cabdff1aSopenharmony_ci    AVIOContext *pb = s->pb;
185cabdff1aSopenharmony_ci
186cabdff1aSopenharmony_ci    sga->sector_headers = 1;
187cabdff1aSopenharmony_ci    sga->first_audio_size = 0;
188cabdff1aSopenharmony_ci    sga->video_stream_index = -1;
189cabdff1aSopenharmony_ci    sga->audio_stream_index = -1;
190cabdff1aSopenharmony_ci    sga->left = 2048;
191cabdff1aSopenharmony_ci    sga->idx = 0;
192cabdff1aSopenharmony_ci
193cabdff1aSopenharmony_ci    s->ctx_flags |= AVFMTCTX_NOHEADER;
194cabdff1aSopenharmony_ci
195cabdff1aSopenharmony_ci    if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
196cabdff1aSopenharmony_ci        while (!avio_feof(pb)) {
197cabdff1aSopenharmony_ci            int header = avio_rb16(pb);
198cabdff1aSopenharmony_ci            int type = header >> 8;
199cabdff1aSopenharmony_ci            int skip = 2046;
200cabdff1aSopenharmony_ci            int clock;
201cabdff1aSopenharmony_ci
202cabdff1aSopenharmony_ci            if (!sga->first_audio_size &&
203cabdff1aSopenharmony_ci                (type == 0xAA ||
204cabdff1aSopenharmony_ci                 type == 0xA1 ||
205cabdff1aSopenharmony_ci                 type == 0xA2 ||
206cabdff1aSopenharmony_ci                 type == 0xA3)) {
207cabdff1aSopenharmony_ci                sga->first_audio_size = avio_rb16(pb);
208cabdff1aSopenharmony_ci                avio_skip(pb, 4);
209cabdff1aSopenharmony_ci                clock = avio_rb16(pb);
210cabdff1aSopenharmony_ci                sga->sample_rate = av_rescale(clock,
211cabdff1aSopenharmony_ci                                              SEGA_CD_PCM_NUM,
212cabdff1aSopenharmony_ci                                              SEGA_CD_PCM_DEN);
213cabdff1aSopenharmony_ci                skip -= 8;
214cabdff1aSopenharmony_ci            }
215cabdff1aSopenharmony_ci            if ((header > 0x07FE && header < 0x8100) ||
216cabdff1aSopenharmony_ci                (header > 0x8200 && header < 0xA100) ||
217cabdff1aSopenharmony_ci                (header > 0xA200 && header < 0xC100)) {
218cabdff1aSopenharmony_ci                sga->sector_headers = 0;
219cabdff1aSopenharmony_ci                break;
220cabdff1aSopenharmony_ci            }
221cabdff1aSopenharmony_ci
222cabdff1aSopenharmony_ci            avio_skip(pb, skip);
223cabdff1aSopenharmony_ci        }
224cabdff1aSopenharmony_ci
225cabdff1aSopenharmony_ci        avio_seek(pb, 0, SEEK_SET);
226cabdff1aSopenharmony_ci    }
227cabdff1aSopenharmony_ci
228cabdff1aSopenharmony_ci    return 0;
229cabdff1aSopenharmony_ci}
230cabdff1aSopenharmony_ci
231cabdff1aSopenharmony_cistatic void print_stats(AVFormatContext *s, const char *where)
232cabdff1aSopenharmony_ci{
233cabdff1aSopenharmony_ci    SGADemuxContext *sga = s->priv_data;
234cabdff1aSopenharmony_ci
235cabdff1aSopenharmony_ci    av_log(s, AV_LOG_DEBUG, "START %s\n", where);
236cabdff1aSopenharmony_ci    av_log(s, AV_LOG_DEBUG, "pos: %"PRIX64"\n", avio_tell(s->pb));
237cabdff1aSopenharmony_ci    av_log(s, AV_LOG_DEBUG, "idx: %X\n", sga->idx);
238cabdff1aSopenharmony_ci    av_log(s, AV_LOG_DEBUG, "packet_type: %X\n", sga->packet_type);
239cabdff1aSopenharmony_ci    av_log(s, AV_LOG_DEBUG, "payload_size: %X\n", sga->payload_size);
240cabdff1aSopenharmony_ci    av_log(s, AV_LOG_DEBUG, "SECTOR: %016"PRIX64"\n", AV_RB64(sga->sector));
241cabdff1aSopenharmony_ci    av_log(s, AV_LOG_DEBUG, "stream: %X\n", sga->sector[1]);
242cabdff1aSopenharmony_ci    av_log(s, AV_LOG_DEBUG, "END %s\n", where);
243cabdff1aSopenharmony_ci}
244cabdff1aSopenharmony_ci
245cabdff1aSopenharmony_cistatic void update_type_size(AVFormatContext *s)
246cabdff1aSopenharmony_ci{
247cabdff1aSopenharmony_ci    SGADemuxContext *sga = s->priv_data;
248cabdff1aSopenharmony_ci
249cabdff1aSopenharmony_ci    if (sga->idx >= 4) {
250cabdff1aSopenharmony_ci        sga->packet_type  = sga->sector[0];
251cabdff1aSopenharmony_ci        sga->payload_size = AV_RB16(sga->sector + 2);
252cabdff1aSopenharmony_ci    } else {
253cabdff1aSopenharmony_ci        sga->packet_type  = 0;
254cabdff1aSopenharmony_ci        sga->payload_size = 0;
255cabdff1aSopenharmony_ci    }
256cabdff1aSopenharmony_ci}
257cabdff1aSopenharmony_ci
258cabdff1aSopenharmony_cistatic int sga_video_packet(AVFormatContext *s, AVPacket *pkt)
259cabdff1aSopenharmony_ci{
260cabdff1aSopenharmony_ci    SGADemuxContext *sga = s->priv_data;
261cabdff1aSopenharmony_ci    int ret;
262cabdff1aSopenharmony_ci
263cabdff1aSopenharmony_ci    if (sga->payload_size <= 8)
264cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
265cabdff1aSopenharmony_ci
266cabdff1aSopenharmony_ci    if (sga->video_stream_index == -1) {
267cabdff1aSopenharmony_ci        AVRational frame_rate;
268cabdff1aSopenharmony_ci
269cabdff1aSopenharmony_ci        AVStream *st = avformat_new_stream(s, NULL);
270cabdff1aSopenharmony_ci        if (!st)
271cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
272cabdff1aSopenharmony_ci
273cabdff1aSopenharmony_ci        st->start_time              = 0;
274cabdff1aSopenharmony_ci        st->codecpar->codec_type    = AVMEDIA_TYPE_VIDEO;
275cabdff1aSopenharmony_ci        st->codecpar->codec_tag     = 0;
276cabdff1aSopenharmony_ci        st->codecpar->codec_id      = AV_CODEC_ID_SGA_VIDEO;
277cabdff1aSopenharmony_ci        sga->video_stream_index     = st->index;
278cabdff1aSopenharmony_ci
279cabdff1aSopenharmony_ci        if (sga->first_audio_size > 0 && sga->sample_rate > 0) {
280cabdff1aSopenharmony_ci            frame_rate.num = sga->sample_rate;
281cabdff1aSopenharmony_ci            frame_rate.den = sga->first_audio_size;
282cabdff1aSopenharmony_ci        } else {
283cabdff1aSopenharmony_ci            frame_rate.num = 15;
284cabdff1aSopenharmony_ci            frame_rate.den = 1;
285cabdff1aSopenharmony_ci        }
286cabdff1aSopenharmony_ci        avpriv_set_pts_info(st, 64, frame_rate.den, frame_rate.num);
287cabdff1aSopenharmony_ci    }
288cabdff1aSopenharmony_ci
289cabdff1aSopenharmony_ci    ret = av_new_packet(pkt, sga->payload_size + 4);
290cabdff1aSopenharmony_ci    if (ret < 0)
291cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
292cabdff1aSopenharmony_ci    memcpy(pkt->data, sga->sector, sga->payload_size + 4);
293cabdff1aSopenharmony_ci    av_assert0(sga->idx >= sga->payload_size + 4);
294cabdff1aSopenharmony_ci    memmove(sga->sector, sga->sector + sga->payload_size + 4, sga->idx - sga->payload_size - 4);
295cabdff1aSopenharmony_ci
296cabdff1aSopenharmony_ci    pkt->stream_index = sga->video_stream_index;
297cabdff1aSopenharmony_ci    pkt->duration = 1;
298cabdff1aSopenharmony_ci    pkt->pos = sga->pkt_pos;
299cabdff1aSopenharmony_ci    pkt->flags |= sga->flags;
300cabdff1aSopenharmony_ci    sga->idx -= sga->payload_size + 4;
301cabdff1aSopenharmony_ci    sga->flags = 0;
302cabdff1aSopenharmony_ci    update_type_size(s);
303cabdff1aSopenharmony_ci
304cabdff1aSopenharmony_ci    av_log(s, AV_LOG_DEBUG, "VIDEO PACKET: %d:%016"PRIX64" i:%X\n", pkt->size, AV_RB64(sga->sector), sga->idx);
305cabdff1aSopenharmony_ci
306cabdff1aSopenharmony_ci    return 0;
307cabdff1aSopenharmony_ci}
308cabdff1aSopenharmony_ci
309cabdff1aSopenharmony_cistatic int sga_audio_packet(AVFormatContext *s, AVPacket *pkt)
310cabdff1aSopenharmony_ci{
311cabdff1aSopenharmony_ci    SGADemuxContext *sga = s->priv_data;
312cabdff1aSopenharmony_ci    int ret;
313cabdff1aSopenharmony_ci
314cabdff1aSopenharmony_ci    if (sga->payload_size <= 8)
315cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
316cabdff1aSopenharmony_ci
317cabdff1aSopenharmony_ci    if (sga->audio_stream_index == -1) {
318cabdff1aSopenharmony_ci        AVStream *st = avformat_new_stream(s, NULL);
319cabdff1aSopenharmony_ci        if (!st)
320cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
321cabdff1aSopenharmony_ci
322cabdff1aSopenharmony_ci        st->start_time              = 0;
323cabdff1aSopenharmony_ci        st->codecpar->codec_type    = AVMEDIA_TYPE_AUDIO;
324cabdff1aSopenharmony_ci        st->codecpar->codec_tag     = 0;
325cabdff1aSopenharmony_ci        st->codecpar->codec_id      = AV_CODEC_ID_PCM_SGA;
326cabdff1aSopenharmony_ci        st->codecpar->ch_layout     = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
327cabdff1aSopenharmony_ci        st->codecpar->sample_rate   = av_rescale(AV_RB16(sga->sector + 8),
328cabdff1aSopenharmony_ci                                                 SEGA_CD_PCM_NUM,
329cabdff1aSopenharmony_ci                                                 SEGA_CD_PCM_DEN);
330cabdff1aSopenharmony_ci        sga->audio_stream_index     = st->index;
331cabdff1aSopenharmony_ci
332cabdff1aSopenharmony_ci        avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
333cabdff1aSopenharmony_ci    }
334cabdff1aSopenharmony_ci
335cabdff1aSopenharmony_ci    ret = av_new_packet(pkt, sga->payload_size - 8);
336cabdff1aSopenharmony_ci    if (ret < 0)
337cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
338cabdff1aSopenharmony_ci    memcpy(pkt->data, sga->sector + 12, sga->payload_size - 8);
339cabdff1aSopenharmony_ci    av_assert0(sga->idx >= sga->payload_size + 4);
340cabdff1aSopenharmony_ci    memmove(sga->sector, sga->sector + sga->payload_size + 4, sga->idx - sga->payload_size - 4);
341cabdff1aSopenharmony_ci
342cabdff1aSopenharmony_ci    pkt->stream_index = sga->audio_stream_index;
343cabdff1aSopenharmony_ci    pkt->duration = pkt->size;
344cabdff1aSopenharmony_ci    pkt->pos = sga->pkt_pos;
345cabdff1aSopenharmony_ci    pkt->flags |= sga->flags;
346cabdff1aSopenharmony_ci    sga->idx -= sga->payload_size + 4;
347cabdff1aSopenharmony_ci    sga->flags = 0;
348cabdff1aSopenharmony_ci    update_type_size(s);
349cabdff1aSopenharmony_ci
350cabdff1aSopenharmony_ci    av_log(s, AV_LOG_DEBUG, "AUDIO PACKET: %d:%016"PRIX64" i:%X\n", pkt->size, AV_RB64(sga->sector), sga->idx);
351cabdff1aSopenharmony_ci
352cabdff1aSopenharmony_ci    return 0;
353cabdff1aSopenharmony_ci}
354cabdff1aSopenharmony_ci
355cabdff1aSopenharmony_cistatic int sga_packet(AVFormatContext *s, AVPacket *pkt)
356cabdff1aSopenharmony_ci{
357cabdff1aSopenharmony_ci    SGADemuxContext *sga = s->priv_data;
358cabdff1aSopenharmony_ci    int ret = 0;
359cabdff1aSopenharmony_ci
360cabdff1aSopenharmony_ci    if (sga->packet_type == 0xCD ||
361cabdff1aSopenharmony_ci        sga->packet_type == 0xCB ||
362cabdff1aSopenharmony_ci        sga->packet_type == 0xC9 ||
363cabdff1aSopenharmony_ci        sga->packet_type == 0xC8 ||
364cabdff1aSopenharmony_ci        sga->packet_type == 0xC7 ||
365cabdff1aSopenharmony_ci        sga->packet_type == 0xC6 ||
366cabdff1aSopenharmony_ci        sga->packet_type == 0xC1 ||
367cabdff1aSopenharmony_ci        sga->packet_type == 0xE7) {
368cabdff1aSopenharmony_ci        ret = sga_video_packet(s, pkt);
369cabdff1aSopenharmony_ci    } else if (sga->packet_type == 0xA1 ||
370cabdff1aSopenharmony_ci               sga->packet_type == 0xA2 ||
371cabdff1aSopenharmony_ci               sga->packet_type == 0xA3 ||
372cabdff1aSopenharmony_ci               sga->packet_type == 0xAA) {
373cabdff1aSopenharmony_ci        ret = sga_audio_packet(s, pkt);
374cabdff1aSopenharmony_ci    } else {
375cabdff1aSopenharmony_ci        if (sga->idx == 0)
376cabdff1aSopenharmony_ci            return AVERROR_EOF;
377cabdff1aSopenharmony_ci        if (sga->sector[0])
378cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
379cabdff1aSopenharmony_ci        memmove(sga->sector, sga->sector + 1, sga->idx - 1);
380cabdff1aSopenharmony_ci        sga->idx--;
381cabdff1aSopenharmony_ci        return AVERROR(EAGAIN);
382cabdff1aSopenharmony_ci    }
383cabdff1aSopenharmony_ci
384cabdff1aSopenharmony_ci    return ret;
385cabdff1aSopenharmony_ci}
386cabdff1aSopenharmony_ci
387cabdff1aSopenharmony_cistatic int try_packet(AVFormatContext *s, AVPacket *pkt)
388cabdff1aSopenharmony_ci{
389cabdff1aSopenharmony_ci    SGADemuxContext *sga = s->priv_data;
390cabdff1aSopenharmony_ci    int ret = AVERROR(EAGAIN);
391cabdff1aSopenharmony_ci
392cabdff1aSopenharmony_ci    update_type_size(s);
393cabdff1aSopenharmony_ci    if (sga->idx >= sga->payload_size + 4) {
394cabdff1aSopenharmony_ci        print_stats(s, "before sga_packet");
395cabdff1aSopenharmony_ci        ret = sga_packet(s, pkt);
396cabdff1aSopenharmony_ci        print_stats(s,  "after sga_packet");
397cabdff1aSopenharmony_ci        if (ret != AVERROR(EAGAIN))
398cabdff1aSopenharmony_ci            return ret;
399cabdff1aSopenharmony_ci    }
400cabdff1aSopenharmony_ci
401cabdff1aSopenharmony_ci    return sga->idx < sga->payload_size + 4 ? AVERROR(EAGAIN) : ret;
402cabdff1aSopenharmony_ci}
403cabdff1aSopenharmony_ci
404cabdff1aSopenharmony_cistatic int sga_read_packet(AVFormatContext *s, AVPacket *pkt)
405cabdff1aSopenharmony_ci{
406cabdff1aSopenharmony_ci    SGADemuxContext *sga = s->priv_data;
407cabdff1aSopenharmony_ci    AVIOContext *pb = s->pb;
408cabdff1aSopenharmony_ci    int header, ret = 0;
409cabdff1aSopenharmony_ci
410cabdff1aSopenharmony_ci    sga->pkt_pos = avio_tell(pb);
411cabdff1aSopenharmony_ci
412cabdff1aSopenharmony_ciretry:
413cabdff1aSopenharmony_ci    update_type_size(s);
414cabdff1aSopenharmony_ci
415cabdff1aSopenharmony_ci    print_stats(s, "start");
416cabdff1aSopenharmony_ci    if (avio_feof(pb) &&
417cabdff1aSopenharmony_ci        (!sga->payload_size || sga->idx < sga->payload_size + 4))
418cabdff1aSopenharmony_ci        return AVERROR_EOF;
419cabdff1aSopenharmony_ci
420cabdff1aSopenharmony_ci    if (sga->idx < sga->payload_size + 4) {
421cabdff1aSopenharmony_ci        ret = ffio_ensure_seekback(pb, 2);
422cabdff1aSopenharmony_ci        if (ret < 0)
423cabdff1aSopenharmony_ci            return ret;
424cabdff1aSopenharmony_ci
425cabdff1aSopenharmony_ci        print_stats(s, "before read header");
426cabdff1aSopenharmony_ci        header = avio_rb16(pb);
427cabdff1aSopenharmony_ci        if (!header) {
428cabdff1aSopenharmony_ci            avio_skip(pb, 2046);
429cabdff1aSopenharmony_ci            sga->left = 0;
430cabdff1aSopenharmony_ci        } else if (!avio_feof(pb) &&
431cabdff1aSopenharmony_ci                   ((header >> 15) ||
432cabdff1aSopenharmony_ci                    !sga->sector_headers)) {
433cabdff1aSopenharmony_ci            avio_seek(pb, -2, SEEK_CUR);
434cabdff1aSopenharmony_ci            sga->flags = AV_PKT_FLAG_KEY;
435cabdff1aSopenharmony_ci            sga->left = 2048;
436cabdff1aSopenharmony_ci        } else {
437cabdff1aSopenharmony_ci            sga->left = 2046;
438cabdff1aSopenharmony_ci        }
439cabdff1aSopenharmony_ci
440cabdff1aSopenharmony_ci        av_assert0(sga->idx + sga->left < sizeof(sga->sector));
441cabdff1aSopenharmony_ci        ret = avio_read(pb, sga->sector + sga->idx, sga->left);
442cabdff1aSopenharmony_ci        if (ret > 0)
443cabdff1aSopenharmony_ci            sga->idx += ret;
444cabdff1aSopenharmony_ci        else if (ret != AVERROR_EOF && ret)
445cabdff1aSopenharmony_ci            return ret;
446cabdff1aSopenharmony_ci        print_stats(s, "after read header");
447cabdff1aSopenharmony_ci
448cabdff1aSopenharmony_ci        update_type_size(s);
449cabdff1aSopenharmony_ci    }
450cabdff1aSopenharmony_ci
451cabdff1aSopenharmony_ci    ret = try_packet(s, pkt);
452cabdff1aSopenharmony_ci    if (ret == AVERROR(EAGAIN))
453cabdff1aSopenharmony_ci        goto retry;
454cabdff1aSopenharmony_ci
455cabdff1aSopenharmony_ci    return ret;
456cabdff1aSopenharmony_ci}
457cabdff1aSopenharmony_ci
458cabdff1aSopenharmony_cistatic int sga_seek(AVFormatContext *s, int stream_index,
459cabdff1aSopenharmony_ci                     int64_t timestamp, int flags)
460cabdff1aSopenharmony_ci{
461cabdff1aSopenharmony_ci    SGADemuxContext *sga = s->priv_data;
462cabdff1aSopenharmony_ci
463cabdff1aSopenharmony_ci    sga->packet_type = sga->payload_size = sga->idx = 0;
464cabdff1aSopenharmony_ci    memset(sga->sector, 0, sizeof(sga->sector));
465cabdff1aSopenharmony_ci
466cabdff1aSopenharmony_ci    return -1;
467cabdff1aSopenharmony_ci}
468cabdff1aSopenharmony_ci
469cabdff1aSopenharmony_ciconst AVInputFormat ff_sga_demuxer = {
470cabdff1aSopenharmony_ci    .name           = "sga",
471cabdff1aSopenharmony_ci    .long_name      = NULL_IF_CONFIG_SMALL("Digital Pictures SGA"),
472cabdff1aSopenharmony_ci    .priv_data_size = sizeof(SGADemuxContext),
473cabdff1aSopenharmony_ci    .read_probe     = sga_probe,
474cabdff1aSopenharmony_ci    .read_header    = sga_read_header,
475cabdff1aSopenharmony_ci    .read_packet    = sga_read_packet,
476cabdff1aSopenharmony_ci    .read_seek      = sga_seek,
477cabdff1aSopenharmony_ci    .extensions     = "sga",
478cabdff1aSopenharmony_ci    .flags          = AVFMT_GENERIC_INDEX,
479cabdff1aSopenharmony_ci};
480