1 /*
2 * Copyright (C) 2023 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 #include <fcntl.h>
17 #include <functional>
18 #include <cstdio>
19 #include "isoundpool.h"
20 #include "sound_parser.h"
21
22 namespace {
23 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_SOUNDPOOL, "SoundParser"};
24 static constexpr int32_t MAX_SOUND_BUFFER_SIZE = 1 * 1024 * 1024;
25 static const std::string AUDIO_RAW_MIMETYPE_INFO = "audio/raw";
26 static const std::string AUDIO_MPEG_MIMETYPE_INFO = "audio/mpeg";
27 }
28
29 namespace OHOS {
30 namespace Media {
SoundParser(int32_t soundID,std::string url)31 SoundParser::SoundParser(int32_t soundID, std::string url)
32 {
33 std::shared_ptr<MediaAVCodec::AVSource> source = MediaAVCodec::AVSourceFactory::CreateWithURI(url);
34 CHECK_AND_RETURN_LOG(source != nullptr, "Create AVSource failed");
35 std::shared_ptr<MediaAVCodec::AVDemuxer> demuxer = MediaAVCodec::AVDemuxerFactory::CreateWithSource(source);
36 CHECK_AND_RETURN_LOG(demuxer != nullptr, "Create AVDemuxer failed");
37 soundID_ = soundID;
38 demuxer_ = demuxer;
39 source_ = source;
40 }
41
SoundParser(int32_t soundID,int32_t fd,int64_t offset,int64_t length)42 SoundParser::SoundParser(int32_t soundID, int32_t fd, int64_t offset, int64_t length)
43 {
44 fdSource_ = fcntl(fd, F_DUPFD_CLOEXEC, MIN_FD); // dup(fd) + close on exec to prevent leaks.
45 offset = offset >= INT64_MAX ? INT64_MAX : offset;
46 length = length >= INT64_MAX ? INT64_MAX : length;
47 MEDIA_LOGI("SoundParser::SoundParser fd:%{public}d, fdSource_:%{public}d,", fd, fdSource_);
48 std::shared_ptr<MediaAVCodec::AVSource> source =
49 MediaAVCodec::AVSourceFactory::CreateWithFD(fdSource_, offset, length);
50 CHECK_AND_RETURN_LOG(source != nullptr, "Create AVSource failed");
51 std::shared_ptr<MediaAVCodec::AVDemuxer> demuxer = MediaAVCodec::AVDemuxerFactory::CreateWithSource(source);
52 CHECK_AND_RETURN_LOG(demuxer != nullptr, "Create AVDemuxer failed");
53
54 soundID_ = soundID;
55 demuxer_ = demuxer;
56 source_ = source;
57 }
58
~SoundParser()59 SoundParser::~SoundParser()
60 {
61 MEDIA_LOGI("SoundParser Destruction, soundID:%{public}d", soundID_);
62 Release();
63 }
64
DoParser()65 int32_t SoundParser::DoParser()
66 {
67 MediaTrace trace("SoundParser::DoParser");
68 MEDIA_LOGI("SoundParser::DoParser start, soundID:%{public}d", soundID_);
69 std::unique_lock<ffrt::mutex> lock(soundParserLock_);
70 isParsing_.store(true);
71 CHECK_AND_RETURN_RET_LOG(source_ != nullptr, MSERR_INVALID_VAL, "DoParser source_ is nullptr");
72 CHECK_AND_RETURN_RET_LOG(demuxer_ != nullptr, MSERR_INVALID_VAL, "DoParser demuxer_ is nullptr");
73 int32_t result = MSERR_OK;
74 result = DoDemuxer(&trackFormat_);
75 if (result != MSERR_OK && callback_ != nullptr) {
76 MEDIA_LOGI("DoDemuxer failed, call callback");
77 callback_->OnError(MSERR_UNSUPPORT_FILE);
78 return MSERR_INVALID_VAL;
79 } else if (result != MSERR_OK && callback_ == nullptr) {
80 MEDIA_LOGI("DoDemuxer failed, callback is nullptr");
81 return MSERR_INVALID_VAL;
82 }
83 result = DoDecode(trackFormat_);
84 if (result != MSERR_OK && callback_ != nullptr) {
85 MEDIA_LOGI("DoDecode failed, call callback");
86 callback_->OnError(MSERR_UNSUPPORT_FILE);
87 return MSERR_INVALID_VAL;
88 } else if (result != MSERR_OK && callback_ == nullptr) {
89 MEDIA_LOGI("DoDecode failed, callback is nullptr");
90 return MSERR_INVALID_VAL;
91 }
92 MEDIA_LOGI("SoundParser::DoParser end, soundID:%{public}d", soundID_);
93 return MSERR_OK;
94 }
95
DoDemuxer(MediaAVCodec::Format * trackFormat)96 int32_t SoundParser::DoDemuxer(MediaAVCodec::Format *trackFormat)
97 {
98 MediaTrace trace("SoundParser::DoDemuxer");
99 MEDIA_LOGI("SoundParser::DoDemuxer start, soundID:%{public}d", soundID_);
100 MediaAVCodec::Format sourceFormat;
101 int32_t sourceTrackCountInfo = 0;
102 int64_t sourceDurationInfo = 0;
103 CHECK_AND_RETURN_RET_LOG(source_ != nullptr, MSERR_INVALID_VAL, "Failed to obtain av source");
104 CHECK_AND_RETURN_RET_LOG(demuxer_ != nullptr, MSERR_INVALID_VAL, "Failed to obtain demuxer");
105 CHECK_AND_RETURN_RET_LOG(trackFormat != nullptr, MSERR_INVALID_VAL, "Invalid trackFormat.");
106 int32_t ret = source_->GetSourceFormat(sourceFormat);
107 if (ret != 0) {
108 MEDIA_LOGE("Get source format failed:%{public}d", ret);
109 }
110 sourceFormat.GetIntValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_TRACK_COUNT, sourceTrackCountInfo);
111 sourceFormat.GetLongValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_DURATION, sourceDurationInfo);
112
113 MEDIA_LOGI("SoundParser sourceTrackCountInfo:%{public}d", sourceTrackCountInfo);
114 for (int32_t sourceTrackIndex = 0; sourceTrackIndex < sourceTrackCountInfo; sourceTrackIndex++) {
115 int32_t trackType = 0;
116 ret = source_->GetTrackFormat(*trackFormat, sourceTrackIndex);
117 if (ret != 0) {
118 MEDIA_LOGE("Get track format failed:%{public}d", ret);
119 }
120 trackFormat->GetIntValue(MediaDescriptionKey::MD_KEY_TRACK_TYPE, trackType);
121 MEDIA_LOGI("SoundParser trackType:%{public}d", trackType);
122 if (trackType == MEDIA_TYPE_AUD) {
123 demuxer_->SelectTrackByID(sourceTrackIndex);
124 std::string trackMimeTypeInfo;
125 trackFormat->GetStringValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_CODEC_MIME, trackMimeTypeInfo);
126 if (AUDIO_RAW_MIMETYPE_INFO.compare(trackMimeTypeInfo) != 0) {
127 // resample format
128 trackFormat->PutIntValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT,
129 MediaAVCodec::SAMPLE_S16LE);
130 } else {
131 isRawFile_ = true;
132 trackFormat->PutStringValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_CODEC_MIME,
133 AUDIO_MPEG_MIMETYPE_INFO);
134 }
135 break;
136 }
137 }
138 MEDIA_LOGI("SoundParser::DoDemuxer end, soundID:%{public}d", soundID_);
139 return MSERR_OK;
140 }
141
DoDecode(MediaAVCodec::Format trackFormat)142 int32_t SoundParser::DoDecode(MediaAVCodec::Format trackFormat)
143 {
144 MediaTrace trace("SoundParser::DoDecode");
145 MEDIA_LOGI("SoundParser::DoDecode start, soundID:%{public}d", soundID_);
146 int32_t trackTypeInfo;
147 trackFormat.GetIntValue(MediaDescriptionKey::MD_KEY_TRACK_TYPE, trackTypeInfo);
148 if (trackTypeInfo == MEDIA_TYPE_AUD) {
149 std::string trackMimeTypeInfo;
150 trackFormat.GetStringValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_CODEC_MIME, trackMimeTypeInfo);
151 MEDIA_LOGI("SoundParser mime type:%{public}s", trackMimeTypeInfo.c_str());
152 audioDec_ = MediaAVCodec::AudioDecoderFactory::CreateByMime(trackMimeTypeInfo);
153 CHECK_AND_RETURN_RET_LOG(audioDec_ != nullptr, MSERR_INVALID_VAL, "Failed to obtain audioDecorder.");
154 int32_t ret = audioDec_->Configure(trackFormat);
155 CHECK_AND_RETURN_RET_LOG(ret == 0, MSERR_INVALID_VAL, "Failed to configure audioDecorder.");
156 audioDecCb_ = std::make_shared<SoundDecoderCallback>(soundID_, audioDec_, demuxer_, isRawFile_);
157 CHECK_AND_RETURN_RET_LOG(audioDecCb_ != nullptr, MSERR_INVALID_VAL, "Failed to obtain decode callback.");
158 ret = audioDec_->SetCallback(audioDecCb_);
159 CHECK_AND_RETURN_RET_LOG(ret == 0, MSERR_INVALID_VAL, "Failed to setCallback audioDecorder");
160 soundParserListener_ = std::make_shared<SoundParserListener>(weak_from_this());
161 CHECK_AND_RETURN_RET_LOG(soundParserListener_ != nullptr, MSERR_INVALID_VAL, "Invalid sound parser listener");
162 audioDecCb_->SetDecodeCallback(soundParserListener_);
163 if (callback_ != nullptr) audioDecCb_->SetCallback(callback_);
164 ret = audioDec_->Start();
165 CHECK_AND_RETURN_RET_LOG(ret == 0, MSERR_INVALID_VAL, "Failed to Start audioDecorder.");
166 MEDIA_LOGI("SoundParser::DoDecode, audioDec_ started, soundID:%{public}d", soundID_);
167 }
168 return MSERR_OK;
169 }
170
GetSoundData(std::deque<std::shared_ptr<AudioBufferEntry>> & soundData) const171 int32_t SoundParser::GetSoundData(std::deque<std::shared_ptr<AudioBufferEntry>> &soundData) const
172 {
173 CHECK_AND_RETURN_RET_LOG(soundParserListener_ != nullptr, MSERR_INVALID_VAL, "Invalid sound parser listener");
174 return soundParserListener_->GetSoundData(soundData);
175 }
176
GetSoundDataTotalSize() const177 size_t SoundParser::GetSoundDataTotalSize() const
178 {
179 CHECK_AND_RETURN_RET_LOG(soundParserListener_ != nullptr, 0, "Invalid sound parser listener");
180 return soundParserListener_->GetSoundDataTotalSize();
181 }
182
IsSoundParserCompleted() const183 bool SoundParser::IsSoundParserCompleted() const
184 {
185 CHECK_AND_RETURN_RET_LOG(soundParserListener_ != nullptr, false, "Invalid sound parser listener");
186 return soundParserListener_->IsSoundParserCompleted();
187 }
188
SetCallback(const std::shared_ptr<ISoundPoolCallback> & callback)189 int32_t SoundParser::SetCallback(const std::shared_ptr<ISoundPoolCallback> &callback)
190 {
191 callback_ = callback;
192 return MSERR_OK;
193 }
194
Release()195 int32_t SoundParser::Release()
196 {
197 MediaTrace trace("SoundParser::Release");
198 MEDIA_LOGI("SoundParser::Release start, soundID:%{public}d", soundID_);
199 std::unique_lock<ffrt::mutex> lock(soundParserLock_);
200 isParsing_.store(false);
201 int32_t ret = MSERR_OK;
202 if (soundParserListener_ != nullptr) soundParserListener_.reset();
203 if (audioDecCb_ != nullptr) {
204 ret = audioDecCb_->Release();
205 audioDecCb_.reset();
206 }
207 if (audioDec_ != nullptr) {
208 ret = audioDec_->Release();
209 audioDec_.reset();
210 }
211 if (demuxer_ != nullptr) demuxer_.reset();
212 if (source_ != nullptr) source_.reset();
213 if (callback_ != nullptr) callback_.reset();
214 if (fdSource_ > 0) {
215 MEDIA_LOGI("SoundParser::Release() fdSource_:%{public}d", fdSource_);
216 (void)close(fdSource_);
217 fdSource_ = -1;
218 }
219 MEDIA_LOGI("SoundParser::Release end, soundID:%{public}d", soundID_);
220 return ret;
221 }
222
SoundDecoderCallback(const int32_t soundID,const std::shared_ptr<MediaAVCodec::AVCodecAudioDecoder> & audioDec,const std::shared_ptr<MediaAVCodec::AVDemuxer> & demuxer,const bool isRawFile)223 SoundDecoderCallback::SoundDecoderCallback(const int32_t soundID,
224 const std::shared_ptr<MediaAVCodec::AVCodecAudioDecoder> &audioDec,
225 const std::shared_ptr<MediaAVCodec::AVDemuxer> &demuxer,
226 const bool isRawFile) : soundID_(soundID), audioDec_(audioDec),
227 demuxer_(demuxer), isRawFile_(isRawFile), eosFlag_(false),
228 decodeShouldCompleted_(false), currentSoundBufferSize_(0)
229 {
230 MEDIA_LOGI("Construction SoundDecoderCallback");
231 }
232
~SoundDecoderCallback()233 SoundDecoderCallback::~SoundDecoderCallback()
234 {
235 MEDIA_LOGI("Destruction SoundDecoderCallback");
236 Release();
237 }
OnError(AVCodecErrorType errorType,int32_t errorCode)238 void SoundDecoderCallback::OnError(AVCodecErrorType errorType, int32_t errorCode)
239 {
240 if (isRawFile_) {
241 MEDIA_LOGI("Recive error, errorType:%{public}d,errorCode:%{public}d", errorType, errorCode);
242 }
243 }
244
OnOutputFormatChanged(const Format & format)245 void SoundDecoderCallback::OnOutputFormatChanged(const Format &format)
246 {
247 (void)format;
248 }
249
OnInputBufferAvailable(uint32_t index,std::shared_ptr<AVSharedMemory> buffer)250 void SoundDecoderCallback::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVSharedMemory> buffer)
251 {
252 amutex_.lock();
253 MediaAVCodec::AVCodecBufferFlag bufferFlag = MediaAVCodec::AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_NONE;
254 MediaAVCodec::AVCodecBufferInfo sampleInfo;
255 if (demuxer_ == nullptr || audioDec_ == nullptr) {
256 MEDIA_LOGE("SoundDecoderCallback Input demuxer_:%{public}d, audioDec_:%{public}d,",
257 demuxer_ == nullptr, audioDec_ == nullptr);
258 amutex_.unlock();
259 return;
260 }
261
262 if (buffer != nullptr && isRawFile_ && !decodeShouldCompleted_) {
263 DealBufferRawFile(bufferFlag, sampleInfo, index, buffer);
264 amutex_.unlock();
265 return;
266 }
267
268 if (buffer != nullptr && !eosFlag_ && !decodeShouldCompleted_) {
269 if (demuxer_->ReadSample(0, buffer, sampleInfo, bufferFlag) != AVCS_ERR_OK) {
270 MEDIA_LOGE("SoundDecoderCallback demuxer error.");
271 amutex_.unlock();
272 return;
273 }
274 if (bufferFlag == AVCODEC_BUFFER_FLAG_EOS) {
275 eosFlag_ = true;
276 }
277 audioDec_->QueueInputBuffer(index, sampleInfo, bufferFlag);
278 }
279 amutex_.unlock();
280 }
281
DealBufferRawFile(MediaAVCodec::AVCodecBufferFlag bufferFlag,MediaAVCodec::AVCodecBufferInfo sampleInfo,uint32_t index,std::shared_ptr<AVSharedMemory> buffer)282 void SoundDecoderCallback::DealBufferRawFile(MediaAVCodec::AVCodecBufferFlag bufferFlag,
283 MediaAVCodec::AVCodecBufferInfo sampleInfo, uint32_t index, std::shared_ptr<AVSharedMemory> buffer)
284 {
285 if (demuxer_->ReadSample(0, buffer, sampleInfo, bufferFlag) != AVCS_ERR_OK) {
286 MEDIA_LOGE("SoundDecoderCallback demuxer error.");
287 return;
288 }
289 if (!decodeShouldCompleted_ && (currentSoundBufferSize_ > MAX_SOUND_BUFFER_SIZE ||
290 bufferFlag == AVCODEC_BUFFER_FLAG_EOS)) {
291 decodeShouldCompleted_ = true;
292 CHECK_AND_RETURN_LOG(listener_ != nullptr, "sound decode listener invalid.");
293 listener_->OnSoundDecodeCompleted(availableAudioBuffers_);
294 listener_->SetSoundBufferTotalSize(static_cast<size_t>(currentSoundBufferSize_));
295 CHECK_AND_RETURN_LOG(callback_ != nullptr, "sound decode:soundpool callback invalid.");
296 callback_->OnLoadCompleted(soundID_);
297 return;
298 }
299 int32_t size = sampleInfo.size;
300 uint8_t *buf = new(std::nothrow) uint8_t[size];
301 if (buf != nullptr) {
302 if (memcpy_s(buf, size, buffer->GetBase(), size) != EOK) {
303 delete[] buf;
304 MEDIA_LOGI("audio buffer copy failed:%{public}s", strerror(errno));
305 } else {
306 availableAudioBuffers_.push_back(std::make_shared<AudioBufferEntry>(buf, size));
307 bufferCond_.notify_all();
308 }
309 }
310 currentSoundBufferSize_ += size;
311 audioDec_->QueueInputBuffer(index, sampleInfo, bufferFlag);
312 return;
313 }
314
OnOutputBufferAvailable(uint32_t index,AVCodecBufferInfo info,AVCodecBufferFlag flag,std::shared_ptr<AVSharedMemory> buffer)315 void SoundDecoderCallback::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag,
316 std::shared_ptr<AVSharedMemory> buffer)
317 {
318 amutex_.lock();
319 if (demuxer_ == nullptr || audioDec_ == nullptr) {
320 MEDIA_LOGE("SoundDecoderCallback Output demuxer_:%{public}d, audioDec_:%{public}d,",
321 demuxer_ == nullptr, audioDec_ == nullptr);
322 amutex_.unlock();
323 return;
324 }
325 if (isRawFile_) {
326 audioDec_->ReleaseOutputBuffer(index);
327 amutex_.unlock();
328 return;
329 }
330 if (buffer != nullptr && !decodeShouldCompleted_) {
331 if (currentSoundBufferSize_ > MAX_SOUND_BUFFER_SIZE || flag == AVCODEC_BUFFER_FLAG_EOS) {
332 decodeShouldCompleted_ = true;
333 if (listener_ != nullptr) {
334 listener_->OnSoundDecodeCompleted(availableAudioBuffers_);
335 listener_->SetSoundBufferTotalSize(static_cast<size_t>(currentSoundBufferSize_));
336 }
337 if (callback_ != nullptr) {
338 callback_->OnLoadCompleted(soundID_);
339 }
340 amutex_.unlock();
341 return;
342 }
343 int32_t size = info.size;
344 uint8_t *buf = new(std::nothrow) uint8_t[size];
345 if (buf != nullptr) {
346 if (memcpy_s(buf, size, buffer->GetBase(), info.size) != EOK) {
347 delete[] buf;
348 MEDIA_LOGI("audio buffer copy failed:%{public}s", strerror(errno));
349 } else {
350 availableAudioBuffers_.push_back(std::make_shared<AudioBufferEntry>(buf, size));
351 bufferCond_.notify_all();
352 }
353 }
354 currentSoundBufferSize_ += size;
355 }
356 audioDec_->ReleaseOutputBuffer(index);
357 amutex_.unlock();
358 }
359
SetCallback(const std::shared_ptr<ISoundPoolCallback> & callback)360 int32_t SoundDecoderCallback::SetCallback(const std::shared_ptr<ISoundPoolCallback> &callback)
361 {
362 MEDIA_LOGI("SoundDecoderCallback::SetCallback");
363 callback_ = callback;
364 return MSERR_OK;
365 }
366
Release()367 int32_t SoundDecoderCallback::Release()
368 {
369 int32_t ret = MSERR_OK;
370 MEDIA_LOGI("SoundDecoderCallback::Release");
371 //here use audioDec, the reason is the same reason in CacheBuffer::Release().please check it
372 //in CacheBuffer::Release()
373 std::shared_ptr<MediaAVCodec::AVCodecAudioDecoder> audioDec;
374 {
375 std::lock_guard lock(amutex_);
376 audioDec = std::move(audioDec_);
377 audioDec_ = nullptr;
378 }
379 if (audioDec != nullptr) {
380 ret = audioDec->Release();
381 audioDec.reset();
382 audioDec = nullptr;
383 }
384 std::lock_guard lock(amutex_);
385 if (demuxer_ != nullptr) demuxer_.reset();
386 if (listener_ != nullptr) listener_.reset();
387 if (!availableAudioBuffers_.empty()) availableAudioBuffers_.clear();
388 if (callback_ != nullptr) callback_.reset();
389 return ret;
390 }
391 } // namespace Media
392 } // namespace OHOS
393