Skip to content

Commit

Permalink
Changes as per comments - 1
Browse files Browse the repository at this point in the history
  • Loading branch information
sr1990 committed Apr 12, 2020
1 parent 4c92d47 commit 98ecdab
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 70 deletions.
32 changes: 29 additions & 3 deletions packager/mpd/base/representation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,9 @@ xml::scoped_xml_ptr<xmlNode> Representation::GetXml() {
}

if (HasLiveOnlyFields(media_info_) &&
!representation.AddLiveOnlyInfo(media_info_, segment_infos_,
start_number_)) {
!representation.AddLiveOnlyInfo(
media_info_, segment_infos_, start_number_,
mpd_options_.mpd_params.target_segment_duration)) {
LOG(ERROR) << "Failed to add Live info.";
return xml::scoped_xml_ptr<xmlNode>();
}
Expand Down Expand Up @@ -333,7 +334,19 @@ void Representation::AddSegmentInfo(int64_t start_time, int64_t duration) {
const int64_t adjusted_duration = AdjustDuration(duration);

if (segment_infos_.empty()) {
start_number_ = start_time / duration;
const int64_t scaled_target_duration =
mpd_options_.mpd_params.target_segment_duration *
media_info_.reference_time_scale();

if (mpd_options_.mpd_params.target_segment_duration > 0 &&
mpd_options_.mpd_params.allow_approximate_segment_timeline) {
if (adjusted_duration == scaled_target_duration) {
start_number_ = start_time / scaled_target_duration + 1;
} else {
start_number_ = start_time / scaled_target_duration;
}
stream_just_started_ = true;
}
}

if (!segment_infos_.empty()) {
Expand All @@ -352,6 +365,19 @@ void Representation::AddSegmentInfo(int64_t start_time, int64_t duration) {
if (ApproximiatelyEqual(segment_end_time_for_same_duration,
actual_segment_end_time)) {
++segment_infos_.back().repeat;
if (mpd_options_.mpd_params.allow_approximate_segment_timeline &&
mpd_options_.mpd_params.target_segment_duration > 0 &&
stream_just_started_ && segment_infos_.size() == 2) {
const SegmentInfo& first_segment = segment_infos_.front();
const SegmentInfo& last_segment = segment_infos_.back();
if (first_segment.repeat == 0 &&
first_segment.duration < last_segment.duration &&
last_segment.repeat > 0) {
segment_infos_.pop_front();
start_number_ = last_segment.start_time / last_segment.duration + 1;
}
stream_just_started_ = false;
}
} else {
segment_infos_.push_back(
{previous_segment_end_time,
Expand Down
12 changes: 7 additions & 5 deletions packager/mpd/base/representation.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@
#ifndef PACKAGER_MPD_BASE_REPRESENTATION_H_
#define PACKAGER_MPD_BASE_REPRESENTATION_H_

#include "packager/mpd/base/bandwidth_estimator.h"
#include "packager/mpd/base/media_info.pb.h"
#include "packager/mpd/base/segment_info.h"
#include "packager/mpd/base/xml/scoped_xml_ptr.h"

#include <stdint.h>

#include <list>
#include <memory>

#include "packager/mpd/base/bandwidth_estimator.h"
#include "packager/mpd/base/media_info.pb.h"
#include "packager/mpd/base/segment_info.h"
#include "packager/mpd/base/xml/scoped_xml_ptr.h"

namespace shaka {

struct ContentProtectionElement;
Expand Down Expand Up @@ -231,6 +231,8 @@ class Representation {
// Starts from 1.
uint32_t start_number_ = 1;

bool stream_just_started_ = false;

// If this is not null, then Representation is responsible for calling the
// right methods at right timings.
std::unique_ptr<RepresentationStateChangeListener> state_change_listener_;
Expand Down
8 changes: 6 additions & 2 deletions packager/mpd/base/representation_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -799,12 +799,16 @@ TEST_P(ApproximateSegmentTimelineTest,
if (allow_approximate_segment_timeline_) {
expected_s_elements = base::StringPrintf(
kSElementTemplateWithoutR, kStartTime, kScaledTargetSegmentDuration);
EXPECT_THAT(representation_->GetXml().get(),
XmlNodeEqual(SegmentTimelineTestBase::ExpectedXml(
expected_s_elements, 1235)));
} else {
expected_s_elements = base::StringPrintf(kSElementTemplateWithoutR,
kStartTime, kDurationSmaller);
EXPECT_THAT(representation_->GetXml().get(),
XmlNodeEqual(SegmentTimelineTestBase::ExpectedXml(
expected_s_elements, 1)));
}
EXPECT_THAT(representation_->GetXml().get(),
XmlNodeEqual(ExpectedXml(expected_s_elements)));
}

TEST_P(ApproximateSegmentTimelineTest, SegmentsWithSimilarDurations) {
Expand Down
42 changes: 25 additions & 17 deletions packager/mpd/base/xml/xml_node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,11 @@ std::string RangeToString(const Range& range) {
base::Uint64ToString(range.end());
}

bool ApproximiatelyEqual(int64_t time1, int64_t time2) {
const double kErrorThresholdSeconds = 0.05;

const uint32_t error_threshold =
static_cast<uint32_t>(kErrorThresholdSeconds * time1);
return std::abs(time1 - time2) <= error_threshold;
}

// Check if segments are continuous and all segments except the last one are of
// the same duration.
bool IsTimelineConstantDuration(const std::list<SegmentInfo>& segment_infos,
uint32_t start_number) {
uint32_t start_number,
const double target_duration) {
if (!FLAGS_segment_template_constant_duration)
return false;

Expand All @@ -64,15 +57,22 @@ bool IsTimelineConstantDuration(const std::list<SegmentInfo>& segment_infos,
return false;

const SegmentInfo& first_segment = segment_infos.front();
if (!ApproximiatelyEqual(first_segment.start_time,
first_segment.duration * start_number))
return false;

if (first_segment.duration < target_duration) {
if (static_cast<uint32_t>(first_segment.start_time / target_duration) !=
start_number)
return false;
} else {
if (static_cast<uint32_t>(first_segment.start_time /
first_segment.duration) != start_number - 1)
return false;
}

if (segment_infos.size() == 1)
return true;

const SegmentInfo& last_segment = segment_infos.back();
if (!(last_segment.repeat == 0 || first_segment.repeat == 0))
if (last_segment.repeat != 0)
return false;

const int64_t expected_last_segment_start_time =
Expand Down Expand Up @@ -414,7 +414,8 @@ bool RepresentationXmlNode::AddVODOnlyInfo(const MediaInfo& media_info) {
bool RepresentationXmlNode::AddLiveOnlyInfo(
const MediaInfo& media_info,
const std::list<SegmentInfo>& segment_infos,
uint32_t start_number) {
uint32_t start_number,
const double target_duration) {
XmlNode segment_template("SegmentTemplate");
if (media_info.has_reference_time_scale()) {
segment_template.SetIntegerAttribute("timescale",
Expand All @@ -440,9 +441,16 @@ bool RepresentationXmlNode::AddLiveOnlyInfo(
if (!segment_infos.empty()) {
// Don't use SegmentTimeline if all segments except the last one are of
// the same duration.
if (IsTimelineConstantDuration(segment_infos, start_number)) {
segment_template.SetIntegerAttribute("duration",
segment_infos.front().duration);
if (IsTimelineConstantDuration(
segment_infos, start_number,
target_duration * media_info.reference_time_scale())) {
if (target_duration > 0) {
segment_template.SetIntegerAttribute(
"duration", target_duration * media_info.reference_time_scale());
} else {
segment_template.SetIntegerAttribute("duration",
segment_infos.front().duration);
}
if (FLAGS_dash_add_last_segment_number_when_needed) {
uint32_t last_segment_number = start_number - 1;
for (const auto& segment_info_element : segment_infos)
Expand Down
3 changes: 2 additions & 1 deletion packager/mpd/base/xml/xml_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,8 @@ class RepresentationXmlNode : public RepresentationBaseXmlNode {
/// SegmentInfos are sorted by its start time.
bool AddLiveOnlyInfo(const MediaInfo& media_info,
const std::list<SegmentInfo>& segment_infos,
uint32_t start_number);
uint32_t start_number,
const double target_duration);

private:
// Add AudioChannelConfiguration element. Note that it is a required element
Expand Down
83 changes: 41 additions & 42 deletions packager/mpd/base/xml/xml_node_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd

#include "packager/mpd/base/xml/xml_node.h"

#include <gflags/gflags.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
Expand All @@ -14,7 +16,6 @@
#include "packager/base/logging.h"
#include "packager/base/strings/string_util.h"
#include "packager/mpd/base/segment_info.h"
#include "packager/mpd/base/xml/xml_node.h"
#include "packager/mpd/test/xml_compare.h"

DECLARE_bool(segment_template_constant_duration);
Expand Down Expand Up @@ -57,7 +58,6 @@ TEST(XmlNodeTest, MetaTestXmlElementsEqual) {
" <C />\n"
"</A>";


// This is same as kXml1 but the attributes are reordered. Note that the
// children are not reordered.
static const char kXml1AttributeReorder[] =
Expand Down Expand Up @@ -134,9 +134,8 @@ TEST(XmlNodeTest, MetaTestXmlElementsEqual) {
// But if it is run on <B> for the first XML, it will return "content1", but
// for second XML will return "c".
TEST(XmlNodeTest, MetaTestXmlEqualDifferentContent) {
ASSERT_FALSE(XmlEqual(
"<A><B>content1</B><B>content2</B></A>",
"<A><B>c</B><B>ontent1content2</B></A>"));
ASSERT_FALSE(XmlEqual("<A><B>content1</B><B>content2</B></A>",
"<A><B>c</B><B>ontent1content2</B></A>"));
}

TEST(XmlNodeTest, ExtractReferencedNamespaces) {
Expand Down Expand Up @@ -252,8 +251,8 @@ TEST_F(LiveSegmentTimelineTest, OneSegmentInfo) {
{kStartTime, kDuration, kRepeat},
};
RepresentationXmlNode representation;
ASSERT_TRUE(
representation.AddLiveOnlyInfo(media_info_, segment_infos, kStartNumber));
ASSERT_TRUE(representation.AddLiveOnlyInfo(media_info_, segment_infos,
kStartNumber, 0));

EXPECT_THAT(
representation.GetRawPtr(),
Expand All @@ -273,8 +272,8 @@ TEST_F(LiveSegmentTimelineTest, OneSegmentInfoNonZeroStartTime) {
{kNonZeroStartTime, kDuration, kRepeat},
};
RepresentationXmlNode representation;
ASSERT_TRUE(
representation.AddLiveOnlyInfo(media_info_, segment_infos, kStartNumber));
ASSERT_TRUE(representation.AddLiveOnlyInfo(media_info_, segment_infos,
kStartNumber, 0));

EXPECT_THAT(representation.GetRawPtr(),
XmlNodeEqual(
Expand All @@ -297,8 +296,8 @@ TEST_F(LiveSegmentTimelineTest, OneSegmentInfoMatchingStartTimeAndNumber) {
{kNonZeroStartTime, kDuration, kRepeat},
};
RepresentationXmlNode representation;
ASSERT_TRUE(
representation.AddLiveOnlyInfo(media_info_, segment_infos, kStartNumber));
ASSERT_TRUE(representation.AddLiveOnlyInfo(media_info_, segment_infos,
kStartNumber, 0));

EXPECT_THAT(
representation.GetRawPtr(),
Expand All @@ -324,8 +323,8 @@ TEST_F(LiveSegmentTimelineTest, AllSegmentsSameDurationExpectLastOne) {
{kStartTime2, kDuration2, kRepeat2},
};
RepresentationXmlNode representation;
ASSERT_TRUE(
representation.AddLiveOnlyInfo(media_info_, segment_infos, kStartNumber));
ASSERT_TRUE(representation.AddLiveOnlyInfo(media_info_, segment_infos,
kStartNumber, 0));

EXPECT_THAT(
representation.GetRawPtr(),
Expand All @@ -351,8 +350,8 @@ TEST_F(LiveSegmentTimelineTest, SecondSegmentInfoNonZeroRepeat) {
{kStartTime2, kDuration2, kRepeat2},
};
RepresentationXmlNode representation;
ASSERT_TRUE(
representation.AddLiveOnlyInfo(media_info_, segment_infos, kStartNumber));
ASSERT_TRUE(representation.AddLiveOnlyInfo(media_info_, segment_infos,
kStartNumber, 0));

EXPECT_THAT(representation.GetRawPtr(),
XmlNodeEqual(
Expand Down Expand Up @@ -383,8 +382,8 @@ TEST_F(LiveSegmentTimelineTest, TwoSegmentInfoWithGap) {
{kStartTime2, kDuration2, kRepeat2},
};
RepresentationXmlNode representation;
ASSERT_TRUE(
representation.AddLiveOnlyInfo(media_info_, segment_infos, kStartNumber));
ASSERT_TRUE(representation.AddLiveOnlyInfo(media_info_, segment_infos,
kStartNumber, 0));

EXPECT_THAT(representation.GetRawPtr(),
XmlNodeEqual(
Expand All @@ -398,31 +397,31 @@ TEST_F(LiveSegmentTimelineTest, TwoSegmentInfoWithGap) {
"</Representation>"));
}

TEST_F(LiveSegmentTimelineTest, LastSegmentNumberSupplementalProperty) {
const uint32_t kStartNumber = 1;
const uint64_t kStartTime = 0;
const uint64_t kDuration = 100;
const uint64_t kRepeat = 9;
std::list<SegmentInfo> segment_infos = {
{kStartTime, kDuration, kRepeat},
};
RepresentationXmlNode representation;
FLAGS_dash_add_last_segment_number_when_needed = true;
ASSERT_TRUE(
representation.AddLiveOnlyInfo(media_info_, segment_infos, kStartNumber));
EXPECT_THAT(
representation.GetRawPtr(),
XmlNodeEqual("<Representation>"
"<SupplementalProperty schemeIdUri=\"http://dashif.org/"
"guidelines/last-segment-number\" value=\"10\"/>"
" <SegmentTemplate media=\"$Number$.m4s\" "
" startNumber=\"1\" duration=\"100\"/>"
"</Representation>"));
FLAGS_dash_add_last_segment_number_when_needed = false;
}
TEST_F(LiveSegmentTimelineTest, LastSegmentNumberSupplementalProperty) {
const uint32_t kStartNumber = 1;
const uint64_t kStartTime = 0;
const uint64_t kDuration = 100;
const uint64_t kRepeat = 9;

std::list<SegmentInfo> segment_infos = {
{kStartTime, kDuration, kRepeat},
};
RepresentationXmlNode representation;
FLAGS_dash_add_last_segment_number_when_needed = true;

ASSERT_TRUE(representation.AddLiveOnlyInfo(media_info_, segment_infos,
kStartNumber, 0));

EXPECT_THAT(
representation.GetRawPtr(),
XmlNodeEqual("<Representation>"
"<SupplementalProperty schemeIdUri=\"http://dashif.org/"
"guidelines/last-segment-number\" value=\"10\"/>"
" <SegmentTemplate media=\"$Number$.m4s\" "
" startNumber=\"1\" duration=\"100\"/>"
"</Representation>"));
FLAGS_dash_add_last_segment_number_when_needed = false;
}

} // namespace xml
} // namespace shaka

0 comments on commit 98ecdab

Please sign in to comment.