• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024-2024 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 HST_LOG_TAG "SeekAgent"
17 
18 #include "seek_agent.h"
19 #include "common/log.h"
20 #include "meta/media_types.h"
21 #include "meta/meta.h"
22 
23 namespace {
24 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_PLAYER, "SeekAgent" };
25 }
26 
27 namespace OHOS {
28 namespace Media {
29 
AudioBufferFilledListener(std::shared_ptr<SeekAgent> seekAgent,sptr<AVBufferQueueProducer> producer,int32_t trackId)30 AudioBufferFilledListener::AudioBufferFilledListener(std::shared_ptr<SeekAgent> seekAgent,
31     sptr<AVBufferQueueProducer> producer, int32_t trackId)
32     : seekAgent_(seekAgent), producer_(producer), trackId_(trackId)
33 {
34     MEDIA_LOG_I("AudioBufferFilledListener ctor called.");
35 }
36 
OnBufferFilled(std::shared_ptr<AVBuffer> & buffer)37 void AudioBufferFilledListener::OnBufferFilled(std::shared_ptr<AVBuffer>& buffer)
38 {
39     if (auto agent = seekAgent_.lock()) {
40         agent->OnAudioBufferFilled(buffer, producer_, trackId_);
41     } else {
42         MEDIA_LOG_E("Invalid agent instance.");
43     }
44 }
45 
VideoBufferFilledListener(std::shared_ptr<SeekAgent> seekAgent,sptr<AVBufferQueueProducer> producer,int32_t trackId)46 VideoBufferFilledListener::VideoBufferFilledListener(std::shared_ptr<SeekAgent> seekAgent,
47     sptr<AVBufferQueueProducer> producer, int32_t trackId)
48     : seekAgent_(seekAgent), producer_(producer), trackId_(trackId)
49 {
50     MEDIA_LOG_I("VideoBufferFilledListener ctor called.");
51 }
52 
OnBufferFilled(std::shared_ptr<AVBuffer> & buffer)53 void VideoBufferFilledListener::OnBufferFilled(std::shared_ptr<AVBuffer>& buffer)
54 {
55     if (auto agent = seekAgent_.lock()) {
56         agent->OnVideoBufferFilled(buffer, producer_, trackId_);
57     } else {
58         MEDIA_LOG_E("Invalid agent instance.");
59     }
60 }
61 
SeekAgent(std::shared_ptr<Pipeline::DemuxerFilter> demuxer,int64_t startPts)62 SeekAgent::SeekAgent(std::shared_ptr<Pipeline::DemuxerFilter> demuxer, int64_t startPts)
63     : demuxer_(demuxer), isAudioTargetArrived_(true), isVideoTargetArrived_(true),
64     seekTargetPts_(-1), mediaStartPts_(startPts), isSeeking_(false)
65 {
66     MEDIA_LOG_I("SeekAgent ctor called.");
67 }
68 
~SeekAgent()69 SeekAgent::~SeekAgent()
70 {
71     MEDIA_LOG_I("~SeekAgent dtor called.");
72 }
73 
Seek(int64_t seekPos,bool & timeout)74 Status SeekAgent::Seek(int64_t seekPos, bool &timeout)
75 {
76     MEDIA_LOG_I("Seek start, seekPos: %{public}" PRId64, seekPos);
77     FALSE_RETURN_V_MSG_E(demuxer_ != nullptr, Status::ERROR_INVALID_PARAMETER, "Invalid demuxer filter instance.");
78     seekTargetPts_ = seekPos * MS_TO_US + mediaStartPts_;
79     int64_t realSeekTime = seekPos;
80     auto st = demuxer_->SeekTo(seekPos, Plugins::SeekMode::SEEK_CLOSEST_INNER, realSeekTime);
81     FALSE_RETURN_V_MSG_E(st == Status::OK, Status::ERROR_INVALID_OPERATION, "Seekto error.");
82 
83     isSeeking_ = true;
84     st = SetBufferFilledListener();
85     FALSE_RETURN_V_MSG_E(st == Status::OK, Status::ERROR_INVALID_OPERATION, "SetBufferFilledListener failed.");
86 
87     demuxer_->SetIsNotPrepareBeforeStart(true);
88     MEDIA_LOG_I("demuxer_ realSeekTime: %{public}" PRId64 "ns", realSeekTime);
89     demuxer_->PrepareBeforeStart();
90     bool isClosetSeekDone = true;
91     {
92         AutoLock lock(targetArrivedLock_);
93         demuxer_->ResumeForSeek();
94         MEDIA_LOG_I("ResumeForSeek end");
95         isClosetSeekDone = targetArrivedCond_.WaitFor(lock, WAIT_MAX_MS, [this] {
96             return (isAudioTargetArrived_ && (isVideoTargetArrived_ || demuxer_->IsVideoMuted())) || isInterruptNeeded_;
97         });
98         MEDIA_LOG_I("Wait end");
99     }
100     MEDIA_LOG_I("PauseForSeek start");
101     demuxer_->PauseForSeek();
102     st = RemoveBufferFilledListener();
103     // interrupt with error
104     if (isInterruptNeeded_) {
105         return Status::ERROR_INVALID_OPERATION;
106     }
107     if (!isClosetSeekDone) {
108         MEDIA_LOG_I("closet seek time out");
109         timeout = true;
110         demuxer_->Flush();
111         auto st = demuxer_->SeekTo(seekPos, Plugins::SeekMode::SEEK_CLOSEST_INNER, realSeekTime);
112         FALSE_RETURN_V_MSG_E(st == Status::OK, Status::ERROR_INVALID_OPERATION, "Seekto error.");
113     }
114     return st;
115 }
116 
GetAllTrackInfo(int32_t & videoTrackId,std::vector<int32_t> & audioTrackIds)117 Status SeekAgent::GetAllTrackInfo(int32_t &videoTrackId, std::vector<int32_t> &audioTrackIds)
118 {
119     auto trackInfo = demuxer_->GetStreamMetaInfo();
120     int32_t trackInfoSize = static_cast<int32_t>(trackInfo.size());
121     for (int32_t index = 0; index < trackInfoSize; index++) {
122         auto trackMeta = trackInfo[index];
123         std::string mimeType;
124         if (trackMeta->Get<Tag::MIME_TYPE>(mimeType) && mimeType.find("video") == 0) {
125             MEDIA_LOG_I("Find video trackId: " PUBLIC_LOG_U32 ", mimeType: " PUBLIC_LOG_S, index, mimeType.c_str());
126             videoTrackId = index;
127             continue;
128         }
129         if (trackMeta->Get<Tag::MIME_TYPE>(mimeType) && mimeType.find("audio") == 0) {
130             MEDIA_LOG_I("Find audio trackId: " PUBLIC_LOG_U32 ", mimeType: " PUBLIC_LOG_S, index, mimeType.c_str());
131             audioTrackIds.push_back(index);
132         }
133     }
134     return Status::OK;
135 }
136 
GetAudioTrackId(int32_t & audioTrackId)137 bool SeekAgent::GetAudioTrackId(int32_t &audioTrackId)
138 {
139     FALSE_RETURN_V_MSG_E(!producerMap_.empty(), false, "producerMap is empty.");
140     FALSE_RETURN_V_MSG_E(demuxer_ != nullptr, false, "Invalid demuxer filter instance.");
141     auto trackInfo = demuxer_->GetStreamMetaInfo();
142     FALSE_RETURN_V_MSG_E(!trackInfo.empty(), false, "track info is empty.");
143     int32_t trackInfoSize = static_cast<int32_t>(trackInfo.size());
144     for (int32_t index = 0; index < trackInfoSize; index++) {
145         auto trackMeta = trackInfo[index];
146         std::string mimeType;
147         if (!trackMeta->Get<Tag::MIME_TYPE>(mimeType) || mimeType.find("audio") != 0) {
148             continue;
149         }
150         if (producerMap_.find(index) != producerMap_.end() && producerMap_[index] != nullptr) {
151             audioTrackId = index;
152             return true;
153         }
154     }
155     return false;
156 }
157 
SetBufferFilledListener()158 Status SeekAgent::SetBufferFilledListener()
159 {
160     FALSE_RETURN_V_MSG_E(demuxer_ != nullptr, Status::ERROR_INVALID_PARAMETER, "Invalid demuxer filter instance.");
161     producerMap_ = demuxer_->GetBufferQueueProducerMap();
162     FALSE_RETURN_V_MSG_E(!producerMap_.empty(), Status::ERROR_INVALID_PARAMETER, "producerMap is empty.");
163 
164     int32_t videoTrackId = -1;
165     std::vector<int32_t> audioTrackIds;
166     GetAllTrackInfo(videoTrackId, audioTrackIds);
167 
168     auto it = producerMap_.begin();
169     while (it != producerMap_.end()) {
170         if (it->second == nullptr) {
171             it++;
172             continue;
173         }
174         if (std::find(audioTrackIds.begin(), audioTrackIds.end(), it->first) != audioTrackIds.end()) {
175             sptr<IBrokerListener> audioListener
176                 = new AudioBufferFilledListener(shared_from_this(), it->second, it->first);
177             {
178                 AutoLock lock(targetArrivedLock_);
179                 isAudioTargetArrived_ = false;
180             }
181             MEDIA_LOG_I("Add Listener audio id : %{public}d", it->first);
182             it->second->SetBufferFilledListener(audioListener);
183             listenerMap_.insert({it->first, audioListener});
184             it++;
185             continue;
186         }
187         if (it->first == videoTrackId) {
188             sptr<IBrokerListener> videoListener
189                 = new VideoBufferFilledListener(shared_from_this(), it->second, it->first);
190             {
191                 AutoLock lock(targetArrivedLock_);
192                 isVideoTargetArrived_ = false;
193             }
194             MEDIA_LOG_I("Add Listener video id : %{public}d", it->first);
195             it->second->SetBufferFilledListener(videoListener);
196             listenerMap_.insert({it->first, videoListener});
197         }
198         it++;
199     }
200     return Status::OK;
201 }
202 
RemoveBufferFilledListener()203 Status SeekAgent::RemoveBufferFilledListener()
204 {
205     auto it = listenerMap_.begin();
206     while (it != listenerMap_.end()) {
207         auto iterator = producerMap_.find(it->first);
208         if (iterator == producerMap_.end()) {
209             it++;
210             continue;
211         }
212         auto producer = iterator->second;
213         if (producer == nullptr) {
214             it++;
215             continue;
216         }
217         if (it->second == nullptr) {
218             it++;
219             continue;
220         }
221         producer->RemoveBufferFilledListener(it->second);
222         it++;
223     }
224     return Status::OK;
225 }
226 
OnAudioBufferFilled(std::shared_ptr<AVBuffer> & buffer,sptr<AVBufferQueueProducer> producer,int32_t trackId)227 Status SeekAgent::OnAudioBufferFilled(std::shared_ptr<AVBuffer>& buffer,
228     sptr<AVBufferQueueProducer> producer, int32_t trackId)
229 {
230     MEDIA_LOG_D("OnAudioBufferFilled, pts: %{public}" PRId64, buffer->pts_);
231     if (buffer->pts_ >= seekTargetPts_ || (buffer->flag_ & static_cast<uint32_t>(AVBufferFlag::EOS))) {
232         {
233             AutoLock lock(targetArrivedLock_);
234             isAudioTargetArrived_ = true;
235         }
236         MEDIA_LOG_I("audio arrive target pts = %{public}" PRId64, buffer->pts_);
237         FALSE_RETURN_V_MSG_E(demuxer_ != nullptr, Status::ERROR_NULL_POINTER, "demuxer_ is nullptr.");
238         demuxer_->PauseTaskByTrackId(trackId);
239         targetArrivedCond_.NotifyAll();
240 
241         producer->ReturnBuffer(buffer, false);
242         return Status::OK;
243     }
244     MEDIA_LOG_D("OnAudioBufferFilled, ReturnBuffer");
245     producer->ReturnBuffer(buffer, false);
246     return Status::OK;
247 }
248 
OnVideoBufferFilled(std::shared_ptr<AVBuffer> & buffer,sptr<AVBufferQueueProducer> producer,int32_t trackId)249 Status SeekAgent::OnVideoBufferFilled(std::shared_ptr<AVBuffer>& buffer,
250     sptr<AVBufferQueueProducer> producer, int32_t trackId)
251 {
252     MEDIA_LOG_I("OnVideoBufferFilled, pts: %{public}" PRId64, buffer->pts_);
253     if (buffer->pts_ >= seekTargetPts_ || (buffer->flag_ & static_cast<uint32_t>(AVBufferFlag::EOS))) {
254         {
255             AutoLock lock(targetArrivedLock_);
256             isVideoTargetArrived_ = true;
257         }
258         MEDIA_LOG_I("video arrive target");
259         FALSE_RETURN_V_MSG_E(demuxer_ != nullptr, Status::ERROR_NULL_POINTER, "demuxer_ is nullptr.");
260         demuxer_->PauseTaskByTrackId(trackId);
261         targetArrivedCond_.NotifyAll();
262         producer->ReturnBuffer(buffer, true);
263         return Status::OK;
264     }
265     bool canDrop = false;
266     buffer->meta_->GetData(Media::Tag::VIDEO_BUFFER_CAN_DROP, canDrop);
267     MEDIA_LOG_D("ReturnBuffer, pts: %{public}" PRId64 ", isPushBuffer: %{public}i", buffer->pts_, !canDrop);
268     producer->ReturnBuffer(buffer, !canDrop);
269     return Status::OK;
270 }
271 
AlignAudioPosition(int64_t audioPosition)272 Status SeekAgent::AlignAudioPosition(int64_t audioPosition)
273 {
274     MEDIA_LOG_I("AlignAudioPosition, audioPosition: %{public}" PRId64, audioPosition);
275     FALSE_RETURN_V_MSG_E(demuxer_ != nullptr, Status::OK, "Invalid demuxer filter instance.");
276     producerMap_ = demuxer_->GetBufferQueueProducerMap();
277     FALSE_RETURN_V_MSG_E(!producerMap_.empty(), Status::OK, "producerMap is empty.");
278     int32_t audioTrackId = 0;
279     FALSE_RETURN_V_MSG_E(GetAudioTrackId(audioTrackId), Status::OK, "audioTrackIds is empty.");
280     seekTargetPts_ = audioPosition * MS_TO_US;
281     sptr<IBrokerListener> audioListener
282         = new AudioBufferFilledListener(shared_from_this(), producerMap_[audioTrackId], audioTrackId);
283     {
284         AutoLock lock(targetArrivedLock_);
285         isAudioTargetArrived_ = false;
286     }
287     producerMap_[audioTrackId]->SetBufferFilledListener(audioListener);
288     listenerMap_.insert({audioTrackId, audioListener});
289     {
290         AutoLock lock(targetArrivedLock_);
291         demuxer_->ResumeAudioAlign();
292         targetArrivedCond_.WaitFor(lock, WAIT_MAX_MS, [this] {return isAudioTargetArrived_;});
293         MEDIA_LOG_I("Wait end");
294     }
295     MEDIA_LOG_I("PauseForSeek start");
296     auto ret = demuxer_->PauseAudioAlign();
297     RemoveBufferFilledListener();
298     return ret;
299 }
300 
OnInterrupted(bool isInterruptNeeded)301 void SeekAgent::OnInterrupted(bool isInterruptNeeded)
302 {
303     MEDIA_LOG_D("SeekAgent onInterrupted %{public}d", isInterruptNeeded);
304     isInterruptNeeded_ = isInterruptNeeded;
305     targetArrivedCond_.NotifyAll();
306 }
307 }  // namespace Media
308 }  // namespace OHOS
309