Detect AV1 in IVF stream
This commit is contained in:
parent
1dc8fb4839
commit
c4adad4297
|
@ -31,6 +31,8 @@ set(HEADER_FILES
|
|||
id3/id3v2frame.h
|
||||
id3/id3v2frameids.h
|
||||
id3/id3v2tag.h
|
||||
ivf/ivfframe.h
|
||||
ivf/ivfstream.h
|
||||
localeawarestring.h
|
||||
margin.h
|
||||
matroska/ebmlelement.h
|
||||
|
@ -102,6 +104,8 @@ set(SRC_FILES
|
|||
id3/id3v2frame.cpp
|
||||
id3/id3v2frameids.cpp
|
||||
id3/id3v2tag.cpp
|
||||
ivf/ivfframe.cpp
|
||||
ivf/ivfstream.cpp
|
||||
localeawarestring.cpp
|
||||
matroska/ebmlelement.cpp
|
||||
matroska/matroskaattachment.cpp
|
||||
|
|
|
@ -34,6 +34,7 @@ enum class TrackType {
|
|||
OggStream, /**< The track is a TagParser::OggStream. */
|
||||
AdtsStream, /**< The track is a TagParser::AdtsStream. */
|
||||
FlacStream, /**< The track is a TagParser::FlacStream. */
|
||||
IvfStream, /**< The track is a TagParser::IvfStream. */
|
||||
};
|
||||
|
||||
class TAG_PARSER_EXPORT AbstractTrack {
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
#include "./ivfframe.h"
|
||||
|
||||
#include "../exceptions.h"
|
||||
|
||||
#include <c++utilities/io/binaryreader.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace IoUtilities;
|
||||
|
||||
namespace TagParser {
|
||||
|
||||
/*!
|
||||
* \class TagParser::IvfFrame
|
||||
* \brief The IvfFrame class is used to parse IVF frames.
|
||||
* \sa https://wiki.multimedia.cx/index.php/IVF
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Parses the header read using the specified \a reader.
|
||||
*/
|
||||
void IvfFrame::parseHeader(IoUtilities::BinaryReader &reader, Diagnostics &diag)
|
||||
{
|
||||
VAR_UNUSED(diag)
|
||||
startOffset = static_cast<uint64>(reader.stream()->tellg());
|
||||
size = reader.readUInt32BE();
|
||||
timestamp = reader.readUInt64BE();
|
||||
}
|
||||
|
||||
} // namespace TagParser
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef TAG_PARSER_IVFRAME_H
|
||||
#define TAG_PARSER_IVFRAME_H
|
||||
|
||||
#include "../diagnostics.h"
|
||||
|
||||
#include <c++utilities/conversion/types.h>
|
||||
|
||||
namespace IoUtilities {
|
||||
class BinaryReader;
|
||||
}
|
||||
|
||||
namespace TagParser {
|
||||
|
||||
class TAG_PARSER_EXPORT IvfFrame {
|
||||
public:
|
||||
constexpr IvfFrame();
|
||||
void parseHeader(IoUtilities::BinaryReader &reader, Diagnostics &diag);
|
||||
|
||||
private:
|
||||
uint64 startOffset;
|
||||
uint64 timestamp;
|
||||
uint32 size;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Constructs a new frame.
|
||||
*/
|
||||
constexpr IvfFrame::IvfFrame()
|
||||
: startOffset(0)
|
||||
, timestamp(0)
|
||||
, size(0)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace TagParser
|
||||
|
||||
#endif // TAG_PARSER_IVFRAME_H
|
|
@ -0,0 +1,66 @@
|
|||
#include "./ivfstream.h"
|
||||
|
||||
#include "../mp4/mp4ids.h"
|
||||
|
||||
#include "../exceptions.h"
|
||||
|
||||
#include <c++utilities/conversion/stringbuilder.h>
|
||||
#include <c++utilities/conversion/stringconversion.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
using namespace ChronoUtilities;
|
||||
using namespace ConversionUtilities;
|
||||
|
||||
namespace TagParser {
|
||||
|
||||
/*!
|
||||
* \class TagParser::IvfStream
|
||||
* \brief Implementation of TagParser::AbstractTrack for ADTS streams.
|
||||
* \sa https://wiki.multimedia.cx/index.php/IVF
|
||||
*/
|
||||
|
||||
void IvfStream::internalParseHeader(Diagnostics &diag)
|
||||
{
|
||||
static const string context("parsing IVF header");
|
||||
if (!m_istream) {
|
||||
throw NoDataFoundException();
|
||||
}
|
||||
|
||||
// check signature and version
|
||||
if (m_reader.readUInt32BE() != 0x444B4946u) {
|
||||
diag.emplace_back(DiagLevel::Critical, "Signature not \"DKIF\".", context);
|
||||
throw InvalidDataException();
|
||||
}
|
||||
const auto version = m_reader.readUInt16LE();
|
||||
m_version = version;
|
||||
if (version != 0) {
|
||||
diag.emplace_back(DiagLevel::Warning, argsToString("Version ", version, " is not supported."), context);
|
||||
}
|
||||
|
||||
// read remaining header
|
||||
m_headerLength = m_reader.readUInt16LE();
|
||||
const auto formatId = m_reader.readUInt32BE();
|
||||
m_formatId = interpretIntegerAsString(formatId);
|
||||
m_pixelSize.setWidth(m_reader.readUInt16LE());
|
||||
m_pixelSize.setHeight(m_reader.readUInt16LE());
|
||||
m_fps = m_reader.readUInt32LE();
|
||||
m_timeScale = m_reader.readUInt32LE();
|
||||
m_sampleCount = m_reader.readUInt32LE();
|
||||
|
||||
// compute further values
|
||||
m_format = FourccIds::fourccToMediaFormat(formatId);
|
||||
m_duration = TimeSpan::fromSeconds(static_cast<double>(m_sampleCount) / m_fps);
|
||||
|
||||
// skip unused bytes
|
||||
m_istream->seekg(4, ios_base::cur);
|
||||
}
|
||||
|
||||
void IvfStream::readFrame(Diagnostics &diag)
|
||||
{
|
||||
m_frames.emplace_back();
|
||||
m_frames.back().parseHeader(m_reader, diag);
|
||||
}
|
||||
|
||||
} // namespace TagParser
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef TAG_PARSER_IVFSTREAM_H
|
||||
#define TAG_PARSER_IVFSTREAM_H
|
||||
|
||||
#include "./ivfframe.h"
|
||||
|
||||
#include "../abstracttrack.h"
|
||||
|
||||
namespace TagParser {
|
||||
|
||||
class TAG_PARSER_EXPORT IvfStream : public AbstractTrack {
|
||||
public:
|
||||
IvfStream(std::iostream &stream, uint64 startOffset);
|
||||
~IvfStream() override;
|
||||
|
||||
TrackType type() const override;
|
||||
|
||||
void readFrame(Diagnostics &diag);
|
||||
|
||||
protected:
|
||||
void internalParseHeader(Diagnostics &diag) override;
|
||||
|
||||
private:
|
||||
std::vector<IvfFrame> m_frames;
|
||||
uint16 m_headerLength;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Constructs a new track for the \a stream at the specified \a startOffset.
|
||||
*/
|
||||
inline IvfStream::IvfStream(std::iostream &stream, uint64 startOffset)
|
||||
: AbstractTrack(stream, startOffset)
|
||||
{
|
||||
m_mediaType = MediaType::Video;
|
||||
}
|
||||
|
||||
inline IvfStream::~IvfStream()
|
||||
{
|
||||
}
|
||||
|
||||
inline TrackType IvfStream::type() const
|
||||
{
|
||||
return TrackType::IvfStream;
|
||||
}
|
||||
|
||||
} // namespace TagParser
|
||||
|
||||
#endif // TAG_PARSER_IVFSTREAM_H
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include "./adts/adtsstream.h"
|
||||
|
||||
#include "./ivf/ivfstream.h"
|
||||
|
||||
#include "./mp4/mp4atom.h"
|
||||
#include "./mp4/mp4container.h"
|
||||
#include "./mp4/mp4ids.h"
|
||||
|
@ -316,6 +318,9 @@ void MediaFileInfo::parseTracks(Diagnostics &diag)
|
|||
case ContainerFormat::Flac:
|
||||
m_singleTrack = make_unique<FlacStream>(*this, m_containerOffset);
|
||||
break;
|
||||
case ContainerFormat::Ivf:
|
||||
m_singleTrack = make_unique<IvfStream>(stream(), m_containerOffset);
|
||||
break;
|
||||
case ContainerFormat::MpegAudioFrames:
|
||||
m_singleTrack = make_unique<MpegAudioFrameStream>(stream(), m_containerOffset);
|
||||
break;
|
||||
|
|
|
@ -57,7 +57,7 @@ MediaFormat fourccToMediaFormat(uint32 fourccId)
|
|||
return GeneralMediaFormat::Mpeg4TimedText;
|
||||
case Hevc1:
|
||||
case Hevc2:
|
||||
return MediaFormat(GeneralMediaFormat::Hevc);
|
||||
return GeneralMediaFormat::Hevc;
|
||||
case Avc1:
|
||||
case Avc2:
|
||||
case Avc3:
|
||||
|
@ -68,7 +68,9 @@ MediaFormat fourccToMediaFormat(uint32 fourccId)
|
|||
case H264Decoder4:
|
||||
case H264Decoder5:
|
||||
case H264Decoder6:
|
||||
return MediaFormat(GeneralMediaFormat::Avc);
|
||||
return GeneralMediaFormat::Avc;
|
||||
case Av1:
|
||||
return GeneralMediaFormat::Av1;
|
||||
case Divx4Decoder1:
|
||||
case Divx4Decoder2:
|
||||
case H263Quicktime:
|
||||
|
@ -169,6 +171,10 @@ MediaFormat fourccToMediaFormat(uint32 fourccId)
|
|||
case MsMpeg4V3Decoder1:
|
||||
case MsMpeg4V3Decoder2:
|
||||
return MediaFormat(GeneralMediaFormat::MicrosoftMpeg4, 3);
|
||||
case Vp8:
|
||||
return GeneralMediaFormat::Vp8;
|
||||
case Vp9:
|
||||
return GeneralMediaFormat::Vp9;
|
||||
case WavPack:
|
||||
return MediaFormat(GeneralMediaFormat::WavPack);
|
||||
case WindowsMediaVideoV17:
|
||||
|
|
|
@ -217,6 +217,7 @@ enum KnownValue : uint32 {
|
|||
Avc2 = 0x61766332, /**< H.264/MPEG-4 AVC video */
|
||||
Avc3 = 0x61766333, /**< H.264/MPEG-4 AVC video */
|
||||
Avc4 = 0x61766334, /**< H.264/MPEG-4 AVC video */
|
||||
Av1 = 0x41563031, /**< AV1 video */
|
||||
Blur = 0x626C7572,
|
||||
Bps8 = 0x38627073,
|
||||
BrightnessAndContrast = 0x6272636F,
|
||||
|
@ -375,6 +376,8 @@ enum KnownValue : uint32 {
|
|||
Ulaw21 = 0x756C6177,
|
||||
VcmImageCodec = 0x4D6A7067,
|
||||
Vdva = 0x76647661,
|
||||
Vp8 = 0x56503830, /**< VP8 video */
|
||||
Vp9 = 0x56503930, /**< VP9 video */
|
||||
WavPack = 0x5756504B,
|
||||
WindowsMediaAudio = 0x6F776D61, /**< ? */
|
||||
WindowsMediaAudio7 = 0x574D4131,
|
||||
|
|
|
@ -1766,7 +1766,7 @@ void Mp4Track::internalParseHeader(Diagnostics &diag)
|
|||
MpegAudioFrame frame;
|
||||
m_istream->seekg(m_stcoAtom->dataOffset() + 8);
|
||||
m_istream->seekg(m_chunkOffsetSize == 8 ? reader.readUInt64BE() : reader.readUInt32BE());
|
||||
frame.parseHeader(reader);
|
||||
frame.parseHeader(reader, diag);
|
||||
MpegAudioFrameStream::addInfo(frame, *this);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -48,10 +48,11 @@ const uint32 MpegAudioFrame::m_sync = 0xFFE00000u;
|
|||
* \throws Throws InvalidDataException if the data read from the stream is
|
||||
* no valid frame header.
|
||||
*/
|
||||
void MpegAudioFrame::parseHeader(BinaryReader &reader)
|
||||
void MpegAudioFrame::parseHeader(BinaryReader &reader, Diagnostics &diag)
|
||||
{
|
||||
m_header = reader.readUInt32BE();
|
||||
if (!isValid()) {
|
||||
diag.emplace_back(DiagLevel::Critical, "Header is invalid.", "parsing MPEG audio frame header");
|
||||
throw InvalidDataException();
|
||||
}
|
||||
reader.stream()->seekg(m_xingHeaderOffset - 4, ios_base::cur);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef TAG_PARSER_MP3FRAMEAUDIOSTREAM_H
|
||||
#define TAG_PARSER_MP3FRAMEAUDIOSTREAM_H
|
||||
|
||||
#include "../global.h"
|
||||
#include "../diagnostics.h"
|
||||
|
||||
#include <c++utilities/conversion/types.h>
|
||||
|
||||
|
@ -38,7 +38,7 @@ class TAG_PARSER_EXPORT MpegAudioFrame {
|
|||
public:
|
||||
constexpr MpegAudioFrame();
|
||||
|
||||
void parseHeader(IoUtilities::BinaryReader &reader);
|
||||
void parseHeader(IoUtilities::BinaryReader &reader, Diagnostics &diag);
|
||||
|
||||
constexpr bool isValid() const;
|
||||
double mpegVersion() const;
|
||||
|
|
|
@ -46,7 +46,7 @@ void MpegAudioFrameStream::internalParseHeader(Diagnostics &diag)
|
|||
// parse frame header
|
||||
m_frames.emplace_back();
|
||||
MpegAudioFrame &frame = m_frames.back();
|
||||
frame.parseHeader(m_reader);
|
||||
frame.parseHeader(m_reader, diag);
|
||||
addInfo(frame, *this);
|
||||
if (frame.isXingBytesfieldPresent()) {
|
||||
uint32 xingSize = frame.xingBytesfield();
|
||||
|
|
|
@ -116,6 +116,7 @@ convert() {
|
|||
convert flac/test.flac ffmpeg -i mtx-test-data/alac/othertest-itunes.m4a -c:a flac flac/test.flac
|
||||
convert flac/test.ogg ffmpeg -i flac/test.flac -vn -c:a copy flac/test.ogg
|
||||
convert mkv/av1_test.mkv ffmpeg -i matroska_wave1/test1.mkv -t 1 -c:v libaom-av1 -crf 30 -cpu-used 5 -an -strict experimental mkv/av1_test.mkv
|
||||
convert misc/av1.ivf ffmpeg -i mkv/av1_test.mkv -c copy misc/av1.ivf
|
||||
convert mkv/nested-tags.mkv \
|
||||
mkvmerge --ui-language en_US \
|
||||
--output 'mkv/nested-tags.mkv' \
|
||||
|
|
|
@ -43,6 +43,7 @@ enum Sig32 : uint32 {
|
|||
Dirac = 0x42424344u,
|
||||
Elf = 0x7F454C46u,
|
||||
Flac = 0x664C6143u,
|
||||
Ivf = 0x444B4946u,
|
||||
JavaClassFile = 0xCAFEBABEu,
|
||||
Ebml = 0x1A45DFA3u,
|
||||
MonkeysAudio = 0x4D414320u,
|
||||
|
@ -159,6 +160,8 @@ ContainerFormat parseSignature(const char *buffer, int bufferSize)
|
|||
return ContainerFormat::Elf;
|
||||
case Flac:
|
||||
return ContainerFormat::Flac;
|
||||
case Ivf:
|
||||
return ContainerFormat::Ivf;
|
||||
case JavaClassFile:
|
||||
return ContainerFormat::JavaClassFile;
|
||||
case Ebml:
|
||||
|
@ -260,6 +263,8 @@ const char *containerFormatAbbreviation(ContainerFormat containerFormat, MediaTy
|
|||
case ContainerFormat::Gif87a:
|
||||
case ContainerFormat::Gif89a:
|
||||
return "gif";
|
||||
case ContainerFormat::Ivf:
|
||||
return "ivf";
|
||||
case ContainerFormat::JavaClassFile:
|
||||
return "class";
|
||||
case ContainerFormat::Jpeg:
|
||||
|
@ -380,6 +385,8 @@ const char *containerFormatName(ContainerFormat containerFormat)
|
|||
case ContainerFormat::Gif87a:
|
||||
case ContainerFormat::Gif89a:
|
||||
return "Graphics Interchange Format";
|
||||
case ContainerFormat::Ivf:
|
||||
return "IVF";
|
||||
case ContainerFormat::JavaClassFile:
|
||||
return "Java class file";
|
||||
case ContainerFormat::Jpeg:
|
||||
|
|
|
@ -30,6 +30,7 @@ enum class ContainerFormat : unsigned int {
|
|||
Gif89a, /**< Graphics Interchange Format (1989) */
|
||||
Gzip, /**< gzip compressed file */
|
||||
Id2v2Tag, /**< file holding an ID2v2 tag only */
|
||||
Ivf, /**< IVF (simple file format that transports raw VP8/VP9/AV1 data) */
|
||||
JavaClassFile, /**< Java class file */
|
||||
Jpeg, /**< JPEG File Interchange Format */
|
||||
Lha, /**< LHA */
|
||||
|
|
|
@ -134,7 +134,7 @@ void WaveAudioStream::internalParseHeader(Diagnostics &diag)
|
|||
}
|
||||
m_istream->seekg(static_cast<streamoff>(m_dataOffset));
|
||||
MpegAudioFrame frame;
|
||||
frame.parseHeader(m_reader);
|
||||
frame.parseHeader(m_reader, diag);
|
||||
MpegAudioFrameStream::addInfo(frame, *this);
|
||||
m_bitrate = frame.isXingFramefieldPresent()
|
||||
? ((static_cast<double>(m_size) * 8.0)
|
||||
|
|
Loading…
Reference in New Issue