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