Detect H.265 video resolution.

This commit is contained in:
Rolf Ahrenberg 2017-02-24 20:49:44 +02:00
parent ba767e02bf
commit 3e78ac0987
8 changed files with 189 additions and 15 deletions

113
h265.c
View File

@ -17,7 +17,7 @@ cFemonH265::cFemonH265(cFemonVideoIf *videoHandlerP)
formatM(VIDEO_FORMAT_INVALID),
frameRateM(0),
bitRateM(0),
scanM(VIDEO_SCAN_INVALID)
scanM(VIDEO_SCAN_PROGRESSIVE)
{
reset();
}
@ -28,7 +28,8 @@ cFemonH265::~cFemonH265()
bool cFemonH265::processVideo(const uint8_t *bufP, int lenP)
{
bool aud_found = false;
uint8_t nal_data[lenP];
bool aud_found = false, sps_found = false;
const uint8_t *buf = bufP;
const uint8_t *start = buf;
const uint8_t *end = start + lenP;
@ -54,8 +55,18 @@ bool cFemonH265::processVideo(const uint8_t *bufP, int lenP)
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);
aud_found = true;
}
break;
case NAL_SPS:
if (!sps_found) {
debug2("%s Found NAL SPS at offset %d/%d", __PRETTY_FUNCTION__, int(buf - start), lenP);
int nal_len = nalUnescape(nal_data, buf + 4, int(end - buf - 4));
consumed = parseSPS(nal_data, nal_len);
if (consumed > 0)
sps_found = true;
}
break;
@ -63,23 +74,26 @@ bool cFemonH265::processVideo(const uint8_t *bufP, int lenP)
break;
}
if (aud_found)
if (aud_found && sps_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);
}
if (aud_found) {
videoHandlerM->SetVideoCodec(VIDEO_CODEC_H265);
if (sps_found) {
debug2("%s width=%d height=%d, aspect=%d format=%d bitrate=%.0f scan=%d framerate=%.2f", __PRETTY_FUNCTION__, widthM, heightM, aspectRatioM, formatM, bitRateM, scanM, frameRateM);
videoHandlerM->SetVideoSize(widthM, heightM);
videoHandlerM->SetVideoScan(scanM);
//videoHandlerM->SetVideoFormat(formatM);
//videoHandlerM->SetVideoAspectRatio(aspectRatioM);
//videoHandlerM->SetVideoBitrate(bitRateM);
//videoHandlerM->SetVideoFramerate(frameRateM);
}
}
return aud_found;
return sps_found;
}
void cFemonH265::reset()
@ -116,3 +130,74 @@ int cFemonH265::nalUnescape(uint8_t *dstP, const uint8_t *srcP, int lenP)
return d;
}
int cFemonH265::parseSPS(const uint8_t *bufP, int lenP)
{
cFemonBitStream bs(bufP, lenP);
uint32_t width = widthM;
uint32_t height = heightM;
bool profilePresentFlag = true;
unsigned int chroma_format_idc;
uint8_t sps_max_sub_layers_minus1;
uint8_t sub_layer_profile_present_flag[8];
uint8_t sub_layer_level_present_flag[8];
bs.SkipBits(4); // sps_video_parameter_set_id
sps_max_sub_layers_minus1 = bs.GetBits(3); // sps_max_sub_layers_minus1
bs.SkipBit(); // sps_temporal_id_nesting_flag
// start of profile_tier_level(1, sps_max_sub_layers_minus1)
if (profilePresentFlag) {
bs.SkipBits(2); // general_profile_space
bs.SkipBit(); // general_profile_space
bs.SkipBits(5); // general_profile_idc
bs.SkipBits(32); // general_profile_compatibility_flag[0-31]
bs.SkipBit(); // general_progressive_source_flag
bs.SkipBit(); // general_interlaced_source_flag
bs.SkipBit(); // general_non_packed_constraint_flag
bs.SkipBit(); // general_frame_only_constraint_flag
// the number of bits in this syntax structure is not affected by this condition
bs.SkipBits(43); // general_reserved_zero_43bits
// the number of bits in this syntax structure is not affected by this condition
bs.SkipBit(); // general_reserved_zero_bit
}
bs.SkipBits(8); // general_level_idc
for (int i = 0; i < sps_max_sub_layers_minus1; ++i) {
sub_layer_profile_present_flag[i] = bs.GetBit(); // sub_layer_profile_present_flag[i]
sub_layer_level_present_flag[i] = bs.GetBit(); // sub_layer_level_present_flag[i]
}
if (sps_max_sub_layers_minus1 > 0) {
for (int i = sps_max_sub_layers_minus1; i < 8; ++i)
bs.SkipBits(2); // reserved_zero_2bits[i]
}
for (int i = 0; i < sps_max_sub_layers_minus1; ++i) {
if (sub_layer_profile_present_flag[i]) {
bs.SkipBits(2); // sub_layer_profile_space[i]
bs.SkipBit(); // sub_layer_tier_flag[i]
bs.SkipBits(5); // sub_layer_profile_idc[i]
bs.SkipBits(32); // sub_layer_profile_compatibility_flag[i][0-31]
bs.SkipBit(); // sub_layer_progressive_source_flag[i]
bs.SkipBit(); // sub_layer_interlaced_source_flag[i]
bs.SkipBit(); // sub_layer_non_packed_constraint_flag[i]
bs.SkipBit(); // sub_layer_frame_only_constraint_flag[i]
// the number of bits in this syntax structure is not affected by this condition
bs.SkipBits(43); // sub_layer_reserved_zero_43bits[i]
// the number of bits in this syntax structure is not affected by this condition
bs.SkipBit(); // sub_layer_reserved_zero_bit[i]
}
if (sub_layer_level_present_flag[i])
bs.SkipBits(8); // sub_layer_level_idc[i]
}
// end of profile_tier_level
bs.SkipUeGolomb(); // sps_seq_parameter_set_id
chroma_format_idc = bs.GetUeGolomb(); // chroma_format_idc
if (chroma_format_idc == 3)
bs.SkipBit(); // separate_colour_plane_flag
width = bs.GetUeGolomb(); // pic_width_in_luma_samples
height = bs.GetUeGolomb(); // pic_height_in_luma_samples
widthM = width;
heightM = height;
return (bs.Index() / 8);
}

