1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * RSD demuxer 3cabdff1aSopenharmony_ci * Copyright (c) 2013 James Almer 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 23cabdff1aSopenharmony_ci#include "avformat.h" 24cabdff1aSopenharmony_ci#include "avio.h" 25cabdff1aSopenharmony_ci#include "demux.h" 26cabdff1aSopenharmony_ci#include "internal.h" 27cabdff1aSopenharmony_ci 28cabdff1aSopenharmony_cistatic const AVCodecTag rsd_tags[] = { 29cabdff1aSopenharmony_ci { AV_CODEC_ID_ADPCM_PSX, MKTAG('V','A','G',' ') }, 30cabdff1aSopenharmony_ci { AV_CODEC_ID_ADPCM_THP_LE, MKTAG('G','A','D','P') }, 31cabdff1aSopenharmony_ci { AV_CODEC_ID_ADPCM_THP, MKTAG('W','A','D','P') }, 32cabdff1aSopenharmony_ci { AV_CODEC_ID_ADPCM_IMA_RAD, MKTAG('R','A','D','P') }, 33cabdff1aSopenharmony_ci { AV_CODEC_ID_ADPCM_IMA_WAV, MKTAG('X','A','D','P') }, 34cabdff1aSopenharmony_ci { AV_CODEC_ID_PCM_S16BE, MKTAG('P','C','M','B') }, 35cabdff1aSopenharmony_ci { AV_CODEC_ID_PCM_S16LE, MKTAG('P','C','M',' ') }, 36cabdff1aSopenharmony_ci { AV_CODEC_ID_XMA2, MKTAG('X','M','A',' ') }, 37cabdff1aSopenharmony_ci { AV_CODEC_ID_NONE, 0 }, 38cabdff1aSopenharmony_ci}; 39cabdff1aSopenharmony_ci 40cabdff1aSopenharmony_cistatic const uint32_t rsd_unsupported_tags[] = { 41cabdff1aSopenharmony_ci MKTAG('O','G','G',' '), 42cabdff1aSopenharmony_ci}; 43cabdff1aSopenharmony_ci 44cabdff1aSopenharmony_cistatic int rsd_probe(const AVProbeData *p) 45cabdff1aSopenharmony_ci{ 46cabdff1aSopenharmony_ci if (memcmp(p->buf, "RSD", 3) || p->buf[3] - '0' < 2 || p->buf[3] - '0' > 6) 47cabdff1aSopenharmony_ci return 0; 48cabdff1aSopenharmony_ci if (AV_RL32(p->buf + 8) > 256 || !AV_RL32(p->buf + 8)) 49cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX / 8; 50cabdff1aSopenharmony_ci if (AV_RL32(p->buf + 16) > 8*48000 || !AV_RL32(p->buf + 16)) 51cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX / 8; 52cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 53cabdff1aSopenharmony_ci} 54cabdff1aSopenharmony_ci 55cabdff1aSopenharmony_cistatic int rsd_read_header(AVFormatContext *s) 56cabdff1aSopenharmony_ci{ 57cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 58cabdff1aSopenharmony_ci int i, ret, version, start = 0x800; 59cabdff1aSopenharmony_ci AVCodecParameters *par; 60cabdff1aSopenharmony_ci AVStream *st = avformat_new_stream(s, NULL); 61cabdff1aSopenharmony_ci 62cabdff1aSopenharmony_ci if (!st) 63cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 64cabdff1aSopenharmony_ci 65cabdff1aSopenharmony_ci avio_skip(pb, 3); // "RSD" 66cabdff1aSopenharmony_ci version = avio_r8(pb) - '0'; 67cabdff1aSopenharmony_ci 68cabdff1aSopenharmony_ci par = st->codecpar; 69cabdff1aSopenharmony_ci par->codec_type = AVMEDIA_TYPE_AUDIO; 70cabdff1aSopenharmony_ci par->codec_tag = avio_rl32(pb); 71cabdff1aSopenharmony_ci par->codec_id = ff_codec_get_id(rsd_tags, par->codec_tag); 72cabdff1aSopenharmony_ci if (!par->codec_id) { 73cabdff1aSopenharmony_ci const char *tag_buf = av_fourcc2str(par->codec_tag); 74cabdff1aSopenharmony_ci for (i=0; i < FF_ARRAY_ELEMS(rsd_unsupported_tags); i++) { 75cabdff1aSopenharmony_ci if (par->codec_tag == rsd_unsupported_tags[i]) { 76cabdff1aSopenharmony_ci avpriv_request_sample(s, "Codec tag: %s", tag_buf); 77cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 78cabdff1aSopenharmony_ci } 79cabdff1aSopenharmony_ci } 80cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Unknown codec tag: %s\n", tag_buf); 81cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 82cabdff1aSopenharmony_ci } 83cabdff1aSopenharmony_ci 84cabdff1aSopenharmony_ci par->ch_layout.nb_channels = avio_rl32(pb); 85cabdff1aSopenharmony_ci if (par->ch_layout.nb_channels <= 0 || par->ch_layout.nb_channels > INT_MAX / 36) { 86cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Invalid number of channels: %d\n", par->ch_layout.nb_channels); 87cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 88cabdff1aSopenharmony_ci } 89cabdff1aSopenharmony_ci 90cabdff1aSopenharmony_ci avio_skip(pb, 4); // Bit depth 91cabdff1aSopenharmony_ci par->sample_rate = avio_rl32(pb); 92cabdff1aSopenharmony_ci if (!par->sample_rate) 93cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 94cabdff1aSopenharmony_ci 95cabdff1aSopenharmony_ci avio_skip(pb, 4); // Unknown 96cabdff1aSopenharmony_ci 97cabdff1aSopenharmony_ci switch (par->codec_id) { 98cabdff1aSopenharmony_ci case AV_CODEC_ID_XMA2: 99cabdff1aSopenharmony_ci par->block_align = 2048; 100cabdff1aSopenharmony_ci if ((ret = ff_alloc_extradata(par, 34)) < 0) 101cabdff1aSopenharmony_ci return ret; 102cabdff1aSopenharmony_ci memset(par->extradata, 0, 34); 103cabdff1aSopenharmony_ci break; 104cabdff1aSopenharmony_ci case AV_CODEC_ID_ADPCM_PSX: 105cabdff1aSopenharmony_ci par->block_align = 16 * par->ch_layout.nb_channels; 106cabdff1aSopenharmony_ci break; 107cabdff1aSopenharmony_ci case AV_CODEC_ID_ADPCM_IMA_RAD: 108cabdff1aSopenharmony_ci par->block_align = 20 * par->ch_layout.nb_channels; 109cabdff1aSopenharmony_ci break; 110cabdff1aSopenharmony_ci case AV_CODEC_ID_ADPCM_IMA_WAV: 111cabdff1aSopenharmony_ci if (version == 2) 112cabdff1aSopenharmony_ci start = avio_rl32(pb); 113cabdff1aSopenharmony_ci 114cabdff1aSopenharmony_ci par->bits_per_coded_sample = 4; 115cabdff1aSopenharmony_ci par->block_align = 36 * par->ch_layout.nb_channels; 116cabdff1aSopenharmony_ci break; 117cabdff1aSopenharmony_ci case AV_CODEC_ID_ADPCM_THP_LE: 118cabdff1aSopenharmony_ci /* RSD3GADP is mono, so only alloc enough memory 119cabdff1aSopenharmony_ci to store the coeff table for a single channel. */ 120cabdff1aSopenharmony_ci 121cabdff1aSopenharmony_ci start = avio_rl32(pb); 122cabdff1aSopenharmony_ci 123cabdff1aSopenharmony_ci if ((ret = ff_get_extradata(s, par, s->pb, 32)) < 0) 124cabdff1aSopenharmony_ci return ret; 125cabdff1aSopenharmony_ci break; 126cabdff1aSopenharmony_ci case AV_CODEC_ID_ADPCM_THP: 127cabdff1aSopenharmony_ci par->block_align = 8 * par->ch_layout.nb_channels; 128cabdff1aSopenharmony_ci avio_skip(s->pb, 0x1A4 - avio_tell(s->pb)); 129cabdff1aSopenharmony_ci 130cabdff1aSopenharmony_ci if ((ret = ff_alloc_extradata(st->codecpar, 32 * par->ch_layout.nb_channels)) < 0) 131cabdff1aSopenharmony_ci return ret; 132cabdff1aSopenharmony_ci 133cabdff1aSopenharmony_ci for (i = 0; i < par->ch_layout.nb_channels; i++) { 134cabdff1aSopenharmony_ci if (avio_feof(pb)) 135cabdff1aSopenharmony_ci return AVERROR_EOF; 136cabdff1aSopenharmony_ci avio_read(s->pb, st->codecpar->extradata + 32 * i, 32); 137cabdff1aSopenharmony_ci avio_skip(s->pb, 8); 138cabdff1aSopenharmony_ci } 139cabdff1aSopenharmony_ci break; 140cabdff1aSopenharmony_ci case AV_CODEC_ID_PCM_S16LE: 141cabdff1aSopenharmony_ci case AV_CODEC_ID_PCM_S16BE: 142cabdff1aSopenharmony_ci if (version != 4) 143cabdff1aSopenharmony_ci start = avio_rl32(pb); 144cabdff1aSopenharmony_ci 145cabdff1aSopenharmony_ci break; 146cabdff1aSopenharmony_ci } 147cabdff1aSopenharmony_ci if (start < 0) 148cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 149cabdff1aSopenharmony_ci 150cabdff1aSopenharmony_ci if (pb->seekable & AVIO_SEEKABLE_NORMAL) { 151cabdff1aSopenharmony_ci int64_t remaining = avio_size(pb); 152cabdff1aSopenharmony_ci 153cabdff1aSopenharmony_ci if (remaining >= start && remaining - start <= INT_MAX) 154cabdff1aSopenharmony_ci switch (par->codec_id) { 155cabdff1aSopenharmony_ci case AV_CODEC_ID_ADPCM_PSX: 156cabdff1aSopenharmony_ci case AV_CODEC_ID_ADPCM_IMA_RAD: 157cabdff1aSopenharmony_ci case AV_CODEC_ID_ADPCM_IMA_WAV: 158cabdff1aSopenharmony_ci case AV_CODEC_ID_ADPCM_THP_LE: 159cabdff1aSopenharmony_ci st->duration = av_get_audio_frame_duration2(par, remaining - start); 160cabdff1aSopenharmony_ci break; 161cabdff1aSopenharmony_ci case AV_CODEC_ID_ADPCM_THP: 162cabdff1aSopenharmony_ci st->duration = (remaining - start) / (8 * par->ch_layout.nb_channels) * 14; 163cabdff1aSopenharmony_ci break; 164cabdff1aSopenharmony_ci case AV_CODEC_ID_PCM_S16LE: 165cabdff1aSopenharmony_ci case AV_CODEC_ID_PCM_S16BE: 166cabdff1aSopenharmony_ci st->duration = (remaining - start) / 2 / par->ch_layout.nb_channels; 167cabdff1aSopenharmony_ci } 168cabdff1aSopenharmony_ci } 169cabdff1aSopenharmony_ci 170cabdff1aSopenharmony_ci avio_skip(pb, start - avio_tell(pb)); 171cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_XMA2) { 172cabdff1aSopenharmony_ci avio_skip(pb, avio_rb32(pb) + avio_rb32(pb)); 173cabdff1aSopenharmony_ci st->duration = avio_rb32(pb); 174cabdff1aSopenharmony_ci } 175cabdff1aSopenharmony_ci 176cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 64, 1, par->sample_rate); 177cabdff1aSopenharmony_ci 178cabdff1aSopenharmony_ci return 0; 179cabdff1aSopenharmony_ci} 180cabdff1aSopenharmony_ci 181cabdff1aSopenharmony_cistatic int rsd_read_packet(AVFormatContext *s, AVPacket *pkt) 182cabdff1aSopenharmony_ci{ 183cabdff1aSopenharmony_ci AVCodecParameters *par = s->streams[0]->codecpar; 184cabdff1aSopenharmony_ci int ret, size = 1024; 185cabdff1aSopenharmony_ci int64_t pos; 186cabdff1aSopenharmony_ci 187cabdff1aSopenharmony_ci if (avio_feof(s->pb)) 188cabdff1aSopenharmony_ci return AVERROR_EOF; 189cabdff1aSopenharmony_ci 190cabdff1aSopenharmony_ci pos = avio_tell(s->pb); 191cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_ADPCM_IMA_RAD || 192cabdff1aSopenharmony_ci par->codec_id == AV_CODEC_ID_ADPCM_PSX || 193cabdff1aSopenharmony_ci par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV || 194cabdff1aSopenharmony_ci par->codec_id == AV_CODEC_ID_XMA2) { 195cabdff1aSopenharmony_ci ret = av_get_packet(s->pb, pkt, par->block_align); 196cabdff1aSopenharmony_ci } else if (par->codec_tag == MKTAG('W','A','D','P') && 197cabdff1aSopenharmony_ci par->ch_layout.nb_channels > 1) { 198cabdff1aSopenharmony_ci int i, ch; 199cabdff1aSopenharmony_ci 200cabdff1aSopenharmony_ci ret = av_new_packet(pkt, par->block_align); 201cabdff1aSopenharmony_ci if (ret < 0) 202cabdff1aSopenharmony_ci return ret; 203cabdff1aSopenharmony_ci for (i = 0; i < 4; i++) { 204cabdff1aSopenharmony_ci for (ch = 0; ch < par->ch_layout.nb_channels; ch++) { 205cabdff1aSopenharmony_ci pkt->data[ch * 8 + i * 2 + 0] = avio_r8(s->pb); 206cabdff1aSopenharmony_ci pkt->data[ch * 8 + i * 2 + 1] = avio_r8(s->pb); 207cabdff1aSopenharmony_ci } 208cabdff1aSopenharmony_ci } 209cabdff1aSopenharmony_ci ret = 0; 210cabdff1aSopenharmony_ci } else { 211cabdff1aSopenharmony_ci ret = av_get_packet(s->pb, pkt, size); 212cabdff1aSopenharmony_ci } 213cabdff1aSopenharmony_ci 214cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_XMA2 && pkt->size >= 1) 215cabdff1aSopenharmony_ci pkt->duration = (pkt->data[0] >> 2) * 512; 216cabdff1aSopenharmony_ci 217cabdff1aSopenharmony_ci pkt->pos = pos; 218cabdff1aSopenharmony_ci pkt->stream_index = 0; 219cabdff1aSopenharmony_ci 220cabdff1aSopenharmony_ci return ret; 221cabdff1aSopenharmony_ci} 222cabdff1aSopenharmony_ci 223cabdff1aSopenharmony_ciconst AVInputFormat ff_rsd_demuxer = { 224cabdff1aSopenharmony_ci .name = "rsd", 225cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("GameCube RSD"), 226cabdff1aSopenharmony_ci .read_probe = rsd_probe, 227cabdff1aSopenharmony_ci .read_header = rsd_read_header, 228cabdff1aSopenharmony_ci .read_packet = rsd_read_packet, 229cabdff1aSopenharmony_ci .extensions = "rsd", 230cabdff1aSopenharmony_ci .codec_tag = (const AVCodecTag* const []){rsd_tags, 0}, 231cabdff1aSopenharmony_ci .flags = AVFMT_GENERIC_INDEX, 232cabdff1aSopenharmony_ci}; 233