mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Implemented a frame parser for H.265 (HEVC) recordings
This commit is contained in:
parent
22cb026e5e
commit
f91468ff9b
@ -3331,6 +3331,7 @@ Thomas Reufer <thomas@reufer.ch>
|
|||||||
for improving handling frame numbers to have a smoother progress display during
|
for improving handling frame numbers to have a smoother progress display during
|
||||||
replay of recordings with B-frames
|
replay of recordings with B-frames
|
||||||
for fixing replaying recordings to their very end, if they don't end with an I-frame
|
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>
|
Eike Sauer <EikeSauer@t-online.de>
|
||||||
for reporting a problem with channels that need more than 5 TS packets for detecting
|
for reporting a problem with channels that need more than 5 TS packets for detecting
|
||||||
|
1
HISTORY
1
HISTORY
@ -8861,3 +8861,4 @@ Video Disk Recorder Revision History
|
|||||||
replay of recordings with B-frames (thanks to Thomas Reufer).
|
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
|
- Fixed replaying recordings to their very end, if they don't end with an I-frame
|
||||||
(thanks to Thomas Reufer).
|
(thanks to Thomas Reufer).
|
||||||
|
- Implemented a frame parser for H.265 (HEVC) recordings (thanks to Thomas Reufer).
|
||||||
|
3
pat.c
3
pat.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#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 1: // STREAMTYPE_11172_VIDEO
|
||||||
case 2: // STREAMTYPE_13818_VIDEO
|
case 2: // STREAMTYPE_13818_VIDEO
|
||||||
case 0x1B: // H.264
|
case 0x1B: // H.264
|
||||||
|
case 0x24: // H.265
|
||||||
Vpid = esPid;
|
Vpid = esPid;
|
||||||
Ppid = pmt.getPCRPid();
|
Ppid = pmt.getPCRPid();
|
||||||
Vtype = stream.getStreamType();
|
Vtype = stream.getStreamType();
|
||||||
|
88
remux.c
88
remux.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#include "remux.h"
|
||||||
@ -708,6 +708,7 @@ void cPatPmtParser::ParsePmt(const uchar *Data, int Length)
|
|||||||
case 0x01: // STREAMTYPE_11172_VIDEO
|
case 0x01: // STREAMTYPE_11172_VIDEO
|
||||||
case 0x02: // STREAMTYPE_13818_VIDEO
|
case 0x02: // STREAMTYPE_13818_VIDEO
|
||||||
case 0x1B: // H.264
|
case 0x1B: // H.264
|
||||||
|
case 0x24: // H.265
|
||||||
vpid = stream.getPid();
|
vpid = stream.getPid();
|
||||||
vtype = stream.getStreamType();
|
vtype = stream.getStreamType();
|
||||||
ppid = Pmt.getPCRPid();
|
ppid = Pmt.getPCRPid();
|
||||||
@ -1204,16 +1205,16 @@ private:
|
|||||||
nutSequenceParameterSet = 7,
|
nutSequenceParameterSet = 7,
|
||||||
nutAccessUnitDelimiter = 9,
|
nutAccessUnitDelimiter = 9,
|
||||||
};
|
};
|
||||||
cTsPayload tsPayload;
|
|
||||||
uchar byte; // holds the current byte value in case of bitwise access
|
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 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)
|
int zeroBytes; // the number of consecutive zero bytes (to detect 0x000003)
|
||||||
uint32_t scanner;
|
|
||||||
// Identifiers written in '_' notation as in "ITU-T H.264":
|
// Identifiers written in '_' notation as in "ITU-T H.264":
|
||||||
bool separate_colour_plane_flag;
|
bool separate_colour_plane_flag;
|
||||||
int log2_max_frame_num;
|
int log2_max_frame_num;
|
||||||
bool frame_mbs_only_flag;
|
bool frame_mbs_only_flag;
|
||||||
//
|
protected:
|
||||||
|
cTsPayload tsPayload;
|
||||||
|
uint32_t scanner;
|
||||||
bool gotAccessUnitDelimiter;
|
bool gotAccessUnitDelimiter;
|
||||||
bool gotSequenceParameterSet;
|
bool gotSequenceParameterSet;
|
||||||
uchar GetByte(bool Raw = false);
|
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::cFrameDetector(int Pid, int Type)
|
cFrameDetector::cFrameDetector(int Pid, int Type)
|
||||||
@ -1456,13 +1532,15 @@ void cFrameDetector::SetPid(int Pid, int Type)
|
|||||||
{
|
{
|
||||||
pid = Pid;
|
pid = Pid;
|
||||||
type = Type;
|
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;
|
delete parser;
|
||||||
parser = NULL;
|
parser = NULL;
|
||||||
if (type == 0x01 || type == 0x02)
|
if (type == 0x01 || type == 0x02)
|
||||||
parser = new cMpeg2Parser;
|
parser = new cMpeg2Parser;
|
||||||
else if (type == 0x1B)
|
else if (type == 0x1B)
|
||||||
parser = new cH264Parser;
|
parser = new cH264Parser;
|
||||||
|
else if (type == 0x24)
|
||||||
|
parser = new cH265Parser;
|
||||||
else if (type == 0x04 || type == 0x06) // MPEG audio or AC3 audio
|
else if (type == 0x04 || type == 0x06) // MPEG audio or AC3 audio
|
||||||
parser = new cAudioParser;
|
parser = new cAudioParser;
|
||||||
else if (type != 0)
|
else if (type != 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user