2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "DVDMessageQueue.h"
11 #include "cores/VideoPlayer/Interface/DemuxPacket.h"
12 #include "cores/VideoPlayer/Interface/TimingConstants.h"
13 #include "utils/log.h"
18 using namespace std::chrono_literals
;
20 CDVDMessageQueue::CDVDMessageQueue(const std::string
&owner
) : m_hEvent(true), m_owner(owner
)
23 m_bInitialized
= false;
25 m_TimeBack
= DVD_NOPTS_VALUE
;
26 m_TimeFront
= DVD_NOPTS_VALUE
;
27 m_TimeSize
= 1.0 / 4.0; /* 4 seconds */
31 CDVDMessageQueue::~CDVDMessageQueue()
33 // remove all remaining messages
37 void CDVDMessageQueue::Init()
40 m_bAbortRequest
= false;
41 m_bInitialized
= true;
42 m_TimeBack
= DVD_NOPTS_VALUE
;
43 m_TimeFront
= DVD_NOPTS_VALUE
;
47 void CDVDMessageQueue::Flush(CDVDMsg::Message type
)
49 std::unique_lock
<CCriticalSection
> lock(m_section
);
51 m_messages
.remove_if([type
](const DVDMessageListItem
&item
){
52 return type
== CDVDMsg::NONE
|| item
.message
->IsType(type
);
55 m_prioMessages
.remove_if([type
](const DVDMessageListItem
&item
){
56 return type
== CDVDMsg::NONE
|| item
.message
->IsType(type
);
59 if (type
== CDVDMsg::DEMUXER_PACKET
|| type
== CDVDMsg::NONE
)
62 m_TimeBack
= DVD_NOPTS_VALUE
;
63 m_TimeFront
= DVD_NOPTS_VALUE
;
67 void CDVDMessageQueue::Abort()
69 std::unique_lock
<CCriticalSection
> lock(m_section
);
71 m_bAbortRequest
= true;
73 // inform waiter for abort action
77 void CDVDMessageQueue::End()
79 std::unique_lock
<CCriticalSection
> lock(m_section
);
83 m_bInitialized
= false;
85 m_bAbortRequest
= false;
88 MsgQueueReturnCode
CDVDMessageQueue::Put(const std::shared_ptr
<CDVDMsg
>& pMsg
, int priority
)
90 return Put(pMsg
, priority
, true);
93 MsgQueueReturnCode
CDVDMessageQueue::PutBack(const std::shared_ptr
<CDVDMsg
>& pMsg
, int priority
)
95 return Put(pMsg
, priority
, false);
98 MsgQueueReturnCode
CDVDMessageQueue::Put(const std::shared_ptr
<CDVDMsg
>& pMsg
,
102 std::unique_lock
<CCriticalSection
> lock(m_section
);
106 CLog::Log(LOGWARNING
, "CDVDMessageQueue({})::Put MSGQ_NOT_INITIALIZED", m_owner
);
107 return MSGQ_NOT_INITIALIZED
;
111 CLog::Log(LOGFATAL
, "CDVDMessageQueue({})::Put MSGQ_INVALID_MSG", m_owner
);
112 return MSGQ_INVALID_MSG
;
121 auto it
= std::find_if(m_prioMessages
.begin(), m_prioMessages
.end(),
122 [prio
](const DVDMessageListItem
&item
){
123 return prio
<= item
.priority
;
125 m_prioMessages
.emplace(it
, pMsg
, priority
);
129 if (m_messages
.empty())
132 m_TimeBack
= DVD_NOPTS_VALUE
;
133 m_TimeFront
= DVD_NOPTS_VALUE
;
137 m_messages
.emplace_front(pMsg
, priority
);
139 m_messages
.emplace_back(pMsg
, priority
);
142 if (pMsg
->IsType(CDVDMsg::DEMUXER_PACKET
) && priority
== 0)
144 DemuxPacket
* packet
= static_cast<CDVDMsgDemuxerPacket
*>(pMsg
.get())->GetPacket();
147 m_iDataSize
+= packet
->iSize
;
155 // inform waiter for new packet
161 MsgQueueReturnCode
CDVDMessageQueue::Get(std::shared_ptr
<CDVDMsg
>& pMsg
,
162 std::chrono::milliseconds timeout
,
165 std::unique_lock
<CCriticalSection
> lock(m_section
);
171 CLog::Log(LOGFATAL
, "CDVDMessageQueue({})::Get MSGQ_NOT_INITIALIZED", m_owner
);
172 return MSGQ_NOT_INITIALIZED
;
175 while (!m_bAbortRequest
)
177 std::list
<DVDMessageListItem
> &msgs
= (priority
> 0 || !m_prioMessages
.empty()) ? m_prioMessages
: m_messages
;
179 if (!msgs
.empty() && (msgs
.back().priority
>= priority
|| m_drain
))
181 DVDMessageListItem
& item(msgs
.back());
182 priority
= item
.priority
;
184 if (item
.message
->IsType(CDVDMsg::DEMUXER_PACKET
) && item
.priority
== 0)
186 DemuxPacket
* packet
=
187 std::static_pointer_cast
<CDVDMsgDemuxerPacket
>(item
.message
)->GetPacket();
190 m_iDataSize
-= packet
->iSize
;
194 pMsg
= std::move(item
.message
);
200 else if (timeout
== 0ms
)
210 // wait for a new message
211 if (!m_hEvent
.Wait(timeout
))
221 return (MsgQueueReturnCode
)ret
;
224 void CDVDMessageQueue::UpdateTimeFront()
226 if (!m_messages
.empty())
228 auto &item
= m_messages
.front();
229 if (item
.message
->IsType(CDVDMsg::DEMUXER_PACKET
))
231 DemuxPacket
* packet
=
232 std::static_pointer_cast
<CDVDMsgDemuxerPacket
>(item
.message
)->GetPacket();
235 if (packet
->dts
!= DVD_NOPTS_VALUE
)
236 m_TimeFront
= packet
->dts
;
237 else if (packet
->pts
!= DVD_NOPTS_VALUE
)
238 m_TimeFront
= packet
->pts
;
240 if (m_TimeBack
== DVD_NOPTS_VALUE
)
241 m_TimeBack
= m_TimeFront
;
247 void CDVDMessageQueue::UpdateTimeBack()
249 if (!m_messages
.empty())
251 auto &item
= m_messages
.back();
252 if (item
.message
->IsType(CDVDMsg::DEMUXER_PACKET
))
254 DemuxPacket
* packet
=
255 std::static_pointer_cast
<CDVDMsgDemuxerPacket
>(item
.message
)->GetPacket();
258 if (packet
->dts
!= DVD_NOPTS_VALUE
)
259 m_TimeBack
= packet
->dts
;
260 else if (packet
->pts
!= DVD_NOPTS_VALUE
)
261 m_TimeBack
= packet
->pts
;
263 if (m_TimeFront
== DVD_NOPTS_VALUE
)
264 m_TimeFront
= m_TimeBack
;
270 unsigned CDVDMessageQueue::GetPacketCount(CDVDMsg::Message type
)
272 std::unique_lock
<CCriticalSection
> lock(m_section
);
278 for (const auto &item
: m_messages
)
280 if(item
.message
->IsType(type
))
283 for (const auto &item
: m_prioMessages
)
285 if(item
.message
->IsType(type
))
292 void CDVDMessageQueue::WaitUntilEmpty()
295 std::unique_lock
<CCriticalSection
> lock(m_section
);
299 CLog::Log(LOGINFO
, "CDVDMessageQueue({})::WaitUntilEmpty", m_owner
);
300 auto msg
= std::make_shared
<CDVDMsgGeneralSynchronize
>(40s
, SYNCSOURCE_ANY
);
302 msg
->Wait(m_bAbortRequest
, 0);
305 std::unique_lock
<CCriticalSection
> lock(m_section
);
310 int CDVDMessageQueue::GetLevel() const
312 std::unique_lock
<CCriticalSection
> lock(m_section
);
314 if (m_iDataSize
> m_iMaxDataSize
)
316 if (m_iDataSize
== 0)
321 return std::min(100, 100 * m_iDataSize
/ m_iMaxDataSize
);
324 int level
= std::min(100.0, ceil(100.0 * m_TimeSize
* (m_TimeFront
- m_TimeBack
) / DVD_TIME_BASE
));
326 // if we added lots of packets with NOPTS, make sure that the queue is not signalled empty
327 if (level
== 0 && m_iDataSize
!= 0)
329 CLog::Log(LOGDEBUG
, "CDVDMessageQueue::GetLevel() - can't determine level");
336 double CDVDMessageQueue::GetTimeSize() const
338 std::unique_lock
<CCriticalSection
> lock(m_section
);
343 return (m_TimeFront
- m_TimeBack
) / DVD_TIME_BASE
;
346 bool CDVDMessageQueue::IsDataBased() const
348 return (m_TimeBack
== DVD_NOPTS_VALUE
||
349 m_TimeFront
== DVD_NOPTS_VALUE
||
350 m_TimeFront
<= m_TimeBack
);