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