diff options
Diffstat (limited to 'src/video/FFMpegDemuxer.cpp')
-rw-r--r-- | src/video/FFMpegDemuxer.cpp | 153 |
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; + } +} + +} |