parsing AVC config
This commit is contained in:
parent
b48dcf5b3d
commit
488fce3ab8
|
@ -18,8 +18,9 @@ set(HEADER_FILES
|
|||
abstracttrack.h
|
||||
adts/adtsframe.h
|
||||
adts/adtsstream.h
|
||||
# avc/avcconfiguration.h
|
||||
# avc/avcinfo.h
|
||||
aspectratio.h
|
||||
avc/avcconfiguration.h
|
||||
avc/avcinfo.h
|
||||
avi/bitmapinfoheader.h
|
||||
backuphelper.h
|
||||
basicfileinfo.h
|
||||
|
@ -89,8 +90,9 @@ set(SRC_FILES
|
|||
abstracttrack.cpp
|
||||
adts/adtsframe.cpp
|
||||
adts/adtsstream.cpp
|
||||
# avc/avcconfiguration.cpp
|
||||
# avc/avcinfo.cpp
|
||||
aspectratio.cpp
|
||||
avc/avcconfiguration.cpp
|
||||
avc/avcinfo.cpp
|
||||
avi/bitmapinfoheader.cpp
|
||||
backuphelper.cpp
|
||||
basicfileinfo.cpp
|
||||
|
@ -134,6 +136,13 @@ set(SRC_FILES
|
|||
mediafileinfo.cpp
|
||||
mediaformat.cpp
|
||||
)
|
||||
set(TEST_HEADER_FILES
|
||||
|
||||
)
|
||||
set(TEST_SRC_FILES
|
||||
tests/cppunit.cpp
|
||||
tests/matroska.cpp
|
||||
)
|
||||
|
||||
# meta data
|
||||
set(META_PROJECT_NAME tagparser)
|
||||
|
@ -189,6 +198,18 @@ add_definitions(
|
|||
-D_GLIBCXX_USE_CXX11_ABI=0
|
||||
)
|
||||
|
||||
# add check target
|
||||
if(NOT TARGET check)
|
||||
set(CMAKE_CTEST_COMMAND ctest -V)
|
||||
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})
|
||||
enable_testing()
|
||||
endif()
|
||||
add_executable(${META_PROJECT_NAME}_tests EXCLUDE_FROM_ALL ${TEST_HEADER_FILES} ${TEST_SRC_FILES})
|
||||
target_link_libraries(${META_PROJECT_NAME}_tests ${META_PROJECT_NAME} c++utilities cppunit)
|
||||
set_target_properties(${META_PROJECT_NAME}_tests PROPERTIES CXX_STANDARD 11)
|
||||
add_test(NAME ${META_PROJECT_NAME}_cppunit COMMAND ${META_PROJECT_NAME}_tests -p "${CMAKE_CURRENT_SOURCE_DIR}/testfiles")
|
||||
add_dependencies(check ${META_PROJECT_NAME}_tests)
|
||||
|
||||
# executable and linking
|
||||
add_library(${META_PROJECT_NAME} SHARED ${HEADER_FILES} ${SRC_FILES} ${RES_FILES} ${WINDOWS_ICON_PATH})
|
||||
target_link_libraries(${META_PROJECT_NAME} c++utilities z)
|
||||
|
|
|
@ -15,6 +15,11 @@
|
|||
using namespace std;
|
||||
using namespace IoUtilities;
|
||||
|
||||
/*!
|
||||
* \remarks Nothing of this code has been tested yet. These classes are
|
||||
* not used by the rest of the library (currently).
|
||||
*/
|
||||
|
||||
namespace Media {
|
||||
|
||||
/*!
|
||||
|
|
|
@ -55,6 +55,7 @@ AbstractTrack::AbstractTrack(istream &inputStream, ostream &outputStream, uint64
|
|||
m_quality(0),
|
||||
m_depth(0),
|
||||
m_fps(0),
|
||||
m_chromaFormat(nullptr),
|
||||
m_interlaced(false),
|
||||
m_timeScale(0),
|
||||
m_enabled(true),
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "./statusprovider.h"
|
||||
#include "./size.h"
|
||||
#include "./margin.h"
|
||||
#include "./aspectratio.h"
|
||||
#include "./mediaformat.h"
|
||||
|
||||
#include <c++utilities/conversion/types.h>
|
||||
|
@ -21,6 +22,7 @@ enum class MediaType;
|
|||
enum class GeneralMediaFormat;
|
||||
class MpegAudioFrameStream;
|
||||
class WaveAudioStream;
|
||||
class Mp4Track;
|
||||
|
||||
/*!
|
||||
* \brief Specifies the track type.
|
||||
|
@ -40,6 +42,7 @@ class LIB_EXPORT AbstractTrack : public StatusProvider
|
|||
{
|
||||
friend class MpegAudioFrameStream;
|
||||
friend class WaveAudioStream;
|
||||
friend class Mp4Track;
|
||||
|
||||
public:
|
||||
virtual ~AbstractTrack();
|
||||
|
@ -85,6 +88,8 @@ public:
|
|||
const std::string &compressorName() const;
|
||||
uint16 depth() const;
|
||||
uint32 fps() const;
|
||||
const char *chromaFormat() const;
|
||||
const AspectRatio &pixelAspectRatio() const;
|
||||
bool isInterlaced() const;
|
||||
uint32 timeScale() const;
|
||||
bool isEnabled() const;
|
||||
|
@ -141,6 +146,8 @@ protected:
|
|||
std::string m_compressorName;
|
||||
uint16 m_depth;
|
||||
uint32 m_fps;
|
||||
const char *m_chromaFormat;
|
||||
AspectRatio m_pixelAspectRatio;
|
||||
bool m_interlaced;
|
||||
uint32 m_timeScale;
|
||||
bool m_enabled;
|
||||
|
@ -241,7 +248,7 @@ inline MediaFormat AbstractTrack::format() const
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the version of the track if known; otherwise returns 0.
|
||||
* \brief Returns the version/level of the track if known; otherwise returns 0.
|
||||
*/
|
||||
inline double AbstractTrack::version() const
|
||||
{
|
||||
|
@ -489,6 +496,24 @@ inline uint32 AbstractTrack::fps() const
|
|||
return m_fps;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the chroma subsampling format if known; otherwise returns nullptr.
|
||||
*
|
||||
* This value only makes sense for video tracks.
|
||||
*/
|
||||
inline const char *AbstractTrack::chromaFormat() const
|
||||
{
|
||||
return m_chromaFormat;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the pixel aspect ratio (PAR).
|
||||
*/
|
||||
inline const AspectRatio &AbstractTrack::pixelAspectRatio() const
|
||||
{
|
||||
return m_pixelAspectRatio;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns true if the video is denoted as interlaced; otherwise returns false.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
#include "./aspectratio.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Media {
|
||||
|
||||
/*!
|
||||
* \struct Media::AspectRatio
|
||||
* \brief The AspectRatio struct defines an aspect ratio.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a PAR form the specified AVC aspectRatioType.
|
||||
*/
|
||||
AspectRatio::AspectRatio(byte aspectRatioType)
|
||||
{
|
||||
static const AspectRatio predefinedPars[] = {
|
||||
AspectRatio(), AspectRatio(1, 1), AspectRatio(12, 11), AspectRatio(10, 11),
|
||||
AspectRatio(16, 11), AspectRatio(40, 33), AspectRatio(24, 11), AspectRatio(20, 11),
|
||||
AspectRatio(32, 11), AspectRatio(80, 33), AspectRatio(18, 11), AspectRatio(15, 11),
|
||||
AspectRatio(64, 33), AspectRatio(160, 99), AspectRatio(4, 3), AspectRatio(3, 2),
|
||||
AspectRatio(2, 1)
|
||||
};
|
||||
if(aspectRatioType < sizeof(predefinedPars)) {
|
||||
*this = predefinedPars[aspectRatioType];
|
||||
} else {
|
||||
numerator = denominator = 0;
|
||||
}
|
||||
type = aspectRatioType;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef MEDIA_ASPECTRATIO_H
|
||||
#define MEDIA_ASPECTRATIO_H
|
||||
|
||||
#include <c++utilities/application/global.h>
|
||||
#include <c++utilities/conversion/types.h>
|
||||
|
||||
namespace Media {
|
||||
|
||||
struct LIB_EXPORT AspectRatio {
|
||||
AspectRatio();
|
||||
AspectRatio(byte aspectRatioType);
|
||||
AspectRatio(uint16 numerator, uint16 denominator);
|
||||
bool isValid() const;
|
||||
bool isExtended() const;
|
||||
|
||||
byte type;
|
||||
uint16 numerator;
|
||||
uint16 denominator;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Constructs an invalid aspect ratio.
|
||||
*/
|
||||
inline AspectRatio::AspectRatio() :
|
||||
type(0),
|
||||
numerator(0),
|
||||
denominator(0)
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a aspect ratio with the specified \a numerator and \a denominator.
|
||||
*/
|
||||
inline AspectRatio::AspectRatio(uint16 numerator, uint16 denominator) :
|
||||
type(0xFF),
|
||||
numerator(numerator),
|
||||
denominator(denominator)
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Returns an indication whether the aspect ratio is present and valid.
|
||||
*/
|
||||
inline bool AspectRatio::isValid() const
|
||||
{
|
||||
return !type || !numerator || !denominator;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns whether numerator and denominator must be read from extended SAR header.
|
||||
*/
|
||||
inline bool AspectRatio::isExtended() const
|
||||
{
|
||||
return type == 0xFF;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // MEDIA_ASPECTRATIO_H
|
|
@ -1,5 +1,75 @@
|
|||
#include "./avcconfiguration.h"
|
||||
|
||||
#include "../exceptions.h"
|
||||
#include "../mediaformat.h"
|
||||
|
||||
#include <c++utilities/io/binaryreader.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace IoUtilities;
|
||||
|
||||
namespace Media {
|
||||
|
||||
void AvcConfiguration::parse(BinaryReader &reader, uint64 maxSize)
|
||||
{
|
||||
if(maxSize < 7) {
|
||||
throw TruncatedDataException();
|
||||
}
|
||||
maxSize -= 7;
|
||||
|
||||
reader.stream()->seekg(1, ios_base::cur); // always 1
|
||||
profileIndication = reader.readByte();
|
||||
profileCompat = reader.readByte();
|
||||
levelIndication = reader.readByte();
|
||||
naluSizeLength = (reader.readByte() & 0x03) + 1;
|
||||
|
||||
// read SPS info entries
|
||||
byte entryCount = reader.readByte() & 0x0f;
|
||||
spsInfos.reserve(entryCount);
|
||||
for(; entryCount; --entryCount) {
|
||||
if(maxSize < 2) {
|
||||
throw TruncatedDataException();
|
||||
}
|
||||
spsInfos.emplace_back();
|
||||
try {
|
||||
spsInfos.back().parse(reader, maxSize);
|
||||
} catch(const TruncatedDataException &) {
|
||||
// TODO: log parsing error
|
||||
if(spsInfos.back().size > maxSize - 2) {
|
||||
throw;
|
||||
}
|
||||
spsInfos.pop_back();
|
||||
} catch(const Failure &) {
|
||||
spsInfos.pop_back();
|
||||
// TODO: log parsing error
|
||||
}
|
||||
maxSize -= spsInfos.back().size;
|
||||
}
|
||||
|
||||
// read PPS info entries
|
||||
entryCount = reader.readByte();
|
||||
ppsInfos.reserve(entryCount);
|
||||
for(; entryCount; --entryCount) {
|
||||
if(maxSize < 2) {
|
||||
throw TruncatedDataException();
|
||||
}
|
||||
ppsInfos.emplace_back();
|
||||
try {
|
||||
ppsInfos.back().parse(reader, maxSize);
|
||||
} catch(const TruncatedDataException &) {
|
||||
// TODO: log parsing error
|
||||
if(ppsInfos.back().size > maxSize - 2) {
|
||||
throw;
|
||||
}
|
||||
ppsInfos.pop_back();
|
||||
} catch(const Failure &) {
|
||||
ppsInfos.pop_back();
|
||||
// TODO: log parsing error
|
||||
}
|
||||
maxSize -= ppsInfos.back().size;
|
||||
}
|
||||
|
||||
// ignore remaining data
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,21 +7,25 @@
|
|||
|
||||
namespace Media {
|
||||
|
||||
class MediaFormat;
|
||||
|
||||
struct LIB_EXPORT AvcConfiguration
|
||||
{
|
||||
AvcConfiguration();
|
||||
byte profileIdc;
|
||||
byte profileIndication;
|
||||
byte profileCompat;
|
||||
byte levelIdc;
|
||||
byte levelIndication;
|
||||
byte naluSizeLength;
|
||||
std::vector<SpsInfo> spsInfos;
|
||||
std::vector<PpsInfo> ppsInfos;
|
||||
|
||||
void parse(IoUtilities::BinaryReader &reader, uint64 maxSize);
|
||||
};
|
||||
|
||||
inline AvcConfiguration::AvcConfiguration() :
|
||||
profileIdc(0),
|
||||
profileIndication(0),
|
||||
profileCompat(0),
|
||||
levelIdc(0),
|
||||
levelIndication(0),
|
||||
naluSizeLength(0)
|
||||
{}
|
||||
|
||||
|
|
265
avc/avcinfo.cpp
265
avc/avcinfo.cpp
|
@ -1,7 +1,16 @@
|
|||
#include "./avcinfo.h"
|
||||
|
||||
#include "../exceptions.h"
|
||||
|
||||
#include <c++utilities/io/binaryreader.h>
|
||||
#include <c++utilities/io/bitreader.h>
|
||||
#include <c++utilities/misc/memory.h>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace std;
|
||||
using namespace IoUtilities;
|
||||
|
||||
namespace Media {
|
||||
|
||||
/*!
|
||||
|
@ -10,25 +19,255 @@ namespace Media {
|
|||
*/
|
||||
|
||||
/*!
|
||||
* \brief SpsInfo::parse
|
||||
* \param stream
|
||||
* \brief Parses the SPS info.
|
||||
*/
|
||||
void SpsInfo::parse(std::istream &stream)
|
||||
void SpsInfo::parse(BinaryReader &reader, uint32 maxSize)
|
||||
{
|
||||
static auto highLevelProfileIds = std::unordered_map<unsigned int, bool> {
|
||||
{ 44, true }, { 83, true }, { 86, true }, { 100, true }, { 110, true },
|
||||
{ 118, true }, { 122, true }, { 128, true }, { 244, true }
|
||||
};
|
||||
int const addSpace = 100;
|
||||
// read (and check) size
|
||||
if(maxSize < 2) {
|
||||
throw TruncatedDataException();
|
||||
}
|
||||
maxSize -= 2;
|
||||
if((size = reader.readUInt16BE()) > maxSize) {
|
||||
throw TruncatedDataException();
|
||||
}
|
||||
|
||||
parNum = 1;
|
||||
parDen = 1;
|
||||
arFound = false;
|
||||
// buffer data for reading with BitReader
|
||||
auto buffer = make_unique<char[]>(size);
|
||||
reader.read(buffer.get(), size);
|
||||
BitReader bitReader(buffer.get(), size);
|
||||
|
||||
uint32 unitsInTick = 0;
|
||||
uint32 timeScale = 0;
|
||||
try {
|
||||
// read general values
|
||||
bitReader.skipBits(3);
|
||||
if(bitReader.readBits<byte>(5) != 7) {
|
||||
throw InvalidDataException();
|
||||
}
|
||||
profileIndication = bitReader.readBits<byte>(8);
|
||||
profileConstraints = bitReader.readBits<byte>(8);
|
||||
levelIndication = bitReader.readBits<byte>(8);
|
||||
id = bitReader.readUnsignedExpGolombCodedBits<ugolomb>();
|
||||
|
||||
// read chroma profile specific values
|
||||
switch(profileIndication) {
|
||||
case 44: case 83: case 86: case 100: case 110:
|
||||
case 118: case 122: case 128: case 244:
|
||||
// high-level profile
|
||||
if((chromaFormatIndication = bitReader.readUnsignedExpGolombCodedBits<ugolomb>()) == 3) {
|
||||
bitReader.skipBits(1); // separate color plane flag
|
||||
}
|
||||
bitReader.readUnsignedExpGolombCodedBits<byte>(); // bit depth luma minus8
|
||||
bitReader.readUnsignedExpGolombCodedBits<byte>(); // bit depth chroma minus8
|
||||
bitReader.skipBits(1); // qpprime y zero transform bypass flag
|
||||
if(bitReader.readBit()) { // sequence scaling matrix present flag
|
||||
for(byte i = 0; i < 8; ++i) {
|
||||
// TODO: store values
|
||||
if(bitReader.readBit()) { // sequence scaling list present
|
||||
if(i < 6) {
|
||||
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;
|
||||
switch(pictureOrderCountType = bitReader.readUnsignedExpGolombCodedBits<ugolomb>()) {
|
||||
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>();
|
||||
for(byte i = 0; i < numRefFramesInPicOrderCntCycle; ++i) {
|
||||
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;
|
||||
mbSize.setWidth(bitReader.readUnsignedExpGolombCodedBits<uint32>() + 1);
|
||||
mbSize.setHeight(bitReader.readUnsignedExpGolombCodedBits<uint32>() + 1);
|
||||
if(!(frameMbsOnly = bitReader.readBit())) { // frame mbs only flag
|
||||
bitReader.readBit(); // mb adaptive frame field flag
|
||||
}
|
||||
bitReader.skipBits(1); // distinct 8x8 inference flag
|
||||
|
||||
// read cropping values
|
||||
if(bitReader.readBit()) { // frame cropping flag
|
||||
cropping.setLeft(bitReader.readUnsignedExpGolombCodedBits<uint32>());
|
||||
cropping.setRight(bitReader.readUnsignedExpGolombCodedBits<uint32>());
|
||||
cropping.setTop(bitReader.readUnsignedExpGolombCodedBits<uint32>());
|
||||
cropping.setBottom(bitReader.readUnsignedExpGolombCodedBits<uint32>());
|
||||
}
|
||||
|
||||
// read VUI (video usability information)
|
||||
if((vuiPresent = bitReader.readBit())) {
|
||||
if((bitReader.readBit())) { // PAR present flag
|
||||
pixelAspectRatio = AspectRatio(bitReader.readBits<byte>(8));
|
||||
if(pixelAspectRatio.isExtended()) {
|
||||
// read extended SAR
|
||||
pixelAspectRatio.numerator = bitReader.readBits<uint16>(16);
|
||||
pixelAspectRatio.denominator = bitReader.readBits<uint16>(16);
|
||||
}
|
||||
}
|
||||
|
||||
// read/skip misc values
|
||||
if(bitReader.readBit()) { // overscan info present
|
||||
bitReader.skipBits(1); // overscan appropriate
|
||||
}
|
||||
if(bitReader.readBit()) { // video signal type present
|
||||
bitReader.skipBits(4); // video format and video full range
|
||||
if(bitReader.readBit()) { // color description present
|
||||
bitReader.skipBits(24); // color primaries, transfer characteristics, matrix coefficients
|
||||
}
|
||||
}
|
||||
if(bitReader.readBit()) { // chroma loc info present
|
||||
bitReader.readUnsignedExpGolombCodedBits<byte>(); // chroma sample loc type top field
|
||||
bitReader.readUnsignedExpGolombCodedBits<byte>(); // chroma sample loc type bottom field
|
||||
}
|
||||
|
||||
// read timing info
|
||||
if((timingInfo.isPresent = bitReader.readBit())) {
|
||||
timingInfo.unitsInTick = bitReader.readBits<uint32>(32);
|
||||
timingInfo.timeScale = bitReader.readBits<uint32>(32);
|
||||
timingInfo.fixedFrameRate = bitReader.readBit();
|
||||
}
|
||||
|
||||
// skip hrd parameters
|
||||
hrdParametersPresent = 0;
|
||||
if(bitReader.readBit()) { // nal hrd parameters present
|
||||
nalHrdParameters.parse(bitReader);
|
||||
hrdParametersPresent = 1;
|
||||
}
|
||||
if(bitReader.readBit()) { // vcl hrd parameters present
|
||||
vclHrdParameters.parse(bitReader);
|
||||
hrdParametersPresent = 1;
|
||||
}
|
||||
if(hrdParametersPresent) {
|
||||
bitReader.skipBits(1); // low delay hrd flag
|
||||
}
|
||||
|
||||
pictureStructPresent = bitReader.readBit();
|
||||
|
||||
if(bitReader.readBit()) { // bitstream restriction flag
|
||||
bitReader.skipBits(1); // motion vectors over pic boundries flag
|
||||
bitReader.readUnsignedExpGolombCodedBits<byte>(); // max bytes per pic denom
|
||||
bitReader.readUnsignedExpGolombCodedBits<byte>(); // max bytes per mb denom
|
||||
bitReader.readUnsignedExpGolombCodedBits<byte>(); // log2 max mv length horizontal
|
||||
bitReader.readUnsignedExpGolombCodedBits<byte>(); // log2 max mv length vertical
|
||||
bitReader.readUnsignedExpGolombCodedBits<byte>(); // reorder frames num
|
||||
bitReader.readUnsignedExpGolombCodedBits<byte>(); // max decoder frame buffering
|
||||
}
|
||||
}
|
||||
|
||||
// calculate actual picture size
|
||||
if(!cropping.isNull()) {
|
||||
// determine cropping scale
|
||||
ugolomb croppingScaleX, croppingScaleY;
|
||||
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);
|
||||
}
|
||||
} catch(const ios_base::failure &) {
|
||||
throw TruncatedDataException();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \struct Media::PpsInfo
|
||||
* \brief The PpsInfo struct holds the picture parameter set.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Parses the PPS info.
|
||||
*/
|
||||
void PpsInfo::parse(BinaryReader &reader, uint32 maxSize)
|
||||
{
|
||||
// read (and check) size
|
||||
if(maxSize < 2) {
|
||||
throw TruncatedDataException();
|
||||
}
|
||||
maxSize -= 2;
|
||||
if((size = reader.readUInt16BE()) > maxSize) {
|
||||
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(1); // zero bit
|
||||
if(bitReader.readBits<byte>(5) != 8) { // nal unit type
|
||||
throw InvalidDataException();
|
||||
}
|
||||
id = bitReader.readUnsignedExpGolombCodedBits<ugolomb>();
|
||||
spsId = bitReader.readUnsignedExpGolombCodedBits<ugolomb>();
|
||||
bitReader.skipBits(1); // entropy coding mode flag
|
||||
picOrderPresent = bitReader.readBit();
|
||||
} catch(const ios_base::failure &) {
|
||||
throw TruncatedDataException();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \struct Media::HrdParameters
|
||||
* \brief The HrdParameters struct holds "Hypothetical Reference Decoder" parameters.
|
||||
* \remarks This is "a model for thinking about the decoding process".
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Parses HRD parameters.
|
||||
*/
|
||||
void HrdParameters::parse(IoUtilities::BitReader &reader)
|
||||
{
|
||||
cpbCount = reader.readUnsignedExpGolombCodedBits<ugolomb>() + 1;
|
||||
bitRateScale = reader.readBits<byte>(4);
|
||||
cpbSizeScale = reader.readBits<byte>(4);
|
||||
for(ugolomb i = 0; i < cpbCount; ++i) {
|
||||
// just skip those values
|
||||
reader.readUnsignedExpGolombCodedBits<byte>(); // bit rate value minus 1
|
||||
reader.readUnsignedExpGolombCodedBits<byte>(); // cpb size value minus 1
|
||||
reader.skipBits(1); // cbr flag
|
||||
}
|
||||
initialCpbRemovalDelayLength = reader.readBits<byte>(5) + 1;
|
||||
cpbRemovalDelayLength = reader.readBits<byte>(5) + 1;
|
||||
cpbOutputDelayLength = reader.readBits<byte>(5) + 1;
|
||||
timeOffsetLength = reader.readBits<byte>(5);
|
||||
}
|
||||
|
||||
|
||||
|
|
122
avc/avcinfo.h
122
avc/avcinfo.h
|
@ -3,23 +3,39 @@
|
|||
|
||||
#include "../margin.h"
|
||||
#include "../size.h"
|
||||
#include "../aspectratio.h"
|
||||
|
||||
namespace IoUtilities {
|
||||
class BinaryReader;
|
||||
class BitReader;
|
||||
}
|
||||
|
||||
namespace Media {
|
||||
|
||||
/*!
|
||||
* \brief Type used to store unsigned integer values using golomb coding.
|
||||
*/
|
||||
typedef uint32 ugolomb;
|
||||
|
||||
/*!
|
||||
* \brief Type used to store signed integer values using golomb coding.
|
||||
*/
|
||||
typedef int32 sgolomb;
|
||||
|
||||
struct LIB_EXPORT TimingInfo {
|
||||
TimingInfo();
|
||||
uint32 unitsInTick;
|
||||
uint32 timeScale;
|
||||
bool isPresent;
|
||||
bool fixedFrameRate;
|
||||
byte isPresent;
|
||||
byte fixedFrameRate;
|
||||
int64 defaultDuration() const;
|
||||
};
|
||||
|
||||
inline TimingInfo::TimingInfo() :
|
||||
unitsInTick(0),
|
||||
timeScale(0),
|
||||
isPresent(false),
|
||||
fixedFrameRate(false)
|
||||
isPresent(0),
|
||||
fixedFrameRate(0)
|
||||
{}
|
||||
|
||||
inline int64 TimingInfo::defaultDuration() const
|
||||
|
@ -27,61 +43,93 @@ inline int64 TimingInfo::defaultDuration() const
|
|||
return 1000000000ll * unitsInTick / timeScale;
|
||||
}
|
||||
|
||||
struct LIB_EXPORT HrdParameters {
|
||||
HrdParameters();
|
||||
ugolomb cpbCount;
|
||||
byte bitRateScale;
|
||||
byte cpbSizeScale;
|
||||
byte initialCpbRemovalDelayLength;
|
||||
byte cpbRemovalDelayLength;
|
||||
byte cpbOutputDelayLength;
|
||||
byte timeOffsetLength;
|
||||
|
||||
void parse(IoUtilities::BitReader &reader);
|
||||
};
|
||||
|
||||
inline HrdParameters::HrdParameters() :
|
||||
cpbCount(0),
|
||||
bitRateScale(0),
|
||||
cpbSizeScale(0),
|
||||
initialCpbRemovalDelayLength(0),
|
||||
cpbRemovalDelayLength(0),
|
||||
cpbOutputDelayLength(0),
|
||||
timeOffsetLength(0)
|
||||
{}
|
||||
|
||||
struct LIB_EXPORT SpsInfo {
|
||||
SpsInfo();
|
||||
uint32 id;
|
||||
uint32 profileIndication;
|
||||
uint32 profileCompat;
|
||||
uint32 levelIdc;
|
||||
uint32 chromatFormatIndication;
|
||||
uint32 log2MaxFrameNum;
|
||||
uint32 offsetForNonRefPic;
|
||||
uint32 offsetForTopToBottomField;
|
||||
uint32 numRefFramesInPicOrderCntCycle;
|
||||
bool deltaPicOrderAlwaysZeroFlag;
|
||||
bool frameMbsOnly;
|
||||
bool vuiPresent;
|
||||
bool arFound;
|
||||
uint32 parNum;
|
||||
uint32 parDen;
|
||||
ugolomb id;
|
||||
byte profileIndication;
|
||||
byte profileConstraints;
|
||||
byte levelIndication;
|
||||
ugolomb chromaFormatIndication;
|
||||
ugolomb pictureOrderCountType;
|
||||
ugolomb log2MaxFrameNum;
|
||||
ugolomb log2MaxPictureOrderCountLsb;
|
||||
sgolomb offsetForNonRefPic;
|
||||
sgolomb offsetForTopToBottomField;
|
||||
ugolomb numRefFramesInPicOrderCntCycle;
|
||||
byte deltaPicOrderAlwaysZeroFlag;
|
||||
byte frameMbsOnly;
|
||||
byte vuiPresent;
|
||||
AspectRatio pixelAspectRatio;
|
||||
TimingInfo timingInfo;
|
||||
Margin cropping;
|
||||
Size size;
|
||||
uint32 checksum;
|
||||
Size pictureSize;
|
||||
byte hrdParametersPresent;
|
||||
HrdParameters nalHrdParameters;
|
||||
HrdParameters vclHrdParameters;
|
||||
byte pictureStructPresent;
|
||||
uint16 size;
|
||||
|
||||
void parse(std::istream &stream);
|
||||
void parse(IoUtilities::BinaryReader &reader, uint32 maxSize);
|
||||
};
|
||||
|
||||
inline SpsInfo::SpsInfo() :
|
||||
id(0),
|
||||
profileIndication(0),
|
||||
profileCompat(0),
|
||||
levelIdc(0),
|
||||
chromatFormatIndication(0),
|
||||
profileConstraints(0),
|
||||
levelIndication(0),
|
||||
chromaFormatIndication(0),
|
||||
pictureOrderCountType(0),
|
||||
log2MaxFrameNum(0),
|
||||
log2MaxPictureOrderCountLsb(0),
|
||||
offsetForNonRefPic(0),
|
||||
offsetForTopToBottomField(0),
|
||||
numRefFramesInPicOrderCntCycle(0),
|
||||
deltaPicOrderAlwaysZeroFlag(false),
|
||||
frameMbsOnly(false),
|
||||
vuiPresent(false),
|
||||
arFound(false),
|
||||
parNum(0),
|
||||
parDen(0),
|
||||
checksum(0)
|
||||
deltaPicOrderAlwaysZeroFlag(0),
|
||||
frameMbsOnly(0),
|
||||
vuiPresent(0),
|
||||
hrdParametersPresent(0),
|
||||
pictureStructPresent(0),
|
||||
size(0)
|
||||
{}
|
||||
|
||||
struct PpsInfo {
|
||||
PpsInfo();
|
||||
uint32 id;
|
||||
uint32 spsId;
|
||||
bool picOrderPresent;
|
||||
ugolomb id;
|
||||
ugolomb spsId;
|
||||
byte picOrderPresent;
|
||||
uint16 size;
|
||||
|
||||
void parse(IoUtilities::BinaryReader &reader, uint32 maxSize);
|
||||
};
|
||||
|
||||
inline PpsInfo::PpsInfo() :
|
||||
id(0),
|
||||
spsId(0),
|
||||
picOrderPresent(false)
|
||||
picOrderPresent(false),
|
||||
size(0)
|
||||
{}
|
||||
|
||||
struct SliceInfo {
|
||||
|
@ -99,7 +147,7 @@ struct SliceInfo {
|
|||
uint32 deltaPicOrderCnt[2];
|
||||
uint32 firstMbInSlice;
|
||||
uint32 sps;
|
||||
uint32 pps;
|
||||
uint32 pps;
|
||||
};
|
||||
|
||||
inline SliceInfo::SliceInfo() :
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
#!/bin/sh
|
||||
|
||||
testfilespath="$1"
|
||||
|
||||
# determine sequences for formatted output
|
||||
red=$(tput setaf 1)
|
||||
green=$(tput setaf 2)
|
||||
yellow=$(tput setaf 3)
|
||||
blue=$(tput setaf 4)
|
||||
bold=$(tput bold)
|
||||
normal=$(tput sgr0)
|
||||
|
||||
inform() {
|
||||
echo "${bold}==> ${blue}INFO:${normal} ${bold}${1}${normal}"
|
||||
}
|
||||
|
||||
success() {
|
||||
echo "${bold}==> ${green}SUCCESS:${normal} ${bold}${1}${normal}"
|
||||
}
|
||||
|
||||
fail() {
|
||||
echo "${bold}==> ${red}FAILURE:${normal} ${bold}${1}${normal}"
|
||||
}
|
||||
|
||||
skipping() {
|
||||
echo 'archive/files already exist -> skipping download'
|
||||
}
|
||||
|
||||
download() {
|
||||
title="$1" url="$2" filename="$3" destdir="$4"
|
||||
|
||||
inform "Downloading \"$title\" ..."
|
||||
if [[ ! -d $destdir ]]; then
|
||||
# actual download
|
||||
pushd '/tmp'
|
||||
if [[ ! -f $filename ]]; then
|
||||
wget --output-document="$filename" "$url"
|
||||
if [[ $? != 0 ]]; then
|
||||
fail "unable to download: \"$url\""
|
||||
return
|
||||
fi
|
||||
else
|
||||
skipping
|
||||
fi
|
||||
popd
|
||||
|
||||
# extraction
|
||||
mkdir "$destdir"
|
||||
pushd "$destdir"
|
||||
case "$filename" in
|
||||
*.zip) unzip "/tmp/$filename";;
|
||||
*) fail "unable to extract archive: format \"${filename#*.}\" not supported"
|
||||
return;;
|
||||
esac
|
||||
if [[ $? != 0 ]]; then
|
||||
fail "unable to extract \"/tmp/$filename\""
|
||||
return
|
||||
fi
|
||||
popd
|
||||
else
|
||||
skipping
|
||||
fi
|
||||
}
|
||||
|
||||
# enter testfiles directory
|
||||
if [[ -d $testfilespath ]]; then
|
||||
cd "$testfilespath"
|
||||
else
|
||||
fail "specified testfiles directory does not exist"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
download \
|
||||
'Matroska Test Suite - Wave 1' \
|
||||
'http://downloads.sourceforge.net/project/matroska/test_files/matroska_test_w1_1.zip?r=&ts=1454982254&use_mirror=netix' \
|
||||
'matroska_test_w1_1.zip' \
|
||||
'matroska_wave1'
|
2
margin.h
2
margin.h
|
@ -123,7 +123,7 @@ inline std::string Margin::toString() const
|
|||
{
|
||||
std::stringstream res;
|
||||
res << "top: " << m_top << "; left: " << m_left;
|
||||
res << "bottom: " << m_bottom << "; right: " << m_right;
|
||||
res << "; bottom: " << m_bottom << "; right: " << m_right;
|
||||
return std::string(res.str());
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "../wav/waveaudiostream.h"
|
||||
|
||||
#include "../avc/avcconfiguration.h"
|
||||
|
||||
#include "../mp4/mp4ids.h"
|
||||
#include "../mp4/mp4track.h"
|
||||
|
||||
|
@ -411,6 +413,19 @@ void MatroskaTrack::internalParseHeader()
|
|||
m_extensionChannelConfig = audioSpecificConfig->extensionChannelConfiguration;
|
||||
}
|
||||
break;
|
||||
case GeneralMediaFormat::Avc:
|
||||
if((codecPrivateElement = m_trackElement->childById(MatroskaIds::CodecPrivate))) {
|
||||
auto avcConfig = make_unique<Media::AvcConfiguration>();
|
||||
try {
|
||||
m_istream->seekg(codecPrivateElement->dataOffset());
|
||||
avcConfig->parse(m_reader, codecPrivateElement->dataSize());
|
||||
Mp4Track::addInfo(*avcConfig, *this);
|
||||
} catch(const TruncatedDataException &) {
|
||||
addNotification(NotificationType::Critical, "AVC configuration is truncated.", context);
|
||||
} catch(const Failure &) {
|
||||
addNotification(NotificationType::Critical, "AVC configuration is invalid.", context);
|
||||
}
|
||||
}
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ const char *MediaFormat::name() const
|
|||
case GeneralMediaFormat::Amr: return "Adaptive Multi-Rate audio codec";
|
||||
case GeneralMediaFormat::Avc:
|
||||
switch(sub) {
|
||||
case AvcCavlc444IntraProfile: return "Advanced Video Coding CAVLC 4:4:4 Intra Profile";
|
||||
case AvcBaselineProfile: return "Advanced Video Coding Basline Profile";
|
||||
case AvcMainProfile: return "Advanced Video Coding Main Profile";
|
||||
case AvcScalableBaselineProfile: return "Advanced Video Coding Scalable Basline Profile";
|
||||
|
@ -49,8 +50,12 @@ const char *MediaFormat::name() const
|
|||
case AvcExtendedProfile: return "Advanced Video Coding Extended Profile";
|
||||
case AvcHighProfile: return "Advanced Video Coding High Profile";
|
||||
case AvcHigh10Profile: return "Advanced Video Coding High 10 Profile";
|
||||
case AvcHighMultiviewProfile: return "Advanced Video Coding Multiview Profile";
|
||||
case AvcHigh422Profile: return "Advanced Video Coding High 4:2:2 Profile";
|
||||
case AvcStereoHighProfile: return "Advanced Video Coding Stereo High Profile";
|
||||
case AvcHighMultiviewDepthProfile: return "Advanced Video Coding Multiview Depth High Profile";
|
||||
case AvcHigh444Profile: return "Advanced Video Coding High 4:4:4 Profile";
|
||||
case AvcHigh444PredictiveProfile: return "Advanced Video Coding High 4:4:4 Predictive Profile";
|
||||
default: return "Advanced Video Coding";
|
||||
}
|
||||
case GeneralMediaFormat::Bitmap: return "Windows Bitmap";
|
||||
|
|
|
@ -195,6 +195,7 @@ enum Mpeg4VideoProfile : unsigned char {
|
|||
};
|
||||
|
||||
enum AvcProfile : unsigned char {
|
||||
AvcCavlc444IntraProfile = 0x2C,
|
||||
AvcBaselineProfile = 0x42,
|
||||
AvcMainProfile = 0x4D,
|
||||
AvcScalableBaselineProfile = 0x53,
|
||||
|
@ -202,8 +203,12 @@ enum AvcProfile : unsigned char {
|
|||
AvcExtendedProfile = 0x58,
|
||||
AvcHighProfile = 0x64,
|
||||
AvcHigh10Profile = 0x6E,
|
||||
AvcHighMultiviewProfile = 0x76,
|
||||
AvcHigh422Profile = 0x7A,
|
||||
AvcHigh444Profile = 0x90
|
||||
AvcStereoHighProfile = 0x80,
|
||||
AvcHighMultiviewDepthProfile = 0x8A,
|
||||
AvcHigh444Profile = 0x90,
|
||||
AvcHigh444PredictiveProfile = 0xF4
|
||||
};
|
||||
|
||||
enum DtsSpecifier : unsigned char {
|
||||
|
|
121
mp4/mp4track.cpp
121
mp4/mp4track.cpp
|
@ -4,6 +4,8 @@
|
|||
#include "./mp4ids.h"
|
||||
#include "./mpeg4descriptor.h"
|
||||
|
||||
#include "../avc/avcconfiguration.h"
|
||||
|
||||
#include "../mpegaudio/mpegaudioframe.h"
|
||||
#include "../mpegaudio/mpegaudioframestream.h"
|
||||
|
||||
|
@ -48,7 +50,8 @@ Mpeg4AudioSpecificConfig::Mpeg4AudioSpecificConfig() :
|
|||
epConfig(0)
|
||||
{}
|
||||
|
||||
Mpeg4VideoSpecificConfig::Mpeg4VideoSpecificConfig()
|
||||
Mpeg4VideoSpecificConfig::Mpeg4VideoSpecificConfig() :
|
||||
profile(0)
|
||||
{}
|
||||
|
||||
/*!
|
||||
|
@ -423,63 +426,6 @@ vector<uint64> Mp4Track::readChunkSizes()
|
|||
return chunkSizes;
|
||||
}
|
||||
|
||||
#ifdef UNDER_CONSTRUCTION
|
||||
/*!
|
||||
* \brief Reads the AVC configuration for the track.
|
||||
* \remarks
|
||||
* - Returns an empty configuration for non-AVC tracks.
|
||||
* - Notifications might be added.
|
||||
*/
|
||||
AvcConfiguration Mp4Track::parseAvcConfiguration(StatusProvider &statusProvider, BinaryReader &reader, uint64 startOffset, uint64 size)
|
||||
{
|
||||
AvcConfiguration config;
|
||||
try {
|
||||
if(size >= 5) {
|
||||
// skip first byte (is always 1)
|
||||
reader.stream()->seekg(startOffset + 1);
|
||||
// read profile, IDC level, NALU size length
|
||||
config.profileIdc = reader.readByte();
|
||||
config.profileCompat = reader.readByte();
|
||||
config.levelIdc = reader.readByte();
|
||||
config.naluSizeLength = reader.readByte() & 0x03;
|
||||
// read SPS infos
|
||||
if((size -= 5) >= 3) {
|
||||
byte entryCount = reader.readByte() & 0x0f;
|
||||
uint16 entrySize;
|
||||
while(entryCount && size) {
|
||||
if((entrySize = reader.readUInt16BE()) <= size) {
|
||||
// TODO: read entry
|
||||
size -= entrySize;
|
||||
} else {
|
||||
throw TruncatedDataException();
|
||||
}
|
||||
--entryCount;
|
||||
}
|
||||
// read PPS infos
|
||||
if((size -= 5) >= 3) {
|
||||
entryCount = reader.readByte();
|
||||
while(entryCount && size) {
|
||||
if((entrySize = reader.readUInt16BE()) <= size) {
|
||||
// TODO: read entry
|
||||
size -= entrySize;
|
||||
} else {
|
||||
throw TruncatedDataException();
|
||||
}
|
||||
--entryCount;
|
||||
}
|
||||
// TODO: read trailer
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw TruncatedDataException();
|
||||
} catch (TruncatedDataException &) {
|
||||
statusProvider.addNotification(NotificationType::Critical, "AVC configuration is truncated.", "parsing AVC configuration");
|
||||
}
|
||||
return config;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief Reads the MPEG-4 elementary stream descriptor for the track.
|
||||
* \remarks
|
||||
|
@ -761,8 +707,7 @@ std::unique_ptr<Mpeg4VideoSpecificConfig> Mp4Track::parseVideoSpecificConfig(Sta
|
|||
default:
|
||||
;
|
||||
}
|
||||
// skip stuff we're not interested in to get the start of the
|
||||
// next video object
|
||||
// skip remainging values to get the start of the next video object
|
||||
while(size >= 3) {
|
||||
if(reader.readUInt24BE() != 1) {
|
||||
reader.stream()->seekg(-2, ios_base::cur);
|
||||
|
@ -915,6 +860,41 @@ void Mp4Track::updateChunkOffset(uint32 chunkIndex, uint64 offset)
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds the information from the specified \a avcConfig to the specified \a track.
|
||||
*/
|
||||
void Mp4Track::addInfo(const AvcConfiguration &avcConfig, AbstractTrack &track)
|
||||
{
|
||||
if(!avcConfig.spsInfos.empty()) {
|
||||
const SpsInfo &spsInfo = avcConfig.spsInfos.back();
|
||||
track.m_format.sub = spsInfo.profileIndication;
|
||||
track.m_version = static_cast<double>(spsInfo.levelIndication) / 10;
|
||||
track.m_cropping = spsInfo.cropping;
|
||||
track.m_pixelSize = spsInfo.pictureSize;
|
||||
switch(spsInfo.chromaFormatIndication) {
|
||||
case 0:
|
||||
track.m_chromaFormat = "monochrome";
|
||||
break;
|
||||
case 1:
|
||||
track.m_chromaFormat = "YUV 4:2:0";
|
||||
break;
|
||||
case 2:
|
||||
track.m_chromaFormat = "YUV 4:2:2";
|
||||
break;
|
||||
case 3:
|
||||
track.m_chromaFormat = "YUV 4:4:4";
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
track.m_pixelAspectRatio = spsInfo.pixelAspectRatio;
|
||||
} else {
|
||||
track.m_format.sub = avcConfig.profileIndication;
|
||||
track.m_version = static_cast<double>(avcConfig.levelIndication) / 10;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Makes the track entry ("trak"-atom) for the track. The data is written to the assigned output stream
|
||||
* at the current position.
|
||||
|
@ -1380,7 +1360,7 @@ void Mp4Track::internalParseHeader()
|
|||
}
|
||||
break;
|
||||
case FourccIds::Mpeg4Sample:
|
||||
//m_istream->seekg(6 + 2, ios_base::cur); // skip reserved bytes and data reference index
|
||||
// skip reserved bytes and data reference index
|
||||
codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 8);
|
||||
if(!esDescParentAtom) {
|
||||
esDescParentAtom = codecConfigContainerAtom;
|
||||
|
@ -1394,10 +1374,23 @@ void Mp4Track::internalParseHeader()
|
|||
;
|
||||
}
|
||||
}
|
||||
// parse AVC configuration
|
||||
//codecConfigContainerAtom->childById(Mp4AtomIds::AvcConfiguration);
|
||||
// parse MPEG-4 elementary stream descriptor
|
||||
|
||||
if(esDescParentAtom) {
|
||||
// parse AVC configuration
|
||||
if(Mp4Atom *avcConfigAtom = esDescParentAtom->childById(Mp4AtomIds::AvcConfiguration)) {
|
||||
m_istream->seekg(avcConfigAtom->dataOffset());
|
||||
m_avcConfig = make_unique<Media::AvcConfiguration>();
|
||||
try {
|
||||
m_avcConfig->parse(reader, avcConfigAtom->dataSize());
|
||||
addInfo(*m_avcConfig, *this);
|
||||
} catch(const TruncatedDataException &) {
|
||||
addNotification(NotificationType::Critical, "AVC configuration is truncated.", context);
|
||||
} catch(const Failure &) {
|
||||
addNotification(NotificationType::Critical, "AVC configuration is invalid.", context);
|
||||
}
|
||||
}
|
||||
|
||||
// parse MPEG-4 elementary stream descriptor
|
||||
Mp4Atom *esDescAtom = esDescParentAtom->childById(Mp4FormatExtensionIds::Mpeg4ElementaryStreamDescriptor);
|
||||
if(!esDescAtom) {
|
||||
esDescAtom = esDescParentAtom->childById(Mp4FormatExtensionIds::Mpeg4ElementaryStreamDescriptor2);
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
#ifndef MP4TRACK_H
|
||||
#define MP4TRACK_H
|
||||
|
||||
#ifdef UNDER_CONSTRUCTION
|
||||
#include "../avc/avcconfiguration.h"
|
||||
#endif
|
||||
|
||||
#include "../abstracttrack.h"
|
||||
|
||||
#include <vector>
|
||||
|
@ -15,6 +11,7 @@ namespace Media
|
|||
|
||||
class Mp4Atom;
|
||||
class Mpeg4Descriptor;
|
||||
class AvcConfiguration;
|
||||
|
||||
class LIB_EXPORT Mpeg4AudioSpecificConfig
|
||||
{
|
||||
|
@ -133,11 +130,9 @@ public:
|
|||
uint32 chunkCount() const;
|
||||
uint32 sampleToChunkEntryCount() const;
|
||||
const Mpeg4ElementaryStreamInfo *mpeg4ElementaryStreamInfo() const;
|
||||
const AvcConfiguration *avcConfiguration() const;
|
||||
|
||||
// methods to parse configuration details from the track header
|
||||
#ifdef UNDER_CONSTRUCTION
|
||||
static AvcConfiguration parseAvcConfiguration(StatusProvider &statusProvider, IoUtilities::BinaryReader &reader, uint64 startOffset, uint64 size);
|
||||
#endif
|
||||
static std::unique_ptr<Mpeg4ElementaryStreamInfo> parseMpeg4ElementaryStreamInfo(StatusProvider &statusProvider, IoUtilities::BinaryReader &reader, Mp4Atom *esDescAtom);
|
||||
static std::unique_ptr<Mpeg4AudioSpecificConfig> parseAudioSpecificConfig(StatusProvider &statusProvider, std::istream &stream, uint64 startOffset, uint64 size);
|
||||
static std::unique_ptr<Mpeg4VideoSpecificConfig> parseVideoSpecificConfig(StatusProvider &statusProvider, IoUtilities::BinaryReader &reader, uint64 startOffset, uint64 size);
|
||||
|
@ -160,6 +155,8 @@ public:
|
|||
void updateChunkOffsets(const std::vector<uint64> &chunkOffsets);
|
||||
void updateChunkOffset(uint32 chunkIndex, uint64 offset);
|
||||
|
||||
static void addInfo(const AvcConfiguration &avcConfig, AbstractTrack &track);
|
||||
|
||||
protected:
|
||||
void internalParseHeader();
|
||||
|
||||
|
@ -187,6 +184,7 @@ private:
|
|||
uint32 m_chunkCount;
|
||||
uint32 m_sampleToChunkEntryCount;
|
||||
std::unique_ptr<Mpeg4ElementaryStreamInfo> m_esInfo;
|
||||
std::unique_ptr<AvcConfiguration> m_avcConfig;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -238,20 +236,26 @@ inline uint32 Mp4Track::sampleToChunkEntryCount() const
|
|||
/*!
|
||||
* \brief Returns information about the MPEG-4 elementary stream.
|
||||
* \remarks
|
||||
* - The Mp4Track::readMpeg4ElementaryStreamInfo() method must be called before
|
||||
* to parse the information. This is done when parsing the track.
|
||||
* - The information is only available, if the track has an MPEG-4 elementary stream
|
||||
* descriptor atom.
|
||||
* - The track must be parsed before this information becomes available.
|
||||
* - The information is only available, if the track has an MPEG-4 elementary stream descriptor atom.
|
||||
* - The track keeps ownership over the returned object.
|
||||
* \sa
|
||||
* - readMpeg4ElementaryStreamInfo()
|
||||
* - hasMpeg4ElementaryStreamDesc()
|
||||
*/
|
||||
inline const Mpeg4ElementaryStreamInfo *Mp4Track::mpeg4ElementaryStreamInfo() const
|
||||
{
|
||||
return m_esInfo.get();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the AVC configuration.
|
||||
* \remarks
|
||||
* - The track must be parsed before this information becomes available.
|
||||
* - The track keeps ownership over the returned object.
|
||||
*/
|
||||
inline const AvcConfiguration *Mp4Track::avcConfiguration() const
|
||||
{
|
||||
return m_avcConfig.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // MP4TRACK_H
|
||||
|
|
|
@ -30,6 +30,9 @@ forcefullparsedefault {
|
|||
HEADERS += \
|
||||
abstractcontainer.h \
|
||||
abstracttrack.h \
|
||||
aspectratio.h \
|
||||
avc/avcinfo.h \
|
||||
avc/avcconfiguration.h \
|
||||
backuphelper.h \
|
||||
basicfileinfo.h \
|
||||
exceptions.h \
|
||||
|
@ -98,6 +101,9 @@ HEADERS += \
|
|||
SOURCES += \
|
||||
abstractcontainer.cpp \
|
||||
abstracttrack.cpp \
|
||||
aspectratio.cpp \
|
||||
avc/avcinfo.cpp \
|
||||
avc/avcconfiguration.cpp
|
||||
backuphelper.cpp \
|
||||
basicfileinfo.cpp \
|
||||
exceptions.cpp \
|
||||
|
@ -154,15 +160,11 @@ SOURCES += \
|
|||
underconstruction {
|
||||
HEADERS += \
|
||||
aac/aacframe.h \
|
||||
aac/aaccodebook.h \
|
||||
avc/avcinfo.h \
|
||||
avc/avcconfiguration.h
|
||||
aac/aaccodebook.h
|
||||
|
||||
SOURCES += \
|
||||
aac/aacframe.cpp \
|
||||
aac/aaccodebook.cpp \
|
||||
avc/avcinfo.cpp \
|
||||
avc/avcconfiguration.cpp
|
||||
aac/aaccodebook.cpp
|
||||
}
|
||||
|
||||
OTHER_FILES += \
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
#include <c++utilities/tests/cppunit.h>
|
|
@ -0,0 +1,51 @@
|
|||
#include <c++utilities/tests/testutils.h>
|
||||
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include <cppunit/TestFixture.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
using namespace CPPUNIT_NS;
|
||||
|
||||
class MatroskaTests : public TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE(MatroskaTests);
|
||||
CPPUNIT_TEST(testParsing);
|
||||
CPPUNIT_TEST(testMaking);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
void testParsing();
|
||||
void testMaking();
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(MatroskaTests);
|
||||
|
||||
void MatroskaTests::setUp()
|
||||
{}
|
||||
|
||||
void MatroskaTests::tearDown()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Tests the Matroska parser via MediaFileInfo.
|
||||
*/
|
||||
void MatroskaTests::testParsing()
|
||||
{
|
||||
cerr << TestUtilities::workingCopyPath("matroska/test1.mkv") << endl;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Tests the Matroska maker via MediaFileInfo.
|
||||
*/
|
||||
void MatroskaTests::testMaking()
|
||||
{
|
||||
|
||||
}
|
Loading…
Reference in New Issue