1
h265.h
View File

@ -33,6 +33,7 @@ private:
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);
int parseSPS(const uint8_t *buf, int len);
public:
cFemonH265(cFemonVideoIf *videoHandlerP);

9
osd.c
View File

@ -307,7 +307,14 @@ void cFemonOsd::DrawStatusWindow(void)
OSDDRAWSTATUSBM(OSDSPACING);
}
if (receiverM) {
if (IS_OSDRESOLUTION(receiverM->VideoVerticalSize(), 1080)) {
if (IS_OSDRESOLUTION(receiverM->VideoVerticalSize(), 2160)) {
switch (receiverM->VideoScan()) {
case VIDEO_SCAN_INTERLACED: bm = &OSDSYMBOL(SYMBOL_FORMAT_2160i); break;
case VIDEO_SCAN_PROGRESSIVE: bm = &OSDSYMBOL(SYMBOL_FORMAT_2160p); break;
default: bm = &OSDSYMBOL(SYMBOL_FORMAT_2160); break;
}
}
else if (IS_OSDRESOLUTION(receiverM->VideoVerticalSize(), 1080)) {
switch (receiverM->VideoScan()) {
case VIDEO_SCAN_INTERLACED: bm = &OSDSYMBOL(SYMBOL_FORMAT_1080i); break;
case VIDEO_SCAN_PROGRESSIVE: bm = &OSDSYMBOL(SYMBOL_FORMAT_1080p); break;

View File

@ -43,6 +43,9 @@
#include "symbols/six.xpm"
#include "symbols/seven.xpm"
#include "symbols/eight.xpm"
#include "symbols/format2160.xpm"
#include "symbols/format2160i.xpm"
#include "symbols/format2160p.xpm"
#include "symbols/format1080.xpm"
#include "symbols/format1080i.xpm"
#include "symbols/format1080p.xpm"
@ -89,6 +92,9 @@ static cBitmap bmFive(five_xpm);
static cBitmap bmSix(six_xpm);
static cBitmap bmSeven(seven_xpm);
static cBitmap bmEight(eight_xpm);
static cBitmap bmFormat2160(format2160_xpm);
static cBitmap bmFormat2160i(format2160i_xpm);
static cBitmap bmFormat2160p(format2160p_xpm);
static cBitmap bmFormat1080(format1080_xpm);
static cBitmap bmFormat1080i(format1080i_xpm);
static cBitmap bmFormat1080p(format1080p_xpm);
@ -172,6 +178,9 @@ bool cFemonSymbolCache::Populate(void)
cacheM.Append(bmSix.Scaled(yFactorM, yFactorM, antiAliasM)); // SYMBOL_SIX
cacheM.Append(bmSeven.Scaled(yFactorM, yFactorM, antiAliasM)); // SYMBOL_SEVEN
cacheM.Append(bmEight.Scaled(yFactorM, yFactorM, antiAliasM)); // SYMBOL_EIGHT
cacheM.Append(bmFormat2160.Scaled(yFactorM, yFactorM, antiAliasM)); // SYMBOL_FORMAT_2160
cacheM.Append(bmFormat2160i.Scaled(yFactorM, yFactorM, antiAliasM)); // SYMBOL_FORMAT_2160i
cacheM.Append(bmFormat2160p.Scaled(yFactorM, yFactorM, antiAliasM)); // SYMBOL_FORMAT_2160p
cacheM.Append(bmFormat1080.Scaled(yFactorM, yFactorM, antiAliasM)); // SYMBOL_FORMAT_1080
cacheM.Append(bmFormat1080i.Scaled(yFactorM, yFactorM, antiAliasM)); // SYMBOL_FORMAT_1080i
cacheM.Append(bmFormat1080p.Scaled(yFactorM, yFactorM, antiAliasM)); // SYMBOL_FORMAT_1080p

View File

@ -45,6 +45,9 @@ enum eSymbols {
SYMBOL_SIX,
SYMBOL_SEVEN,
SYMBOL_EIGHT,
SYMBOL_FORMAT_2160,
SYMBOL_FORMAT_2160i,
SYMBOL_FORMAT_2160p,
SYMBOL_FORMAT_1080,
SYMBOL_FORMAT_1080i,
SYMBOL_FORMAT_1080p,

23
symbols/format2160.xpm Normal file
View File

@ -0,0 +1,23 @@
/* XPM */
static const char *const format2160_xpm[] = {
"40 18 2 1",
". c #FFFFFF",
"+ c #000000",
"++++++++++++++++++++++++++++++++++++++++",
"+......................................+",
"+.....++++......++..++++++....++++.....+",
"+...+++++++..+++++.++++++++..++++++....+",
"+...++....++.+++++.+++...++..++..++....+",
"+.........++....++.++.......++....++...+",
"+.........++....++.++.......++....++...+",
"+.........++....++.++.+++...++....++...+",
"+.......+++.....++.+++++++..++....++...+",
"+......+++......++.+++..+++.++....++...+",
"+.....+++.......++.++....++.++....++...+",
"+.....+++.......++.++....++.++....++...+",
"+....+++........++.++....++.++....++...+",
"+....++.........++.+++..+++..++..++....+",
"+....++++++++...++..+++++++..++++++....+",
"+....++++++++...++...+++++....++++.....+",
"+......................................+",
"++++++++++++++++++++++++++++++++++++++++"};

23
symbols/format2160i.xpm Normal file
View File

@ -0,0 +1,23 @@
/* XPM */
static const char *const format2160i_xpm[] = {
"43 18 2 1",
". c #FFFFFF",
"+ c #000000",
"+++++++++++++++++++++++++++++++++++++++++++",
"+.........................................+",
"+.....++++......++..++++++....++++........+",
"+...+++++++..+++++.++++++++..++++++.......+",
"+...++....++.+++++.+++...++..++..++.......+",
"+.........++....++.++.......++....++......+",
"+.........++....++.++.......++....++.++...+",
"+.........++....++.++.+++...++....++.++...+",
"+.......+++.....++.+++++++..++....++......+",
"+......+++......++.+++..+++.++....++.++...+",
"+.....+++.......++.++....++.++....++.++...+",
"+.....+++.......++.++....++.++....++.++...+",
"+....+++........++.++....++.++....++.++...+",
"+....++.........++.+++..+++..++..++..++...+",
"+....++++++++...++..+++++++..++++++..++...+",
"+....++++++++...++...+++++....++++...++...+",
"+.........................................+",
"+++++++++++++++++++++++++++++++++++++++++++"};

23
symbols/format2160p.xpm Normal file
View File

@ -0,0 +1,23 @@
/* XPM */
static const char *const format2160p_xpm[] = {
"47 18 2 1",
". c #FFFFFF",
"+ c #000000",
"+++++++++++++++++++++++++++++++++++++++++++++++",
"+.............................................+",
"+.....++++......++..++++++....++++............+",
"+...+++++++..+++++.++++++++..++++++...........+",
"+...++....++.+++++.+++...++..++..++...........+",
"+.........++....++.++.......++....++..........+",
"+.........++....++.++.......++....++..........+",
"+.........++....++.++.+++...++....++.++++.....+",
"+.......+++.....++.+++++++..++....++.+++++....+",
"+......+++......++.+++..+++.++....++.++..++...+",
"+.....+++.......++.++....++.++....++.++..++...+",
"+.....+++.......++.++....++.++....++.+++++....+",
"+....+++........++.++....++.++....++.++++.....+",
"+....++.........++.+++..+++..++..++..++.......+",
"+....++++++++...++..+++++++..++++++..++.......+",
"+....++++++++...++...+++++....++++...++.......+",
"+.............................................+",
"+++++++++++++++++++++++++++++++++++++++++++++++"};