1 /*
2 * Copyright (c) 2022-2022 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 "WavDemuxerPlugin"
17
18 #include "wav_demuxer_plugin.h"
19
20 #include <algorithm>
21 #include <cstdio>
22 #include <cstring>
23 #include <new>
24 #include "foundation/log.h"
25 #include "osal/thread/scoped_lock.h"
26 #include "plugin/common/plugin_buffer.h"
27 #include "plugin/common/plugin_time.h"
28 #include "osal/utils/util.h"
29 #include "utils/constants.h"
30
31 namespace OHOS {
32 namespace Media {
33 namespace Plugin {
34 namespace WavPlugin {
35 namespace {
36 constexpr uint8_t MAX_RANK = 100;
37 constexpr uint8_t PROBE_READ_LENGTH = 4;
38 constexpr uint32_t WAV_PER_FRAME_SIZE = 8192;
39 constexpr uint32_t WAV_HEAD_INFO_LEN = sizeof(WavHeadAttr);
40 bool WavSniff(const uint8_t *inputBuf);
41 std::map<uint32_t, AudioSampleFormat> g_WavAudioSampleFormatPacked = {
42 {8, AudioSampleFormat::U8},
43 {16, AudioSampleFormat::S16},
44 {32, AudioSampleFormat::S32},
45 };
46
47 enum class WavAudioFormat {
48 WAVE_FORMAT_PCM = 0x0001,
49 WAVE_FORMAT_IEEE_FLOAT = 0x0003,
50 WAVE_FORMAT_ALAW = 0x0006,
51 WAVE_FORMAT_MULAW = 0x0007,
52 WAVE_FORMAT_EXTENSIBLE = 0xFFFE,
53 };
54 int Sniff(const std::string& pluginName, std::shared_ptr<DataSource> dataSource);
55 Status RegisterPlugin(const std::shared_ptr<Register>& reg);
56 }
57
WavDemuxerPlugin(std::string name)58 WavDemuxerPlugin::WavDemuxerPlugin(std::string name)
59 : DemuxerPlugin(std::move(name)),
60 fileSize_(0),
61 ioContext_(),
62 dataOffset_(0),
63 seekable_(Seekable::INVALID),
64 wavHeadLength_(0)
65 {
66 MEDIA_LOG_I("WavDemuxerPlugin, plugin name: " PUBLIC_LOG_S, pluginName_.c_str());
67 }
68
~WavDemuxerPlugin()69 WavDemuxerPlugin::~WavDemuxerPlugin()
70 {
71 MEDIA_LOG_I("~WavDemuxerPlugin");
72 }
73
SetDataSource(const std::shared_ptr<DataSource> & source)74 Status WavDemuxerPlugin::SetDataSource(const std::shared_ptr<DataSource>& source)
75 {
76 ioContext_.dataSource = source;
77 if (ioContext_.dataSource != nullptr) {
78 ioContext_.dataSource->GetSize(fileSize_);
79 }
80 MEDIA_LOG_I("fileSize_ " PUBLIC_LOG_ZU, fileSize_);
81 seekable_ = source->GetSeekable();
82 return Status::OK;
83 }
84
GetMediaInfo(MediaInfo & mediaInfo)85 Status WavDemuxerPlugin::GetMediaInfo(MediaInfo& mediaInfo)
86 {
87 auto buffer = std::make_shared<Buffer>();
88 buffer->WrapMemory((uint8_t*)&wavHeader_, sizeof(wavHeader_), 0);
89 Status status = ioContext_.dataSource->ReadAt(0, buffer, WAV_HEAD_INFO_LEN);
90 if (status != Status::OK) {
91 return status;
92 }
93 wavHeadLength_ = WAV_HEAD_INFO_LEN;
94 if (wavHeader_.audioFormat == static_cast<uint16_t>(WavAudioFormat::WAVE_FORMAT_PCM)) {
95 wavHeadLength_ -= 12; // 12 = subChunk2ID(optional)+subChunk2Size(optional)+dataFactSize(optional)
96 }
97 MEDIA_LOG_D("wavHeadLength_ " PUBLIC_LOG_U32, wavHeadLength_);
98 dataOffset_ = wavHeadLength_;
99 mediaInfo.tracks.resize(1);
100 if (wavHeader_.numChannels == 1) {
101 mediaInfo.tracks[0].Insert<Tag::AUDIO_CHANNEL_LAYOUT>(AudioChannelLayout::MONO);
102 } else {
103 mediaInfo.tracks[0].Insert<Tag::AUDIO_CHANNEL_LAYOUT>(AudioChannelLayout::STEREO);
104 }
105 int64_t duration = 0;
106 if (!Sec2HstTime((fileSize_ - wavHeadLength_) * 8 / // 8
107 (wavHeader_.sampleRate * wavHeader_.bitsPerSample * wavHeader_.numChannels), duration)) {
108 MEDIA_LOG_E("value overflow!");
109 }
110 mediaInfo.tracks[0].Insert<Tag::MEDIA_DURATION>(duration);
111 mediaInfo.tracks[0].Insert<Tag::MEDIA_TYPE>(MediaType::AUDIO);
112 mediaInfo.tracks[0].Insert<Tag::AUDIO_SAMPLE_RATE>(wavHeader_.sampleRate);
113 mediaInfo.tracks[0].Insert<Tag::MEDIA_BITRATE>((wavHeader_.byteRate) * 8); // 8 byte to bit
114 mediaInfo.tracks[0].Insert<Tag::AUDIO_CHANNELS>(wavHeader_.numChannels);
115 mediaInfo.tracks[0].Insert<Tag::TRACK_ID>(0);
116 mediaInfo.tracks[0].Insert<Tag::MIME>(MEDIA_MIME_AUDIO_RAW);
117 mediaInfo.tracks[0].Insert<Tag::AUDIO_MPEG_VERSION>(1);
118 mediaInfo.tracks[0].Insert<Tag::AUDIO_SAMPLE_PER_FRAME>(WAV_PER_FRAME_SIZE);
119 if (wavHeader_.audioFormat == static_cast<uint16_t>(WavAudioFormat::WAVE_FORMAT_PCM)
120 || wavHeader_.audioFormat == static_cast<uint16_t>(WavAudioFormat::WAVE_FORMAT_EXTENSIBLE)) {
121 mediaInfo.tracks[0].Insert<Tag::AUDIO_SAMPLE_FORMAT>
122 (g_WavAudioSampleFormatPacked[static_cast<uint32_t>(wavHeader_.bitsPerSample)]);
123 } else if (wavHeader_.audioFormat == static_cast<uint16_t>(WavAudioFormat::WAVE_FORMAT_IEEE_FLOAT)) {
124 mediaInfo.tracks[0].Insert<Tag::AUDIO_SAMPLE_FORMAT>(AudioSampleFormat::F32);
125 } else {
126 mediaInfo.tracks[0].Insert<Tag::AUDIO_SAMPLE_FORMAT>(AudioSampleFormat::NONE);
127 }
128 mediaInfo.tracks[0].Insert<Tag::BITS_PER_CODED_SAMPLE>(wavHeader_.bitsPerSample);
129 return Status::OK;
130 }
131
ReadFrame(Buffer & outBuffer,int32_t timeOutMs)132 Status WavDemuxerPlugin::ReadFrame(Buffer& outBuffer, int32_t timeOutMs)
133 {
134 std::shared_ptr<Buffer> outBufferPtr(&outBuffer, [](Buffer *) {});
135 if (outBuffer.IsEmpty()) {
136 outBuffer.AllocMemory(nullptr, WAV_PER_FRAME_SIZE);
137 }
138 Status retResult = ioContext_.dataSource->ReadAt(dataOffset_, outBufferPtr, WAV_PER_FRAME_SIZE);
139 dataOffset_ += outBuffer.GetMemory()->GetSize();
140 if (retResult != Status::OK) {
141 MEDIA_LOG_E("Read Data Error");
142 }
143 return retResult;
144 }
145
SeekTo(int32_t trackId,int64_t hstTime,SeekMode mode)146 Status WavDemuxerPlugin::SeekTo(int32_t trackId, int64_t hstTime, SeekMode mode)
147 {
148 if (fileSize_ <= 0 || seekable_ == Seekable::INVALID || seekable_ == Seekable::UNSEEKABLE) {
149 return Status::ERROR_INVALID_OPERATION;
150 }
151 auto blockAlign = wavHeader_.bitsPerSample / 8 * wavHeader_.numChannels; // blockAlign = wavHeader_.blockAlign
152 auto byteRate = blockAlign * wavHeader_.sampleRate; // byteRate = wavHeader_.byteRate
153
154 // time(sec) * byte per second= current time byte number
155 auto position = HstTime2Sec(hstTime) * byteRate;
156
157 // current time byte number / blockAlign
158 // To round and position to the starting point of a complete sample.
159 if (blockAlign) {
160 position = position / blockAlign * blockAlign;
161 }
162 dataOffset_ = position;
163 return Status::OK;
164 }
165
Reset()166 Status WavDemuxerPlugin::Reset()
167 {
168 dataOffset_ = 0;
169 fileSize_ = 0;
170 seekable_ = Seekable::SEEKABLE;
171 return Status::OK;
172 }
173
GetParameter(Tag tag,ValueType & value)174 Status WavDemuxerPlugin::GetParameter(Tag tag, ValueType &value)
175 {
176 return Status::ERROR_UNIMPLEMENTED;
177 }
178
SetParameter(Tag tag,const ValueType & value)179 Status WavDemuxerPlugin::SetParameter(Tag tag, const ValueType &value)
180 {
181 return Status::ERROR_UNIMPLEMENTED;
182 }
183
GetAllocator()184 std::shared_ptr<Allocator> WavDemuxerPlugin::GetAllocator()
185 {
186 return nullptr;
187 }
188
SetCallback(Callback * cb)189 Status WavDemuxerPlugin::SetCallback(Callback* cb)
190 {
191 return Status::OK;
192 }
193
GetTrackCount()194 size_t WavDemuxerPlugin::GetTrackCount()
195 {
196 return 0;
197 }
SelectTrack(int32_t trackId)198 Status WavDemuxerPlugin::SelectTrack(int32_t trackId)
199 {
200 return Status::OK;
201 }
UnselectTrack(int32_t trackId)202 Status WavDemuxerPlugin::UnselectTrack(int32_t trackId)
203 {
204 return Status::OK;
205 }
GetSelectedTracks(std::vector<int32_t> & trackIds)206 Status WavDemuxerPlugin::GetSelectedTracks(std::vector<int32_t>& trackIds)
207 {
208 return Status::OK;
209 }
210
211 namespace {
WavSniff(const uint8_t * inputBuf)212 bool WavSniff(const uint8_t *inputBuf)
213 {
214 // 解析数据起始位置的值,判断是否为wav格式文件
215 return ((inputBuf[0] != 'R') || (inputBuf[1] != 'I') || (inputBuf[2] != 'F') || (inputBuf[3] != 'F')); // 0 1 2 3
216 }
Sniff(const std::string & name,std::shared_ptr<DataSource> dataSource)217 int Sniff(const std::string& name, std::shared_ptr<DataSource> dataSource)
218 {
219 MEDIA_LOG_I("Sniff in");
220 Status status = Status::ERROR_UNKNOWN;
221 auto buffer = std::make_shared<Buffer>();
222 auto bufData = buffer->AllocMemory(nullptr, PROBE_READ_LENGTH);
223 status = dataSource->ReadAt(0, buffer, PROBE_READ_LENGTH);
224 if (status != Status::OK) {
225 MEDIA_LOG_E("Sniff Read Data Error");
226 return 0;
227 }
228 if (WavSniff(bufData->GetReadOnlyData())) {
229 return 0;
230 }
231 return MAX_RANK;
232 }
233
RegisterPlugin(const std::shared_ptr<Register> & reg)234 Status RegisterPlugin(const std::shared_ptr<Register>& reg)
235 {
236 MEDIA_LOG_I("RegisterPlugin called.");
237 if (!reg) {
238 MEDIA_LOG_I("RegisterPlugin failed due to nullptr pointer for reg.");
239 return Status::ERROR_INVALID_PARAMETER;
240 }
241
242 std::string pluginName = "WavDemuxerPlugin";
243 DemuxerPluginDef regInfo;
244 regInfo.name = pluginName;
245 regInfo.description = "adapter for wav demuxer plugin";
246 regInfo.rank = MAX_RANK;
247 regInfo.creator = [](const std::string &name) -> std::shared_ptr<DemuxerPlugin> {
248 return std::make_shared<WavDemuxerPlugin>(name);
249 };
250 regInfo.sniffer = Sniff;
251 auto rtv = reg->AddPlugin(regInfo);
252 if (rtv != Status::OK) {
253 MEDIA_LOG_I("RegisterPlugin AddPlugin failed with return " PUBLIC_LOG_D32, static_cast<int>(rtv));
254 }
255 return Status::OK;
256 }
257 }
258
__anonaadb2ae50502null259 PLUGIN_DEFINITION(WavDemuxer, LicenseType::APACHE_V2, RegisterPlugin, [] {});
260 } // namespace WavPlugin
261 } // namespace Plugin
262 } // namespace Media
263 } // namespace OHOS
264