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:
parent
f81324d280
commit
c700e6b8a4
180
H264Nalu.cpp
180
H264Nalu.cpp
|
@ -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;
|
||||
}
|
||||
|
|
185
H264Nalu.h
185
H264Nalu.h
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue