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
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
Add a try to extradata parsing. It may fail.
  • Loading branch information
ChristianFeldmann committed Aug 29, 2022
commit 4bf97cd288504c4e1d79dd249f15f09c5141d0c1
142 changes: 75 additions & 67 deletions YUViewLib/src/filesource/FileSourceFFmpegFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ QByteArray FileSourceFFmpegFile::getNextUnit(bool getLastDataAgain)
{
// Return the remainder of the buffer and clear it so that the next packet is loaded on the
// next call
this->lastReturnArray = currentPacketData.mid(this->posInData + offset);
this->lastReturnArray = this->currentPacketData.mid(this->posInData + offset);
this->currentPacketData.clear();
}
else
Expand Down Expand Up @@ -167,7 +167,7 @@ QByteArray FileSourceFFmpegFile::getNextUnit(bool getLastDataAgain)
else if (this->packetDataFormat == PacketDataFormat::OBU)
{
SubByteReaderLogging reader(
SubByteReaderLogging::convertToByteVector(currentPacketData), nullptr, "", posInData);
SubByteReaderLogging::convertToByteVector(this->currentPacketData), nullptr, "", posInData);

try
{
Expand All @@ -177,16 +177,16 @@ QByteArray FileSourceFFmpegFile::getNextUnit(bool getLastDataAgain)
if (header.obu_has_size_field)
{
auto completeSize = header.obu_size + reader.nrBytesRead();
this->lastReturnArray = currentPacketData.mid(posInData, completeSize);
this->lastReturnArray = this->currentPacketData.mid(posInData, completeSize);
this->posInData += completeSize;
if (this->posInData >= currentPacketData.size())
if (this->posInData >= this->currentPacketData.size())
this->currentPacketData.clear();
}
else
{
// The OBU is the remainder of the input
this->lastReturnArray = currentPacketData.mid(posInData);
this->posInData = currentPacketData.size();
this->lastReturnArray = this->currentPacketData.mid(posInData);
this->posInData = this->currentPacketData.size();
this->currentPacketData.clear();
}
}
Expand Down Expand Up @@ -231,88 +231,96 @@ QList<QByteArray> FileSourceFFmpegFile::getParameterSets()

QList<QByteArray> retArray;

