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