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