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/channel_layout.h"
26 #include "libavutil/internal.h"
30 #include "avio_internal.h"
32 #define SEGA_CD_PCM_NUM 12500000
33 #define SEGA_CD_PCM_DEN 786432
35 typedef struct SGADemuxContext
{
36 int video_stream_index
;
37 int audio_stream_index
;
39 uint8_t sector
[65536 * 2];
51 static int sga_probe(const AVProbeData
*p
)
53 const uint8_t *src
= p
->buf
;
54 int score
= 0, sectors
= 1;
58 if (p
->buf_size
< 2048)
61 for (int i
= 0; i
+ 2 < p
->buf_size
; i
+= 2048) {
62 int header
= AV_RB16(src
+ i
);
64 if ((header
> 0x07FE && header
< 0x8100) ||
65 (header
> 0x8200 && header
< 0xA100) ||
66 (header
> 0xA200 && header
< 0xC100)) {
72 for (int i
= 0; i
+ 4 < p
->buf_size
;) {
73 int header
= AV_RB16(src
+ i
);
74 int left
= AV_RB16(src
+ i
+ 2);
75 int offset
, type
, size
;
79 if (sectors
&& header
&& last_left
== 0) {
83 last_left
= left
= header
;
85 } else if (sectors
&& header
) {
88 if (header
!= 0x7FE && left
< 7)
93 i
+= sectors
? 2048 : left
+ 4;
98 if (sectors
&& (i
> 0 && left
< 0x7fe) &&
99 (i
+ left
+ 14 < p
->buf_size
)) {
100 offset
= i
+ left
+ 2;
101 } else if (sectors
&& i
> 0) {
103 last_left
-= FFMIN(last_left
, 2046);
110 header
= AV_RB16(src
+ offset
);
111 size
= AV_RB16(src
+ offset
+ 2) + 4;
113 while ((header
& 0xFF00) == 0) {
115 if (offset
+ 4 >= p
->buf_size
)
117 header
= AV_RB16(src
+ offset
);
118 size
= AV_RB16(src
+ offset
+ 2) + 4;
121 if (offset
+ 12 >= p
->buf_size
)
123 if ((header
& 0xFF) > 1)
135 new_rate
= AV_RB16(src
+ offset
+ 8);
137 sample_rate
= new_rate
;
138 if (sample_rate
== 0 || new_rate
!= sample_rate
)
140 if (src
[offset
+ 10] != 1)
144 } else if (type
== 0xC1 ||
152 int nb_pals
= src
[offset
+ 9];
153 int tiles_w
= src
[offset
+ 10];
154 int tiles_h
= src
[offset
+ 11];
158 if (nb_pals
== 0 || nb_pals
> 4)
160 if (tiles_w
== 0 || tiles_w
> 80)
162 if (tiles_h
== 0 || tiles_h
> 60)
166 } else if (header
== 0x7FE) {
172 i
+= sectors
? 2048 : size
+ 4;
173 last_left
-= FFMIN(last_left
, 2046);
179 return av_clip(score
, 0, AVPROBE_SCORE_MAX
);
182 static int sga_read_header(AVFormatContext
*s
)
184 SGADemuxContext
*sga
= s
->priv_data
;
185 AVIOContext
*pb
= s
->pb
;
187 sga
->sector_headers
= 1;
188 sga
->first_audio_size
= 0;
189 sga
->video_stream_index
= -1;
190 sga
->audio_stream_index
= -1;
194 s
->ctx_flags
|= AVFMTCTX_NOHEADER
;
196 if (pb
->seekable
& AVIO_SEEKABLE_NORMAL
) {
197 while (!avio_feof(pb
)) {
198 int header
= avio_rb16(pb
);
199 int type
= header
>> 8;
203 if (!sga
->first_audio_size
&&
208 sga
->first_audio_size
= avio_rb16(pb
);
210 clock
= avio_rb16(pb
);
211 sga
->sample_rate
= av_rescale(clock
,
216 if ((header
> 0x07FE && header
< 0x8100) ||
217 (header
> 0x8200 && header
< 0xA100) ||
218 (header
> 0xA200 && header
< 0xC100)) {
219 sga
->sector_headers
= 0;
226 avio_seek(pb
, 0, SEEK_SET
);
232 static void print_stats(AVFormatContext
*s
, const char *where
)
234 SGADemuxContext
*sga
= s
->priv_data
;
236 av_log(s
, AV_LOG_DEBUG
, "START %s\n", where
);
237 av_log(s
, AV_LOG_DEBUG
, "pos: %"PRIX64
"\n", avio_tell(s
->pb
));
238 av_log(s
, AV_LOG_DEBUG
, "idx: %X\n", sga
->idx
);
239 av_log(s
, AV_LOG_DEBUG
, "packet_type: %X\n", sga
->packet_type
);
240 av_log(s
, AV_LOG_DEBUG
, "payload_size: %X\n", sga
->payload_size
);
241 av_log(s
, AV_LOG_DEBUG
, "SECTOR: %016"PRIX64
"\n", AV_RB64(sga
->sector
));
242 av_log(s
, AV_LOG_DEBUG
, "stream: %X\n", sga
->sector
[1]);
243 av_log(s
, AV_LOG_DEBUG
, "END %s\n", where
);
246 static void update_type_size(AVFormatContext
*s
)
248 SGADemuxContext
*sga
= s
->priv_data
;
251 sga
->packet_type
= sga
->sector
[0];
252 sga
->payload_size
= AV_RB16(sga
->sector
+ 2);
254 sga
->packet_type
= 0;
255 sga
->payload_size
= 0;
259 static int sga_video_packet(AVFormatContext
*s
, AVPacket
*pkt
)
261 SGADemuxContext
*sga
= s
->priv_data
;
264 if (sga
->payload_size
<= 8)
265 return AVERROR_INVALIDDATA
;
267 if (sga
->video_stream_index
== -1) {
268 AVRational frame_rate
;
270 AVStream
*st
= avformat_new_stream(s
, NULL
);
272 return AVERROR(ENOMEM
);
275 st
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
276 st
->codecpar
->codec_tag
= 0;
277 st
->codecpar
->codec_id
= AV_CODEC_ID_SGA_VIDEO
;
278 sga
->video_stream_index
= st
->index
;
280 if (sga
->first_audio_size
> 0 && sga
->sample_rate
> 0) {
281 frame_rate
.num
= sga
->sample_rate
;
282 frame_rate
.den
= sga
->first_audio_size
;
287 avpriv_set_pts_info(st
, 64, frame_rate
.den
, frame_rate
.num
);
290 ret
= av_new_packet(pkt
, sga
->payload_size
+ 4);
292 return AVERROR(ENOMEM
);
293 memcpy(pkt
->data
, sga
->sector
, sga
->payload_size
+ 4);
294 av_assert0(sga
->idx
>= sga
->payload_size
+ 4);
295 memmove(sga
->sector
, sga
->sector
+ sga
->payload_size
+ 4, sga
->idx
- sga
->payload_size
- 4);
297 pkt
->stream_index
= sga
->video_stream_index
;
299 pkt
->pos
= sga
->pkt_pos
;
300 pkt
->flags
|= sga
->flags
;
301 sga
->idx
-= sga
->payload_size
+ 4;
305 av_log(s
, AV_LOG_DEBUG
, "VIDEO PACKET: %d:%016"PRIX64
" i:%X\n", pkt
->size
, AV_RB64(sga
->sector
), sga
->idx
);
310 static int sga_audio_packet(AVFormatContext
*s
, AVPacket
*pkt
)
312 SGADemuxContext
*sga
= s
->priv_data
;
315 if (sga
->payload_size
<= 8)
316 return AVERROR_INVALIDDATA
;
318 if (sga
->audio_stream_index
== -1) {
319 AVStream
*st
= avformat_new_stream(s
, NULL
);
321 return AVERROR(ENOMEM
);
324 st
->codecpar
->codec_type
= AVMEDIA_TYPE_AUDIO
;
325 st
->codecpar
->codec_tag
= 0;
326 st
->codecpar
->codec_id
= AV_CODEC_ID_PCM_SGA
;
327 st
->codecpar
->ch_layout
= (AVChannelLayout
)AV_CHANNEL_LAYOUT_MONO
;
328 st
->codecpar
->sample_rate
= av_rescale(AV_RB16(sga
->sector
+ 8),
331 sga
->audio_stream_index
= st
->index
;
333 avpriv_set_pts_info(st
, 64, 1, st
->codecpar
->sample_rate
);
336 ret
= av_new_packet(pkt
, sga
->payload_size
- 8);
338 return AVERROR(ENOMEM
);
339 memcpy(pkt
->data
, sga
->sector
+ 12, sga
->payload_size
- 8);
340 av_assert0(sga
->idx
>= sga
->payload_size
+ 4);
341 memmove(sga
->sector
, sga
->sector
+ sga
->payload_size
+ 4, sga
->idx
- sga
->payload_size
- 4);
343 pkt
->stream_index
= sga
->audio_stream_index
;
344 pkt
->duration
= pkt
->size
;
345 pkt
->pos
= sga
->pkt_pos
;
346 pkt
->flags
|= sga
->flags
;
347 sga
->idx
-= sga
->payload_size
+ 4;
351 av_log(s
, AV_LOG_DEBUG
, "AUDIO PACKET: %d:%016"PRIX64
" i:%X\n", pkt
->size
, AV_RB64(sga
->sector
), sga
->idx
);
356 static int sga_packet(AVFormatContext
*s
, AVPacket
*pkt
)
358 SGADemuxContext
*sga
= s
->priv_data
;
361 if (sga
->packet_type
== 0xCD ||
362 sga
->packet_type
== 0xCB ||
363 sga
->packet_type
== 0xC9 ||
364 sga
->packet_type
== 0xC8 ||
365 sga
->packet_type
== 0xC7 ||
366 sga
->packet_type
== 0xC6 ||
367 sga
->packet_type
== 0xC1 ||
368 sga
->packet_type
== 0xE7) {
369 ret
= sga_video_packet(s
, pkt
);
370 } else if (sga
->packet_type
== 0xA1 ||
371 sga
->packet_type
== 0xA2 ||
372 sga
->packet_type
== 0xA3 ||
373 sga
->packet_type
== 0xAA) {
374 ret
= sga_audio_packet(s
, pkt
);
379 return AVERROR_INVALIDDATA
;
380 memmove(sga
->sector
, sga
->sector
+ 1, sga
->idx
- 1);
382 return AVERROR(EAGAIN
);
388 static int try_packet(AVFormatContext
*s
, AVPacket
*pkt
)
390 SGADemuxContext
*sga
= s
->priv_data
;
391 int ret
= AVERROR(EAGAIN
);
394 if (sga
->idx
>= sga
->payload_size
+ 4) {
395 print_stats(s
, "before sga_packet");
396 ret
= sga_packet(s
, pkt
);
397 print_stats(s
, "after sga_packet");
398 if (ret
!= AVERROR(EAGAIN
))
402 return sga
->idx
< sga
->payload_size
+ 4 ? AVERROR(EAGAIN
) : ret
;
405 static int sga_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
407 SGADemuxContext
*sga
= s
->priv_data
;
408 AVIOContext
*pb
= s
->pb
;
411 sga
->pkt_pos
= avio_tell(pb
);
416 print_stats(s
, "start");
418 (!sga
->payload_size
|| sga
->idx
< sga
->payload_size
+ 4))
421 if (sga
->idx
< sga
->payload_size
+ 4) {
422 ret
= ffio_ensure_seekback(pb
, 2);
426 print_stats(s
, "before read header");
427 header
= avio_rb16(pb
);
431 } else if (!avio_feof(pb
) &&
433 !sga
->sector_headers
)) {
434 avio_seek(pb
, -2, SEEK_CUR
);
435 sga
->flags
= AV_PKT_FLAG_KEY
;
441 av_assert0(sga
->idx
+ sga
->left
< sizeof(sga
->sector
));
442 ret
= avio_read(pb
, sga
->sector
+ sga
->idx
, sga
->left
);
445 else if (ret
!= AVERROR_EOF
&& ret
)
447 print_stats(s
, "after read header");
452 ret
= try_packet(s
, pkt
);
453 if (ret
== AVERROR(EAGAIN
))
459 static int sga_seek(AVFormatContext
*s
, int stream_index
,
460 int64_t timestamp
, int flags
)
462 SGADemuxContext
*sga
= s
->priv_data
;
464 sga
->packet_type
= sga
->payload_size
= sga
->idx
= 0;
465 memset(sga
->sector
, 0, sizeof(sga
->sector
));
470 const FFInputFormat ff_sga_demuxer
= {
472 .p
.long_name
= NULL_IF_CONFIG_SMALL("Digital Pictures SGA"),
473 .p
.extensions
= "sga",
474 .p
.flags
= AVFMT_GENERIC_INDEX
,
475 .priv_data_size
= sizeof(SGADemuxContext
),
476 .read_probe
= sga_probe
,
477 .read_header
= sga_read_header
,
478 .read_packet
= sga_read_packet
,
479 .read_seek
= sga_seek
,