Permalink
Browse files

pvr: rework parsing of stream to not hammer re-open of codecs

Old code would cause dvdplayer to thrash around closing and re-opening
codecs while a stream was being parse. And if it never found extradata
it would never open any codec.
  • Loading branch information...
1 parent a1a5742 commit 41ca644e807d4897a316fd63d89be05c22589bdd @elupus committed Sep 21, 2012
Showing with 133 additions and 158 deletions.
  1. +106 −141 xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp
  2. +27 −17 xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.h
View
247 xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp
@@ -29,12 +29,29 @@
using namespace PVR;
-CDemuxStreamVideoPVRClient::~CDemuxStreamVideoPVRClient()
+CDemuxStreamPVRInternal::CDemuxStreamPVRInternal(CDVDDemuxPVRClient *parent)
+ : m_parent(parent)
+ , m_parser(NULL)
+ , m_context(NULL)
{
- if (m_pParser)
+}
+
+CDemuxStreamPVRInternal::~CDemuxStreamPVRInternal()
+{
+ DisposeParser();
+}
+
+void CDemuxStreamPVRInternal::DisposeParser()
+{
+ if (m_parser)
+ {
+ m_parent->m_dllAvCodec.av_parser_close(m_parser);
+ m_parser = NULL;
+ }
+ if (m_context)
{
- m_parent->m_dllAvCodec.av_parser_close(m_pParser);
- m_pParser = NULL;
+ m_parent->m_dllAvCodec.avcodec_close(m_context);
+ m_context = NULL;
}
}
@@ -53,15 +70,6 @@ void CDemuxStreamVideoPVRClient::GetStreamInfo(std::string& strInfo)
}
}
-CDemuxStreamAudioPVRClient::~CDemuxStreamAudioPVRClient()
-{
- if (m_pParser)
- {
- m_parent->m_dllAvCodec.av_parser_close(m_pParser);
- m_pParser = NULL;
- }
-}
-
void CDemuxStreamAudioPVRClient::GetStreamInfo(std::string& strInfo)
{
switch (codec)
@@ -94,7 +102,6 @@ CDVDDemuxPVRClient::CDVDDemuxPVRClient() : CDVDDemux()
{
m_pInput = NULL;
for (int i = 0; i < MAX_STREAMS; i++) m_streams[i] = NULL;
- for (int i = 0; i < MAX_STREAMS; i++) m_streamsToParse[i] = NULL;
}
CDVDDemuxPVRClient::~CDVDDemuxPVRClient()
@@ -134,14 +141,6 @@ void CDVDDemuxPVRClient::Dispose()
delete m_streams[i];
}
m_streams[i] = NULL;
-
- if (m_streamsToParse[i])
- {
- if (m_streamsToParse[i]->ExtraData)
- delete[] (BYTE*)(m_streamsToParse[i]->ExtraData);
- delete m_streamsToParse[i];
- }
- m_streamsToParse[i] = NULL;
}
m_pInput = NULL;
@@ -171,61 +170,65 @@ void CDVDDemuxPVRClient::Flush()
m_pvrClient->DemuxFlush();
}
-bool CDVDDemuxPVRClient::ParsePacket(DemuxPacket* pPacket)
+void CDVDDemuxPVRClient::ParsePacket(DemuxPacket* pkt)
{
- bool bReturn(false);
+ CDemuxStream* st = m_streams[pkt->iStreamId];
+ if (st == NULL)
+ return;
+
+ if (st->ExtraSize)
+ return;
- if (pPacket && pPacket->iSize)
+ CDemuxStreamPVRInternal* pvr = dynamic_cast<CDemuxStreamPVRInternal*>(st);
+
+ if(pvr == NULL
+ || pvr->m_parser == NULL)
+ return;
+
+ if(pvr->m_parser->parser->split == NULL)
{
- CDemuxStream* st = m_streamsToParse[pPacket->iStreamId];
- AVCodecParserContext* pParser = NULL;
- if (st && st->type == STREAM_VIDEO)
- pParser = ((CDemuxStreamVideoPVRClient*)st)->m_pParser;
- else if (st && st->type == STREAM_AUDIO)
- pParser = ((CDemuxStreamAudioPVRClient*)st)->m_pParser;
-
- if (st && pParser)
+ CLog::Log(LOGDEBUG, "%s - parser have not split function", __FUNCTION__);
+ pvr->DisposeParser();
+ return;
+ }
+
+ if(pvr->m_context == NULL)
+ {
+ AVCodec *codec = m_dllAvCodec.avcodec_find_decoder(st->codec);
+ if (codec == NULL)
{
- // use split function of parser to get SPS
- if (pParser->parser->split)
- {
- AVCodec *codec;
- AVCodecContext *pCodecContext = NULL;
- codec = m_dllAvCodec.avcodec_find_decoder(st->codec);
- if (!codec)
- {
- CLog::Log(LOGERROR, "%s - Error, can't find decoder", __FUNCTION__);
- }
- else
- {
- pCodecContext = m_dllAvCodec.avcodec_alloc_context3(codec);
- int i = pParser->parser->split(pCodecContext, pPacket->pData, pPacket->iSize);
- if (i > 0 && i < FF_MAX_EXTRADATA_SIZE)
- {
- if (st->ExtraData)
- delete[] (uint8_t*)(st->ExtraData);
- st->ExtraSize = i;
- st->ExtraData = new uint8_t[st->ExtraSize+FF_INPUT_BUFFER_PADDING_SIZE];
- memcpy(st->ExtraData, pPacket->pData, st->ExtraSize);
- memset((uint8_t*)st->ExtraData + st->ExtraSize, 0 , FF_INPUT_BUFFER_PADDING_SIZE);
- bReturn = true;
- }
- else
- {
- CLog::Log(LOGERROR, "%s - Error, could not split extra data", __FUNCTION__);
- }
- }
- m_dllAvCodec.avcodec_close(pCodecContext);
- }
- else
- {
- // steam has no extradata to split
- bReturn = true;
- }
+ CLog::Log(LOGERROR, "%s - can't find decoder", __FUNCTION__);
+ pvr->DisposeParser();
+ return;
}
+
+ pvr->m_context = m_dllAvCodec.avcodec_alloc_context3(codec);
+ if(pvr->m_context == NULL)
+ {
+ CLog::Log(LOGERROR, "%s - can't allocate context", __FUNCTION__);
+ pvr->DisposeParser();
+ return;
+ }
+ }
+
+ int len = pvr->m_parser->parser->split(pvr->m_context, pkt->pData, pkt->iSize);
+ if (len > 0 && len < FF_MAX_EXTRADATA_SIZE)
+ {
+ delete[] (uint8_t*)(st->ExtraData);
+ st->ExtraSize = len;
+ st->ExtraData = new uint8_t[len+FF_INPUT_BUFFER_PADDING_SIZE];
+ memcpy(st->ExtraData, pkt->pData, len);
+ memset((uint8_t*)st->ExtraData + len, 0 , FF_INPUT_BUFFER_PADDING_SIZE);
}
- return bReturn;
+ if(st->ExtraData)
+ {
+ CLog::Log(LOGDEBUG, "%s - extradata found for %d:%d - closing parser", __FUNCTION__, st->iId, st->iPhysicalId);
+ pvr->DisposeParser();
+ st->changes++;
+ }
+
+ return;
}
DemuxPacket* CDVDDemuxPVRClient::Read()
@@ -251,24 +254,11 @@ DemuxPacket* CDVDDemuxPVRClient::Read()
{
Reset();
}
-
- // check if streams needs parsing
- int streamId = pPacket->iStreamId;
- CDemuxStream *stream = NULL;
- if (streamId >= 0 && streamId < MAX_STREAMS)
- stream = m_streamsToParse[streamId];
- if (stream)
+ else if (pPacket->iStreamId >= 0
+ && pPacket->iStreamId < MAX_STREAMS
+ && m_streams[pPacket->iStreamId])
{
- if (!ParsePacket(pPacket))
- {
- CDVDDemuxUtils::FreeDemuxPacket(pPacket);
- return CDVDDemuxUtils::AllocateDemuxPacket(0);
- }
- else
- {
- m_streams[streamId] = m_streamsToParse[streamId];
- m_streamsToParse[streamId] = NULL;
- }
+ ParsePacket(pPacket);
}
return pPacket;
@@ -290,8 +280,6 @@ void CDVDDemuxPVRClient::RequestStreams()
for (unsigned int i = 0; i < props.iStreamCount; ++i)
{
- CDemuxStream* (*streams)[MAX_STREAMS] = &m_streams;
-
if (props.stream[i].iCodecType == AVMEDIA_TYPE_AUDIO)
{
CDemuxStreamAudioPVRClient* st = new CDemuxStreamAudioPVRClient(this);
@@ -300,14 +288,8 @@ void CDVDDemuxPVRClient::RequestStreams()
st->iBlockAlign = props.stream[i].iBlockAlign;
st->iBitRate = props.stream[i].iBitRate;
st->iBitsPerSample = props.stream[i].iBitsPerSample;
- st->m_pParser = m_dllAvCodec.av_parser_init(props.stream[i].iCodecId);
- if (st->m_pParser)
- {
- m_streamsToParse[props.stream[i].iStreamIndex] = st;
- streams = &m_streamsToParse;
- }
- else
- m_streams[props.stream[i].iStreamIndex] = st;
+ st->m_parser = m_dllAvCodec.av_parser_init(props.stream[i].iCodecId);
+ m_streams[props.stream[i].iStreamIndex] = st;
}
else if (props.stream[i].iCodecType == AVMEDIA_TYPE_VIDEO)
{
@@ -317,14 +299,8 @@ void CDVDDemuxPVRClient::RequestStreams()
st->iHeight = props.stream[i].iHeight;
st->iWidth = props.stream[i].iWidth;
st->fAspect = props.stream[i].fAspect;
- st->m_pParser = m_dllAvCodec.av_parser_init(props.stream[i].iCodecId);
- if (st->m_pParser)
- {
- m_streamsToParse[props.stream[i].iStreamIndex] = st;
- streams = &m_streamsToParse;
- }
- else
- m_streams[props.stream[i].iStreamIndex] = st;
+ st->m_parser = m_dllAvCodec.av_parser_init(props.stream[i].iCodecId);
+ m_streams[props.stream[i].iStreamIndex] = st;
}
else if (props.stream[i].iCodecId == CODEC_ID_DVB_TELETEXT)
{
@@ -339,18 +315,18 @@ void CDVDDemuxPVRClient::RequestStreams()
else
m_streams[props.stream[i].iStreamIndex] = new CDemuxStream();
- (*streams)[props.stream[i].iStreamIndex]->codec = (CodecID)props.stream[i].iCodecId;
- (*streams)[props.stream[i].iStreamIndex]->iId = props.stream[i].iStreamIndex;
- (*streams)[props.stream[i].iStreamIndex]->iPhysicalId = props.stream[i].iPhysicalId;
- (*streams)[props.stream[i].iStreamIndex]->language[0] = props.stream[i].strLanguage[0];
- (*streams)[props.stream[i].iStreamIndex]->language[1] = props.stream[i].strLanguage[1];
- (*streams)[props.stream[i].iStreamIndex]->language[2] = props.stream[i].strLanguage[2];
- (*streams)[props.stream[i].iStreamIndex]->language[3] = props.stream[i].strLanguage[3];
+ m_streams[props.stream[i].iStreamIndex]->codec = (CodecID)props.stream[i].iCodecId;
+ m_streams[props.stream[i].iStreamIndex]->iId = props.stream[i].iStreamIndex;
+ m_streams[props.stream[i].iStreamIndex]->iPhysicalId = props.stream[i].iPhysicalId;
+ m_streams[props.stream[i].iStreamIndex]->language[0] = props.stream[i].strLanguage[0];
+ m_streams[props.stream[i].iStreamIndex]->language[1] = props.stream[i].strLanguage[1];
+ m_streams[props.stream[i].iStreamIndex]->language[2] = props.stream[i].strLanguage[2];
+ m_streams[props.stream[i].iStreamIndex]->language[3] = props.stream[i].strLanguage[3];
CLog::Log(LOGDEBUG,"CDVDDemuxPVRClient::RequestStreams(): added stream %d:%d with codec_id %d",
- (*streams)[props.stream[i].iStreamIndex]->iId,
- (*streams)[props.stream[i].iStreamIndex]->iPhysicalId,
- (*streams)[props.stream[i].iStreamIndex]->codec);
+ m_streams[props.stream[i].iStreamIndex]->iId,
+ m_streams[props.stream[i].iStreamIndex]->iPhysicalId,
+ m_streams[props.stream[i].iStreamIndex]->codec);
}
}
@@ -360,42 +336,31 @@ void CDVDDemuxPVRClient::UpdateStreams(PVR_STREAM_PROPERTIES *props)
for (unsigned int i = 0; i < props->iStreamCount; ++i)
{
- CDemuxStream* (*streams)[MAX_STREAMS] = &m_streams;
-
- if (m_streams[props->stream[i].iStreamIndex] != NULL &&
- m_streams[props->stream[i].iStreamIndex]->codec == (CodecID)props->stream[i].iCodecId)
- {
- streams = &m_streams;
- }
- else if (m_streamsToParse[props->stream[i].iStreamIndex] != NULL &&
- m_streamsToParse[props->stream[i].iStreamIndex]->codec == (CodecID)props->stream[i].iCodecId)
- {
- streams = &m_streamsToParse;
- }
- else
+ if (m_streams[props->stream[i].iStreamIndex] == NULL &&
+ m_streams[props->stream[i].iStreamIndex]->codec != (CodecID)props->stream[i].iCodecId)
{
CLog::Log(LOGERROR,"Invalid stream inside UpdateStreams");
continue;
}
- if ((*streams)[props->stream[i].iStreamIndex]->type == STREAM_AUDIO)
+ if (m_streams[props->stream[i].iStreamIndex]->type == STREAM_AUDIO)
{
- CDemuxStreamAudioPVRClient* st = (CDemuxStreamAudioPVRClient*) (*streams)[props->stream[i].iStreamIndex];
+ CDemuxStreamAudioPVRClient* st = (CDemuxStreamAudioPVRClient*) m_streams[props->stream[i].iStreamIndex];
st->iChannels = props->stream[i].iChannels;
st->iSampleRate = props->stream[i].iSampleRate;
st->iBlockAlign = props->stream[i].iBlockAlign;
st->iBitRate = props->stream[i].iBitRate;
st->iBitsPerSample = props->stream[i].iBitsPerSample;
}
- else if ((*streams)[props->stream[i].iStreamIndex]->type == STREAM_VIDEO)
+ else if (m_streams[props->stream[i].iStreamIndex]->type == STREAM_VIDEO)
{
if (bGotVideoStream)
{
CLog::Log(LOGDEBUG, "CDVDDemuxPVRClient - %s - skip video stream", __FUNCTION__);
continue;
}
- CDemuxStreamVideoPVRClient* st = (CDemuxStreamVideoPVRClient*) (*streams)[props->stream[i].iStreamIndex];
+ CDemuxStreamVideoPVRClient* st = (CDemuxStreamVideoPVRClient*) m_streams[props->stream[i].iStreamIndex];
if (st->iWidth <= 0 || st->iHeight <= 0)
{
CLog::Log(LOGWARNING, "CDVDDemuxPVRClient - %s - invalid stream data", __FUNCTION__);
@@ -409,21 +374,21 @@ void CDVDDemuxPVRClient::UpdateStreams(PVR_STREAM_PROPERTIES *props)
st->fAspect = props->stream[i].fAspect;
bGotVideoStream = true;
}
- else if ((*streams)[props->stream[i].iStreamIndex]->type == STREAM_SUBTITLE)
+ else if (m_streams[props->stream[i].iStreamIndex]->type == STREAM_SUBTITLE)
{
- CDemuxStreamSubtitlePVRClient* st = (CDemuxStreamSubtitlePVRClient*) (*streams)[props->stream[i].iStreamIndex];
+ CDemuxStreamSubtitlePVRClient* st = (CDemuxStreamSubtitlePVRClient*) m_streams[props->stream[i].iStreamIndex];
st->identifier = props->stream[i].iIdentifier;
}
- (*streams)[props->stream[i].iStreamIndex]->language[0] = props->stream[i].strLanguage[0];
- (*streams)[props->stream[i].iStreamIndex]->language[1] = props->stream[i].strLanguage[1];
- (*streams)[props->stream[i].iStreamIndex]->language[2] = props->stream[i].strLanguage[2];
- (*streams)[props->stream[i].iStreamIndex]->language[3] = props->stream[i].strLanguage[3];
+ m_streams[props->stream[i].iStreamIndex]->language[0] = props->stream[i].strLanguage[0];
+ m_streams[props->stream[i].iStreamIndex]->language[1] = props->stream[i].strLanguage[1];
+ m_streams[props->stream[i].iStreamIndex]->language[2] = props->stream[i].strLanguage[2];
+ m_streams[props->stream[i].iStreamIndex]->language[3] = props->stream[i].strLanguage[3];
CLog::Log(LOGDEBUG,"CDVDDemuxPVRClient::UpdateStreams(): update stream %d:%d with codec_id %d",
- (*streams)[props->stream[i].iStreamIndex]->iId,
- (*streams)[props->stream[i].iStreamIndex]->iPhysicalId,
- (*streams)[props->stream[i].iStreamIndex]->codec);
+ m_streams[props->stream[i].iStreamIndex]->iId,
+ m_streams[props->stream[i].iStreamIndex]->iPhysicalId,
+ m_streams[props->stream[i].iStreamIndex]->codec);
}
}
View
44 xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.h
@@ -45,45 +45,56 @@ extern "C" {
class CDVDDemuxPVRClient;
struct PVR_STREAM_PROPERTIES;
-class CDemuxStreamVideoPVRClient : public CDemuxStreamVideo
+class CDemuxStreamPVRInternal
+{
+public:
+ CDemuxStreamPVRInternal(CDVDDemuxPVRClient *parent);
+ ~CDemuxStreamPVRInternal();
+
+ void DisposeParser();
+
+ CDVDDemuxPVRClient * m_parent;
+ AVCodecParserContext* m_parser;
+ AVCodecContext * m_context;
+};
+
+class CDemuxStreamVideoPVRClient
+ : public CDemuxStreamVideo
+ , public CDemuxStreamPVRInternal
{
- CDVDDemuxPVRClient *m_parent;
public:
CDemuxStreamVideoPVRClient(CDVDDemuxPVRClient *parent)
- : m_parent(parent), m_pParser(NULL)
+ : CDemuxStreamPVRInternal(parent)
{}
- virtual ~CDemuxStreamVideoPVRClient();
virtual void GetStreamInfo(std::string& strInfo);
- AVCodecParserContext* m_pParser;
};
-class CDemuxStreamAudioPVRClient : public CDemuxStreamAudio
+class CDemuxStreamAudioPVRClient
+ : public CDemuxStreamAudio
+ , public CDemuxStreamPVRInternal
{
- CDVDDemuxPVRClient *m_parent;
public:
CDemuxStreamAudioPVRClient(CDVDDemuxPVRClient *parent)
- : m_parent(parent)
+ : CDemuxStreamPVRInternal(parent)
{}
- virtual ~CDemuxStreamAudioPVRClient();
virtual void GetStreamInfo(std::string& strInfo);
- AVCodecParserContext* m_pParser;
};
-class CDemuxStreamSubtitlePVRClient : public CDemuxStreamSubtitle
+class CDemuxStreamSubtitlePVRClient
+ : public CDemuxStreamSubtitle
+ , public CDemuxStreamPVRInternal
{
- CDVDDemuxPVRClient *m_parent;
public:
CDemuxStreamSubtitlePVRClient(CDVDDemuxPVRClient *parent)
- : m_parent(parent)
+ : CDemuxStreamPVRInternal(parent)
{}
virtual void GetStreamInfo(std::string& strInfo);
};
class CDVDDemuxPVRClient : public CDVDDemux
{
- friend class CDemuxStreamVideoPVRClient;
- friend class CDemuxStreamAudioPVRClient;
+ friend class CDemuxStreamPVRInternal;
public:
@@ -110,14 +121,13 @@ class CDVDDemuxPVRClient : public CDVDDemux
#define MAX_STREAMS 100
#endif
CDemuxStream* m_streams[MAX_STREAMS]; // maximum number of streams that ffmpeg can handle
- CDemuxStream* m_streamsToParse[MAX_STREAMS];
boost::shared_ptr<PVR::CPVRClient> m_pvrClient;
DllAvCodec m_dllAvCodec;
private:
void RequestStreams();
void UpdateStreams(PVR_STREAM_PROPERTIES *props);
- bool ParsePacket(DemuxPacket* pPacket);
+ void ParsePacket(DemuxPacket* pPacket);
};

0 comments on commit 41ca644

Please sign in to comment.