From de0423a9daa327e5428fbace007abf60104e20bb Mon Sep 17 00:00:00 2001 From: Thulinma Date: Mon, 15 Feb 2021 21:15:59 +0100 Subject: [PATCH] Fixed H264 analyser + H264 pretty printing improvements --- lib/h264.cpp | 53 +++++++++++++++++++++++++++++++-- lib/h264.h | 3 ++ src/analysers/analyser.cpp | 2 +- src/analysers/analyser_h264.cpp | 38 +++++++++++++---------- 4 files changed, 78 insertions(+), 18 deletions(-) diff --git a/lib/h264.cpp b/lib/h264.cpp index 464c2be4..76948a54 100644 --- a/lib/h264.cpp +++ b/lib/h264.cpp @@ -428,16 +428,63 @@ namespace h264{ payload.insert(4, 1, 0x08); } + const char* spsUnit::profile(){ + if (profileIdc == 66){ + if (constraintSet1Flag){return "Constrained baseline";} + return "Baseline"; + } + if (profileIdc == 77){return "Main";} + if (profileIdc == 88){return "Extended";} + if (profileIdc == 100){return "High";} + if (profileIdc == 110){ + if (constraintSet3Flag){return "High-10 Intra";} + return "High-10"; + } + if (profileIdc == 122){ + if (constraintSet3Flag){return "High-4:2:2 Intra";} + return "High-4:2:2"; + } + if (profileIdc == 244){ + if (constraintSet3Flag){return "High-4:4:4 Intra";} + return "High-4:4:4"; + } + if (profileIdc == 44){return "CAVLC 4:4:4 Intra";} + return "Unknown"; + } + + const char* spsUnit::level(){ + if (levelIdc == 9){return "1b";} + if (levelIdc == 10){return "1";} + if (levelIdc == 11){ + if (constraintSet3Flag){return "1b";} + return "1.1"; + } + if (levelIdc == 12){return "1.2";} + if (levelIdc == 13){return "1.3";} + if (levelIdc == 20){return "2";} + if (levelIdc == 21){return "2.1";} + if (levelIdc == 21){return "2.2";} + if (levelIdc == 30){return "3";} + if (levelIdc == 31){return "3.1";} + if (levelIdc == 31){return "3.2";} + if (levelIdc == 40){return "4";} + if (levelIdc == 41){return "4.1";} + if (levelIdc == 41){return "4.2";} + if (levelIdc == 50){return "5";} + if (levelIdc == 51){return "5.1";} + return "Unknown"; + } + void spsUnit::toPrettyString(std::ostream &out){ out << "Nal unit of type " << (((uint8_t)payload[0]) & 0x1F) << " [Sequence Parameter Set] , " << payload.size() << " bytes long" << std::endl; out << " profile_idc: 0x" << std::setw(2) << std::setfill('0') << std::hex << (int)profileIdc - << std::dec << " (" << (int)profileIdc << ")" << std::endl; + << std::dec << " (" << (int)profileIdc << ") = " << profile() << std::endl; out << " contraints: " << (constraintSet0Flag ? "0 " : "") << (constraintSet1Flag ? "1 " : "") << (constraintSet2Flag ? "2 " : "") << (constraintSet3Flag ? "3 " : "") << (constraintSet4Flag ? "4 " : "") << (constraintSet5Flag ? "5" : "") << std::endl; out << " level_idc: 0x" << std::setw(2) << std::setfill('0') << std::hex << (int)levelIdc - << std::dec << " (" << (int)profileIdc << ")" << std::endl; + << std::dec << " (" << (int)levelIdc << ") = " << level() << std::endl; out << " seq_parameter_set_id: " << seqParameterSetId << (seqParameterSetId >= 32 ? " INVALID" : "") << std::endl; switch (profileIdc){ @@ -1052,10 +1099,12 @@ namespace h264{ chromaSampleLocTypeBottomField = bs.getUExpGolomb(); } timingInfoPresentFlag = bs.get(1); + derived_fps = 0.0; if (timingInfoPresentFlag){ numUnitsInTick = bs.get(32); timeScale = bs.get(32); fixedFrameRateFlag = bs.get(1); + derived_fps = (double)timeScale / (2 * numUnitsInTick); } nalHrdParametersPresentFlag = bs.get(1); // hrd param nal diff --git a/lib/h264.h b/lib/h264.h index e05e4a36..5f92a66b 100644 --- a/lib/h264.h +++ b/lib/h264.h @@ -150,6 +150,7 @@ namespace h264{ uint64_t log2MaxMvLengthVertical; uint64_t numReorderFrames; uint64_t maxDecFrameBuffering; + double derived_fps; }; class spsUnit : public nalUnit{ @@ -158,6 +159,8 @@ namespace h264{ ~spsUnit(){ if (scalingListPresentFlags != NULL){free(scalingListPresentFlags);} } + const char* profile(); + const char* level(); std::string generate(); void toPrettyString(std::ostream &out); void scalingList(uint64_t *scalingList, size_t sizeOfScalingList, diff --git a/src/analysers/analyser.cpp b/src/analysers/analyser.cpp index 4838f1ac..c47e9f88 100644 --- a/src/analysers/analyser.cpp +++ b/src/analysers/analyser.cpp @@ -51,7 +51,7 @@ bool Analyser::isOpen(){ int Analyser::run(Util::Config &conf){ isActive = &conf.is_active; if (!open(conf.getString("filename"))){return 1;} - while (conf.is_active && isOpen()){ + while (conf.is_active){ if (!parsePacket()){ if (isOpen()){ FAIL_MSG("Could not parse packet!"); diff --git a/src/analysers/analyser_h264.cpp b/src/analysers/analyser_h264.cpp index aee5173f..42d46c22 100644 --- a/src/analysers/analyser_h264.cpp +++ b/src/analysers/analyser_h264.cpp @@ -34,26 +34,34 @@ bool AnalyserH264::parsePacket(){ } size_t size = 0; - h264::nalUnit *nalPtr; - do{ - size = 0; - nalPtr = h264::nalFactory(dataBuffer.data(), dataBuffer.size(), size, !sizePrepended); - if (nalPtr){ - HIGH_MSG("Read a %lu-byte NAL unit at position %" PRIu64, size, prePos); - if (detail >= 2){nalPtr->toPrettyString(std::cout);} - dataBuffer.erase(0, size); // erase the NAL unit we just read - prePos += size; - return true; + h264::nalUnit *nalPtr = h264::nalFactory(dataBuffer.data(), dataBuffer.size(), size, !sizePrepended); + if (!nalPtr){ + FAIL_MSG("Could not read a NAL unit at position %" PRIu64, prePos); + return false; + } + HIGH_MSG("Read a %lu-byte NAL unit at position %" PRIu64, size, prePos); + if (detail >= 2){nalPtr->toPrettyString(std::cout);} + //SPS unit? Find the FPS, if any. + if (nalPtr->getType() == 7){ + h264::spsUnit *sps = (h264::spsUnit*)nalPtr; + if (sps->vuiParametersPresentFlag && sps->vuiParams.fixedFrameRateFlag){ + INFO_MSG("Frame rate: %f", sps->vuiParams.derived_fps); + }else{ + INFO_MSG("Frame rate undetermined - assuming 25 FPS"); } - ///\TODO update mediaTime with current timestamp - }while (nalPtr); - FAIL_MSG("Could not read a NAL unit at position %" PRIu64, prePos); - return false; + } + dataBuffer.erase(0, size); // erase the NAL unit we just read + prePos += size; + ///\TODO update mediaTime with current timestamp + return true; } uint64_t AnalyserH264::neededBytes(){ // We buffer a megabyte if AnnexB - if (!sizePrepended){return 1024 * 1024;} + if (!sizePrepended){ + if (isOpen()){return 1024 * 1024;} + return dataBuffer.size(); + } // otherwise, buffer the exact size needed if (dataBuffer.size() < 4){return 4;} return Bit::btohl(dataBuffer.data()) + 4;