Skip to content
Snippets Groups Projects
Commit c7e61ddb authored by Nicolas Pope's avatar Nicolas Pope
Browse files

Merge branch 'bug/h264-pps-fix' into 'main'

H264 Parse Fixes

See merge request beyondaka/beyond-protocol!41
parents d604ca7e 13c9cd83
No related branches found
No related tags found
No related merge requests found
...@@ -29,8 +29,9 @@ int main(int argc, char *argv[]) { ...@@ -29,8 +29,9 @@ int main(int argc, char *argv[]) {
if (spkt.channel == Channel::kColour && pkt.codec == Codec::kH264) { if (spkt.channel == Channel::kColour && pkt.codec == Codec::kH264) {
try { try {
auto slices = parser->parse(pkt.data); auto slices = parser->parse(pkt.data);
int ix = 0;
for (const ftl::codec::h264::Slice &s : slices) { for (const ftl::codec::h264::Slice &s : slices) {
LOG(INFO) << "Slice (" << spkt.timestamp << ")" << std::endl << ftl::codec::h264::prettySlice(s); LOG(INFO) << "Slice (" << spkt.timestamp << ", " << ix++ << ")" << std::endl << ftl::codec::h264::prettySlice(s);
} }
} catch (const std::exception &e) { } catch (const std::exception &e) {
LOG(ERROR) << e.what(); LOG(ERROR) << e.what();
......
...@@ -87,9 +87,9 @@ struct PPS { ...@@ -87,9 +87,9 @@ struct PPS {
bool constrained_intra_pred = false; bool constrained_intra_pred = false;
bool redundant_pic_cnt_present = false; bool redundant_pic_cnt_present = false;
int transform_8x8_mode = 0; int transform_8x8_mode = 0;
uint8_t scaling_matrix4[6][16]; uint8_t scaling_matrix4[6][16]; // NOT Populated
uint8_t scaling_matrix8[2][64]; uint8_t scaling_matrix8[2][64]; // NOT Populated
uint8_t chroma_qp_table[2][64]; uint8_t chroma_qp_table[2][64]; // NOT Populated
int chroma_qp_diff = 0; int chroma_qp_diff = 0;
}; };
...@@ -102,7 +102,7 @@ struct SPS{ ...@@ -102,7 +102,7 @@ struct SPS{
int log2_max_frame_num = 0; int log2_max_frame_num = 0;
int maxFrameNum = 0; int maxFrameNum = 0;
POCType poc_type = POCType::kType0; POCType poc_type = POCType::kType0;
int log2_max_poc_lsb = 0; int log2_max_poc_lsb = 4;
bool delta_pic_order_always_zero_flag = false; bool delta_pic_order_always_zero_flag = false;
int offset_for_non_ref_pic = 0; int offset_for_non_ref_pic = 0;
int offset_for_top_to_bottom_field = 0; int offset_for_top_to_bottom_field = 0;
...@@ -248,6 +248,7 @@ class Parser { ...@@ -248,6 +248,7 @@ class Parser {
void _parsePPS(ftl::codec::detail::ParseContext *ctx, size_t length); void _parsePPS(ftl::codec::detail::ParseContext *ctx, size_t length);
void _parseSPS(ftl::codec::detail::ParseContext *ctx, size_t length); void _parseSPS(ftl::codec::detail::ParseContext *ctx, size_t length);
void _checkEnding(ftl::codec::detail::ParseContext *ctx, size_t length);
bool _skipToNAL(ftl::codec::detail::ParseContext *ctx); bool _skipToNAL(ftl::codec::detail::ParseContext *ctx);
Slice _createSlice(ftl::codec::detail::ParseContext *ctx, const NALHeader &header, size_t length); Slice _createSlice(ftl::codec::detail::ParseContext *ctx, const NALHeader &header, size_t length);
}; };
......
...@@ -33,12 +33,12 @@ static NALHeader extractNALHeader(ParseContext *ctx) { ...@@ -33,12 +33,12 @@ static NALHeader extractNALHeader(ParseContext *ctx) {
bool ftl::codec::h264::Parser::_skipToNAL(ParseContext *ctx) { bool ftl::codec::h264::Parser::_skipToNAL(ParseContext *ctx) {
uint32_t code = 0xFFFFFFFF; uint32_t code = 0xFFFFFFFF;
while (ctx->index < ctx->length && code != 1) { while (ctx->index < ctx->length && (code & 0xFFFFFF) != 1) {
code = (code << 8) | ctx->ptr[ctx->index >> 3]; code = (code << 8) | ctx->ptr[ctx->index >> 3];
ctx->index += 8; ctx->index += 8;
} }
return (code == 1); return ((code & 0xFFFFFF) == 1);
} }
static void decodeScalingList(ParseContext *ctx, uint8_t *factors, int size) { static void decodeScalingList(ParseContext *ctx, uint8_t *factors, int size) {
...@@ -78,8 +78,6 @@ void ftl::codec::h264::Parser::_parseSPS(ParseContext *ctx, size_t length) { ...@@ -78,8 +78,6 @@ void ftl::codec::h264::Parser::_parseSPS(ParseContext *ctx, size_t length) {
unsigned int sps_id = golombUnsigned31(ctx); unsigned int sps_id = golombUnsigned31(ctx);
sps_.id = sps_id; sps_.id = sps_id;
LOG(INFO) << "Parse SPS " << sps_.id;
sps_.profile_idc = static_cast<ProfileIDC>(profile_idc); sps_.profile_idc = static_cast<ProfileIDC>(profile_idc);
sps_.level_idc = static_cast<LevelIDC>(level_idc); sps_.level_idc = static_cast<LevelIDC>(level_idc);
...@@ -161,21 +159,57 @@ void ftl::codec::h264::Parser::_parseSPS(ParseContext *ctx, size_t length) { ...@@ -161,21 +159,57 @@ void ftl::codec::h264::Parser::_parseSPS(ParseContext *ctx, size_t length) {
sps_.vui_parameters_present_flag = getBits1(ctx); sps_.vui_parameters_present_flag = getBits1(ctx);
if (sps_.vui_parameters_present_flag) { if (sps_.vui_parameters_present_flag) {
// TODO(Nick): decode VUI if (getBits1(ctx)) {
// Aspect ratio info
int ratio_idc = getBits(ctx, 8);
if (ratio_idc == 255) {
LOG(WARNING) << "Extended SAR";
}
}
if (getBits1(ctx)) {
getBits1(ctx);
}
sps_.video_signal_type_present_flag = getBits1(ctx);
if (sps_.video_signal_type_present_flag) {
LOG(WARNING) << "Video signal info present";
}
if (getBits1(ctx)) {
LOG(WARNING) << "Chromo location info";
}
sps_.timing_info_present_flag = getBits1(ctx);
if (sps_.timing_info_present_flag) {
sps_.num_units_in_tick = getBits(ctx, 32);
sps_.time_scale = getBits(ctx, 32);
sps_.fixed_frame_rate_flag = getBits1(ctx);
}
sps_.nal_hrd_parameters_present_flag = getBits1(ctx);
if (sps_.nal_hrd_parameters_present_flag) {
LOG(WARNING) << "NAL HRD present";
}
sps_.vcl_hrd_parameters_present_flag = getBits1(ctx);
if (sps_.vcl_hrd_parameters_present_flag) {
LOG(WARNING) << "VCL HRD present";
}
sps_.pic_struct_present_flag = getBits1(ctx);
sps_.bitstream_restriction_flag = getBits1(ctx);
if (sps_.bitstream_restriction_flag) {
LOG(WARNING) << "Bitstream restriction";
}
} }
_checkEnding(ctx, length);
} }
void ftl::codec::h264::Parser::_parsePPS(ParseContext *ctx, size_t length) { void ftl::codec::h264::Parser::_parsePPS(ParseContext *ctx, size_t length) {
pps_.id = golombUnsigned(ctx); pps_.id = golombUnsigned(ctx);
pps_.sps_id = golombUnsigned31(ctx); pps_.sps_id = golombUnsigned31(ctx);
LOG(INFO) << "Parse PPS " << pps_.id << ", " << pps_.sps_id; pps_.cabac = getBits1(ctx); // Entropy encoding mode
pps_.cabac = getBits1(ctx);
pps_.pic_order_present = getBits1(ctx); pps_.pic_order_present = getBits1(ctx);
pps_.slice_group_count = golombUnsigned(ctx); pps_.slice_group_count = golombUnsigned(ctx) + 1;
if (pps_.slice_group_count > 1) { if (pps_.slice_group_count > 1) {
pps_.mb_slice_group_map_type = golombUnsigned(ctx); pps_.mb_slice_group_map_type = golombUnsigned(ctx);
LOG(WARNING) << "Slice group parsing";
} }
pps_.ref_count[0] = golombUnsigned(ctx) + 1; pps_.ref_count[0] = golombUnsigned(ctx) + 1;
pps_.ref_count[1] = golombUnsigned(ctx) + 1; pps_.ref_count[1] = golombUnsigned(ctx) + 1;
...@@ -193,9 +227,41 @@ void ftl::codec::h264::Parser::_parsePPS(ParseContext *ctx, size_t length) { ...@@ -193,9 +227,41 @@ void ftl::codec::h264::Parser::_parsePPS(ParseContext *ctx, size_t length) {
if (ctx->index < length) { if (ctx->index < length) {
// Read some other stuff // Read some other stuff
pps_.transform_8x8_mode = getBits1(ctx);
// Decode scaling matrices
if (getBits1(ctx)) {
LOG(WARNING) << "HAS SCALING MATRIX";
}
pps_.chroma_qp_index_offset[1] = golombSigned(ctx);
} else { } else {
pps_.chroma_qp_index_offset[1] = pps_.chroma_qp_index_offset[0]; pps_.chroma_qp_index_offset[1] = pps_.chroma_qp_index_offset[0];
} }
// TODO: Build QP table.
if (pps_.chroma_qp_index_offset[0] != pps_.chroma_qp_index_offset[1]) {
pps_.chroma_qp_diff = 1;
}
_checkEnding(ctx, length);
}
void ftl::codec::h264::Parser::_checkEnding(ParseContext *ctx, size_t length) {
if (!getBits1(ctx)) {
throw FTL_Error("Missing NAL stop bit");
}
int remainingBits = 8 - (ctx->index % 8);
if (remainingBits != 8) {
if (getBits(ctx, remainingBits) != 0) {
throw FTL_Error("Non-zero terminating bits");
}
}
if (length - ctx->index != 16) {
throw FTL_Error("No trailing zero word");
}
if (getBits(ctx, 16) != 0) {
throw FTL_Error("Trailing bits not zero");
}
} }
Slice ftl::codec::h264::Parser::_createSlice(ParseContext *ctx, const NALHeader &header, size_t length) { Slice ftl::codec::h264::Parser::_createSlice(ParseContext *ctx, const NALHeader &header, size_t length) {
...@@ -320,20 +386,20 @@ std::list<Slice> ftl::codec::h264::Parser::parse(const std::vector<uint8_t> &dat ...@@ -320,20 +386,20 @@ std::list<Slice> ftl::codec::h264::Parser::parse(const std::vector<uint8_t> &dat
while (true) { while (true) {
bool hasNext = _skipToNAL(&nextCtx); bool hasNext = _skipToNAL(&nextCtx);
offset = parseCtx.index; offset = parseCtx.index;
length = nextCtx.index - parseCtx.index; length = (hasNext) ? nextCtx.index - parseCtx.index - 24 : data.size() * 8 - parseCtx.index;
// auto type = ftl::codecs::h264::extractNALType(&parseCtx); // auto type = ftl::codecs::h264::extractNALType(&parseCtx);
auto header = extractNALHeader(&parseCtx); auto header = extractNALHeader(&parseCtx);
auto type = static_cast<NALType>(header.type); auto type = static_cast<NALType>(header.type);
switch (type) { switch (type) {
case NALType::SPS: case NALType::SPS:
_parseSPS(&parseCtx, 0); _parseSPS(&parseCtx, length + parseCtx.index);
if (parseCtx.index > nextCtx.index) { if (parseCtx.index > nextCtx.index) {
throw FTL_Error("Bad SPS parse"); throw FTL_Error("Bad SPS parse");
} }
break; break;
case NALType::PPS: case NALType::PPS:
_parsePPS(&parseCtx, 0); _parsePPS(&parseCtx, length + parseCtx.index);
if (parseCtx.index > nextCtx.index) { if (parseCtx.index > nextCtx.index) {
throw FTL_Error("Bad PPS parse"); throw FTL_Error("Bad PPS parse");
} }
...@@ -399,6 +465,7 @@ std::string ftl::codec::h264::prettyPPS(const PPS &pps) { ...@@ -399,6 +465,7 @@ std::string ftl::codec::h264::prettyPPS(const PPS &pps) {
stream << " - weighted_pred: " << std::to_string(pps.weighted_pred) << std::endl; stream << " - weighted_pred: " << std::to_string(pps.weighted_pred) << std::endl;
stream << " - init_qp: " << std::to_string(pps.init_qp) << std::endl; stream << " - init_qp: " << std::to_string(pps.init_qp) << std::endl;
stream << " - init_qs: " << std::to_string(pps.init_qs) << std::endl; stream << " - init_qs: " << std::to_string(pps.init_qs) << std::endl;
stream << " - transform_8x8_mode: " << std::to_string(pps.transform_8x8_mode) << std::endl;
return stream.str(); return stream.str();
} }
...@@ -409,6 +476,7 @@ std::string ftl::codec::h264::prettySPS(const SPS &sps) { ...@@ -409,6 +476,7 @@ std::string ftl::codec::h264::prettySPS(const SPS &sps) {
stream << " - level_idc: " << std::to_string(static_cast<int>(sps.level_idc)) << std::endl; stream << " - level_idc: " << std::to_string(static_cast<int>(sps.level_idc)) << std::endl;
stream << " - chroma_format_idc: " << std::to_string(static_cast<int>(sps.chroma_format_idc)) << std::endl; stream << " - chroma_format_idc: " << std::to_string(static_cast<int>(sps.chroma_format_idc)) << std::endl;
stream << " - transform_bypass: " << std::to_string(sps.transform_bypass) << std::endl; stream << " - transform_bypass: " << std::to_string(sps.transform_bypass) << std::endl;
stream << " - scaling_matrix_present: " << std::to_string(sps.scaling_matrix_present) << std::endl;
stream << " - maxFrameNum: " << std::to_string(sps.maxFrameNum) << std::endl; stream << " - maxFrameNum: " << std::to_string(sps.maxFrameNum) << std::endl;
stream << " - poc_type: " << std::to_string(static_cast<int>(sps.poc_type)) << std::endl; stream << " - poc_type: " << std::to_string(static_cast<int>(sps.poc_type)) << std::endl;
stream << " - offset_for_non_ref_pic: " << std::to_string(sps.offset_for_non_ref_pic) << std::endl; stream << " - offset_for_non_ref_pic: " << std::to_string(sps.offset_for_non_ref_pic) << std::endl;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment