1
0
Fork 0

Experimental:

- Rewrote H264 NALU iterator code. New class identifies partial NALU (e.g. TV streams) and various invalid NALUs.
- Fixed typos + cosmetics

git-svn-id: svn://svn.code.sf.net/p/qsdecoder/code/trunk/IntelQuickSyncDecoder@92 dfccccb7-dd81-40b7-a334-5a7ba89c2b1d
This commit is contained in:
egur 2013-06-08 21:17:19 +00:00
parent f81324d280
commit c700e6b8a4
5 changed files with 334 additions and 237 deletions

View File

@ -1,106 +1,134 @@
/*
* Copyright (C) 2010-2012 Hendrik Leppkes
* http://www.1f0.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Initial design and concept by Gabest and the MPC-HC Team, copyright under GPLv2
*/
* Copyright (c) 2013, INTEL CORPORATION
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
* Neither the name of INTEL CORPORATION nor the names of its contributors may
* be used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "stdafx.h"
#include "H264Nalu.h"
void CH264Nalu::SetBuffer(const BYTE* pBuffer, size_t nSize, int nNALSize)
H264_NaluIterator::H264_NaluIterator(const uint8_t* pBuffer, size_t bufSize, int nalSize) :
m_NalSize(nalSize),
m_pBuffer(pBuffer),
m_BufSize(bufSize),
m_StreamType((nalSize == 0) ? AnnexB : RTP),
m_CurPos(0),
m_NextRTP(0),
m_NalPos(0),
m_NalDataPos(0)
{
m_pBuffer = pBuffer;
m_nSize = nSize;
m_nNALSize = nNALSize;
m_nCurPos = 0;
m_nNextRTP = 0;
m_nNALStartPos = 0;
m_nNALDataPos = 0;
if (nNALSize == 0 && nSize > 0)
MoveToNextAnnexBStartcode();
// Stream type is constant throughout the stream.
// RTP style streams are accompanied by extra data passed to the decoder
// at initialization time.
// Find 1st AnnexB NALU
if (m_StreamType == AnnexB && bufSize > 3)
FindNextStartCode();
}
bool CH264Nalu::MoveToNextAnnexBStartcode()
bool H264_NaluIterator::FindNextStartCode()
{
if (m_nSize < 4)
return false;
size_t nBuffEnd = m_nSize - 4;
//ASSERT(m_StreamType == AnnexB); // Sanity check
for (size_t i=m_nCurPos; i<nBuffEnd; i++) {
if ((*((DWORD*)(m_pBuffer+i)) & 0x00FFFFFF) == 0x00010000) {
// Find next AnnexB Nal
m_nCurPos = i;
const uint8_t* p = m_pBuffer + m_CurPos;
const uint8_t* pEnd = m_pBuffer + m_BufSize - 4;
while (p < pEnd)
{
if ((*((uint32_t*)(p)) & 0x00FFFFFF) == 0x00010000) // == 00 00 01
{
// Find next AnnexB NAL
m_CurPos = p - m_pBuffer;
return true;
}
++p;
}
m_nCurPos = m_nSize;
m_CurPos = m_BufSize;
return false;
}
bool CH264Nalu::MoveToNextRTPStartcode()
H264_NAL_RC H264_NaluIterator::Next()
{
if (m_nNextRTP < m_nSize) {
m_nCurPos = m_nNextRTP;
return true;
}
// End of stream
if (m_CurPos + m_NalSize >= m_BufSize) return NALU_EOS;
bool isPartial = false;
m_nCurPos = m_nSize;
return false;
}
bool CH264Nalu::ReadNext()
{
if (m_nCurPos >= m_nSize) return false;
if ((m_nNALSize != 0) && (m_nCurPos == m_nNextRTP))
// RTP style NALU (AVC1):
// (XX XX) XX XX NAL..., with XX XX XX XX or XX XX equal to NAL size (big endian)
if (m_StreamType == RTP)
{
if (m_nCurPos+m_nNALSize >= m_nSize) return false;
// RTP Nalu type : (XX XX) XX XX NAL..., with XX XX XX XX or XX XX equal to NAL size
m_nNALStartPos = m_nCurPos;
m_nNALDataPos = m_nCurPos + m_nNALSize;
unsigned nTemp = 0;
for (int i=0; i<m_nNALSize; i++)
// Position of next NALU
m_NalPos = m_CurPos;
// Position of next NALU data section
m_NalDataPos = m_CurPos + m_NalSize;
// Get NALU size in bytes from stream (big endian)
size_t nSize = 0;
for (int i = 0; i <m_NalSize; ++i)
{
nTemp = (nTemp << 8) + m_pBuffer[m_nCurPos++];
nSize = (nSize << 8) + m_pBuffer[m_CurPos++];
}
m_nNextRTP += nTemp + m_nNALSize;
MoveToNextRTPStartcode();
// Find next NALU
m_NextRTP += (nSize + m_NalSize);
// Partial NALU
if (m_NextRTP > m_BufSize)
{
m_CurPos = m_BufSize;
isPartial = true;
}
m_CurPos = m_NextRTP;
}
// AnnexB style NALU:
// (00) 00 00 01 NAL...
else
{
// Remove trailing bits
while (m_pBuffer[m_nCurPos]==0x00 && ((*((DWORD*)(m_pBuffer+m_nCurPos)) & 0x00FFFFFF) != 0x00010000))
m_nCurPos++;
// Remove trailing zeroes and the optional (00) BYTE:
const size_t bufEnd = m_BufSize - 3;
while (m_pBuffer[m_CurPos] == 0 && ((*((uint32_t*)(m_pBuffer+m_CurPos)) & 0x00FFFFFF) != 0x00010000) && m_CurPos < bufEnd)
++m_CurPos;
// AnnexB Nalu : 00 00 01 NAL...
m_nNALStartPos = m_nCurPos;
m_nCurPos += 3;
m_nNALDataPos = m_nCurPos;
MoveToNextAnnexBStartcode();
m_NalPos = m_CurPos;
m_CurPos = m_NalDataPos = m_CurPos + 3;
// Note: AnnexB streams usually do not end with a start code so
// a fragmented stream can't be identified.
if (!FindNextStartCode())
{
isPartial = true;
}
}
forbidden_bit = (m_pBuffer[m_nNALDataPos]>>7) & 1;
nal_reference_idc = (m_pBuffer[m_nNALDataPos]>>5) & 3;
nal_unit_type = (NALU_TYPE) (m_pBuffer[m_nNALDataPos] & 0x1f);
// Get NALU metadata
m_Nal.data = m_pBuffer[m_NalDataPos];
bool isValid = (m_Nal.forbidden_bit == 0) && IS_VALID_NALU(m_Nal.nal_unit_type);
return true;
if (isPartial && isValid) return NALU_PARTIAL;
return (isValid) ? NALU_OK : NALU_INVALID;
}

View File

@ -1,82 +1,115 @@
/*
* Copyright (C) 2010-2012 Hendrik Leppkes
* http://www.1f0.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Initial design and concept by Gabest and the MPC-HC Team, copyright under GPLv2
*/
* Copyright (c) 2013, INTEL CORPORATION
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
* Neither the name of INTEL CORPORATION nor the names of its contributors may
* be used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
typedef enum
enum H264_STREAM_TYPE
{
NALU_TYPE_SLICE = 1,
NALU_TYPE_DPA = 2,
NALU_TYPE_DPB = 3,
NALU_TYPE_DPC = 4,
NALU_TYPE_IDR = 5,
NALU_TYPE_SEI = 6,
NALU_TYPE_SPS = 7,
NALU_TYPE_PPS = 8,
NALU_TYPE_AUD = 9,
NALU_TYPE_EOSEQ = 10,
NALU_TYPE_EOSTREAM = 11,
NALU_TYPE_FILL = 12,
NALU_TYPE_MAX_VALID = 12
} NALU_TYPE;
#define IS_VALID_NALU(nalu) (nalu > 0 && nalu <= NALU_TYPE_MAX_VALID)
class CH264Nalu
{
private :
int forbidden_bit; //! should be always FALSE
int nal_reference_idc; //! NALU_PRIORITY_xxxx
NALU_TYPE nal_unit_type; //! NALU_TYPE_xxxx
size_t m_nNALStartPos; //! NALU start (including startcode / size)
size_t m_nNALDataPos; //! Useful part
const BYTE *m_pBuffer;
size_t m_nCurPos;
size_t m_nNextRTP;
size_t m_nSize;
int m_nNALSize;
bool MoveToNextAnnexBStartcode();
bool MoveToNextRTPStartcode();
public :
CH264Nalu() { SetBuffer(NULL, 0, 0); }
NALU_TYPE GetType() const { return nal_unit_type; }
bool IsRefFrame() const { return (nal_reference_idc != 0); }
size_t GetDataLength() const { return m_nCurPos - m_nNALDataPos; }
const BYTE *GetDataBuffer() { return m_pBuffer + m_nNALDataPos; }
size_t GetRoundedDataLength() const
{
size_t nSize = m_nCurPos - m_nNALDataPos;
return nSize + 128 - (nSize %128);
}
size_t GetLength() const { return m_nCurPos - m_nNALStartPos; }
const BYTE *GetNALBuffer() { return m_pBuffer + m_nNALStartPos; }
bool IsEOF() const { return m_nCurPos >= m_nSize; }
void SetBuffer (const BYTE *pBuffer, size_t nSize, int nNALSize);
bool ReadNext();
RTP = 1, // No start codes - prefixed with length field
AnnexB = 2 // With start codes (00 00 00 01) - first 00 is optional
};
enum NALU_TYPE
{
NALU_TYPE_SLICE = 1,
NALU_TYPE_DPA = 2,
NALU_TYPE_DPB = 3,
NALU_TYPE_DPC = 4,
NALU_TYPE_IDR = 5,
NALU_TYPE_SEI = 6,
NALU_TYPE_SPS = 7,
NALU_TYPE_PPS = 8,
NALU_TYPE_AUD = 9,
NALU_TYPE_EOSEQ = 10,
NALU_TYPE_EOSTREAM = 11,
NALU_TYPE_FILL = 12,
NALU_TYPE_MAX_VALID = 12
};
enum NALU_REF_IDC
{
NALU_PRIORITY_DISPOSABLE = 0,
NALU_PRIORITY_LOW = 1,
NALU_PRIORITY_HIGH = 2,
NALU_PRIORITY_HIGHEST = 3
};
union H264_NAL
{
uint8_t data;
struct
{
NALU_TYPE nal_unit_type : 5;
unsigned nal_reference_idc : 2; /* VS2010 treat NALU_REF_IDC as signed - should be unsigned*/
unsigned forbidden_bit : 1;
};
};
enum H264_NAL_RC
{
NALU_OK = 0, // Full NAL
NALU_PARTIAL = 1, // partial - need to resend the partial packet concatinated to the next packet
NALU_INVALID = 2, // Invalid attributes - decoder should usually discard this one
NALU_EOS = 3 // End of stream - nothing to output
};
#define IS_VALID_NALU(n) (n > 0 && n <= NALU_TYPE_MAX_VALID)
class H264_NaluIterator
{
public:
H264_NaluIterator(const uint8_t *pBuffer, size_t bufSize, int nalSize);
H264_STREAM_TYPE GetStreamType() const { return m_StreamType; }
NALU_TYPE GetNaluType() const { return m_Nal.nal_unit_type; }
NALU_REF_IDC GetNaluRefIdc() const { return (NALU_REF_IDC)m_Nal.nal_reference_idc; }
bool IsRefFrame() const { return (m_Nal.nal_reference_idc != NALU_PRIORITY_DISPOSABLE); }
size_t GetDataLength() const { return m_CurPos - m_NalDataPos; }
const uint8_t* GetDataBuffer() const { return m_pBuffer + m_NalDataPos; }
size_t GetNalLength() const { return m_CurPos - m_NalPos; }
const uint8_t* GetNALBuffer() const { return m_pBuffer + m_NalPos; }
bool IsEOF() const { return m_CurPos >= m_BufSize; }
H264_NAL_RC Next();
private:
// No copying supported!
H264_NaluIterator(const H264_NaluIterator&);
H264_NaluIterator& operator=(const H264_NaluIterator&);
bool FindNextStartCode();
// data members
const int m_NalSize;
const uint8_t* m_pBuffer;
const size_t m_BufSize;
H264_STREAM_TYPE m_StreamType; // Either AVC or AnnexB
H264_NAL m_Nal;
size_t m_CurPos;
size_t m_NextRTP;
size_t m_NalPos; // NALU start (including startcode / size)
size_t m_NalDataPos; // Data part of NALU
};

View File

@ -58,21 +58,21 @@ CFrameConstructor::CFrameConstructor()
{
m_bSeqHeaderInserted = false;
m_bDvdStripPackets = false;
MSDK_ZERO_VAR(m_ResidualBS);
MSDK_ZERO_VAR(m_ResidialBS);
MSDK_ZERO_VAR(m_Headers);
m_ResidualBS.MaxLength = 100;
m_ResidualBS.Data = new mfxU8[m_ResidualBS.MaxLength];
m_ResidialBS.MaxLength = 100;
m_ResidialBS.Data = new mfxU8[m_ResidialBS.MaxLength];
}
CFrameConstructor::~CFrameConstructor()
{
delete[] m_ResidualBS.Data;
delete[] m_ResidialBS.Data;
delete[] m_Headers.Data;
}
void CFrameConstructor::Reset()
{
m_ResidualBS.DataOffset = m_ResidualBS.DataLength = 0;
m_ResidialBS.DataOffset = m_ResidialBS.DataLength = 0;
m_bSeqHeaderInserted = false;
}
@ -88,23 +88,23 @@ void CFrameConstructor::UpdateTimeStamp(IMediaSample* pSample, mfxBitstream* pBS
void CFrameConstructor::SaveResidualData(mfxBitstream* pBS)
{
MSDK_CHECK_POINTER_NO_RET(pBS);
// m_ResidualBS must be empty
ASSERT(m_ResidualBS.DataLength == 0);
m_ResidualBS.DataOffset = 0;
m_ResidualBS.DataLength = pBS->DataLength;
// m_ResidialBS must be empty
ASSERT(m_ResidialBS.DataLength == 0);
m_ResidialBS.DataOffset = 0;
m_ResidialBS.DataLength = pBS->DataLength;
// Check if a bigger buffer is needed
if (pBS->DataLength > m_ResidualBS.MaxLength)
if (pBS->DataLength > m_ResidialBS.MaxLength)
{
delete[] m_ResidualBS.Data;
delete[] m_ResidialBS.Data;
mfxU32 newSize = pBS->DataLength;
m_ResidualBS.Data = new mfxU8[newSize];
MSDK_CHECK_POINTER_NO_RET(m_ResidualBS.Data);
m_ResidualBS.MaxLength = newSize;
m_ResidialBS.Data = new mfxU8[newSize];
MSDK_CHECK_POINTER_NO_RET(m_ResidialBS.Data);
m_ResidialBS.MaxLength = newSize;
}
ASSERT(pBS->DataOffset + pBS->DataLength <= pBS->MaxLength);
memcpy(m_ResidualBS.Data, pBS->Data + pBS->DataOffset, pBS->DataLength);
memcpy(m_ResidialBS.Data, pBS->Data + pBS->DataOffset, pBS->DataLength);
}
mfxStatus CFrameConstructor::ConstructHeaders(
@ -169,7 +169,7 @@ mfxStatus CFrameConstructor::ConstructFrame(IMediaSample* pSample, mfxBitstream*
}
// Prefix the sequence headers if needed
size_t newDataSize = nDataSize + m_ResidualBS.DataLength +
size_t newDataSize = nDataSize + m_ResidialBS.DataLength +
((m_bSeqHeaderInserted) ? 0 : m_Headers.DataLength);
pBS->MaxLength = pBS->DataLength = (mfxU32)newDataSize;
@ -291,11 +291,11 @@ void CFrameConstructor::StripDvdPacket(BYTE*& p, int& len)
void CFrameConstructor::WriteResidualData(mfxU8*& pData)
{
if (m_ResidualBS.DataLength)
if (m_ResidialBS.DataLength)
{
memcpy(pData, m_ResidualBS.Data, m_ResidualBS.DataLength);
pData += m_ResidualBS.DataLength;
m_ResidualBS.DataLength = 0;
memcpy(pData, m_ResidialBS.Data, m_ResidialBS.DataLength);
pData += m_ResidialBS.DataLength;
m_ResidialBS.DataLength = 0;
}
}
@ -380,7 +380,7 @@ mfxStatus CVC1FrameConstructor::ConstructFrame(IMediaSample* pSample, mfxBitstre
UpdateTimeStamp(pSample, pBS);
// Prefix the sequence headers if needed
size_t newDataSize = nDataSize + m_ResidualBS.DataLength +
size_t newDataSize = nDataSize + m_ResidialBS.DataLength +
((m_bSeqHeaderInserted) ? 0 : m_Headers.DataLength) + // Add headers size
8; // Add upto 8 bytes for extra start codes
@ -478,7 +478,7 @@ CAVCFrameConstructor::CAVCFrameConstructor()
m_HeaderNalSize = 2; //MSDN - MPEG2VideoInfo->dwSequenceHeader delimited by 2 byte length fields
m_NalSize = 0;
SetValue(0x01000000, m_H264StartCode);
m_TempBuffer.reserve(1<<20);
m_OutputBuffer.reserve(1<<20);
}
CAVCFrameConstructor::~CAVCFrameConstructor()
@ -504,43 +504,49 @@ mfxStatus CAVCFrameConstructor::ConstructHeaders(VIDEOINFOHEADER2* vih,
// SPS and/or PPS Data will be present
mfxStatus sts = MFX_ERR_NONE;
size_t nNalDataLen;
const mfxU8* pNalDataBuff;
CH264Nalu itStartCode;
MSDK_ZERO_VAR(m_Headers);
m_TempBuffer.clear();
m_OutputBuffer.clear();
m_NalSize = mp2->dwFlags;
H264_NaluIterator itStartCode((BYTE*)mp2->dwSequenceHeader, mp2->cbSequenceHeader, m_HeaderNalSize); // Nal size = 2
H264_NAL_RC rc;
bool eos = false;
itStartCode.SetBuffer((BYTE*)mp2->dwSequenceHeader, mp2->cbSequenceHeader, m_HeaderNalSize); // Nal size = 2
while (itStartCode.ReadNext())
{
nNalDataLen = itStartCode.GetDataLength();
pNalDataBuff = itStartCode.GetDataBuffer();
NALU_TYPE naluType = itStartCode.GetType();
switch (naluType)
while (!eos)
{
rc = itStartCode.Next();
NALU_TYPE naluType = itStartCode.GetNaluType();
switch (rc)
{
case NALU_TYPE_SPS:
case NALU_TYPE_PPS:
m_TempBuffer.insert(m_TempBuffer.end(), m_H264StartCode, m_H264StartCode + 4);
m_TempBuffer.insert(m_TempBuffer.end(), pNalDataBuff, pNalDataBuff+nNalDataLen);
break;
default:
// Only keep valid NALUs
if (IS_VALID_NALU(naluType))
case NALU_PARTIAL: // For headers, partials are fine (h264 extra data)
case NALU_OK:
{
sts = MFX_ERR_MORE_DATA;
size_t nNalDataLen = itStartCode.GetDataLength();
const BYTE* pNalDataBuff = itStartCode.GetDataBuffer();
if (naluType == NALU_TYPE_SPS || naluType == NALU_TYPE_PPS)
{
m_OutputBuffer.insert(m_OutputBuffer.end(), m_H264StartCode, m_H264StartCode + 4);
m_OutputBuffer.insert(m_OutputBuffer.end(), pNalDataBuff, pNalDataBuff+nNalDataLen);
}
}
break;
}
case NALU_EOS:
eos = true;
break;
case NALU_INVALID:
break;
} // switch
}
if (m_TempBuffer.size())
if (m_OutputBuffer.size())
{
// Keep a copy of the SPS/PPS to be placed into the decode stream (after each new segment).
MSDK_SAFE_DELETE_ARRAY(m_Headers.Data);
m_Headers.Data = new mfxU8[m_TempBuffer.size()];
m_Headers.DataLength = m_Headers.MaxLength = (mfxU32)m_TempBuffer.size();
memcpy(m_Headers.Data, &m_TempBuffer.front(), m_TempBuffer.size());
m_Headers.Data = new mfxU8[m_OutputBuffer.size()];
m_Headers.DataLength = m_Headers.MaxLength = (mfxU32)m_OutputBuffer.size();
memcpy(m_Headers.Data, &m_OutputBuffer.front(), m_OutputBuffer.size());
}
return sts;
@ -548,12 +554,6 @@ mfxStatus CAVCFrameConstructor::ConstructHeaders(VIDEOINFOHEADER2* vih,
mfxStatus CAVCFrameConstructor::ConstructFrame(IMediaSample* pSample, mfxBitstream* pBS)
{
// AnnexB style stream - just copy the buffer as is.
if (0 == m_NalSize)
{
return CFrameConstructor::ConstructFrame(pSample, pBS);
}
mfxU8* pDataBuffer = NULL;
MSDK_CHECK_POINTER(pSample, MFX_ERR_NULL_PTR);
MSDK_CHECK_POINTER(pBS, MFX_ERR_NULL_PTR);
@ -565,50 +565,77 @@ mfxStatus CAVCFrameConstructor::ConstructFrame(IMediaSample* pSample, mfxBitstre
pSample->GetPointer(&pDataBuffer);
MSDK_CHECK_POINTER(pDataBuffer, MFX_ERR_NULL_PTR);
m_TempBuffer.clear();
m_TempBuffer.reserve(nDataSize);
CH264Nalu itStartCode;
itStartCode.SetBuffer(pDataBuffer, nDataSize, m_NalSize); // Nal size = 4 (usually); declared in extra data (ConstructHeaders)
// Iterate over the NALUs and convert them to have start codes.
while (itStartCode.ReadNext())
if (!m_InputBuffer.empty())
{
NALU_TYPE naluType = itStartCode.GetType();
// Discard AUD NALUs
if (NALU_TYPE_AUD == naluType)
continue;
if (!IS_VALID_NALU(naluType))
continue;
size_t nNalDataLen = itStartCode.GetDataLength();
const BYTE* pNalDataBuff = itStartCode.GetDataBuffer();
ASSERT(nNalDataLen > 0); // Shouldn't fail!
if (nNalDataLen > 0)
{
m_TempBuffer.insert(m_TempBuffer.end(), m_H264StartCode, m_H264StartCode + 4);
m_TempBuffer.insert(m_TempBuffer.end(), pNalDataBuff, pNalDataBuff + nNalDataLen);
}
m_InputBuffer.insert(m_InputBuffer.end(), pDataBuffer, pDataBuffer + nDataSize);
pDataBuffer = &m_InputBuffer.front();
nDataSize = (mfxU32)m_InputBuffer.size();
}
if (m_TempBuffer.empty())
m_OutputBuffer.clear();
m_OutputBuffer.reserve(nDataSize);
H264_NaluIterator itStartCode(pDataBuffer, nDataSize, m_NalSize); // Nal size = 4 (usually); declared in extra data (ConstructHeaders)
bool eos = false;
// Iterate over the NALUs and convert them to have start codes.
while (!eos)
{
H264_NAL_RC rc = itStartCode.Next();
NALU_TYPE naluType = itStartCode.GetNaluType();
switch (rc)
{
case NALU_OK:
{
// Discard AUD NALUs
if (NALU_TYPE_AUD == naluType)
continue;
size_t nNalDataLen = itStartCode.GetDataLength();
const BYTE* pNalDataBuff = itStartCode.GetDataBuffer();
m_OutputBuffer.insert(m_OutputBuffer.end(), m_H264StartCode, m_H264StartCode + 4);
m_OutputBuffer.insert(m_OutputBuffer.end(), pNalDataBuff, pNalDataBuff + nNalDataLen);
}
break;
// Got partial NAL, save it for next run
// Note - The residial data buffer contains processed NALs.
// Here we need to save unprocessed NALs.
case NALU_PARTIAL:
{
std::vector<mfxU8> temp;
size_t start = (itStartCode.GetNALBuffer() - pDataBuffer);
temp.insert(temp.end(), pDataBuffer + start, pDataBuffer + nDataSize);
m_InputBuffer.swap(temp);
}
break;
case NALU_EOS:
eos = true;
break;
case NALU_INVALID: // discard
break;
} // switch
}
if (m_OutputBuffer.empty())
{
return MFX_ERR_NONE;
}
// Update data size
nDataSize = (mfxU32)m_TempBuffer.size();
pDataBuffer = &m_TempBuffer.front();
size_t newDataSize = nDataSize + m_ResidualBS.DataLength +
nDataSize = (mfxU32)m_OutputBuffer.size();
pDataBuffer = &m_OutputBuffer.front();
size_t newDataSize = nDataSize + m_ResidialBS.DataLength +
((m_bSeqHeaderInserted) ? 0 : m_Headers.DataLength);
mfxU8* pData = pBS->Data = new mfxU8[newDataSize];
pBS->MaxLength = (mfxU32)newDataSize;
// Write data left from previous samples
// Write data left from previous samples (processed data)
WriteResidualData(pData);
// Write sequence headers if needed
@ -620,3 +647,9 @@ mfxStatus CAVCFrameConstructor::ConstructFrame(IMediaSample* pSample, mfxBitstre
return MFX_ERR_NONE;
}
void CAVCFrameConstructor::Reset()
{
CFrameConstructor::Reset();
m_InputBuffer.clear();
}

View File

@ -50,7 +50,7 @@ protected:
bool m_bSeqHeaderInserted;
bool m_bDvdStripPackets;
mfxBitstream m_Headers;
mfxBitstream m_ResidualBS;
mfxBitstream m_ResidialBS;
};
////////////////////////////////////////////////////////////////////////////////////////////
@ -82,10 +82,12 @@ public:
const GUID& guidFormat,
size_t nMtSize,
size_t nVideoInfoSize);
void Reset();
private:
mfxU32 m_NalSize;
mfxU32 m_HeaderNalSize;
mfxU8 m_H264StartCode[4];
std::vector<mfxU8> m_TempBuffer; // used for building the output stream
std::vector<mfxU8> m_InputBuffer;
std::vector<mfxU8> m_OutputBuffer; // Used for building the output stream
};

View File

@ -11,6 +11,7 @@
#include <tchar.h>
#include <stdio.h>
#include <process.h>
#include <stdint.h>
// Platform SDK
#include <sdkddkver.h>