summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2016-12-22 12:22:11 +0100
committerKlaus Schmidinger <vdr@tvdr.de>2016-12-22 12:22:11 +0100
commitf91468ff9bca7bbf07ff854909cd5564dbb59f23 (patch)
tree6bb8d4963ce56130672307d62257ea2783fb5502
parent22cb026e5e3cb12667d6e07db585a41d748bb55a (diff)
downloadvdr-f91468ff9bca7bbf07ff854909cd5564dbb59f23.tar.gz
vdr-f91468ff9bca7bbf07ff854909cd5564dbb59f23.tar.bz2
Implemented a frame parser for H.265 (HEVC) recordings
-rw-r--r--CONTRIBUTORS1
-rw-r--r--HISTORY1
-rw-r--r--pat.c3
-rw-r--r--remux.c88
4 files changed, 87 insertions, 6 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index e717e36e..cb2c516a 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -3331,6 +3331,7 @@ Thomas Reufer <thomas@reufer.ch>
for improving handling frame numbers to have a smoother progress display during
replay of recordings with B-frames
for fixing replaying recordings to their very end, if they don't end with an I-frame
+ for implementing a frame parser for H.265 (HEVC) recordings
Eike Sauer <EikeSauer@t-online.de>
for reporting a problem with channels that need more than 5 TS packets for detecting
diff --git a/HISTORY b/HISTORY
index 8b8130b2..ce3af2d7 100644
--- a/HISTORY
+++ b/HISTORY
@@ -8861,3 +8861,4 @@ Video Disk Recorder Revision History
replay of recordings with B-frames (thanks to Thomas Reufer).
- Fixed replaying recordings to their very end, if they don't end with an I-frame
(thanks to Thomas Reufer).
+- Implemented a frame parser for H.265 (HEVC) recordings (thanks to Thomas Reufer).
diff --git a/pat.c b/pat.c
index beb5609a..a22c9ac9 100644
--- a/pat.c
+++ b/pat.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: pat.c 4.1 2015/08/17 08:46:55 kls Exp $
+ * $Id: pat.c 4.2 2016/12/22 11:42:23 kls Exp $
*/
#include "pat.h"
@@ -439,6 +439,7 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
case 1: // STREAMTYPE_11172_VIDEO
case 2: // STREAMTYPE_13818_VIDEO
case 0x1B: // H.264
+ case 0x24: // H.265
Vpid = esPid;
Ppid = pmt.getPCRPid();
Vtype = stream.getStreamType();
diff --git a/remux.c b/remux.c
index 6c07efcb..139540ef 100644
--- a/remux.c
+++ b/remux.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: remux.c 4.1 2015/03/11 09:49:38 kls Exp $
+ * $Id: remux.c 4.2 2016/12/22 11:45:52 kls Exp $
*/
#include "remux.h"
@@ -708,6 +708,7 @@ void cPatPmtParser::ParsePmt(const uchar *Data, int Length)
case 0x01: // STREAMTYPE_11172_VIDEO
case 0x02: // STREAMTYPE_13818_VIDEO
case 0x1B: // H.264
+ case 0x24: // H.265
vpid = stream.getPid();
vtype = stream.getStreamType();
ppid = Pmt.getPCRPid();
@@ -1204,16 +1205,16 @@ private:
nutSequenceParameterSet = 7,
nutAccessUnitDelimiter = 9,
};
- cTsPayload tsPayload;
uchar byte; // holds the current byte value in case of bitwise access
int bit; // the bit index into the current byte (-1 if we're not in bit reading mode)
int zeroBytes; // the number of consecutive zero bytes (to detect 0x000003)
- uint32_t scanner;
// Identifiers written in '_' notation as in "ITU-T H.264":
bool separate_colour_plane_flag;
int log2_max_frame_num;
bool frame_mbs_only_flag;
- //
+protected:
+ cTsPayload tsPayload;
+ uint32_t scanner;
bool gotAccessUnitDelimiter;
bool gotSequenceParameterSet;
uchar GetByte(bool Raw = false);
@@ -1430,6 +1431,81 @@ void cH264Parser::ParseSliceHeader(void)
}
}
+// --- cH265Parser -----------------------------------------------------------
+
+class cH265Parser : public cH264Parser {
+private:
+ enum eNalUnitType {
+ nutSliceSegmentTrailingN = 0,
+ nutSliceSegmentTrailingR = 1,
+ nutSliceSegmentTSAN = 2,
+ nutSliceSegmentTSAR = 3,
+ nutSliceSegmentSTSAN = 4,
+ nutSliceSegmentSTSAR = 5,
+ nutSliceSegmentRADLN = 6,
+ nutSliceSegmentRADLR = 7,
+ nutSliceSegmentRASLN = 8,
+ nutSliceSegmentRASLR = 9,
+ nutSliceSegmentBLAWLP = 16,
+ nutSliceSegmentBLAWRADL = 17,
+ nutSliceSegmentBLANLP = 18,
+ nutSliceSegmentIDRWRADL = 19,
+ nutSliceSegmentIDRNLP = 20,
+ nutSliceSegmentCRANUT = 21,
+ nutVideoParameterSet = 32,
+ nutSequenceParameterSet = 33,
+ nutPictureParameterSet = 34,
+ nutAccessUnitDelimiter = 35,
+ nutEndOfSequence = 36,
+ nutEndOfBitstream = 37,
+ nutFillerData = 38,
+ nutPrefixSEI = 39,
+ nutSuffixSEI = 40,
+ nutNonVCLRes0 = 41,
+ nutNonVCLRes3 = 44,
+ nutUnspecified0 = 48,
+ nutUnspecified7 = 55,
+ };
+public:
+ cH265Parser(void);
+ virtual int Parse(const uchar *Data, int Length, int Pid);
+ };
+
+cH265Parser::cH265Parser(void)
+:cH264Parser()
+{
+}
+
+int cH265Parser::Parse(const uchar *Data, int Length, int Pid)
+{
+ newFrame = independentFrame = false;
+ tsPayload.Setup(const_cast<uchar *>(Data), Length, Pid);
+ if (TsPayloadStart(Data)) {
+ tsPayload.SkipPesHeader();
+ scanner = EMPTY_SCANNER;
+ }
+ for (;;) {
+ scanner = (scanner << 8) | GetByte(true);
+ if ((scanner & 0xFFFFFF00) == 0x00000100) { // NAL unit start
+ uchar NalUnitType = (scanner >> 1) & 0x3F;
+ GetByte(); // nuh_layer_id + nuh_temporal_id_plus1
+ if (NalUnitType <= nutSliceSegmentRASLR || (NalUnitType >= nutSliceSegmentBLAWLP && NalUnitType <= nutSliceSegmentCRANUT)) {
+ if (NalUnitType == nutSliceSegmentIDRWRADL || NalUnitType == nutSliceSegmentIDRNLP || NalUnitType == nutSliceSegmentCRANUT)
+ independentFrame = true;
+ if (GetBit()) { // first_slice_segment_in_pic_flag
+ newFrame = true;
+ tsPayload.Statistics();
+ }
+ break;
+ }
+ }
+ if (tsPayload.AtPayloadStart() // stop at any new payload start to have the buffer refilled if necessary
+ || tsPayload.Eof()) // or if we're out of data
+ break;
+ }
+ return tsPayload.Used();
+}
+
// --- cFrameDetector --------------------------------------------------------
cFrameDetector::cFrameDetector(int Pid, int Type)
@@ -1456,13 +1532,15 @@ void cFrameDetector::SetPid(int Pid, int Type)
{
pid = Pid;
type = Type;
- isVideo = type == 0x01 || type == 0x02 || type == 0x1B; // MPEG 1, 2 or H.264
+ isVideo = type == 0x01 || type == 0x02 || type == 0x1B || type == 0x24; // MPEG 1, 2, H.264 or H.265
delete parser;
parser = NULL;
if (type == 0x01 || type == 0x02)
parser = new cMpeg2Parser;
else if (type == 0x1B)
parser = new cH264Parser;
+ else if (type == 0x24)
+ parser = new cH265Parser;
else if (type == 0x04 || type == 0x06) // MPEG audio or AC3 audio
parser = new cAudioParser;
else if (type != 0)