FFmpeg
sga.c
Go to the documentation of this file.
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/internal.h"
26 #include "avformat.h"
27 #include "internal.h"
28 #include "avio_internal.h"
29 
30 #define SEGA_CD_PCM_NUM 12500000
31 #define SEGA_CD_PCM_DEN 786432
32 
33 typedef struct SGADemuxContext {
36 
37  uint8_t sector[65536 * 2];
43  int flags;
44  int idx;
45  int left;
46  int64_t pkt_pos;
48 
49 static int sga_probe(const AVProbeData *p)
50 {
51  const uint8_t *src = p->buf;
52  int score = 0, sectors = 1;
53  int last_left = 0;
54  int sample_rate = -1;
55 
56  if (p->buf_size < 2048)
57  return 0;
58 
59  for (int i = 0; i + 2 < p->buf_size; i += 2048) {
60  int header = AV_RB16(src + i);
61 
62  if ((header > 0x07FE && header < 0x8100) ||
63  (header > 0x8200 && header < 0xA100) ||
64  (header > 0xA200 && header < 0xC100)) {
65  sectors = 0;
66  break;
67  }
68  }
69 
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;
74 
75  if (last_left < 0)
76  return 0;
77  if (sectors && header && last_left == 0) {
78  if (header >> 12) {
79  last_left = left;
80  } else {
81  last_left = left = header;
82  }
83  } else if (sectors && header) {
84  left = header;
85  last_left -= left;
86  if (header != 0x7FE && left < 7)
87  return 0;
88  } else if (sectors) {
89  if (left <= 8)
90  return 0;
91  i += sectors ? 2048 : left + 4;
92  last_left = 0;
93  continue;
94  }
95 
96  if (sectors && (i > 0 && left < 0x7fe) &&
97  (i + left + 14 < p->buf_size)) {
98  offset = i + left + 2;
99  } else if (sectors && i > 0) {
100  i += 2048;
101  last_left -= FFMIN(last_left, 2046);
102  continue;
103  } else {
104  offset = 0;
105  last_left = left;
106  }
107 
108  header = AV_RB16(src + offset);
109  size = AV_RB16(src + offset + 2) + 4;
110 
111  while ((header & 0xFF00) == 0) {
112  offset++;
113  if (offset + 4 >= p->buf_size)
114  break;
115  header = AV_RB16(src + offset);
116  size = AV_RB16(src + offset + 2) + 4;
117  }
118 
119  if (offset + 12 >= p->buf_size)
120  break;
121  if ((header & 0xFF) > 1)
122  return 0;
123  type = header >> 8;
124 
125  if (type == 0xAA ||
126  type == 0xA1 ||
127  type == 0xA2 ||
128  type == 0xA3) {
129  int new_rate;
130 
131  if (size <= 12)
132  return 0;
133  new_rate = AV_RB16(src + offset + 8);
134  if (sample_rate < 0)
135  sample_rate = new_rate;
136  if (sample_rate == 0 || new_rate != sample_rate)
137  return 0;
138  if (src[offset + 10] != 1)
139  return 0;
140 
141  score += 10;
142  } else if (type == 0xC1 ||
143  type == 0xC6 ||
144  type == 0xC7 ||
145  type == 0xC8 ||
146  type == 0xC9 ||
147  type == 0xCB ||
148  type == 0xCD ||
149  type == 0xE7) {
150  int nb_pals = src[offset + 9];
151  int tiles_w = src[offset + 10];
152  int tiles_h = src[offset + 11];
153 
154  if (size <= 12)
155  return 0;
156  if (nb_pals == 0 || nb_pals > 4)
157  return 0;
158  if (tiles_w == 0 || tiles_w > 80)
159  return 0;
160  if (tiles_h == 0 || tiles_h > 60)
161  return 0;
162 
163  score += 10;
164  } else if (header == 0x7FE) {
165  ;
166  } else {
167  return 0;
168  }
169 
170  i += sectors ? 2048 : size + 4;
171  last_left -= FFMIN(last_left, 2046);
172 
173  if (score < 0)
174  break;
175  }
176 
177  return av_clip(score, 0, AVPROBE_SCORE_MAX);
178 }
179 
181 {
182  SGADemuxContext *sga = s->priv_data;
183  AVIOContext *pb = s->pb;
184 
185  sga->sector_headers = 1;
186  sga->first_audio_size = 0;
187  sga->video_stream_index = -1;
188  sga->audio_stream_index = -1;
189  sga->left = 2048;
190  sga->idx = 0;
191 
193 
194  if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
195  while (!avio_feof(pb)) {
196  int header = avio_rb16(pb);
197  int type = header >> 8;
198  int skip = 2046;
199  int clock;
200 
201  if (!sga->first_audio_size &&
202  (type == 0xAA ||
203  type == 0xA1 ||
204  type == 0xA2 ||
205  type == 0xA3)) {
206  sga->first_audio_size = avio_rb16(pb);
207  avio_skip(pb, 4);
208  clock = avio_rb16(pb);
209  sga->sample_rate = av_rescale(clock,
212  skip -= 8;
213  }
214  if ((header > 0x07FE && header < 0x8100) ||
215  (header > 0x8200 && header < 0xA100) ||
216  (header > 0xA200 && header < 0xC100)) {
217  sga->sector_headers = 0;
218  break;
219  }
220 
221  avio_skip(pb, skip);
222  }
223 
224  avio_seek(pb, 0, SEEK_SET);
225  }
226 
227  return 0;
228 }
229 
230 static void print_stats(AVFormatContext *s, const char *where)
231 {
232  SGADemuxContext *sga = s->priv_data;
233 
234  av_log(s, AV_LOG_DEBUG, "START %s\n", where);
235  av_log(s, AV_LOG_DEBUG, "pos: %"PRIX64"\n", avio_tell(s->pb));
236  av_log(s, AV_LOG_DEBUG, "idx: %X\n", sga->idx);
237  av_log(s, AV_LOG_DEBUG, "packet_type: %X\n", sga->packet_type);
238  av_log(s, AV_LOG_DEBUG, "payload_size: %X\n", sga->payload_size);
239  av_log(s, AV_LOG_DEBUG, "SECTOR: %016"PRIX64"\n", AV_RB64(sga->sector));
240  av_log(s, AV_LOG_DEBUG, "stream: %X\n", sga->sector[1]);
241  av_log(s, AV_LOG_DEBUG, "END %s\n", where);
242 }
243 
245 {
246  SGADemuxContext *sga = s->priv_data;
247 
248  if (sga->idx >= 4) {
249  sga->packet_type = sga->sector[0];
250  sga->payload_size = AV_RB16(sga->sector + 2);
251  } else {
252  sga->packet_type = 0;
253  sga->payload_size = 0;
254  }
255 }
256 
258 {
259  SGADemuxContext *sga = s->priv_data;
260  int ret;
261 
262  if (sga->payload_size <= 8)
263  return AVERROR_INVALIDDATA;
264 
265  if (sga->video_stream_index == -1) {
266  AVRational frame_rate;
267 
269  if (!st)
270  return AVERROR(ENOMEM);
271 
272  st->start_time = 0;
274  st->codecpar->codec_tag = 0;
276  sga->video_stream_index = st->index;
277 
278  if (sga->first_audio_size > 0 && sga->sample_rate > 0) {
279  frame_rate.num = sga->sample_rate;
280  frame_rate.den = sga->first_audio_size;
281  } else {
282  frame_rate.num = 15;
283  frame_rate.den = 1;
284  }
285  avpriv_set_pts_info(st, 64, frame_rate.den, frame_rate.num);
286  }
287 
288  ret = av_new_packet(pkt, sga->payload_size + 4);
289  if (ret < 0)
290  return AVERROR(ENOMEM);
291  memcpy(pkt->data, sga->sector, sga->payload_size + 4);
292  av_assert0(sga->idx >= sga->payload_size + 4);
293  memmove(sga->sector, sga->sector + sga->payload_size + 4, sga->idx - sga->payload_size - 4);
294 
295  pkt->stream_index = sga->video_stream_index;
296  pkt->duration = 1;
297  pkt->pos = sga->pkt_pos;
298  pkt->flags |= sga->flags;
299  sga->idx -= sga->payload_size + 4;
300  sga->flags = 0;
301  update_type_size(s);
302 
303  av_log(s, AV_LOG_DEBUG, "VIDEO PACKET: %d:%016"PRIX64" i:%X\n", pkt->size, AV_RB64(sga->sector), sga->idx);
304 
305  return 0;
306 }
307 
309 {
310  SGADemuxContext *sga = s->priv_data;
311  int ret;
312 
313  if (sga->payload_size <= 8)
314  return AVERROR_INVALIDDATA;
315 
316  if (sga->audio_stream_index == -1) {
318  if (!st)
319  return AVERROR(ENOMEM);
320 
321  st->start_time = 0;
323  st->codecpar->codec_tag = 0;
325  st->codecpar->channels = 1;
327  st->codecpar->sample_rate = av_rescale(AV_RB16(sga->sector + 8),
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 
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 
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 
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 
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 
470  .name = "sga",
471  .long_name = NULL_IF_CONFIG_SMALL("Digital Pictures SGA"),
472  .priv_data_size = sizeof(SGADemuxContext),
476  .read_seek = sga_seek,
477  .extensions = "sga",
479 };
#define NULL
Definition: coverity.c:32
static int try_packet(AVFormatContext *s, AVPacket *pkt)
Definition: sga.c:387
Bytestream IO Context.
Definition: avio.h:161
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
static int sga_packet(AVFormatContext *s, AVPacket *pkt)
Definition: sga.c:355
int packet_type
Definition: sga.c:42
int64_t pos
byte position in stream, -1 if unknown
Definition: packet.h:389
void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition: utils.c:4999
static int read_seek(AVFormatContext *ctx, int stream_index, int64_t timestamp, int flags)
Definition: libcdio.c:153
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:60
int num
Numerator.
Definition: rational.h:59
int index
stream index in AVFormatContext
Definition: avformat.h:885
int size
Definition: packet.h:370
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:253
static int sga_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition: sga.c:404
static void print_stats(AVFormatContext *s, const char *where)
Definition: sga.c:230
GLint GLenum type
Definition: opengl_enc.c:104
int64_t avio_skip(AVIOContext *s, int64_t offset)
Skip given number of bytes forward.
Definition: aviobuf.c:337
AVPacket * pkt
Definition: movenc.c:59
unsigned int avio_rb16(AVIOContext *s)
Definition: aviobuf.c:766
int ctx_flags
Flags signalling stream properties.
Definition: avformat.h:1296
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_WB24 unsigned int_TMPL AV_RB16
Definition: bytestream.h:91
Format I/O context.
Definition: avformat.h:1247
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
uint8_t
int video_stream_index
Definition: sga.c:34
static int sga_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
Definition: sga.c:458
#define AVFMTCTX_NOHEADER
signal that no header is present (streams are added dynamically)
Definition: avformat.h:1187
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: packet.h:387
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:4553
int first_audio_size
Definition: sga.c:40
#define av_clip
Definition: common.h:122
uint8_t * data
Definition: packet.h:369
int left
Definition: sga.c:45
#define AVERROR_EOF
End of file.
Definition: error.h:55
#define SEGA_CD_PCM_DEN
Definition: sga.c:31
ptrdiff_t size
Definition: opengl_enc.c:100
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:557
static const uint8_t header[24]
Definition: sdr2.c:67
static int sga_probe(const AVProbeData *p)
Definition: sga.c:49
uint64_t channel_layout
Audio only.
Definition: codec_par.h:162
#define av_log(a,...)
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:633
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: packet.h:410
#define src
Definition: vp8dsp.c:255
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: avpacket.c:99
AVInputFormat ff_sga_demuxer
Definition: sga.c:469
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:117
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:215
enum AVMediaType codec_type
General type of the encoded data.
Definition: codec_par.h:56
simple assert() macros that are a bit more flexible than ISO C assert().
static int sga_read_header(AVFormatContext *s)
Definition: sga.c:180
int flags
A combination of AV_PKT_FLAG values.
Definition: packet.h:375
int buf_size
Size of buf except extra allocated bytes.
Definition: avformat.h:444
unsigned char * buf
Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero.
Definition: avformat.h:443
common internal API header
int seekable
A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable.
Definition: avio.h:260
int64_t pkt_pos
Definition: sga.c:46
int64_t av_rescale(int64_t a, int64_t b, int64_t c)
Rescale a 64-bit integer with rounding to nearest.
Definition: mathematics.c:129
#define FFMIN(a, b)
Definition: common.h:105
int audio_stream_index
Definition: sga.c:35
uint8_t sector[65536 *2]
Definition: sga.c:37
#define s(width, name)
Definition: cbs_vp9.c:257
static int read_header(FFV1Context *f)
Definition: ffv1dec.c:527
Stream structure.
Definition: avformat.h:884
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
Definition: avio_reading.c:42
int payload_size
Definition: sga.c:41
#define AVIO_SEEKABLE_NORMAL
Seeking works like for a local file.
Definition: avio.h:40
int sector_headers
Definition: sga.c:38
AVIOContext * pb
I/O context.
Definition: avformat.h:1289
static int sga_audio_packet(AVFormatContext *s, AVPacket *pkt)
Definition: sga.c:308
#define AVFMT_GENERIC_INDEX
Use generic index building code.
Definition: avformat.h:463
Rational number (pair of numerator and denominator).
Definition: rational.h:58
int flags
Definition: sga.c:43
This structure contains the data a format has to probe a file.
Definition: avformat.h:441
static int read_probe(const AVProbeData *pd)
Definition: jvdec.c:55
int ffio_ensure_seekback(AVIOContext *s, int64_t buf_size)
Ensures that the requested seekback buffer size will be available.
Definition: aviobuf.c:998
int sample_rate
Audio only.
Definition: codec_par.h:170
#define AVPROBE_SCORE_MAX
maximum score
Definition: avformat.h:453
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_RB64
Definition: bytestream.h:91
Main libavformat public API header.
int64_t start_time
Decoding: pts of the first frame of the stream in presentation order, in stream time base...
Definition: avformat.h:923
static int sga_video_packet(AVFormatContext *s, AVPacket *pkt)
Definition: sga.c:257
#define SEGA_CD_PCM_NUM
Definition: sga.c:30
int den
Denominator.
Definition: rational.h:60
int sample_rate
Definition: sga.c:39
void * priv_data
Format private data.
Definition: avformat.h:1275
int channels
Audio only.
Definition: codec_par.h:166
int idx
Definition: sga.c:44
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:654
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1049
int avio_feof(AVIOContext *s)
Similar to feof() but also returns nonzero on read errors.
Definition: aviobuf.c:364
uint32_t codec_tag
Additional information about the codec (corresponds to the AVI FOURCC).
Definition: codec_par.h:64
int stream_index
Definition: packet.h:371
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
#define AV_CH_LAYOUT_MONO
static void update_type_size(AVFormatContext *s)
Definition: sga.c:244
This structure stores compressed data.
Definition: packet.h:346
int i
Definition: input.c:407