1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-07-11 14:30:22 +02:00
Files
compat
doc
ffbuild
fftools
libavcodec
libavdevice
libavfilter
libavformat
tests
.gitignore
3dostr.c
4xm.c
Makefile
a64.c
aacdec.c
aadec.c
aaxdec.c
ac3_channel_layout_tab.c
ac3dec.c
acedec.c
acm.c
act.c
adp.c
ads.c
adtsenc.c
adxdec.c
aea.c
afc.c
aiff.c
aiff.h
aiffdec.c
aiffenc.c
aixdec.c
allformats.c
alp.c
amr.c
amvenc.c
anm.c
apac.c
apc.c
ape.c
apetag.c
apetag.h
apm.c
apngdec.c
apngenc.c
aptxdec.c
aqtitledec.c
argo_asf.c
argo_asf.h
argo_brp.c
argo_cvg.c
asf.c
asf.h
asf_tags.c
asfcrypt.c
asfcrypt.h
asfdec_f.c
asfdec_o.c
asfenc.c
assdec.c
assenc.c
ast.c
ast.h
astdec.c
astenc.c
async.c
au.c
av1.c
av1.h
av1dec.c
avc.c
avc.h
avformat.c
avformat.h
avformatres.rc
avi.h
avidec.c
avienc.c
avio.c
avio.h
avio_internal.h
aviobuf.c
avisynth.c
avlanguage.c
avlanguage.h
avr.c
avs.c
avs2dec.c
avs3dec.c
bethsoftvid.c
bfi.c
bink.c
binka.c
bintext.c
bit.c
bluray.c
bmv.c
boadec.c
bonk.c
brstm.c
c93.c
cache.c
caf.c
caf.h
cafdec.c
cafenc.c
cavsvideodec.c
cdg.c
cdxl.c
chromaprint.c
cinedec.c
codec2.c
concat.c
concatdec.c
crcenc.c
crypto.c
dash.c
dash.h
dashdec.c
dashenc.c
data_uri.c
dauddec.c
daudenc.c
dca_sample_rate_tab.c
dcstr.c
demux.c
demux.h
demux_utils.c
derf.c
dfa.c
dfpwmdec.c
dhav.c
diracdec.c
dnxhddec.c
dovi_isom.c
dovi_isom.h
dsfdec.c
dsicin.c
dss.c
dtsdec.c
dtshddec.c
dump.c
dv.c
dv.h
dvbsub.c
dvbtxt.c
dvenc.c
dxa.c
eacdata.c
electronicarts.c
epafdec.c
ffmeta.h
ffmetadec.c
ffmetaenc.c
fifo.c
fifo_test.c
file.c
file_open.c
filmstripdec.c
filmstripenc.c
fitsdec.c
fitsenc.c
flac_picture.c
flac_picture.h
flacdec.c
flacenc.c
flacenc.h
flacenc_header.c
flic.c
flv.h
flvdec.c
flvenc.c
format.c
framecrcenc.c
framehash.c
frmdec.c
fsb.c
ftp.c
fwse.c
g722.c
g723_1.c
g726.c
g729dec.c
gdv.c
genh.c
gif.c
gifdec.c
golomb_tab.c
gopher.c
gsmdec.c
gxf.c
gxf.h
gxfenc.c
h261dec.c
h263dec.c
h264dec.c
hashenc.c
hca.c
hcom.c
hdsenc.c
hevc.c
hevc.h
hevcdec.c
hls.c
hls_sample_encryption.c
hls_sample_encryption.h
hlsenc.c
hlsplaylist.c
hlsplaylist.h
hlsproto.c
hnm.c
http.c
http.h
httpauth.c
httpauth.h
icecast.c
icodec.c
icoenc.c
id3v1.c
id3v1.h
id3v2.c
id3v2.h
id3v2enc.c
idcin.c
idroqdec.c
idroqenc.c
iff.c
ifv.c
ilbc.c
imf.h
imf_cpl.c
imfdec.c
img2.c
img2.h
img2_alias_pix.c
img2_brender_pix.c
img2dec.c
img2enc.c
imx.c
ingenientdec.c
internal.h
ip.c
ip.h
ipfsgateway.c
ipmovie.c
ipudec.c
ircam.c
ircam.h
ircamdec.c
ircamenc.c
isom.c
isom.h
isom_tags.c
iss.c
iv8.c
ivfdec.c
ivfenc.c
jacosubdec.c
jacosubenc.c
jpegtables.c
jpegxl_probe.c
jpegxl_probe.h
jvdec.c
kvag.c
lafdec.c
latmenc.c
libamqp.c
libavformat.v
libgme.c
libmodplug.c
libopenmpt.c
librist.c
librtmp.c
libsmbclient.c
libsrt.c
libssh.c
libzmq.c
lmlm4.c
loasdec.c
log2_tab.c
lrc.c
lrc.h
lrcdec.c
lrcenc.c
luodatdec.c
lvfdec.c
lxfdec.c
m4vdec.c
matroska.c
matroska.h
matroskadec.c
matroskaenc.c
mca.c
mccdec.c
md5proto.c
metadata.c
metadata.h
mgsts.c
microdvddec.c
microdvdenc.c
mj2kdec.c
mkvtimestamp_v2.c
mlpdec.c
mlvdec.c
mm.c
mmf.c
mms.c
mms.h
mmsh.c
mmst.c
mods.c
moflex.c
mov.c
mov_chan.c
mov_chan.h
mov_esds.c
movenc.c
movenc.h
movenc_ttml.c
movenc_ttml.h
movenccenc.c
movenccenc.h
movenchint.c
mp3dec.c
mp3enc.c
mpc.c
mpc8.c
mpeg.c
mpeg.h
mpeg4audio_sample_rates.c
mpegaudiotabs.c
mpegenc.c
mpegts.c
mpegts.h
mpegtsenc.c
mpegvideodec.c
mpjpeg.c
mpjpegdec.c
mpl2dec.c
mpsubdec.c
msf.c
msnwc_tcp.c
mspdec.c
mtaf.c
mtv.c
musx.c
mux.c
mux.h
mux_utils.c
mvdec.c
mvi.c
mxf.c
mxf.h
mxfdec.c
mxfenc.c
mxg.c
ncdec.c
network.c
network.h
nistspheredec.c
nspdec.c
nsvdec.c
nullenc.c
nut.c
nut.h
nutdec.c
nutenc.c
nuv.c
oggdec.c
oggdec.h
oggenc.c
oggparsecelt.c
oggparsedirac.c
oggparseflac.c
oggparseogm.c
oggparseopus.c
oggparseskeleton.c
oggparsespeex.c
oggparsetheora.c
oggparsevorbis.c
oggparsevp8.c
oma.c
oma.h
omadec.c
omaenc.c
options.c
options_table.h
os_support.c
os_support.h
paf.c
pcm.c
pcm.h
pcmdec.c
pcmenc.c
pjsdec.c
pmpdec.c
pp_bnk.c
prompeg.c
protocols.c
psxstr.c
pva.c
pvfdec.c
qcp.c
qtpalette.c
qtpalette.h
r3d.c
rawdec.c
rawdec.h
rawenc.c
rawenc.h
rawutils.c
rawutils.h
rawvideodec.c
rdt.c
rdt.h
realtextdec.c
redspark.c
replaygain.c
replaygain.h
riff.c
riff.h
riffdec.c
riffenc.c
rl2.c
rm.c
rm.h
rmdec.c
rmenc.c
rmsipr.c
rmsipr.h
rpl.c
rsd.c
rso.c
rso.h
rsodec.c
rsoenc.c
rtmp.h
rtmpcrypt.c
rtmpcrypt.h
rtmpdh.c
rtmpdh.h
rtmpdigest.c
rtmphttp.c
rtmppkt.c
rtmppkt.h
rtmpproto.c
rtp.c
rtp.h
rtpdec.c
rtpdec.h
rtpdec_ac3.c
rtpdec_amr.c
rtpdec_asf.c
rtpdec_dv.c
rtpdec_formats.h
rtpdec_g726.c
rtpdec_h261.c
rtpdec_h263.c
rtpdec_h263_rfc2190.c
rtpdec_h264.c
rtpdec_hevc.c
rtpdec_ilbc.c
rtpdec_jpeg.c
rtpdec_latm.c
rtpdec_mpa_robust.c
rtpdec_mpeg12.c
rtpdec_mpeg4.c
rtpdec_mpegts.c
rtpdec_qcelp.c
rtpdec_qdm2.c
rtpdec_qt.c
rtpdec_rfc4175.c
rtpdec_svq3.c
rtpdec_vc2hq.c
rtpdec_vp8.c
rtpdec_vp9.c
rtpdec_xiph.c
rtpenc.c
rtpenc.h
rtpenc_aac.c
rtpenc_amr.c
rtpenc_chain.c
rtpenc_chain.h
rtpenc_h261.c
rtpenc_h263.c
rtpenc_h263_rfc2190.c
rtpenc_h264_hevc.c
rtpenc_jpeg.c
rtpenc_latm.c
rtpenc_mpegts.c
rtpenc_mpv.c
rtpenc_rfc4175.c
rtpenc_vc2hq.c
rtpenc_vp8.c
rtpenc_vp9.c
rtpenc_xiph.c
rtpproto.c
rtpproto.h
rtsp.c
rtsp.h
rtspcodes.h
rtspdec.c
rtspenc.c
s337m.c
samidec.c
sapdec.c
sapenc.c
sauce.c
sauce.h
sbcdec.c
sbgdec.c
sccdec.c
sccenc.c
scd.c
sctp.c
sdp.c
sdr2.c
sdsdec.c
sdxdec.c
seek.c
segafilm.c
segafilmenc.c
segment.c
serdec.c
sga.c
shortendec.c
sierravmd.c
siff.c
smacker.c
smjpeg.c
smjpeg.h
smjpegdec.c
smjpegenc.c
smoothstreamingenc.c
smush.c
sol.c
sox.h
soxdec.c
soxenc.c
spdif.c
spdif.h
spdifdec.c
spdifenc.c
srtdec.c
srtenc.c
srtp.c
srtp.h
srtpproto.c
stldec.c
subfile.c
subtitles.c
subtitles.h
subviewer1dec.c
subviewerdec.c
supdec.c
supenc.c
svag.c
svs.c
swf.c
swf.h
swfdec.c
swfenc.c
takdec.c
tcp.c
tedcaptionsdec.c
tee.c
tee_common.c
tee_common.h
teeproto.c
thp.c
tiertexseq.c
tls.c
tls.h
tls_gnutls.c
tls_libtls.c
tls_mbedtls.c
tls_openssl.c
tls_schannel.c
tls_securetransport.c
tmv.c
to_upper4.c
tta.c
ttaenc.c
ttmlenc.c
ttmlenc.h
tty.c
txd.c
ty.c
udp.c
uncodedframecrcenc.c
unix.c
url.c
url.h
urldecode.c
urldecode.h
utils.c
vag.c
vapoursynth.c
vc1dec.c
vc1test.c
vc1testenc.c
version.c
version.h
version_major.h
vividas.c
vivo.c
voc.c
voc.h
voc_packet.c
vocdec.c
vocenc.c
vorbiscomment.c
vorbiscomment.h
vpcc.c
vpcc.h
vpk.c
vplayerdec.c
vqf.c
w64.c
w64.h
wady.c
wavdec.c
wavenc.c
wc3movie.c
webm_chunk.c
webmdashenc.c
webpenc.c
webvttdec.c
webvttenc.c
westwood_aud.c
westwood_audenc.c
westwood_vqa.c
wsddec.c
wtv.h
wtv_common.c
wtvdec.c
wtvenc.c
wv.c
wv.h
wvdec.c
wvedec.c
wvenc.c
xa.c
xmv.c
xvag.c
xwma.c
yop.c
yuv4mpeg.h
yuv4mpegdec.c
yuv4mpegenc.c
libavutil
libpostproc
libswresample
libswscale
presets
tests
tools
.gitattributes
.gitignore
.mailmap
.travis.yml
CONTRIBUTING.md
COPYING.GPLv2
COPYING.GPLv3
COPYING.LGPLv2.1
COPYING.LGPLv3
CREDITS
Changelog
INSTALL.md
LICENSE.md
MAINTAINERS
Makefile
README.md
RELEASE
configure
FFmpeg/libavformat/mca.c

