@@ -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,75 @@ 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+ #if APIVERSNUM >= 30014
960+ /* *
961+ * Force a decoder drain and return true, if all buffers have been played out
962+ *
963+ * @return true, if the buffers are empty, false otherwise
964+ */
965+ bool cSoftHdDevice::Drain (void )
966+ {
967+ if (IsDetached ())
968+ return true ;
969+
970+ // enter drain mode once
971+ if (!m_draining) {
972+ LOGDEBUG (" device: %s: start draining" , __FUNCTION__);
973+ m_draining = true ;
974+ if (!m_videoReassemblyBuffer.IsEmpty ())
975+ m_pVideoStream->PushAvPacket (m_videoReassemblyBuffer.PopAvPacket ());
976+ m_pVideoStream->Drain ();
936977 }
937978
979+ const auto buffersEmpty = [&]() {
980+ return m_playbackMode == AUDIO_ONLY
981+ ? m_pAudio->IsBufferEmpty ()
982+ : m_pVideoStream->BuffersEmpty ();
983+ };
984+
985+ if (!buffersEmpty ())
986+ return false ;
987+
988+ LOGDEBUG (" device: %s: drained, buffers are empty" , __FUNCTION__);
989+ m_draining = false ;
990+
938991 return true ;
939992}
993+ #endif
940994
941995/* *
942996 * Sets the video display format
0 commit comments