• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &reg);
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> &reg)
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