1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * 4X Technologies .4xm File Demuxer (no muxer) 3cabdff1aSopenharmony_ci * Copyright (c) 2003 The FFmpeg project 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/** 23cabdff1aSopenharmony_ci * @file 24cabdff1aSopenharmony_ci * 4X Technologies file demuxer 25cabdff1aSopenharmony_ci * by Mike Melanson (melanson@pcisys.net) 26cabdff1aSopenharmony_ci * for more information on the .4xm file format, visit: 27cabdff1aSopenharmony_ci * http://www.pcisys.net/~melanson/codecs/ 28cabdff1aSopenharmony_ci */ 29cabdff1aSopenharmony_ci 30cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 31cabdff1aSopenharmony_ci#include "libavutil/intfloat.h" 32cabdff1aSopenharmony_ci#include "libavcodec/internal.h" 33cabdff1aSopenharmony_ci#include "avformat.h" 34cabdff1aSopenharmony_ci#include "internal.h" 35cabdff1aSopenharmony_ci 36cabdff1aSopenharmony_ci#define RIFF_TAG MKTAG('R', 'I', 'F', 'F') 37cabdff1aSopenharmony_ci#define FOURXMV_TAG MKTAG('4', 'X', 'M', 'V') 38cabdff1aSopenharmony_ci#define LIST_TAG MKTAG('L', 'I', 'S', 'T') 39cabdff1aSopenharmony_ci#define HEAD_TAG MKTAG('H', 'E', 'A', 'D') 40cabdff1aSopenharmony_ci#define TRK__TAG MKTAG('T', 'R', 'K', '_') 41cabdff1aSopenharmony_ci#define MOVI_TAG MKTAG('M', 'O', 'V', 'I') 42cabdff1aSopenharmony_ci#define VTRK_TAG MKTAG('V', 'T', 'R', 'K') 43cabdff1aSopenharmony_ci#define STRK_TAG MKTAG('S', 'T', 'R', 'K') 44cabdff1aSopenharmony_ci#define std__TAG MKTAG('s', 't', 'd', '_') 45cabdff1aSopenharmony_ci#define name_TAG MKTAG('n', 'a', 'm', 'e') 46cabdff1aSopenharmony_ci#define vtrk_TAG MKTAG('v', 't', 'r', 'k') 47cabdff1aSopenharmony_ci#define strk_TAG MKTAG('s', 't', 'r', 'k') 48cabdff1aSopenharmony_ci#define ifrm_TAG MKTAG('i', 'f', 'r', 'm') 49cabdff1aSopenharmony_ci#define pfrm_TAG MKTAG('p', 'f', 'r', 'm') 50cabdff1aSopenharmony_ci#define cfrm_TAG MKTAG('c', 'f', 'r', 'm') 51cabdff1aSopenharmony_ci#define ifr2_TAG MKTAG('i', 'f', 'r', '2') 52cabdff1aSopenharmony_ci#define pfr2_TAG MKTAG('p', 'f', 'r', '2') 53cabdff1aSopenharmony_ci#define cfr2_TAG MKTAG('c', 'f', 'r', '2') 54cabdff1aSopenharmony_ci#define snd__TAG MKTAG('s', 'n', 'd', '_') 55cabdff1aSopenharmony_ci 56cabdff1aSopenharmony_ci#define vtrk_SIZE 0x44 57cabdff1aSopenharmony_ci#define strk_SIZE 0x28 58cabdff1aSopenharmony_ci 59cabdff1aSopenharmony_ci#define GET_LIST_HEADER() \ 60cabdff1aSopenharmony_ci fourcc_tag = avio_rl32(pb); \ 61cabdff1aSopenharmony_ci size = avio_rl32(pb); \ 62cabdff1aSopenharmony_ci if (fourcc_tag != LIST_TAG) { \ 63cabdff1aSopenharmony_ci ret = AVERROR_INVALIDDATA; \ 64cabdff1aSopenharmony_ci goto fail; \ 65cabdff1aSopenharmony_ci } \ 66cabdff1aSopenharmony_ci fourcc_tag = avio_rl32(pb); 67cabdff1aSopenharmony_ci 68cabdff1aSopenharmony_citypedef struct AudioTrack { 69cabdff1aSopenharmony_ci int sample_rate; 70cabdff1aSopenharmony_ci int bits; 71cabdff1aSopenharmony_ci int channels; 72cabdff1aSopenharmony_ci int stream_index; 73cabdff1aSopenharmony_ci int adpcm; 74cabdff1aSopenharmony_ci int64_t audio_pts; 75cabdff1aSopenharmony_ci} AudioTrack; 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_citypedef struct FourxmDemuxContext { 78cabdff1aSopenharmony_ci int video_stream_index; 79cabdff1aSopenharmony_ci int track_count; 80cabdff1aSopenharmony_ci AudioTrack *tracks; 81cabdff1aSopenharmony_ci 82cabdff1aSopenharmony_ci int64_t video_pts; 83cabdff1aSopenharmony_ci AVRational fps; 84cabdff1aSopenharmony_ci} FourxmDemuxContext; 85cabdff1aSopenharmony_ci 86cabdff1aSopenharmony_cistatic int fourxm_probe(const AVProbeData *p) 87cabdff1aSopenharmony_ci{ 88cabdff1aSopenharmony_ci if ((AV_RL32(&p->buf[0]) != RIFF_TAG) || 89cabdff1aSopenharmony_ci (AV_RL32(&p->buf[8]) != FOURXMV_TAG)) 90cabdff1aSopenharmony_ci return 0; 91cabdff1aSopenharmony_ci 92cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 93cabdff1aSopenharmony_ci} 94cabdff1aSopenharmony_ci 95cabdff1aSopenharmony_cistatic int parse_vtrk(AVFormatContext *s, 96cabdff1aSopenharmony_ci FourxmDemuxContext *fourxm, uint8_t *buf, int size, 97cabdff1aSopenharmony_ci int left) 98cabdff1aSopenharmony_ci{ 99cabdff1aSopenharmony_ci AVStream *st; 100cabdff1aSopenharmony_ci /* check that there is enough data */ 101cabdff1aSopenharmony_ci if (size != vtrk_SIZE || left < size + 8) { 102cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 103cabdff1aSopenharmony_ci } 104cabdff1aSopenharmony_ci 105cabdff1aSopenharmony_ci /* allocate a new AVStream */ 106cabdff1aSopenharmony_ci st = avformat_new_stream(s, NULL); 107cabdff1aSopenharmony_ci if (!st) 108cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 109cabdff1aSopenharmony_ci 110cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 60, fourxm->fps.den, fourxm->fps.num); 111cabdff1aSopenharmony_ci 112cabdff1aSopenharmony_ci fourxm->video_stream_index = st->index; 113cabdff1aSopenharmony_ci 114cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 115cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_4XM; 116cabdff1aSopenharmony_ci 117cabdff1aSopenharmony_ci st->codecpar->extradata = av_mallocz(4 + AV_INPUT_BUFFER_PADDING_SIZE); 118cabdff1aSopenharmony_ci if (!st->codecpar->extradata) 119cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 120cabdff1aSopenharmony_ci st->codecpar->extradata_size = 4; 121cabdff1aSopenharmony_ci AV_WL32(st->codecpar->extradata, AV_RL32(buf + 16)); 122cabdff1aSopenharmony_ci st->codecpar->width = AV_RL32(buf + 36); 123cabdff1aSopenharmony_ci st->codecpar->height = AV_RL32(buf + 40); 124cabdff1aSopenharmony_ci 125cabdff1aSopenharmony_ci return 0; 126cabdff1aSopenharmony_ci} 127cabdff1aSopenharmony_ci 128cabdff1aSopenharmony_ci 129cabdff1aSopenharmony_cistatic int parse_strk(AVFormatContext *s, 130cabdff1aSopenharmony_ci FourxmDemuxContext *fourxm, uint8_t *buf, int size, 131cabdff1aSopenharmony_ci int left) 132cabdff1aSopenharmony_ci{ 133cabdff1aSopenharmony_ci AVStream *st; 134cabdff1aSopenharmony_ci int track; 135cabdff1aSopenharmony_ci /* check that there is enough data */ 136cabdff1aSopenharmony_ci if (size != strk_SIZE || left < size + 8) 137cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 138cabdff1aSopenharmony_ci 139cabdff1aSopenharmony_ci track = AV_RL32(buf + 8); 140cabdff1aSopenharmony_ci if ((unsigned)track >= UINT_MAX / sizeof(AudioTrack) - 1 || 141cabdff1aSopenharmony_ci track >= s->max_streams) { 142cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "current_track too large\n"); 143cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 144cabdff1aSopenharmony_ci } 145cabdff1aSopenharmony_ci 146cabdff1aSopenharmony_ci if (track + 1 > fourxm->track_count) { 147cabdff1aSopenharmony_ci if (av_reallocp_array(&fourxm->tracks, track + 1, sizeof(AudioTrack))) 148cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 149cabdff1aSopenharmony_ci memset(&fourxm->tracks[fourxm->track_count], 0, 150cabdff1aSopenharmony_ci sizeof(AudioTrack) * (track + 1 - fourxm->track_count)); 151cabdff1aSopenharmony_ci fourxm->track_count = track + 1; 152cabdff1aSopenharmony_ci } else { 153cabdff1aSopenharmony_ci if (fourxm->tracks[track].bits) 154cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 155cabdff1aSopenharmony_ci } 156cabdff1aSopenharmony_ci fourxm->tracks[track].adpcm = AV_RL32(buf + 12); 157cabdff1aSopenharmony_ci fourxm->tracks[track].channels = AV_RL32(buf + 36); 158cabdff1aSopenharmony_ci fourxm->tracks[track].sample_rate = AV_RL32(buf + 40); 159cabdff1aSopenharmony_ci fourxm->tracks[track].bits = AV_RL32(buf + 44); 160cabdff1aSopenharmony_ci fourxm->tracks[track].audio_pts = 0; 161cabdff1aSopenharmony_ci 162cabdff1aSopenharmony_ci if (fourxm->tracks[track].channels <= 0 || 163cabdff1aSopenharmony_ci fourxm->tracks[track].channels > FF_SANE_NB_CHANNELS || 164cabdff1aSopenharmony_ci fourxm->tracks[track].sample_rate <= 0 || 165cabdff1aSopenharmony_ci fourxm->tracks[track].bits <= 0 || 166cabdff1aSopenharmony_ci fourxm->tracks[track].bits > INT_MAX / FF_SANE_NB_CHANNELS) { 167cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "audio header invalid\n"); 168cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 169cabdff1aSopenharmony_ci } 170cabdff1aSopenharmony_ci if (!fourxm->tracks[track].adpcm && fourxm->tracks[track].bits<8) { 171cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "bits unspecified for non ADPCM\n"); 172cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 173cabdff1aSopenharmony_ci } 174cabdff1aSopenharmony_ci 175cabdff1aSopenharmony_ci if (fourxm->tracks[track].sample_rate > INT64_MAX / fourxm->tracks[track].bits / fourxm->tracks[track].channels) { 176cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Overflow during bit rate calculation %d * %d * %d\n", 177cabdff1aSopenharmony_ci fourxm->tracks[track].sample_rate, fourxm->tracks[track].bits, fourxm->tracks[track].channels); 178cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 179cabdff1aSopenharmony_ci } 180cabdff1aSopenharmony_ci 181cabdff1aSopenharmony_ci /* allocate a new AVStream */ 182cabdff1aSopenharmony_ci st = avformat_new_stream(s, NULL); 183cabdff1aSopenharmony_ci if (!st) 184cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 185cabdff1aSopenharmony_ci 186cabdff1aSopenharmony_ci st->id = track; 187cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 60, 1, fourxm->tracks[track].sample_rate); 188cabdff1aSopenharmony_ci 189cabdff1aSopenharmony_ci fourxm->tracks[track].stream_index = st->index; 190cabdff1aSopenharmony_ci 191cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; 192cabdff1aSopenharmony_ci st->codecpar->codec_tag = 0; 193cabdff1aSopenharmony_ci st->codecpar->ch_layout.nb_channels = fourxm->tracks[track].channels; 194cabdff1aSopenharmony_ci st->codecpar->sample_rate = fourxm->tracks[track].sample_rate; 195cabdff1aSopenharmony_ci st->codecpar->bits_per_coded_sample = fourxm->tracks[track].bits; 196cabdff1aSopenharmony_ci st->codecpar->bit_rate = (int64_t)st->codecpar->ch_layout.nb_channels * 197cabdff1aSopenharmony_ci st->codecpar->sample_rate * 198cabdff1aSopenharmony_ci st->codecpar->bits_per_coded_sample; 199cabdff1aSopenharmony_ci st->codecpar->block_align = st->codecpar->ch_layout.nb_channels * 200cabdff1aSopenharmony_ci st->codecpar->bits_per_coded_sample; 201cabdff1aSopenharmony_ci 202cabdff1aSopenharmony_ci if (fourxm->tracks[track].adpcm){ 203cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_ADPCM_4XM; 204cabdff1aSopenharmony_ci } else if (st->codecpar->bits_per_coded_sample == 8) { 205cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_PCM_U8; 206cabdff1aSopenharmony_ci } else 207cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; 208cabdff1aSopenharmony_ci 209cabdff1aSopenharmony_ci return 0; 210cabdff1aSopenharmony_ci} 211cabdff1aSopenharmony_ci 212cabdff1aSopenharmony_cistatic int fourxm_read_header(AVFormatContext *s) 213cabdff1aSopenharmony_ci{ 214cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 215cabdff1aSopenharmony_ci unsigned int fourcc_tag; 216cabdff1aSopenharmony_ci unsigned int size; 217cabdff1aSopenharmony_ci int header_size; 218cabdff1aSopenharmony_ci FourxmDemuxContext *fourxm = s->priv_data; 219cabdff1aSopenharmony_ci unsigned char *header = NULL; 220cabdff1aSopenharmony_ci int i, ret; 221cabdff1aSopenharmony_ci 222cabdff1aSopenharmony_ci fourxm->track_count = 0; 223cabdff1aSopenharmony_ci fourxm->tracks = NULL; 224cabdff1aSopenharmony_ci fourxm->fps = (AVRational){1,1}; 225cabdff1aSopenharmony_ci fourxm->video_stream_index = -1; 226cabdff1aSopenharmony_ci 227cabdff1aSopenharmony_ci /* skip the first 3 32-bit numbers */ 228cabdff1aSopenharmony_ci avio_skip(pb, 12); 229cabdff1aSopenharmony_ci 230cabdff1aSopenharmony_ci /* check for LIST-HEAD */ 231cabdff1aSopenharmony_ci GET_LIST_HEADER(); 232cabdff1aSopenharmony_ci header_size = size - 4; 233cabdff1aSopenharmony_ci if (fourcc_tag != HEAD_TAG || header_size < 0) 234cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 235cabdff1aSopenharmony_ci 236cabdff1aSopenharmony_ci /* allocate space for the header and load the whole thing */ 237cabdff1aSopenharmony_ci header = av_malloc(header_size); 238cabdff1aSopenharmony_ci if (!header) 239cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 240cabdff1aSopenharmony_ci if (avio_read(pb, header, header_size) != header_size) { 241cabdff1aSopenharmony_ci av_free(header); 242cabdff1aSopenharmony_ci return AVERROR(EIO); 243cabdff1aSopenharmony_ci } 244cabdff1aSopenharmony_ci 245cabdff1aSopenharmony_ci /* take the lazy approach and search for any and all vtrk and strk chunks */ 246cabdff1aSopenharmony_ci for (i = 0; i < header_size - 8; i++) { 247cabdff1aSopenharmony_ci fourcc_tag = AV_RL32(&header[i]); 248cabdff1aSopenharmony_ci size = AV_RL32(&header[i + 4]); 249cabdff1aSopenharmony_ci if (size > header_size - i - 8 && (fourcc_tag == vtrk_TAG || fourcc_tag == strk_TAG)) { 250cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "chunk larger than array %d>%d\n", size, header_size - i - 8); 251cabdff1aSopenharmony_ci ret = AVERROR_INVALIDDATA; 252cabdff1aSopenharmony_ci goto fail; 253cabdff1aSopenharmony_ci } 254cabdff1aSopenharmony_ci 255cabdff1aSopenharmony_ci if (fourcc_tag == std__TAG) { 256cabdff1aSopenharmony_ci if (header_size - i < 16) { 257cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "std TAG truncated\n"); 258cabdff1aSopenharmony_ci ret = AVERROR_INVALIDDATA; 259cabdff1aSopenharmony_ci goto fail; 260cabdff1aSopenharmony_ci } 261cabdff1aSopenharmony_ci fourxm->fps = av_d2q(av_int2float(AV_RL32(&header[i + 12])), 10000); 262cabdff1aSopenharmony_ci } else if (fourcc_tag == vtrk_TAG) { 263cabdff1aSopenharmony_ci if ((ret = parse_vtrk(s, fourxm, header + i, size, 264cabdff1aSopenharmony_ci header_size - i)) < 0) 265cabdff1aSopenharmony_ci goto fail; 266cabdff1aSopenharmony_ci 267cabdff1aSopenharmony_ci i += 8 + size; 268cabdff1aSopenharmony_ci } else if (fourcc_tag == strk_TAG) { 269cabdff1aSopenharmony_ci if ((ret = parse_strk(s, fourxm, header + i, size, 270cabdff1aSopenharmony_ci header_size - i)) < 0) 271cabdff1aSopenharmony_ci goto fail; 272cabdff1aSopenharmony_ci 273cabdff1aSopenharmony_ci i += 8 + size; 274cabdff1aSopenharmony_ci } 275cabdff1aSopenharmony_ci } 276cabdff1aSopenharmony_ci 277cabdff1aSopenharmony_ci /* skip over the LIST-MOVI chunk (which is where the stream should be */ 278cabdff1aSopenharmony_ci GET_LIST_HEADER(); 279cabdff1aSopenharmony_ci if (fourcc_tag != MOVI_TAG) { 280cabdff1aSopenharmony_ci ret = AVERROR_INVALIDDATA; 281cabdff1aSopenharmony_ci goto fail; 282cabdff1aSopenharmony_ci } 283cabdff1aSopenharmony_ci 284cabdff1aSopenharmony_ci av_free(header); 285cabdff1aSopenharmony_ci /* initialize context members */ 286cabdff1aSopenharmony_ci fourxm->video_pts = -1; /* first frame will push to 0 */ 287cabdff1aSopenharmony_ci 288cabdff1aSopenharmony_ci return 0; 289cabdff1aSopenharmony_cifail: 290cabdff1aSopenharmony_ci av_free(header); 291cabdff1aSopenharmony_ci return ret; 292cabdff1aSopenharmony_ci} 293cabdff1aSopenharmony_ci 294cabdff1aSopenharmony_cistatic int fourxm_read_packet(AVFormatContext *s, 295cabdff1aSopenharmony_ci AVPacket *pkt) 296cabdff1aSopenharmony_ci{ 297cabdff1aSopenharmony_ci FourxmDemuxContext *fourxm = s->priv_data; 298cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 299cabdff1aSopenharmony_ci unsigned int fourcc_tag; 300cabdff1aSopenharmony_ci unsigned int size; 301cabdff1aSopenharmony_ci int ret = 0; 302cabdff1aSopenharmony_ci unsigned int track_number; 303cabdff1aSopenharmony_ci int packet_read = 0; 304cabdff1aSopenharmony_ci unsigned char header[8]; 305cabdff1aSopenharmony_ci int64_t audio_frame_count; 306cabdff1aSopenharmony_ci 307cabdff1aSopenharmony_ci while (!packet_read) { 308cabdff1aSopenharmony_ci if ((ret = avio_read(s->pb, header, 8)) < 0) 309cabdff1aSopenharmony_ci return ret; 310cabdff1aSopenharmony_ci fourcc_tag = AV_RL32(&header[0]); 311cabdff1aSopenharmony_ci size = AV_RL32(&header[4]); 312cabdff1aSopenharmony_ci if (avio_feof(pb)) 313cabdff1aSopenharmony_ci return AVERROR(EIO); 314cabdff1aSopenharmony_ci switch (fourcc_tag) { 315cabdff1aSopenharmony_ci case LIST_TAG: 316cabdff1aSopenharmony_ci /* this is a good time to bump the video pts */ 317cabdff1aSopenharmony_ci fourxm->video_pts++; 318cabdff1aSopenharmony_ci 319cabdff1aSopenharmony_ci /* skip the LIST-* tag and move on to the next fourcc */ 320cabdff1aSopenharmony_ci avio_rl32(pb); 321cabdff1aSopenharmony_ci break; 322cabdff1aSopenharmony_ci 323cabdff1aSopenharmony_ci case ifrm_TAG: 324cabdff1aSopenharmony_ci case pfrm_TAG: 325cabdff1aSopenharmony_ci case cfrm_TAG: 326cabdff1aSopenharmony_ci case ifr2_TAG: 327cabdff1aSopenharmony_ci case pfr2_TAG: 328cabdff1aSopenharmony_ci case cfr2_TAG: 329cabdff1aSopenharmony_ci /* allocate 8 more bytes than 'size' to account for fourcc 330cabdff1aSopenharmony_ci * and size */ 331cabdff1aSopenharmony_ci if (size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE - 8) 332cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 333cabdff1aSopenharmony_ci if (fourxm->video_stream_index < 0) 334cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 335cabdff1aSopenharmony_ci if ((ret = av_new_packet(pkt, size + 8)) < 0) 336cabdff1aSopenharmony_ci return ret; 337cabdff1aSopenharmony_ci pkt->stream_index = fourxm->video_stream_index; 338cabdff1aSopenharmony_ci pkt->pts = fourxm->video_pts; 339cabdff1aSopenharmony_ci pkt->pos = avio_tell(s->pb); 340cabdff1aSopenharmony_ci memcpy(pkt->data, header, 8); 341cabdff1aSopenharmony_ci ret = avio_read(s->pb, &pkt->data[8], size); 342cabdff1aSopenharmony_ci 343cabdff1aSopenharmony_ci if (ret < 0) { 344cabdff1aSopenharmony_ci av_packet_unref(pkt); 345cabdff1aSopenharmony_ci } else { 346cabdff1aSopenharmony_ci packet_read = 1; 347cabdff1aSopenharmony_ci av_shrink_packet(pkt, ret + 8); 348cabdff1aSopenharmony_ci } 349cabdff1aSopenharmony_ci break; 350cabdff1aSopenharmony_ci 351cabdff1aSopenharmony_ci case snd__TAG: 352cabdff1aSopenharmony_ci track_number = avio_rl32(pb); 353cabdff1aSopenharmony_ci avio_skip(pb, 4); 354cabdff1aSopenharmony_ci size -= 8; 355cabdff1aSopenharmony_ci 356cabdff1aSopenharmony_ci if (track_number < fourxm->track_count && 357cabdff1aSopenharmony_ci fourxm->tracks[track_number].channels > 0) { 358cabdff1aSopenharmony_ci ret = av_get_packet(s->pb, pkt, size); 359cabdff1aSopenharmony_ci if (ret < 0) 360cabdff1aSopenharmony_ci return ret; 361cabdff1aSopenharmony_ci pkt->stream_index = 362cabdff1aSopenharmony_ci fourxm->tracks[track_number].stream_index; 363cabdff1aSopenharmony_ci pkt->pts = fourxm->tracks[track_number].audio_pts; 364cabdff1aSopenharmony_ci packet_read = 1; 365cabdff1aSopenharmony_ci 366cabdff1aSopenharmony_ci /* pts accounting */ 367cabdff1aSopenharmony_ci audio_frame_count = size; 368cabdff1aSopenharmony_ci if (fourxm->tracks[track_number].adpcm) 369cabdff1aSopenharmony_ci audio_frame_count -= 2 * (fourxm->tracks[track_number].channels); 370cabdff1aSopenharmony_ci audio_frame_count /= fourxm->tracks[track_number].channels; 371cabdff1aSopenharmony_ci if (fourxm->tracks[track_number].adpcm) { 372cabdff1aSopenharmony_ci audio_frame_count *= 2; 373cabdff1aSopenharmony_ci } else 374cabdff1aSopenharmony_ci audio_frame_count /= 375cabdff1aSopenharmony_ci (fourxm->tracks[track_number].bits / 8); 376cabdff1aSopenharmony_ci fourxm->tracks[track_number].audio_pts += audio_frame_count; 377cabdff1aSopenharmony_ci } else { 378cabdff1aSopenharmony_ci avio_skip(pb, size); 379cabdff1aSopenharmony_ci } 380cabdff1aSopenharmony_ci break; 381cabdff1aSopenharmony_ci 382cabdff1aSopenharmony_ci default: 383cabdff1aSopenharmony_ci avio_skip(pb, size); 384cabdff1aSopenharmony_ci break; 385cabdff1aSopenharmony_ci } 386cabdff1aSopenharmony_ci } 387cabdff1aSopenharmony_ci return ret; 388cabdff1aSopenharmony_ci} 389cabdff1aSopenharmony_ci 390cabdff1aSopenharmony_cistatic int fourxm_read_close(AVFormatContext *s) 391cabdff1aSopenharmony_ci{ 392cabdff1aSopenharmony_ci FourxmDemuxContext *fourxm = s->priv_data; 393cabdff1aSopenharmony_ci 394cabdff1aSopenharmony_ci av_freep(&fourxm->tracks); 395cabdff1aSopenharmony_ci 396cabdff1aSopenharmony_ci return 0; 397cabdff1aSopenharmony_ci} 398cabdff1aSopenharmony_ci 399cabdff1aSopenharmony_ciconst AVInputFormat ff_fourxm_demuxer = { 400cabdff1aSopenharmony_ci .name = "4xm", 401cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("4X Technologies"), 402cabdff1aSopenharmony_ci .priv_data_size = sizeof(FourxmDemuxContext), 403cabdff1aSopenharmony_ci .flags_internal = FF_FMT_INIT_CLEANUP, 404cabdff1aSopenharmony_ci .read_probe = fourxm_probe, 405cabdff1aSopenharmony_ci .read_header = fourxm_read_header, 406cabdff1aSopenharmony_ci .read_packet = fourxm_read_packet, 407cabdff1aSopenharmony_ci .read_close = fourxm_read_close, 408cabdff1aSopenharmony_ci}; 409