Many thanks to Nikolay and f_c for their help.
My application is now nicely decoding both MPEG-4 and H.264. The "only" remaining problem is that the decoder appears to get stuck returning -996 UMC_ERR_NOT_ENOUGH_DATA, both for an MPEG-4 MP4 file and for an H.264 MP4 file, both of which play nicely with Quick Time v7.4. I've inserted some code, see below, to watch for the decoder getting stuck with UMC_ERR_NOT_ENOUGH_DATA and aborting in that event. For both files, the point where the decoder gets stuck with UMC_ERR_NOT_ENOUGH_DATA is apparently at end of file. Is it possible that the splitter has stopped running but failed to advise the decoder?
// AtsPlaybackMpeg4Proc.cpp
//
#include "stdafx.h"
#include "AtsPlaybackMpeg4.h"
#include "AtsPlaybackMpeg4Doc.h"
#include "AtsPlaybackMpeg4View.h"
#include "ipp.h"
#include "umc_file_reader.h"
#include "umc_fio_reader.h"
#include "umc_h264_dec.h"
#include "umc_h264_spl.h"
#include "umc_h264_timing.h"
#include "umc_mp4_spl.h"
#include "umc_mpeg4_video_decoder.h"
#include "umc_splitter.h"
#include "umc_video_render.h"
#include "fw_video_render.h"
#include "vm_time.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
void CAtsPlaybackMpeg4View::PlaybackThread(void)
{
CString str;
UMC::Status umcResult;
//-------------------------------------------------------------------------
// init file reader
//-------------------------------------------------------------------------
UMC::FIOReader reader;
UMC::FileReaderParams readerParams;
readerParams.m_portion_size = 0;
vm_string_strcpy(readerParams.m_file_name, (LPCTSTR)m_strMpeg4File);
umcResult = reader.Init(&readerParams);
if (umcResult != UMC::UMC_OK)
{
str.Format("FIOReader.Init failure %d", umcResult);
AfxMessageBox(str);
return;
}
//-------------------------------------------------------------------------
// init splitter
//-------------------------------------------------------------------------
UMC::MP4Splitter splitter;
UMC::SplitterParams splitterParams;
splitterParams.m_lFlags = UMC::VIDEO_SPLITTER;
splitterParams.m_pDataReader = &reader;
umcResult = splitter.Init(splitterParams);
if (umcResult != UMC::UMC_OK)
{
str.Format("Splitter.Init failure %d", umcResult);
AfxMessageBox(str);
return;
}
umcResult = splitter.Run();
if (umcResult != UMC::UMC_OK)
{
str.Format("Splitter.Run failure %d", umcResult);
AfxMessageBox(str);
return;
}
UMC::Spl
itterInfo *streamInfo;
umcResult = splitter.GetInfo(&streamInfo);
if (umcResult != UMC::UMC_OK)
{
str.Format("Splitter.GetInfo failure %d", umcResult);
AfxMessageBox(str);
return;
}
Ipp32u videoTrack;
for (videoTrack = 0; videoTrack < streamInfo->m_nOfTracks; videoTrack++)
{
TRACE("videoTrack %d m_type 0x%X
", videoTrack, streamInfo->m_ppTrackInfo[videoTrack]->m_Type);
if (streamInfo->m_ppTrackInfo[videoTrack]->m_Type == UMC::TRACK_MPEG4V ||
streamInfo->m_ppTrackInfo[videoTrack]->m_Type == UMC::TRACK_H264)
break;
}
if (videoTrack == streamInfo->m_nOfTracks)
{
AfxMessageBox("MP4 does not contain TRACK_MPEG4V or TRACK_H264");
return;
}
UMC::VideoStreamInfo &videoTrackInfo = *((UMC::VideoStreamInfo *)streamInfo->m_ppTrackInfo[videoTrack]->m_pStreamInfo);
TRACE("m_nOfTracks %d videoTrack %d stream_type 0x%X framerate %.1f clip_info.width %d clip_info.height %d color_format %d
",
streamInfo->m_nOfTracks,
videoTrack,
videoTrackInfo.stream_type,
videoTrackInfo.framerate,
videoTrackInfo.clip_info.width,
videoTrackInfo.clip_info.height,
videoTrackInfo.color_format);
//-------------------------------------------------------------------------
// init video decoder
//-------------------------------------------------------------------------
UMC::VideoDecoder *decoder;
switch (videoTrackInfo.stream_type)
{
case UMC::MPEG4_VIDEO :
decoder = (UMC::VideoDecoder*)(new UMC::MPEG4VideoDecoder());
break;
case UMC::H264_VIDEO :
decoder = (UMC::VideoDecoder*)(new UMC::H264VideoDecoder());
break;
default :
str.Format("stream_type %d neither MPEG4_VIDEO nor H264_VIDEO", videoTrackInfo.stream_type);
AfxMessageBox(str);
return;
}
UMC::VideoDecoderParams decoderParams;
decoderParams.info = videoTrackInfo;
decoderParams.numThreads = 1;
decoderParams.lFlags = UMC::FLAG_VDEC_REORDER;
decoderParams.m_pData = stream
Info->m_ppTrackInfo[videoTrack]->m_pDecSpecInfo;
umcResult = decoder->Init(&decoderParams);
if (umcResult != UMC::UMC_OK)
{
str.Format("MPEG4VideoDecoder.Init failure %d", umcResult);
AfxMessageBox(str);
return;
}
//-------------------------------------------------------------------------
// init video renderer
//-------------------------------------------------------------------------
UMC::VideoRenderParams renderParams;
umcResult = renderParams.out_data_template.Init(
videoTrackInfo.clip_info.width,
videoTrackInfo.clip_info.height,
videoTrackInfo.color_format);
if (umcResult != UMC::UMC_OK)
{
str.Format("VideoRenderParams.Init failure %d", umcResult);
AfxMessageBox(str);
return;
}
UMC::FWVideoRender render;
umcResult = render.Init(&renderParams);
if (umcResult != UMC::UMC_OK)
{
str.Format("FWVideoRender.Init failure %d", umcResult);
AfxMessageBox(str);
return;
}
//-------------------------------------------------------------------------
// process frames
//-------------------------------------------------------------------------
UMC::MediaData dataIn;
UMC::VideoData dataOut;
vm_tick total = 0;
vm_tick freq = vm_time_get_frequency();
int nframes = 0;
int decoderWait = 0;
while (1)
{
while (1)
{
umcResult = splitter.GetNextData(&dataIn, videoTrack);
if (umcResult != UMC::UMC_ERR_NOT_ENOUGH_DATA)
break;
vm_time_sleep(5);
}
if (umcResult != UMC::UMC_OK &&
umcResult != UMC::UMC_ERR_END_OF_STREAM)
{
str.Format("Splitter.GetNextData failure %d", umcResult);
AfxMessageBox(str);
break;
}
render.LockInputBuffer(&dataOut);
vm_tick t0 = vm_time_get_tick();
// if call to GetNextVideoData was entirely successful then pass MediaData input to GetFrame
if (umcResult == UMC::UMC_OK)
umcResult = decoder->GetFrame(&dataIn, &dataOut);
// if call to GetNextVideoData was not entirely successful then pass NULL input to GetFrame
else
umcResult = decoder->GetFrame(NULL, &dataOut);
vm_tick t1 = vm_time_get_tick();
total += t1 - t0;
// if call to GetFrame resulted in end of stream
if (umcResult == UMC::UMC_ERR_END_OF_STREAM)
{
AfxMessageBox("decoder.GetFrame returned UMC_ERR_END_OF_STREAM");
break;
}
// if call to GetFrame resulted in fatal error
if (umcResult != UMC::UMC_OK &&
umcResult != UMC::UMC_ERR_NOT_ENOUGH_DATA)
{
str.Format("decoder.GetFrame failure %d", umcResult);
AfxMessageBox(str);
break;
}
render.UnLockInputBuffer(&dataOut);
// if call to GetFrame was entirely successful then render output frame
if (umcResult == UMC::UMC_OK)
{
TRACE("frame %d delta %d FPS %.1f
", nframes, t1 - t0, 1.0 / ((t1 - t0) / (double)freq));
Ipp64f time = -1;
while (render.GetRenderFrame(&time) == UMC::UMC_ERR_TIMEOUT)
AfxMessageBox("render.GetRenderFrame UMC_ERR_TIMEOUT");
umcResult = render.RenderFrame();
if (umcResult != UMC::UMC_OK)
{
str.Format("render.RenderFrame failure %d", umcResult);
AfxMessageBox(str);
break;
&
nbsp;}
nframes++;
decoderWait = 0;
}
// check for stuck at UMC_ERR_NOT_ENOUGH_DATA
else if (++decoderWait >= 100)
{
AfxMessageBox("decoder stuck at UMC_ERR_NOT_ENOUGH_DATA");
return;
}
}
TRACE("exiting
");
}
DWORD WINAPI CAtsPlaybackMpeg4View::StartPlaybackThread(LPVOID arg)
{
CAtsPlaybackMpeg4View *lpView = (CAtsPlaybackMpeg4View*)arg;
lpView->PlaybackThread();
return(0);
}