From ce4d2a08e6448b7bfab68b89a12a156ed3294a63 Mon Sep 17 00:00:00 2001
From: Thomas Reufer <thomas@reufer.ch>
Date: Mon, 28 Mar 2016 19:47:14 +0200
Subject: [PATCH] Implement H.265 frame parser

---
 pat.c   |  1 +
 remux.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 82 insertions(+), 3 deletions(-)

--- a/pat.c
+++ b/pat.c
@@ -440,6 +440,7 @@
               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();
--- a/remux.c
+++ b/remux.c
@@ -708,6 +708,7 @@
            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 @@
     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 @@
      }
 }
 
+// --- 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)
@@ -1463,6 +1539,8 @@
      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)