📄 hantrodecoderdmo.cpp
字号:
pmt->pUnk = NULL;
// Initialize the format
VIDEOINFO *pviOutput = (VIDEOINFO *)pmt->pbFormat;
ZeroMemory(pviOutput, FIELD_OFFSET(VIDEOINFO, dwBitMasks[3]));
pviOutput->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
if( pmt->subtype == MEDIASUBTYPE_RGB565 )
{
pviOutput->bmiHeader.biCompression = BI_BITFIELDS; // Unpacked RGB data
}
else // MEDIASUBTYPE_IYUV )
{
pviOutput->bmiHeader.biCompression = supportedOutputFourCCs[0];
}
switch( dwTypeIndex )
{
case 0:
pviOutput->bmiHeader.biBitCount = (WORD)BitsPerPixel(OUTPUTTYPE_IYUV); // bits per pixel
break;
case 1:
pviOutput->bmiHeader.biBitCount = (WORD)BitsPerPixel(OUTPUTTYPE_iyuv); // bits per pixel
break;
case 2:
pviOutput->bmiHeader.biBitCount = 16; // bits per pixel
break;
}
pviOutput->bmiHeader.biPlanes = 1; // Fixed
pviOutput->bmiHeader.biWidth = lWidth; // Width same as input
pviOutput->bmiHeader.biHeight = lHeight; // Height reversed (top-down input vs. bottom-up output)
pviOutput->bmiHeader.biSizeImage = pmt->lSampleSize; // fixed sample size
pviOutput->TrueColorInfo.dwBitMasks[0] = 0xF800;
pviOutput->TrueColorInfo.dwBitMasks[1] = 0x07E0;
pviOutput->TrueColorInfo.dwBitMasks[2] = 0x001F;
pviOutput->AvgTimePerFrame = pvihInput->AvgTimePerFrame; // copy data
// Don't crop the input image
pviOutput->rcSource.left = 0;
pviOutput->rcSource.right = 0;
pviOutput->rcSource.top = 0;
pviOutput->rcSource.bottom = 0;
// No scaling
pviOutput->rcTarget.left = 0;
pviOutput->rcTarget.right = lWidth;
pviOutput->rcTarget.top = 0;
pviOutput->rcTarget.bottom = lHeight;
}
}
return S_OK;
}
// This method retrieves the buffer requirements for a specified input stream.
//
// Parameters
//
// dwInputStreamIndex
// Zero-based index of an input stream on the DMO.
// pcbSize
// [out] Pointer to a variable that receives the minimum size of an input buffer
// for this stream, in bytes.
// pcbMaxLookahead
// [out] Pointer to a variable that receives the maximum amount of data that the
// DMO will hold for a lookahead, in bytes. If the DMO does not perform a lookahead
// on the stream, the value is zero.
// pcbAlignment
// [out] Pointer to a variable that receives the required buffer alignment, in bytes.
// If the input stream has no alignment requirement, the value is 1.
//
// Return Values
// Returns an HRESULT value. Possible values include the following.
// Value Description
// S_OK Success
// DMO_E_INVALIDSTREAMINDEX Invalid stream index
// DMO_E_TYPE_NOT_SET Media type was not set
HRESULT CHantroDecoderDMO::InternalGetInputSizeInfo(DWORD dwInputStreamIndex, DWORD *pcbSize,
DWORD *pcbMaxLookahead, DWORD *pcbAlignment)
{
*pcbSize = 1;
*pcbMaxLookahead = 0;
*pcbAlignment = 1;
return S_OK;
}
// This method retrieves the buffer requirements for a specified output stream.
//
// Parameters
//
// dwOutputStreamIndex
// Zero-based index of an output stream on the DMO.
// pcbSize
// [out] Pointer to a variable that receives the minimum size of an output
// buffer for this stream, in bytes.
// pcbAlignment
// [out] Pointer to a variable that receives the required buffer alignment,
// in bytes. If the output stream has no alignment requirement, the value is 1.
//
// Return Values
//
// Returns an HRESULT value. Possible values include the following.
// Value Description
// S_OK Success
// DMO_E_INVALIDSTREAMINDEX Invalid stream index
// DMO_E_TYPE_NOT_SET Media type was not set
HRESULT CHantroDecoderDMO::InternalGetOutputSizeInfo(DWORD dwOutputStreamIndex, DWORD *pcbSize,
DWORD *pcbAlignment)
{
*pcbAlignment = 1;
*pcbSize = OutputType(0)->lSampleSize;
return S_OK;
}
// This method retrieves the maximum latency on a specified input stream.
HRESULT CHantroDecoderDMO::InternalGetInputMaxLatency(DWORD dwInputStreamIndex,
REFERENCE_TIME *prtMaxLatency)
{
return E_NOTIMPL;
}
// This method sets the maximum latency on a specified input stream. For the definition
// of maximum latency, see IMediaObject::GetInputMaxLatency.
HRESULT CHantroDecoderDMO::InternalSetInputMaxLatency(DWORD dwInputStreamIndex,
REFERENCE_TIME rtMaxLatency)
{
return E_NOTIMPL;
}
// This method flushes all internally buffered data.
HRESULT CHantroDecoderDMO::InternalFlush()
{
InternalDiscontinuity(0);
// Release input buffer
if( m_pInputBuffer != NULL )
{
m_pInputBuffer->Release();
m_pInputBuffer = NULL;
}
return S_OK;
}
// This method signals a discontinuity on the specified input stream.
HRESULT CHantroDecoderDMO::InternalDiscontinuity(DWORD dwInputStreamIndex)
{
return S_OK;
}
// This method allocates any resources needed by the DMO. Calling this method is always optional.
HRESULT CHantroDecoderDMO::InternalAllocateStreamingResources()
{
// Reinitialize variables
InternalDiscontinuity(0);
// Allocate memory for the decoder
m_pDecoder = new CHantroDecoderWrapper((OutputType(0))->subtype);
if( NULL == m_pDecoder )
return S_FALSE;
// Begin streaming
HRESULT hr = m_pDecoder->StartStream();
if( FAILED(hr) )
{
delete m_pDecoder;
}
#ifdef HDDMO_LOG
char logname[255];
static int logcount=0;
sprintf( logname, "/dmo-log-%d.txt", logcount++ );
slog = fopen( logname, "w" );
#endif
return S_OK;
}
// This method frees resources allocated by the DMO. Calling this method is always optional.
HRESULT CHantroDecoderDMO::InternalFreeStreamingResources()
{
#ifdef HDDMO_LOG
fclose(slog);
#endif
// Free streaming resources
HRESULT hr = m_pDecoder->EndStream();
if( FAILED(hr) )
{
// What can we do, if freeing fails?
}
// Release input buffer
if( m_pInputBuffer != NULL )
{
m_pInputBuffer->Release();
m_pInputBuffer = NULL;
}
// Clean up instance
delete m_pDecoder;
m_pDecoder = NULL;
return S_OK;
}
// Method for processing input data (MPEG-4/H.263 bitstream)
//
// Parameters:
// dwInputStreamIndex
// Zero-based index of an input stream on the DMO.
// pBuffer
// Pointer to the buffer's IMediaBuffer interface.
// dwFlags
// Bitwise combination of zero or more flags from the DMO_INPUT_DATA_BUFFER_FLAGS enumeration.
// rtTimestamp
// Time stamp that specifies the start time of the data in the buffer. If the buffer has a
// valid time stamp, set the DMO_INPUT_DATA_BUFFERF_TIME flag in the dwFlags parameter. Otherwise,
// the DMO ignores this value.
// rtTimelength
// Reference time specifying the duration of the data in the buffer. If this value is valid, set
// the DMO_INPUT_DATA_BUFFERF_TIMELENGTH flag in the dwFlags parameter. Otherwise, the DMO ignores
// this value.
//
// Return Values
//
// Returns an HRESULT value. Possible values include the following.
// Value Description
// S_OK Success
// S_FALSE No output to process
// DMO_E_INVALIDSTREAMINDEX Invalid stream index
// DMO_E_NOTACCEPTING Data cannot be accepted
HRESULT CHantroDecoderDMO::InternalProcessInput(DWORD dwInputStreamIndex, IMediaBuffer *pBuffer,
DWORD dwFlags, REFERENCE_TIME rtTimestamp,
REFERENCE_TIME rtTimelength)
{
// Ensure we can receive more input data, even though IMediaObjectImpl
// should provide this already
if( m_pInputBuffer != NULL )
{
HDDMO_TRACE( "DecDmo:ProcessInput: #NOK previous pInputBuffer not completely comsumed.\n" );
return DMO_E_NOTACCEPTING;
}
if( (dwFlags & DMO_INPUT_DATA_BUFFERF_TIME) != 0 )
{
rtTimestamp = INVALID_REFTIME;
}
if( (dwFlags & DMO_INPUT_DATA_BUFFERF_TIMELENGTH) != 0 )
{
rtTimelength = INVALID_REFTIME;
}
if( rtTimelength == 0 && rtTimestamp == 0 )
{
rtTimelength = INVALID_REFTIME;
rtTimestamp = INVALID_REFTIME;
}
m_rtTimestamp = rtTimestamp;
m_rtTimelength = rtTimelength;
m_pInputBuffer = pBuffer;
m_pInputBuffer->AddRef();
// Don't perfom any check if the provided buffer does contain output-able
// data, leave it for ProcessOutput.
return S_OK;
}
// This method generates output from the current input data.
//
// Parameters
//
// dwFlags
// Bitwise combination of zero or more flags from the DMO_PROCESS_OUTPUT_FLAGS enumeration.
// cOutputBufferCount
// Number of output buffers.
// pOutputBuffers
// [in, out] Pointer to an array of DMO_OUTPUT_DATA_BUFFER structures containing the output buffers.
// Specify the size of the array in the cOutputBufferCount parameter.
// pdwStatus
// [out] Pointer to a variable that receives a reserved value (zero). The application should
// ignore this value.
HRESULT CHantroDecoderDMO::InternalProcessOutput(DWORD dwFlags,
DWORD cOutputBufferCount,
DMO_OUTPUT_DATA_BUFFER *pOutputBuffers,
DWORD *pdwStatus)
{
// Do we have any input buffer to process?
if( m_pInputBuffer==NULL )
{
HDDMO_TRACE( "DecDmo:ProcessOutput: #NOK No input buffer to be processed!\n" );
return S_FALSE;
}
// Check input buffer
BYTE* pInputData;
DWORD inputLength;
HRESULT hr = m_pInputBuffer->GetBufferAndLength( &pInputData, &inputLength );
if (FAILED(hr)) {
HDDMO_TRACE( "DecDmo:ProcessOutput: #NOK GetBufferAndLength for input buffer failed\n" );
return hr;
}
// Check output buffer
PBYTE pOutputData;
DWORD cbOutputData;
DWORD cbOutputCurrent;
hr = pOutputBuffers[0].pBuffer->GetBufferAndLength(&pOutputData, &cbOutputCurrent);
if (FAILED(hr)) {
HDDMO_TRACE( "DecDmo:ProcessOutput: #NOK GetBufferAndLength for output buffer failed\n" );
return hr;
}
hr = pOutputBuffers[0].pBuffer->GetMaxLength(&cbOutputData);
if (FAILED(hr)) {
HDDMO_TRACE( "DecDmo:ProcessOutput: #NOK GetMaxLength for output buffer failed\n" );
return hr;
}
if (cbOutputData < cbOutputCurrent + (DWORD)OutputType(0)->lSampleSize) {
HDDMO_TRACE( "ProcessOutput: size failed: cbData=%d, cbCurrent=%d, sampleSize=%d\n",
cbOutputData, cbOutputCurrent, (DWORD)OutputType(0)->lSampleSize );
return E_INVALIDARG;
}
// Decode input stream *and* copy to output buffer
BOOL streamNotEmpty = FALSE;
LONG outputWidth, outputHeight;
REFERENCE_TIME outputStart;
REFERENCE_TIME outputDuration;
do hr = m_pDecoder->DecodeStream( pInputData, inputLength, m_rtTimestamp, m_rtTimelength,
pOutputData, &streamNotEmpty, &outputWidth, &outputHeight,
&outputStart, &outputDuration );
while( hr!=S_OK && streamNotEmpty );
if( hr != S_OK )
{
// S_FALSE when image not available
// E_FAIL, etc, on error
m_pInputBuffer->Release();
m_pInputBuffer = NULL;
return hr;
}
// For sanity check, if the stream doesn't chage the frame size
//ASSERT( cbOutputCurrent+(DWORD)OutputType(0)->lSampleSize==(outputWidth*outputHeight*3)/2 );
// Say we've filled the buffer
hr = pOutputBuffers[0].pBuffer->SetLength( cbOutputCurrent+(DWORD)OutputType(0)->lSampleSize );
pOutputBuffers[0].dwStatus = DMO_OUTPUT_DATA_BUFFERF_TIME | DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH;
pOutputBuffers[0].rtTimestamp = outputStart;
pOutputBuffers[0].rtTimelength = outputDuration;
if( streamNotEmpty )
{
pOutputBuffers[0].dwStatus |= DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE;
// TODO! Test adjustment of timestamps between VOPs in the same input buffer.
// Same behaviour as before memory optimizations is achieved by *not* touching
// m_rtTimexxx, i.e., leaving it commented out.
// m_rtTimelength = outputDuration;
// m_rtTimestamp = outputStart;
}
else // streamConsumed
{
m_pInputBuffer->Release();
m_pInputBuffer = NULL;
m_rtTimelength = INVALID_REFTIME;
m_rtTimestamp = INVALID_REFTIME;
}
#ifdef HDDMO_LOG
int cs = csum( pOutputData, cbOutputCurrent+(DWORD)OutputType(0)->lSampleSize );
fprintf( slog, "%d\t%d\t%04X\n", (int)(outputStart/10000), (outputWidth*outputHeight*3)/2, cs );
#endif
return S_OK;
}
// This method queries whether an input stream can accept more input.
// The derived class must declare and implement this method.
//
// Parameters
//
// dwInputStreamIndex
// Index of an input stream.
//
// Return Values
// Returns S_OK if the input stream can accept input or otherwise returns S_FALSE.
HRESULT CHantroDecoderDMO::InternalAcceptingInput(DWORD dwInputStreamIndex)
{
return m_pInputBuffer == NULL ? S_OK : S_FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -