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