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     MEDIA_LOG_I("ResumeForSeek end");
91     bool isClosetSeekDone = true;
92     {
93         AutoLock lock(targetArrivedLock_);
94         demuxer_->ResumeForSeek();
95         isClosetSeekDone = targetArrivedCond_.WaitFor(lock, WAIT_MAX_MS,
96             [this] {return (isAudioTargetArrived_ && isVideoTargetArrived_) || isInterrputNeeded_;});
97         MEDIA_LOG_I("Wait end");
98     }
99     MEDIA_LOG_I("PauseForSeek start");
100     demuxer_->PauseForSeek();
101     st = RemoveBufferFilledListener();
102     // interrupt with error
103     if (isInterrputNeeded_) {
104         return Status::ERROR_INVALID_OPERATION;
105     }
106     if (!isClosetSeekDone) {
107         MEDIA_LOG_I("closet seek time out");
108         timeout = true;
109         demuxer_->Flush();
110         auto st = demuxer_->SeekTo(seekPos, Plugins::SeekMode::SEEK_CLOSEST_INNER, realSeekTime);
111         FALSE_RETURN_V_MSG_E(st == Status::OK, Status::ERROR_INVALID_OPERATION, "Seekto error.");
112     }
113     return st;
114 }
115 
GetAllTrackInfo(uint32_t & videoTrackId,std::vector<uint32_t> & audioTrackIds)116 Status SeekAgent::GetAllTrackInfo(uint32_t &videoTrackId, std::vector<uint32_t> &audioTrackIds)
117 {
118     auto trackInfo = demuxer_->GetStreamMetaInfo();
119     for (uint32_t index = 0; index < trackInfo.size(); index++) {
120         auto trackMeta = trackInfo[index];
121         std::string mimeType;
122         if (trackMeta->Get<Tag::MIME_TYPE>(mimeType) && mimeType.find("video") == 0) {
123             MEDIA_LOG_I("Find video trackId: " PUBLIC_LOG_U32 ", mimeType: " PUBLIC_LOG_S, index, mimeType.c_str());
124             videoTrackId = index;
125             continue;
126         }
127         if (trackMeta->Get<Tag::MIME_TYPE>(mimeType) && mimeType.find("audio") == 0) {
128             MEDIA_LOG_I("Find audio trackId: " PUBLIC_LOG_U32 ", mimeType: " PUBLIC_LOG_S, index, mimeType.c_str());
129             audioTrackIds.push_back(index);
130         }
131     }
132     return Status::OK;
133 }
134 
GetAudioTrackId(uint32_t & audioTrackId)135 bool SeekAgent::GetAudioTrackId(uint32_t &audioTrackId)
136 {
137     FALSE_RETURN_V_MSG_E(!producerMap_.empty(), false, "producerMap is empty.");
138     FALSE_RETURN_V_MSG_E(demuxer_ != nullptr, false, "Invalid demuxer filter instance.");
139     auto trackInfo = demuxer_->GetStreamMetaInfo();
140     FALSE_RETURN_V_MSG_E(!trackInfo.empty(), false, "track info is empty.");
141     for (uint32_t index = 0; index < trackInfo.size(); index++) {
142         auto trackMeta = trackInfo[index];
143         std::string mimeType;
144         if (!trackMeta->Get<Tag::MIME_TYPE>(mimeType) || mimeType.find("audio") != 0) {
145             continue;
146         }
147         if (producerMap_.find(index) != producerMap_.end() && producerMap_[index] != nullptr) {
148             audioTrackId = index;
149             return true;
150         }
151     }
152     return false;
153 }
154 
SetBufferFilledListener()155 Status SeekAgent::SetBufferFilledListener()
156 {
157     FALSE_RETURN_V_MSG_E(demuxer_ != nullptr, Status::ERROR_INVALID_PARAMETER, "Invalid demuxer filter instance.");
158     producerMap_ = demuxer_->GetBufferQueueProducerMap();
159     FALSE_RETURN_V_MSG_E(!producerMap_.empty(), Status::ERROR_INVALID_PARAMETER, "producerMap is empty.");
160 
161     uint32_t videoTrackId = -1;
162     std::vector<uint32_t> audioTrackIds;
163     GetAllTrackInfo(videoTrackId, audioTrackIds);
164 
165     auto it = producerMap_.begin();
166     while (it != producerMap_.end()) {
167         if (it->second == nullptr) {
168             it++;
169             continue;
170         }
171         if (std::find(audioTrackIds.begin(), audioTrackIds.end(), it->first) != audioTrackIds.end()) {
172             sptr<IBrokerListener> audioListener
173                 = new AudioBufferFilledListener(shared_from_this(), it->second, it->first);
174             {
175                 AutoLock lock(targetArrivedLock_);
176                 isAudioTargetArrived_ = false;
177             }
178             MEDIA_LOG_I("Add Listener audio id : %{public}d", it->first);
179             it->second->SetBufferFilledListener(audioListener);
180             listenerMap_.insert({it->first, audioListener});
181             it++;
182             continue;
183         }
184         if (it->first == videoTrackId) {
185             sptr<IBrokerListener> videoListener
186                 = new VideoBufferFilledListener(shared_from_this(), it->second, it->first);
187             {
188                 AutoLock lock(targetArrivedLock_);
189                 isVideoTargetArrived_ = false;
190             }
191             MEDIA_LOG_I("Add Listener video id : %{public}d", it->first);
192             it->second->SetBufferFilledListener(videoListener);
193             listenerMap_.insert({it->first, videoListener});
194         }
195         it++;
196     }
197     return Status::OK;
198 }
199 
RemoveBufferFilledListener()200 Status SeekAgent::RemoveBufferFilledListener()
201 {
202     auto it = listenerMap_.begin();
203     while (it != listenerMap_.end()) {
204         auto iterator = producerMap_.find(it->first);
205         if (iterator == producerMap_.end()) {
206             it++;
207             continue;
208         }
209         auto producer = iterator->second;
210         if (producer == nullptr) {
211             it++;
212             continue;
213         }
214         if (it->second == nullptr) {
215             it++;
216             continue;
217         }
218         producer->RemoveBufferFilledListener(it->second);
219         it++;
220     }
221     return Status::OK;
222 }
223 
OnAudioBufferFilled(std::shared_ptr<AVBuffer> & buffer,sptr<AVBufferQueueProducer> producer,int32_t trackId)224 Status SeekAgent::OnAudioBufferFilled(std::shared_ptr<AVBuffer>& buffer,
225     sptr<AVBufferQueueProducer> producer, int32_t trackId)
226 {
227     MEDIA_LOG_D("OnAudioBufferFilled, pts: %{public}" PRId64, buffer->pts_);
228     if (buffer->pts_ >= seekTargetPts_ || (buffer->flag_ & (uint32_t)(AVBufferFlag::EOS))) {
229         {
230             AutoLock lock(targetArrivedLock_);
231             isAudioTargetArrived_ = true;
232         }
233         MEDIA_LOG_I("audio arrive target pts = %{public}" PRId64, buffer->pts_);
234         FALSE_RETURN_V_MSG_E(demuxer_ != nullptr, Status::ERROR_NULL_POINTER, "demuxer_ is nullptr.");
235         demuxer_->PauseTaskByTrackId(trackId);
236         targetArrivedCond_.NotifyAll();
237 
238         producer->ReturnBuffer(buffer, false);
239         return Status::OK;
240     }
241     MEDIA_LOG_D("OnAudioBufferFilled, ReturnBuffer");
242     producer->ReturnBuffer(buffer, false);
243     return Status::OK;
244 }
245 
OnVideoBufferFilled(std::shared_ptr<AVBuffer> & buffer,sptr<AVBufferQueueProducer> producer,int32_t trackId)246 Status SeekAgent::OnVideoBufferFilled(std::shared_ptr<AVBuffer>& buffer,
247     sptr<AVBufferQueueProducer> producer, int32_t trackId)
248 {
249     MEDIA_LOG_I("OnVideoBufferFilled, pts: %{public}" PRId64, buffer->pts_);
250     if (buffer->pts_ >= seekTargetPts_ || (buffer->flag_ & (uint32_t)(AVBufferFlag::EOS))) {
251         {
252             AutoLock lock(targetArrivedLock_);
253             isVideoTargetArrived_ = true;
254         }
255         MEDIA_LOG_I("video arrive target");
256         FALSE_RETURN_V_MSG_E(demuxer_ != nullptr, Status::ERROR_NULL_POINTER, "demuxer_ is nullptr.");
257         demuxer_->PauseTaskByTrackId(trackId);
258         targetArrivedCond_.NotifyAll();
259         producer->ReturnBuffer(buffer, true);
260         return Status::OK;
261     }
262     bool canDrop = false;
263     buffer->meta_->GetData(Media::Tag::VIDEO_BUFFER_CAN_DROP, canDrop);
264     MEDIA_LOG_D("ReturnBuffer, pts: %{public}" PRId64 ", isPushBuffer: %{public}i", buffer->pts_, !canDrop);
265     producer->ReturnBuffer(buffer, !canDrop);
266     return Status::OK;
267 }
268 
AlignAudioPosition(int64_t audioPosition)269 Status SeekAgent::AlignAudioPosition(int64_t audioPosition)
270 {
271     MEDIA_LOG_I("AlignAudioPosition, audioPosition: %{public}" PRId64, audioPosition);
272     FALSE_RETURN_V_MSG_E(demuxer_ != nullptr, Status::OK, "Invalid demuxer filter instance.");
273     producerMap_ = demuxer_->GetBufferQueueProducerMap();
274     FALSE_RETURN_V_MSG_E(!producerMap_.empty(), Status::OK, "producerMap is empty.");
275     uint32_t audioTrackId = 0;
276     FALSE_RETURN_V_MSG_E(GetAudioTrackId(audioTrackId), Status::OK, "audioTrackIds is empty.");
277     seekTargetPts_ = audioPosition * MS_TO_US;
278     sptr<IBrokerListener> audioListener
279         = new AudioBufferFilledListener(shared_from_this(), producerMap_[audioTrackId], audioTrackId);
280     {
281         AutoLock lock(targetArrivedLock_);
282         isAudioTargetArrived_ = false;
283     }
284     producerMap_[audioTrackId]->SetBufferFilledListener(audioListener);
285     listenerMap_.insert({audioTrackId, audioListener});
286     {
287         AutoLock lock(targetArrivedLock_);
288         demuxer_->ResumeAudioAlign();
289         targetArrivedCond_.WaitFor(lock, WAIT_MAX_MS, [this] {return isAudioTargetArrived_;});
290         MEDIA_LOG_I("Wait end");
291     }
292     MEDIA_LOG_I("PauseForSeek start");
293     auto ret = demuxer_->PauseAudioAlign();
294     RemoveBufferFilledListener();
295     return ret;
296 }
297 
SetInterruptState(bool isNeed)298 void SeekAgent::SetInterruptState(bool isNeed)
299 {
300     isInterrputNeeded_ = isNeed;
301     targetArrivedCond_.NotifyAll();
302 }
303 }  // namespace Media
304 }  // namespace OHOS
305