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