summaryrefslogtreecommitdiff
path: root/src/video/VideoDemuxerThread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/video/VideoDemuxerThread.cpp')
-rw-r--r--src/video/VideoDemuxerThread.cpp157
1 files changed, 157 insertions, 0 deletions
diff --git a/src/video/VideoDemuxerThread.cpp b/src/video/VideoDemuxerThread.cpp
new file mode 100644
index 0000000..370e237
--- /dev/null
+++ b/src/video/VideoDemuxerThread.cpp
@@ -0,0 +1,157 @@
+//
+// libavg - Media Playback Engine.
+// Copyright (C) 2003-2014 Ulrich von Zadow
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Current versions can be found at www.libavg.de
+//
+
+#include "VideoDemuxerThread.h"
+
+#include "../base/TimeSource.h"
+
+using namespace std;
+
+namespace avg {
+
+VideoDemuxerThread::VideoDemuxerThread(CQueue& cmdQ, AVFormatContext* pFormatContext,
+ const map<int, VideoMsgQueuePtr>& packetQs)
+ : WorkerThread<VideoDemuxerThread>("VideoDemuxer", cmdQ),
+ m_PacketQs(packetQs),
+ m_bEOF(false),
+ m_pFormatContext(pFormatContext),
+ m_pDemuxer()
+{
+ map<int, VideoMsgQueuePtr>::iterator it;
+ for (it = m_PacketQs.begin(); it != m_PacketQs.end(); it++) {
+ int streamIndex = it->first;
+ m_PacketQEOFMap[streamIndex] = false;
+ }
+}
+
+VideoDemuxerThread::~VideoDemuxerThread()
+{
+}
+
+bool VideoDemuxerThread::init()
+{
+ map<int, VideoMsgQueuePtr>::iterator it;
+ vector<int> streamIndexes;
+ for (it = m_PacketQs.begin(); it != m_PacketQs.end(); it++) {
+ streamIndexes.push_back(it->first);
+ }
+ m_pDemuxer = FFMpegDemuxerPtr(new FFMpegDemuxer(m_pFormatContext, streamIndexes));
+ return true;
+}
+
+bool VideoDemuxerThread::work()
+{
+ if (m_bEOF) {
+ waitForCommand();
+ } else {
+ map<int, VideoMsgQueuePtr>::iterator it;
+ int shortestQ = -1;
+ int shortestLength = INT_MAX;
+ for (it = m_PacketQs.begin(); it != m_PacketQs.end(); it++) {
+ if (it->second->size() < shortestLength &&
+ it->second->size() < it->second->getMaxSize() &&
+ !m_PacketQEOFMap[it->first])
+ {
+ shortestLength = it->second->size();
+ shortestQ = it->first;
+ }
+ }
+
+ if (shortestQ < 0) {
+ // All queues are at their max capacity. Take a nap and try again later.
+ // Note that we can't wait on the queue. If decoding is paused, the queues can
+ // remain full indefinitely and commands from the application (seek() and
+ // close() must still be processed.
+ msleep(10);
+ return true;
+ }
+
+ AVPacket * pPacket = m_pDemuxer->getPacket(shortestQ);
+ VideoMsgPtr pMsg(new VideoMsg);
+ if (pPacket == 0) {
+ onStreamEOF(shortestQ);
+ pMsg->setEOF();
+ } else {
+ pMsg->setPacket(pPacket);
+ }
+ m_PacketQs[shortestQ]->push(pMsg);
+ msleep(0);
+ }
+ return true;
+}
+
+void VideoDemuxerThread::seek(int seqNum, float destTime)
+{
+ map<int, VideoMsgQueuePtr>::iterator it;
+ m_pDemuxer->seek(destTime);
+ for (it = m_PacketQs.begin(); it != m_PacketQs.end(); it++) {
+ VideoMsgQueuePtr pPacketQ = it->second;
+ clearQueue(pPacketQ);
+
+ // send SEEK_DONE
+ VideoMsgPtr pMsg(new VideoMsg);
+ pMsg->setSeekDone(seqNum, destTime);
+ pPacketQ->push(pMsg);
+ m_PacketQEOFMap[it->first] = false;
+ }
+ m_bEOF = false;
+}
+
+void VideoDemuxerThread::close()
+{
+ map<int, VideoMsgQueuePtr>::iterator it;
+ for (it = m_PacketQs.begin(); it != m_PacketQs.end(); it++) {
+ VideoMsgQueuePtr pPacketQ = it->second;
+ clearQueue(pPacketQ);
+
+ VideoMsgPtr pMsg(new VideoMsg);
+ pMsg->setClosed();
+ pPacketQ->push(pMsg);
+ m_PacketQEOFMap[it->first] = false;
+ }
+ stop();
+}
+
+void VideoDemuxerThread::onStreamEOF(int streamIndex)
+{
+ m_PacketQEOFMap[streamIndex] = true;
+ m_bEOF = true;
+ map<int, bool>::iterator it;
+ for (it = m_PacketQEOFMap.begin(); it != m_PacketQEOFMap.end(); it++) {
+ if (!it->second) {
+ m_bEOF = false;
+ break;
+ }
+ }
+}
+
+void VideoDemuxerThread::clearQueue(VideoMsgQueuePtr pPacketQ)
+{
+ VideoMsgPtr pMsg;
+ do {
+ pMsg = pPacketQ->pop(false);
+ if (pMsg) {
+ pMsg->freePacket();
+ }
+ } while (pMsg);
+}
+
+}