📄 umc_threaded_demuxer.cpp
字号:
m_pRulesState->m_bAnyRuleValidAfterInit = false;
return UMC_OK;
}
Status ThreadedDemuxer::SetTimePosition(Ipp64f timePos)
{
TDEM_CHECK_INIT;
Stop();
m_bEndOfStream = false;
Status umcRes = m_pDemuxer->SetTimePosition(timePos);
if (UMC_OK != umcRes)
return umcRes;
vm_debug_trace1(VM_DEBUG_INFO, VM_STRING("ThreadedDemuxer: new time pos = %f\n"), timePos);
return umcRes;
}
Status ThreadedDemuxer::GetTimePosition(Ipp64f &timePos)
{
TDEM_CHECK_INIT;
return m_pDemuxer->GetTimePosition(timePos);
}
void ThreadedDemuxer::TerminateInit(void)
{
if (m_pRulesState)
{
if (m_pRulesState->m_pRules)
{
delete[] m_pRulesState->m_pRules;
m_pRulesState->m_pRules = NULL;
}
if (m_pRulesState->m_pRuleState)
{
ippsFree(m_pRulesState->m_pRuleState);
m_pRulesState->m_pRuleState = NULL;
}
delete m_pRulesState;
m_pRulesState = NULL;
}
if (m_pDemuxer)
{
delete m_pDemuxer;
m_pDemuxer = NULL;
}
}
Status ThreadedDemuxer::AnalyzeParams(SplitterParams *pParams)
{
Ipp32u i;
const TrackRule *pRules = NULL;
if (DynamicCast<DemuxerParams>(pParams))
{
pRules = ((DemuxerParams *)pParams)->m_pRules;
m_pRulesState->m_uiRules = ((DemuxerParams *)pParams)->m_uiRules;
}
// presets have higher priority than manually defined rules
if (pParams->m_lFlags & FLAG_VSPL_PRESET_MASK)
{
Ipp32s iPreset = (pParams->m_lFlags & FLAG_VSPL_PRESET_MASK) - 1;
if (iPreset < sizeof(SplInitPresets) / sizeof(SplInitPresets[0]))
{
pRules = SplInitPresets[iPreset].pRules;
m_pRulesState->m_uiRules = SplInitPresets[iPreset].uiRules;
}
}
if (0 == m_pRulesState->m_uiRules || NULL == pRules)
return UMC_ERR_INIT;
m_pRulesState->m_pRules = new TrackRule[m_pRulesState->m_uiRules];
m_pRulesState->m_pRuleState = ippsMalloc_32s(m_pRulesState->m_uiRules);
if (!m_pRulesState->m_pRules || !m_pRulesState->m_pRuleState)
return UMC_ERR_ALLOC;
ippsZero_32s(m_pRulesState->m_pRuleState, m_pRulesState->m_uiRules);
ippsCopy_8u((Ipp8u *)pRules, (Ipp8u *)m_pRulesState->m_pRules, m_pRulesState->m_uiRules * sizeof(TrackRule));
// analyse rules
for (i = 0; i < m_pRulesState->m_uiRules; i++)
{
// when FLAG_VSPL_FAST_INIT is set, whole playback is like init stage
if (m_uiFlags & FLAG_VSPL_FAST_INIT)
m_pRulesState->m_pRules[i].m_bValidAfterInit = true;
if (m_pRulesState->m_pRules[i].m_bValidAfterInit)
m_pRulesState->m_bAnyRuleValidAfterInit = true;
// if positive PID is specified it implies that iMaxNOfESs isn't greater than 1
if (m_pRulesState->m_pRules[i].m_iPID >= 0 && m_pRulesState->m_pRules[i].m_iLimit > 1)
m_pRulesState->m_pRules[i].m_iLimit = 1;
// count total number of tracks defined by rules
if (m_pRulesState->m_pRules[i].m_iLimit < 0)
m_pRulesState->m_iMaxTracks = MAX_TRACK;
else if (m_pRulesState->m_iMaxTracks < MAX_TRACK)
m_pRulesState->m_iMaxTracks += m_pRulesState->m_pRules[i].m_iLimit;
}
return UMC_OK;
}
Ipp32u ThreadedDemuxer::ThreadRoutine()
{
Status umcRes = UMC_OK;
MediaData data;
Ipp32u uiTrack = 0;
// initialization
while (!m_bStop && !(m_uiFlags & FLAG_VSPL_FAST_INIT))
{
umcRes = m_pDemuxer->CheckNextData(&data, &uiTrack);
if (UMC_OK == umcRes)
{ // next access unit is received, check if it's from new track
if (!m_pRulesState->m_bIsTriedByRules[uiTrack])
{
if (TryTrackByRules(uiTrack))
{ // match some rule, leave it enabled
m_OnAutoEnable.Lock();
m_bAutoEnable = true;
m_OnAutoEnable.Unlock();
}
else
{ // not match to any rule, disable it
m_pDemuxer->EnableTrack(uiTrack, 0);
}
}
}
else if (UMC_WRN_INVALID_STREAM == umcRes)
{ // change of PAT is detected, notify app and prepare for re-init
if (m_pOnPSIChangeEvent)
m_pOnPSIChangeEvent->Set();
m_OnInit.Reset();
m_pRulesState->Reset();
vm_debug_trace(VM_DEBUG_ALL, VM_STRING("ThreadedDemuxer: thread exited due to PSI changes\n"));
return 0;
}
else if (UMC_ERR_NOT_ENOUGH_BUFFER == umcRes || UMC_ERR_END_OF_STREAM == umcRes ||
m_pRulesState->m_iMatchedTracks >= m_pRulesState->m_iMaxTracks)
{ // initialization stage completes (any buffer is full, EOS or all rules are matched)
#ifdef VM_DEBUG
if (UMC_ERR_NOT_ENOUGH_BUFFER == umcRes)
vm_debug_trace1(VM_DEBUG_INFO, VM_STRING("ThreadedDemuxer: Init completed: Reason: buffer(track=%d) is full\n"), uiTrack);
else if (UMC_ERR_END_OF_STREAM == umcRes)
vm_debug_trace(VM_DEBUG_INFO, VM_STRING("ThreadedDemuxer: Init completed: Reason: END_OF_STREAM\n"));
else
vm_debug_trace(VM_DEBUG_INFO, VM_STRING("ThreadedDemuxer: Init completed: Reason: All streams specified by rules were detected\n"));
#endif //VM_DEBUG
m_bStop = (m_uiFlags & FLAG_VSPL_STOP_AFTER_INIT) != 0;
break;
}
else
{
vm_debug_trace(VM_DEBUG_INFO, VM_STRING("ThreadedDemuxer: Init completed: unexpected error\n"));
m_OnInit.Set();
return 1;
}
}
// notify main thread that initialization stage is passed
m_OnInit.Set();
// main loop
while (!m_bStop)
{
umcRes = m_pDemuxer->CheckNextData(&data, &uiTrack);
if (UMC_OK == umcRes)
{ // next access unit is received
if (!m_pRulesState->m_bIsTriedByRules[uiTrack])
{
if (TryTrackByRules(uiTrack))
{ // matches some rule, leave it enabled
m_OnAutoEnable.Lock();
m_bAutoEnable = true;
m_OnAutoEnable.Unlock();
}
else
{ // doesn't match to any rule, disable it
m_pDemuxer->EnableTrack(uiTrack, 0);
}
}
}
else if (UMC_WRN_INVALID_STREAM == umcRes)
{ // change of PAT is detected, notify app and prepare for re-init
if (m_pOnPSIChangeEvent)
m_pOnPSIChangeEvent->Set();
m_OnInit.Reset();
m_pRulesState->Reset();
vm_debug_trace(VM_DEBUG_ALL, VM_STRING("ThreadedDemuxer: thread exited due to PSI changes\n"));
return 0;
}
else if (UMC_ERR_NOT_ENOUGH_BUFFER == umcRes)
{ // buffer is full, it blocks parsing thread, what until app get data from fulled buffer
m_iBlockingPID = uiTrack;
vm_debug_trace1(VM_DEBUG_VERBOSE, VM_STRING("ThreadedDemuxer: blocked by PID=%d\n"), m_iBlockingPID);
m_OnUnlock.Wait();
m_iBlockingPID = -1;
m_OnUnlock.Reset();
}
else
{
vm_debug_trace(VM_DEBUG_INFO, VM_STRING("ThreadedDemuxer: Init completed: unexpected error\n"));
break;
}
}
m_bStop = true;
m_bEndOfStream = (UMC_ERR_END_OF_STREAM == umcRes);
vm_debug_trace1(VM_DEBUG_ALL, VM_STRING("ThreadedDemuxer: thread exited with res = %d\n"), umcRes);
return 0;
}
void ThreadedDemuxer::AlterQuality(Ipp64f time)
{
if (m_pDemuxer)
m_pDemuxer->AlterQuality(time);
}
bool ThreadedDemuxer::TryTrackByRules(Ipp32u uiTrack)
{
// if all possible tracks enabled
if (m_pRulesState->m_iMatchedTracks >= m_pRulesState->m_iMaxTracks)
return false;
// if init finished and enabling after init isn't required
if (UMC_OK == m_OnInit.Wait(0) && !m_pRulesState->m_bAnyRuleValidAfterInit)
return false;
SplitterInfo *pSplInfo;
Status umcRes = m_pDemuxer->GetInfo(&pSplInfo);
if (UMC_OK != umcRes)
return false;
TrackInfo *pInfo = pSplInfo->m_ppTrackInfo[uiTrack];
m_pRulesState->m_bIsTriedByRules[uiTrack] = true;
Ipp32u rule;
for (rule = 0; rule < m_pRulesState->m_uiRules; rule++)
{
// check if this rule valid at current state of threaded demuxer
if (UMC_OK == m_OnInit.Wait(0) && !m_pRulesState->m_pRules[rule].m_bValidAfterInit)
continue;
// check if required number of tracks of this type was already found
if (m_pRulesState->m_pRules[rule].m_iLimit >= 0 && m_pRulesState->m_pRuleState[rule] >= m_pRulesState->m_pRules[rule].m_iLimit)
continue;
// check if track type fits type mask of rule
if (!(pInfo->m_Type & m_pRulesState->m_pRules[rule].m_TypeMask))
continue;
// check if track PID fits required PID (if it's positive)
if (m_pRulesState->m_pRules[rule].m_iPID >= 0 && (Ipp32s)pInfo->m_PID != m_pRulesState->m_pRules[rule].m_iPID)
continue;
m_pRulesState->m_pRuleState[rule]++;
m_pRulesState->m_iMatchedTracks++;
return true;
}
return false;
}
} // namespace UMC
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -