tagparser/avc/avcinfo.cpp

292 lines
11 KiB
C++
Raw Permalink Normal View History

2015-09-06 19:57:33 +02:00
#include "./avcinfo.h"
2015-04-22 19:22:01 +02:00
2016-02-17 20:19:05 +01:00
#include "../exceptions.h"
#include <c++utilities/io/binaryreader.h>
#include <c++utilities/io/bitreader.h>
2017-02-05 21:02:40 +01:00
#include <memory>
2018-03-07 01:17:50 +01:00
#include <unordered_map>
2015-04-22 19:22:01 +02:00
2016-02-17 20:19:05 +01:00
using namespace std;
2019-06-10 22:49:11 +02:00
using namespace CppUtilities;
2016-02-17 20:19:05 +01:00
namespace TagParser {
2015-04-22 19:22:01 +02:00
/*!
* \struct TagParser::SpsInfo
* \brief The SpsInfo struct holds the sequence parameter set.
*/
/*!
2016-02-17 20:19:05 +01:00
* \brief Parses the SPS info.
*/
2019-03-13 19:06:42 +01:00
void SpsInfo::parse(BinaryReader &reader, std::uint32_t maxSize)
2016-02-17 20:19:05 +01:00
{
// read (and check) size
if ((maxSize < minSize) || (size = reader.readUInt16BE()) > (maxSize - minSize)) {
2016-02-17 20:19:05 +01:00
throw TruncatedDataException();
}
// buffer data for reading with BitReader
auto buffer = make_unique<char[]>(size);
reader.read(buffer.get(), size);
BitReader bitReader(buffer.get(), size);
try {
// read general values
bitReader.skipBits(3);
2019-03-13 19:06:42 +01:00
if (bitReader.readBits<std::uint8_t>(5) != 7) {
2016-02-17 20:19:05 +01:00
throw InvalidDataException();
}
2019-03-13 19:06:42 +01:00
profileIndication = bitReader.readBits<std::uint8_t>(8);
profileConstraints = bitReader.readBits<std::uint8_t>(8);
levelIndication = bitReader.readBits<std::uint8_t>(8);
2016-02-17 20:19:05 +01:00
id = bitReader.readUnsignedExpGolombCodedBits<ugolomb>();
// read chroma profile specific values
2018-03-07 01:17:50 +01:00
switch (profileIndication) {
case 44:
case 83:
case 86:
case 100:
case 110:
case 118:
case 122:
case 128:
case 244:
2016-02-17 20:19:05 +01:00
// high-level profile
2018-03-07 01:17:50 +01:00
if ((chromaFormatIndication = bitReader.readUnsignedExpGolombCodedBits<ugolomb>()) == 3) {
2016-02-17 20:19:05 +01:00
bitReader.skipBits(1); // separate color plane flag
}
2019-03-13 19:06:42 +01:00
bitReader.readUnsignedExpGolombCodedBits<std::uint8_t>(); // bit depth luma minus8
bitReader.readUnsignedExpGolombCodedBits<std::uint8_t>(); // bit depth chroma minus8
2016-02-17 20:19:05 +01:00
bitReader.skipBits(1); // qpprime y zero transform bypass flag
2018-03-07 01:17:50 +01:00
if (bitReader.readBit()) { // sequence scaling matrix present flag
2019-03-13 19:06:42 +01:00
for (std::uint8_t i = 0; i < 8; ++i) {
2016-02-17 20:19:05 +01:00
// TODO: store values
2018-03-07 01:17:50 +01:00
if (bitReader.readBit()) { // sequence scaling list present
if (i < 6) {
2016-02-17 20:19:05 +01:00
bitReader.skipBits(16); // scalingList4x4[i]
} else {
bitReader.skipBits(64); // scalingList8x8[i - 6]
}
}
}
}
break;
default:
chromaFormatIndication = 1; // assume YUV 4:2:0
}
// read misc values
log2MaxFrameNum = bitReader.readUnsignedExpGolombCodedBits<ugolomb>() + 4;
2018-03-07 01:17:50 +01:00
switch (pictureOrderCountType = bitReader.readUnsignedExpGolombCodedBits<ugolomb>()) {
2016-02-17 20:19:05 +01:00
case 0:
log2MaxPictureOrderCountLsb = bitReader.readUnsignedExpGolombCodedBits<ugolomb>() + 4;
break;
case 1:
deltaPicOrderAlwaysZeroFlag = bitReader.readBit();
offsetForNonRefPic = bitReader.readSignedExpGolombCodedBits<sgolomb>();
offsetForTopToBottomField = bitReader.readSignedExpGolombCodedBits<sgolomb>();
numRefFramesInPicOrderCntCycle = bitReader.readUnsignedExpGolombCodedBits<ugolomb>();
2019-03-13 19:06:42 +01:00
for (std::uint8_t i = 0; i < numRefFramesInPicOrderCntCycle; ++i) {
2016-02-17 20:19:05 +01:00
bitReader.readUnsignedExpGolombCodedBits<ugolomb>(); // offset for ref frames
}
break;
case 2:
break;
default:
throw InvalidDataException();
}
bitReader.readUnsignedExpGolombCodedBits<ugolomb>(); // ref frames num
bitReader.skipBits(1); // gaps in frame num value allowed flag
// read picture size related values
Size mbSize;
2019-03-13 19:06:42 +01:00
mbSize.setWidth(bitReader.readUnsignedExpGolombCodedBits<std::uint32_t>() + 1);
mbSize.setHeight(bitReader.readUnsignedExpGolombCodedBits<std::uint32_t>() + 1);
2018-03-07 01:17:50 +01:00
if (!(frameMbsOnly = bitReader.readBit())) { // frame mbs only flag
2016-02-17 20:19:05 +01:00
bitReader.readBit(); // mb adaptive frame field flag
}
bitReader.skipBits(1); // distinct 8x8 inference flag
// read cropping values
2018-03-07 01:17:50 +01:00
if (bitReader.readBit()) { // frame cropping flag
2019-03-13 19:06:42 +01:00
cropping.setLeft(bitReader.readUnsignedExpGolombCodedBits<std::uint32_t>());
cropping.setRight(bitReader.readUnsignedExpGolombCodedBits<std::uint32_t>());
cropping.setTop(bitReader.readUnsignedExpGolombCodedBits<std::uint32_t>());
cropping.setBottom(bitReader.readUnsignedExpGolombCodedBits<std::uint32_t>());
2016-02-17 20:19:05 +01:00
}
// calculate actual picture size
2018-03-07 01:17:50 +01:00
if (!cropping.isNull()) {
// determine cropping scale
ugolomb croppingScaleX, croppingScaleY;
2018-03-07 01:17:50 +01:00
switch (chromaFormatIndication) {
case 1: // 4:2:0
croppingScaleX = 2;
croppingScaleY = frameMbsOnly ? 2 : 4;
break;
case 2: // 4:2:2
croppingScaleX = 2;
croppingScaleY = 2 - frameMbsOnly;
break;
default: // case 0: monochrome, case 3: 4:4:4
croppingScaleX = 1;
croppingScaleY = 2 - frameMbsOnly;
break;
}
pictureSize.setWidth(mbSize.width() * 16 - croppingScaleX * (cropping.left() + cropping.right()));
pictureSize.setHeight((2 - frameMbsOnly) * mbSize.height() * 16 - croppingScaleY * (cropping.top() + cropping.bottom()));
} else {
pictureSize.setWidth(mbSize.width() * 16);
pictureSize.setHeight((2 - frameMbsOnly) * mbSize.height() * 16);
}
2016-02-17 20:19:05 +01:00
// read VUI (video usability information)
2018-03-07 01:17:50 +01:00
if ((vuiPresent = bitReader.readBit())) {
if ((bitReader.readBit())) { // PAR present flag
2019-03-13 19:06:42 +01:00
pixelAspectRatio = AspectRatio(bitReader.readBits<std::uint8_t>(8));
2018-03-07 01:17:50 +01:00
if (pixelAspectRatio.isExtended()) {
2016-02-17 20:19:05 +01:00
// read extended SAR
2019-03-13 19:06:42 +01:00
pixelAspectRatio.numerator = bitReader.readBits<std::uint16_t>(16);
pixelAspectRatio.denominator = bitReader.readBits<std::uint16_t>(16);
2016-02-17 20:19:05 +01:00
}
}
// read/skip misc values
2018-03-07 01:17:50 +01:00
if (bitReader.readBit()) { // overscan info present
2016-02-17 20:19:05 +01:00
bitReader.skipBits(1); // overscan appropriate
}
2018-03-07 01:17:50 +01:00
if (bitReader.readBit()) { // video signal type present
2016-02-17 20:19:05 +01:00
bitReader.skipBits(4); // video format and video full range
2018-03-07 01:17:50 +01:00
if (bitReader.readBit()) { // color description present
2016-02-17 20:19:05 +01:00
bitReader.skipBits(24); // color primaries, transfer characteristics, matrix coefficients
}
}
2018-03-07 01:17:50 +01:00
if (bitReader.readBit()) { // chroma loc info present
2019-03-13 19:06:42 +01:00
bitReader.readUnsignedExpGolombCodedBits<std::uint8_t>(); // chroma sample loc type top field
bitReader.readUnsignedExpGolombCodedBits<std::uint8_t>(); // chroma sample loc type bottom field
2016-02-17 20:19:05 +01:00
}
// read timing info
2018-03-07 01:17:50 +01:00
if ((timingInfo.isPresent = bitReader.readBit())) {
2019-03-13 19:06:42 +01:00
timingInfo.unitsInTick = bitReader.readBits<std::uint32_t>(32);
timingInfo.timeScale = bitReader.readBits<std::uint32_t>(32);
2016-02-17 20:19:05 +01:00
timingInfo.fixedFrameRate = bitReader.readBit();
}
// skip hrd parameters
hrdParametersPresent = 0;
2018-03-07 01:17:50 +01:00
if (bitReader.readBit()) { // nal hrd parameters present
2016-02-17 20:19:05 +01:00
nalHrdParameters.parse(bitReader);
hrdParametersPresent = 1;
}
2018-03-07 01:17:50 +01:00
if (bitReader.readBit()) { // vcl hrd parameters present
2016-02-17 20:19:05 +01:00
vclHrdParameters.parse(bitReader);
hrdParametersPresent = 1;
}
2018-03-07 01:17:50 +01:00
if (hrdParametersPresent) {
2016-02-17 20:19:05 +01:00
bitReader.skipBits(1); // low delay hrd flag
}
pictureStructPresent = bitReader.readBit();
// TODO: investigate error (truncated data) when parsing mtx-test-data/mkv/attachment-without-fileuid.mkv
2018-03-07 01:17:50 +01:00
if (bitReader.readBit()) { // bitstream restriction flag
2021-07-02 03:00:50 +02:00
bitReader.skipBits(1); // motion vectors over pic boundaries flag
2019-03-13 19:06:42 +01:00
bitReader.readUnsignedExpGolombCodedBits<std::uint8_t>(); // max bytes per pic denom
bitReader.readUnsignedExpGolombCodedBits<std::uint8_t>(); // max bytes per mb denom
bitReader.readUnsignedExpGolombCodedBits<std::uint8_t>(); // log2 max mv length horizontal
bitReader.readUnsignedExpGolombCodedBits<std::uint8_t>(); // log2 max mv length vertical
bitReader.readUnsignedExpGolombCodedBits<std::uint8_t>(); // reorder frames num
bitReader.readUnsignedExpGolombCodedBits<std::uint8_t>(); // max decoder frame buffering
2016-02-17 20:19:05 +01:00
}
}
2019-03-13 19:06:42 +01:00
} catch (const std::ios_base::failure &) {
2016-02-17 20:19:05 +01:00
throw TruncatedDataException();
}
}
/*!
* \struct TagParser::PpsInfo
2016-02-17 20:19:05 +01:00
* \brief The PpsInfo struct holds the picture parameter set.
*/
/*!
* \brief Parses the PPS info.
*/
2019-03-13 19:06:42 +01:00
void PpsInfo::parse(BinaryReader &reader, std::uint32_t maxSize)
2015-04-22 19:22:01 +02:00
{
2016-02-17 20:19:05 +01:00
// read (and check) size
if ((maxSize < minSize) || (size = reader.readUInt16BE()) > (maxSize - minSize)) {
2016-02-17 20:19:05 +01:00
throw TruncatedDataException();
}
2015-04-22 19:22:01 +02:00
2016-02-17 20:19:05 +01:00
// buffer data for reading with BitReader
auto buffer = make_unique<char[]>(size);
reader.read(buffer.get(), size);
BitReader bitReader(buffer.get(), size);
2015-04-22 19:22:01 +02:00
2016-02-17 20:19:05 +01:00
try {
// read general values
bitReader.skipBits(1); // zero bit
2019-03-13 19:06:42 +01:00
if (bitReader.readBits<std::uint8_t>(5) != 8) { // nal unit type
throw NotImplementedException();
2016-02-17 20:19:05 +01:00
}
id = bitReader.readUnsignedExpGolombCodedBits<ugolomb>();
spsId = bitReader.readUnsignedExpGolombCodedBits<ugolomb>();
bitReader.skipBits(1); // entropy coding mode flag
picOrderPresent = bitReader.readBit();
2019-03-13 19:06:42 +01:00
} catch (const std::ios_base::failure &) {
2016-02-17 20:19:05 +01:00
throw TruncatedDataException();
}
}
2015-04-22 19:22:01 +02:00
2016-02-17 20:19:05 +01:00
/*!
* \struct TagParser::HrdParameters
2016-02-17 20:19:05 +01:00
* \brief The HrdParameters struct holds "Hypothetical Reference Decoder" parameters.
* \remarks This is "a model for thinking about the decoding process".
*/
2015-04-22 19:22:01 +02:00
2016-02-17 20:19:05 +01:00
/*!
* \brief Parses HRD parameters.
*/
2019-06-10 22:49:11 +02:00
void HrdParameters::parse(CppUtilities::BitReader &reader)
2016-02-17 20:19:05 +01:00
{
cpbCount = reader.readUnsignedExpGolombCodedBits<ugolomb>() + 1;
2019-03-13 19:06:42 +01:00
bitRateScale = reader.readBits<std::uint8_t>(4);
cpbSizeScale = reader.readBits<std::uint8_t>(4);
2018-03-07 01:17:50 +01:00
for (ugolomb i = 0; i < cpbCount; ++i) {
2016-02-17 20:19:05 +01:00
// just skip those values
2019-03-13 19:06:42 +01:00
reader.readUnsignedExpGolombCodedBits<std::uint8_t>(); // bit rate value minus 1
reader.readUnsignedExpGolombCodedBits<std::uint8_t>(); // cpb size value minus 1
2016-02-17 20:19:05 +01:00
reader.skipBits(1); // cbr flag
}
2019-03-13 19:06:42 +01:00
initialCpbRemovalDelayLength = reader.readBits<std::uint8_t>(5) + 1;
cpbRemovalDelayLength = reader.readBits<std::uint8_t>(5) + 1;
cpbOutputDelayLength = reader.readBits<std::uint8_t>(5) + 1;
timeOffsetLength = reader.readBits<std::uint8_t>(5);
2015-04-22 19:22:01 +02:00
}
2016-08-04 00:16:19 +02:00
/*!
* \struct TagParser::TimingInfo
2016-08-04 00:16:19 +02:00
* \brief The TimingInfo struct holds timing information (part of SPS info).
*/
2015-04-22 19:22:01 +02:00
2016-08-04 00:16:19 +02:00
/*!
* \struct TagParser::SliceInfo
2016-08-04 00:16:19 +02:00
* \brief The SliceInfo struct holds the slice information of an AVC frame.
* \remarks currently not useful, might be removed
*/
/*!
* \struct TagParser::AvcFrame
2016-08-04 00:16:19 +02:00
* \brief The AvcFrame struct holds an AVC frame.
* \remarks currently not useful, might be removed
*/
2015-04-22 19:22:01 +02:00
2018-03-07 01:17:50 +01:00
} // namespace TagParser