diff --git a/Makefile b/Makefile index 70e6837..988c1cf 100644 --- a/Makefile +++ b/Makefile @@ -61,7 +61,7 @@ all-redirect: all ### The object files (add further files here): -OBJS = $(PLUGIN).o aac.o ac3.o config.o h264.o latm.o mpeg.o osd.o receiver.o setup.o symbol.o tools.o +OBJS = $(PLUGIN).o aac.o ac3.o config.o h264.o h265.o latm.o mpeg.o osd.o receiver.o setup.o symbol.o tools.o ### The main target: diff --git a/h265.c b/h265.c new file mode 100644 index 0000000..31a02e3 --- /dev/null +++ b/h265.c @@ -0,0 +1,118 @@ +/* + * h265.c: Frontend Status Monitor plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include "log.h" +#include "tools.h" +#include "h265.h" + +cFemonH265::cFemonH265(cFemonVideoIf *videoHandlerP) +: videoHandlerM(videoHandlerP), + widthM(0), + heightM(0), + aspectRatioM(VIDEO_ASPECT_RATIO_INVALID), + formatM(VIDEO_FORMAT_INVALID), + frameRateM(0), + bitRateM(0), + scanM(VIDEO_SCAN_INVALID) +{ + reset(); +} + +cFemonH265::~cFemonH265() +{ +} + +bool cFemonH265::processVideo(const uint8_t *bufP, int lenP) +{ + bool aud_found = false; + const uint8_t *buf = bufP; + const uint8_t *start = buf; + const uint8_t *end = start + lenP; + + if (!videoHandlerM) + return false; + + // skip PES header + if (!PesLongEnough(lenP)) + return false; + buf += PesPayloadOffset(buf); + start = buf; + + reset(); + + for (;;) { + int consumed = 0; + + buf = nextStartCode(buf, end); + if (buf >= end) + break; + + switch ((buf[3] >> 1) & 0x3F) { + case NAL_AUD: + if (!aud_found) { + aud_found = true; + debug2("%s Found NAL AUD at offset %d/%d", __PRETTY_FUNCTION__, int(buf - start), lenP); + } + break; + + default: + break; + } + + if (aud_found) + break; + + buf += consumed + 4; + } + + if (aud_found) { + videoHandlerM->SetVideoCodec(VIDEO_CODEC_H265); + //videoHandlerM->SetVideoFormat(formatM); + //videoHandlerM->SetVideoSize(widthM, heightM); + //videoHandlerM->SetVideoAspectRatio(aspectRatioM); + //videoHandlerM->SetVideoBitrate(bitRateM); + //videoHandlerM->SetVideoScan(scanM); + //videoHandlerM->SetVideoFramerate((scanM == VIDEO_SCAN_PROGRESSIVE) ? (frameRateM / 2) : frameRateM); + } + + return aud_found; +} + +void cFemonH265::reset() +{ +} + +const uint8_t *cFemonH265::nextStartCode(const uint8_t *startP, const uint8_t *endP) +{ + for (endP -= 3; startP < endP; ++startP) { + if ((startP[0] == 0x00) && (startP[1] == 0x00) && (startP[2] == 0x01)) + return startP; + } + return (endP + 3); +} + +int cFemonH265::nalUnescape(uint8_t *dstP, const uint8_t *srcP, int lenP) +{ + int s = 0, d = 0; + + while (s < lenP) { + if (!srcP[s] && !srcP[s + 1]) { + // hit 00 00 xx + dstP[d] = dstP[d + 1] = 0; + s += 2; + d += 2; + if (srcP[s] == 3) { + s++; // 00 00 03 xx --> 00 00 xx + if (s >= lenP) + return d; + } + } + dstP[d++] = srcP[s++]; + } + + return d; +} diff --git a/h265.h b/h265.h new file mode 100644 index 0000000..30d8dbf --- /dev/null +++ b/h265.h @@ -0,0 +1,44 @@ +/* + * h265.h: Frontend Status Monitor plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#ifndef __FEMON_H265_H +#define __FEMON_H265_H + +#include "video.h" + +class cFemonH265 { +private: + enum { + NAL_VPS = 32, // Video Parameter Set + NAL_SPS = 33, // Sequence Parameter Set + NAL_PPS = 34, // Picture Parameter Set + NAL_AUD = 35, // Access Unit Delimiter + NAL_EOS = 36, // End of Sequence + NAL_EOB = 37, // End of Bitstream + }; + + cFemonVideoIf *videoHandlerM; + uint32_t widthM; + uint32_t heightM; + eVideoAspectRatio aspectRatioM; + eVideoFormat formatM; + double frameRateM; + double bitRateM; + eVideoScan scanM; + + void reset(); + const uint8_t *nextStartCode(const uint8_t *start, const uint8_t *end); + int nalUnescape(uint8_t *dst, const uint8_t *src, int len); + +public: + cFemonH265(cFemonVideoIf *videoHandlerP); + virtual ~cFemonH265(); + + bool processVideo(const uint8_t *bufP, int lenP); + }; + +#endif //__FEMON_H265_H diff --git a/osd.c b/osd.c index 6228287..dab3fab 100644 --- a/osd.c +++ b/osd.c @@ -341,6 +341,7 @@ void cFemonOsd::DrawStatusWindow(void) switch (receiverM->VideoCodec()) { case VIDEO_CODEC_MPEG2: bm = &OSDSYMBOL(SYMBOL_MPEG2); break; case VIDEO_CODEC_H264: bm = &OSDSYMBOL(SYMBOL_H264); break; + case VIDEO_CODEC_H265: bm = &OSDSYMBOL(SYMBOL_H265); break; default: bm = NULL; break; } OSDDRAWSTATUSBM(OSDSPACING); diff --git a/receiver.c b/receiver.c index c5c1cef..240f1a1 100644 --- a/receiver.c +++ b/receiver.c @@ -19,6 +19,7 @@ cFemonReceiver::cFemonReceiver(const cChannel *channelP, int aTrackP, int dTrack sleepM(), activeM(false), detectH264M(this), + detectH265M(this), detectMpegM(this, this), detectAacM(this), detectLatmM(this), @@ -163,12 +164,18 @@ void cFemonReceiver::Action(void) processed = true; if (TsPayloadStart(Data)) { while (const uint8_t *p = videoAssemblerM.GetPes(len)) { - if (videoTypeM == 0x1B) { // MPEG4 + if (videoTypeM == 0x1B) { if (detectH264M.processVideo(p, len)) { videoValidM = true; break; } } + else if (videoTypeM == 0x24) { + if (detectH265M.processVideo(p, len)) { + videoValidM = true; + break; + } + } else { if (detectMpegM.processVideo(p, len)) { videoValidM = true; diff --git a/receiver.h b/receiver.h index abd5c6e..b2e6891 100644 --- a/receiver.h +++ b/receiver.h @@ -15,6 +15,7 @@ #include "ac3.h" #include "audio.h" #include "h264.h" +#include "h265.h" #include "latm.h" #include "mpeg.h" #include "tools.h" @@ -27,6 +28,7 @@ private: bool activeM; cFemonH264 detectH264M; + cFemonH265 detectH265M; cFemonMPEG detectMpegM; cFemonAAC detectAacM; cFemonLATM detectLatmM; diff --git a/symbol.c b/symbol.c index a645b9f..6dc6084 100644 --- a/symbol.c +++ b/symbol.c @@ -19,6 +19,7 @@ #include "symbols/dolbydigital51.xpm" #include "symbols/mpeg2.xpm" #include "symbols/h264.xpm" +#include "symbols/h265.xpm" #include "symbols/ntsc.xpm" #include "symbols/pal.xpm" #include "symbols/encrypted.xpm" @@ -64,6 +65,7 @@ static cBitmap bmDolbyDigital20(dolbydigital20_xpm); static cBitmap bmDolbyDigital51(dolbydigital51_xpm); static cBitmap bmMpeg2(mpeg2_xpm); static cBitmap bmH264(h264_xpm); +static cBitmap bmH265(h265_xpm); static cBitmap bmPal(pal_xpm); static cBitmap bmNtsc(ntsc_xpm); static cBitmap bmEncrypted(encrypted_xpm); @@ -146,6 +148,7 @@ bool cFemonSymbolCache::Populate(void) cacheM.Append(bmDolbyDigital51.Scaled(yFactorM, yFactorM, antiAliasM)); // SYMBOL_DD51 cacheM.Append(bmMpeg2.Scaled(yFactorM, yFactorM, antiAliasM)); // SYMBOL_MPEG2 cacheM.Append(bmH264.Scaled(yFactorM, yFactorM, antiAliasM)); // SYMBOL_H264 + cacheM.Append(bmH265.Scaled(yFactorM, yFactorM, antiAliasM)); // SYMBOL_H265 cacheM.Append(bmPal.Scaled(yFactorM, yFactorM, antiAliasM)); // SYMBOL_PAL cacheM.Append(bmNtsc.Scaled(yFactorM, yFactorM, antiAliasM)); // SYMBOL_NTSC cacheM.Append(bmEncrypted.Scaled(yFactorM, yFactorM, antiAliasM)); // SYMBOL_ENCRYPTED diff --git a/symbol.h b/symbol.h index de8a462..fbfed60 100644 --- a/symbol.h +++ b/symbol.h @@ -21,6 +21,7 @@ enum eSymbols { SYMBOL_DD51, SYMBOL_MPEG2, SYMBOL_H264, + SYMBOL_H265, SYMBOL_PAL, SYMBOL_NTSC, SYMBOL_ENCRYPTED, diff --git a/symbols/h265.xpm b/symbols/h265.xpm new file mode 100644 index 0000000..7be7c20 --- /dev/null +++ b/symbols/h265.xpm @@ -0,0 +1,23 @@ +/* XPM */ +static const char *const h265_xpm[] = { +"40 18 2 1", +". c #FFFFFF", +"+ c #000000", +"++++++++++++++++++++++++++++++++++++++++", +"+......................................+", +"+..++...++.....+++++...+++++..+++++++..+", +"+..++...++....+++++++.+++++++.+++++++..+", +"+..++...++....++...++.++...++.++.......+", +"+..++...++.........++.++......++.......+", +"+..++...++.........++.++......++.......+", +"+..++...++........+++.++......++.......+", +"+..+++++++.......+++..++++++..++++++...+", +"+..+++++++......+++...+++++++.+++++++..+", +"+..++...++.....+++....++...++.....+++..+", +"+..++...++....+++.....++...++......++..+", +"+..++...++....++......++...++......++..+", +"+..++...++....++...++.++...++.++...++..+", +"+..++...++.++.+++++++.+++++++.++...++..+", +"+..++...++.++.+++++++..+++++...+++++...+", +"+......................................+", +"++++++++++++++++++++++++++++++++++++++++"}; diff --git a/video.h b/video.h index 01ff131..e75e7e7 100644 --- a/video.h +++ b/video.h @@ -12,7 +12,8 @@ enum eVideoCodec { VIDEO_CODEC_INVALID = -1, VIDEO_CODEC_UNKNOWN, VIDEO_CODEC_MPEG2, - VIDEO_CODEC_H264 + VIDEO_CODEC_H264, + VIDEO_CODEC_H265 }; enum eVideoFormat {