1 /*
2 * Copyright (c) 2021-2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define HST_LOG_TAG "Minimp4DemuxerPlugin"
17
18 #include "minimp4_demuxer_plugin.h"
19 #include <algorithm>
20 #include <cstdio>
21 #include <cstring>
22 #include <new>
23
24 #include <securec.h>
25 #include "core/plugin_manager.h"
26 #include "foundation/log.h"
27 #include "plugin/common/plugin_buffer.h"
28 #include "plugin/common/plugin_time.h"
29 #include "utils/constants.h"
30 #include "utils/memory_helper.h"
31
32 namespace OHOS {
33 namespace Media {
34 namespace Plugin {
35 namespace Minimp4 {
36 namespace {
37 std::vector<int> sampleRateVec {
38 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350
39 };
40
41 constexpr int8_t ADTS_HEADER_SIZE = 7;
42 constexpr int8_t MP4_HEADER_OFFSET = 4;
43 constexpr int8_t RANK_MAX = 100;
44 constexpr uint32_t DEFAULT_AUDIO_SAMPLE_PER_FRAME = 1024;
45
46 int ReadCallback(int64_t offset, void *buffer, size_t size, void *token);
47
48 int Sniff(const std::string &name, std::shared_ptr<DataSource> dataSource);
49
50 Status RegisterPlugins(const std::shared_ptr<Register> ®);
51
52 void UpdatePluginDefinition(CodecPluginDef &definition);
53 }
54
MiniMP4DemuxerPlugin(std::string name)55 MiniMP4DemuxerPlugin::MiniMP4DemuxerPlugin(std::string name)
56 : DemuxerPlugin(std::move(name)),
57 ioContext_(),
58 callback_(nullptr),
59 mediaInfo_(nullptr),
60 fileSize_(0),
61 sampleIndex_(0)
62 {
63 memset_s(&miniMP4_, sizeof(MP4D_demux_t), 0, sizeof(MP4D_demux_t));
64 MEDIA_LOG_I("MiniMP4DemuxerPlugin, plugin name: %" PUBLIC_LOG "s", pluginName_.c_str());
65 }
66
~MiniMP4DemuxerPlugin()67 MiniMP4DemuxerPlugin::~MiniMP4DemuxerPlugin()
68 {
69 MEDIA_LOG_I("~MiniMP4DemuxerPlugin");
70 }
71
SetDataSource(const std::shared_ptr<DataSource> & source)72 Status MiniMP4DemuxerPlugin::SetDataSource(const std::shared_ptr<DataSource> &source)
73 {
74 ioContext_.dataSource = source;
75 source->GetSize(fileSize_);
76 return Status::OK;
77 }
78
Init()79 Status MiniMP4DemuxerPlugin::Init()
80 {
81 MEDIA_LOG_I("Init called");
82 Reset();
83 return Status::OK;
84 }
85
Deinit()86 Status MiniMP4DemuxerPlugin::Deinit()
87 {
88 return Status::OK;
89 }
90
Prepare()91 Status MiniMP4DemuxerPlugin::Prepare()
92 {
93 return Status::OK;
94 }
95
Reset()96 Status MiniMP4DemuxerPlugin::Reset()
97 {
98 MP4D_close(&miniMP4_);
99 ioContext_.offset = 0;
100 ioContext_.eos = false;
101 mediaInfo_.reset();
102 return Status::OK;
103 }
104
Start()105 Status MiniMP4DemuxerPlugin::Start()
106 {
107 return Status::OK;
108 }
109
Stop()110 Status MiniMP4DemuxerPlugin::Stop()
111 {
112 return Status::OK;
113 }
114
IsParameterSupported(Tag tag)115 bool MiniMP4DemuxerPlugin::IsParameterSupported(Tag tag)
116 {
117 (void)tag;
118 return false;
119 }
120
GetParameter(Tag tag,ValueType & value)121 Status MiniMP4DemuxerPlugin::GetParameter(Tag tag, ValueType &value)
122 {
123 (void)tag;
124 (void)value;
125 return Status::ERROR_UNIMPLEMENTED;
126 }
127
SetParameter(Tag tag,const ValueType & value)128 Status MiniMP4DemuxerPlugin::SetParameter(Tag tag, const ValueType &value)
129 {
130 (void)tag;
131 (void)value;
132 return Status::ERROR_UNIMPLEMENTED;
133 }
134
135
GetAllocator()136 std::shared_ptr<Allocator> MiniMP4DemuxerPlugin::GetAllocator()
137 {
138 return nullptr;
139 }
140
SetCallback(const std::shared_ptr<Callback> & cb)141 Status MiniMP4DemuxerPlugin::SetCallback(const std::shared_ptr<Callback> &cb)
142 {
143 callback_ = cb;
144 return Status::OK;
145 }
146
GetTrackCount()147 size_t MiniMP4DemuxerPlugin::GetTrackCount()
148 {
149 size_t trackCnt = 0;
150 if (mediaInfo_) {
151 trackCnt = mediaInfo_->tracks.size();
152 }
153 return trackCnt;
154 }
155
SelectTrack(int32_t trackId)156 Status MiniMP4DemuxerPlugin::SelectTrack(int32_t trackId)
157 {
158 return Status::OK;
159 }
160
UnselectTrack(int32_t trackId)161 Status MiniMP4DemuxerPlugin::UnselectTrack(int32_t trackId)
162 {
163 return Status::OK;
164 }
165
GetSelectedTracks(std::vector<int32_t> & trackIds)166 Status MiniMP4DemuxerPlugin::GetSelectedTracks(std::vector<int32_t> &trackIds)
167 {
168 trackIds.clear();
169 trackIds.push_back(1);
170 return Status::OK;
171 }
172
GetMediaInfo(MediaInfo & mediaInfo)173 Status MiniMP4DemuxerPlugin::GetMediaInfo(MediaInfo &mediaInfo)
174 {
175 if (fileSize_ == 0 || ioContext_.dataSource == nullptr) {
176 return Status::ERROR_UNKNOWN;
177 }
178 MemoryHelper::make_unique<MediaInfo>().swap(mediaInfo_);
179 mediaInfo_->general.clear();
180 mediaInfo_->tracks.clear();
181
182 if (MP4D_open(&miniMP4_, ReadCallback, reinterpret_cast<void *>(this), fileSize_) == 0) {
183 MEDIA_LOG_E("MP4D_open IS ERROR");
184 mediaInfo_ = nullptr;
185 return Status::ERROR_MISMATCHED_TYPE;
186 }
187 if (AudioAdapterForDecoder() != Status::OK) {
188 mediaInfo_ = nullptr;
189 return Status::ERROR_UNKNOWN;
190 }
191
192 TagMap tagPair { { Tag::AUDIO_SAMPLE_RATE,
193 static_cast<uint32_t>(miniMP4_.track->SampleDescription.audio.samplerate_hz) },
194 {Tag::MEDIA_BITRATE, static_cast<int64_t>(miniMP4_.track->avg_bitrate_bps) },
195 {Tag::AUDIO_CHANNELS, static_cast<uint32_t>(miniMP4_.track->SampleDescription.audio.channelcount) },
196 {Tag::TRACK_ID, static_cast<uint32_t>(0) },
197 {Tag::MIME, std::string(MEDIA_MIME_AUDIO_AAC) },
198 {Tag::AUDIO_MPEG_VERSION, static_cast<uint32_t>(4) },
199 {Tag::AUDIO_AAC_PROFILE, AudioAacProfile::LC },
200 {Tag::AUDIO_AAC_STREAM_FORMAT, AudioAacStreamFormat::MP4ADTS },
201 {Tag::AUDIO_SAMPLE_FORMAT, AudioSampleFormat::S16P },
202 {Tag::AUDIO_SAMPLE_PER_FRAME, DEFAULT_AUDIO_SAMPLE_PER_FRAME },
203 {Tag::AUDIO_CHANNEL_LAYOUT, AudioChannelLayout::STEREO } };
204 mediaInfo_->tracks.push_back(tagPair);
205 mediaInfo = *mediaInfo_;
206 return Status::OK;
207 }
208
FillADTSHead(std::shared_ptr<Memory> & data,uint32_t frameSize)209 void MiniMP4DemuxerPlugin::FillADTSHead(std::shared_ptr<Memory> &data, uint32_t frameSize)
210 {
211 uint8_t adtsHeader[ADTS_HEADER_SIZE] = {0};
212 uint32_t channelConfig = miniMP4_.track->SampleDescription.audio.channelcount;
213 uint32_t packetLen = frameSize + 7;
214 uint32_t samplerateIndex = 0;
215 /* 按格式读取信息帧 */
216 uint8_t objectTypeIndication = miniMP4_.track->object_type_indication;
217 samplerateIndex = ((miniMP4_.track->dsi[0] & 0x7) << 1) + (miniMP4_.track->dsi[1] >> 7); // 1,7 按协议取信息帧
218 adtsHeader[0] = static_cast<uint8_t>(0xFF);
219 adtsHeader[1] = static_cast<uint8_t>(0xF1);
220 adtsHeader[2] = static_cast<uint8_t>(objectTypeIndication) + (samplerateIndex << 2) + (channelConfig >> 2); // 2
221 adtsHeader[3] = static_cast<uint8_t>(((channelConfig & 0x3) << 6) + (packetLen >> 11)); // 3,6,11 按协议取信息帧
222 adtsHeader[4] = static_cast<uint8_t>((packetLen & 0x7FF) >> 3); // 4, 3 按协议取信息帧
223 adtsHeader[5] = static_cast<uint8_t>(((packetLen & 0x7) << 5) + 0x1F); // 5 按协议取信息帧
224 adtsHeader[6] = static_cast<uint8_t>(0xFC); // 6 按协议取信息帧
225 data->Write(adtsHeader, ADTS_HEADER_SIZE, 0);
226 }
227
ReadFrame(Buffer & info,int32_t timeOutMs)228 Status MiniMP4DemuxerPlugin::ReadFrame(Buffer &info, int32_t timeOutMs)
229 {
230 if (!mediaInfo_) {
231 return Status::ERROR_INVALID_PARAMETER;
232 }
233
234 if (sampleIndex_ >= miniMP4_.track->sample_count) {
235 return Status::END_OF_STREAM;
236 }
237 uint32_t frameSize = 0;
238 uint32_t timeStamp = 0;
239 uint32_t duration = 0;
240 uint64_t offset = MP4D_frame_offset(&miniMP4_, 0, sampleIndex_, &frameSize, &timeStamp, &duration);
241 if (offset > fileSize_) {
242 return Status::ERROR_UNKNOWN;
243 }
244 sampleIndex_++;
245 auto buffer = std::make_shared<Buffer>();
246 auto bufData = buffer->AllocMemory(nullptr, frameSize);
247 if (bufData == nullptr) {
248 return Status::ERROR_UNKNOWN;
249 }
250 auto result = ioContext_.dataSource->ReadAt(offset, buffer, static_cast<size_t>(frameSize));
251 if (result != Status::OK) {
252 return Status::ERROR_UNKNOWN;
253 }
254 auto data = info.AllocMemory(nullptr, frameSize + ADTS_HEADER_SIZE);
255 auto writePtr = bufData->GetWritableData(frameSize);
256 if ((data != nullptr) && (writePtr != nullptr)) {
257 FillADTSHead(data, frameSize);
258 size_t writeSize = data->Write(writePtr, frameSize, ADTS_HEADER_SIZE);
259 ASSERT_CONDITION(writeSize == frameSize, "copy data failed");
260 }
261 return Status::OK;
262 }
263
SeekTo(int32_t trackId,int64_t hstTime,SeekMode mode)264 Status MiniMP4DemuxerPlugin::SeekTo(int32_t trackId, int64_t hstTime, SeekMode mode)
265 {
266 uint32_t frameSize = 0;
267 uint32_t timeStamp = 0;
268 uint32_t duration = 0;
269 uint64_t offsetStart = MP4D_frame_offset(&miniMP4_, 0, 0, &frameSize, &timeStamp, &duration);
270 uint64_t offsetEnd =
271 MP4D_frame_offset(&miniMP4_, 0, miniMP4_.track->sample_count - 1, &frameSize, &timeStamp, &duration);
272 uint64_t targetPos = (Plugin::HstTime2Us(hstTime) * static_cast<int64_t>(miniMP4_.track->avg_bitrate_bps)) / 8 +
273 offsetStart;
274 if (targetPos >= offsetEnd) {
275 sampleIndex_ = miniMP4_.track->sample_count;
276 return Status::OK;
277 }
278 sampleIndex_ = 0;
279 uint64_t tempPos = 0;
280 while (sampleIndex_ < miniMP4_.track->sample_count) {
281 tempPos = MP4D_frame_offset(&miniMP4_, 0, sampleIndex_, &frameSize, &timeStamp, &duration);
282 if (tempPos <= targetPos) {
283 sampleIndex_++;
284 } else {
285 break;
286 }
287 }
288 return Status::OK;
289 }
290
GetFileSize()291 size_t MiniMP4DemuxerPlugin::GetFileSize()
292 {
293 return fileSize_;
294 }
295
GetInputBuffer()296 std::shared_ptr<DataSource> MiniMP4DemuxerPlugin::GetInputBuffer()
297 {
298 return ioContext_.dataSource;
299 }
300
AudioAdapterForDecoder()301 Status MiniMP4DemuxerPlugin::AudioAdapterForDecoder()
302 {
303 if (miniMP4_.track == nullptr) {
304 return Status::ERROR_UNKNOWN;
305 }
306 /* 适配解码协议 */
307 size_t sampleRateIndex = (static_cast<uint32_t>(miniMP4_.track->dsi[0] & 0x7) << 1) +
308 (static_cast<uint32_t>(miniMP4_.track->dsi[1]) >> 7);
309
310 if ((sampleRateVec.size() <= sampleRateIndex) || (miniMP4_.track->dsi_bytes >= 20)) { // 20 按协议适配解码器
311 return Status::ERROR_MISMATCHED_TYPE;
312 }
313 miniMP4_.track->SampleDescription.audio.samplerate_hz = sampleRateVec[sampleRateIndex];
314 miniMP4_.track->SampleDescription.audio.channelcount = (miniMP4_.track->dsi[1] & 0x7F) >> 3; // 3 按协议适配解码器
315 return Status::OK;
316 }
317 namespace {
ReadCallback(int64_t offset,void * buffer,size_t size,void * token)318 int ReadCallback(int64_t offset, void *buffer, size_t size, void *token)
319 {
320 MiniMP4DemuxerPlugin *mp4Demuxer = (MiniMP4DemuxerPlugin *)token;
321 uint32_t file_size = mp4Demuxer->GetFileSize();
322 if (offset >= file_size) {
323 MEDIA_LOG_E("ReadCallback offset is bigger");
324 return -1;
325 }
326 std::shared_ptr<DataSource> inputBuffer = mp4Demuxer->GetInputBuffer();
327 auto bufferObj = std::make_shared<Buffer>();
328 auto bufData = bufferObj->WrapMemory(reinterpret_cast<uint8_t*>(buffer), size, size);
329 if (inputBuffer->ReadAt(offset, bufferObj, size) != Status::OK) {
330 return -1;
331 }
332 return 0;
333 }
334
Sniff(const std::string & name,std::shared_ptr<DataSource> dataSource)335 int Sniff(const std::string &name, std::shared_ptr<DataSource> dataSource)
336 {
337 unsigned char m4aCheck[] = {'f', 't', 'y', 'p'};
338 auto buffer = std::make_shared<Buffer>();
339 auto bufData = buffer->AllocMemory(nullptr, sizeof(m4aCheck));
340 if (dataSource->ReadAt(MP4_HEADER_OFFSET, buffer, static_cast<size_t>(sizeof(m4aCheck))) != Status::OK) {
341 return 0;
342 }
343 if (memcmp(bufData->GetReadOnlyData(), &m4aCheck, sizeof(m4aCheck)) != 0) {
344 MEDIA_LOG_E("memcmp m4aCheck is error");
345 return 0;
346 }
347 return RANK_MAX;
348 }
349
RegisterPlugins(const std::shared_ptr<Register> & reg)350 Status RegisterPlugins(const std::shared_ptr<Register> ®)
351 {
352 MEDIA_LOG_D("RegisterPlugins called");
353 if (!reg) {
354 MEDIA_LOG_E("RegisterPlugins fail due to null pointer for reg");
355 return Status::ERROR_INVALID_PARAMETER;
356 }
357 std::string pluginName = "MiniMP4DemuxerPlugin";
358 DemuxerPluginDef regInfo;
359 regInfo.name = pluginName;
360 regInfo.description = "adapter for minimp4 demuxer plugin";
361 regInfo.rank = RANK_MAX;
362 regInfo.creator = [](const std::string &name) -> std::shared_ptr<DemuxerPlugin> {
363 return std::make_shared<MiniMP4DemuxerPlugin>(name);
364 };
365 regInfo.sniffer = Sniff;
366 auto ret = reg->AddPlugin(regInfo);
367 if (ret != Status::OK) {
368 MEDIA_LOG_E("RegisterPlugin AddPlugin failed with return %" PUBLIC_LOG "d", static_cast<int>(ret));
369 }
370 return Status::OK;
371 }
372 }
__anon0c63c70a0402null373 PLUGIN_DEFINITION(MiniMP4Demuxer, LicenseType::CC0, RegisterPlugins, [] {});
374 } // namespace Minimp4
375 } // namespace Plugin
376 } // namespace Media
377 } // namespace OHOS