summaryrefslogtreecommitdiff
path: root/src/video/FFMpegDemuxer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/video/FFMpegDemuxer.cpp')
-rw-r--r--src/video/FFMpegDemuxer.cpp153
1 files changed, 153 insertions, 0 deletions
diff --git a/src/video/FFMpegDemuxer.cpp b/src/video/FFMpegDemuxer.cpp
new file mode 100644
index 0000000..b092c7d
--- /dev/null
+++ b/src/video/FFMpegDemuxer.cpp
@@ -0,0 +1,153 @@
+//
+// 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 "FFMpegDemuxer.h"
+
+#include "../base/ScopeTimer.h"
+#include "../base/ObjectCounter.h"
+#include "../base/Exception.h"
+#include "../base/Logger.h"
+
+#include <cstring>
+#include <iostream>
+
+using namespace std;
+
+namespace avg {
+
+FFMpegDemuxer::FFMpegDemuxer(AVFormatContext * pFormatContext, vector<int> streamIndexes)
+ : m_pFormatContext(pFormatContext)
+{
+ ObjectCounter::get()->incRef(&typeid(*this));
+ for (unsigned i = 0; i < streamIndexes.size(); ++i) {
+ m_PacketLists[streamIndexes[i]] = PacketList();
+ }
+}
+
+FFMpegDemuxer::~FFMpegDemuxer()
+{
+ clearPacketCache();
+ ObjectCounter::get()->decRef(&typeid(*this));
+}
+
+AVPacket * FFMpegDemuxer::getPacket(int streamIndex)
+{
+ // Make sure enableStream was called on streamIndex.
+ AVG_ASSERT(m_PacketLists.size() > 0);
+ AVG_ASSERT(streamIndex > -1 && streamIndex < 10);
+
+ if (m_PacketLists.find(streamIndex) == m_PacketLists.end()) {
+ cerr << this << ": getPacket: Stream " << streamIndex << " not found." << endl;
+ dump();
+ AVG_ASSERT(false);
+ }
+
+ PacketList& curPacketList = m_PacketLists.find(streamIndex)->second;
+ AVPacket* pPacket;
+ if (!curPacketList.empty()) {
+ // The stream has packets queued already.
+ pPacket = curPacketList.front();
+ curPacketList.pop_front();
+ } else {
+ // No packets queued for this stream -> read and queue packets until we get one
+ // that is meant for this stream.
+ do {
+ pPacket = new AVPacket;
+ memset(pPacket, 0, sizeof(AVPacket));
+ int err = av_read_frame(m_pFormatContext, pPacket);
+ if (err < 0) {
+ // EOF or error
+#if LIBAVUTIL_VERSION_MAJOR > 50
+ if (err != int(AVERROR_EOF)) {
+ char sz[256];
+ av_strerror(err, sz, 256);
+ AVG_TRACE(Logger::category::PLAYER, Logger::severity::ERROR,
+ "Error decoding video: " << sz);
+ }
+#endif
+ av_free_packet(pPacket);
+ delete pPacket;
+ pPacket = 0;
+ return 0;
+ }
+ if (pPacket->stream_index != streamIndex) {
+ if (m_PacketLists.find(pPacket->stream_index) != m_PacketLists.end()) {
+ // Relevant stream, but not ours
+ av_dup_packet(pPacket);
+ PacketList& otherPacketList =
+ m_PacketLists.find(pPacket->stream_index)->second;
+ otherPacketList.push_back(pPacket);
+ } else {
+ // Disabled stream
+ av_free_packet(pPacket);
+ delete pPacket;
+ pPacket = 0;
+ }
+ } else {
+ // Our stream
+ av_dup_packet(pPacket);
+ }
+ } while (!pPacket || pPacket->stream_index != streamIndex);
+ }
+
+ return pPacket;
+}
+
+void FFMpegDemuxer::seek(float destTime)
+{
+#if LIBAVFORMAT_BUILD <= 4616
+ av_seek_frame(m_pFormatContext, -1, destTime*1000000);
+#else
+#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
+ av_seek_frame(m_pFormatContext, -1, destTime*1000000, 0);
+#else
+ av_seek_frame(m_pFormatContext, -1, (long long)(destTime*AV_TIME_BASE),
+ AVSEEK_FLAG_BACKWARD);
+#endif
+#endif
+ clearPacketCache();
+}
+
+void FFMpegDemuxer::clearPacketCache()
+{
+ map<int, PacketList>::iterator it;
+ for (it = m_PacketLists.begin(); it != m_PacketLists.end(); ++it) {
+ PacketList::iterator it2;
+ PacketList* pPacketList = &(it->second);
+ for (it2 = pPacketList->begin(); it2 != pPacketList->end(); ++it2) {
+ av_free_packet(*it2);
+ delete *it2;
+ }
+ pPacketList->clear();
+ }
+}
+
+void FFMpegDemuxer::dump()
+{
+ map<int, PacketList>::iterator it;
+ cerr << "FFMpegDemuxer " << this << endl;
+ cerr << "packetlists.size(): " << int(m_PacketLists.size()) << endl;
+ for (it = m_PacketLists.begin(); it != m_PacketLists.end(); ++it) {
+ cerr << " " << it->first << ": " << int(it->second.size()) << endl;
+ }
+}
+
+}