Skip to content

Commit

Permalink
pvr: rework parsing of stream to not hammer re-open of codecs
Browse files Browse the repository at this point in the history
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
Joakim Plate committed Sep 21, 2012
1 parent a1a5742 commit 41ca644
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 158 deletions.
247 changes: 106 additions & 141 deletions xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp
Expand Up @@ -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;
}
}

Expand All @@ -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)
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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()
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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)
{
Expand All @@ -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)
{
Expand All @@ -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);
}
}

Expand All @@ -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__);
Expand All @@ -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);
}
}

Expand Down

0 comments on commit 41ca644

Please sign in to comment.