mkvmuxer: Add support for the Colour element and its children.

Change-Id: I8026a2ba6c664cbf0ce0a6602a79942283b194b1
This commit is contained in:
Tom Finegan 2016-02-08 15:21:45 -08:00
parent 41a9147f2a
commit a281a22955
2 changed files with 382 additions and 5 deletions

View File

@ -8,11 +8,13 @@
#include "mkvmuxer.hpp"
#include <cfloat>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <memory>
#include <new>
#include "mkvmuxerutil.hpp"
@ -27,6 +29,9 @@
namespace mkvmuxer {
const float MasteringMetadata::kUnspecifiedMmValue = FLT_MAX;
const uint64 Colour::kUnspecifiedColourValue = UINT64_MAX;
namespace {
// Deallocate the string designated by |dst|, and then copy the |src|
// string to |dst|. The caller owns both the |src| string and the
@ -55,6 +60,20 @@ bool StrCpy(const char* src, char** dst_ptr) {
strcpy(dst, src); // NOLINT
return true;
}
typedef std::auto_ptr<PrimaryChromaticity> PrimaryChromaticityPtr;
bool CopyChromaticity(const PrimaryChromaticity* src,
PrimaryChromaticityPtr* dst) {
if (!dst)
return false;
dst->reset(new (std::nothrow) PrimaryChromaticity(src->x, src->y));
if (!dst->get())
return false;
return true;
}
} // namespace
///////////////////////////////////////////////////////////////
@ -842,6 +861,231 @@ void Track::set_name(const char* name) {
}
}
///////////////////////////////////////////////////////////////
//
// Colour and its child elements
uint64 PrimaryChromaticity::PrimaryChromaticityPayloadSize(MkvId x_id,
MkvId y_id) const {
return EbmlElementSize(x_id, x) + EbmlElementSize(y_id, y);
}
bool PrimaryChromaticity::Write(IMkvWriter* writer, MkvId x_id,
MkvId y_id) const {
return WriteEbmlElement(writer, x_id, x) && WriteEbmlElement(writer, y_id, y);
}
uint64 MasteringMetadata::MasteringMetadataPayloadSize() const {
uint64 size = 0;
if (luminance_max != kUnspecifiedMmValue)
size += EbmlElementSize(kMkvLuminanceMax, luminance_max);
if (luminance_min != kUnspecifiedMmValue)
size += EbmlElementSize(kMkvLuminanceMin, luminance_min);
if (r_) {
size += r_->PrimaryChromaticityPayloadSize(kMkvPrimaryRChromaticityX,
kMkvPrimaryRChromaticityY);
}
if (g_) {
size += g_->PrimaryChromaticityPayloadSize(kMkvPrimaryGChromaticityX,
kMkvPrimaryGChromaticityY);
}
if (b_) {
size += b_->PrimaryChromaticityPayloadSize(kMkvPrimaryBChromaticityX,
kMkvPrimaryBChromaticityY);
}
if (white_point_) {
size += white_point_->PrimaryChromaticityPayloadSize(
kMkvWhitePointChromaticityX, kMkvWhitePointChromaticityY);
}
if (size > 0)
size += EbmlMasterElementSize(kMkvMasteringMetadata, size);
return size;
}
bool MasteringMetadata::Write(IMkvWriter* writer) const {
const uint64 size = MasteringMetadataPayloadSize();
// Don't write an empty element.
if (size == 0)
return true;
if (!WriteEbmlMasterElement(writer, kMkvMasteringMetadata, size))
return false;
if (luminance_max != kUnspecifiedMmValue &&
!WriteEbmlElement(writer, kMkvLuminanceMax, luminance_max)) {
return false;
}
if (luminance_min != kUnspecifiedMmValue &&
!WriteEbmlElement(writer, kMkvLuminanceMin, luminance_min)) {
return false;
}
if (r_ &&
!r_->Write(writer, kMkvPrimaryRChromaticityX,
kMkvPrimaryRChromaticityY)) {
return false;
}
if (g_ &&
!g_->Write(writer, kMkvPrimaryGChromaticityX,
kMkvPrimaryGChromaticityY)) {
return false;
}
if (b_ &&
!b_->Write(writer, kMkvPrimaryBChromaticityX,
kMkvPrimaryBChromaticityY)) {
return false;
}
if (white_point_ &&
!white_point_->Write(writer, kMkvWhitePointChromaticityX,
kMkvWhitePointChromaticityY)) {
return false;
}
return true;
}
bool MasteringMetadata::SetChromaticity(
const PrimaryChromaticity* r, const PrimaryChromaticity* g,
const PrimaryChromaticity* b, const PrimaryChromaticity* white_point) {
PrimaryChromaticityPtr r_ptr(NULL);
if (r) {
if (!CopyChromaticity(r, &r_ptr))
return false;
}
PrimaryChromaticityPtr g_ptr(NULL);
if (g) {
if (!CopyChromaticity(g, &g_ptr))
return false;
}
PrimaryChromaticityPtr b_ptr(NULL);
if (b) {
if (!CopyChromaticity(b, &b_ptr))
return false;
}
PrimaryChromaticityPtr wp_ptr(NULL);
if (white_point) {
if (!CopyChromaticity(white_point, &wp_ptr))
return false;
}
r_ = r_ptr.release();
g_ = g_ptr.release();
b_ = b_ptr.release();
white_point_ = wp_ptr.release();
return true;
}
uint64 Colour::ColourPayloadSize() const {
uint64 size = 0;
if (matrix != kUnspecifiedColourValue)
size += EbmlElementSize(kMkvMatrix, matrix);
if (bits_per_channel != kUnspecifiedColourValue)
size += EbmlElementSize(kMkvBitsPerChannel, bits_per_channel);
if (chroma_subsampling != kUnspecifiedColourValue)
size += EbmlElementSize(kMkvChromaSubsampling, chroma_subsampling);
if (chroma_siting_horz != kUnspecifiedColourValue)
size += EbmlElementSize(kMkvChromaSitingHorz, chroma_siting_horz);
if (chroma_siting_vert != kUnspecifiedColourValue)
size += EbmlElementSize(kMkvChromaSitingVert, chroma_siting_vert);
if (range != kUnspecifiedColourValue)
size += EbmlElementSize(kMkvRange, range);
if (transfer_function != kUnspecifiedColourValue)
size += EbmlElementSize(kMkvTransferFunction, transfer_function);
if (primaries != kUnspecifiedColourValue)
size += EbmlElementSize(kMkvPrimaries, primaries);
if (max_cll != kUnspecifiedColourValue)
size += EbmlElementSize(kMkvMaxCLL, max_cll);
if (max_fall != kUnspecifiedColourValue)
size += EbmlElementSize(kMkvMaxFALL, max_fall);
if (mastering_metadata_)
size += mastering_metadata_->MasteringMetadataPayloadSize();
if (size > 0)
size += EbmlMasterElementSize(kMkvColour, size);
return size;
}
bool Colour::Write(IMkvWriter* writer) const {
const uint64 size = ColourPayloadSize();
// Don't write an empty element.
if (size == 0)
return true;
if (!WriteEbmlMasterElement(writer, kMkvColour, size))
return false;
if (matrix != kUnspecifiedColourValue &&
!WriteEbmlElement(writer, kMkvMatrix, matrix)) {
return false;
}
if (bits_per_channel != kUnspecifiedColourValue &&
!WriteEbmlElement(writer, kMkvBitsPerChannel, bits_per_channel)) {
return false;
}
if (chroma_subsampling != kUnspecifiedColourValue &&
!WriteEbmlElement(writer, kMkvChromaSubsampling, chroma_subsampling)) {
return false;
}
if (chroma_siting_horz != kUnspecifiedColourValue &&
!WriteEbmlElement(writer, kMkvChromaSitingHorz, chroma_siting_horz)) {
return false;
}
if (chroma_siting_vert != kUnspecifiedColourValue &&
!WriteEbmlElement(writer, kMkvChromaSitingVert, chroma_siting_vert)) {
return false;
}
if (range != kUnspecifiedColourValue &&
!WriteEbmlElement(writer, kMkvRange, range)) {
return false;
}
if (transfer_function != kUnspecifiedColourValue &&
!WriteEbmlElement(writer, kMkvTransferFunction, transfer_function)) {
return false;
}
if (primaries != kUnspecifiedColourValue &&
!WriteEbmlElement(writer, kMkvPrimaries, primaries)) {
return false;
}
if (max_cll != kUnspecifiedColourValue &&
!WriteEbmlElement(writer, kMkvMaxCLL, max_cll)) {
return false;
}
if (max_fall != kUnspecifiedColourValue &&
!WriteEbmlElement(writer, kMkvMaxFALL, max_fall)) {
return false;
}
if (mastering_metadata_ && !mastering_metadata_->Write(writer))
return false;
return true;
}
bool Colour::SetMasteringMetadata(const MasteringMetadata& mastering_metadata) {
std::auto_ptr<MasteringMetadata> mm_ptr(new MasteringMetadata());
if (!mm_ptr.get())
return false;
mm_ptr->luminance_max = mastering_metadata.luminance_max;
mm_ptr->luminance_min = mastering_metadata.luminance_min;
if (!mm_ptr->SetChromaticity(mastering_metadata.r(), mastering_metadata.g(),
mastering_metadata.b(),
mastering_metadata.white_point())) {
return false;
}
delete mastering_metadata_;
mastering_metadata_ = mm_ptr.release();
return true;
}
///////////////////////////////////////////////////////////////
//
// VideoTrack Class
@ -858,9 +1102,10 @@ VideoTrack::VideoTrack(unsigned int* seed)
height_(0),
stereo_mode_(0),
alpha_mode_(0),
width_(0) {}
width_(0),
colour_(NULL) {}
VideoTrack::~VideoTrack() {}
VideoTrack::~VideoTrack() { delete colour_; }
bool VideoTrack::SetStereoMode(uint64 stereo_mode) {
if (stereo_mode != kMono && stereo_mode != kSideBySideLeftIsFirst &&
@ -945,6 +1190,10 @@ bool VideoTrack::Write(IMkvWriter* writer) const {
return false;
}
}
if (colour_) {
if (!colour_->Write(writer))
return false;
}
const int64 stop_position = writer->Position();
if (stop_position < 0 ||
@ -955,6 +1204,30 @@ bool VideoTrack::Write(IMkvWriter* writer) const {
return true;
}
bool VideoTrack::SetColour(const Colour& colour) {
std::auto_ptr<Colour> colour_ptr(new Colour());
if (!colour_ptr.get())
return false;
if (colour.mastering_metadata()) {
if (!colour_ptr->SetMasteringMetadata(*colour.mastering_metadata()))
return false;
}
colour_ptr->matrix = colour.matrix;
colour_ptr->primaries = colour.bits_per_channel;
colour_ptr->chroma_subsampling = colour.chroma_subsampling;
colour_ptr->chroma_siting_horz = colour.chroma_siting_horz;
colour_ptr->chroma_siting_vert = colour.chroma_siting_vert;
colour_ptr->range = colour.range;
colour_ptr->transfer_function = colour.transfer_function;
colour_ptr->primaries = colour.primaries;
colour_ptr->max_cll = colour.max_cll;
colour_ptr->max_fall = colour.max_fall;
colour_ = colour_ptr.release();
return true;
}
uint64 VideoTrack::VideoPayloadSize() const {
uint64 size = EbmlElementSize(kMkvPixelWidth, width_);
size += EbmlElementSize(kMkvPixelHeight, height_);
@ -976,6 +1249,8 @@ uint64 VideoTrack::VideoPayloadSize() const {
size += EbmlElementSize(kMkvAlphaMode, alpha_mode_);
if (frame_rate_ > 0.0)
size += EbmlElementSize(kMkvFrameRate, static_cast<float>(frame_rate_));
if (colour_)
size += colour_->ColourPayloadSize();
return size;
}
@ -1048,9 +1323,7 @@ const char Tracks::kVp9CodecId[] = "V_VP9";
const char Tracks::kVp10CodecId[] = "V_VP10";
Tracks::Tracks()
: track_entries_(NULL),
track_entries_size_(0),
wrote_tracks_(false) {}
: track_entries_(NULL), track_entries_size_(0), wrote_tracks_(false) {}
Tracks::~Tracks() {
if (track_entries_) {

View File

@ -9,7 +9,10 @@
#ifndef MKVMUXER_HPP
#define MKVMUXER_HPP
#include <cstddef>
#include "mkvmuxertypes.hpp"
#include "webmids.hpp"
// For a description of the WebM elements see
// http://www.webmproject.org/code/specs/container/.
@ -329,6 +332,100 @@ class ContentEncoding {
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncoding);
};
///////////////////////////////////////////////////////////////
// Colour element.
struct PrimaryChromaticity {
PrimaryChromaticity(float x_val, float y_val) : x(x_val), y(y_val) {}
PrimaryChromaticity() : x(0), y(0) {}
~PrimaryChromaticity() {}
uint64 PrimaryChromaticityPayloadSize(MkvId x_id, MkvId y_id) const;
bool Write(IMkvWriter* writer, MkvId x_id, MkvId y_id) const;
float x;
float y;
};
class MasteringMetadata {
public:
static const float kUnspecifiedMmValue;
MasteringMetadata()
: luminance_max(kUnspecifiedMmValue),
luminance_min(kUnspecifiedMmValue),
r_(NULL),
g_(NULL),
b_(NULL),
white_point_(NULL) {}
~MasteringMetadata() {
delete r_;
delete g_;
delete b_;
delete white_point_;
}
uint64 MasteringMetadataPayloadSize() const;
bool Write(IMkvWriter* writer) const;
// Copies non-null chromaticity.
bool SetChromaticity(const PrimaryChromaticity* r,
const PrimaryChromaticity* g,
const PrimaryChromaticity* b,
const PrimaryChromaticity* white_point);
const PrimaryChromaticity* r() const { return r_; }
const PrimaryChromaticity* g() const { return g_; }
const PrimaryChromaticity* b() const { return b_; }
const PrimaryChromaticity* white_point() const { return white_point_; }
float luminance_max;
float luminance_min;
private:
PrimaryChromaticity* r_;
PrimaryChromaticity* g_;
PrimaryChromaticity* b_;
PrimaryChromaticity* white_point_;
};
class Colour {
public:
static const uint64 kUnspecifiedColourValue;
Colour()
: matrix(kUnspecifiedColourValue),
bits_per_channel(kUnspecifiedColourValue),
chroma_subsampling(kUnspecifiedColourValue),
chroma_siting_horz(kUnspecifiedColourValue),
chroma_siting_vert(kUnspecifiedColourValue),
range(kUnspecifiedColourValue),
transfer_function(kUnspecifiedColourValue),
primaries(kUnspecifiedColourValue),
max_cll(kUnspecifiedColourValue),
max_fall(kUnspecifiedColourValue),
mastering_metadata_(NULL) {}
~Colour() { delete mastering_metadata_; }
uint64 ColourPayloadSize() const;
bool Write(IMkvWriter* writer) const;
// Deep copies |mastering_metadata|.
bool SetMasteringMetadata(const MasteringMetadata& mastering_metadata);
const MasteringMetadata* mastering_metadata() const {
return mastering_metadata_;
}
uint64 matrix;
uint64 bits_per_channel;
uint64 chroma_subsampling;
uint64 chroma_siting_horz;
uint64 chroma_siting_vert;
uint64 range;
uint64 transfer_function;
uint64 primaries;
uint64 max_cll;
uint64 max_fall;
private:
MasteringMetadata* mastering_metadata_;
};
///////////////////////////////////////////////////////////////
// Track element.
class Track {
@ -471,6 +568,11 @@ class VideoTrack : public Track {
void set_width(uint64 width) { width_ = width; }
uint64 width() const { return width_; }
Colour* colour() { return colour_; }
// Deep copies |colour|.
bool SetColour(const Colour& colour);
private:
// Returns the size in bytes of the Video element.
uint64 VideoPayloadSize() const;
@ -488,6 +590,8 @@ class VideoTrack : public Track {
uint64 alpha_mode_;
uint64 width_;
Colour* colour_;
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(VideoTrack);
};