diff --git a/DirectShowFilters/BDReader/BDReader.vcxproj b/DirectShowFilters/BDReader/BDReader.vcxproj
index 51daeb26d41..727a6f02089 100644
--- a/DirectShowFilters/BDReader/BDReader.vcxproj
+++ b/DirectShowFilters/BDReader/BDReader.vcxproj
@@ -353,6 +353,9 @@
+
+
+
@@ -377,6 +380,9 @@
+
+
+
diff --git a/DirectShowFilters/BDReader/source/BDReader.cpp b/DirectShowFilters/BDReader/source/BDReader.cpp
index 7ed561c2b9f..37017dc6cf1 100644
--- a/DirectShowFilters/BDReader/source/BDReader.cpp
+++ b/DirectShowFilters/BDReader/source/BDReader.cpp
@@ -319,6 +319,7 @@ STDMETHODIMP CBDReaderFilter::SetVideoDecoder(int format, GUID* decoder)
{
if (format != BLURAY_STREAM_TYPE_VIDEO_H264 &&
format != BLURAY_STREAM_TYPE_VIDEO_VC1 &&
+ format != BLURAY_STREAM_TYPE_VIDEO_HEVC &&
format != BLURAY_STREAM_TYPE_VIDEO_MPEG2)
return E_INVALIDARG;
diff --git a/DirectShowFilters/BDReader/source/Clip.cpp b/DirectShowFilters/BDReader/source/Clip.cpp
index ef4c7f80bf6..06c57605177 100644
--- a/DirectShowFilters/BDReader/source/Clip.cpp
+++ b/DirectShowFilters/BDReader/source/Clip.cpp
@@ -43,23 +43,21 @@ CClip::CClip(int clipNumber, int playlistNumber, REFERENCE_TIME firstPacketTime,
audioPlaybackPosition = playlistFirstPacketTime;
videoPlaybackPosition = playlistFirstPacketTime;
- earliestPacketAccepted = _I64_MAX;
+ m_rtEarliestPacketAccepted = _I64_MAX;
firstVideoPosition = _I64_MAX;
firstAudioPosition = _I64_MAX;
clipDuration = duration;
- clipPlaylistOffset = totalStreamOffset;
+ m_rtClipPlaylistOffset = totalStreamOffset;
m_rtStreamStartOffset = streamStartOffset;
m_playlistOffset = clipOffset;
m_rtPlayedDuration = 0;
m_rtPrevAudioStart = 0;
- m_rtClipVideoStartingOffset = 0LL;
- m_rtClipAudioStartingOffset = 0LL;
-
- m_bCalculateAudioOffset = true;
- m_bCalculateVideoOffset = true;
-
+ m_rtClipStartingOffset = 0LL;
+
+ m_bCalculateOffset = true;
+
noAudio =! audioPresent;
clipInterrupted = interrupted;
@@ -70,8 +68,8 @@ CClip::CClip(int clipNumber, int playlistNumber, REFERENCE_TIME firstPacketTime,
firstAudio = true;
firstVideo = true;
- firstPacketAccepted = false;
- firstPacketReturned = false;
+ m_bFirstPacketAccepted = false;
+ m_bFirstPacketReturned = false;
clipReset = false;
//LogDebug("CClip:: New Clip (%d,%d) stream Offset %I64d", nPlaylist, nClip, totalStreamOffset);
@@ -94,8 +92,8 @@ Packet* CClip::ReturnNextAudioPacket(REFERENCE_TIME playlistOffset)
if (noAudio)
{
ret = GenerateFakeAudio(audioPlaybackPosition);
- if (earliestPacketAccepted == INT64_MAX)
- earliestPacketAccepted = audioPlaybackPosition;
+ if (m_rtEarliestPacketAccepted == INT64_MAX)
+ m_rtEarliestPacketAccepted = audioPlaybackPosition;
}
else
{
@@ -122,20 +120,20 @@ Packet* CClip::ReturnNextAudioPacket(REFERENCE_TIME playlistOffset)
if (clipInterrupted)
ret->nNewSegment |= NS_INTERRUPTED;
- if (m_bCalculateAudioOffset && (abs(earliestPacketAccepted - ret->rtStart) > 0))
- m_rtClipAudioStartingOffset = earliestPacketAccepted - ret->rtStart;
+ if (m_bCalculateOffset && (abs(m_rtEarliestPacketAccepted - ret->rtStart) > 0))
+ m_rtClipStartingOffset = m_rtEarliestPacketAccepted - ret->rtStart;
- m_bCalculateAudioOffset = false;
+ m_bCalculateOffset = false;
}
- if (!firstPacketReturned)
- firstPacketReturned = true;
+ if (!m_bFirstPacketReturned)
+ m_bFirstPacketReturned = true;
ret->rtPlaylistTime = ret->rtStart - m_playlistOffset;
- ret->rtClipStartTime = ret->rtStart - earliestPacketAccepted + m_rtClipAudioStartingOffset;
- ret->rtStart += clipPlaylistOffset - earliestPacketAccepted + m_rtClipAudioStartingOffset;
- ret->rtStop += clipPlaylistOffset - earliestPacketAccepted + m_rtClipAudioStartingOffset;
+ ret->rtClipStartTime = ret->rtStart - m_rtEarliestPacketAccepted + m_rtClipStartingOffset;
+ ret->rtStart += m_rtClipPlaylistOffset - m_rtEarliestPacketAccepted + m_rtClipStartingOffset;
+ ret->rtStop += m_rtClipPlaylistOffset - m_rtEarliestPacketAccepted + m_rtClipStartingOffset;
if (m_rtPrevAudioStart == 0)
m_rtPrevAudioStart = ret->rtStart;
@@ -178,10 +176,10 @@ Packet* CClip::ReturnNextVideoPacket(REFERENCE_TIME playlistOffset)
firstVideo = false;
ret->pmt = CreateMediaType(m_videoPmt);
- if (m_bCalculateVideoOffset && (abs(earliestPacketAccepted - ret->rtStart) > 0))
- m_rtClipVideoStartingOffset = earliestPacketAccepted - ret->rtStart;
+ if (m_bCalculateOffset && (abs(m_rtEarliestPacketAccepted - ret->rtStart) > 0))
+ m_rtClipStartingOffset = m_rtEarliestPacketAccepted - ret->rtStart;
- m_bCalculateVideoOffset = false;
+ m_bCalculateOffset = false;
}
if (ret->rtStart > videoPlaybackPosition)
@@ -190,14 +188,14 @@ Packet* CClip::ReturnNextVideoPacket(REFERENCE_TIME playlistOffset)
//LogDebug("Videoplayback position (%d,%d) %I64d", nPlaylist, nClip, videoPlaybackPosition);
}
- if (!firstPacketReturned)
- firstPacketReturned = true;
+ if (!m_bFirstPacketReturned)
+ m_bFirstPacketReturned = true;
ret->rtPlaylistTime = ret->rtStart - m_playlistOffset;
- ret->rtClipStartTime = ret->rtStart - earliestPacketAccepted + m_rtClipVideoStartingOffset;
- ret->rtStart += clipPlaylistOffset - earliestPacketAccepted + m_rtClipVideoStartingOffset;
- ret->rtStop += clipPlaylistOffset - earliestPacketAccepted + m_rtClipVideoStartingOffset;
+ ret->rtClipStartTime = ret->rtStart - m_rtEarliestPacketAccepted + m_rtClipStartingOffset;
+ ret->rtStart += m_rtClipPlaylistOffset - m_rtEarliestPacketAccepted + m_rtClipStartingOffset;
+ ret->rtStop += m_rtClipPlaylistOffset - m_rtEarliestPacketAccepted + m_rtClipStartingOffset;
}
}
// LogDebug("Clip: vid: return Packet rtStart: %I64d offset: %I64d seekRequired %d",ret->rtStart, ret->rtOffset,ret->bSeekRequired);
@@ -245,10 +243,10 @@ Packet* CClip::GenerateFakeAudio(REFERENCE_TIME rtStart)
packet->pmt = CreateMediaType(&pmt);
}
- if (earliestPacketAccepted == INT64_MAX)
- earliestPacketAccepted = audioPlaybackPosition;
+ if (m_rtEarliestPacketAccepted == INT64_MAX)
+ m_rtEarliestPacketAccepted = audioPlaybackPosition;
- firstPacketAccepted = true;
+ m_bFirstPacketAccepted = true;
lastAudioPosition += FAKE_AUDIO_DURATION;
audioPlaybackPosition += FAKE_AUDIO_DURATION;
@@ -274,10 +272,12 @@ bool CClip::AcceptAudioPacket(Packet* packet)
else
{
//CAutoLock lock(m_sectionRead);
- if (!firstPacketReturned)
+ if (!m_bFirstPacketReturned)
{
- if (earliestPacketAccepted > packet->rtStart) earliestPacketAccepted = packet->rtStart;
- firstPacketAccepted = true;
+ if (m_rtEarliestPacketAccepted > packet->rtStart)
+ m_rtEarliestPacketAccepted = packet->rtStart;
+
+ m_bFirstPacketAccepted = true;
}
packet->nClipNumber = nClip;
@@ -304,12 +304,12 @@ bool CClip::AcceptVideoPacket(Packet* packet)
}
else
{
- if (!firstPacketReturned && packet->rtStart != Packet::INVALID_TIME && earliestPacketAccepted > packet->rtStart)
- earliestPacketAccepted = packet->rtStart;
+ if (!m_bFirstPacketReturned && packet->rtStart != Packet::INVALID_TIME && m_rtEarliestPacketAccepted > packet->rtStart)
+ m_rtEarliestPacketAccepted = packet->rtStart;
- if (!firstPacketAccepted && packet->rtStart != Packet::INVALID_TIME)
+ if (!m_bFirstPacketAccepted && packet->rtStart != Packet::INVALID_TIME)
{
- firstPacketAccepted = true;
+ m_bFirstPacketAccepted = true;
lastVideoPosition = packet->rtStart;
}
@@ -392,23 +392,22 @@ void CClip::Reset(REFERENCE_TIME totalStreamOffset)
lastVideoPosition = playlistFirstPacketTime;
lastAudioPosition = playlistFirstPacketTime;
- firstPacketAccepted ? clipReset = true : clipReset = false;
+ m_bFirstPacketAccepted ? clipReset = true : clipReset = false;
- clipPlaylistOffset = totalStreamOffset;
+ m_rtClipPlaylistOffset = totalStreamOffset;
audioPlaybackPosition = playlistFirstPacketTime;
videoPlaybackPosition = playlistFirstPacketTime;
- m_rtClipAudioStartingOffset = 0LL;
- m_rtClipVideoStartingOffset = 0LL;
+ m_rtClipStartingOffset = 0LL;
- earliestPacketAccepted = INT64_MAX;
+ m_rtEarliestPacketAccepted = INT64_MAX;
superseded = NO_SUPERSEDE;
firstAudio = true;
firstVideo = true;
- firstPacketAccepted = false;
- firstPacketReturned = false;
+ m_bFirstPacketAccepted = false;
+ m_bFirstPacketReturned = false;
}
bool CClip::HasAudio()
diff --git a/DirectShowFilters/BDReader/source/Clip.h b/DirectShowFilters/BDReader/source/Clip.h
index 79aeb09569f..cb9cbd5bdd6 100644
--- a/DirectShowFilters/BDReader/source/Clip.h
+++ b/DirectShowFilters/BDReader/source/Clip.h
@@ -63,7 +63,7 @@ class CClip
void Supersede(int supersedeType);
bool IsSuperseded(int supersedeType);
REFERENCE_TIME playlistFirstPacketTime;
- REFERENCE_TIME clipPlaylistOffset;
+ REFERENCE_TIME m_rtClipPlaylistOffset;
void Reset(REFERENCE_TIME totalStreamOffset);
bool HasAudio();
bool HasVideo();
@@ -85,7 +85,7 @@ class CClip
// starttime of the last video packet returned from the clip to the pin
REFERENCE_TIME videoPlaybackPosition;
- REFERENCE_TIME earliestPacketAccepted;
+ REFERENCE_TIME m_rtEarliestPacketAccepted;
// Clip duration as provided by libbluray
REFERENCE_TIME clipDuration;
@@ -98,9 +98,8 @@ class CClip
// Accurate clip starting time (when known).
// Not set when selecting chapter from the menu
- REFERENCE_TIME m_rtClipAudioStartingOffset;
- REFERENCE_TIME m_rtClipVideoStartingOffset;
-
+ REFERENCE_TIME m_rtClipStartingOffset;
+
// true would indicate that this is the first audio packet
bool firstAudio;
// true would indicate that this is the first video packet
@@ -120,13 +119,12 @@ class CClip
CCritSec m_sectionVectorAudio;
CCritSec m_sectionVectorVideo;
- bool m_bCalculateAudioOffset;
- bool m_bCalculateVideoOffset;
+ bool m_bCalculateOffset;
// indicates if this is the first packet to be buffered in clip
- bool firstPacketAccepted;
+ bool m_bFirstPacketAccepted;
// indicates if this is the first packet to be returned from the clip
- bool firstPacketReturned;
+ bool m_bFirstPacketReturned;
REFERENCE_TIME m_rtPrevAudioStart;
REFERENCE_TIME m_rtPlayedDuration; // Do not zero on reset as this should be cumulative
diff --git a/DirectShowFilters/BDReader/source/DeMultiplexer.cpp b/DirectShowFilters/BDReader/source/DeMultiplexer.cpp
index 957a7fb9c22..771f1df06a0 100644
--- a/DirectShowFilters/BDReader/source/DeMultiplexer.cpp
+++ b/DirectShowFilters/BDReader/source/DeMultiplexer.cpp
@@ -812,7 +812,7 @@ void CDeMultiplexer::FlushPESBuffers(bool bDiscardData, bool bSetCurrentClipFill
if (m_videoServiceType == BLURAY_STREAM_TYPE_VIDEO_MPEG1 ||
m_videoServiceType == BLURAY_STREAM_TYPE_VIDEO_MPEG2)
FillVideoMPEG2(NULL, NULL, true);
- else if (m_videoServiceType == BLURAY_STREAM_TYPE_VIDEO_H264)
+ else if (m_videoServiceType == BLURAY_STREAM_TYPE_VIDEO_H264 || m_videoServiceType == BLURAY_STREAM_TYPE_VIDEO_HEVC)
FillVideoH264PESPacket(NULL, m_pBuild, true);
else if (m_videoServiceType == BLURAY_STREAM_TYPE_VIDEO_VC1)
FillVideoVC1PESPacket(NULL, m_pBuild, true);
@@ -996,10 +996,22 @@ void CDeMultiplexer::FillVideoH264PESPacket(CTsHeader* header, CAutoPtr
if (!pData)
continue;
- if ((pData[4]&0x1f) == 0x09)
- m_fHasAccessUnitDelimiters = true;
+ bool bFlag = false;
+ if (m_videoServiceType == BLURAY_STREAM_TYPE_VIDEO_HEVC)
+ {
+ if (((pData[4] >> 1) & 0x3f) == HEVC::NAL_AUD)
+ {
+ m_fHasAccessUnitDelimiters = true;
+ bFlag = true;
+ }
+ }
+ else if ((pData[4] & 0x1f) == NALU_TYPE_AUD)
+ {
+ m_fHasAccessUnitDelimiters = true;
+ bFlag = true;
+ }
- if ((pData[4]&0x1f) == 0x09 || !m_fHasAccessUnitDelimiters && pPacket->rtStart != Packet::INVALID_TIME)
+ if (bFlag || !m_fHasAccessUnitDelimiters && pPacket->rtStart != Packet::INVALID_TIME)
{
p = m_pl.RemoveHead();
@@ -1263,8 +1275,8 @@ void CDeMultiplexer::FillVideoH264(CTsHeader* header, byte* tsPacket)
if (m_pBuild->GetCount() && m_videoServiceType != BLURAY_STREAM_TYPE_VIDEO_VC1)
{
- FillVideoH264PESPacket(header, m_pBuild);
- m_pBuild.Free();
+ FillVideoH264PESPacket(header, m_pBuild);
+ m_pBuild.Free();
}
}
@@ -1716,6 +1728,8 @@ char* CDeMultiplexer::StreamFormatAsString(int pStreamType)
return "H264";
case BLURAY_STREAM_TYPE_VIDEO_VC1:
return "VC1";
+ case BLURAY_STREAM_TYPE_VIDEO_HEVC:
+ return "HEVC";
case BLURAY_STREAM_TYPE_AUDIO_LPCM:
return "LPCM";
case BLURAY_STREAM_TYPE_AUDIO_AC3:
diff --git a/DirectShowFilters/BDReader/source/FrameHeaderParser.cpp b/DirectShowFilters/BDReader/source/FrameHeaderParser.cpp
index fa2ade00410..cf317bc16ac 100644
--- a/DirectShowFilters/BDReader/source/FrameHeaderParser.cpp
+++ b/DirectShowFilters/BDReader/source/FrameHeaderParser.cpp
@@ -35,12 +35,16 @@
#include
#include
#include
+#include "HEVC\Hevc.h"
+#include "HEVC\HevcNalDecode.h"
// For more details for memory leak detection see the alloctracing.h header
#include "..\..\alloctracing.h"
extern void LogDebug(const char *fmt, ...) ;
+#define LOG_HEVC_FHP //LogDebug
+
#define countof(array) (sizeof(array)/sizeof(array[0]))
#define DNew new
@@ -48,6 +52,14 @@ extern void LogDebug(const char *fmt, ...) ;
#define TRUEHD_SYNC_WORD 0xf8726f
+//AVC Chroma format IDC definitions
+#define YUV400 0
+#define YUV420 1
+#define YUV422 2
+#define YUV444 3
+
+using namespace HEVC;
+
// LR C LFE LRs LRvh LRc LRrs Cs Ts LRsd LRw Cvh LFE2
static const UINT8 thd_chancount[13] = {2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1};
static const UINT8 mlp_quants[16] = {16, 20, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
@@ -1665,6 +1677,187 @@ bool CFrameHeaderParser::Read(avchdr& h, int len, CMediaType* pmt)
return true;
}
+bool CFrameHeaderParser::Read(hevchdr& h, int len, CMediaType* pmt)
+{
+ if ((len <= 6) || (len > 65534))
+ return(false); //Sanity check
+
+ memset(&h, 0, sizeof(h));
+ h.progressive = true;
+ h.AvgTimePerFrame = 370000; //27 Hz
+
+ while (GetRemaining() > 4 && (h.spslen == 0 || h.ppslen == 0 || h.vpslen == 0))
+ {
+ const int nal_len = BitRead(32);
+ const INT64 nal_pos = GetPos();
+ const INT64 next_nal = nal_pos + nal_len;
+
+ NALUnitType nal_type = HevcNalDecode::processNALUnit(GetBufferPos(), nal_len, h);
+
+ if (nal_type == NAL_FAIL) //NAL decoding error
+ {
+ return(false);
+ }
+ else if (nal_type == NAL_SPS)
+ {
+ LOG_HEVC_FHP("SPS found");
+ //Copy SPS to buffer
+ h.sps = (BYTE*)malloc(nal_len);
+ if (h.sps == NULL)
+ {
+ //malloc error...
+ h.spslen = 0;
+ return(false);
+ }
+ ByteRead(h.sps, nal_len);
+ h.spslen = nal_len;
+ }
+ else if (nal_type == NAL_PPS)
+ {
+ LOG_HEVC_FHP("PPS found");
+ //Copy PPS to new buffer
+ h.pps = (BYTE*)malloc(nal_len);
+ if (h.pps == NULL)
+ {
+ //malloc error...
+ h.ppslen = 0;
+ return(false);
+ }
+ ByteRead(h.pps, nal_len);
+ h.ppslen = nal_len;
+ }
+ else if (nal_type == NAL_VPS)
+ {
+ LOG_HEVC_FHP("VPS found");
+ //Copy VPS to new buffer
+ h.vps = (BYTE*)malloc(nal_len);
+ if (h.vps == NULL)
+ {
+ //malloc error...
+ h.vpslen = 0;
+ return(false);
+ }
+ ByteRead(h.vps, nal_len);
+ h.vpslen = nal_len;
+ }
+
+ Seek(next_nal);
+ }
+
+ if (!h.spslen || !h.ppslen || !h.vpslen || h.height < 100 || h.width < 100 || h.AvgTimePerFrame < 1000)
+ return(false);
+
+ if (!pmt)
+ return(true);
+
+ {
+
+ int extra = h.spslen + 4 + h.ppslen + 4 + h.vpslen + 4;
+ pmt->SetType(&MEDIATYPE_Video);
+ //pmt->SetSubtype(&MEDIASUBTYPE_H264);
+ pmt->SetSubtype(&HEVC_SubType);
+ pmt->formattype = FORMAT_MPEG2_VIDEO;
+ pmt->bTemporalCompression = true;
+
+ int len = FIELD_OFFSET(MPEG2VIDEOINFO, dwSequenceHeader) + extra;
+ MPEG2VIDEOINFO* vi = (MPEG2VIDEOINFO*)pmt->AllocFormatBuffer(len);
+ memset(vi, 0, len);
+ vi->hdr.AvgTimePerFrame = h.AvgTimePerFrame;
+
+ /*
+ h.ar=h.width/h.height;
+ struct {DWORD x, y;} ar[] = {{h.width,h.height},{4,3},{16,9},{221,100},{h.width,h.height}};
+ int i = min(max(h.ar, 1), 5)-1;
+ */
+ struct { DWORD x, y; } ar[] = { {1,1},{1,1},{12,11},{10,11},{16,11},{40,33},{24,11},{20,11},{32,11},{80,33},{18,11},{15,11},{64,33},{160,99},{1,1},{1,1} };
+ if (h.ar == 255)
+ {
+ // make sure that both are 0 or none
+ if (h.arx == 0 || h.ary == 0)
+ h.arx = h.ary = 0;
+ // h.arx and h.ary now contain sample aspect ratio
+ }
+ else if (h.ar < 1 || h.ar > 13)
+ {
+ // aspect ratio unspecified or reserved
+ h.ar = 0;
+ h.arx = h.ary = 0;
+ }
+ else
+ {
+ // use preset aspect ratio
+ h.arx = ar[h.ar].x;
+ h.ary = ar[h.ar].y;
+ }
+
+ h.arx *= h.width;
+ h.ary *= h.height;
+
+ DWORD a = h.arx, b = h.ary;
+ while (a) { DWORD tmp = a; a = b % tmp; b = tmp; }
+ if (b) h.arx /= b, h.ary /= b;
+ vi->hdr.dwPictAspectRatioX = h.arx;
+ vi->hdr.dwPictAspectRatioY = h.ary;
+ vi->hdr.bmiHeader.biSize = sizeof(vi->hdr.bmiHeader);
+ vi->hdr.bmiHeader.biWidth = h.width;
+ vi->hdr.bmiHeader.biHeight = h.height;
+ vi->hdr.rcSource.right = h.width;
+ vi->hdr.rcSource.bottom = h.height;
+ vi->hdr.rcTarget.right = h.width;
+ vi->hdr.rcTarget.bottom = h.height;
+ vi->hdr.bmiHeader.biCompression = 'CVEH';
+ vi->hdr.bmiHeader.biPlanes = 1;
+
+
+ switch (h.chromaFormat)
+ {
+ case YUV420:
+ vi->hdr.bmiHeader.biBitCount = h.lumaDepth + (h.chromaDepth / 2);
+ break;
+ case YUV422:
+ vi->hdr.bmiHeader.biBitCount = h.lumaDepth + h.chromaDepth;
+ break;
+ case YUV444:
+ vi->hdr.bmiHeader.biBitCount = h.lumaDepth + (2 * h.chromaDepth);
+ break;
+ case YUV400: //Monochrome
+ vi->hdr.bmiHeader.biBitCount = h.lumaDepth;
+ break;
+ default:
+ vi->hdr.bmiHeader.biBitCount = h.lumaDepth + (h.chromaDepth / 2);
+ }
+
+ vi->hdr.bmiHeader.biClrUsed = 0;
+ vi->hdr.bmiHeader.biSizeImage = DIBSIZE(vi->hdr.bmiHeader);
+ vi->dwProfile = h.profile;
+ vi->dwFlags = 0;
+ vi->dwLevel = h.level;
+ vi->cbSequenceHeader = extra;
+ vi->dwStartTimeCode = 0;
+ BYTE* p = (BYTE*)&vi->dwSequenceHeader[0];
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 1;
+ memcpy(p, h.sps, (size_t)h.spslen);
+ p += h.spslen;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 1;
+ memcpy(p, h.pps, (size_t)h.ppslen);
+ p += h.ppslen;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 1;
+ memcpy(p, h.vps, (size_t)h.vpslen);
+
+ pmt->SetFormat((BYTE*)vi, len);
+ }
+
+ return true;
+}
bool CFrameHeaderParser::Read(vc1hdr& h, int len, CMediaType* pmt)
{
@@ -1994,10 +2187,10 @@ bool CFrameHeaderParser::Read(bdlpcmhdr& h, int len, CMediaType* pmt)
wfe.Samples.wSamplesPerBlock = 0;
wfe.Samples.wValidBitsPerSample = bitspersample[h.bitpersample];
- wfe.SubFormat = MEDIASUBTYPE_PCM;
+ wfe.SubFormat = MEDIASUBTYPE_BD_LPCM_AUDIO; //MEDIASUBTYPE_PCM;
pmt->majortype = MEDIATYPE_Audio;
- pmt->subtype = MEDIASUBTYPE_PCM;
+ pmt->subtype = MEDIASUBTYPE_BD_LPCM_AUDIO; //MEDIASUBTYPE_PCM;
pmt->formattype = FORMAT_WaveFormatEx;
pmt->SetFormat((BYTE*)&wfe, sizeof(wfe));
@@ -2042,4 +2235,3 @@ void CFrameHeaderParser::DumpAvcHeader(avchdr h)
*/
LogDebug("=================================");
}
-
diff --git a/DirectShowFilters/BDReader/source/FrameHeaderParser.h b/DirectShowFilters/BDReader/source/FrameHeaderParser.h
index f539e750fa7..9247ce42845 100644
--- a/DirectShowFilters/BDReader/source/FrameHeaderParser.h
+++ b/DirectShowFilters/BDReader/source/FrameHeaderParser.h
@@ -29,6 +29,11 @@
#include
#include "GolombBuffer.h"
+#include "HEVC\Hevc.h"
+#include "HEVC\HevcNalDecode.h"
+
+using namespace HEVC;
+
static const byte pixel_aspect[17][2]={
{0, 1},
{1, 1},
@@ -429,7 +434,7 @@ struct BasicVideoInfo
}
};
-class CFrameHeaderParser:public CGolombBuffer
+class CFrameHeaderParser:public CGolombBuffer, public HEVC::HevcNalDecode
{
int m_tslen; // transport stream packet length (188 or 192 bytes, auto-detected)
@@ -460,6 +465,7 @@ class CFrameHeaderParser:public CGolombBuffer
bool Read(vc1hdr& h, int len, CMediaType* pmt = NULL);
bool Read(bdlpcmhdr& h, int len, CMediaType* pmt = NULL);
bool Read(thdhdr& h, int len, CMediaType* pmt = NULL);
+ bool Read(hevchdr& h, int len, CMediaType* pmt);
void RemoveMpegEscapeCode(BYTE* dst, BYTE* src, int length);
diff --git a/DirectShowFilters/BDReader/source/HEVC/BitstreamReader.cpp b/DirectShowFilters/BDReader/source/HEVC/BitstreamReader.cpp
new file mode 100644
index 00000000000..838dbf147a8
--- /dev/null
+++ b/DirectShowFilters/BDReader/source/HEVC/BitstreamReader.cpp
@@ -0,0 +1,189 @@
+// Copyright (C) 2016 Team MediaPortal
+// http://www.team-mediaportal.com
+//
+// MediaPortal 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.
+//
+// MediaPortal 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 MediaPortal. If not, see .
+
+// ========================================================================
+// The code in this file is derived from the 'HEVCESBrowser' project,
+// a tool for analyzing HEVC(h265) bitstreams authored by 'virinext'.
+// See https://github.com/virinext/hevcesbrowser
+// and http://www.codeproject.com/Tips/896030/The-Structure-of-HEVC-Video
+// Licensed under the GNU General Public License and
+// the Code Project Open License, http://www.codeproject.com/info/cpol10.aspx
+// ========================================================================
+
+
+#include "BitstreamReader.h"
+
+#include
+#include
+#include
+
+
+BitstreamReader::BitstreamReader(const uint8_t *ptr, std::size_t size):
+ m_ptr(ptr)
+ ,m_size(size)
+ ,m_posBase(0)
+ ,m_posInBase(CHAR_BIT - 1)
+{
+}
+
+std::size_t BitstreamReader::available()
+{
+ return (m_size - m_posBase -1) * CHAR_BIT + m_posInBase + 1;
+}
+
+std::size_t BitstreamReader::availableInNalU()
+{
+ std::size_t pos = m_posBase;
+ if(m_posInBase)
+ pos++;
+ for(; pos<(m_size - 3); pos++)
+ {
+ bool naluFinded = m_ptr[pos] == 0 && m_ptr[pos+1] == 0 && m_ptr[pos+2] == 1;
+
+ if(!naluFinded)
+ {
+ if(m_size - pos >= 4 && m_ptr[pos] == 0 && m_ptr[pos+1] == 0 && m_ptr[pos+2] == 0 && m_ptr[pos+3] == 1)
+ naluFinded = true;
+ }
+
+ if(naluFinded)
+ {
+ return (pos - m_posBase - 1) * CHAR_BIT + m_posInBase + 1;
+ }
+
+ }
+
+ return m_size;
+}
+
+
+bool BitstreamReader::getBit()
+{
+ if(m_posBase >= m_size)
+ throw std::runtime_error("BitstreamReader: not enough data");
+
+ bool res = (m_ptr[m_posBase] & (1 << m_posInBase)) != 0;
+
+ m_posInBase--;
+
+ if(m_posInBase > CHAR_BIT)
+ {
+ m_posInBase = CHAR_BIT-1;
+ m_posBase++;
+
+ if(m_posBase >= 2)
+ {
+ if(m_ptr[m_posBase - 2] == 0 && m_ptr[m_posBase - 1] == 0 && m_ptr[m_posBase] == 3)
+ m_posBase++;
+ }
+ }
+
+ return res;
+}
+
+
+uint32_t BitstreamReader::getBits(std::size_t num)
+{
+ assert(num <= 32);
+
+ uint32_t result = 0;
+ for(std::size_t i=0; i= 2)
+ {
+ if(m_ptr[m_posBase - 2] == 0 && m_ptr[m_posBase - 1] == 0 && m_ptr[m_posBase] == 3)
+ m_posBase++;
+ }
+
+ uint32_t scipBytes = (uint32_t)(num / 8);
+
+
+ while(scipBytes)
+ {
+ scipBytes--;
+ m_posBase++;
+ if(m_posBase >= 2)
+ {
+ if(m_ptr[m_posBase - 2] == 0 && m_ptr[m_posBase - 1] == 0 && m_ptr[m_posBase] == 3)
+ m_posBase++;
+ }
+ }
+
+ if(m_posInBase > num % 8)
+ m_posInBase -= num % 8;
+ else
+ {
+ m_posBase++;
+ m_posInBase = m_posInBase - num % 8 + 8;
+ }
+
+}
+
+uint32_t BitstreamReader::showBits(std::size_t num)
+{
+ assert(num <= 32);
+
+ std::size_t posBasePrev = m_posBase;
+ std::size_t posInBasePrev = m_posInBase;
+
+ uint32_t result = 0;
+ for(std::size_t i=0; i= 32)
+ return 0;
+// throw std::range_error("Golomb: size of value more then 32 bits");
+
+ return (1 << numZeroBits) - 1 + getBits(numZeroBits);
+}
+
+
+
+int32_t BitstreamReader::getGolombS()
+{
+ int32_t buf = getGolombU();
+
+ if (buf & 1)
+ buf = (buf + 1) >> 1;
+ else
+ buf = -(buf >> 1);
+
+ return buf;
+}
+
diff --git a/DirectShowFilters/BDReader/source/HEVC/BitstreamReader.h b/DirectShowFilters/BDReader/source/HEVC/BitstreamReader.h
new file mode 100644
index 00000000000..556ba2ebcf8
--- /dev/null
+++ b/DirectShowFilters/BDReader/source/HEVC/BitstreamReader.h
@@ -0,0 +1,54 @@
+// Copyright (C) 2016 Team MediaPortal
+// http://www.team-mediaportal.com
+//
+// MediaPortal 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.
+//
+// MediaPortal 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 MediaPortal. If not, see .
+
+// ========================================================================
+// The code in this file is derived from the 'HEVCESBrowser' project,
+// a tool for analyzing HEVC(h265) bitstreams authored by 'virinext'.
+// See https://github.com/virinext/hevcesbrowser
+// and http://www.codeproject.com/Tips/896030/The-Structure-of-HEVC-Video
+// Licensed under the GNU General Public License and
+// the Code Project Open License, http://www.codeproject.com/info/cpol10.aspx
+// ========================================================================
+
+#ifndef BITSTREAM_READER_H_
+#define BITSTREAM_READER_H_
+
+#include
+#include
+
+class BitstreamReader
+{
+public:
+ BitstreamReader(const uint8_t *ptr, std::size_t size);
+ bool getBit();
+ uint32_t getBits(std::size_t num);
+ void skipBits(std::size_t num);
+ uint32_t showBits(std::size_t num);
+ uint32_t getGolombU();
+ int32_t getGolombS();
+
+ std::size_t available();
+ std::size_t availableInNalU();
+
+private:
+ const uint8_t *m_ptr;
+ std::size_t m_size;
+ std::size_t m_posBase;
+ std::size_t m_posInBase;
+};
+
+
+#endif
\ No newline at end of file
diff --git a/DirectShowFilters/BDReader/source/HEVC/Hevc.cpp b/DirectShowFilters/BDReader/source/HEVC/Hevc.cpp
new file mode 100644
index 00000000000..25cffabeb02
--- /dev/null
+++ b/DirectShowFilters/BDReader/source/HEVC/Hevc.cpp
@@ -0,0 +1,339 @@
+// Copyright (C) 2016 Team MediaPortal
+// http://www.team-mediaportal.com
+//
+// MediaPortal 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.
+//
+// MediaPortal 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 MediaPortal. If not, see .
+
+// ========================================================================
+// The code in this file is derived from the 'HEVCESBrowser' project,
+// a tool for analyzing HEVC(h265) bitstreams authored by 'virinext'.
+// See https://github.com/virinext/hevcesbrowser
+// and http://www.codeproject.com/Tips/896030/The-Structure-of-HEVC-Video
+// Licensed under the GNU General Public License and
+// the Code Project Open License, http://www.codeproject.com/info/cpol10.aspx
+// ========================================================================
+
+#include "Hevc.h"
+
+#include
+
+using namespace HEVC;
+
+NALUnit::NALUnit(NALUnitType type):
+ m_nalUnitType(type)
+ ,m_processFailed(false)
+{
+}
+
+
+NALUnit::~NALUnit()
+{
+}
+
+
+NALUnitType NALUnit::getType() const
+{
+ return m_nalUnitType;
+}
+
+
+
+HEVC::VPS::VPS(): NALUnit(HEVC::NAL_VPS)
+{
+ toDefault();
+}
+
+
+HEVC::SPS::SPS(): NALUnit(NAL_SPS)
+{
+ toDefault();
+}
+
+
+HEVC::PPS::PPS(): NALUnit(NAL_PPS)
+{
+ toDefault();
+};
+
+
+HEVC::AUD::AUD(): NALUnit(NAL_AUD)
+{
+ toDefault();
+};
+
+
+void ProfileTierLevel::toDefault()
+{
+ general_profile_space = 0;
+ general_tier_flag = 0;
+ general_profile_idc = 0;
+ general_profile_compatibility_flag[32];
+ general_progressive_source_flag = 0;
+ general_interlaced_source_flag = 0;
+ general_non_packed_constraint_flag = 0;
+ general_frame_only_constraint_flag = 0;
+ general_level_idc = 0;
+ sub_layer_profile_present_flag.clear();
+ sub_layer_level_present_flag.clear();
+ sub_layer_profile_space.clear();
+ sub_layer_tier_flag.clear();
+ sub_layer_profile_idc.clear();
+ sub_layer_profile_compatibility_flag.clear();
+ sub_layer_progressive_source_flag.clear();
+ sub_layer_interlaced_source_flag.clear();
+ sub_layer_non_packed_constraint_flag.clear();
+ sub_layer_frame_only_constraint_flag.clear();
+ sub_layer_level_idc.clear();
+}
+
+
+void SubLayerHrdParameters::toDefault()
+{
+ bit_rate_value_minus1.clear();
+ cpb_size_value_minus1.clear();
+ cpb_size_du_value_minus1.clear();
+ bit_rate_du_value_minus1.clear();
+ cbr_flag.clear();
+}
+
+
+void HrdParameters::toDefault()
+{
+ nal_hrd_parameters_present_flag = 0;
+ vcl_hrd_parameters_present_flag = 0;
+ sub_pic_hrd_params_present_flag = 0;
+ tick_divisor_minus2 = 0;
+ du_cpb_removal_delay_increment_length_minus1 = 0;
+ sub_pic_cpb_params_in_pic_timing_sei_flag = 0;
+ dpb_output_delay_du_length_minus1 = 0;
+ bit_rate_scale = 0;
+ cpb_size_scale = 0;
+ cpb_size_du_scale = 0;
+ initial_cpb_removal_delay_length_minus1 = 23;
+ au_cpb_removal_delay_length_minus1 = 23;
+ dpb_output_delay_length_minus1 = 23;
+ fixed_pic_rate_general_flag.clear();
+ fixed_pic_rate_within_cvs_flag.clear();
+ elemental_duration_in_tc_minus1.clear();
+ low_delay_hrd_flag.clear();
+ cpb_cnt_minus1.clear();
+ nal_sub_layer_hrd_parameters.clear();
+ vcl_sub_layer_hrd_parameters.clear();
+}
+
+
+void ShortTermRefPicSet::toDefault()
+{
+ inter_ref_pic_set_prediction_flag = 0;
+ delta_idx_minus1 = 0;
+ delta_rps_sign = 0;
+ abs_delta_rps_minus1 = 0;
+ used_by_curr_pic_flag.clear();
+ use_delta_flag.clear();
+ num_negative_pics = 0;
+ num_positive_pics = 0;
+ delta_poc_s0_minus1.clear();
+ used_by_curr_pic_s0_flag.clear();
+ delta_poc_s1_minus1.clear();
+ used_by_curr_pic_s1_flag.clear();
+}
+
+
+
+void VuiParameters::toDefault()
+{
+ aspect_ratio_info_present_flag = 0;
+ aspect_ratio_idc = 0;
+ sar_width = 0;
+ sar_height = 0;
+ overscan_info_present_flag = 0;
+ overscan_appropriate_flag = 0;
+ video_signal_type_present_flag = 0;
+ video_format = 5;
+ video_full_range_flag = 0;
+ colour_description_present_flag = 0;
+ colour_primaries = 2;
+ transfer_characteristics = 2;
+ matrix_coeffs = 2;
+ chroma_loc_info_present_flag = 0;
+ chroma_sample_loc_type_top_field = 0;
+ chroma_sample_loc_type_bottom_field = 0;
+ neutral_chroma_indication_flag = 0;
+ field_seq_flag = 0;
+ frame_field_info_present_flag = 0;
+ default_display_window_flag = 0;
+ def_disp_win_left_offset = 0;
+ def_disp_win_right_offset = 0;
+ def_disp_win_top_offset = 0;
+ def_disp_win_bottom_offset = 0;
+ vui_timing_info_present_flag = 0;
+ vui_num_units_in_tick = 0;
+ vui_time_scale = 0;
+ vui_poc_proportional_to_timing_flag = 0;
+ vui_num_ticks_poc_diff_one_minus1 = 0;
+ vui_hrd_parameters_present_flag = 0;
+ hrd_parameters.toDefault();
+ bitstream_restriction_flag = 0;
+ tiles_fixed_structure_flag = 0;
+ motion_vectors_over_pic_boundaries_flag = 0;
+ restricted_ref_pic_lists_flag = 0;
+ min_spatial_segmentation_idc = 0;
+ max_bytes_per_pic_denom = 2;
+ max_bits_per_min_cu_denom = 1;
+ log2_max_mv_length_horizontal = 15;
+ log2_max_mv_length_vertical = 15;
+}
+
+
+
+void VPS::toDefault()
+{
+ vps_video_parameter_set_id = 0;
+ vps_max_layers_minus1 = 0;
+ vps_max_sub_layers_minus1 = 0;
+ vps_temporal_id_nesting_flag = 0;
+ profile_tier_level.toDefault();
+ vps_sub_layer_ordering_info_present_flag = 0;
+ vps_max_dec_pic_buffering_minus1.clear();
+ vps_max_num_reorder_pics.clear();
+ vps_max_latency_increase_plus1.clear();
+ vps_max_layer_id = 0;
+ vps_num_layer_sets_minus1 = 0;
+ layer_id_included_flag.clear();
+ vps_timing_info_present_flag = 0;
+ vps_num_units_in_tick = 0;
+ vps_time_scale = 0;
+ vps_poc_proportional_to_timing_flag = 0;
+ vps_num_ticks_poc_diff_one_minus1 = 0;
+ vps_num_hrd_parameters = 0;
+ hrd_layer_set_idx.clear();
+ cprms_present_flag.clear();
+ hrd_parameters.clear();
+ vps_extension_flag = 0;
+}
+
+
+void SPS::toDefault()
+{
+ sps_video_parameter_set_id = 0;
+ sps_max_sub_layers_minus1 = 0;
+ sps_temporal_id_nesting_flag = 0;
+ profile_tier_level.toDefault();
+ sps_seq_parameter_set_id = 0;
+ chroma_format_idc = 0;
+ separate_colour_plane_flag = 0;
+ pic_width_in_luma_samples = 0;
+ pic_height_in_luma_samples = 0;
+ conformance_window_flag = 0;
+ conf_win_left_offset = 0;
+ conf_win_right_offset = 0;
+ conf_win_top_offset = 0;
+ conf_win_bottom_offset = 0;
+ bit_depth_luma_minus8 = 0;
+ bit_depth_chroma_minus8 = 0;
+ log2_max_pic_order_cnt_lsb_minus4 = 0;
+ sps_sub_layer_ordering_info_present_flag = 0;
+ sps_max_dec_pic_buffering_minus1.clear();
+ sps_max_num_reorder_pics.clear();
+ sps_max_latency_increase_plus1.clear();
+ log2_min_luma_coding_block_size_minus3 = 0;
+ log2_diff_max_min_luma_coding_block_size = 0;
+ log2_min_transform_block_size_minus2 = 0;
+ log2_diff_max_min_transform_block_size = 0;
+ max_transform_hierarchy_depth_inter = 0;
+ max_transform_hierarchy_depth_intra = 0;
+ scaling_list_enabled_flag = 0;
+ scaling_list_data.toDefault();
+ sps_scaling_list_data_present_flag = 0;
+ amp_enabled_flag = 0;
+ sample_adaptive_offset_enabled_flag = 0;
+ pcm_enabled_flag = 0;
+ pcm_sample_bit_depth_luma_minus1 = 0;
+ pcm_sample_bit_depth_chroma_minus1 = 0;
+ log2_min_pcm_luma_coding_block_size_minus3 = 0;
+ log2_diff_max_min_pcm_luma_coding_block_size = 0;
+ pcm_loop_filter_disabled_flag = 0;
+ num_short_term_ref_pic_sets = 0;
+ short_term_ref_pic_set.clear();
+ long_term_ref_pics_present_flag = 0;
+ num_long_term_ref_pics_sps = 0;
+ lt_ref_pic_poc_lsb_sps.clear();
+ used_by_curr_pic_lt_sps_flag.clear();
+ sps_temporal_mvp_enabled_flag = 0;
+ strong_intra_smoothing_enabled_flag = 0;
+ vui_parameters_present_flag = 0;
+ vui_parameters.toDefault();
+ sps_extension_flag = 0;
+}
+
+
+
+void PPS::toDefault()
+{
+ pps_pic_parameter_set_id = 0;
+ pps_seq_parameter_set_id = 0;
+ dependent_slice_segments_enabled_flag = 0;
+ output_flag_present_flag = 0;
+ num_extra_slice_header_bits = 0;
+ sign_data_hiding_flag = 0;
+ cabac_init_present_flag = 0;
+ num_ref_idx_l0_default_active_minus1 = 0;
+ num_ref_idx_l1_default_active_minus1 = 0;
+ init_qp_minus26 = 0;
+ constrained_intra_pred_flag = 0;
+ transform_skip_enabled_flag = 0;
+ cu_qp_delta_enabled_flag = 0;
+ diff_cu_qp_delta_depth = 0;
+ pps_cb_qp_offset = 0;
+ pps_cr_qp_offset = 0;
+ pps_slice_chroma_qp_offsets_present_flag = 0;
+ weighted_pred_flag = 0;
+ weighted_bipred_flag = 0;
+ transquant_bypass_enabled_flag = 0;
+ tiles_enabled_flag = 0;
+ entropy_coding_sync_enabled_flag = 0;
+ num_tile_columns_minus1 = 0;
+ num_tile_rows_minus1 = 0;
+ uniform_spacing_flag = 1;
+ column_width_minus1.clear();
+ row_height_minus1.clear();
+ loop_filter_across_tiles_enabled_flag = 0;
+ pps_loop_filter_across_slices_enabled_flag = 0;
+ deblocking_filter_control_present_flag = 0;
+ deblocking_filter_override_enabled_flag = 0;
+ pps_deblocking_filter_disabled_flag = 0;
+ pps_beta_offset_div2 = 0;
+ pps_tc_offset_div2 = 0;
+ pps_scaling_list_data_present_flag = 0;
+ lists_modification_present_flag = 0;
+ log2_parallel_merge_level_minus2 = 0;
+ slice_segment_header_extension_present_flag = 0;
+ pps_extension_flag = 0;
+}
+
+
+void ScalingListData::toDefault()
+{
+ scaling_list_delta_coef.clear();
+ scaling_list_pred_mode_flag.clear();
+ scaling_list_pred_matrix_id_delta.clear();
+ scaling_list_dc_coef_minus8.clear();
+}
+
+
+void AUD::toDefault()
+{
+ pic_type = 0;
+}
+
+
diff --git a/DirectShowFilters/BDReader/source/HEVC/Hevc.h b/DirectShowFilters/BDReader/source/HEVC/Hevc.h
new file mode 100644
index 00000000000..e9d48ecdc7e
--- /dev/null
+++ b/DirectShowFilters/BDReader/source/HEVC/Hevc.h
@@ -0,0 +1,476 @@
+// Copyright (C) 2016 Team MediaPortal
+// http://www.team-mediaportal.com
+//
+// MediaPortal 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.
+//
+// MediaPortal 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 MediaPortal. If not, see .
+
+// ========================================================================
+// The code in this file is derived from the 'HEVCESBrowser' project,
+// a tool for analyzing HEVC(h265) bitstreams authored by 'virinext'.
+// See https://github.com/virinext/hevcesbrowser
+// and http://www.codeproject.com/Tips/896030/The-Structure-of-HEVC-Video
+// Licensed under the GNU General Public License and
+// the Code Project Open License, http://www.codeproject.com/info/cpol10.aspx
+// ========================================================================
+
+#ifndef HEVC_H_
+#define HEVC_H_
+
+//#include
+#include
+#include
+#include
+#include
+#include
+
+namespace HEVC
+{
+
+ struct hevchdr
+ {
+ uint8_t profile, level;
+ uint64_t chromaFormat;
+ uint16_t lumaDepth, chromaDepth;
+ unsigned int width, height;
+ bool progressive;
+ uint8_t * sps;
+ uint8_t * pps;
+ uint8_t * vps;
+ __int64 spslen;
+ __int64 ppslen;
+ __int64 vpslen;
+ __int64 AvgTimePerFrame;
+ int arx, ary;
+ uint8_t ar;
+ hevchdr()
+ {
+ profile = 0;
+ level = 0;
+ chromaFormat = 0;
+ lumaDepth = 0;
+ chromaDepth = 0;
+ progressive = true;
+ sps = NULL;
+ pps = NULL;
+ vps = NULL;
+ spslen = 0;
+ ppslen = 0;
+ vpslen = 0;
+ AvgTimePerFrame = 370000; //27 Hz
+ ar = 0;
+ arx = 0;
+ ary = 0;
+ width = 0;
+ height = 0;
+ }
+
+ ~hevchdr()
+ {
+ if (sps != NULL) free(sps);
+ if (pps != NULL) free(pps);
+ if (vps != NULL) free(vps);
+ sps = NULL;
+ pps = NULL;
+ vps = NULL;
+ }
+ };
+
+ enum NALUnitType
+ {
+ NAL_FAIL = -1,
+ NAL_TRAIL_N = 0,
+ NAL_TRAIL_R = 1,
+ NAL_TSA_N = 2,
+ NAL_TSA_R = 3,
+ NAL_STSA_N = 4,
+ NAL_STSA_R = 5,
+ NAL_RADL_N = 6,
+ NAL_RADL_R = 7,
+ NAL_RASL_N = 8,
+ NAL_RASL_R = 9,
+ NAL_BLA_W_LP = 16,
+ NAL_BLA_W_RADL = 17,
+ NAL_BLA_N_LP = 18,
+ NAL_IDR_W_RADL = 19,
+ NAL_IDR_N_LP = 20,
+ NAL_CRA_NUT = 21,
+ NAL_IRAP_VCL23 = 23,
+ NAL_VPS = 32,
+ NAL_SPS = 33,
+ NAL_PPS = 34,
+ NAL_AUD = 35,
+ NAL_EOS_NUT = 36,
+ NAL_EOB_NUT = 37,
+ NAL_FD_NUT = 38,
+ NAL_SEI_PREFIX = 39,
+ NAL_SEI_SUFFIX = 40,
+ NAL_RESERVED = 255
+ };
+
+ class ProfileTierLevel
+ {
+ public:
+ uint8_t general_profile_space;
+ uint8_t general_tier_flag;
+ uint8_t general_profile_idc;
+ uint8_t general_profile_compatibility_flag[32];
+ uint8_t general_progressive_source_flag;
+ uint8_t general_interlaced_source_flag;
+ uint8_t general_non_packed_constraint_flag;
+ uint8_t general_frame_only_constraint_flag;
+ uint8_t general_level_idc;
+ std::vector sub_layer_profile_present_flag;
+ std::vector sub_layer_level_present_flag;
+ std::vector sub_layer_profile_space;
+ std::vector sub_layer_tier_flag;
+ std::vector sub_layer_profile_idc;
+ std::vector< std::vector< uint8_t> >
+ sub_layer_profile_compatibility_flag;
+ std::vector sub_layer_progressive_source_flag;
+ std::vector sub_layer_interlaced_source_flag;
+ std::vector sub_layer_non_packed_constraint_flag;
+ std::vector sub_layer_frame_only_constraint_flag;
+ std::vector sub_layer_level_idc;
+
+ void toDefault();
+
+ //bool operator == (const ProfileTierLevel &) const;
+ };
+
+ class SubLayerHrdParameters
+ {
+ public:
+ std::vector bit_rate_value_minus1;
+ std::vector cpb_size_value_minus1;
+ std::vector cpb_size_du_value_minus1;
+ std::vector bit_rate_du_value_minus1;
+ std::vector cbr_flag;
+
+ void toDefault();
+
+ //bool operator == (const SubLayerHrdParameters &) const;
+ };
+
+
+ class ScalingListData
+ {
+ public:
+ std::vector< std::vector< uint8_t> > scaling_list_pred_mode_flag;
+ std::vector< std::vector< uint32_t> > scaling_list_pred_matrix_id_delta;
+ std::vector< std::vector< uint32_t> > scaling_list_dc_coef_minus8;
+ std::vector > >
+ scaling_list_delta_coef;
+
+ void toDefault();
+
+ //bool operator == (const ScalingListData &) const;
+ };
+
+ class HrdParameters
+ {
+ public:
+ uint8_t nal_hrd_parameters_present_flag;
+ uint8_t vcl_hrd_parameters_present_flag;
+ uint8_t sub_pic_hrd_params_present_flag;
+ uint8_t tick_divisor_minus2;
+ uint8_t du_cpb_removal_delay_increment_length_minus1;
+ uint8_t sub_pic_cpb_params_in_pic_timing_sei_flag;
+ uint8_t dpb_output_delay_du_length_minus1;
+ uint8_t bit_rate_scale;
+ uint8_t cpb_size_scale;
+ uint8_t cpb_size_du_scale;
+ uint8_t initial_cpb_removal_delay_length_minus1;
+ uint8_t au_cpb_removal_delay_length_minus1;
+ uint8_t dpb_output_delay_length_minus1;
+ std::vector fixed_pic_rate_general_flag;
+ std::vector fixed_pic_rate_within_cvs_flag;
+ std::vector elemental_duration_in_tc_minus1;
+ std::vector low_delay_hrd_flag;
+ std::vector cpb_cnt_minus1;
+ std::vector
+ nal_sub_layer_hrd_parameters;
+ std::vector
+ vcl_sub_layer_hrd_parameters;
+
+ void toDefault();
+
+ //bool operator == (const HrdParameters &) const;
+ };
+
+ class ShortTermRefPicSet
+ {
+ public:
+ uint8_t inter_ref_pic_set_prediction_flag;
+ uint32_t delta_idx_minus1;
+ uint8_t delta_rps_sign;
+ uint32_t abs_delta_rps_minus1;
+ std::vector used_by_curr_pic_flag;
+ std::vector use_delta_flag;
+ uint32_t num_negative_pics;
+ uint32_t num_positive_pics;
+ std::vector delta_poc_s0_minus1;
+ std::vector used_by_curr_pic_s0_flag;
+ std::vector delta_poc_s1_minus1;
+ std::vector used_by_curr_pic_s1_flag;
+
+ void toDefault();
+
+ //bool operator == (const ShortTermRefPicSet &) const;
+ };
+
+ class RefPicListModification
+ {
+ public:
+ uint8_t ref_pic_list_modification_flag_l0;
+ std::vector list_entry_l0;
+ uint8_t ref_pic_list_modification_flag_l1;
+ std::vector list_entry_l1;
+
+ void toDefault();
+
+ //bool operator == (const RefPicListModification &) const;
+ };
+
+ class VuiParameters
+ {
+ public:
+ uint8_t aspect_ratio_info_present_flag;
+ uint8_t aspect_ratio_idc;
+ uint16_t sar_width;
+ uint16_t sar_height;
+ uint8_t overscan_info_present_flag;
+ uint8_t overscan_appropriate_flag;
+ uint8_t video_signal_type_present_flag;
+ uint8_t video_format;
+ uint8_t video_full_range_flag;
+ uint8_t colour_description_present_flag;
+ uint8_t colour_primaries;
+ uint8_t transfer_characteristics;
+ uint8_t matrix_coeffs;
+ uint8_t chroma_loc_info_present_flag;
+ uint32_t chroma_sample_loc_type_top_field;
+ uint32_t chroma_sample_loc_type_bottom_field;
+ uint8_t neutral_chroma_indication_flag;
+ uint8_t field_seq_flag;
+ uint8_t frame_field_info_present_flag;
+ uint8_t default_display_window_flag;
+ uint32_t def_disp_win_left_offset;
+ uint32_t def_disp_win_right_offset;
+ uint32_t def_disp_win_top_offset;
+ uint32_t def_disp_win_bottom_offset;
+ uint8_t vui_timing_info_present_flag;
+ uint32_t vui_num_units_in_tick;
+ uint32_t vui_time_scale;
+ uint8_t vui_poc_proportional_to_timing_flag;
+ uint32_t vui_num_ticks_poc_diff_one_minus1;
+ uint8_t vui_hrd_parameters_present_flag;
+ HrdParameters hrd_parameters;
+ uint8_t bitstream_restriction_flag;
+ uint8_t tiles_fixed_structure_flag;
+ uint8_t motion_vectors_over_pic_boundaries_flag;
+ uint8_t restricted_ref_pic_lists_flag;
+ uint32_t min_spatial_segmentation_idc;
+ uint32_t max_bytes_per_pic_denom;
+ uint32_t max_bits_per_min_cu_denom;
+ uint32_t log2_max_mv_length_horizontal;
+ uint32_t log2_max_mv_length_vertical;
+
+ void toDefault();
+
+ //bool operator == (const VuiParameters &) const;
+
+ };
+
+
+
+ class NALUnit
+ {
+ public:
+ NALUnit(NALUnitType type);
+ virtual ~NALUnit();
+ virtual NALUnitType getType() const;
+
+ std::shared_ptr copy() const;
+
+ bool m_processFailed;
+
+ NALUnitType m_nalUnitType;
+ };
+
+
+
+ class VPS: public NALUnit
+ {
+ public:
+ VPS();
+ uint8_t vps_video_parameter_set_id;
+ uint8_t vps_max_layers_minus1;
+ uint8_t vps_max_sub_layers_minus1;
+ uint8_t vps_temporal_id_nesting_flag;
+ ProfileTierLevel profile_tier_level;
+ uint8_t vps_sub_layer_ordering_info_present_flag;
+ std::vector vps_max_dec_pic_buffering_minus1;
+ std::vector vps_max_num_reorder_pics;
+ std::vector vps_max_latency_increase_plus1;
+ uint8_t vps_max_layer_id;
+ uint32_t vps_num_layer_sets_minus1;
+ std::vector >
+ layer_id_included_flag;
+ uint8_t vps_timing_info_present_flag;
+ uint32_t vps_num_units_in_tick;
+ uint32_t vps_time_scale;
+ uint8_t vps_poc_proportional_to_timing_flag;
+ uint32_t vps_num_ticks_poc_diff_one_minus1;
+ uint32_t vps_num_hrd_parameters;
+ std::vector hrd_layer_set_idx;
+ std::vector cprms_present_flag;
+ std::vector
+ hrd_parameters;
+ uint8_t vps_extension_flag;
+
+ void toDefault();
+ //bool operator == (const VPS &) const;
+ };
+
+
+ class SPS: public NALUnit
+ {
+ public:
+ SPS();
+ uint8_t sps_video_parameter_set_id;
+ uint8_t sps_max_sub_layers_minus1;
+ uint8_t sps_temporal_id_nesting_flag;
+ ProfileTierLevel profile_tier_level;
+ uint32_t sps_seq_parameter_set_id;
+ uint32_t chroma_format_idc;
+ uint8_t separate_colour_plane_flag;
+ uint32_t pic_width_in_luma_samples;
+ uint32_t pic_height_in_luma_samples;
+ uint8_t conformance_window_flag;
+ uint32_t conf_win_left_offset;
+ uint32_t conf_win_right_offset;
+ uint32_t conf_win_top_offset;
+ uint32_t conf_win_bottom_offset;
+ uint32_t bit_depth_luma_minus8;
+ uint32_t bit_depth_chroma_minus8;
+ uint32_t log2_max_pic_order_cnt_lsb_minus4;
+ uint8_t sps_sub_layer_ordering_info_present_flag;
+ std::vector sps_max_dec_pic_buffering_minus1;
+ std::vector sps_max_num_reorder_pics;
+ std::vector sps_max_latency_increase_plus1;
+ uint32_t log2_min_luma_coding_block_size_minus3;
+ uint32_t log2_diff_max_min_luma_coding_block_size;
+ uint32_t log2_min_transform_block_size_minus2;
+ uint32_t log2_diff_max_min_transform_block_size;
+ uint32_t max_transform_hierarchy_depth_inter;
+ uint32_t max_transform_hierarchy_depth_intra;
+ uint8_t scaling_list_enabled_flag;
+ uint8_t sps_scaling_list_data_present_flag;
+ ScalingListData scaling_list_data;
+ uint8_t amp_enabled_flag;
+ uint8_t sample_adaptive_offset_enabled_flag;
+ uint8_t pcm_enabled_flag;
+ uint8_t pcm_sample_bit_depth_luma_minus1;
+ uint8_t pcm_sample_bit_depth_chroma_minus1;
+ uint32_t log2_min_pcm_luma_coding_block_size_minus3;
+ uint32_t log2_diff_max_min_pcm_luma_coding_block_size;
+ uint8_t pcm_loop_filter_disabled_flag;
+ uint32_t num_short_term_ref_pic_sets;
+ std::vector
+ short_term_ref_pic_set;
+ uint8_t long_term_ref_pics_present_flag;
+ uint32_t num_long_term_ref_pics_sps;
+ std::vector lt_ref_pic_poc_lsb_sps;
+ std::vector used_by_curr_pic_lt_sps_flag;
+ uint8_t sps_temporal_mvp_enabled_flag;
+ uint8_t strong_intra_smoothing_enabled_flag;
+ uint8_t vui_parameters_present_flag;
+ VuiParameters vui_parameters;
+ uint8_t sps_extension_flag;
+
+ void toDefault();
+
+ //bool operator == (const SPS &) const;
+ };
+
+
+ class PPS: public NALUnit
+ {
+ public:
+ PPS();
+
+ uint32_t pps_pic_parameter_set_id;
+ uint32_t pps_seq_parameter_set_id;
+ uint8_t dependent_slice_segments_enabled_flag;
+ uint8_t output_flag_present_flag;
+ uint8_t num_extra_slice_header_bits;
+ uint8_t sign_data_hiding_flag;
+ uint8_t cabac_init_present_flag;
+ uint32_t num_ref_idx_l0_default_active_minus1;
+ uint32_t num_ref_idx_l1_default_active_minus1;
+ int32_t init_qp_minus26;
+ uint8_t constrained_intra_pred_flag;
+ uint8_t transform_skip_enabled_flag;
+ uint8_t cu_qp_delta_enabled_flag;
+ uint32_t diff_cu_qp_delta_depth;
+ int32_t pps_cb_qp_offset;
+ int32_t pps_cr_qp_offset;
+ uint8_t pps_slice_chroma_qp_offsets_present_flag;
+ uint8_t weighted_pred_flag;
+ uint8_t weighted_bipred_flag;
+ uint8_t transquant_bypass_enabled_flag;
+ uint8_t tiles_enabled_flag;
+ uint8_t entropy_coding_sync_enabled_flag;
+ uint32_t num_tile_columns_minus1;
+ uint32_t num_tile_rows_minus1;
+ uint8_t uniform_spacing_flag;
+ std::vector
+ column_width_minus1;
+ std::vector
+ row_height_minus1;
+ uint8_t loop_filter_across_tiles_enabled_flag;
+ uint8_t pps_loop_filter_across_slices_enabled_flag;
+ uint8_t deblocking_filter_control_present_flag;
+ uint8_t deblocking_filter_override_enabled_flag;
+ uint8_t pps_deblocking_filter_disabled_flag;
+ uint32_t pps_beta_offset_div2;
+ uint32_t pps_tc_offset_div2;
+ uint8_t pps_scaling_list_data_present_flag;
+ ScalingListData
+ scaling_list_data;
+ uint8_t lists_modification_present_flag;
+ int32_t log2_parallel_merge_level_minus2;
+ uint8_t slice_segment_header_extension_present_flag;
+ uint8_t pps_extension_flag;
+
+ void toDefault();
+
+ //bool operator == (const PPS &) const;
+ };
+
+
+
+
+ class AUD: public NALUnit
+ {
+ public:
+ AUD();
+
+ uint8_t pic_type;
+ void toDefault();
+ };
+
+
+}
+
+#endif
diff --git a/DirectShowFilters/BDReader/source/HEVC/HevcNalDecode.cpp b/DirectShowFilters/BDReader/source/HEVC/HevcNalDecode.cpp
new file mode 100644
index 00000000000..d051178003e
--- /dev/null
+++ b/DirectShowFilters/BDReader/source/HEVC/HevcNalDecode.cpp
@@ -0,0 +1,749 @@
+// Copyright (C) 2016 Team MediaPortal
+// http://www.team-mediaportal.com
+//
+// MediaPortal 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.
+//
+// MediaPortal 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 MediaPortal. If not, see .
+
+// ========================================================================
+// The code in this file is derived from the 'HEVCESBrowser' project,
+// a tool for analyzing HEVC(h265) bitstreams authored by 'virinext'.
+// See https://github.com/virinext/hevcesbrowser
+// and http://www.codeproject.com/Tips/896030/The-Structure-of-HEVC-Video
+// Licensed under the GNU General Public License and
+// the Code Project Open License, http://www.codeproject.com/info/cpol10.aspx
+// ========================================================================
+
+#include "HevcNalDecode.h"
+
+#include
+#include
+#include
+
+#include
+
+#include
+
+extern void LogDebug(const char *fmt, ...) ;
+
+using namespace HEVC;
+
+NALUnitType HevcNalDecode::processNALUnit(const uint8_t *pdata, std::size_t size, hevchdr& h)
+{
+ //Note: 'emulation_prevention_three_byte' removal is dealt with inside the BitstreamReader
+ BitstreamReader bs(pdata, size);
+
+ NALUnitType type = NAL_FAIL;
+
+ try
+ {
+ type = processNALUnitHeader(bs);
+ }
+ catch(...)
+ {
+ LogDebug("HevcNalDecode:processNALUnit exception ...");
+ return NAL_FAIL;
+ }
+
+ switch(type)
+ {
+ case NAL_SPS:
+ {
+ std::shared_ptr psps(new SPS);
+ try
+ {
+ processSPS(psps, bs);
+ }
+ catch(...)
+ {
+ LogDebug("HevcNalDecode:processSPS exception ...");
+ return NAL_FAIL;
+ }
+
+ //Assign values to hevchdr elements
+ h.chromaFormat = psps -> chroma_format_idc;
+
+ h.width = psps -> pic_width_in_luma_samples;
+ h.height = psps -> pic_height_in_luma_samples;
+ if (h.height == 1088) h.height = 1080; // Prevent blur lines
+
+ h.lumaDepth = psps -> bit_depth_luma_minus8 + 8; // bit_depth_luma_minus8
+ h.chromaDepth = psps -> bit_depth_chroma_minus8 + 8; // bit_depth_chroma_minus8
+
+ h.progressive = (psps->profile_tier_level.general_progressive_source_flag > 0);
+
+ h.profile = psps->profile_tier_level.general_profile_idc;
+ h.level = psps->profile_tier_level.general_level_idc;
+
+ if(psps -> vui_parameters_present_flag)
+ {
+ if (psps->vui_parameters.aspect_ratio_info_present_flag)
+ {
+ h.ar = psps->vui_parameters.aspect_ratio_idc;
+ if(h.ar == 255) //EXTENDED_SAR
+ {
+ h.arx = psps->vui_parameters.sar_width;
+ h.ary = psps->vui_parameters.sar_height;
+ // make sure that both are 0 if one is 0
+ if(h.arx == 0 || h.ary == 0)
+ {
+ h.arx = 0;
+ h.ary = 0;
+ }
+ }
+ else //Look up the aspect ratio from a table
+ {
+ struct {int x, y;} ar[] = {{0,0},{1,1},{12,11},{10,11},{16,11},{40,33},{24,11},{20,11},{32,11},{80,33},{18,11},{15,11},{64,33},{160,99},{4,3},{3,2},{2,1}};
+ if(h.ar > 16)
+ {
+ // aspect ratio reserved
+ h.arx = 0;
+ h.ary = 0;
+ }
+ else
+ {
+ // use preset aspect ratio
+ h.arx = ar[h.ar].x;
+ h.ary = ar[h.ar].y;
+ }
+ }
+
+ h.arx *= h.width;
+ h.ary *= h.height;
+
+ uint32_t a = h.arx, b = h.ary;
+ while(a) {uint32_t tmp = a; a = b % tmp; b = tmp;}
+ if(b) h.arx /= b, h.ary /= b;
+ }
+
+ if (psps->vui_parameters.vui_timing_info_present_flag)
+ {
+ if ((psps->vui_parameters.vui_time_scale > 0) && (psps->vui_parameters.vui_num_units_in_tick > 0))
+ {
+ h.AvgTimePerFrame = (__int64)((10000000.0 * (double)psps->vui_parameters.vui_num_units_in_tick)/(double)psps->vui_parameters.vui_time_scale);
+ }
+ }
+ }
+
+ if (h.arx == 0 && h.ary == 0) //Do something sensible if aspect ratio info not present
+ {
+ if (h.width > 0 && h.width > 0)
+ {
+ h.arx = h.width;
+ h.ary = h.height;
+
+ uint32_t a = h.arx, b = h.ary;
+ while(a) {uint32_t tmp = a; a = b % tmp; b = tmp;}
+ if(b) h.arx /= b, h.ary /= b;
+ }
+ }
+
+ break;
+ }
+
+ default: {} //Do not decode any other NALs
+ };
+
+ return type;
+}
+
+//Remove 'emulation_prevention_three_byte' characters and copy to new buffer
+void HevcNalDecode::Remove3Byte(uint8_t* dst, const uint8_t* src, int length)
+{
+ int si=0;
+ int di=0;
+ while(si+23){
+ dst[di++]= src[si++];
+ dst[di++]= src[si++];
+ }
+ else if(src[si]==0 && src[si+1]==0){
+ if(src[si+2]==3){ //escape
+ dst[di++]= 0;
+ dst[di++]= 0;
+ si+=3;
+ continue;
+ }
+ else //next start code
+ return;
+ }
+
+ dst[di++]= src[si++];
+ }
+}
+
+
+NALUnitType HevcNalDecode::processNALUnitHeader(BitstreamReader &bs)
+{
+ //forbidden_zero_bit
+ bs.getBit();
+
+ NALUnitType type = (NALUnitType)bs.getBits(6);
+
+ //nuh_layer_id
+ bs.getBits(6);
+
+ //nuh_temporal_id_plus1
+ bs.getBits(3);
+ return type;
+}
+
+void HevcNalDecode::processSPS(std::shared_ptr psps, BitstreamReader &bs)
+{
+ psps -> sps_video_parameter_set_id = bs.getBits(4);
+ psps -> sps_max_sub_layers_minus1 = bs.getBits(3);
+ psps -> sps_temporal_id_nesting_flag = bs.getBits(1);
+ psps -> profile_tier_level = processProfileTierLevel(psps -> sps_max_sub_layers_minus1, bs);
+
+ psps -> sps_seq_parameter_set_id = bs.getGolombU();
+ psps -> chroma_format_idc = bs.getGolombU();
+
+ if(psps -> chroma_format_idc == 3)
+ psps -> separate_colour_plane_flag = bs.getBits(1);
+ else
+ psps -> separate_colour_plane_flag = 0;
+
+ psps -> pic_width_in_luma_samples = bs.getGolombU();
+ psps -> pic_height_in_luma_samples = bs.getGolombU();
+ psps -> conformance_window_flag = bs.getBits(1);
+
+ if(psps -> conformance_window_flag)
+ {
+ psps -> conf_win_left_offset = bs.getGolombU();
+ psps -> conf_win_right_offset = bs.getGolombU();
+ psps -> conf_win_top_offset = bs.getGolombU();
+ psps -> conf_win_bottom_offset = bs.getGolombU();
+ }
+
+ psps -> bit_depth_luma_minus8 = bs.getGolombU();
+ psps -> bit_depth_chroma_minus8 = bs.getGolombU();
+ psps -> log2_max_pic_order_cnt_lsb_minus4 = bs.getGolombU();
+ psps -> sps_sub_layer_ordering_info_present_flag = bs.getBits(1);
+
+ psps -> sps_max_dec_pic_buffering_minus1.resize(psps -> sps_max_sub_layers_minus1 + 1, 0);
+ psps -> sps_max_num_reorder_pics.resize(psps -> sps_max_sub_layers_minus1 + 1, 0);
+ psps -> sps_max_latency_increase_plus1.resize(psps -> sps_max_sub_layers_minus1 + 1, 0);
+
+ for(std::size_t i=(psps -> sps_sub_layer_ordering_info_present_flag ? 0 : psps -> sps_max_sub_layers_minus1);
+ i<=psps -> sps_max_sub_layers_minus1;
+ i++)
+ {
+ psps -> sps_max_dec_pic_buffering_minus1[i] = bs.getGolombU();
+ psps -> sps_max_num_reorder_pics[i] = bs.getGolombU();
+ psps -> sps_max_latency_increase_plus1[i] = bs.getGolombU();
+ }
+
+ psps -> log2_min_luma_coding_block_size_minus3 = bs.getGolombU();
+ psps -> log2_diff_max_min_luma_coding_block_size = bs.getGolombU();
+ psps -> log2_min_transform_block_size_minus2 = bs.getGolombU();
+ psps -> log2_diff_max_min_transform_block_size = bs.getGolombU();
+ psps -> max_transform_hierarchy_depth_inter = bs.getGolombU();
+ psps -> max_transform_hierarchy_depth_intra = bs.getGolombU();
+
+ psps -> scaling_list_enabled_flag = bs.getBits(1);
+ if(psps -> scaling_list_enabled_flag)
+ {
+ psps -> sps_scaling_list_data_present_flag = bs.getBits(1);
+ if(psps -> sps_scaling_list_data_present_flag)
+ {
+ psps -> scaling_list_data = processScalingListData(bs);
+ }
+ }
+
+ psps -> amp_enabled_flag = bs.getBits(1);
+ psps -> sample_adaptive_offset_enabled_flag = bs.getBits(1);
+ psps -> pcm_enabled_flag = bs.getBits(1);
+
+ if(psps -> pcm_enabled_flag)
+ {
+ psps -> pcm_sample_bit_depth_luma_minus1 = bs.getBits(4);
+ psps -> pcm_sample_bit_depth_chroma_minus1 = bs.getBits(4);
+ psps -> log2_min_pcm_luma_coding_block_size_minus3 = bs.getGolombU();
+ psps -> log2_diff_max_min_pcm_luma_coding_block_size = bs.getGolombU();
+ psps -> pcm_loop_filter_disabled_flag = bs.getBits(1);
+ }
+
+ psps -> num_short_term_ref_pic_sets = bs.getGolombU();
+
+ psps -> short_term_ref_pic_set.resize(psps -> num_short_term_ref_pic_sets);
+ for(std::size_t i=0; i num_short_term_ref_pic_sets; i++)
+ psps -> short_term_ref_pic_set[i] = processShortTermRefPicSet(i, psps -> num_short_term_ref_pic_sets, psps -> short_term_ref_pic_set, psps, bs);
+
+ psps -> long_term_ref_pics_present_flag = bs.getBits(1);
+ if(psps -> long_term_ref_pics_present_flag)
+ {
+ psps -> num_long_term_ref_pics_sps = bs.getGolombU();
+ psps -> lt_ref_pic_poc_lsb_sps.resize(psps -> num_long_term_ref_pics_sps);
+ psps -> used_by_curr_pic_lt_sps_flag.resize(psps -> num_long_term_ref_pics_sps);
+
+ for(std::size_t i = 0; i num_long_term_ref_pics_sps; i++)
+ {
+ psps -> lt_ref_pic_poc_lsb_sps[i] = bs.getBits(psps -> log2_max_pic_order_cnt_lsb_minus4 + 4);
+ psps -> used_by_curr_pic_lt_sps_flag[i] = bs.getBits(1);
+ }
+ }
+
+ psps -> sps_temporal_mvp_enabled_flag = bs.getBits(1);
+ psps -> strong_intra_smoothing_enabled_flag = bs.getBits(1);
+ psps -> vui_parameters_present_flag = bs.getBits(1);
+
+ if(psps -> vui_parameters_present_flag)
+ {
+ psps -> vui_parameters = processVuiParameters(psps -> sps_max_sub_layers_minus1, bs);
+ }
+
+ psps -> sps_extension_flag = bs.getBits(1);
+}
+
+
+//=======================================================================
+
+VuiParameters HevcNalDecode::processVuiParameters(std::size_t sps_max_sub_layers_minus1, BitstreamReader &bs)
+{
+ VuiParameters vui;
+
+ vui.toDefault();
+
+ vui.aspect_ratio_idc = 0;
+ vui.sar_width = 0;
+ vui.sar_height = 0;
+
+
+ vui.aspect_ratio_info_present_flag = bs.getBits(1);
+
+ if(vui.aspect_ratio_info_present_flag)
+ {
+ vui.aspect_ratio_idc = bs.getBits(8);
+
+ if(vui.aspect_ratio_idc == 255) //EXTENDED_SAR
+ {
+ vui.sar_width = bs.getBits(16);
+ vui.sar_height = bs.getBits(16);
+ }
+ }
+
+
+ vui.overscan_info_present_flag = bs.getBits(1);
+ if(vui.overscan_info_present_flag)
+ vui.overscan_appropriate_flag = bs.getBits(1);
+
+ vui.video_format = 5;
+ vui.video_full_range_flag = 0;
+ vui.colour_primaries = 2;
+ vui.transfer_characteristics = 2;
+ vui.matrix_coeffs = 2;
+
+ vui.video_signal_type_present_flag = bs.getBits(1);
+
+ if(vui.video_signal_type_present_flag)
+ {
+ vui.video_format = bs.getBits(3);
+ vui.video_full_range_flag = bs.getBits(1);
+ vui.colour_description_present_flag = bs.getBits(1);
+
+ if(vui.colour_description_present_flag)
+ {
+ vui.colour_primaries = bs.getBits(8);
+ vui.transfer_characteristics = bs.getBits(8);
+ vui.matrix_coeffs = bs.getBits(8);
+ }
+
+ }
+
+ vui.chroma_sample_loc_type_top_field = 0;
+ vui.chroma_sample_loc_type_bottom_field = 0;
+
+ vui.chroma_loc_info_present_flag = bs.getBits(1);
+ if(vui.chroma_loc_info_present_flag)
+ {
+ vui.chroma_sample_loc_type_top_field = bs.getGolombU();
+ vui.chroma_sample_loc_type_bottom_field = bs.getGolombU();
+ }
+
+
+ vui.neutral_chroma_indication_flag = bs.getBits(1);
+ vui.field_seq_flag = bs.getBits(1);
+ vui.frame_field_info_present_flag = bs.getBits(1);
+ vui.default_display_window_flag = bs.getBits(1);
+
+ vui.def_disp_win_left_offset = 0;
+ vui.def_disp_win_right_offset = 0;
+ vui.def_disp_win_right_offset = 0;
+ vui.def_disp_win_bottom_offset = 0;
+
+ if(vui.default_display_window_flag)
+ {
+ vui.def_disp_win_left_offset = bs.getGolombU();
+ vui.def_disp_win_right_offset = bs.getGolombU();
+ vui.def_disp_win_top_offset = bs.getGolombU();
+ vui.def_disp_win_bottom_offset = bs.getGolombU();
+ }
+
+ vui.vui_timing_info_present_flag = bs.getBits(1);
+
+ if(vui.vui_timing_info_present_flag)
+ {
+ vui.vui_num_units_in_tick = bs.getBits(32);
+ vui.vui_time_scale = bs.getBits(32);
+ vui.vui_poc_proportional_to_timing_flag = bs.getBits(1);
+
+ if(vui.vui_poc_proportional_to_timing_flag)
+ vui.vui_num_ticks_poc_diff_one_minus1 = bs.getGolombU();
+
+ vui.vui_hrd_parameters_present_flag = bs.getBits(1);
+
+ if(vui.vui_hrd_parameters_present_flag)
+ vui.hrd_parameters = processHrdParameters(1, sps_max_sub_layers_minus1, bs);
+ }
+
+ vui.bitstream_restriction_flag = bs.getBits(1);
+
+ if(vui.bitstream_restriction_flag)
+ {
+ vui.tiles_fixed_structure_flag = bs.getBits(1);
+ vui.motion_vectors_over_pic_boundaries_flag = bs.getBits(1);
+ vui.restricted_ref_pic_lists_flag = bs.getBits(1);
+
+ vui.min_spatial_segmentation_idc = bs.getGolombU();
+ vui.max_bytes_per_pic_denom = bs.getGolombU();
+ vui.max_bits_per_min_cu_denom = bs.getGolombU();
+ vui.log2_max_mv_length_horizontal = bs.getGolombU();
+ vui.log2_max_mv_length_vertical = bs.getGolombU();
+ }
+
+ return vui;
+}
+
+//=======================================================================
+
+ProfileTierLevel HevcNalDecode::processProfileTierLevel(std::size_t max_sub_layers_minus1, BitstreamReader &bs)
+{
+ ProfileTierLevel ptl;
+
+ ptl.toDefault();
+
+ ptl.general_profile_space = bs.getBits(2);
+ ptl.general_tier_flag = bs.getBits(1);
+ ptl.general_profile_idc = bs.getBits(5);
+
+ for(std::size_t i=0; i<32; i++)
+ ptl.general_profile_compatibility_flag[i] = bs.getBits(1);
+
+ ptl.general_progressive_source_flag = bs.getBits(1);
+ ptl.general_interlaced_source_flag = bs.getBits(1);
+ ptl.general_non_packed_constraint_flag = bs.getBits(1);
+ ptl.general_frame_only_constraint_flag = bs.getBits(1);
+ bs.getBits(32);
+ bs.getBits(12);
+ ptl.general_level_idc = bs.getBits(8);
+
+ ptl.sub_layer_profile_present_flag.resize(max_sub_layers_minus1);
+ ptl.sub_layer_level_present_flag.resize(max_sub_layers_minus1);
+
+ for(std::size_t i=0; i 0)
+ {
+ for(std::size_t i=max_sub_layers_minus1; i<8; i++)
+ bs.getBits(2);
+ }
+
+ ptl.sub_layer_profile_space.resize(max_sub_layers_minus1);
+ ptl.sub_layer_tier_flag.resize(max_sub_layers_minus1);
+ ptl.sub_layer_profile_idc.resize(max_sub_layers_minus1);
+ ptl.sub_layer_profile_compatibility_flag.resize(max_sub_layers_minus1);
+ ptl.sub_layer_progressive_source_flag.resize(max_sub_layers_minus1);
+ ptl.sub_layer_interlaced_source_flag.resize(max_sub_layers_minus1);
+ ptl.sub_layer_non_packed_constraint_flag.resize(max_sub_layers_minus1);
+ ptl.sub_layer_frame_only_constraint_flag.resize(max_sub_layers_minus1);
+ ptl.sub_layer_level_idc.resize(max_sub_layers_minus1);
+
+ for(std::size_t i=0; i= 2)
+ sc.scaling_list_dc_coef_minus8[sizeId-2].resize(6);
+ }
+
+ for(std::size_t matrixId = 0; matrixId<(size_t)((sizeId == 3)?2:6); matrixId++)
+ {
+ sc.scaling_list_pred_mode_flag[sizeId][matrixId] = bs.getBits(1);
+ if(!sc.scaling_list_pred_mode_flag[sizeId][matrixId])
+ sc.scaling_list_pred_matrix_id_delta[sizeId][matrixId] = bs.getGolombU();
+ else
+ {
+ std::size_t nextCoef = 8;
+ std::size_t coefNum = std::min(64, (1 << (4 + (sizeId << 1))));
+ if(sizeId > 1)
+ sc.scaling_list_dc_coef_minus8[sizeId-2][matrixId] = bs.getGolombS();
+
+ sc.scaling_list_delta_coef[sizeId][matrixId].resize(coefNum);
+ for(std::size_t i = 0; i < coefNum; i++)
+ sc.scaling_list_delta_coef[sizeId][matrixId][i] = bs.getGolombS();
+ }
+ }
+ }
+
+ return sc;
+}
+
+//=======================================================================
+
+ShortTermRefPicSet HevcNalDecode::processShortTermRefPicSet(std::size_t stRpsIdx, std::size_t num_short_term_ref_pic_sets, const std::vector &refPicSets, std::shared_ptr psps, BitstreamReader &bs)
+{
+ ShortTermRefPicSet rpset;
+
+ rpset.toDefault();
+
+ rpset.inter_ref_pic_set_prediction_flag = 0;
+ rpset.delta_idx_minus1 = 0;
+ if(stRpsIdx)
+ {
+ rpset.inter_ref_pic_set_prediction_flag = bs.getBits(1);
+ }
+
+ if(rpset.inter_ref_pic_set_prediction_flag)
+ {
+ if(stRpsIdx == num_short_term_ref_pic_sets)
+ rpset.delta_idx_minus1 = bs.getGolombU();
+
+ rpset.delta_rps_sign = bs.getBits(1);
+ rpset.abs_delta_rps_minus1 = bs.getGolombU();
+
+ std::size_t RefRpsIdx = stRpsIdx - (rpset.delta_idx_minus1 + 1);
+ std::size_t NumDeltaPocs = 0;
+
+ if(refPicSets[RefRpsIdx].inter_ref_pic_set_prediction_flag)
+ {
+ for(std::size_t i=0; i psps -> sps_max_dec_pic_buffering_minus1[psps -> sps_max_sub_layers_minus1])
+ {
+ LogDebug("HevcNalDecode:ShortTermRefPicSet: num_negative_pics > sps_max_dec_pic_buffering_minus1");
+ return rpset;
+ }
+
+ if(rpset.num_positive_pics > psps -> sps_max_dec_pic_buffering_minus1[psps -> sps_max_sub_layers_minus1])
+ {
+ LogDebug("HevcNalDecode:ShortTermRefPicSet: num_positive_pics > sps_max_dec_pic_buffering_minus1");
+ return rpset;
+ }
+
+ rpset.delta_poc_s0_minus1.resize(rpset.num_negative_pics);
+ rpset.used_by_curr_pic_s0_flag.resize(rpset.num_negative_pics);
+
+ for(std::size_t i=0; i.
+
+// ========================================================================
+// The code in this file is derived from the 'HEVCESBrowser' project,
+// a tool for analyzing HEVC(h265) bitstreams authored by 'virinext'.
+// See https://github.com/virinext/hevcesbrowser
+// and http://www.codeproject.com/Tips/896030/The-Structure-of-HEVC-Video
+// Licensed under the GNU General Public License and
+// the Code Project Open License, http://www.codeproject.com/info/cpol10.aspx
+// ========================================================================
+
+#ifndef HEVC_NAL_DECODE
+#define HEVC_NAL_DECODE
+
+#include "Hevc.h"
+#include "BitstreamReader.h"
+
+#include