231 lines
7.9 KiB
C
Raw Normal View History

/*
* MCA demuxer
* Copyright (c) 2020 Zixing Liu
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "avio_internal.h"
#include "demux.h"
#include "internal.h"
typedef struct MCADemuxContext {
uint32_t block_count;
uint16_t block_size;
uint32_t current_block;
uint32_t data_start;
uint32_t samples_per_block;
} MCADemuxContext;
static int probe(const AVProbeData *p)
{
if (AV_RL32(p->buf) == MKTAG('M', 'A', 'D', 'P') &&
AV_RL16(p->buf + 4) <= 0x5)
return AVPROBE_SCORE_MAX / 3 * 2;
return 0;
}
static int read_header(AVFormatContext *s)
{
AVStream *st;
MCADemuxContext *m = s->priv_data;
AVCodecParameters *par;
int64_t file_size = avio_size(s->pb);
uint16_t version = 0;
uint32_t header_size, data_size, data_offset, loop_start, loop_end,
nb_samples, nb_metadata, coef_offset = 0;
int ch, ret;
int64_t ret_size;
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
par = st->codecpar;
par->codec_type = AVMEDIA_TYPE_AUDIO;
// parse file headers
avio_skip(s->pb, 0x4); // skip the file magic
version = avio_rl16(s->pb);
avio_skip(s->pb, 0x2); // padding
par->ch_layout.nb_channels = avio_r8(s->pb);
avio_skip(s->pb, 0x1); // padding
m->block_size = avio_rl16(s->pb);
nb_samples = avio_rl32(s->pb);
par->sample_rate = avio_rl32(s->pb);
loop_start = avio_rl32(s->pb);
loop_end = avio_rl32(s->pb);
header_size = avio_rl32(s->pb);
data_size = avio_rl32(s->pb);
avio_skip(s->pb, 0x4);
nb_metadata = avio_rl16(s->pb);
avio_skip(s->pb, 0x2); // unknown u16 field
// samples per frame = 14; frame size = 8 (2^3)
m->samples_per_block = (m->block_size * 14) >> 3;
if (m->samples_per_block < 1)
return AVERROR_INVALIDDATA;
m->block_count = nb_samples / m->samples_per_block;
st->duration = nb_samples;
// sanity checks
if (!par->ch_layout.nb_channels || par->sample_rate <= 0
|| loop_start > loop_end || m->block_count < 1)
return AVERROR_INVALIDDATA;
if ((ret = av_dict_set_int(&s->metadata, "loop_start",
av_rescale(loop_start, AV_TIME_BASE,
par->sample_rate), 0)) < 0)
return ret;
if ((ret = av_dict_set_int(&s->metadata, "loop_end",
av_rescale(loop_end, AV_TIME_BASE,
par->sample_rate), 0)) < 0)
return ret;
if ((32 + 4 + m->block_size) > (INT_MAX / par->ch_layout.nb_channels) ||
(32 + 4 + m->block_size) * par->ch_layout.nb_channels > INT_MAX - 8)
return AVERROR_INVALIDDATA;
avpriv_set_pts_info(st, 64, 1, par->sample_rate);
if (version <= 4) {
// version <= 4 needs to use the file size to calculate the offsets
if (file_size < 0) {
return AVERROR(EIO);
}
if (file_size - data_size > UINT32_MAX)
return AVERROR_INVALIDDATA;
m->data_start = file_size - data_size;
if (version <= 3) {
nb_metadata = 0;
// header_size is not available or incorrect in older versions
header_size = m->data_start;
}
} else if (version == 5) {
// read data_start location from the header
if (0x30 * par->ch_layout.nb_channels + 0x4 > header_size)
return AVERROR_INVALIDDATA;
data_offset = header_size - 0x30 * par->ch_layout.nb_channels - 0x4;
if ((ret_size = avio_seek(s->pb, data_offset, SEEK_SET)) < 0)
return ret_size;
m->data_start = avio_rl32(s->pb);
// check if the metadata is reasonable
if (file_size > 0 && (int64_t)m->data_start + data_size > file_size) {
// the header is broken beyond repair
if ((int64_t)header_size + data_size > file_size) {
av_log(s, AV_LOG_ERROR,
"MCA metadata corrupted, unable to determine the data offset.\n");
return AVERROR_INVALIDDATA;
}
// recover the data_start information from the data size
av_log(s, AV_LOG_WARNING,
"Incorrect header size found in metadata, "
"header size approximated from the data size\n");
if (file_size - data_offset > UINT32_MAX)
return AVERROR_INVALIDDATA;
m->data_start = file_size - data_size;
}
} else {
avpriv_request_sample(s, "version %d", version);
return AVERROR_PATCHWELCOME;
}
// coefficient alignment = 0x30; metadata size = 0x14
if (0x30 * par->ch_layout.nb_channels + nb_metadata * 0x14 > header_size)
return AVERROR_INVALIDDATA;
coef_offset =
header_size - 0x30 * par->ch_layout.nb_channels + nb_metadata * 0x14;
st->start_time = 0;
par->codec_id = AV_CODEC_ID_ADPCM_THP_LE;
ret = ff_alloc_extradata(st->codecpar, 32 * par->ch_layout.nb_channels);
if (ret < 0)
return ret;
if ((ret_size = avio_seek(s->pb, coef_offset, SEEK_SET)) < 0)
return ret_size;
for (ch = 0; ch < par->ch_layout.nb_channels; ch++) {
if ((ret = ffio_read_size(s->pb, par->extradata + ch * 32, 32)) < 0)
return ret;
// 0x30 (alignment) - 0x20 (actual size, 32) = 0x10 (padding)
avio_skip(s->pb, 0x10);
}
// seek to the beginning of the adpcm data
// there are some files where the adpcm audio data is not immediately after the header
if ((ret_size = avio_seek(s->pb, m->data_start, SEEK_SET)) < 0)
return ret_size;
return 0;
}
static int read_packet(AVFormatContext *s, AVPacket *pkt)
{
AVCodecParameters *par = s->streams[0]->codecpar;
MCADemuxContext *m = s->priv_data;
uint16_t size = m->block_size;
uint32_t samples = m->samples_per_block;
int ret = 0;
if (avio_feof(s->pb))
return AVERROR_EOF;
m->current_block++;
if (m->current_block > m->block_count)
return AVERROR_EOF;
if ((ret = av_get_packet(s->pb, pkt, size * par->ch_layout.nb_channels)) < 0)
return ret;
pkt->duration = samples;
pkt->stream_index = 0;
return 0;
}
static int read_seek(AVFormatContext *s, int stream_index,
int64_t timestamp, int flags)
{
AVStream *st = s->streams[stream_index];
MCADemuxContext *m = s->priv_data;
int64_t ret = 0;
if (timestamp < 0)
timestamp = 0;
timestamp /= m->samples_per_block;
if (timestamp >= m->block_count)
timestamp = m->block_count - 1;
ret = avio_seek(s->pb, m->data_start + timestamp * m->block_size *
st->codecpar->ch_layout.nb_channels, SEEK_SET);
if (ret < 0)
return ret;
m->current_block = timestamp;
avpriv_update_cur_dts(s, st, timestamp * m->samples_per_block);
return 0;
}
const AVInputFormat ff_mca_demuxer = {
.name = "mca",
.long_name = NULL_IF_CONFIG_SMALL("MCA Audio Format"),
.priv_data_size = sizeof(MCADemuxContext),
.read_probe = probe,
.read_header = read_header,
.read_packet = read_packet,
.read_seek = read_seek,
.extensions = "mca",
};