1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * AIFF/AIFF-C demuxer 3cabdff1aSopenharmony_ci * Copyright (c) 2006 Patrick Guimond 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 "libavutil/dict.h" 24cabdff1aSopenharmony_ci#include "avformat.h" 25cabdff1aSopenharmony_ci#include "demux.h" 26cabdff1aSopenharmony_ci#include "internal.h" 27cabdff1aSopenharmony_ci#include "pcm.h" 28cabdff1aSopenharmony_ci#include "aiff.h" 29cabdff1aSopenharmony_ci#include "id3v2.h" 30cabdff1aSopenharmony_ci#include "mov_chan.h" 31cabdff1aSopenharmony_ci#include "replaygain.h" 32cabdff1aSopenharmony_ci 33cabdff1aSopenharmony_ci#define AIFF 0 34cabdff1aSopenharmony_ci#define AIFF_C_VERSION1 0xA2805140 35cabdff1aSopenharmony_ci 36cabdff1aSopenharmony_citypedef struct AIFFInputContext { 37cabdff1aSopenharmony_ci int64_t data_end; 38cabdff1aSopenharmony_ci int block_duration; 39cabdff1aSopenharmony_ci} AIFFInputContext; 40cabdff1aSopenharmony_ci 41cabdff1aSopenharmony_cistatic enum AVCodecID aiff_codec_get_id(int bps) 42cabdff1aSopenharmony_ci{ 43cabdff1aSopenharmony_ci if (bps <= 8) 44cabdff1aSopenharmony_ci return AV_CODEC_ID_PCM_S8; 45cabdff1aSopenharmony_ci if (bps <= 16) 46cabdff1aSopenharmony_ci return AV_CODEC_ID_PCM_S16BE; 47cabdff1aSopenharmony_ci if (bps <= 24) 48cabdff1aSopenharmony_ci return AV_CODEC_ID_PCM_S24BE; 49cabdff1aSopenharmony_ci if (bps <= 32) 50cabdff1aSopenharmony_ci return AV_CODEC_ID_PCM_S32BE; 51cabdff1aSopenharmony_ci 52cabdff1aSopenharmony_ci /* bigger than 32 isn't allowed */ 53cabdff1aSopenharmony_ci return AV_CODEC_ID_NONE; 54cabdff1aSopenharmony_ci} 55cabdff1aSopenharmony_ci 56cabdff1aSopenharmony_ci/* returns the size of the found tag */ 57cabdff1aSopenharmony_cistatic int64_t get_tag(AVIOContext *pb, uint32_t * tag) 58cabdff1aSopenharmony_ci{ 59cabdff1aSopenharmony_ci int64_t size; 60cabdff1aSopenharmony_ci 61cabdff1aSopenharmony_ci if (avio_feof(pb)) 62cabdff1aSopenharmony_ci return AVERROR(EIO); 63cabdff1aSopenharmony_ci 64cabdff1aSopenharmony_ci *tag = avio_rl32(pb); 65cabdff1aSopenharmony_ci size = avio_rb32(pb); 66cabdff1aSopenharmony_ci 67cabdff1aSopenharmony_ci return size; 68cabdff1aSopenharmony_ci} 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_ci/* Metadata string read */ 71cabdff1aSopenharmony_cistatic void get_meta(AVFormatContext *s, const char *key, int64_t size) 72cabdff1aSopenharmony_ci{ 73cabdff1aSopenharmony_ci uint8_t *str = NULL; 74cabdff1aSopenharmony_ci 75cabdff1aSopenharmony_ci if (size < SIZE_MAX) 76cabdff1aSopenharmony_ci str = av_malloc(size+1); 77cabdff1aSopenharmony_ci 78cabdff1aSopenharmony_ci if (str) { 79cabdff1aSopenharmony_ci int res = avio_read(s->pb, str, size); 80cabdff1aSopenharmony_ci if (res < 0){ 81cabdff1aSopenharmony_ci av_free(str); 82cabdff1aSopenharmony_ci return; 83cabdff1aSopenharmony_ci } 84cabdff1aSopenharmony_ci size -= res; 85cabdff1aSopenharmony_ci str[res] = 0; 86cabdff1aSopenharmony_ci av_dict_set(&s->metadata, key, str, AV_DICT_DONT_STRDUP_VAL); 87cabdff1aSopenharmony_ci } 88cabdff1aSopenharmony_ci 89cabdff1aSopenharmony_ci avio_skip(s->pb, size); 90cabdff1aSopenharmony_ci} 91cabdff1aSopenharmony_ci 92cabdff1aSopenharmony_ci/* Returns the number of sound data frames or negative on error */ 93cabdff1aSopenharmony_cistatic int get_aiff_header(AVFormatContext *s, int64_t size, 94cabdff1aSopenharmony_ci unsigned version) 95cabdff1aSopenharmony_ci{ 96cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 97cabdff1aSopenharmony_ci AVCodecParameters *par = s->streams[0]->codecpar; 98cabdff1aSopenharmony_ci AIFFInputContext *aiff = s->priv_data; 99cabdff1aSopenharmony_ci int exp; 100cabdff1aSopenharmony_ci uint64_t val; 101cabdff1aSopenharmony_ci int sample_rate; 102cabdff1aSopenharmony_ci unsigned int num_frames; 103cabdff1aSopenharmony_ci int channels; 104cabdff1aSopenharmony_ci 105cabdff1aSopenharmony_ci if (size & 1) 106cabdff1aSopenharmony_ci size++; 107cabdff1aSopenharmony_ci par->codec_type = AVMEDIA_TYPE_AUDIO; 108cabdff1aSopenharmony_ci channels = avio_rb16(pb); 109cabdff1aSopenharmony_ci par->ch_layout.nb_channels = channels; 110cabdff1aSopenharmony_ci num_frames = avio_rb32(pb); 111cabdff1aSopenharmony_ci par->bits_per_coded_sample = avio_rb16(pb); 112cabdff1aSopenharmony_ci 113cabdff1aSopenharmony_ci exp = avio_rb16(pb) - 16383 - 63; 114cabdff1aSopenharmony_ci val = avio_rb64(pb); 115cabdff1aSopenharmony_ci if (exp <-63 || exp >63) { 116cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "exp %d is out of range\n", exp); 117cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 118cabdff1aSopenharmony_ci } 119cabdff1aSopenharmony_ci if (exp >= 0) 120cabdff1aSopenharmony_ci sample_rate = val << exp; 121cabdff1aSopenharmony_ci else 122cabdff1aSopenharmony_ci sample_rate = (val + (1ULL<<(-exp-1))) >> -exp; 123cabdff1aSopenharmony_ci if (sample_rate <= 0) 124cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 125cabdff1aSopenharmony_ci 126cabdff1aSopenharmony_ci par->sample_rate = sample_rate; 127cabdff1aSopenharmony_ci if (size < 18) 128cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 129cabdff1aSopenharmony_ci size -= 18; 130cabdff1aSopenharmony_ci 131cabdff1aSopenharmony_ci /* get codec id for AIFF-C */ 132cabdff1aSopenharmony_ci if (size < 4) { 133cabdff1aSopenharmony_ci version = AIFF; 134cabdff1aSopenharmony_ci } else if (version == AIFF_C_VERSION1) { 135cabdff1aSopenharmony_ci par->codec_tag = avio_rl32(pb); 136cabdff1aSopenharmony_ci par->codec_id = ff_codec_get_id(ff_codec_aiff_tags, par->codec_tag); 137cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_NONE) 138cabdff1aSopenharmony_ci avpriv_request_sample(s, "unknown or unsupported codec tag: %s", 139cabdff1aSopenharmony_ci av_fourcc2str(par->codec_tag)); 140cabdff1aSopenharmony_ci size -= 4; 141cabdff1aSopenharmony_ci } 142cabdff1aSopenharmony_ci 143cabdff1aSopenharmony_ci if (version != AIFF_C_VERSION1 || par->codec_id == AV_CODEC_ID_PCM_S16BE) { 144cabdff1aSopenharmony_ci par->codec_id = aiff_codec_get_id(par->bits_per_coded_sample); 145cabdff1aSopenharmony_ci par->bits_per_coded_sample = av_get_bits_per_sample(par->codec_id); 146cabdff1aSopenharmony_ci aiff->block_duration = 1; 147cabdff1aSopenharmony_ci } else { 148cabdff1aSopenharmony_ci switch (par->codec_id) { 149cabdff1aSopenharmony_ci case AV_CODEC_ID_PCM_F32BE: 150cabdff1aSopenharmony_ci case AV_CODEC_ID_PCM_F64BE: 151cabdff1aSopenharmony_ci case AV_CODEC_ID_PCM_S16LE: 152cabdff1aSopenharmony_ci case AV_CODEC_ID_PCM_ALAW: 153cabdff1aSopenharmony_ci case AV_CODEC_ID_PCM_MULAW: 154cabdff1aSopenharmony_ci aiff->block_duration = 1; 155cabdff1aSopenharmony_ci break; 156cabdff1aSopenharmony_ci case AV_CODEC_ID_ADPCM_IMA_QT: 157cabdff1aSopenharmony_ci par->block_align = 34 * channels; 158cabdff1aSopenharmony_ci break; 159cabdff1aSopenharmony_ci case AV_CODEC_ID_MACE3: 160cabdff1aSopenharmony_ci par->block_align = 2 * channels; 161cabdff1aSopenharmony_ci break; 162cabdff1aSopenharmony_ci case AV_CODEC_ID_ADPCM_G726LE: 163cabdff1aSopenharmony_ci par->bits_per_coded_sample = 5; 164cabdff1aSopenharmony_ci case AV_CODEC_ID_ADPCM_IMA_WS: 165cabdff1aSopenharmony_ci case AV_CODEC_ID_ADPCM_G722: 166cabdff1aSopenharmony_ci case AV_CODEC_ID_MACE6: 167cabdff1aSopenharmony_ci case AV_CODEC_ID_SDX2_DPCM: 168cabdff1aSopenharmony_ci par->block_align = 1 * channels; 169cabdff1aSopenharmony_ci break; 170cabdff1aSopenharmony_ci case AV_CODEC_ID_GSM: 171cabdff1aSopenharmony_ci par->block_align = 33; 172cabdff1aSopenharmony_ci break; 173cabdff1aSopenharmony_ci default: 174cabdff1aSopenharmony_ci aiff->block_duration = 1; 175cabdff1aSopenharmony_ci break; 176cabdff1aSopenharmony_ci } 177cabdff1aSopenharmony_ci if (par->block_align > 0) 178cabdff1aSopenharmony_ci aiff->block_duration = av_get_audio_frame_duration2(par, 179cabdff1aSopenharmony_ci par->block_align); 180cabdff1aSopenharmony_ci } 181cabdff1aSopenharmony_ci 182cabdff1aSopenharmony_ci /* Block align needs to be computed in all cases, as the definition 183cabdff1aSopenharmony_ci * is specific to applications -> here we use the WAVE format definition */ 184cabdff1aSopenharmony_ci if (!par->block_align) 185cabdff1aSopenharmony_ci par->block_align = (av_get_bits_per_sample(par->codec_id) * channels) >> 3; 186cabdff1aSopenharmony_ci 187cabdff1aSopenharmony_ci if (aiff->block_duration) { 188cabdff1aSopenharmony_ci par->bit_rate = av_rescale(par->sample_rate, par->block_align * 8LL, 189cabdff1aSopenharmony_ci aiff->block_duration); 190cabdff1aSopenharmony_ci if (par->bit_rate < 0) 191cabdff1aSopenharmony_ci par->bit_rate = 0; 192cabdff1aSopenharmony_ci } 193cabdff1aSopenharmony_ci 194cabdff1aSopenharmony_ci /* Chunk is over */ 195cabdff1aSopenharmony_ci if (size) 196cabdff1aSopenharmony_ci avio_skip(pb, size); 197cabdff1aSopenharmony_ci 198cabdff1aSopenharmony_ci return num_frames; 199cabdff1aSopenharmony_ci} 200cabdff1aSopenharmony_ci 201cabdff1aSopenharmony_cistatic int aiff_probe(const AVProbeData *p) 202cabdff1aSopenharmony_ci{ 203cabdff1aSopenharmony_ci /* check file header */ 204cabdff1aSopenharmony_ci if (p->buf[0] == 'F' && p->buf[1] == 'O' && 205cabdff1aSopenharmony_ci p->buf[2] == 'R' && p->buf[3] == 'M' && 206cabdff1aSopenharmony_ci p->buf[8] == 'A' && p->buf[9] == 'I' && 207cabdff1aSopenharmony_ci p->buf[10] == 'F' && (p->buf[11] == 'F' || p->buf[11] == 'C')) 208cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 209cabdff1aSopenharmony_ci else 210cabdff1aSopenharmony_ci return 0; 211cabdff1aSopenharmony_ci} 212cabdff1aSopenharmony_ci 213cabdff1aSopenharmony_ci/* aiff input */ 214cabdff1aSopenharmony_cistatic int aiff_read_header(AVFormatContext *s) 215cabdff1aSopenharmony_ci{ 216cabdff1aSopenharmony_ci int ret; 217cabdff1aSopenharmony_ci int64_t filesize, size; 218cabdff1aSopenharmony_ci int64_t offset = 0, position; 219cabdff1aSopenharmony_ci uint32_t tag; 220cabdff1aSopenharmony_ci unsigned version = AIFF_C_VERSION1; 221cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 222cabdff1aSopenharmony_ci AVStream * st; 223cabdff1aSopenharmony_ci AIFFInputContext *aiff = s->priv_data; 224cabdff1aSopenharmony_ci ID3v2ExtraMeta *id3v2_extra_meta; 225cabdff1aSopenharmony_ci 226cabdff1aSopenharmony_ci /* check FORM header */ 227cabdff1aSopenharmony_ci filesize = get_tag(pb, &tag); 228cabdff1aSopenharmony_ci if (filesize < 4 || tag != MKTAG('F', 'O', 'R', 'M')) 229cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 230cabdff1aSopenharmony_ci 231cabdff1aSopenharmony_ci /* AIFF data type */ 232cabdff1aSopenharmony_ci tag = avio_rl32(pb); 233cabdff1aSopenharmony_ci if (tag == MKTAG('A', 'I', 'F', 'F')) /* Got an AIFF file */ 234cabdff1aSopenharmony_ci version = AIFF; 235cabdff1aSopenharmony_ci else if (tag != MKTAG('A', 'I', 'F', 'C')) /* An AIFF-C file then */ 236cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 237cabdff1aSopenharmony_ci 238cabdff1aSopenharmony_ci filesize -= 4; 239cabdff1aSopenharmony_ci 240cabdff1aSopenharmony_ci st = avformat_new_stream(s, NULL); 241cabdff1aSopenharmony_ci if (!st) 242cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 243cabdff1aSopenharmony_ci 244cabdff1aSopenharmony_ci while (filesize > 0) { 245cabdff1aSopenharmony_ci /* parse different chunks */ 246cabdff1aSopenharmony_ci size = get_tag(pb, &tag); 247cabdff1aSopenharmony_ci 248cabdff1aSopenharmony_ci if (size == AVERROR_EOF && offset > 0 && st->codecpar->block_align) { 249cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "header parser hit EOF\n"); 250cabdff1aSopenharmony_ci goto got_sound; 251cabdff1aSopenharmony_ci } 252cabdff1aSopenharmony_ci if (size < 0) 253cabdff1aSopenharmony_ci return size; 254cabdff1aSopenharmony_ci 255cabdff1aSopenharmony_ci filesize -= size + 8; 256cabdff1aSopenharmony_ci 257cabdff1aSopenharmony_ci switch (tag) { 258cabdff1aSopenharmony_ci case MKTAG('C', 'O', 'M', 'M'): /* Common chunk */ 259cabdff1aSopenharmony_ci /* Then for the complete header info */ 260cabdff1aSopenharmony_ci st->nb_frames = get_aiff_header(s, size, version); 261cabdff1aSopenharmony_ci if (st->nb_frames < 0) 262cabdff1aSopenharmony_ci return st->nb_frames; 263cabdff1aSopenharmony_ci if (offset > 0) // COMM is after SSND 264cabdff1aSopenharmony_ci goto got_sound; 265cabdff1aSopenharmony_ci break; 266cabdff1aSopenharmony_ci case MKTAG('I', 'D', '3', ' '): 267cabdff1aSopenharmony_ci position = avio_tell(pb); 268cabdff1aSopenharmony_ci ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, size); 269cabdff1aSopenharmony_ci if (id3v2_extra_meta) 270cabdff1aSopenharmony_ci if ((ret = ff_id3v2_parse_apic(s, id3v2_extra_meta)) < 0 || 271cabdff1aSopenharmony_ci (ret = ff_id3v2_parse_chapters(s, id3v2_extra_meta)) < 0) { 272cabdff1aSopenharmony_ci ff_id3v2_free_extra_meta(&id3v2_extra_meta); 273cabdff1aSopenharmony_ci return ret; 274cabdff1aSopenharmony_ci } 275cabdff1aSopenharmony_ci ff_id3v2_free_extra_meta(&id3v2_extra_meta); 276cabdff1aSopenharmony_ci if (position + size > avio_tell(pb)) 277cabdff1aSopenharmony_ci avio_skip(pb, position + size - avio_tell(pb)); 278cabdff1aSopenharmony_ci break; 279cabdff1aSopenharmony_ci case MKTAG('F', 'V', 'E', 'R'): /* Version chunk */ 280cabdff1aSopenharmony_ci version = avio_rb32(pb); 281cabdff1aSopenharmony_ci break; 282cabdff1aSopenharmony_ci case MKTAG('N', 'A', 'M', 'E'): /* Sample name chunk */ 283cabdff1aSopenharmony_ci get_meta(s, "title" , size); 284cabdff1aSopenharmony_ci break; 285cabdff1aSopenharmony_ci case MKTAG('A', 'U', 'T', 'H'): /* Author chunk */ 286cabdff1aSopenharmony_ci get_meta(s, "author" , size); 287cabdff1aSopenharmony_ci break; 288cabdff1aSopenharmony_ci case MKTAG('(', 'c', ')', ' '): /* Copyright chunk */ 289cabdff1aSopenharmony_ci get_meta(s, "copyright", size); 290cabdff1aSopenharmony_ci break; 291cabdff1aSopenharmony_ci case MKTAG('A', 'N', 'N', 'O'): /* Annotation chunk */ 292cabdff1aSopenharmony_ci get_meta(s, "comment" , size); 293cabdff1aSopenharmony_ci break; 294cabdff1aSopenharmony_ci case MKTAG('S', 'S', 'N', 'D'): /* Sampled sound chunk */ 295cabdff1aSopenharmony_ci if (size < 8) 296cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 297cabdff1aSopenharmony_ci aiff->data_end = avio_tell(pb) + size; 298cabdff1aSopenharmony_ci offset = avio_rb32(pb); /* Offset of sound data */ 299cabdff1aSopenharmony_ci avio_rb32(pb); /* BlockSize... don't care */ 300cabdff1aSopenharmony_ci offset += avio_tell(pb); /* Compute absolute data offset */ 301cabdff1aSopenharmony_ci if (st->codecpar->block_align && !(pb->seekable & AVIO_SEEKABLE_NORMAL)) /* Assume COMM already parsed */ 302cabdff1aSopenharmony_ci goto got_sound; 303cabdff1aSopenharmony_ci if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) { 304cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "file is not seekable\n"); 305cabdff1aSopenharmony_ci return -1; 306cabdff1aSopenharmony_ci } 307cabdff1aSopenharmony_ci avio_skip(pb, size - 8); 308cabdff1aSopenharmony_ci break; 309cabdff1aSopenharmony_ci case MKTAG('w', 'a', 'v', 'e'): 310cabdff1aSopenharmony_ci if ((uint64_t)size > (1<<30)) 311cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 312cabdff1aSopenharmony_ci if ((ret = ff_get_extradata(s, st->codecpar, pb, size)) < 0) 313cabdff1aSopenharmony_ci return ret; 314cabdff1aSopenharmony_ci if ( (st->codecpar->codec_id == AV_CODEC_ID_QDMC || st->codecpar->codec_id == AV_CODEC_ID_QDM2) 315cabdff1aSopenharmony_ci && size>=12*4 && !st->codecpar->block_align) { 316cabdff1aSopenharmony_ci st->codecpar->block_align = AV_RB32(st->codecpar->extradata+11*4); 317cabdff1aSopenharmony_ci aiff->block_duration = AV_RB32(st->codecpar->extradata+9*4); 318cabdff1aSopenharmony_ci } else if (st->codecpar->codec_id == AV_CODEC_ID_QCELP) { 319cabdff1aSopenharmony_ci char rate = 0; 320cabdff1aSopenharmony_ci if (size >= 25) 321cabdff1aSopenharmony_ci rate = st->codecpar->extradata[24]; 322cabdff1aSopenharmony_ci switch (rate) { 323cabdff1aSopenharmony_ci case 'H': // RATE_HALF 324cabdff1aSopenharmony_ci st->codecpar->block_align = 17; 325cabdff1aSopenharmony_ci break; 326cabdff1aSopenharmony_ci case 'F': // RATE_FULL 327cabdff1aSopenharmony_ci default: 328cabdff1aSopenharmony_ci st->codecpar->block_align = 35; 329cabdff1aSopenharmony_ci } 330cabdff1aSopenharmony_ci aiff->block_duration = 160; 331cabdff1aSopenharmony_ci st->codecpar->bit_rate = (int64_t)st->codecpar->sample_rate * (st->codecpar->block_align << 3) / 332cabdff1aSopenharmony_ci aiff->block_duration; 333cabdff1aSopenharmony_ci } 334cabdff1aSopenharmony_ci break; 335cabdff1aSopenharmony_ci case MKTAG('C','H','A','N'): 336cabdff1aSopenharmony_ci if ((ret = ff_mov_read_chan(s, pb, st, size)) < 0) 337cabdff1aSopenharmony_ci return ret; 338cabdff1aSopenharmony_ci break; 339cabdff1aSopenharmony_ci case MKTAG('A','P','C','M'): /* XA ADPCM compressed sound chunk */ 340cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_ADPCM_XA; 341cabdff1aSopenharmony_ci aiff->data_end = avio_tell(pb) + size; 342cabdff1aSopenharmony_ci offset = avio_tell(pb) + 8; 343cabdff1aSopenharmony_ci /* This field is unknown and its data seems to be irrelevant */ 344cabdff1aSopenharmony_ci avio_rb32(pb); 345cabdff1aSopenharmony_ci st->codecpar->block_align = avio_rb32(pb); 346cabdff1aSopenharmony_ci 347cabdff1aSopenharmony_ci goto got_sound; 348cabdff1aSopenharmony_ci break; 349cabdff1aSopenharmony_ci case 0: 350cabdff1aSopenharmony_ci if (offset > 0 && st->codecpar->block_align) // COMM && SSND 351cabdff1aSopenharmony_ci goto got_sound; 352cabdff1aSopenharmony_ci default: /* Jump */ 353cabdff1aSopenharmony_ci avio_skip(pb, size); 354cabdff1aSopenharmony_ci } 355cabdff1aSopenharmony_ci 356cabdff1aSopenharmony_ci /* Skip required padding byte for odd-sized chunks. */ 357cabdff1aSopenharmony_ci if (size & 1) { 358cabdff1aSopenharmony_ci filesize--; 359cabdff1aSopenharmony_ci avio_skip(pb, 1); 360cabdff1aSopenharmony_ci } 361cabdff1aSopenharmony_ci } 362cabdff1aSopenharmony_ci 363cabdff1aSopenharmony_ci ret = ff_replaygain_export(st, s->metadata); 364cabdff1aSopenharmony_ci if (ret < 0) 365cabdff1aSopenharmony_ci return ret; 366cabdff1aSopenharmony_ci 367cabdff1aSopenharmony_cigot_sound: 368cabdff1aSopenharmony_ci if (!st->codecpar->block_align && st->codecpar->codec_id == AV_CODEC_ID_QCELP) { 369cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "qcelp without wave chunk, assuming full rate\n"); 370cabdff1aSopenharmony_ci st->codecpar->block_align = 35; 371cabdff1aSopenharmony_ci } else if (st->codecpar->block_align <= 0) { 372cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "could not find COMM tag or invalid block_align value\n"); 373cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 374cabdff1aSopenharmony_ci } 375cabdff1aSopenharmony_ci if (aiff->block_duration < 0) 376cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 377cabdff1aSopenharmony_ci 378cabdff1aSopenharmony_ci /* Now positioned, get the sound data start and end */ 379cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); 380cabdff1aSopenharmony_ci st->start_time = 0; 381cabdff1aSopenharmony_ci st->duration = st->nb_frames * aiff->block_duration; 382cabdff1aSopenharmony_ci 383cabdff1aSopenharmony_ci /* Position the stream at the first block */ 384cabdff1aSopenharmony_ci avio_seek(pb, offset, SEEK_SET); 385cabdff1aSopenharmony_ci 386cabdff1aSopenharmony_ci return 0; 387cabdff1aSopenharmony_ci} 388cabdff1aSopenharmony_ci 389cabdff1aSopenharmony_ci#define MAX_SIZE 4096 390cabdff1aSopenharmony_ci 391cabdff1aSopenharmony_cistatic int aiff_read_packet(AVFormatContext *s, 392cabdff1aSopenharmony_ci AVPacket *pkt) 393cabdff1aSopenharmony_ci{ 394cabdff1aSopenharmony_ci AVStream *st = s->streams[0]; 395cabdff1aSopenharmony_ci AIFFInputContext *aiff = s->priv_data; 396cabdff1aSopenharmony_ci int64_t max_size; 397cabdff1aSopenharmony_ci int res, size; 398cabdff1aSopenharmony_ci 399cabdff1aSopenharmony_ci /* calculate size of remaining data */ 400cabdff1aSopenharmony_ci max_size = aiff->data_end - avio_tell(s->pb); 401cabdff1aSopenharmony_ci if (max_size <= 0) 402cabdff1aSopenharmony_ci return AVERROR_EOF; 403cabdff1aSopenharmony_ci 404cabdff1aSopenharmony_ci if (!st->codecpar->block_align) { 405cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "block_align not set\n"); 406cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 407cabdff1aSopenharmony_ci } 408cabdff1aSopenharmony_ci 409cabdff1aSopenharmony_ci /* Now for that packet */ 410cabdff1aSopenharmony_ci switch (st->codecpar->codec_id) { 411cabdff1aSopenharmony_ci case AV_CODEC_ID_ADPCM_IMA_QT: 412cabdff1aSopenharmony_ci case AV_CODEC_ID_GSM: 413cabdff1aSopenharmony_ci case AV_CODEC_ID_QDM2: 414cabdff1aSopenharmony_ci case AV_CODEC_ID_QCELP: 415cabdff1aSopenharmony_ci size = st->codecpar->block_align; 416cabdff1aSopenharmony_ci break; 417cabdff1aSopenharmony_ci default: 418cabdff1aSopenharmony_ci size = st->codecpar->block_align ? (MAX_SIZE / st->codecpar->block_align) * st->codecpar->block_align : MAX_SIZE; 419cabdff1aSopenharmony_ci if (!size) 420cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 421cabdff1aSopenharmony_ci } 422cabdff1aSopenharmony_ci size = FFMIN(max_size, size); 423cabdff1aSopenharmony_ci res = av_get_packet(s->pb, pkt, size); 424cabdff1aSopenharmony_ci if (res < 0) 425cabdff1aSopenharmony_ci return res; 426cabdff1aSopenharmony_ci 427cabdff1aSopenharmony_ci if (size >= st->codecpar->block_align) 428cabdff1aSopenharmony_ci pkt->flags &= ~AV_PKT_FLAG_CORRUPT; 429cabdff1aSopenharmony_ci /* Only one stream in an AIFF file */ 430cabdff1aSopenharmony_ci pkt->stream_index = 0; 431cabdff1aSopenharmony_ci pkt->duration = (res / st->codecpar->block_align) * (int64_t) aiff->block_duration; 432cabdff1aSopenharmony_ci return 0; 433cabdff1aSopenharmony_ci} 434cabdff1aSopenharmony_ci 435cabdff1aSopenharmony_ciconst AVInputFormat ff_aiff_demuxer = { 436cabdff1aSopenharmony_ci .name = "aiff", 437cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("Audio IFF"), 438cabdff1aSopenharmony_ci .priv_data_size = sizeof(AIFFInputContext), 439cabdff1aSopenharmony_ci .read_probe = aiff_probe, 440cabdff1aSopenharmony_ci .read_header = aiff_read_header, 441cabdff1aSopenharmony_ci .read_packet = aiff_read_packet, 442cabdff1aSopenharmony_ci .read_seek = ff_pcm_read_seek, 443cabdff1aSopenharmony_ci .codec_tag = ff_aiff_codec_tags_list, 444cabdff1aSopenharmony_ci}; 445