1 /*
2 * Copyright (C) 2025 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 MEDIA_PLUGIN
17 #include <unistd.h>
18 #include <chrono>
19 #include "avcodec_trace.h"
20 #include "securec.h"
21 #include "ffmpeg_format_helper.h"
22 #include "ffmpeg_utils.h"
23 #include "buffer/avbuffer.h"
24 #include "plugin/plugin_buffer.h"
25 #include "plugin/plugin_definition.h"
26 #include "common/log.h"
27 #include "meta/video_types.h"
28 #include "demuxer_log_compressor.h"
29 #include "ffmpeg_demuxer_plugin.h"
30 #include "meta/format.h"
31 #include "syspara/parameters.h"
32
33 namespace {
34 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_DEMUXER, "FfmpegDemuxerThread" };
35 }
36
37 namespace OHOS {
38 namespace Media {
39 namespace Plugins {
40 namespace Ffmpeg {
41 const int32_t AV_READ_PACKET_READ_ERROR = -1;
42 const int32_t AV_READ_PACKET_READ_AGAIN = -2;
43 const int32_t AV_READ_PACKET_RETRY_UPPER_LIMIT = 9;
44 const int32_t AV_READ_PACKET_SLEEP_TIME = 50;
45
46 std::condition_variable FFmpegDemuxerPlugin::readCbCv_;
47 std::mutex FFmpegDemuxerPlugin::readPacketMutex_;
48
49 // Write packet data into the buffer provided by ffmpeg
AVReadPacket(void * opaque,uint8_t * buf,int bufSize)50 int FFmpegDemuxerPlugin::AVReadPacket(void* opaque, uint8_t* buf, int bufSize)
51 {
52 int ret = CheckContextIsValid(opaque, bufSize);
53 FALSE_RETURN_V(ret == 0, ret);
54 ret = -1;
55 auto ioContext = static_cast<IOContext*>(opaque);
56 FALSE_RETURN_V_MSG_E(ioContext != nullptr, ret, "IOContext is nullptr");
57 auto buffer = std::make_shared<Buffer>();
58 FALSE_RETURN_V_MSG_E(buffer != nullptr, ret, "Buffer is nullptr");
59 auto bufData = buffer->WrapMemory(buf, bufSize, 0);
60 FALSE_RETURN_V_MSG_E(buffer->GetMemory() != nullptr, ret, "Memory is nullptr");
61 MediaAVCodec::AVCodecTrace trace("AVReadPacket_ReadAt");
62 int tryCount = 0;
63 do {
64 auto result = ioContext->dataSource->ReadAt(ioContext->offset, buffer, static_cast<size_t>(bufSize));
65 int dataSize = static_cast<int>(buffer->GetMemory()->GetSize());
66 UpdateInitDownloadData(ioContext, dataSize);
67 MEDIA_LOG_D("Want:" PUBLIC_LOG_D32 ", Get:" PUBLIC_LOG_D32 ", offset:" PUBLIC_LOG_D64 ", index:" PUBLIC_LOG_D32,
68 bufSize, dataSize, ioContext->offset, readatIndex_.load());
69 #ifdef BUILD_ENG_VERSION
70 DumpParam dumpParam {DumpMode(DUMP_READAT_INPUT & ioContext->dumpMode), buf, -1, ioContext->offset,
71 dataSize, readatIndex_++, -1, -1};
72 Dump(dumpParam);
73 #endif
74 switch (result) {
75 case Status::OK:
76 ret = HandleReadOK(ioContext, dataSize);
77 break;
78 case Status::ERROR_AGAIN:
79 ret = HandleReadAgain(ioContext, dataSize, tryCount);
80 break;
81 case Status::END_OF_STREAM:
82 ret = HandleReadEOS(ioContext);
83 break;
84 default:
85 ret = HandleReadError(static_cast<int>(result));
86 break;
87 }
88 } while (ret == AV_READ_PACKET_READ_AGAIN);
89 return ret;
90 }
91
HandleReadOK(IOContext * ioContext,int dataSize)92 int FFmpegDemuxerPlugin::HandleReadOK(IOContext* ioContext, int dataSize)
93 {
94 if (dataSize > 0) {
95 ioContext->offset += dataSize;
96 return dataSize;
97 }
98 return AV_READ_PACKET_READ_ERROR;
99 }
100
HandleReadAgain(IOContext * ioContext,int dataSize,int & tryCount)101 int FFmpegDemuxerPlugin::HandleReadAgain(IOContext* ioContext, int dataSize, int& tryCount)
102 {
103 if (dataSize > 0) {
104 ioContext->offset += dataSize;
105 return dataSize;
106 }
107 if (ioContext->invokerType != InvokerType::READ) {
108 ioContext->retry = true;
109 ioContext->initErrorAgain = (ioContext->invokerType == InvokerType::INIT ? true : false);
110 MEDIA_LOG_I("Read again, invokerType!=READ, offset:" PUBLIC_LOG_D64, ioContext->offset);
111 return AV_READ_PACKET_READ_ERROR;
112 }
113 tryCount++;
114 if (tryCount >= AV_READ_PACKET_RETRY_UPPER_LIMIT) {
115 std::unique_lock<std::mutex> readLock(readPacketMutex_);
116 readCbCv_.wait(readLock, [ioContext]() {
117 return (ioContext->readCbReady) || (ioContext->invokerType != InvokerType::READ);
118 }); // Wait to be notified
119 ioContext->readCbReady = false; // Reset the flag
120 tryCount = 0;
121 } else {
122 MEDIA_LOG_I("Read again, retry count: " PUBLIC_LOG_D32 ", offset:" PUBLIC_LOG_D64, tryCount, ioContext->offset);
123 std::this_thread::sleep_for(std::chrono::milliseconds(AV_READ_PACKET_SLEEP_TIME));
124 }
125 return AV_READ_PACKET_READ_AGAIN;
126 }
127
HandleReadEOS(IOContext * ioContext)128 int FFmpegDemuxerPlugin::HandleReadEOS(IOContext* ioContext)
129 {
130 MEDIA_LOG_I("Read end");
131 ioContext->eos = true;
132 return AVERROR_EOF;
133 }
134
HandleReadError(int result)135 int FFmpegDemuxerPlugin::HandleReadError(int result)
136 {
137 MEDIA_LOG_I("Read failed " PUBLIC_LOG_D32, static_cast<int>(result));
138 return AV_READ_PACKET_READ_ERROR;
139 }
140
UpdateInitDownloadData(IOContext * ioContext,int dataSize)141 void FFmpegDemuxerPlugin::UpdateInitDownloadData(IOContext* ioContext, int dataSize)
142 {
143 if (!ioContext->initCompleted) {
144 if (ioContext->initDownloadDataSize <= UINT32_MAX - static_cast<uint32_t>(dataSize)) {
145 ioContext->initDownloadDataSize += static_cast<uint32_t>(dataSize);
146 } else {
147 MEDIA_LOG_W("DataSize " PUBLIC_LOG_U32 " is invalid", static_cast<uint32_t>(dataSize));
148 }
149 }
150 }
151
ReadSample(uint32_t trackId,std::shared_ptr<AVBuffer> sample,uint32_t timeout)152 Status FFmpegDemuxerPlugin::ReadSample(uint32_t trackId, std::shared_ptr<AVBuffer> sample, uint32_t timeout)
153 {
154 std::lock_guard<std::shared_mutex> lock(sharedMutex_);
155 Status ret;
156 MediaAVCodec::AVCodecTrace trace("ReadSample_timeout");
157 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_NULL_POINTER, "AVFormatContext is nullptr");
158 FALSE_RETURN_V_MSG_E(!selectedTrackIds_.empty(), Status::ERROR_INVALID_OPERATION, "No track has been selected");
159 FALSE_RETURN_V_MSG_E(TrackIsSelected(trackId), Status::ERROR_INVALID_PARAMETER, "Track has not been selected");
160 FALSE_RETURN_V_MSG_E(sample != nullptr && sample->memory_!=nullptr, Status::ERROR_INVALID_PARAMETER,
161 "AVBuffer or memory is nullptr");
162 FALSE_RETURN_V_MSG_E(readModeMap_.find(0) == readModeMap_.end(), Status::ERROR_INVALID_OPERATION,
163 "Cannot use sync and async Read together");
164 readModeMap_[1] = 1;
165 isPauseReadPacket_ = false;
166 if (ioContext_.invokerType != InvokerType::READ) {
167 std::lock_guard<std::mutex> readLock(ioContext_.invokerTypeMutex);
168 ioContext_.invokerType = InvokerType::READ;
169 }
170 trackId_ = trackId;
171 if (!cacheQueue_.HasCache(trackId) && timeout == 0) {
172 return Status::ERROR_WAIT_TIMEOUT;
173 }
174 if (!readThread_) {
175 readThread_ = std::make_unique<std::thread>(&FFmpegDemuxerPlugin::FFmpegReadLoop, this);
176 }
177 ret = WaitForLoop(trackId, timeout);
178 FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "Frame reading thread error, ret = " PUBLIC_LOG_D32, ret);
179
180 std::lock_guard<std::mutex> lockTrack(*trackMtx_[trackId].get());
181 auto samplePacket = cacheQueue_.Front(trackId);
182 FALSE_RETURN_V_MSG_E(samplePacket != nullptr, Status::ERROR_NULL_POINTER, "Cache packet is nullptr");
183
184 if (samplePacket->isEOS) {
185 ret = SetEosSample(sample);
186 if (ret == Status::OK) {
187 DumpPacketInfo(trackId, Stage::FILE_END);
188 cacheQueue_.Pop(trackId);
189 }
190 return ret;
191 }
192
193 ret = ConvertAVPacketToSample(sample, samplePacket);
194 DumpPacketInfo(trackId, Stage::FIRST_READ);
195 if (ret == Status::ERROR_NOT_ENOUGH_DATA) {
196 return Status::OK;
197 } else if (ret == Status::OK) {
198 MEDIA_LOG_D("All partial sample has been copied");
199 cacheQueue_.Pop(trackId);
200 }
201 return ret;
202 }
203
ShouldWaitForRead(uint32_t trackId)204 bool FFmpegDemuxerPlugin::ShouldWaitForRead(uint32_t trackId)
205 {
206 if ((NeedCombineFrame(trackId) && cacheQueue_.GetCacheSize(trackId) <= 1) ||
207 (!NeedCombineFrame(trackId) && !cacheQueue_.HasCache(trackId))) {
208 return true;
209 }
210 return false;
211 }
212
WaitForLoop(const uint32_t trackId,const uint32_t timeout)213 Status FFmpegDemuxerPlugin::WaitForLoop(const uint32_t trackId, const uint32_t timeout)
214 {
215 if (ShouldWaitForRead(trackId)) {
216 isWaitingForReadThread_.store(true);
217 if (threadState_ == READING) {
218 std::lock_guard<std::mutex> readLock(readPacketMutex_);
219 ioContext_.readCbReady = true;
220 readCbCv_.notify_one();
221 }
222 if (threadState_ == WAITING) {
223 std::lock_guard<std::mutex> readLock(ioContext_.invokerTypeMutex);
224 threadReady_ = true;
225 readLoopCv_.notify_one();
226 }
227 {
228 std::unique_lock<std::mutex> readLock(readSampleMutex_);
229 if (!readCacheCv_.wait_for(readLock, std::chrono::milliseconds(timeout),
230 [this, trackId] { return !ShouldWaitForRead(trackId);})) {
231 isWaitingForReadThread_.store(false);
232 FALSE_RETURN_V_MSG_E(readLoopStatus_ == Status::OK, readLoopStatus_, "read thread abnoraml end");
233 return Status::ERROR_WAIT_TIMEOUT;
234 }
235 }
236 }
237 isWaitingForReadThread_.store(false);
238 return Status::OK;
239 }
240
FFmpegReadLoop()241 void FFmpegDemuxerPlugin::FFmpegReadLoop()
242 {
243 if (isAsyncReadThreadPrioritySet_.load()) {
244 UpdateAsyncReadThreadPriority();
245 }
246 threadState_ = READING;
247 AVPacket *pkt = nullptr;
248 bool continueRead = true;
249 while (continueRead) {
250 if ((!NeedCombineFrame(trackId_) || cacheQueue_.GetCacheSize(trackId_) != 1) && NeedWaitForRead()) {
251 HandleReadWait();
252 }
253 {
254 std::lock_guard<std::mutex> readLock(readSampleMutex_);
255 readCacheCv_.notify_one();
256 }
257 if (ioContext_.invokerType == InvokerType::DESTORY) {
258 MEDIA_LOG_I("DESTORY trackId=" PUBLIC_LOG_D32, trackId_);
259 break;
260 }
261 if (!EnsurePacketAllocated(pkt)) {
262 break;
263 }
264 if (!ReadAndProcessFrame(pkt)) {
265 break;
266 }
267 pkt = nullptr;
268 }
269 {
270 std::lock_guard<std::mutex> readLock(readSampleMutex_);
271 readCacheCv_.notify_one();
272 }
273 {
274 std::lock_guard<std::mutex> seekWaitLock(seekWaitMutex_);
275 threadState_ = NOT_STARTED;
276 seekWaitCv_.notify_one();
277 }
278 MEDIA_LOG_I("Read loop end");
279 }
280
NeedWaitForRead()281 bool FFmpegDemuxerPlugin::NeedWaitForRead()
282 {
283 return (cacheQueue_.HasCache(trackId_) || isPauseReadPacket_) && ioContext_.invokerType != InvokerType::DESTORY;
284 }
285
HandleReadWait()286 void FFmpegDemuxerPlugin::HandleReadWait()
287 {
288 std::unique_lock<std::mutex> readLock(ioContext_.invokerTypeMutex);
289 {
290 std::unique_lock<std::mutex> seekWaitLock(seekWaitMutex_);
291 threadState_ = WAITING;
292 seekWaitCv_.notify_one();
293 }
294 readLoopCv_.wait(readLock, [this]() {
295 return (threadReady_) || (ioContext_.invokerType == InvokerType::DESTORY) ||
296 (!cacheQueue_.HasCache(trackId_) && !isPauseReadPacket_) ||
297 (isWaitingForReadThread_.load() && cacheQueue_.GetCacheSize(trackId_) <= 1);
298 });
299 threadState_ = READING;
300 threadReady_ = false;
301 }
302
EnsurePacketAllocated(AVPacket * & pkt)303 bool FFmpegDemuxerPlugin::EnsurePacketAllocated(AVPacket*& pkt)
304 {
305 if (pkt == nullptr) {
306 pkt = av_packet_alloc();
307 if (pkt == nullptr) {
308 MEDIA_LOG_E("Call av_packet_alloc failed");
309 readLoopStatus_ = Status::ERROR_NULL_POINTER;
310 return false;
311 }
312 }
313 return true;
314 }
315
ReadAndProcessFrame(AVPacket * pkt)316 bool FFmpegDemuxerPlugin::ReadAndProcessFrame(AVPacket* pkt)
317 {
318 {
319 std::unique_lock<std::mutex> sLock(syncMutex_);
320 readLoopStatus_ = Status::OK;
321 int ffmpegRet = AVReadFrameLimit(pkt);
322 if (ffmpegRet == AVERROR_EOF) {
323 HandleAVPacketEndOfStream(pkt);
324 return true;
325 }
326 if (ffmpegRet < 0) {
327 HandleAVPacketReadError(pkt, ffmpegRet);
328 return false;
329 }
330 }
331 auto trackId = pkt->stream_index;
332 if (!TrackIsSelected(trackId)) {
333 av_packet_unref(pkt);
334 return true;
335 }
336 AVStream* avStream = formatContext_->streams[trackId];
337 bool isWebVTT = IsWebvttMP4(avStream);
338 if (isWebVTT && WebvttPktProcess(pkt)) {
339 return true;
340 }
341 Status ret = AddPacketToCacheQueue(pkt);
342 if (ret != Status::OK) {
343 MEDIA_LOG_E("Add cache failed");
344 readLoopStatus_ = ret;
345 return false;
346 }
347 if (isWebVTT) {
348 AVPacket* vttePkt = nullptr;
349 if (!EnsurePacketAllocated(vttePkt)) {
350 readLoopStatus_ = Status::ERROR_NULL_POINTER;
351 return false;
352 }
353 if (!ReadOnePacketAndProcessWebVTT(vttePkt)) {
354 return false;
355 }
356 }
357 if (!NeedCombineFrame(trackId_) || cacheQueue_.GetCacheSize(trackId_) != 1) {
358 std::lock_guard<std::mutex> readLock(readSampleMutex_);
359 readCacheCv_.notify_one();
360 }
361 return true;
362 }
363
HandleAVPacketEndOfStream(AVPacket * pkt)364 void FFmpegDemuxerPlugin::HandleAVPacketEndOfStream(AVPacket* pkt)
365 {
366 WebvttMP4EOSProcess(pkt);
367 av_packet_free(&pkt);
368 Status ret = PushEOSToAllCache();
369 if (ret != Status::OK) {
370 readLoopStatus_ = ret;
371 return;
372 }
373 readLoopStatus_ = Status::END_OF_STREAM;
374 {
375 std::lock_guard<std::mutex> readLock(readSampleMutex_);
376 readCacheCv_.notify_one();
377 }
378 }
379
HandleAVPacketReadError(AVPacket * pkt,int ffmpegRet)380 void FFmpegDemuxerPlugin::HandleAVPacketReadError(AVPacket* pkt, int ffmpegRet)
381 {
382 FALSE_RETURN_MSG(pkt != nullptr, "AVPacket is nullptr");
383 av_packet_free(&pkt);
384 MEDIA_LOG_E("Call av_read_frame failed:" PUBLIC_LOG_S ", retry: " PUBLIC_LOG_D32,
385 AVStrError(ffmpegRet).c_str(), int(ioContext_.retry));
386 readLoopStatus_ = Status::ERROR_UNKNOWN;
387 }
388
ReadOnePacketAndProcessWebVTT(AVPacket * pkt)389 bool FFmpegDemuxerPlugin::ReadOnePacketAndProcessWebVTT(AVPacket* pkt)
390 {
391 std::unique_lock<std::mutex> sLock(syncMutex_);
392 readLoopStatus_ = Status::OK;
393 int ffmpegRet = AVReadFrameLimit(pkt);
394 if (ffmpegRet == AVERROR_EOF) {
395 HandleAVPacketEndOfStream(pkt);
396 return false;
397 }
398 if (ffmpegRet < 0) {
399 HandleAVPacketReadError(pkt, ffmpegRet);
400 return false;
401 }
402 if (WebvttPktProcess(pkt)) {
403 MEDIA_LOG_D("Webvtt packet processed successfully");
404 }
405 return true;
406 }
ReleaseFFmpegReadLoop()407 void FFmpegDemuxerPlugin::ReleaseFFmpegReadLoop()
408 {
409 if (ioContext_.invokerType != InvokerType::DESTORY) {
410 std::lock_guard<std::mutex> destoryLock(ioContext_.invokerTypeMutex);
411 ioContext_.invokerType = InvokerType::DESTORY;
412 readLoopCv_.notify_one();
413 }
414 std::unique_lock<std::mutex> readLock(readPacketMutex_);
415 ioContext_.readCbReady = true;
416 readCbCv_.notify_one();
417 readLock.unlock();
418 if (readThread_ != nullptr && readThread_->joinable()) {
419 readThread_->join();
420 }
421 readThread_ = nullptr;
422 readLoopStatus_ = Status::OK; // Reset readLoopStatus_ to OK after destroy
423 }
424
GetNextSampleSize(uint32_t trackId,int32_t & size,uint32_t timeout)425 Status FFmpegDemuxerPlugin::GetNextSampleSize(uint32_t trackId, int32_t& size, uint32_t timeout)
426 {
427 std::lock_guard<std::shared_mutex> lock(sharedMutex_);
428 MediaAVCodec::AVCodecTrace trace("GetNextSampleSize_timeout");
429 MEDIA_LOG_D("In, track " PUBLIC_LOG_D32, trackId);
430 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_UNKNOWN, "AVFormatContext is nullptr");
431 FALSE_RETURN_V_MSG_E(TrackIsSelected(trackId), Status::ERROR_UNKNOWN, "Track has not been selected");
432 FALSE_RETURN_V_MSG_E(readModeMap_.find(0) == readModeMap_.end(), Status::ERROR_INVALID_OPERATION,
433 "Cannot use sync and async Read together");
434 readModeMap_[1] = 1;
435 isPauseReadPacket_ = false;
436 if (ioContext_.invokerType != InvokerType::READ) {
437 std::lock_guard<std::mutex> readLock(ioContext_.invokerTypeMutex);
438 ioContext_.invokerType = InvokerType::READ;
439 }
440 trackId_ = trackId;
441 if (!cacheQueue_.HasCache(trackId) && timeout == 0) {
442 return Status::ERROR_WAIT_TIMEOUT;
443 }
444 if (!readThread_) {
445 readThread_ = std::make_unique<std::thread>(&FFmpegDemuxerPlugin::FFmpegReadLoop, this);
446 }
447
448 Status ret = WaitForLoop(trackId, timeout);
449 FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "Frame reading thread error, ret = " PUBLIC_LOG_D32, ret);
450
451 std::shared_ptr<SamplePacket> samplePacket = cacheQueue_.Front(trackId);
452 FALSE_RETURN_V_MSG_E(samplePacket != nullptr, Status::ERROR_UNKNOWN, "Cache sample is nullptr");
453 if (samplePacket->isEOS) {
454 MEDIA_LOG_I("Track " PUBLIC_LOG_D32 " eos", trackId);
455 return Status::END_OF_STREAM;
456 }
457 FALSE_RETURN_V_MSG_E(samplePacket->pkts.size() > 0, Status::ERROR_UNKNOWN, "Cache sample is empty");
458 int totalSize = 0;
459 for (auto pkt : samplePacket->pkts) {
460 FALSE_RETURN_V_MSG_E(pkt != nullptr, Status::ERROR_UNKNOWN, "Packet in sample is nullptr");
461 totalSize += pkt->size;
462 }
463
464 FALSE_RETURN_V_MSG_E(trackId < formatContext_->nb_streams, Status::ERROR_UNKNOWN, "Track is out of range");
465 AVStream* avStream = formatContext_->streams[trackId];
466 FALSE_RETURN_V_MSG_E(avStream != nullptr && avStream->codecpar != nullptr,
467 Status::ERROR_UNKNOWN, "AVStream is nullptr");
468 if ((std::count(g_streamContainedXPS.begin(), g_streamContainedXPS.end(), avStream->codecpar->codec_id) > 0) &&
469 static_cast<uint32_t>(samplePacket->pkts[0]->flags) & static_cast<uint32_t>(AV_PKT_FLAG_KEY)) {
470 totalSize += avStream->codecpar->extradata_size;
471 }
472 size = totalSize;
473 return Status::OK;
474 }
475
Pause()476 Status FFmpegDemuxerPlugin::Pause()
477 {
478 std::lock_guard<std::shared_mutex> lock(sharedMutex_);
479 isPauseReadPacket_ = true;
480 return Status::OK;
481 }
482
GetLastPTSByTrackId(uint32_t trackId,int64_t & lastPTS)483 Status FFmpegDemuxerPlugin::GetLastPTSByTrackId(uint32_t trackId, int64_t &lastPTS)
484 {
485 std::lock_guard<std::shared_mutex> lock(sharedMutex_);
486 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_NULL_POINTER, "AVFormatContext is nullptr");
487 FALSE_RETURN_V_MSG_E(!selectedTrackIds_.empty(), Status::ERROR_INVALID_OPERATION, "No track has been selected");
488 FALSE_RETURN_V_MSG_E(TrackIsSelected(trackId), Status::ERROR_INVALID_PARAMETER, "Track has not been selected");
489 lastPTS = INT64_MIN;
490 auto ret = cacheQueue_.GetLastPTSByTrackId(trackId, lastPTS);
491 if (ret != Status::OK) {
492 MEDIA_LOG_E("Get last pts failed");
493 }
494 return ret;
495 }
496
BoostReadThreadPriority()497 Status FFmpegDemuxerPlugin::BoostReadThreadPriority()
498 {
499 std::lock_guard<std::shared_mutex> lock(sharedMutex_);
500 if (threadState_ != ThreadState::NOT_STARTED && readThread_ != nullptr) {
501 MEDIA_LOG_W("Async read thread is running, cannot set priority now");
502 return Status::ERROR_WRONG_STATE;
503 }
504 if (isAsyncReadThreadPrioritySet_) {
505 MEDIA_LOG_W("Async read thread priority has been set, cannot set again");
506 return Status::ERROR_WRONG_STATE;
507 }
508 isAsyncReadThreadPrioritySet_.store(true);
509 MEDIA_LOG_I("Boost read thread priority to user interactive");
510 return Status::OK;
511 }
512
UpdateAsyncReadThreadPriority()513 void FFmpegDemuxerPlugin::UpdateAsyncReadThreadPriority()
514 {
515 auto ret = SetThreadQos(OHOS::QOS::QosLevel::QOS_USER_INTERACTIVE);
516 if (ret != 0) {
517 MEDIA_LOG_E("Set thread qos failed, ret = " PUBLIC_LOG_D32, ret);
518 } else {
519 MEDIA_LOG_I("Set thread qos success, level = " PUBLIC_LOG_U32, OHOS::QOS::QosLevel::QOS_USER_INTERACTIVE);
520 }
521 }
522 } // namespace Ffmpeg
523 } // namespace Plugins
524 } // namespace Media
525 } // namespace OHOS
526