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