Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/479 lib dav1d support #484

Draft
wants to merge 15 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
More work
  • Loading branch information
ChristianFeldmann committed Nov 11, 2022
commit 9f2dd1d3497324a0d6c26840f14c9512cf5cac20
13 changes: 13 additions & 0 deletions YUViewLib/src/common/Typedef.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,19 @@ struct Offset
int y{};
};

struct FileStartEndPos
{
int64_t start{};
int64_t end{};
};

std::string to_string(const FileStartEndPos fileStartEndPos)
{
std::ostringstream ss;
ss << "(" << fileStartEndPos.start << ", " << fileStartEndPos.end << ")";
return ss.str();
}

// A list of value pair lists, where every list has a string (title)
class ValuePairListSets : public QList<QPair<QString, QStringPairList>>
{
Expand Down
8 changes: 3 additions & 5 deletions YUViewLib/src/filesource/FileSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,12 @@ const auto InputFormatMapper = EnumMapper<InputFormat>({{InputFormat::Invalid, "
{InputFormat::OBUAV1, "OBUAV1"},
{InputFormat::Libav, "Libav"}});

struct FileStartEndPos
struct DataAndStartEndPos
{
int64_t start{};
int64_t end{};
QByteArray data{};
FileStartEndPos startEnd{};
};

using DataAndStartEndPos = std::pair<QByteArray, FileStartEndPos>;

/* The FileSource class provides functions for accessing files. Besides the reading of
* certain blocks of the file, it also directly provides information on the file for the
* fileInfoWidget. It also adds functions for guessing the format from the filename.
Expand Down
52 changes: 22 additions & 30 deletions YUViewLib/src/filesource/FileSourceAnnexBFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,13 @@ void FileSourceAnnexBFile::seekToFirstNAL()
this->nrBytesBeforeFirstNAL = this->bufferStartPosInFile + uint64_t(this->posInBuffer);
}

QByteArray FileSourceAnnexBFile::getNextNALUnit(bool getLastDataAgain,
pairUint64 *startEndPosInFile)
DataAndStartEndPos FileSourceAnnexBFile::getNextNALUnit(bool getLastDataAgain)
{
if (getLastDataAgain)
return this->lastReturnArray;
return this->lastDataAndPos;

this->lastReturnArray.clear();

if (startEndPosInFile)
startEndPosInFile->first = this->bufferStartPosInFile + uint64_t(this->posInBuffer);
this->lastDataAndPos.data.clear();
this->lastDataAndPos.startEnd.start = this->bufferStartPosInFile + this->posInBuffer;

int nextStartCodePos = -1;
int searchOffset = 3;
Expand All @@ -109,25 +106,24 @@ QByteArray FileSourceAnnexBFile::getNextNALUnit(bool getLastDataAgain,
// Part of the start code was in the last buffer (see special boundary cases below). Add those
// parts.
const auto nrZeroBytesMissing = std::abs(this->posInBuffer);
this->lastReturnArray.append(nrZeroBytesMissing, char(0));
this->lastDataAndPos.data.append(nrZeroBytesMissing, char(0));
}
nextStartCodePos = this->fileBuffer.indexOf(STARTCODE, this->posInBuffer + searchOffset);

if (nextStartCodePos < 0 || (uint64_t)nextStartCodePos > this->fileBufferSize)
{
// No start code found ... append all data in the current buffer.
this->lastReturnArray +=
this->lastDataAndPos.data +=
this->fileBuffer.mid(this->posInBuffer, this->fileBufferSize - this->posInBuffer);
DEBUG_ANNEXBFILE("FileSourceHEVCAnnexBFile::getNextNALUnit no start code found - ret size "
<< this->lastReturnArray.size());
<< this->lastDataAndPos.data.size());

if (this->fileBufferSize < BUFFERSIZE)
{
// We are out of file and could not find a next position
this->posInBuffer = BUFFERSIZE;
if (startEndPosInFile)
startEndPosInFile->second = this->bufferStartPosInFile + this->fileBufferSize - 1;
return this->lastReturnArray;
this->posInBuffer = BUFFERSIZE;
this->lastDataAndPos.startEnd.end = this->bufferStartPosInFile + this->fileBufferSize - 1;
return this->lastDataAndPos;
}

// Before we load the next bytes: The start code might be located at the boundary to the next
Expand All @@ -137,7 +133,7 @@ QByteArray FileSourceAnnexBFile::getNextNALUnit(bool getLastDataAgain,
const auto lastByteZero2 = this->fileBuffer.at(this->fileBufferSize - 1) == (char)0;

// We have to continue searching - get the next buffer
updateBuffer();
this->updateBuffer();

if (this->fileBufferSize > 2)
{
Expand All @@ -148,7 +144,7 @@ QByteArray FileSourceAnnexBFile::getNextNALUnit(bool getLastDataAgain,
// buffer
startCodeFound = true;
nextStartCodePos = lastByteZero0 ? -3 : -2;
this->lastReturnArray.chop(lastByteZero0 ? 3 : 2);
this->lastDataAndPos.data.chop(lastByteZero0 ? 3 : 2);
}
else if (this->fileBuffer.at(0) == (char)0 && this->fileBuffer.at(1) == (char)1 &&
lastByteZero2)
Expand All @@ -157,7 +153,7 @@ QByteArray FileSourceAnnexBFile::getNextNALUnit(bool getLastDataAgain,
// last buffer
startCodeFound = true;
nextStartCodePos = lastByteZero1 ? -2 : -1;
this->lastReturnArray.chop(lastByteZero0 ? 1 : 1);
this->lastDataAndPos.data.chop(lastByteZero0 ? 1 : 1);
}
else if (this->fileBuffer.at(0) == (char)0 && this->fileBuffer.at(1) == (char)0 &&
this->fileBuffer.at(2) == (char)1)
Expand All @@ -166,7 +162,7 @@ QByteArray FileSourceAnnexBFile::getNextNALUnit(bool getLastDataAgain,
startCodeFound = true;
nextStartCodePos = lastByteZero2 ? -1 : 0;
if (lastByteZero2)
this->lastReturnArray.chop(1);
this->lastDataAndPos.data.chop(1);
}
}

Expand All @@ -182,35 +178,31 @@ QByteArray FileSourceAnnexBFile::getNextNALUnit(bool getLastDataAgain,
}

// Position found
if (startEndPosInFile)
startEndPosInFile->second = this->bufferStartPosInFile + nextStartCodePos;
this->lastDataAndPos.startEnd.end = this->bufferStartPosInFile + nextStartCodePos;
if (nextStartCodePos > int(this->posInBuffer))
this->lastReturnArray +=
this->lastDataAndPos.data +=
this->fileBuffer.mid(this->posInBuffer, nextStartCodePos - this->posInBuffer);
this->posInBuffer = nextStartCodePos;
DEBUG_ANNEXBFILE("FileSourceAnnexBFile::getNextNALUnit start code found - ret size "
<< this->lastReturnArray.size());
return this->lastReturnArray;
<< this->lastDataAndPos.data.size());
return this->lastDataAndPos;
}

QByteArray FileSourceAnnexBFile::getFrameData(pairUint64 startEndFilePos)
QByteArray FileSourceAnnexBFile::getFrameData(const FileStartEndPos &startEndFilePos)
{
// Get all data for the frame (all NAL units in the raw format with start codes).
// We don't need to convert the format to the mp4 ISO format. The ffmpeg decoder can also accept
// raw NAL units. When the extradata is set as raw NAL units, the AVPackets must also be raw NAL
// units.
QByteArray retArray;

auto start = startEndFilePos.first;
auto end = startEndFilePos.second;

// Seek the source file to the start position
this->seek(start);
this->seek(startEndFilePos.start);

// Retrieve NAL units (and repackage them) until we reached out end position
while (end > this->bufferStartPosInFile + this->posInBuffer)
while (startEndFilePos.end > this->bufferStartPosInFile + this->posInBuffer)
{
auto nalData = this->getNextNALUnit();
auto [nalData, fileStartEndPos] = this->getNextNALUnit();

int headerOffset = 0;
if (nalData.at(0) == (char)0 && nalData.at(1) == (char)0)
Expand Down
12 changes: 6 additions & 6 deletions YUViewLib/src/filesource/FileSourceAnnexBFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,21 +59,21 @@ class FileSourceAnnexBFile : public FileSource
// Also return the start and end position of the NAL unit in the file so you can seek to it.
// startEndPosInFile: The file positions of the first byte in the NAL header and the end position
// of the last byte
QByteArray getNextNALUnit(bool getLastDataAgain = false, pairUint64 *startEndPosInFile = nullptr);
DataAndStartEndPos getNextNALUnit(bool getLastDataAgain = false);

// Get all bytes that are needed to decode the next frame (from the given start to the given end
// position) The data will be returned in the ISO/IEC 14496-15 format (4 bytes size followed by
// the payload).
QByteArray getFrameData(pairUint64 startEndFilePos);
QByteArray getFrameData(const FileStartEndPos &startEndFilePos);

bool seek(int64_t pos) override;

[[nodiscard]] uint64_t getNrBytesBeforeFirstNAL() const { return this->nrBytesBeforeFirstNAL; }

protected:
QByteArray fileBuffer;
uint64_t fileBufferSize{0}; ///< How many of the bytes are used? We don't resize the fileBuffer
uint64_t bufferStartPosInFile{
int64_t fileBufferSize{0}; ///< How many of the bytes are used? We don't resize the fileBuffer
int64_t bufferStartPosInFile{
0}; ///< The byte position in the file of the start of the currently loaded buffer

// The current position in the input buffer in bytes. This always points to the first byte of a
Expand All @@ -86,7 +86,7 @@ class FileSourceAnnexBFile : public FileSource
void seekToFirstNAL();

// We will keep the last buffer in case the reader wants to get it again
QByteArray lastReturnArray;
DataAndStartEndPos lastDataAndPos;

uint64_t nrBytesBeforeFirstNAL{0};
int64_t nrBytesBeforeFirstNAL{0};
};
2 changes: 1 addition & 1 deletion YUViewLib/src/filesource/FileSourceOBUFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class FileSourceOBUFile : public FileSource

// Get the next OBU. Also return the start and end position of the OBU in the file so
// you can seek to it.
[[nodiscard]] DataAndStartEndPos getNextOBU(bool getLastDataAgain = false);
DataAndStartEndPos getNextOBU(bool getLastDataAgain = false);

protected:
// We will keep the last buffer in case the reader wants to get it again
Expand Down
10 changes: 6 additions & 4 deletions YUViewLib/src/parser/AV1/AV1OBU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,12 @@ ParserAV1OBU::ParserAV1OBU(QObject *parent) : Base(parent)
this->decValues.PrevFrameID = -1;
}

std::pair<size_t, std::string> ParserAV1OBU::parseAndAddOBU(int obuID,
ByteVector & data,
std::shared_ptr<TreeItem> parent,
pairUint64 obuStartEndPosFile)
Base::ParseResult
ParserAV1OBU::parseAndAddUnit(int obuID,
const ByteVector & data,
std::optional<BitratePlotModel::BitrateEntry> bitrateEntry,
std::optional<FileStartEndPos> obuStartEndPosFile = {},
std::shared_ptr<TreeItem> parent = nullptr)
{
// Use the given tree item. If it is not set, use the nalUnitMode (if active).
// We don't set data (a name) for this item yet.
Expand Down
12 changes: 6 additions & 6 deletions YUViewLib/src/parser/AV1/AV1OBU.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,18 @@ class ParserAV1OBU : public Base
ParserAV1OBU(QObject *parent = nullptr);
~ParserAV1OBU() {}

std::pair<size_t, std::string> parseAndAddOBU(int obuID,
ByteVector & data,
std::shared_ptr<TreeItem> parent,
pairUint64 obuStartEndPosFile = pairUint64(-1, -1));
ParseResult parseAndAddUnit(int obuID,
const ByteVector & data,
std::optional<BitratePlotModel::BitrateEntry> bitrateEntry,
std::optional<FileStartEndPos> nalStartEndPosFile = {},
std::shared_ptr<TreeItem> parent = nullptr);

// So far, we only parse AV1 Obu files from the AVFormat parser so we don't need this (yet).
// When parsing of raw OBU files is added, we will need this.
bool runParsingOfFile(QString) override
{
assert(false);
return false;
}

QList<QTreeWidgetItem *> getStreamInfo() override { return {}; }
unsigned int getNrStreams() override { return 1; }
QString getShortStreamDescription(int) const override { return "Video"; }
Expand Down
6 changes: 3 additions & 3 deletions YUViewLib/src/parser/AV1/OpenBitstreamUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class ObuPayload
class OpenBitstreamUnit
{
public:
OpenBitstreamUnit(int obu_idx, std::optional<pairUint64> filePosStartEnd) : obu_idx(obu_idx)
OpenBitstreamUnit(int obu_idx, std::optional<FileStartEndPos> filePosStartEnd) : obu_idx(obu_idx)
{
if (filePosStartEnd)
this->filePosStartEnd = *filePosStartEnd;
Expand All @@ -61,8 +61,8 @@ class OpenBitstreamUnit
std::shared_ptr<ObuPayload> payload;

// Pointer to the first byte of the start code of the NAL unit
pairUint64 filePosStartEnd;
int obu_idx{};
FileStartEndPos filePosStartEnd;
int obu_idx{};
};

} // namespace parser::av1
36 changes: 18 additions & 18 deletions YUViewLib/src/parser/AVC/AnnexBAVC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ struct CurrentSliceData

std::optional<FrameParsingData>
getFrameDataWithUpdatedPosition(std::optional<FrameParsingData> data,
std::optional<pairUint64> nalStartEndPosFile,
std::optional<FileStartEndPos> nalStartEndPosFile,
std::optional<CurrentSliceData> currentSliceData)
{
auto newData = data.value_or(FrameParsingData());
Expand All @@ -80,7 +80,7 @@ getFrameDataWithUpdatedPosition(std::optional<FrameParsingData> data,
if (!newData.fileStartEndPos)
newData.fileStartEndPos = nalStartEndPosFile;
else
newData.fileStartEndPos->second = nalStartEndPosFile->second;
newData.fileStartEndPos->end = nalStartEndPosFile->end;
}
if (currentSliceData)
{
Expand Down Expand Up @@ -178,11 +178,11 @@ video::yuv::PixelFormatYUV AnnexBAVC::getPixelFormat() const
}

AnnexB::ParseResult
AnnexBAVC::parseAndAddNALUnit(int nalID,
const ByteVector & data,
std::optional<BitratePlotModel::BitrateEntry> bitrateEntry,
std::optional<pairUint64> nalStartEndPosFile,
std::shared_ptr<TreeItem> parent)
AnnexBAVC::parseAndAddUnit(int nalID,
const ByteVector & data,
std::optional<BitratePlotModel::BitrateEntry> bitrateEntry,
std::optional<FileStartEndPos> nalStartEndPosFile,
std::shared_ptr<TreeItem> parent)
{
AnnexB::ParseResult parseResult;

Expand Down Expand Up @@ -269,7 +269,7 @@ AnnexBAVC::parseAndAddNALUnit(int nalI
nalAVC->rbsp = newSPS;
nalAVC->rawData = data;
this->nalUnitsForSeeking.push_back(nalAVC);
parseResult.nalTypeName =
parseResult.unitTypeName =
"SPS(" + std::to_string(newSPS->seqParameterSetData.seq_parameter_set_id) + ") ";
}
else if (nalAVC->header.nal_unit_type == NalType::PPS)
Expand All @@ -287,7 +287,7 @@ AnnexBAVC::parseAndAddNALUnit(int nalI
nalAVC->rbsp = newPPS;
nalAVC->rawData = data;
this->nalUnitsForSeeking.push_back(nalAVC);
parseResult.nalTypeName = "PPS(" + std::to_string(newPPS->pic_parameter_set_id) + ") ";
parseResult.unitTypeName = "PPS(" + std::to_string(newPPS->pic_parameter_set_id) + ") ";
}
else if (nalAVC->header.nal_unit_type == NalType::CODED_SLICE_NON_IDR ||
nalAVC->header.nal_unit_type == NalType::CODED_SLICE_IDR ||
Expand Down Expand Up @@ -364,25 +364,25 @@ AnnexBAVC::parseAndAddNALUnit(int nalI
currentSliceType = to_string(newSliceHeader->slice_type);

DEBUG_AVC("AnnexBAVC::parseAndAddNALUnit Parsed Slice POC " << newSliceHeader->globalPOC);
parseResult.nalTypeName = "Slice(POC " + std::to_string(newSliceHeader->globalPOC) + ") ";
parseResult.unitTypeName = "Slice(POC " + std::to_string(newSliceHeader->globalPOC) + ") ";
}
else if (nalAVC->header.nal_unit_type == NalType::CODED_SLICE_DATA_PARTITION_B)
{
if (!this->currentAUPartitionASPS)
throw std::logic_error("No partition A slice header found.");
auto slice = std::make_shared<slice_data_partition_b_layer_rbsp>();
slice->parse(reader, this->currentAUPartitionASPS);
specificDescription = " Slice Partition B";
parseResult.nalTypeName = "Slice-PartB ";
specificDescription = " Slice Partition B";
parseResult.unitTypeName = "Slice-PartB ";
}
else if (nalAVC->header.nal_unit_type == NalType::CODED_SLICE_DATA_PARTITION_C)
{
if (!this->currentAUPartitionASPS)
throw std::logic_error("No partition A slice header found.");
auto slice = std::make_shared<slice_data_partition_c_layer_rbsp>();
slice->parse(reader, this->currentAUPartitionASPS);
specificDescription = " Slice Partition C";
parseResult.nalTypeName = "Slice-PartC ";
specificDescription = " Slice Partition C";
parseResult.unitTypeName = "Slice-PartC ";
}
else if (nalAVC->header.nal_unit_type == NalType::SEI)
{
Expand Down Expand Up @@ -420,19 +420,19 @@ AnnexBAVC::parseAndAddNALUnit(int nalI
specificDescription += "(x" + std::to_string(newSEI->seis.size()) + ")";
DEBUG_AVC("AnnexBAVC::parseAndAddNALUnit Parsed SEI (" << newSEI->seis.size()
<< " messages)");
parseResult.nalTypeName = "SEI(x" + std::to_string(newSEI->seis.size()) + ") ";
parseResult.unitTypeName = "SEI(x" + std::to_string(newSEI->seis.size()) + ") ";
}
else if (nalAVC->header.nal_unit_type == NalType::FILLER)
{
specificDescription = " Filler";
DEBUG_AVC("AnnexBAVC::parseAndAddNALUnit Parsed Filler data");
parseResult.nalTypeName = "Filler ";
parseResult.unitTypeName = "Filler ";
}
else if (nalAVC->header.nal_unit_type == NalType::AUD)
{
specificDescription = " AUD";
DEBUG_AVC("AnnexBAVC::parseAndAddNALUnit Parsed AUD");
parseResult.nalTypeName = "AUD ";
parseResult.unitTypeName = "AUD ";
}

if (nalAVC->header.nal_unit_type == NalType::CODED_SLICE_IDR ||
Expand Down Expand Up @@ -608,7 +608,7 @@ std::optional<AnnexB::SeekData> AnnexBAVC::getSeekData(int iFrameNr)
// Seek here
AnnexB::SeekData seekData;
if (nal->filePosStartEnd)
seekData.filePos = nal->filePosStartEnd->first;
seekData.filePos = nal->filePosStartEnd->start;

// Get the bitstream of all active parameter sets
for (const auto &nalMap : {activeSPSNal, activePPSNal})
Expand Down
Loading