// Since the FFmpeg developers don't want to make it too easy, the extradata is organized
// differently depending on the codec.
auto codecID = this->ff.getCodecIDWrapper(video_stream.getCodecID());
if (codecID.isHEVC())
try
{
if (extradata.at(0) == 1)
// Since the FFmpeg developers don't want to make it too easy, the extradata is organized
// differently depending on the codec.
auto codecID = this->ff.getCodecIDWrapper(video_stream.getCodecID());
if (codecID.isHEVC())
{
// Internally, ffmpeg uses a custom format for the parameter sets (hvcC).
// The hvcC parameters come first, and afterwards, the "normal" parameter sets are sent.
if (extradata.at(0) == 1)
{
// Internally, ffmpeg uses a custom format for the parameter sets (hvcC).
// The hvcC parameters come first, and afterwards, the "normal" parameter sets are sent.

// The first 22 bytes are fixed hvcC parameter set (see hvcc_write in libavformat hevc.c)
auto numOfArrays = int(extradata.at(22));

// The first 22 bytes are fixed hvcC parameter set (see hvcc_write in libavformat hevc.c)
auto numOfArrays = int(extradata.at(22));
int pos = 23;
for (int i = 0; i < numOfArrays; i++)
{
// The first byte contains the NAL unit type (which we don't use here).
pos++;
// int byte = (unsigned char)(extradata.at(pos++));
// bool array_completeness = byte & (1 << 7);
// int nalUnitType = byte & 0x3f;

// Two bytes numNalus
int numNalus = (unsigned char)(extradata.at(pos++)) << 7;
numNalus += (unsigned char)(extradata.at(pos++));

for (int j = 0; j < numNalus; j++)
{
// Two bytes nalUnitLength
int nalUnitLength = (unsigned char)(extradata.at(pos++)) << 7;
nalUnitLength += (unsigned char)(extradata.at(pos++));

// nalUnitLength bytes payload of the NAL unit
// This payload includes the NAL unit header
auto rawNAL = extradata.mid(pos, nalUnitLength);
retArray.append(rawNAL);
pos += nalUnitLength;
}
}
}
}
else if (codecID.isAVC())
{
// Note: Actually we would only need this if we would feed the AVC bitstream to a different
// decoder then ffmpeg.
// So this function is so far not called (and not tested).

int pos = 23;
for (int i = 0; i < numOfArrays; i++)
// First byte is 1, length must be at least 7 bytes
if (extradata.at(0) == 1 && extradata.length() >= 7)
{
// The first byte contains the NAL unit type (which we don't use here).
pos++;
// int byte = (unsigned char)(extradata.at(pos++));
// bool array_completeness = byte & (1 << 7);
// int nalUnitType = byte & 0x3f;
int nrSPS = extradata.at(5) & 0x1f;
int pos = 6;
for (int i = 0; i < nrSPS; i++)
{
int nalUnitLength = (unsigned char)(extradata.at(pos++)) << 7;
nalUnitLength += (unsigned char)(extradata.at(pos++));

// Two bytes numNalus
int numNalus = (unsigned char)(extradata.at(pos++)) << 7;
numNalus += (unsigned char)(extradata.at(pos++));
auto rawNAL = extradata.mid(pos, nalUnitLength);
retArray.append(rawNAL);
pos += nalUnitLength;
}

for (int j = 0; j < numNalus; j++)
int nrPPS = extradata.at(pos++);
for (int i = 0; i < nrPPS; i++)
{
// Two bytes nalUnitLength
int nalUnitLength = (unsigned char)(extradata.at(pos++)) << 7;
nalUnitLength += (unsigned char)(extradata.at(pos++));

// nalUnitLength bytes payload of the NAL unit
// This payload includes the NAL unit header
auto rawNAL = extradata.mid(pos, nalUnitLength);
retArray.append(rawNAL);
pos += nalUnitLength;
}
}
}
}
else if (codecID.isAVC())
{
// Note: Actually we would only need this if we would feed the AVC bitstream to a different
// decoder then ffmpeg.
// So this function is so far not called (and not tested).

// First byte is 1, length must be at least 7 bytes
if (extradata.at(0) == 1 && extradata.length() >= 7)
else if (codecID.isAV1())
{
int nrSPS = extradata.at(5) & 0x1f;
int pos = 6;
for (int i = 0; i < nrSPS; i++)
{
int nalUnitLength = (unsigned char)(extradata.at(pos++)) << 7;
nalUnitLength += (unsigned char)(extradata.at(pos++));

auto rawNAL = extradata.mid(pos, nalUnitLength);
retArray.append(rawNAL);
pos += nalUnitLength;
}

int nrPPS = extradata.at(pos++);
for (int i = 0; i < nrPPS; i++)
{
int nalUnitLength = (unsigned char)(extradata.at(pos++)) << 7;
nalUnitLength += (unsigned char)(extradata.at(pos++));

auto rawNAL = extradata.mid(pos, nalUnitLength);
retArray.append(rawNAL);
pos += nalUnitLength;
}
// This should be a normal OBU for the seuqence header starting with the OBU header
SubByteReaderLogging reader(SubByteReaderLogging::convertToByteVector(extradata), nullptr);
parser::av1::obu_header header;
header.parse(reader);
if (header.obu_type == parser::av1::ObuType::OBU_SEQUENCE_HEADER)
retArray.append(extradata);
}
}
else if (codecID.isAV1())
catch (const std::exception &e)
{
// This should be a normal OBU for the seuqence header starting with the OBU header
SubByteReaderLogging reader(SubByteReaderLogging::convertToByteVector(extradata), nullptr);
parser::av1::obu_header header;
header.parse(reader);
if (header.obu_type == parser::av1::ObuType::OBU_SEQUENCE_HEADER)
retArray.append(extradata);
(void)e;
DEBUG_FFMPEG("Failed to parse extradata: " << e.what());
}

return retArray;
Expand Down