Add support for the Projection element

It's a part of the Google Spatial Media V2 spec:
https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md

Change-Id: I52f05e34b19239af09774da2f88eb584a0bfa628
This commit is contained in:
Michael Bradshaw 2016-08-25 12:00:05 -07:00
parent dae3d48a6f
commit 676a7135d1
8 changed files with 339 additions and 2 deletions

View File

@ -132,6 +132,7 @@ add_library(webm_parser STATIC
"${LIBWEBM_SRC_DIR}/webm_parser/src/parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/parser_utils.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/parser_utils.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/projection_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/recursive_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/seek_head_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/seek_parser.h"
@ -347,6 +348,7 @@ if (ENABLE_TESTS)
"${LIBWEBM_SRC_DIR}/webm_parser/tests/master_value_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/mastering_metadata_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/parser_utils_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/projection_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/recursive_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/seek_head_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/seek_parser_test.cc"

View File

@ -217,6 +217,18 @@ std::ostream& operator<<(std::ostream& os, Id id) {
return os << "LuminanceMax";
case Id::kLuminanceMin:
return os << "LuminanceMin";
case Id::kProjection:
return os << "Projection";
case Id::kProjectionType:
return os << "kProjectionType";
case Id::kProjectionPrivate:
return os << "kProjectionPrivate";
case Id::kProjectionPoseYaw:
return os << "kProjectionPoseYaw";
case Id::kProjectionPosePitch:
return os << "kProjectionPosePitch";
case Id::kProjectionPoseRoll:
return os << "ProjectionPoseRoll";
case Id::kAudio:
return os << "Audio";
case Id::kSamplingFrequency:
@ -441,6 +453,19 @@ std::ostream& operator<<(std::ostream& os, Primaries value) {
}
}
std::ostream& operator<<(std::ostream& os, ProjectionType value) {
switch (value) {
case ProjectionType::kRectangular:
return os << "0 (rectangular)";
case ProjectionType::kEquirectangular:
return os << "1 (equirectangular)";
case ProjectionType::kCubeMap:
return os << "2 (cube map)";
default:
return PrintUnknownEnumValue(os, value);
}
}
std::ostream& operator<<(std::ostream& os, FlagInterlaced value) {
switch (value) {
case FlagInterlaced::kUnspecified:
@ -684,6 +709,7 @@ class DemoCallback : public Callback {
PrintOptionalElement("AspectRatioType", video.aspect_ratio_type);
PrintOptionalElement("FrameRate", video.frame_rate);
PrintMasterElement("Colour", video.colour);
PrintMasterElement("Projection", video.projection);
}
void PrintMasterElement(const Colour& colour) {
@ -725,6 +751,14 @@ class DemoCallback : public Callback {
PrintOptionalElement("LuminanceMin", mastering_metadata.luminance_min);
}
void PrintMasterElement(const Projection& projection) {
PrintMandatoryElement("ProjectionType", projection.type);
PrintOptionalElement("ProjectionPrivate", projection.projection_private);
PrintMandatoryElement("ProjectionPoseYaw", projection.pose_yaw);
PrintMandatoryElement("ProjectionPosePitch", projection.pose_pitch);
PrintMandatoryElement("ProjectionPoseRoll", projection.pose_roll);
}
void PrintMasterElement(const Audio& audio) {
PrintMandatoryElement("SamplingFrequency", audio.sampling_frequency);
PrintOptionalElement("OutputSamplingFrequency", audio.output_frequency);

View File

@ -883,6 +883,66 @@ struct Colour {
}
};
/**
A parsed \WebMID{ProjectionType} element.
*/
enum class ProjectionType : std::uint64_t {
/**
Rectangular.
*/
kRectangular = 0,
/**
Equirectangular.
*/
kEquirectangular = 1,
/**
Cube map.
*/
kCubeMap = 2,
};
/**
A parsed \WebMID{Projection} element.
*/
struct Projection {
/**
A parsed \WebMID{ProjectionType} element.
*/
Element<ProjectionType> type;
/**
A parsed \WebMID{ProjectionPrivate} element.
*/
Element<std::vector<std::uint8_t>> projection_private;
/**
A parsed \WebMID{ProjectionPoseYaw} element.
*/
Element<double> pose_yaw;
/**
A parsed \WebMID{ProjectionPosePitch} element.
*/
Element<double> pose_pitch;
/**
A parsed \WebMID{ProjectionPoseRoll} element.
*/
Element<double> pose_roll;
/**
Returns true if every member within the two objects are equal.
*/
bool operator==(const Projection& other) const {
return type == other.type &&
projection_private == other.projection_private &&
pose_yaw == other.pose_yaw && pose_pitch == other.pose_pitch &&
pose_roll == other.pose_roll;
}
};
/**
A parsed \WebMID{FlagInterlaced} element.
*/
@ -1113,6 +1173,11 @@ struct Video {
*/
Element<Colour> colour;
/**
A parsed \WebMID{Projection} element.
*/
Element<Projection> projection;
/**
Returns true if every member within the two objects are equal.
*/
@ -1128,7 +1193,8 @@ struct Video {
display_height == other.display_height &&
display_unit == other.display_unit &&
aspect_ratio_type == other.aspect_ratio_type &&
frame_rate == other.frame_rate && colour == other.colour;
frame_rate == other.frame_rate && colour == other.colour &&
projection == other.projection;
}
};

View File

@ -704,6 +704,48 @@ enum class Id : std::uint32_t {
*/
kLuminanceMin = 0x55DA,
/**
\WebMID{Projection} element ID.
\WebMTable{Master, 5, No, No, No, , }
*/
kProjection = 0x7670,
/**
\WebMID{ProjectionType} element ID.
\WebMTable{Unsigned integer, 6, Yes, No, No, , 0}
*/
kProjectionType = 0x7671,
/**
\WebMID{ProjectionPrivate} element ID.
\WebMTable{Binary, 6, No, No, No, , }
*/
kProjectionPrivate = 0x7672,
/**
\WebMID{ProjectionPoseYaw} element ID.
\WebMTable{Float, 6, Yes, No, No, , 0}
*/
kProjectionPoseYaw = 0x7673,
/**
\WebMID{ProjectionPosePitch} element ID.
\WebMTable{Float, 6, Yes, No, No, , 0}
*/
kProjectionPosePitch = 0x7674,
/**
\WebMID{ProjectionPoseRoll} element ID.
\WebMTable{Float, 6, Yes, No, No, , 0}
*/
kProjectionPoseRoll = 0x7675,
/**
\MatroskaID{Audio} element ID.

View File

@ -0,0 +1,40 @@
// Copyright (c) 2016 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#ifndef SRC_PROJECTION_PARSER_H_
#define SRC_PROJECTION_PARSER_H_
#include "src/byte_parser.h"
#include "src/float_parser.h"
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "webm/dom_types.h"
#include "webm/id.h"
namespace webm {
// Spec reference:
// https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md#projection-master-element
class ProjectionParser : public MasterValueParser<Projection> {
public:
ProjectionParser()
: MasterValueParser(
MakeChild<IntParser<ProjectionType>>(Id::kProjectionType,
&Projection::type),
MakeChild<BinaryParser>(Id::kProjectionPrivate,
&Projection::projection_private),
MakeChild<FloatParser>(Id::kProjectionPoseYaw,
&Projection::pose_yaw),
MakeChild<FloatParser>(Id::kProjectionPosePitch,
&Projection::pose_pitch),
MakeChild<FloatParser>(Id::kProjectionPoseRoll,
&Projection::pose_roll)) {}
};
} // namespace webm
#endif // SRC_PROJECTION_PARSER_H_

View File

@ -16,6 +16,7 @@
#include "src/float_parser.h"
#include "src/int_parser.h"
#include "src/master_value_parser.h"
#include "src/projection_parser.h"
#include "webm/callback.h"
#include "webm/dom_types.h"
#include "webm/id.h"
@ -58,7 +59,8 @@ class VideoParser : public MasterValueParser<Video> {
MakeChild<IntParser<AspectRatioType>>(Id::kAspectRatioType,
&Video::aspect_ratio_type),
MakeChild<FloatParser>(Id::kFrameRate, &Video::frame_rate),
MakeChild<ColourParser>(Id::kColour, &Video::colour)) {}
MakeChild<ColourParser>(Id::kColour, &Video::colour),
MakeChild<ProjectionParser>(Id::kProjection, &Video::projection)) {}
Status Init(const ElementMetadata& metadata,
std::uint64_t max_size) override {

View File

@ -0,0 +1,129 @@
// Copyright (c) 2016 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#include "src/projection_parser.h"
#include "gtest/gtest.h"
#include "test_utils/element_parser_test.h"
#include "webm/id.h"
using webm::ElementParserTest;
using webm::Id;
using webm::Projection;
using webm::ProjectionType;
using webm::ProjectionParser;
namespace {
class ProjectionParserTest
: public ElementParserTest<ProjectionParser, Id::kProjection> {};
TEST_F(ProjectionParserTest, DefaultParse) {
ParseAndVerify();
const Projection projection = parser_.value();
EXPECT_FALSE(projection.type.is_present());
EXPECT_EQ(ProjectionType::kRectangular, projection.type.value());
EXPECT_FALSE(projection.projection_private.is_present());
EXPECT_EQ(std::vector<std::uint8_t>{}, projection.projection_private.value());
EXPECT_FALSE(projection.pose_yaw.is_present());
EXPECT_EQ(0.0, projection.pose_yaw.value());
EXPECT_FALSE(projection.pose_pitch.is_present());
EXPECT_EQ(0.0, projection.pose_pitch.value());
EXPECT_FALSE(projection.pose_roll.is_present());
EXPECT_EQ(0.0, projection.pose_roll.value());
}
TEST_F(ProjectionParserTest, DefaultValues) {
SetReaderData({
0x76, 0x71, // ID = 0x7671 (ProjectionType).
0x80, // Size = 0.
0x76, 0x72, // ID = 0x7672 (ProjectionPrivate).
0x80, // Size = 0.
0x76, 0x73, // ID = 0x7673 (ProjectionPoseYaw).
0x80, // Size = 0.
0x76, 0x74, // ID = 0x7674 (ProjectionPosePitch).
0x80, // Size = 0.
0x76, 0x75, // ID = 0x7675 (ProjectionPoseRoll).
0x80, // Size = 0.
});
ParseAndVerify();
const Projection projection = parser_.value();
EXPECT_TRUE(projection.type.is_present());
EXPECT_EQ(ProjectionType::kRectangular, projection.type.value());
EXPECT_TRUE(projection.projection_private.is_present());
EXPECT_EQ(std::vector<std::uint8_t>{}, projection.projection_private.value());
EXPECT_TRUE(projection.pose_yaw.is_present());
EXPECT_EQ(0.0, projection.pose_yaw.value());
EXPECT_TRUE(projection.pose_pitch.is_present());
EXPECT_EQ(0.0, projection.pose_pitch.value());
EXPECT_TRUE(projection.pose_roll.is_present());
EXPECT_EQ(0.0, projection.pose_roll.value());
}
TEST_F(ProjectionParserTest, CustomValues) {
SetReaderData({
0x76, 0x71, // ID = 0x7671 (ProjectionType).
0x10, 0x00, 0x00, 0x01, // Size = 1.
0x01, // Body (value = equirectangular).
0x76, 0x72, // ID = 0x7672 (ProjectionPrivate).
0x10, 0x00, 0x00, 0x01, // Size = 1.
0x00, // Body.
0x76, 0x73, // ID = 0x7673 (ProjectionPoseYaw).
0x10, 0x00, 0x00, 0x04, // Size = 4.
0x3f, 0x80, 0x00, 0x00, // Body (value = 1.0).
0x76, 0x74, // ID = 0x7674 (ProjectionPosePitch).
0x10, 0x00, 0x00, 0x04, // Size = 4.
0x40, 0x00, 0x00, 0x00, // Body (value = 2.0).
0x76, 0x75, // ID = 0x7675 (ProjectionPoseRoll).
0x10, 0x00, 0x00, 0x04, // Size = 4.
0x40, 0x80, 0x00, 0x00, // Body (value = 4.0).
});
ParseAndVerify();
const Projection projection = parser_.value();
EXPECT_TRUE(projection.type.is_present());
EXPECT_EQ(ProjectionType::kEquirectangular, projection.type.value());
EXPECT_TRUE(projection.projection_private.is_present());
EXPECT_EQ(std::vector<std::uint8_t>{0x00},
projection.projection_private.value());
EXPECT_TRUE(projection.pose_yaw.is_present());
EXPECT_EQ(1.0, projection.pose_yaw.value());
EXPECT_TRUE(projection.pose_pitch.is_present());
EXPECT_EQ(2.0, projection.pose_pitch.value());
EXPECT_TRUE(projection.pose_roll.is_present());
EXPECT_EQ(4.0, projection.pose_roll.value());
}
} // namespace

View File

@ -18,6 +18,8 @@ using webm::DisplayUnit;
using webm::ElementParserTest;
using webm::FlagInterlaced;
using webm::Id;
using webm::Projection;
using webm::ProjectionType;
using webm::StereoMode;
using webm::Video;
using webm::VideoParser;
@ -75,6 +77,9 @@ TEST_F(VideoParserTest, DefaultParse) {
EXPECT_FALSE(video.colour.is_present());
EXPECT_EQ(Colour{}, video.colour.value());
EXPECT_FALSE(video.projection.is_present());
EXPECT_EQ(Projection{}, video.projection.value());
}
TEST_F(VideoParserTest, DefaultValues) {
@ -123,6 +128,9 @@ TEST_F(VideoParserTest, DefaultValues) {
0x55, 0xB0, // ID = 0x55B0 (Colour).
0x20, 0x00, 0x00, // Size = 0.
0x76, 0x70, // ID = 0x7670 (Projection).
0x20, 0x00, 0x00, // Size = 0.
});
ParseAndVerify();
@ -173,6 +181,9 @@ TEST_F(VideoParserTest, DefaultValues) {
EXPECT_TRUE(video.colour.is_present());
EXPECT_EQ(Colour{}, video.colour.value());
EXPECT_TRUE(video.projection.is_present());
EXPECT_EQ(Projection{}, video.projection.value());
}
TEST_F(VideoParserTest, CustomValues) {
@ -239,6 +250,13 @@ TEST_F(VideoParserTest, CustomValues) {
0x55, 0xB2, // ID = 0x55B2 (BitsPerChannel).
0x10, 0x00, 0x00, 0x01, // Size = 1.
0x01, // Body (value = 1).
0x76, 0x70, // ID = 0x7670 (Projection).
0x10, 0x00, 0x00, 0x07, // Size = 7.
0x76, 0x71, // ID = 0x7671 (ProjectionType).
0x10, 0x00, 0x00, 0x01, // Size = 1.
0x02, // Body (value = cube map).
});
ParseAndVerify();
@ -291,6 +309,10 @@ TEST_F(VideoParserTest, CustomValues) {
EXPECT_TRUE(video.colour.value().bits_per_channel.is_present());
EXPECT_EQ(static_cast<std::uint64_t>(1),
video.colour.value().bits_per_channel.value());
EXPECT_TRUE(video.projection.is_present());
EXPECT_TRUE(video.projection.value().type.is_present());
EXPECT_EQ(ProjectionType::kCubeMap, video.projection.value().type.value());
}
TEST_F(VideoParserTest, AbsentDisplaySize) {