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