Use pixel_{height,width} to set AdaptationSet@par
- Pass pixel_height and pixel_width from VideoStreamInfo to MediaInfo. - par can only be set if all the Representations have the same picture aspect ratio. That is the ratio of sar_x*width:sar_y*height should all be the same. - If there is a Representation that does not have the sar attribute set, par is also not set. Change-Id: Id34c95e4a99da9ce028a9f35737cfe5bca9e5697
This commit is contained in:
parent
ec21b04fab
commit
21e43966db
|
@ -86,6 +86,12 @@ void AddVideoInfo(const VideoStreamInfo* video_stream_info,
|
||||||
video_info->set_height(video_stream_info->height());
|
video_info->set_height(video_stream_info->height());
|
||||||
video_info->set_time_scale(video_stream_info->time_scale());
|
video_info->set_time_scale(video_stream_info->time_scale());
|
||||||
|
|
||||||
|
if (video_stream_info->pixel_width() > 0)
|
||||||
|
video_info->set_pixel_width(video_stream_info->pixel_width());
|
||||||
|
|
||||||
|
if (video_stream_info->pixel_height() > 0)
|
||||||
|
video_info->set_pixel_height(video_stream_info->pixel_height());
|
||||||
|
|
||||||
const std::vector<uint8_t>& extra_data = video_stream_info->extra_data();
|
const std::vector<uint8_t>& extra_data = video_stream_info->extra_data();
|
||||||
if (!extra_data.empty()) {
|
if (!extra_data.empty()) {
|
||||||
video_info->set_decoder_config(&extra_data[0], extra_data.size());
|
video_info->set_decoder_config(&extra_data[0], extra_data.size());
|
||||||
|
|
|
@ -35,6 +35,8 @@ struct VideoStreamInfoParameters {
|
||||||
std::string language;
|
std::string language;
|
||||||
uint16_t width;
|
uint16_t width;
|
||||||
uint16_t height;
|
uint16_t height;
|
||||||
|
uint32_t pixel_width;
|
||||||
|
uint32_t pixel_height;
|
||||||
uint8_t nalu_length_size;
|
uint8_t nalu_length_size;
|
||||||
std::vector<uint8_t> extra_data;
|
std::vector<uint8_t> extra_data;
|
||||||
bool is_encrypted;
|
bool is_encrypted;
|
||||||
|
@ -63,10 +65,8 @@ scoped_refptr<StreamInfo> CreateVideoStreamInfo(
|
||||||
param.language,
|
param.language,
|
||||||
param.width,
|
param.width,
|
||||||
param.height,
|
param.height,
|
||||||
// TODO(rkuroiwa): Once MedianInfo proto change that
|
param.pixel_width,
|
||||||
// adds pizel_{width,height} lands, add tests.
|
param.pixel_height,
|
||||||
0, // No pixel width.
|
|
||||||
0, // No pixel height.
|
|
||||||
0, // trick_play_rate
|
0, // trick_play_rate
|
||||||
param.nalu_length_size,
|
param.nalu_length_size,
|
||||||
vector_as_array(¶m.extra_data),
|
vector_as_array(¶m.extra_data),
|
||||||
|
@ -85,16 +85,18 @@ VideoStreamInfoParameters GetDefaultVideoStreamInfoParams() {
|
||||||
const char* kLanuageUndefined = "und";
|
const char* kLanuageUndefined = "und";
|
||||||
const uint16_t kWidth = 720;
|
const uint16_t kWidth = 720;
|
||||||
const uint16_t kHeight = 480;
|
const uint16_t kHeight = 480;
|
||||||
|
const uint32_t kPixelWidth = 1;
|
||||||
|
const uint32_t kPixelHeight = 1;
|
||||||
const uint8_t kNaluLengthSize = 1;
|
const uint8_t kNaluLengthSize = 1;
|
||||||
const std::vector<uint8_t> kExtraData;
|
const std::vector<uint8_t> kExtraData;
|
||||||
const bool kEncryptedFlag = false;
|
const bool kEncryptedFlag = false;
|
||||||
|
|
||||||
VideoStreamInfoParameters param = {
|
VideoStreamInfoParameters param = {
|
||||||
kTrackId, kTimeScale, kVideoStreamDuration, kH264Codec,
|
kTrackId, kTimeScale, kVideoStreamDuration, kH264Codec,
|
||||||
VideoStreamInfo::GetCodecString(
|
VideoStreamInfo::GetCodecString(kCodecH264, kH264Profile,
|
||||||
kCodecH264, kH264Profile, kH264CompatibleProfile, kH264Level),
|
kH264CompatibleProfile, kH264Level),
|
||||||
kLanuageUndefined, kWidth, kHeight, kNaluLengthSize, kExtraData,
|
kLanuageUndefined, kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||||
kEncryptedFlag};
|
kNaluLengthSize, kExtraData, kEncryptedFlag};
|
||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,10 +226,12 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, UnencryptedStream_Normal) {
|
||||||
const char kExpectedProtobufOutput[] =
|
const char kExpectedProtobufOutput[] =
|
||||||
"bandwidth: 7620\n"
|
"bandwidth: 7620\n"
|
||||||
"video_info {\n"
|
"video_info {\n"
|
||||||
" codec: \"avc1.010101\"\n"
|
" codec: 'avc1.010101'\n"
|
||||||
" width: 720\n"
|
" width: 720\n"
|
||||||
" height: 480\n"
|
" height: 480\n"
|
||||||
" time_scale: 10\n"
|
" time_scale: 10\n"
|
||||||
|
" pixel_width: 1\n"
|
||||||
|
" pixel_height: 1\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"init_range {\n"
|
"init_range {\n"
|
||||||
" begin: 0\n"
|
" begin: 0\n"
|
||||||
|
@ -239,7 +243,7 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, UnencryptedStream_Normal) {
|
||||||
"}\n"
|
"}\n"
|
||||||
"reference_time_scale: 1000\n"
|
"reference_time_scale: 1000\n"
|
||||||
"container_type: 1\n"
|
"container_type: 1\n"
|
||||||
"media_file_name: \"test_output_file_name.mp4\"\n"
|
"media_file_name: 'test_output_file_name.mp4'\n"
|
||||||
"media_duration_seconds: 10.5\n";
|
"media_duration_seconds: 10.5\n";
|
||||||
ASSERT_NO_FATAL_FAILURE(ExpectTempFileToEqual(kExpectedProtobufOutput));
|
ASSERT_NO_FATAL_FAILURE(ExpectTempFileToEqual(kExpectedProtobufOutput));
|
||||||
}
|
}
|
||||||
|
@ -249,26 +253,26 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, EncryptedStream_Normal) {
|
||||||
|
|
||||||
scoped_refptr<StreamInfo> stream_info =
|
scoped_refptr<StreamInfo> stream_info =
|
||||||
CreateVideoStreamInfo(GetDefaultVideoStreamInfoParams());
|
CreateVideoStreamInfo(GetDefaultVideoStreamInfoParams());
|
||||||
|
|
||||||
FireOnMediaStartWithDefaultMuxerOptions(*stream_info, kEnableEncryption);
|
FireOnMediaStartWithDefaultMuxerOptions(*stream_info, kEnableEncryption);
|
||||||
|
|
||||||
OnMediaEndParameters media_end_param = GetDefaultOnMediaEndParams();
|
OnMediaEndParameters media_end_param = GetDefaultOnMediaEndParams();
|
||||||
FireOnMediaEndWithParams(media_end_param);
|
FireOnMediaEndWithParams(media_end_param);
|
||||||
|
|
||||||
const char kExpectedProtobufOutput[] =
|
const char kExpectedProtobufOutput[] =
|
||||||
"bandwidth: 7620\n"
|
"bandwidth: 7620\n"
|
||||||
"video_info {\n"
|
"video_info {\n"
|
||||||
" codec: \"avc1.010101\"\n"
|
" codec: 'avc1.010101'\n"
|
||||||
" width: 720\n"
|
" width: 720\n"
|
||||||
" height: 480\n"
|
" height: 480\n"
|
||||||
" time_scale: 10\n"
|
" time_scale: 10\n"
|
||||||
|
" pixel_width: 1\n"
|
||||||
|
" pixel_height: 1\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"content_protections {\n"
|
"content_protections {\n"
|
||||||
" scheme_id_uri: \"urn:mpeg:dash:mp4protection:2011\"\n"
|
" scheme_id_uri: 'urn:mpeg:dash:mp4protection:2011'\n"
|
||||||
" value: \"cenc\"\n"
|
" value: 'cenc'\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"content_protections {\n"
|
"content_protections {\n"
|
||||||
" scheme_id_uri: \"http://foo.com/bar\"\n"
|
" scheme_id_uri: 'http://foo.com/bar'\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"init_range {\n"
|
"init_range {\n"
|
||||||
" begin: 0\n"
|
" begin: 0\n"
|
||||||
|
@ -280,7 +284,44 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, EncryptedStream_Normal) {
|
||||||
"}\n"
|
"}\n"
|
||||||
"reference_time_scale: 1000\n"
|
"reference_time_scale: 1000\n"
|
||||||
"container_type: 1\n"
|
"container_type: 1\n"
|
||||||
"media_file_name: \"test_output_file_name.mp4\"\n"
|
"media_file_name: 'test_output_file_name.mp4'\n"
|
||||||
|
"media_duration_seconds: 10.5\n";
|
||||||
|
ASSERT_NO_FATAL_FAILURE(ExpectTempFileToEqual(kExpectedProtobufOutput));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that VideoStreamInfo with non-0 pixel_{width,height} is set in the
|
||||||
|
// generated MediaInfo.
|
||||||
|
TEST_F(VodMediaInfoDumpMuxerListenerTest, CheckPixelWidthAndHeightSet) {
|
||||||
|
VideoStreamInfoParameters params = GetDefaultVideoStreamInfoParams();
|
||||||
|
params.pixel_width = 8;
|
||||||
|
params.pixel_height = 9;
|
||||||
|
|
||||||
|
scoped_refptr<StreamInfo> stream_info = CreateVideoStreamInfo(params);
|
||||||
|
FireOnMediaStartWithDefaultMuxerOptions(*stream_info, !kEnableEncryption);
|
||||||
|
OnMediaEndParameters media_end_param = GetDefaultOnMediaEndParams();
|
||||||
|
FireOnMediaEndWithParams(media_end_param);
|
||||||
|
|
||||||
|
const char kExpectedProtobufOutput[] =
|
||||||
|
"bandwidth: 7620\n"
|
||||||
|
"video_info {\n"
|
||||||
|
" codec: 'avc1.010101'\n"
|
||||||
|
" width: 720\n"
|
||||||
|
" height: 480\n"
|
||||||
|
" time_scale: 10\n"
|
||||||
|
" pixel_width: 8\n"
|
||||||
|
" pixel_height: 9\n"
|
||||||
|
"}\n"
|
||||||
|
"init_range {\n"
|
||||||
|
" begin: 0\n"
|
||||||
|
" end: 120\n"
|
||||||
|
"}\n"
|
||||||
|
"index_range {\n"
|
||||||
|
" begin: 121\n"
|
||||||
|
" end: 221\n"
|
||||||
|
"}\n"
|
||||||
|
"reference_time_scale: 1000\n"
|
||||||
|
"container_type: 1\n"
|
||||||
|
"media_file_name: 'test_output_file_name.mp4'\n"
|
||||||
"media_duration_seconds: 10.5\n";
|
"media_duration_seconds: 10.5\n";
|
||||||
ASSERT_NO_FATAL_FAILURE(ExpectTempFileToEqual(kExpectedProtobufOutput));
|
ASSERT_NO_FATAL_FAILURE(ExpectTempFileToEqual(kExpectedProtobufOutput));
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,6 +212,65 @@ bool HasRequiredVideoFields(const MediaInfo_VideoInfo& video_info) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Euclidean algorithm.
|
||||||
|
// gcd(a,0) = a
|
||||||
|
// gcd(a,b) = gcd(b, a % b)
|
||||||
|
uint32_t GreatestCommonDivisor(uint32_t a, uint32_t b) {
|
||||||
|
while (b != 0) {
|
||||||
|
const uint32_t new_b = a % b;
|
||||||
|
a = b;
|
||||||
|
b = new_b;
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the picture aspect ratio string e.g. "16:9", "4:3".
|
||||||
|
std::string GetPictureAspectRatio(uint32_t width, uint32_t height,
|
||||||
|
uint32_t pixel_width, uint32_t pixel_height) {
|
||||||
|
const uint32_t scaled_width = pixel_width * width;
|
||||||
|
const uint32_t scaled_height = pixel_height * height;
|
||||||
|
const uint32_t gcd = GreatestCommonDivisor(scaled_width, scaled_height);
|
||||||
|
DCHECK_NE(gcd, 0u) << "GCD of width*pix_width (" << scaled_width
|
||||||
|
<< ") and height*pix_height (" << scaled_height
|
||||||
|
<< ") is 0.";
|
||||||
|
|
||||||
|
const uint32_t par_x = scaled_width / gcd;
|
||||||
|
const uint32_t par_y = scaled_height / gcd;
|
||||||
|
return base::IntToString(par_x) + ":" + base::IntToString(par_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds an entry to picture_aspect_ratio if the size of picture_aspect_ratio is
|
||||||
|
// less than 2 and video_info has both pixel width and pixel height.
|
||||||
|
void AddPictureAspectRatio(
|
||||||
|
const MediaInfo::VideoInfo& video_info,
|
||||||
|
std::set<std::string>* picture_aspect_ratio) {
|
||||||
|
// If there are more than one entries in picture_aspect_ratio, the @par
|
||||||
|
// attribute cannot be set, so skip.
|
||||||
|
if (picture_aspect_ratio->size() > 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (video_info.width() == 0 || video_info.height() == 0 ||
|
||||||
|
video_info.pixel_width() == 0 || video_info.pixel_height() == 0) {
|
||||||
|
// If there is even one Representation without a @sar attribute, @par cannot
|
||||||
|
// be calculated.
|
||||||
|
// Just populate the set with at least 2 bogus strings so that further call
|
||||||
|
// to this function will bail out immediately.
|
||||||
|
picture_aspect_ratio->insert("bogus");
|
||||||
|
picture_aspect_ratio->insert("entries");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string par = GetPictureAspectRatio(
|
||||||
|
video_info.width(), video_info.height(),
|
||||||
|
video_info.pixel_width(), video_info.pixel_height());
|
||||||
|
DVLOG(1) << "Setting par as: " << par
|
||||||
|
<< " for video with width: " << video_info.width()
|
||||||
|
<< " height: " << video_info.height()
|
||||||
|
<< " pixel_width: " << video_info.pixel_width() << " pixel_height; "
|
||||||
|
<< video_info.pixel_height();
|
||||||
|
picture_aspect_ratio->insert(par);
|
||||||
|
}
|
||||||
|
|
||||||
// Spooky static initialization/cleanup of libxml.
|
// Spooky static initialization/cleanup of libxml.
|
||||||
class LibXmlInitializer {
|
class LibXmlInitializer {
|
||||||
public:
|
public:
|
||||||
|
@ -536,6 +595,8 @@ Representation* AdaptationSet::AddRepresentation(const MediaInfo& media_info) {
|
||||||
base::IntToString(video_info.time_scale()) + "/" +
|
base::IntToString(video_info.time_scale()) + "/" +
|
||||||
base::IntToString(video_info.frame_duration());
|
base::IntToString(video_info.frame_duration());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AddPictureAspectRatio(video_info, &picture_aspect_ratio_);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (media_info.has_video_info()) {
|
if (media_info.has_video_info()) {
|
||||||
|
@ -600,6 +661,9 @@ xml::ScopedXmlPtr<xmlNode>::type AdaptationSet::GetXml() {
|
||||||
adaptation_set.SetStringAttribute("maxFrameRate",
|
adaptation_set.SetStringAttribute("maxFrameRate",
|
||||||
video_frame_rates_.rbegin()->second);
|
video_frame_rates_.rbegin()->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (picture_aspect_ratio_.size() == 1)
|
||||||
|
adaptation_set.SetStringAttribute("par", *picture_aspect_ratio_.begin());
|
||||||
return adaptation_set.PassScopedPtr();
|
return adaptation_set.PassScopedPtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -230,6 +230,16 @@ class AdaptationSet {
|
||||||
// Determined by examining the MediaInfo passed to AddRepresentation().
|
// Determined by examining the MediaInfo passed to AddRepresentation().
|
||||||
std::string content_type_;
|
std::string content_type_;
|
||||||
|
|
||||||
|
// This does not have to be a set, it could be a list or vector because all we
|
||||||
|
// really care is whether there is more than one entry.
|
||||||
|
// Contains one entry if all the Representations have the same picture aspect
|
||||||
|
// ratio (@par attribute for AdaptationSet).
|
||||||
|
// There will be more than one entry if there are multiple picture aspect
|
||||||
|
// ratios.
|
||||||
|
// The @par attribute should only be set if there is exactly one entry
|
||||||
|
// in this set.
|
||||||
|
std::set<std::string> picture_aspect_ratio_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(AdaptationSet);
|
DISALLOW_COPY_AND_ASSIGN(AdaptationSet);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -209,7 +209,8 @@ class SegmentTemplateTest : public DynamicMpdBuilderTest {
|
||||||
"type=\"dynamic\" profiles=\"urn:mpeg:dash:profile:isoff-live:2011\">\n"
|
"type=\"dynamic\" profiles=\"urn:mpeg:dash:profile:isoff-live:2011\">\n"
|
||||||
" <Period start=\"PT0S\">\n"
|
" <Period start=\"PT0S\">\n"
|
||||||
" <AdaptationSet id=\"0\" width=\"720\" height=\"480\""
|
" <AdaptationSet id=\"0\" width=\"720\" height=\"480\""
|
||||||
" frameRate=\"10/5\" contentType=\"video\">\n"
|
" frameRate=\"10/5\" contentType=\"video\""
|
||||||
|
" par=\"3:2\">\n"
|
||||||
" <Representation id=\"0\" bandwidth=\"%" PRIu64 "\" "
|
" <Representation id=\"0\" bandwidth=\"%" PRIu64 "\" "
|
||||||
"codecs=\"avc1.010101\" mimeType=\"video/mp4\" width=\"720\" "
|
"codecs=\"avc1.010101\" mimeType=\"video/mp4\" width=\"720\" "
|
||||||
"height=\"480\" frameRate=\"10/5\" sar=\"1:1\">\n"
|
"height=\"480\" frameRate=\"10/5\" sar=\"1:1\">\n"
|
||||||
|
@ -292,7 +293,8 @@ class TimeShiftBufferDepthTest : public SegmentTemplateTest {
|
||||||
"timeShiftBufferDepth=\"PT%dS\">\n"
|
"timeShiftBufferDepth=\"PT%dS\">\n"
|
||||||
" <Period start=\"PT0S\">\n"
|
" <Period start=\"PT0S\">\n"
|
||||||
" <AdaptationSet id=\"0\" width=\"720\" height=\"480\""
|
" <AdaptationSet id=\"0\" width=\"720\" height=\"480\""
|
||||||
" frameRate=\"10/2\" contentType=\"video\">\n"
|
" frameRate=\"10/2\" contentType=\"video\""
|
||||||
|
" par=\"3:2\">\n"
|
||||||
" <Representation id=\"0\" bandwidth=\"%" PRIu64 "\" "
|
" <Representation id=\"0\" bandwidth=\"%" PRIu64 "\" "
|
||||||
"codecs=\"avc1.010101\" mimeType=\"video/mp4\" width=\"720\" "
|
"codecs=\"avc1.010101\" mimeType=\"video/mp4\" width=\"720\" "
|
||||||
"height=\"480\" frameRate=\"10/2\" sar=\"1:1\">\n"
|
"height=\"480\" frameRate=\"10/2\" sar=\"1:1\">\n"
|
||||||
|
@ -540,6 +542,125 @@ TEST_F(CommonMpdBuilderTest, AdapatationSetMaxFrameRate) {
|
||||||
ExpectAttributeNotSet("frameRate", adaptation_set_xml.get()));
|
ExpectAttributeNotSet("frameRate", adaptation_set_xml.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify that if the picture aspect ratio of all the Representations are the
|
||||||
|
// same, @par attribute is present.
|
||||||
|
TEST_F(CommonMpdBuilderTest, AdaptationSetParAllSame) {
|
||||||
|
const char k720pVideoInfo[] =
|
||||||
|
"video_info {\n"
|
||||||
|
" codec: 'avc1'\n"
|
||||||
|
" width: 1280\n"
|
||||||
|
" height: 720\n"
|
||||||
|
" time_scale: 3000\n"
|
||||||
|
" frame_duration: 100\n"
|
||||||
|
" pixel_width: 1\n"
|
||||||
|
" pixel_height: 1\n"
|
||||||
|
"}\n"
|
||||||
|
"container_type: 1\n";
|
||||||
|
const char k1080pVideoInfo[] =
|
||||||
|
"video_info {\n"
|
||||||
|
" codec: 'avc1'\n"
|
||||||
|
" width: 1920\n"
|
||||||
|
" height: 1080\n"
|
||||||
|
" time_scale: 3000\n"
|
||||||
|
" frame_duration: 100\n"
|
||||||
|
" pixel_width: 1\n"
|
||||||
|
" pixel_height: 1\n"
|
||||||
|
"}\n"
|
||||||
|
"container_type: 1\n";
|
||||||
|
|
||||||
|
// Note that this has non-1 pixel width and height.
|
||||||
|
// Which makes the par 16:9.
|
||||||
|
const char k360pVideoInfo[] =
|
||||||
|
"video_info {\n"
|
||||||
|
" codec: 'avc1'\n"
|
||||||
|
" width: 720\n"
|
||||||
|
" height: 360\n"
|
||||||
|
" time_scale: 3000\n"
|
||||||
|
" frame_duration: 100\n"
|
||||||
|
" pixel_width: 8\n"
|
||||||
|
" pixel_height: 9\n"
|
||||||
|
"}\n"
|
||||||
|
"container_type: 1\n";
|
||||||
|
|
||||||
|
AdaptationSet* video_adaptation_set = mpd_.AddAdaptationSet("");
|
||||||
|
ASSERT_TRUE(video_adaptation_set);
|
||||||
|
ASSERT_TRUE(video_adaptation_set->AddRepresentation(
|
||||||
|
ConvertToMediaInfo(k720pVideoInfo)));
|
||||||
|
ASSERT_TRUE(video_adaptation_set->AddRepresentation(
|
||||||
|
ConvertToMediaInfo(k1080pVideoInfo)));
|
||||||
|
ASSERT_TRUE(video_adaptation_set->AddRepresentation(
|
||||||
|
ConvertToMediaInfo(k360pVideoInfo)));
|
||||||
|
|
||||||
|
xml::ScopedXmlPtr<xmlNode>::type adaptation_set_xml(
|
||||||
|
video_adaptation_set->GetXml());
|
||||||
|
EXPECT_NO_FATAL_FAILURE(ExpectAttributeEqString("par", "16:9",
|
||||||
|
adaptation_set_xml.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that adding Representations with different par will generate
|
||||||
|
// AdaptationSet without @par.
|
||||||
|
TEST_F(CommonMpdBuilderTest, AdaptationSetParDifferent) {
|
||||||
|
const char k16by9VideoInfo[] =
|
||||||
|
"video_info {\n"
|
||||||
|
" codec: 'avc1'\n"
|
||||||
|
" width: 1280\n"
|
||||||
|
" height: 720\n"
|
||||||
|
" time_scale: 3000\n"
|
||||||
|
" frame_duration: 100\n"
|
||||||
|
" pixel_width: 1\n"
|
||||||
|
" pixel_height: 1\n"
|
||||||
|
"}\n"
|
||||||
|
"container_type: 1\n";
|
||||||
|
// Note that 720:360 is 2:1 where as 720p (above) is 16:9.
|
||||||
|
const char k2by1VideoInfo[] =
|
||||||
|
"video_info {\n"
|
||||||
|
" codec: 'avc1'\n"
|
||||||
|
" width: 720\n"
|
||||||
|
" height: 360\n"
|
||||||
|
" time_scale: 3000\n"
|
||||||
|
" frame_duration: 100\n"
|
||||||
|
" pixel_width: 1\n"
|
||||||
|
" pixel_height: 1\n"
|
||||||
|
"}\n"
|
||||||
|
"container_type: 1\n";
|
||||||
|
|
||||||
|
AdaptationSet* video_adaptation_set = mpd_.AddAdaptationSet("");
|
||||||
|
ASSERT_TRUE(video_adaptation_set);
|
||||||
|
ASSERT_TRUE(video_adaptation_set->AddRepresentation(
|
||||||
|
ConvertToMediaInfo(k16by9VideoInfo)));
|
||||||
|
ASSERT_TRUE(video_adaptation_set->AddRepresentation(
|
||||||
|
ConvertToMediaInfo(k2by1VideoInfo)));
|
||||||
|
|
||||||
|
xml::ScopedXmlPtr<xmlNode>::type adaptation_set_xml(
|
||||||
|
video_adaptation_set->GetXml());
|
||||||
|
EXPECT_NO_FATAL_FAILURE(
|
||||||
|
ExpectAttributeNotSet("par", adaptation_set_xml.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that adding Representation without pixel_width and pixel_height will
|
||||||
|
// not set @par.
|
||||||
|
TEST_F(CommonMpdBuilderTest, AdaptationSetParUnknown) {
|
||||||
|
const char kUknownPixelWidthAndHeight[] =
|
||||||
|
"video_info {\n"
|
||||||
|
" codec: 'avc1'\n"
|
||||||
|
" width: 1280\n"
|
||||||
|
" height: 720\n"
|
||||||
|
" time_scale: 3000\n"
|
||||||
|
" frame_duration: 100\n"
|
||||||
|
"}\n"
|
||||||
|
"container_type: 1\n";
|
||||||
|
|
||||||
|
AdaptationSet* video_adaptation_set = mpd_.AddAdaptationSet("");
|
||||||
|
ASSERT_TRUE(video_adaptation_set);
|
||||||
|
ASSERT_TRUE(video_adaptation_set->AddRepresentation(
|
||||||
|
ConvertToMediaInfo(kUknownPixelWidthAndHeight)));
|
||||||
|
|
||||||
|
xml::ScopedXmlPtr<xmlNode>::type adaptation_set_xml(
|
||||||
|
video_adaptation_set->GetXml());
|
||||||
|
EXPECT_NO_FATAL_FAILURE(
|
||||||
|
ExpectAttributeNotSet("par", adaptation_set_xml.get()));
|
||||||
|
}
|
||||||
|
|
||||||
// Catch the case where it ends up wrong if integer division is used to check
|
// Catch the case where it ends up wrong if integer division is used to check
|
||||||
// the frame rate.
|
// the frame rate.
|
||||||
// IOW, A/B != C/D but when using integer division A/B == C/D.
|
// IOW, A/B != C/D but when using integer division A/B == C/D.
|
||||||
|
|
|
@ -330,13 +330,17 @@ bool RepresentationXmlNode::AddVideoInfo(const VideoInfo& video_info) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (video_info.has_pixel_width() && video_info.has_pixel_height()) {
|
||||||
|
SetStringAttribute("sar", base::IntToString(video_info.pixel_width()) +
|
||||||
|
":" +
|
||||||
|
base::IntToString(video_info.pixel_height()));
|
||||||
|
}
|
||||||
|
|
||||||
SetIntegerAttribute("width", video_info.width());
|
SetIntegerAttribute("width", video_info.width());
|
||||||
SetIntegerAttribute("height", video_info.height());
|
SetIntegerAttribute("height", video_info.height());
|
||||||
SetStringAttribute("frameRate",
|
SetStringAttribute("frameRate",
|
||||||
base::IntToString(video_info.time_scale()) + "/" +
|
base::IntToString(video_info.time_scale()) + "/" +
|
||||||
base::IntToString(video_info.frame_duration()));
|
base::IntToString(video_info.frame_duration()));
|
||||||
SetStringAttribute("sar", base::IntToString(video_info.pixel_width()) + ":" +
|
|
||||||
base::IntToString(video_info.pixel_height()));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<MPD xmlns="urn:mpeg:DASH:schema:MPD:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT10.5S">
|
<MPD xmlns="urn:mpeg:DASH:schema:MPD:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT10.5S">
|
||||||
<Period>
|
<Period>
|
||||||
<AdaptationSet id="0" width="720" height="480" frameRate="10/1" contentType="video">
|
<AdaptationSet id="0" width="720" height="480" frameRate="10/1" contentType="video" par="3:2">
|
||||||
<Representation id="1" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" width="720" height="480" frameRate="10/1" sar="1:1">
|
<Representation id="1" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" width="720" height="480" frameRate="10/1" sar="1:1">
|
||||||
<BaseURL>test_output_file_name1.mp4</BaseURL>
|
<BaseURL>test_output_file_name1.mp4</BaseURL>
|
||||||
<SegmentBase indexRange="121-221" timescale="1000">
|
<SegmentBase indexRange="121-221" timescale="1000">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<MPD xmlns="urn:mpeg:DASH:schema:MPD:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd" availabilityStartTime="2011-12-25T12:30:00" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011">
|
<MPD xmlns="urn:mpeg:DASH:schema:MPD:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd" availabilityStartTime="2011-12-25T12:30:00" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011">
|
||||||
<Period start="PT0S">
|
<Period start="PT0S">
|
||||||
<AdaptationSet id="0" width="720" height="480" frameRate="10/5" contentType="video">
|
<AdaptationSet id="0" width="720" height="480" frameRate="10/5" contentType="video" par="3:2">
|
||||||
<Representation id="0" bandwidth="102400" codecs="avc1.010101" mimeType="video/mp4" width="720" height="480" frameRate="10/5" sar="1:1">
|
<Representation id="0" bandwidth="102400" codecs="avc1.010101" mimeType="video/mp4" width="720" height="480" frameRate="10/5" sar="1:1">
|
||||||
<SegmentTemplate timescale="1000" initialization="init.mp4" media="$Time$.mp4">
|
<SegmentTemplate timescale="1000" initialization="init.mp4" media="$Time$.mp4">
|
||||||
<SegmentTimeline>
|
<SegmentTimeline>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<MPD xmlns="urn:mpeg:DASH:schema:MPD:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT10.5S">
|
<MPD xmlns="urn:mpeg:DASH:schema:MPD:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT10.5S">
|
||||||
<Period>
|
<Period>
|
||||||
<AdaptationSet id="0" width="720" height="480" frameRate="10/1" contentType="video">
|
<AdaptationSet id="0" width="720" height="480" frameRate="10/1" contentType="video" par="3:2">
|
||||||
<Representation id="3" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" width="720" height="480" frameRate="10/1" sar="1:1">
|
<Representation id="3" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" width="720" height="480" frameRate="10/1" sar="1:1">
|
||||||
<BaseURL>test_output_file_name1.mp4</BaseURL>
|
<BaseURL>test_output_file_name1.mp4</BaseURL>
|
||||||
<SegmentBase indexRange="121-221" timescale="1000">
|
<SegmentBase indexRange="121-221" timescale="1000">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<MPD xmlns="urn:mpeg:DASH:schema:MPD:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT10.5S">
|
<MPD xmlns="urn:mpeg:DASH:schema:MPD:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT10.5S">
|
||||||
<Period>
|
<Period>
|
||||||
<AdaptationSet id="0" width="720" height="480" frameRate="10/1" contentType="video">
|
<AdaptationSet id="0" width="720" height="480" frameRate="10/1" contentType="video" par="3:2">
|
||||||
<Representation id="0" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" width="720" height="480" frameRate="10/1" sar="1:1">
|
<Representation id="0" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" width="720" height="480" frameRate="10/1" sar="1:1">
|
||||||
<BaseURL>test_output_file_name1.mp4</BaseURL>
|
<BaseURL>test_output_file_name1.mp4</BaseURL>
|
||||||
<SegmentBase indexRange="121-221" timescale="1000">
|
<SegmentBase indexRange="121-221" timescale="1000">
|
||||||
|
|
Loading…
Reference in New Issue