3 * Copyright (c) 2020 Zixing Liu
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "libavutil/intreadwrite.h"
24 #include "avio_internal.h"
28 typedef struct MCADemuxContext
{
31 uint32_t current_block
;
33 uint32_t samples_per_block
;
36 static int probe(const AVProbeData
*p
)
38 if (AV_RL32(p
->buf
) == MKTAG('M', 'A', 'D', 'P') &&
39 AV_RL16(p
->buf
+ 4) <= 0x5)
40 return AVPROBE_SCORE_MAX
/ 3 * 2;
44 static int read_header(AVFormatContext
*s
)
47 MCADemuxContext
*m
= s
->priv_data
;
48 AVCodecParameters
*par
;
49 int64_t file_size
= avio_size(s
->pb
);
51 uint32_t header_size
, data_size
, data_offset
, loop_start
, loop_end
,
52 nb_samples
, nb_metadata
, coef_offset
= 0;
56 st
= avformat_new_stream(s
, NULL
);
58 return AVERROR(ENOMEM
);
60 par
->codec_type
= AVMEDIA_TYPE_AUDIO
;
63 avio_skip(s
->pb
, 0x4); // skip the file magic
64 version
= avio_rl16(s
->pb
);
65 avio_skip(s
->pb
, 0x2); // padding
66 par
->ch_layout
.nb_channels
= avio_r8(s
->pb
);
67 avio_skip(s
->pb
, 0x1); // padding
68 m
->block_size
= avio_rl16(s
->pb
);
69 nb_samples
= avio_rl32(s
->pb
);
70 par
->sample_rate
= avio_rl32(s
->pb
);
71 loop_start
= avio_rl32(s
->pb
);
72 loop_end
= avio_rl32(s
->pb
);
73 header_size
= avio_rl32(s
->pb
);
74 data_size
= avio_rl32(s
->pb
);
75 avio_skip(s
->pb
, 0x4);
76 nb_metadata
= avio_rl16(s
->pb
);
77 avio_skip(s
->pb
, 0x2); // unknown u16 field
79 // samples per frame = 14; frame size = 8 (2^3)
80 m
->samples_per_block
= (m
->block_size
* 14) >> 3;
82 if (m
->samples_per_block
< 1)
83 return AVERROR_INVALIDDATA
;
85 m
->block_count
= nb_samples
/ m
->samples_per_block
;
86 st
->duration
= nb_samples
;
89 if (!par
->ch_layout
.nb_channels
|| par
->sample_rate
<= 0
90 || loop_start
> loop_end
|| m
->block_count
< 1)
91 return AVERROR_INVALIDDATA
;
92 if ((ret
= av_dict_set_int(&s
->metadata
, "loop_start",
93 av_rescale(loop_start
, AV_TIME_BASE
,
94 par
->sample_rate
), 0)) < 0)
96 if ((ret
= av_dict_set_int(&s
->metadata
, "loop_end",
97 av_rescale(loop_end
, AV_TIME_BASE
,
98 par
->sample_rate
), 0)) < 0)
100 if ((32 + 4 + m
->block_size
) > (INT_MAX
/ par
->ch_layout
.nb_channels
) ||
101 (32 + 4 + m
->block_size
) * par
->ch_layout
.nb_channels
> INT_MAX
- 8)
102 return AVERROR_INVALIDDATA
;
103 avpriv_set_pts_info(st
, 64, 1, par
->sample_rate
);
106 // version <= 4 needs to use the file size to calculate the offsets
110 if (file_size
- data_size
> UINT32_MAX
)
111 return AVERROR_INVALIDDATA
;
112 m
->data_start
= file_size
- data_size
;
115 // header_size is not available or incorrect in older versions
116 header_size
= m
->data_start
;
118 } else if (version
== 5) {
119 // read data_start location from the header
120 if (0x30 * par
->ch_layout
.nb_channels
+ 0x4 > header_size
)
121 return AVERROR_INVALIDDATA
;
122 data_offset
= header_size
- 0x30 * par
->ch_layout
.nb_channels
- 0x4;
123 if ((ret_size
= avio_seek(s
->pb
, data_offset
, SEEK_SET
)) < 0)
125 m
->data_start
= avio_rl32(s
->pb
);
126 // check if the metadata is reasonable
127 if (file_size
> 0 && (int64_t)m
->data_start
+ data_size
> file_size
) {
128 // the header is broken beyond repair
129 if ((int64_t)header_size
+ data_size
> file_size
) {
130 av_log(s
, AV_LOG_ERROR
,
131 "MCA metadata corrupted, unable to determine the data offset.\n");
132 return AVERROR_INVALIDDATA
;
134 // recover the data_start information from the data size
135 av_log(s
, AV_LOG_WARNING
,
136 "Incorrect header size found in metadata, "
137 "header size approximated from the data size\n");
138 if (file_size
- data_offset
> UINT32_MAX
)
139 return AVERROR_INVALIDDATA
;
140 m
->data_start
= file_size
- data_size
;
143 avpriv_request_sample(s
, "version %d", version
);
144 return AVERROR_PATCHWELCOME
;
147 // coefficient alignment = 0x30; metadata size = 0x14
148 if (0x30 * par
->ch_layout
.nb_channels
+ nb_metadata
* 0x14 > header_size
)
149 return AVERROR_INVALIDDATA
;
151 header_size
- 0x30 * par
->ch_layout
.nb_channels
+ nb_metadata
* 0x14;
154 par
->codec_id
= AV_CODEC_ID_ADPCM_THP_LE
;
156 ret
= ff_alloc_extradata(st
->codecpar
, 32 * par
->ch_layout
.nb_channels
);
160 if ((ret_size
= avio_seek(s
->pb
, coef_offset
, SEEK_SET
)) < 0)
162 for (ch
= 0; ch
< par
->ch_layout
.nb_channels
; ch
++) {
163 if ((ret
= ffio_read_size(s
->pb
, par
->extradata
+ ch
* 32, 32)) < 0)
165 // 0x30 (alignment) - 0x20 (actual size, 32) = 0x10 (padding)
166 avio_skip(s
->pb
, 0x10);
169 // seek to the beginning of the adpcm data
170 // there are some files where the adpcm audio data is not immediately after the header
171 if ((ret_size
= avio_seek(s
->pb
, m
->data_start
, SEEK_SET
)) < 0)
177 static int read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
179 AVCodecParameters
*par
= s
->streams
[0]->codecpar
;
180 MCADemuxContext
*m
= s
->priv_data
;
181 uint16_t size
= m
->block_size
;
182 uint32_t samples
= m
->samples_per_block
;
185 if (avio_feof(s
->pb
))
188 if (m
->current_block
> m
->block_count
)
191 if ((ret
= av_get_packet(s
->pb
, pkt
, size
* par
->ch_layout
.nb_channels
)) < 0)
193 pkt
->duration
= samples
;
194 pkt
->stream_index
= 0;
199 static int read_seek(AVFormatContext
*s
, int stream_index
,
200 int64_t timestamp
, int flags
)
202 AVStream
*st
= s
->streams
[stream_index
];
203 MCADemuxContext
*m
= s
->priv_data
;
208 timestamp
/= m
->samples_per_block
;
209 if (timestamp
>= m
->block_count
)
210 timestamp
= m
->block_count
- 1;
211 ret
= avio_seek(s
->pb
, m
->data_start
+ timestamp
* m
->block_size
*
212 st
->codecpar
->ch_layout
.nb_channels
, SEEK_SET
);
216 m
->current_block
= timestamp
;
217 avpriv_update_cur_dts(s
, st
, timestamp
* m
->samples_per_block
);
221 const FFInputFormat ff_mca_demuxer
= {
223 .p
.long_name
= NULL_IF_CONFIG_SMALL("MCA Audio Format"),
224 .p
.extensions
= "mca",
225 .priv_data_size
= sizeof(MCADemuxContext
),
227 .read_header
= read_header
,
228 .read_packet
= read_packet
,
229 .read_seek
= read_seek
,