• 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     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