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