@@ -649,6 +649,8 @@ bool cSoftHdDevice::SetPlayMode(ePlayMode play_mode)
649649 m_externalPlayerActive = false ;
650650 }
651651
652+ m_draining = false ;
653+
652654 switch (play_mode) {
653655 case pmNone:
654656 OnEventReceived (StopEvent{});
@@ -810,6 +812,8 @@ void cSoftHdDevice::Clear(void)
810812 m_pAudio->ResetHwDelayBaseline ();
811813 FlushAudio ();
812814
815+ m_draining = false ;
816+
813817 SetState (BUFFERING );
814818
815819 m_pRender->Resume ();
@@ -888,7 +892,7 @@ void cSoftHdDevice::HandleStillPicture(const uchar *data, int size)
888892
889893 m_pVideoStream->PushAvPacket (m_videoReassemblyBuffer.PopAvPacket ());
890894 m_pVideoStream->ResetInputPts (); // stillpicture shouldn't trigger having video data
891- m_pVideoStream->Flush ();
895+ m_pVideoStream->Drain ();
892896}
893897
894898/* *
@@ -918,25 +922,76 @@ bool cSoftHdDevice::Poll(__attribute__ ((unused)) cPoller & poller, int timeoutM
918922}
919923
920924/* *
921- * Flush the device output buffers.
925+ * Return true, if the output buffers are empty, false otherwise.
926+ * Wait max. up to timeoutMs in case the buffers are not empty.
927+ *
928+ * This function does not initiate a decoder drain like Drain()
929+ * so some data may stay unprocessed in the decoder, while the other
930+ * buffers are already emtpy. Therefore, players should use the
931+ * new Drain() function instead.
922932 *
923933 * @param timeoutMs timeout in ms to become ready
934+ *
935+ * @return true, if the buffers are empty, false otherwise
936+ *
937+ * @note Flush() is marked DEPRECATED since APIVERSION 14
924938 */
925939bool cSoftHdDevice::Flush (int timeoutMs)
926940{
927941 if (IsDetached ())
928942 return true ;
929943
930- LOGDEBUG (" device: %s: timeout %d ms" , __FUNCTION__, timeoutMs);
931- if (m_pVideoStream->GetAvPacketsFilled ()) {
932- if (timeoutMs) { // let display thread work
933- usleep (timeoutMs * 1000 );
934- }
935- return !m_pVideoStream->GetAvPacketsFilled ();
944+ LOGDEBUG (" device: %s: timeout % ms" , __FUNCTION__, timeoutMs);
945+
946+ const auto buffersEmpty = [&]() {
947+ return m_playbackMode == AUDIO_ONLY
948+ ? m_pAudio->IsBufferEmpty ()
949+ : m_pVideoStream->BuffersEmpty ();
950+ };
951+
952+ const cTimeMs timeout (timeoutMs);
953+ while (!buffersEmpty () && !timeout.TimedOut ())
954+ cCondWait::SleepMs (std::min (5 , timeoutMs));
955+
956+ return buffersEmpty ();
957+ }
958+
959+
960+ #if APIVERSNUM >= 30014
961+ /* *
962+ * Force a decoder drain and return true, if all buffers have been played out
963+ *
964+ * @return true, if the buffers are empty, false otherwise
965+ */
966+ bool cSoftHdDevice::Drain (void )
967+ {
968+ if (IsDetached ())
969+ return true ;
970+
971+ // enter drain mode once
972+ if (!m_draining) {
973+ LOGDEBUG (" device: %s: start draining" , __FUNCTION__);
974+ m_draining = true ;
975+ if (!m_videoReassemblyBuffer.IsEmpty ())
976+ m_pVideoStream->PushAvPacket (m_videoReassemblyBuffer.PopAvPacket ());
977+ m_pVideoStream->Drain ();
936978 }
937979
980+ const auto buffersEmpty = [&]() {
981+ return m_playbackMode == AUDIO_ONLY
982+ ? m_pAudio->IsBufferEmpty ()
983+ : m_pVideoStream->BuffersEmpty ();
984+ };
985+
986+ if (!buffersEmpty ())
987+ return false ;
988+
989+ LOGDEBUG (" device: %s: drained, buffers are empty" , __FUNCTION__);
990+ m_draining = false ;
991+
938992 return true ;
939993}
994+ #endif
940995
941996/* *
942997 * Sets the video display format
0 commit comments