mkvmuxer: Add Projection element support.

Part of the Spherical Video V2 draft specification:
https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md

Change-Id: Ia935ba975a0f01c1fb2919325ab7f70254c2ed10
This commit is contained in:
Tom Finegan 2016-08-29 10:07:45 -07:00
parent 725f36207e
commit 483a0ff800
3 changed files with 181 additions and 2 deletions

View File

@ -124,6 +124,14 @@ enum MkvId {
kMkvLuminanceMin = 0x55DA,
// end mastering metadata
// end colour
// projection
kMkvProjection = 0x7670,
kMkvProjectionType = 0x7671,
kMkvProjectionPrivate = 0x7672,
kMkvProjectionPoseYaw = 0x7673,
kMkvProjectionPosePitch = 0x7674,
kMkvProjectionPoseRoll = 0x7675,
// end projection
// audio
kMkvAudio = 0xE1,
kMkvSamplingFrequency = 0xB5,

View File

@ -1228,6 +1228,89 @@ uint64_t Colour::PayloadSize() const {
return size;
}
///////////////////////////////////////////////////////////////
//
// Projection element
uint64_t Projection::ProjectionSize() const {
uint64_t size = PayloadSize();
if (size > 0)
size += EbmlMasterElementSize(libwebm::kMkvProjection, size);
return size;
}
bool Projection::Write(IMkvWriter* writer) const {
const uint64_t size = PayloadSize();
// Don't write an empty element.
if (size == 0)
return true;
if (!WriteEbmlMasterElement(writer, libwebm::kMkvProjection, size))
return false;
if (!WriteEbmlElement(writer, libwebm::kMkvProjectionType,
static_cast<uint64>(type_))) {
return false;
}
if (private_data_length_ > 0 && private_data_ != NULL &&
!WriteEbmlElement(writer, libwebm::kMkvProjectionPrivate, private_data_,
private_data_length_)) {
return false;
}
if (!WriteEbmlElement(writer, libwebm::kMkvProjectionPoseYaw, pose_yaw_))
return false;
if (!WriteEbmlElement(writer, libwebm::kMkvProjectionPosePitch, pose_pitch_)) {
return false;
}
if (!WriteEbmlElement(writer, libwebm::kMkvProjectionPoseRoll, pose_roll_)) {
return false;
}
return true;
}
bool Projection::SetProjectionPrivate(const uint8_t* data,
uint64_t data_length) {
if (data == NULL || data_length == 0) {
return false;
}
uint8_t* new_private_data = new (std::nothrow) uint8_t[data_length];
if (new_private_data == NULL) {
return false;
}
delete[] private_data_;
private_data_ = new_private_data;
private_data_length_ = data_length;
memcpy(private_data_, data, static_cast<size_t>(data_length));
return true;
}
uint64_t Projection::PayloadSize() const {
uint64_t size =
EbmlElementSize(libwebm::kMkvProjection, static_cast<uint64>(type_));
if (private_data_length_ > 0 && private_data_ != NULL) {
size += EbmlElementSize(libwebm::kMkvProjectionPrivate, private_data_,
private_data_length_);
}
size += EbmlElementSize(libwebm::kMkvProjectionPoseYaw, pose_yaw_);
size += EbmlElementSize(libwebm::kMkvProjectionPosePitch, pose_pitch_);
size += EbmlElementSize(libwebm::kMkvProjectionPoseRoll, pose_roll_);
return size;
}
///////////////////////////////////////////////////////////////
//
// VideoTrack Class
@ -1245,9 +1328,13 @@ VideoTrack::VideoTrack(unsigned int* seed)
stereo_mode_(0),
alpha_mode_(0),
width_(0),
colour_(NULL) {}
colour_(NULL),
projection_(NULL) {}
VideoTrack::~VideoTrack() { delete colour_; }
VideoTrack::~VideoTrack() {
delete colour_;
delete projection_;
}
bool VideoTrack::SetStereoMode(uint64_t stereo_mode) {
if (stereo_mode != kMono && stereo_mode != kSideBySideLeftIsFirst &&
@ -1346,6 +1433,10 @@ bool VideoTrack::Write(IMkvWriter* writer) const {
if (!colour_->Write(writer))
return false;
}
if (projection_) {
if (!projection_->Write(writer))
return false;
}
const int64_t stop_position = writer->Position();
if (stop_position < 0 ||
@ -1384,6 +1475,27 @@ bool VideoTrack::SetColour(const Colour& colour) {
return true;
}
bool VideoTrack::SetProjection(const Projection& projection) {
std::auto_ptr<Projection> projection_ptr(new Projection());
if (!projection_ptr.get())
return false;
if (projection.private_data()) {
if (!projection_ptr->SetProjectionPrivate(
projection.private_data(), projection.private_data_length())) {
return false;
}
}
projection_ptr->set_type(projection.type());
projection_ptr->set_pose_yaw(projection.pose_yaw());
projection_ptr->set_pose_pitch(projection.pose_pitch());
projection_ptr->set_pose_roll(projection.pose_roll());
delete projection_;
projection_ = projection_ptr.release();
return true;
}
uint64_t VideoTrack::VideoPayloadSize() const {
uint64_t size =
EbmlElementSize(libwebm::kMkvPixelWidth, static_cast<uint64>(width_));
@ -1419,6 +1531,9 @@ uint64_t VideoTrack::VideoPayloadSize() const {
if (colour_)
size += colour_->ColourSize();
if (projection_)
size += projection_->ProjectionSize();
return size;
}

View File

@ -464,6 +464,56 @@ class Colour {
MasteringMetadata* mastering_metadata_;
};
///////////////////////////////////////////////////////////////
// Projection element.
class Projection {
public:
enum ProjectionType {
kTypeNotPresent = -1,
kRectangular = 0,
kEquirectangular = 1,
kCubeMap = 2,
kMesh = 3,
};
static const uint64_t kValueNotPresent;
Projection()
: type_(kRectangular),
pose_yaw_(0.0),
pose_pitch_(0.0),
pose_roll_(0.0),
private_data_(NULL),
private_data_length_(0) {}
~Projection() { delete[] private_data_; }
uint64_t ProjectionSize() const;
bool Write(IMkvWriter* writer) const;
bool SetProjectionPrivate(const uint8_t* private_data,
uint64_t private_data_length);
ProjectionType type() const { return type_; }
void set_type(ProjectionType type) { type_ = type; }
float pose_yaw() const { return pose_yaw_; }
void set_pose_yaw(float pose_yaw) { pose_yaw_ = pose_yaw; }
float pose_pitch() const { return pose_pitch_; }
void set_pose_pitch(float pose_pitch) { pose_pitch_ = pose_pitch; }
float pose_roll() const { return pose_roll_; }
void set_pose_roll(float pose_roll) { pose_roll_ = pose_roll; }
uint8_t* private_data() const { return private_data_; }
uint64_t private_data_length() const { return private_data_length_; }
private:
// Returns size of VideoProjection child elements.
uint64_t PayloadSize() const;
ProjectionType type_;
float pose_yaw_;
float pose_pitch_;
float pose_roll_;
uint8_t* private_data_;
uint64_t private_data_length_;
};
///////////////////////////////////////////////////////////////
// Track element.
class Track {
@ -611,6 +661,11 @@ class VideoTrack : public Track {
// Deep copies |colour|.
bool SetColour(const Colour& colour);
Projection* projection() { return projection_; };
// Deep copies |projection|.
bool SetProjection(const Projection& projection);
private:
// Returns the size in bytes of the Video element.
uint64_t VideoPayloadSize() const;
@ -629,6 +684,7 @@ class VideoTrack : public Track {
uint64_t width_;
Colour* colour_;
Projection* projection_;
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(VideoTrack);
};