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