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