• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
34 typedef 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 
sga_probe(const AVProbeData * p)50 static 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 
sga_read_header(AVFormatContext * s)181 static 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 
print_stats(AVFormatContext * s,const char * where)231 static 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 
update_type_size(AVFormatContext * s)245 static 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 
sga_video_packet(AVFormatContext * s,AVPacket * pkt)258 static 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 
sga_audio_packet(AVFormatContext * s,AVPacket * pkt)309 static 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 
sga_packet(AVFormatContext * s,AVPacket * pkt)355 static 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 
try_packet(AVFormatContext * s,AVPacket * pkt)387 static 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 
sga_read_packet(AVFormatContext * s,AVPacket * pkt)404 static 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 
412 retry:
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 
sga_seek(AVFormatContext * s,int stream_index,int64_t timestamp,int flags)458 static 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 
469 const 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