2 * Digital Pictures SGA game demuxer
4 * Copyright (C) 2021 Paul B Mahol
6 * This file is part of FFmpeg.
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.
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.
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
23 #include "libavutil/intreadwrite.h"
24 #include "libavutil/avassert.h"
25 #include "libavutil/internal.h"
28 #include "avio_internal.h"
30 #define SEGA_CD_PCM_NUM 12500000
31 #define SEGA_CD_PCM_DEN 786432
33 typedef struct SGADemuxContext {
34 int video_stream_index;
35 int audio_stream_index;
37 uint8_t sector[65536 * 2];
49 static int sga_probe(const AVProbeData *p)
51 const uint8_t *src = p->buf;
52 int score = 0, sectors = 1;
56 if (p->buf_size < 2048)
59 for (int i = 0; i + 2 < p->buf_size; i += 2048) {
60 int header = AV_RB16(src + i);
62 if ((header > 0x07FE && header < 0x8100) ||
63 (header > 0x8200 && header < 0xA100) ||
64 (header > 0xA200 && header < 0xC100)) {
70 for (int i = 0; i + 4 < p->buf_size;) {
71 int header = AV_RB16(src + i);
72 int left = AV_RB16(src + i + 2);
73 int offset, type, size;
77 if (sectors && header && last_left == 0) {
81 } else if (sectors && header) {
84 if (header != 0x7FE && left < 7)
89 i += sectors ? 2048 : left + 4;
94 if (sectors && (i > 0 && left < 0x7fe) &&
95 (i + left + 14 < p->buf_size)) {
96 offset = i + left + 2;
97 } else if (sectors && i > 0) {
99 last_left -= FFMIN(last_left, 2046);
106 header = AV_RB16(src + offset);
107 size = AV_RB16(src + offset + 2) + 4;
109 while ((header & 0xFF00) == 0) {
111 if (offset + 4 >= p->buf_size)
113 header = AV_RB16(src + offset);
114 size = AV_RB16(src + offset + 2) + 4;
117 if (offset + 12 >= p->buf_size)
119 if ((header & 0xFF) > 1)
131 new_rate = AV_RB16(src + offset + 8);
133 sample_rate = new_rate;
134 if (sample_rate == 0 || new_rate != sample_rate)
136 if (src[offset + 10] != 1)
140 } else if (type == 0xC1 ||
148 int nb_pals = src[offset + 9];
149 int tiles_w = src[offset + 10];
150 int tiles_h = src[offset + 11];
154 if (nb_pals == 0 || nb_pals > 4)
156 if (tiles_w == 0 || tiles_w > 80)
158 if (tiles_h == 0 || tiles_h > 60)
162 } else if (header == 0x7FE) {
168 i += sectors ? 2048 : size + 4;
169 last_left -= FFMIN(last_left, 2046);
175 return av_clip(score, 0, AVPROBE_SCORE_MAX);
178 static int sga_read_header(AVFormatContext *s)
180 SGADemuxContext *sga = s->priv_data;
181 AVIOContext *pb = s->pb;
183 sga->sector_headers = 1;
184 sga->first_audio_size = 0;
185 sga->video_stream_index = -1;
186 sga->audio_stream_index = -1;
190 s->ctx_flags |= AVFMTCTX_NOHEADER;
192 if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
193 while (!avio_feof(pb)) {
194 int header = avio_rb16(pb);
195 int type = header >> 8;
199 if (!sga->first_audio_size &&
204 sga->first_audio_size = avio_rb16(pb);
206 clock = avio_rb16(pb);
207 sga->sample_rate = av_rescale(clock,
212 if ((header > 0x07FE && header < 0x8100) ||
213 (header > 0x8200 && header < 0xA100) ||
214 (header > 0xA200 && header < 0xC100)) {
215 sga->sector_headers = 0;
222 avio_seek(pb, 0, SEEK_SET);
228 static void print_stats(AVFormatContext *s, const char *where)
230 SGADemuxContext *sga = s->priv_data;
232 av_log(s, AV_LOG_DEBUG, "START %s\n", where);
233 av_log(s, AV_LOG_DEBUG, "pos: %lX\n", avio_tell(s->pb));
234 av_log(s, AV_LOG_DEBUG, "idx: %X\n", sga->idx);
235 av_log(s, AV_LOG_DEBUG, "packet_type: %X\n", sga->packet_type);
236 av_log(s, AV_LOG_DEBUG, "payload_size: %X\n", sga->payload_size);
237 av_log(s, AV_LOG_DEBUG, "SECTOR: %016lX\n", AV_RB64(sga->sector));
238 av_log(s, AV_LOG_DEBUG, "stream: %X\n", sga->sector[1]);
239 av_log(s, AV_LOG_DEBUG, "END %s\n", where);
242 static void update_type_size(AVFormatContext *s)
244 SGADemuxContext *sga = s->priv_data;
247 sga->packet_type = sga->sector[0];
248 sga->payload_size = AV_RB16(sga->sector + 2);
250 sga->packet_type = 0;
251 sga->payload_size = 0;
255 static int sga_video_packet(AVFormatContext *s, AVPacket *pkt)
257 SGADemuxContext *sga = s->priv_data;
260 if (sga->payload_size <= 8)
261 return AVERROR_INVALIDDATA;
263 if (sga->video_stream_index == -1) {
264 AVRational frame_rate;
266 AVStream *st = avformat_new_stream(s, NULL);
268 return AVERROR(ENOMEM);
271 st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
272 st->codecpar->codec_tag = 0;
273 st->codecpar->codec_id = AV_CODEC_ID_SGA_VIDEO;
274 sga->video_stream_index = st->index;
276 if (sga->first_audio_size > 0 && sga->sample_rate > 0) {
277 frame_rate.num = sga->sample_rate;
278 frame_rate.den = sga->first_audio_size;
283 avpriv_set_pts_info(st, 64, frame_rate.den, frame_rate.num);
286 ret = av_new_packet(pkt, sga->payload_size + 4);
288 return AVERROR(ENOMEM);
289 memcpy(pkt->data, sga->sector, sga->payload_size + 4);
290 av_assert0(sga->idx >= sga->payload_size + 4);
291 memmove(sga->sector, sga->sector + sga->payload_size + 4, sga->idx - sga->payload_size - 4);
293 pkt->stream_index = sga->video_stream_index;
295 pkt->pos = sga->pkt_pos;
296 pkt->flags |= sga->flags;
297 sga->idx -= sga->payload_size + 4;
301 av_log(s, AV_LOG_DEBUG, "VIDEO PACKET: %d:%016lX i:%X\n", pkt->size, AV_RB64(sga->sector), sga->idx);
306 static int sga_audio_packet(AVFormatContext *s, AVPacket *pkt)
308 SGADemuxContext *sga = s->priv_data;
311 if (sga->payload_size <= 8)
312 return AVERROR_INVALIDDATA;
314 if (sga->audio_stream_index == -1) {
315 AVStream *st = avformat_new_stream(s, NULL);
317 return AVERROR(ENOMEM);
320 st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
321 st->codecpar->codec_tag = 0;
322 st->codecpar->codec_id = AV_CODEC_ID_PCM_SGA;
323 st->codecpar->channels = 1;
324 st->codecpar->channel_layout= AV_CH_LAYOUT_MONO;
325 st->codecpar->sample_rate = av_rescale(AV_RB16(sga->sector + 8),
328 sga->audio_stream_index = st->index;
330 avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
333 ret = av_new_packet(pkt, sga->payload_size - 8);
335 return AVERROR(ENOMEM);
336 memcpy(pkt->data, sga->sector + 12, sga->payload_size - 8);
337 av_assert0(sga->idx >= sga->payload_size + 4);
338 memmove(sga->sector, sga->sector + sga->payload_size + 4, sga->idx - sga->payload_size - 4);
340 pkt->stream_index = sga->audio_stream_index;
341 pkt->duration = pkt->size;
342 pkt->pos = sga->pkt_pos;
343 pkt->flags |= sga->flags;
344 sga->idx -= sga->payload_size + 4;
348 av_log(s, AV_LOG_DEBUG, "AUDIO PACKET: %d:%016lX i:%X\n", pkt->size, AV_RB64(sga->sector), sga->idx);
353 static int sga_packet(AVFormatContext *s, AVPacket *pkt)
355 SGADemuxContext *sga = s->priv_data;
358 if (sga->packet_type == 0xCD ||
359 sga->packet_type == 0xCB ||
360 sga->packet_type == 0xC9 ||
361 sga->packet_type == 0xC8 ||
362 sga->packet_type == 0xC7 ||
363 sga->packet_type == 0xC6 ||
364 sga->packet_type == 0xC1 ||
365 sga->packet_type == 0xE7) {
366 ret = sga_video_packet(s, pkt);
367 } else if (sga->packet_type == 0xA1 ||
368 sga->packet_type == 0xA2 ||
369 sga->packet_type == 0xA3 ||
370 sga->packet_type == 0xAA) {
371 ret = sga_audio_packet(s, pkt);
376 return AVERROR_INVALIDDATA;
377 memmove(sga->sector, sga->sector + 1, sga->idx - 1);
379 return AVERROR(EAGAIN);
385 static int try_packet(AVFormatContext *s, AVPacket *pkt)
387 SGADemuxContext *sga = s->priv_data;
388 int ret = AVERROR(EAGAIN);
391 if (sga->idx >= sga->payload_size + 4) {
392 print_stats(s, "before sga_packet");
393 ret = sga_packet(s, pkt);
394 print_stats(s, "after sga_packet");
395 if (ret != AVERROR(EAGAIN))
399 return sga->idx < sga->payload_size + 4 ? AVERROR(EAGAIN) : ret;
402 static int sga_read_packet(AVFormatContext *s, AVPacket *pkt)
404 SGADemuxContext *sga = s->priv_data;
405 AVIOContext *pb = s->pb;
408 sga->pkt_pos = avio_tell(pb);
413 print_stats(s, "start");
415 (!sga->payload_size || sga->idx < sga->payload_size + 4))
418 if (sga->idx < sga->payload_size + 4) {
419 ret = ffio_ensure_seekback(pb, 2);
423 print_stats(s, "before read header");
424 header = avio_rb16(pb);
428 } else if (!avio_feof(pb) &&
430 !sga->sector_headers)) {
431 avio_seek(pb, -2, SEEK_CUR);
432 sga->flags = AV_PKT_FLAG_KEY;
438 av_assert0(sga->idx + sga->left < sizeof(sga->sector));
439 ret = avio_read(pb, sga->sector + sga->idx, sga->left);
442 else if (ret != AVERROR_EOF && ret)
444 print_stats(s, "after read header");
449 ret = try_packet(s, pkt);
450 if (ret == AVERROR(EAGAIN))
456 static int sga_seek(AVFormatContext *s, int stream_index,
457 int64_t timestamp, int flags)
459 SGADemuxContext *sga = s->priv_data;
461 sga->packet_type = sga->payload_size = sga->idx = 0;
462 memset(sga->sector, 0, sizeof(sga->sector));
467 AVInputFormat ff_sga_demuxer = {
469 .long_name = NULL_IF_CONFIG_SMALL("Digital Pictures SGA"),
470 .priv_data_size = sizeof(SGADemuxContext),
471 .read_probe = sga_probe,
472 .read_header = sga_read_header,
473 .read_packet = sga_read_packet,
474 .read_seek = sga_seek,
476 .flags = AVFMT_GENERIC_INDEX,