diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj index 22bb772e17a67..9273ba0eb1084 100644 --- a/project/VS2010Express/XBMC.vcxproj +++ b/project/VS2010Express/XBMC.vcxproj @@ -265,6 +265,7 @@ + @@ -950,6 +951,7 @@ + diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters index e642a0298ce25..8b0b01435bd39 100644 --- a/project/VS2010Express/XBMC.vcxproj.filters +++ b/project/VS2010Express/XBMC.vcxproj.filters @@ -3223,6 +3223,9 @@ filesystem\VideoDatabaseDirectory + + cores\VideoPlayer\DVDDemuxers + @@ -6245,6 +6248,9 @@ filesystem\VideoDatabaseDirectory + + cores\VideoPlayer\DVDDemuxers + diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp index 8ad42db5aa288..cff755ff365b7 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp @@ -192,6 +192,7 @@ CDVDDemuxFFmpeg::CDVDDemuxFFmpeg() : CDVDDemux() m_currentPts = DVD_NOPTS_VALUE; m_bMatroska = false; m_bAVI = false; + m_pSSIF = nullptr; m_speed = DVD_PLAYSPEED_NORMAL; m_program = UINT_MAX; m_pkt.result = -1; @@ -499,7 +500,7 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput, bool streaminfo, bool filein if (m_checkvideo) { // make sure we start video with an i-frame - //ResetVideoStreams(); + ResetVideoStreams(); } } else @@ -536,6 +537,8 @@ void CDVDDemuxFFmpeg::Dispose() m_pkt.result = -1; av_free_packet(&m_pkt.pkt); + SAFE_DELETE(m_pSSIF); + if (m_pFormatContext) { for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++) @@ -583,6 +586,9 @@ void CDVDDemuxFFmpeg::Flush() m_pkt.result = -1; av_free_packet(&m_pkt.pkt); + + if (m_pSSIF) + m_pSSIF->Flush(); } void CDVDDemuxFFmpeg::Abort() @@ -729,7 +735,9 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() { Flush(); } - else if (IsProgramChange()) + // libavformat is confused by the interleaved SSIF. + // Disable program management for those + else if (!m_pSSIF && IsProgramChange()) { // update streams CreateStreams(m_program); @@ -756,6 +764,9 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() m_pkt.result = -1; av_free_packet(&m_pkt.pkt); + + if (m_pSSIF) + m_pSSIF->Flush(); } else { @@ -765,7 +776,9 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() if (IsVideoReady()) { - if (m_program != UINT_MAX) + // libavformat is confused by the interleaved SSIF. + // Disable program management for those + if (!m_pSSIF && m_program != UINT_MAX ) { /* check so packet belongs to selected program */ for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++) @@ -906,6 +919,14 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() stream = AddStream(pPacket->iStreamId); } } + if (stream && m_pSSIF) + { + if (stream->type == STREAM_VIDEO || + stream->type == STREAM_DATA) + pPacket = m_pSSIF->AddPacket(pPacket); + if (stream->type == STREAM_DATA && pPacket->iSize) + stream = GetStreamInternal(pPacket->iStreamId); + } if (!stream) { CLog::Log(LOGERROR, "CDVDDemuxFFmpeg::AddStream - internal error, stream is null"); @@ -929,6 +950,9 @@ bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts) m_pkt.result = -1; av_free_packet(&m_pkt.pkt); + if (m_pSSIF) + m_pSSIF->Flush(); + CDVDInputStream::ISeekTime* ist = dynamic_cast(m_pInput); if (ist) { @@ -996,6 +1020,9 @@ bool CDVDDemuxFFmpeg::SeekByte(int64_t pos) m_pkt.result = -1; av_free_packet(&m_pkt.pkt); + if (m_pSSIF) + m_pSSIF->Flush(); + return (ret >= 0); } @@ -1184,11 +1211,13 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int iId) { if (pStream->codec->codec_id == AV_CODEC_ID_H264_MVC) { - // ignore MVC extension streams, they are handled specially + m_pSSIF = new CDVDDemuxStreamSSIF(); + m_pSSIF->SetMVCStreamId(iId); + stream = new CDemuxStream(); stream->type = STREAM_DATA; - stream->disabled = true; pStream->need_parsing = AVSTREAM_PARSE_NONE; + pStream->codec->codec_type = AVMEDIA_TYPE_DATA; break; } CDemuxStreamVideoFFmpeg* st = new CDemuxStreamVideoFFmpeg(this, pStream); @@ -1286,7 +1315,11 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int iId) { if (h264_is_annexb(m_pFormatContext->iformat->name, pStream)) { - // TODO + if (m_pSSIF) + { + m_pSSIF->SetH264StreamId(iId); + pStream->codec->codec_tag = MKTAG('M', 'V', 'C', ' '); + } } else { @@ -1402,7 +1435,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int iId) if (langTag) strncpy(stream->language, langTag->value, 3); - if( stream->type != STREAM_NONE && pStream->codec->extradata && pStream->codec->extradata_size > 0 ) + if (stream->type != STREAM_NONE && pStream->codec->extradata && pStream->codec->extradata_size > 0) { stream->ExtraSize = pStream->codec->extradata_size; stream->ExtraData = new uint8_t[pStream->codec->extradata_size]; @@ -1825,6 +1858,7 @@ void CDVDDemuxFFmpeg::ResetVideoStreams() if (st->codec->extradata) av_free(st->codec->extradata); st->codec->extradata = NULL; + st->codec->extradata_size = 0; st->codec->width = 0; } } diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.h index 7ab4bbac7e542..4360f61e37d54 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.h +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.h @@ -21,6 +21,7 @@ */ #include "DVDDemux.h" +#include "DVDDemuxStreamSSIF.h" #include "threads/CriticalSection.h" #include "threads/SystemClock.h" #include @@ -156,6 +157,7 @@ class CDVDDemuxFFmpeg : public CDVDDemux double m_currentPts; // used for stream length estimation bool m_bMatroska; bool m_bAVI; + CDVDDemuxStreamSSIF* m_pSSIF; int m_speed; unsigned m_program; XbmcThreads::EndTime m_timeout; diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxStreamSSIF.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxStreamSSIF.cpp new file mode 100644 index 0000000000000..01952bfbc8239 --- /dev/null +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxStreamSSIF.cpp @@ -0,0 +1,166 @@ +/* +* Copyright (C) 2005-2013 Team XBMC +* http://xbmc.org +* +* This Program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This Program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with XBMC; see the file COPYING. If not, see +* . +* +*/ + +#include "DVDDemuxStreamSSIF.h" +#include "DVDClock.h" +#include "DVDDemuxUtils.h" +#include "utils/log.h" + +//#define DEBUG_VERBOSE + +DemuxPacket* CDVDDemuxStreamSSIF::AddPacket(DemuxPacket* &srcPkt) +{ + if (srcPkt->iStreamId != m_h264StreamId && + srcPkt->iStreamId != m_mvcStreamId) + return srcPkt; + + DemuxPacket* newpkt = NULL; + newpkt = CDVDDemuxUtils::AllocateDemuxPacket(srcPkt->iSize); + newpkt->iSize = srcPkt->iSize; + + newpkt->pts = srcPkt->pts; + newpkt->dts = srcPkt->dts; + newpkt->duration = srcPkt->duration; + newpkt->iGroupId = srcPkt->iGroupId; + newpkt->iStreamId = srcPkt->iStreamId; + memcpy(newpkt->pData, srcPkt->pData, srcPkt->iSize); + + CDVDDemuxUtils::FreeDemuxPacket(srcPkt); + srcPkt = NULL; + + if (newpkt->iStreamId == m_h264StreamId) + m_H264queue.push(newpkt); + else if (newpkt->iStreamId == m_mvcStreamId) + m_MVCqueue.push(newpkt); + + return GetMVCPacket(); +} + +void CDVDDemuxStreamSSIF::Flush() +{ + while (!m_H264queue.empty()) + { + CDVDDemuxUtils::FreeDemuxPacket(m_H264queue.front()); + m_H264queue.pop(); + } + while (!m_MVCqueue.empty()) + { + CDVDDemuxUtils::FreeDemuxPacket(m_MVCqueue.front()); + m_MVCqueue.pop(); + } +} + +DemuxPacket* CDVDDemuxStreamSSIF::MergePacket(DemuxPacket* &srcPkt, DemuxPacket* &appendPkt) +{ + DemuxPacket* newpkt = NULL; + newpkt = CDVDDemuxUtils::AllocateDemuxPacket(srcPkt->iSize + appendPkt->iSize); + newpkt->iSize = srcPkt->iSize + appendPkt->iSize; + + newpkt->pts = srcPkt->pts; + newpkt->dts = srcPkt->dts; + newpkt->duration = srcPkt->duration; + newpkt->iGroupId = srcPkt->iGroupId; + newpkt->iStreamId = srcPkt->iStreamId; + memcpy(newpkt->pData, srcPkt->pData, srcPkt->iSize); + memcpy(newpkt->pData + srcPkt->iSize, appendPkt->pData, appendPkt->iSize); + + CDVDDemuxUtils::FreeDemuxPacket(srcPkt); + srcPkt = NULL; + CDVDDemuxUtils::FreeDemuxPacket(appendPkt); + appendPkt = NULL; + + return newpkt; +} + +DemuxPacket* CDVDDemuxStreamSSIF::GetMVCPacket() +{ + // Here, we recreate a h264 MVC packet from the base one + buffered MVC NALU's + while (!m_H264queue.empty() && !m_MVCqueue.empty()) + { + DemuxPacket* h264pkt = m_H264queue.front(); + double tsH264 = (h264pkt->dts != DVD_NOPTS_VALUE ? h264pkt->dts : h264pkt->pts); + DemuxPacket* mvcpkt = m_MVCqueue.front(); + double tsMVC = (mvcpkt->dts != DVD_NOPTS_VALUE ? mvcpkt->dts : mvcpkt->pts); + + if (tsH264 == tsMVC) + { + m_H264queue.pop(); + m_MVCqueue.pop(); + + while (!m_H264queue.empty()) + { + DemuxPacket* pkt = m_H264queue.front(); + double ts = (pkt->dts != DVD_NOPTS_VALUE ? pkt->dts : pkt->pts); + if (ts == DVD_NOPTS_VALUE) + { +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, ">>> MVC merge h264 fragment: %6d+%6d, pts(%.3f/%.3f) dts(%.3f/%.3f)", h264pkt->iSize, pkt->iSize, h264pkt->pts*1e-6, pkt->pts*1e-6, h264pkt->dts*1e-6, pkt->dts*1e-6); +#endif + h264pkt = MergePacket(h264pkt, pkt); + m_H264queue.pop(); + } + else + break; + } + while (!m_MVCqueue.empty()) + { + DemuxPacket* pkt = m_MVCqueue.front(); + double ts = (pkt->dts != DVD_NOPTS_VALUE ? pkt->dts : pkt->pts); + if (ts == DVD_NOPTS_VALUE) + { +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, ">>> MVC merge mvc fragment: %6d+%6d, pts(%.3f/%.3f) dts(%.3f/%.3f)", mvcpkt->iSize, pkt->iSize, mvcpkt->pts*1e-6, pkt->pts*1e-6, mvcpkt->dts*1e-6, pkt->dts*1e-6); +#endif + mvcpkt = MergePacket(mvcpkt, pkt); + m_MVCqueue.pop(); + } + else + break; + } + +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, ">>> MVC merge packet: %6d+%6d, pts(%.3f/%.3f) dts(%.3f/%.3f)", h264pkt->iSize, mvcpkt->iSize, h264pkt->pts*1e-6, mvcpkt->pts*1e-6, h264pkt->dts*1e-6, mvcpkt->dts*1e-6); +#endif + return MergePacket(h264pkt, mvcpkt); + } + else if (tsH264 > tsMVC) + { +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, ">>> MVC discard mvc: %6d, pts(%.3f) dts(%.3f)", mvcpkt->iSize, mvcpkt->pts*1e-6, mvcpkt->dts*1e-6); +#endif + CDVDDemuxUtils::FreeDemuxPacket(mvcpkt); + m_MVCqueue.pop(); + } + else + { +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, ">>> MVC discard h264: %6d, pts(%.3f) dts(%.3f)", h264pkt->iSize, h264pkt->pts*1e-6, h264pkt->dts*1e-6); +#endif + CDVDDemuxUtils::FreeDemuxPacket(h264pkt); + m_H264queue.pop(); + } + } + +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, ">>> MVC waiting. MVC(%d) H264(%d)", m_MVCqueue.size(), m_H264queue.size()); +#endif + + return CDVDDemuxUtils::AllocateDemuxPacket(0); +} \ No newline at end of file diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxStreamSSIF.h b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxStreamSSIF.h new file mode 100644 index 0000000000000..8412627a3ea13 --- /dev/null +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxStreamSSIF.h @@ -0,0 +1,49 @@ +#pragma once + +/* +* Copyright (C) 2005-2013 Team XBMC +* http://xbmc.org +* +* This Program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This Program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with XBMC; see the file COPYING. If not, see +* . +* +*/ + +#include "DVDDemuxPacket.h" +#include + +extern "C" { +#include "libavformat/avformat.h" +} + +class CDVDDemuxStreamSSIF +{ +public: + CDVDDemuxStreamSSIF() {}; + ~CDVDDemuxStreamSSIF() { Flush(); } + + DemuxPacket* AddPacket(DemuxPacket* &scrPkt); + void Flush(); + void SetH264StreamId(int id) { m_h264StreamId = id; }; + void SetMVCStreamId(int id) { m_mvcStreamId = id; }; + +private: + DemuxPacket* GetMVCPacket(); + DemuxPacket* MergePacket(DemuxPacket* &srcPkt, DemuxPacket* &appendPkt); + + std::queue m_H264queue; + std::queue m_MVCqueue; + int m_h264StreamId = 0; + int m_mvcStreamId = 0; +}; diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/Makefile.in b/xbmc/cores/VideoPlayer/DVDDemuxers/Makefile.in index 94ad153db55d0..874662d45559e 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/Makefile.in +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/Makefile.in @@ -9,6 +9,7 @@ SRCS += DVDDemuxUtils.cpp SRCS += DVDDemuxVobsub.cpp SRCS += DVDDemuxCC.cpp SRCS += DVDFactoryDemuxer.cpp +SRCS += DVDDemuxStreamSSIF.cpp LIB = DVDDemuxers.a diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp index dde10e1eb9a2c..4e6596e35d28d 100644 --- a/xbmc/settings/AdvancedSettings.cpp +++ b/xbmc/settings/AdvancedSettings.cpp @@ -399,7 +399,7 @@ void CAdvancedSettings::Initialize() m_pictureExtensions = ".png|.jpg|.jpeg|.bmp|.gif|.ico|.tif|.tiff|.tga|.pcx|.cbz|.zip|.cbr|.rar|.dng|.nef|.cr2|.crw|.orf|.arw|.erf|.3fr|.dcr|.x3f|.mef|.raf|.mrw|.pef|.sr2|.rss|.webp|.jp2"; m_musicExtensions = ".nsv|.m4a|.flac|.aac|.strm|.pls|.rm|.rma|.mpa|.wav|.wma|.ogg|.mp3|.mp2|.m3u|.gdm|.imf|.m15|.sfx|.uni|.ac3|.dts|.cue|.aif|.aiff|.wpl|.ape|.mac|.mpc|.mp+|.mpp|.shn|.zip|.rar|.wv|.dsp|.xsp|.xwav|.waa|.wvs|.wam|.gcm|.idsp|.mpdsp|.mss|.spt|.rsd|.sap|.cmc|.cmr|.dmc|.mpt|.mpd|.rmt|.tmc|.tm8|.tm2|.oga|.url|.pxml|.tta|.rss|.wtv|.mka|.tak|.opus|.dff|.dsf"; - m_videoExtensions = ".m4v|.3g2|.3gp|.nsv|.tp|.ts|.ty|.strm|.pls|.rm|.rmvb|.m3u|.m3u8|.ifo|.mov|.qt|.divx|.xvid|.bivx|.vob|.nrg|.img|.iso|.pva|.wmv|.asf|.asx|.ogm|.m2v|.avi|.bin|.dat|.mpg|.mpeg|.mp4|.mkv|.mk3d|.avc|.vp3|.svq3|.nuv|.viv|.dv|.fli|.flv|.rar|.001|.wpl|.zip|.vdr|.dvr-ms|.xsp|.mts|.m2t|.m2ts|.evo|.ogv|.sdp|.avs|.rec|.url|.pxml|.vc1|.h264|.rcv|.rss|.mpls|.webm|.bdmv|.wtv"; + m_videoExtensions = ".m4v|.3g2|.3gp|.nsv|.tp|.ts|.ty|.strm|.pls|.rm|.rmvb|.m3u|.m3u8|.ifo|.mov|.qt|.divx|.xvid|.bivx|.vob|.nrg|.img|.iso|.pva|.wmv|.asf|.asx|.ogm|.m2v|.avi|.bin|.dat|.mpg|.mpeg|.mp4|.mkv|.mk3d|.avc|.vp3|.svq3|.nuv|.viv|.dv|.fli|.flv|.rar|.001|.wpl|.zip|.vdr|.dvr-ms|.xsp|.mts|.m2t|.m2ts|.evo|.ogv|.sdp|.avs|.rec|.url|.pxml|.vc1|.h264|.rcv|.rss|.mpls|.webm|.bdmv|.wtv|.ssif"; m_subtitlesExtensions = ".utf|.utf8|.utf-8|.sub|.srt|.smi|.rt|.txt|.ssa|.text|.ssa|.aqt|.jss|.ass|.idx|.ifo|.rar|.zip"; m_discStubExtensions = ".disc"; // internal music extensions