📄 theoradecodefilter.cpp
字号:
//Create the structures for setproperties to use
ALLOCATOR_PROPERTIES locReqAlloc;
ALLOCATOR_PROPERTIES locActualAlloc;
//MTS::: Maybe this needs to be reconsidered for other output types... ie rgb32 will be much bigger
const unsigned long MIN_BUFFER_SIZE = 16*16; //What should this be ????
const unsigned long DEFAULT_BUFFER_SIZE = 1024*1024 * 2;
const unsigned long MIN_NUM_BUFFERS = 1;
const unsigned long DEFAULT_NUM_BUFFERS = 1;
//Validate and change what we have been requested to do.
//Allignment of data
if (inPropertyRequest->cbAlign <= 0) {
locReqAlloc.cbAlign = 1;
} else {
locReqAlloc.cbAlign = inPropertyRequest->cbAlign;
}
//Size of each buffer
if (inPropertyRequest->cbBuffer < MIN_BUFFER_SIZE) {
locReqAlloc.cbBuffer = DEFAULT_BUFFER_SIZE;
} else {
locReqAlloc.cbBuffer = inPropertyRequest->cbBuffer;
}
//How many prefeixed bytes
if (inPropertyRequest->cbPrefix < 0) {
locReqAlloc.cbPrefix = 0;
} else {
locReqAlloc.cbPrefix = inPropertyRequest->cbPrefix;
}
//Number of buffers in the allcoator
if (inPropertyRequest->cBuffers < MIN_NUM_BUFFERS) {
locReqAlloc.cBuffers = DEFAULT_NUM_BUFFERS;
} else {
locReqAlloc.cBuffers = inPropertyRequest->cBuffers;
}
//Set the properties in the allocator
locHR = inAllocator->SetProperties(&locReqAlloc, &locActualAlloc);
//Check the response
switch (locHR) {
case E_POINTER:
//debugLog<<"DecideBufferSize : SetProperties - NULL POINTER"<<endl;
return locHR;
case VFW_E_ALREADY_COMMITTED:
//debugLog<<"DecideBufferSize : SetProperties - Already COMMITED"<<endl;
return locHR;
case VFW_E_BADALIGN:
//debugLog<<"DecideBufferSize : SetProperties - Bad ALIGN"<<endl;
return locHR;
case VFW_E_BUFFERS_OUTSTANDING:
//debugLog<<"DecideBufferSize : SetProperties - BUFFS OUTSTANDING"<<endl;
return locHR;
case S_OK:
break;
default:
//debugLog<<"DecideBufferSize : SetProperties - UNKNOWN ERROR"<<endl;
break;
}
locHR = inAllocator->Commit();
//debugLog<<"DecideBufferSize : Commit Returned "<<locHR<<endl;
switch (locHR) {
case E_FAIL:
//debugLog<<"DecideBufferSize : Commit - FAILED "<<endl;
return locHR;
case E_POINTER:
//debugLog<<"DecideBufferSize : Commit - NULL POINTER "<<endl;
return locHR;
case E_INVALIDARG:
//debugLog<<"DecideBufferSize : Commit - INVALID ARG "<<endl;
return locHR;
case E_NOTIMPL:
//debugLog<<"DecideBufferSize : Commit - NOT IMPL"<<endl;
return locHR;
case S_OK:
//debugLog<<"DecideBufferSize : Commit - ** SUCCESS **"<<endl;
break;
default:
//debugLog<<"DecideBufferSize : Commit - UNKNOWN ERROR "<<endl;
return locHR;
}
debugLog<<"Buffer allocated"<<endl;
return S_OK;
}
HRESULT TheoraDecodeFilter::GetMediaType(int inPosition, CMediaType* outOutputMediaType)
{
if (inPosition < 0) {
return E_INVALIDARG;
} else if (inPosition < mOutputMediaTypes.size()) {
VIDEOINFOHEADER2* locVideoFormat = (VIDEOINFOHEADER2*)outOutputMediaType->AllocFormatBuffer(sizeof(VIDEOINFOHEADER2));
FillVideoInfoHeader2(inPosition, locVideoFormat);
FillMediaType(inPosition, outOutputMediaType, locVideoFormat->bmiHeader.biSizeImage);
debugLog<<"Get Media Type"<<endl;
return S_OK;
} else {
return VFW_S_NO_MORE_ITEMS;
}
}
void TheoraDecodeFilter::ResetFrameCount()
{
//XTODO::: Maybe not needed
mFrameCount = 0;
}
HRESULT TheoraDecodeFilter::NewSegment(REFERENCE_TIME inStart, REFERENCE_TIME inEnd, double inRate)
{
debugLog<<"Resetting frame count"<<endl;
ResetFrameCount();
mSegStart = inStart;
mSegEnd = inEnd;
mPlaybackRate = inRate;
return CTransformFilter::NewSegment(inStart, inEnd, inRate);
}
HRESULT TheoraDecodeFilter::Receive(IMediaSample* inInputSample)
{
BYTE* locBuff = NULL;
//Get a source poitner into the input buffer
HRESULT locHR = inInputSample->GetPointer(&locBuff);
if (locHR != S_OK) {
//debugLog<<"Receive : Get pointer failed..."<<locHR<<endl;
return S_FALSE;
} else {
if ((inInputSample->GetActualDataLength() > 0) && ((locBuff[0] & 128) != 0)) {
//inInputSample->Release();
//This is a header, so ignore it
return S_OK;
}
//Make a copy of the packet buffer
BYTE* locNewBuff = new unsigned char[inInputSample->GetActualDataLength()]; //This gets put into a packet.
memcpy((void*)locNewBuff, (const void*)locBuff, inInputSample->GetActualDataLength());
REFERENCE_TIME locStart = 0;
REFERENCE_TIME locEnd = 0;
inInputSample->GetTime(&locStart, &locEnd);
debugLog<<"Theora::Receive - Sample: Size = "<<inInputSample->GetActualDataLength()<<" Time: "<<locStart<<" - "<<locEnd<<endl;
//This packet is given to the decoder or buffered for later
StampedOggPacket* locPacket = new StampedOggPacket(locNewBuff, inInputSample->GetActualDataLength(), false, false, locStart, locEnd, StampedOggPacket::OGG_END_ONLY);
//Buffer all packets, even if we are about to send them anyway
mBufferedPackets.push_back(locPacket);
if (locEnd < 0) {
//The packet was ok, but we just aren't going to deliver it yet
return S_OK;
} else {
//Now we have one with a stamp, we can send all the previous ones.
TheoraDecodeInputPin* locInputPin = (TheoraDecodeInputPin*)m_pInput;
REFERENCE_TIME locGlobalEnd = locInputPin->convertGranuleToTime(locEnd);
unsigned long locNumBufferedFrames = mBufferedPackets.size();
REFERENCE_TIME locGlobalStart = locGlobalEnd - (locNumBufferedFrames * mFrameDuration);
locStart = locGlobalStart;
//Offsetting
REFERENCE_TIME locGlobalOffset = 0;
//Handle stream offsetting
if (!locInputPin->getSentStreamOffset() && (locInputPin->getOutputPinInterface() != NULL)) {
locInputPin->getOutputPinInterface()->notifyStreamBaseTime(locStart);
locInputPin->setSentStreamOffset(true);
}
if (locInputPin->getOutputPinInterface() != NULL) {
locGlobalOffset = locInputPin->getOutputPinInterface()->getGlobalBaseTime();
}
debugLog<<"Theora::Receive - "<<locNumBufferedFrames<<" frames buffered"<<endl;
for (unsigned long i = 0; i < locNumBufferedFrames; i++) {
debugLog<<"Theora::Receive - Processing buffered frame "<<i<<endl;
bool locIsKeyFrame = mTheoraDecoder->isKeyFrame(mBufferedPackets[i]);
debugLog<<"Pre theora decode"<<endl;
yuv_buffer* locYUV = mTheoraDecoder->decodeTheora(mBufferedPackets[i]); //This accept the packet and deletes it
debugLog<<"Post theora decode"<<endl;
locEnd = locStart + mFrameDuration;
REFERENCE_TIME locAdjustedStart = locStart - mSegStart - locGlobalOffset;
REFERENCE_TIME locAdjustedEnd = locEnd - mSegStart - locGlobalOffset;
if (locAdjustedStart < 0) {
locAdjustedStart = 0;
}
if (locAdjustedEnd >= 0) {
if (locYUV != NULL) {
IMediaSample* locOutSample = NULL;
debugLog<<"Theora::Receive - Pre output sample initialisation"<<endl;
locHR = InitializeOutputSample(inInputSample, &locOutSample);
if (locHR != S_OK) {
//XTODO::: We need to trash our buffered packets
debugLog<<"Theora::Receive - Output sample initialisation failed"<<endl;
deleteBufferedPacketsAfter(i);
return S_FALSE;
}
debugLog<<"Theora::Receive - Output sample initialisation suceeded"<<endl;
//REFERENCE_TIME locAdjustedStart = (locStart * RATE_DENOMINATOR) / mRateNumerator;
//REFERENCE_TIME locAdjustedEnd = (locEnd * RATE_DENOMINATOR) / mRateNumerator;
//Fill the sample info
if (TheoraDecoded(locYUV, locOutSample, locIsKeyFrame, locAdjustedStart, locAdjustedEnd) != S_OK) {
//XTODO::: We need to trash our buffered packets
locOutSample->Release();
deleteBufferedPacketsAfter(i);
return S_FALSE;
} else {
//Deliver the sample
debugLog<<"Theora::Receive - Delivering: "<<locAdjustedStart<<" to "<<locAdjustedEnd<<(locIsKeyFrame ? "KEYFRAME": " ")<<endl;
locHR = m_pOutput->Deliver(locOutSample);
ULONG locTempRefCount = locOutSample->Release();
debugLog<<"Theora::Receive - After deliver refcount = "<<locTempRefCount<<endl;
debugLog<<"Theora::Receive - Post delivery"<<endl;
if (locHR != S_OK) {
//XTODO::: We need to trash our buffered packets
debugLog<<"Theora::Receive - Delivery failed"<<endl;
debugLog<<"Theora::Receive - locHR = "<<locHR<<endl;
//locOutSample->Release();
deleteBufferedPacketsAfter(i);
return S_FALSE;
}
debugLog<<"Theora::Receive - Delivery Suceeded"<<endl;
}
} else {
//XTODO::: We need to trash our buffered packets
debugLog<<"locYUV == NULL"<<endl;
deleteBufferedPacketsAfter(i);
return S_FALSE;
}
}
locStart = locEnd;
}
mBufferedPackets.clear();
debugLog<<"Leaving receive method with S_OK"<<endl;
return S_OK;
}
}
}
void TheoraDecodeFilter::deleteBufferedPacketsAfter(unsigned long inPacketIndex)
{
for (size_t i = inPacketIndex + 1; i < mBufferedPackets.size(); i++) {
delete mBufferedPackets[i];
}
mBufferedPackets.clear();
}
HRESULT TheoraDecodeFilter::Transform(IMediaSample* inInputSample, IMediaSample* outOutputSample)
{
//debugLog<<"Theora::Transform NOT IMPLEMENTED"<<endl;
return E_NOTIMPL;
}
HRESULT TheoraDecodeFilter::DecodeToRGB565(yuv_buffer* inYUVBuffer, IMediaSample* outSample, bool inIsKeyFrame, REFERENCE_TIME inStart, REFERENCE_TIME inEnd)
{
//TODO::: This ineeds to be implemented correctly, currently just outputs a single colour
BYTE* locBuffer = NULL;
outSample->GetPointer(&locBuffer);
const unsigned short RED_SHIFT = 11;
const unsigned short GREEN_SHIFT = 6;
const unsigned short BLUE_SHIFT = 0;
unsigned short* locShortBuffer = (unsigned short*)locBuffer;
for (unsigned int i = 0; i < mBMIWidth*mBMIHeight; i++) {
locShortBuffer[i] = (31 << RED_SHIFT);
}
REFERENCE_TIME locStart = inStart;
REFERENCE_TIME locEnd = inEnd;
BOOL locIsKeyFrame = FALSE;
if (inIsKeyFrame) {
locIsKeyFrame = TRUE;
};
SetSampleParams(outSample, mBMIFrameSize, &locStart, &locEnd, locIsKeyFrame);
return S_OK;
}
HRESULT TheoraDecodeFilter::DecodeToRGB24(yuv_buffer* inYUVBuffer, IMediaSample* outSample, bool inIsKeyFrame, REFERENCE_TIME inStart, REFERENCE_TIME inEnd)
{
//TODO::: This ineeds to be implemented correctly, currently just outputs a single colour
BYTE* locBuffer = NULL;
outSample->GetPointer(&locBuffer);
const unsigned short RED_SHIFT = 16;
const unsigned short GREEN_SHIFT = 8;
const unsigned short BLUE_SHIFT = 0;
unsigned long* locLongBuffer = (unsigned long*)locBuffer;
for (unsigned int i = 0; i < mBMIWidth*mBMIHeight; i++) {
locLongBuffer[i] = (255 << RED_SHIFT);
}
REFERENCE_TIME locStart = inStart;
REFERENCE_TIME locEnd = inEnd;
BOOL locIsKeyFrame = FALSE;
if (inIsKeyFrame) {
locIsKeyFrame = TRUE;
};
SetSampleParams(outSample, mBMIFrameSize, &locStart, &locEnd, locIsKeyFrame);
return S_OK;
}
HRESULT TheoraDecodeFilter::DecodeToYUY2(yuv_buffer* inYUVBuffer, IMediaSample* outSample, bool inIsKeyFrame, REFERENCE_TIME inStart, REFERENCE_TIME inEnd)
{
BYTE* locBuffer = NULL;
outSample->GetPointer(&locBuffer);
//Get the stride values and offsets
long locYStride = inYUVBuffer->y_stride;
long locUVStride = inYUVBuffer->uv_stride;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -