Use PTS instead of DTS in ChunkingHandler

DTS was used in ChunkingHandler. As a result, SegmentInfo contained
timestamp in DTS. MP4Muxer has a logic to change SegmentInfo to use
PTS but not in other muxers.

Benefits of using PTS in ChunkingHandler:

- De-dup the redundant logic in MP4Muxer
- Ensure consistent behavior in different output containers
- Consistent with other timestamps, e.g. Ad Cue timestamps

Issue #413

Change-Id: Ib671badf144e0c0866d60f4ff0ac0cbbdd33817e
This commit is contained in:
KongQun Yang 2018-03-20 19:13:22 -07:00
parent 5f072e3b08
commit 571ee24f3e
32 changed files with 61 additions and 45 deletions

View File

@ -10,7 +10,7 @@ bear-640x360-video-1.ts
#EXTINF:1.001,
#EXT-X-BYTERANGE:18236@376
bear-640x360-video-2.ts
#EXTINF:0.667,
#EXTINF:0.734,
#EXT-X-BYTERANGE:19928@376
bear-640x360-video-3.ts
#EXT-X-ENDLIST

View File

@ -6,4 +6,4 @@
#EXT-X-STREAM-INF:BANDWIDTH=1217520,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group"
bear-640x360-video.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=238898,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-video-iframe.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=217180,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-video-iframe.m3u8"

View File

@ -10,7 +10,7 @@ bear-640x360-video-1.ts
#EXTINF:1.001,
#EXT-X-BYTERANGE:18236@376
bear-640x360-video-2.ts
#EXTINF:0.667,
#EXTINF:0.734,
#EXT-X-BYTERANGE:19928@376
bear-640x360-video-3.ts
#EXT-X-ENDLIST

View File

@ -6,4 +6,4 @@
#EXT-X-STREAM-INF:BANDWIDTH=1217520,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group"
bear-640x360-video.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=238898,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-video-iframe.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=217180,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-video-iframe.m3u8"

View File

@ -6,8 +6,8 @@
<Representation id="0" bandwidth="1023201" codecs="avc1.64001e" mimeType="video/MP2T" sar="1:1" frameRate="90000/0">
<SegmentTemplate timescale="90000" media="bear-640x360-video-$Number$.ts" startNumber="1">
<SegmentTimeline>
<S t="0" d="90090" r="1"/>
<S t="180180" d="66066"/>
<S t="6006" d="90090" r="1"/>
<S t="186186" d="66066"/>
</SegmentTimeline>
</SegmentTemplate>
</Representation>

View File

@ -12,7 +12,7 @@ bear-640x360-ac3-video-1.ts
#EXTINF:1.001,
#EXT-X-BYTERANGE:18236@376
bear-640x360-ac3-video-2.ts
#EXTINF:0.667,
#EXTINF:0.734,
#EXT-X-BYTERANGE:19928@376
bear-640x360-ac3-video-3.ts
#EXT-X-ENDLIST

View File

@ -6,4 +6,4 @@
#EXT-X-STREAM-INF:BANDWIDTH=1242863,CODECS="avc1.64001e,ac-3",RESOLUTION=640x360,AUDIO="default-audio-group"
bear-640x360-ac3-video.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=238898,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-ac3-video-iframe.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=217180,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-ac3-video-iframe.m3u8"

View File

@ -10,7 +10,7 @@ bear-640x360-ac3-video-1.ts
#EXTINF:1.001,
#EXT-X-BYTERANGE:18236@376
bear-640x360-ac3-video-2.ts
#EXTINF:0.667,
#EXTINF:0.734,
#EXT-X-BYTERANGE:19928@376
bear-640x360-ac3-video-3.ts
#EXT-X-ENDLIST

View File

@ -6,4 +6,4 @@
#EXT-X-STREAM-INF:BANDWIDTH=1242863,CODECS="avc1.64001e,ac-3",RESOLUTION=640x360,AUDIO="default-audio-group"
bear-640x360-ac3-video.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=238898,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-ac3-video-iframe.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=217180,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-ac3-video-iframe.m3u8"

View File

@ -12,7 +12,7 @@ bear-640x360-video-1.ts
#EXTINF:1.001,
#EXT-X-BYTERANGE:18236@376
bear-640x360-video-2.ts
#EXTINF:0.667,
#EXTINF:0.734,
#EXT-X-BYTERANGE:19928@376
bear-640x360-video-3.ts
#EXT-X-ENDLIST

View File

@ -6,4 +6,4 @@
#EXT-X-STREAM-INF:BANDWIDTH=1154999,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group"
bear-640x360-video.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=238898,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-video-iframe.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=217180,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-video-iframe.m3u8"

View File

@ -12,7 +12,7 @@ bear-640x360-ac3-video-1.ts
#EXTINF:1.001,
#EXT-X-BYTERANGE:18236@376
bear-640x360-ac3-video-2.ts
#EXTINF:0.667,
#EXTINF:0.734,
#EXT-X-BYTERANGE:19928@376
bear-640x360-ac3-video-3.ts
#EXT-X-ENDLIST

View File

@ -6,4 +6,4 @@
#EXT-X-STREAM-INF:BANDWIDTH=1216578,CODECS="avc1.64001e,ac-3",RESOLUTION=640x360,AUDIO="default-audio-group"
bear-640x360-ac3-video.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=238898,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-ac3-video-iframe.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=217180,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-ac3-video-iframe.m3u8"

View File

@ -10,6 +10,6 @@ bear-640x360-video-1.ts
#EXTINF:1.001,
#EXT-X-BYTERANGE:18236@376
bear-640x360-video-2.ts
#EXTINF:0.667,
#EXTINF:0.734,
#EXT-X-BYTERANGE:19928@376
bear-640x360-video-3.ts

View File

@ -6,4 +6,4 @@
#EXT-X-STREAM-INF:BANDWIDTH=1217520,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group"
bear-640x360-video.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=238898,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-video-iframe.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=217180,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-video-iframe.m3u8"

View File

@ -10,6 +10,6 @@
#EXT-X-BYTERANGE:18236@376
bear-640x360-video-2.ts
#EXT-X-KEY:METHOD=SAMPLE-AES,URI="data:text/plain;base64,MzQ1Njc4OTAxMjM0NTYxMg==",IV=0x3334353637383930,KEYFORMAT="identity"
#EXTINF:0.667,
#EXTINF:0.734,
#EXT-X-BYTERANGE:19928@376
bear-640x360-video-3.ts

View File

@ -6,4 +6,4 @@
#EXT-X-STREAM-INF:BANDWIDTH=1217520,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group"
bear-640x360-video.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=238898,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-video-iframe.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=217180,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-video-iframe.m3u8"

View File

@ -7,6 +7,6 @@
#EXTINF:1.001,
#EXT-X-BYTERANGE:18236@376
bear-640x360-video-2.ts
#EXTINF:0.667,
#EXTINF:0.734,
#EXT-X-BYTERANGE:19928@376
bear-640x360-video-3.ts

View File

@ -6,4 +6,4 @@
#EXT-X-STREAM-INF:BANDWIDTH=1217520,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group"
bear-640x360-video.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=238898,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-video-iframe.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=217180,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-video-iframe.m3u8"

View File

@ -12,7 +12,7 @@ bear-640x360-video-1.ts
#EXTINF:1.001,
#EXT-X-BYTERANGE:18236@376
bear-640x360-video-2.ts
#EXTINF:0.667,
#EXTINF:0.734,
#EXT-X-BYTERANGE:19928@376
bear-640x360-video-3.ts
#EXT-X-ENDLIST

View File

@ -6,4 +6,4 @@
#EXT-X-STREAM-INF:BANDWIDTH=1217520,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group"
bear-640x360-video.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=238898,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-video-iframe.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=217180,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-video-iframe.m3u8"

View File

@ -4,4 +4,4 @@
#EXT-X-STREAM-INF:BANDWIDTH=1183949,CODECS="avc1.64001f",RESOLUTION=1024x436
sintel-1024x436-video.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=745984,CODECS="avc1.64001f",RESOLUTION=1024x436,URI="sintel-1024x436-video-iframe.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=447591,CODECS="avc1.64001f",RESOLUTION=1024x436,URI="sintel-1024x436-video-iframe.m3u8"

View File

@ -16,15 +16,15 @@ sintel-1024x436-video-2.ts
#EXT-X-BYTERANGE:376@376
sintel-1024x436-video-3.ts
#EXTINF:0.958,
#EXT-X-BYTERANGE:376@4700
sintel-1024x436-video-3.ts
#EXT-X-BYTERANGE:376@376
sintel-1024x436-video-4.ts
#EXTINF:0.917,
#EXT-X-BYTERANGE:5452@376
#EXT-X-BYTERANGE:5452@41924
sintel-1024x436-video-4.ts
#EXTINF:1.000,
#EXT-X-BYTERANGE:11092@376
sintel-1024x436-video-5.ts
#EXTINF:0.125,
#EXTINF:0.208,
#EXT-X-BYTERANGE:11656@376
sintel-1024x436-video-6.ts
#EXT-X-ENDLIST

View File

@ -9,9 +9,9 @@ sintel-1024x436-video-1.ts
#EXT-X-KEY:METHOD=SAMPLE-AES,URI="data:text/plain;base64,MTIzNDU2Nzg5MDEyMzQ1Ng==",IV=0x3334353637383930,KEYFORMAT="identity"
#EXTINF:1.000,
sintel-1024x436-video-2.ts
#EXTINF:1.875,
sintel-1024x436-video-3.ts
#EXTINF:0.917,
sintel-1024x436-video-3.ts
#EXTINF:1.875,
sintel-1024x436-video-4.ts
#EXTINF:1.000,
sintel-1024x436-video-5.ts

View File

@ -12,7 +12,7 @@ bear-640x360-video-1.ts
#EXTINF:1.001,
#EXT-X-BYTERANGE:18236@376
bear-640x360-video-2.ts
#EXTINF:0.667,
#EXTINF:0.734,
#EXT-X-BYTERANGE:19928@376
bear-640x360-video-3.ts
#EXT-X-ENDLIST

View File

@ -6,4 +6,4 @@
#EXT-X-STREAM-INF:BANDWIDTH=1217520,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group"
bear-640x360-video.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=238898,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-video-iframe.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=217180,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-video-iframe.m3u8"

View File

@ -12,7 +12,7 @@ bear-640x360-ec3-video-1.ts
#EXTINF:1.001,
#EXT-X-BYTERANGE:18236@376
bear-640x360-ec3-video-2.ts
#EXTINF:0.667,
#EXTINF:0.734,
#EXT-X-BYTERANGE:19928@376
bear-640x360-ec3-video-3.ts
#EXT-X-ENDLIST

View File

@ -6,4 +6,4 @@
#EXT-X-STREAM-INF:BANDWIDTH=1216655,CODECS="avc1.64001e,ec-3",RESOLUTION=640x360,AUDIO="default-audio-group"
bear-640x360-ec3-video.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=238898,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-ec3-video-iframe.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=217180,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-ec3-video-iframe.m3u8"

View File

@ -16,6 +16,16 @@ namespace shaka {
namespace media {
namespace {
const size_t kStreamIndex = 0;
bool IsNewSegmentIndex(int64_t new_index, int64_t current_index) {
return new_index != current_index &&
// Index is calculated from pts, which could decrease. We do not expect
// it to decrease by more than one segment though, which could happen
// only if there is a big overlap in the timeline, in which case, we
// will create a new segment and leave it to the player to handle it.
new_index != current_index - 1;
}
} // namespace
ChunkingHandler::ChunkingHandler(const ChunkingParams& chunking_params)
@ -80,7 +90,7 @@ Status ChunkingHandler::OnMediaSample(
std::shared_ptr<const MediaSample> sample) {
DCHECK_NE(time_scale_, 0u) << "kStreamInfo should arrive before kMediaSample";
const int64_t timestamp = sample->dts();
const int64_t timestamp = sample->pts();
bool started_new_segment = false;
const bool can_start_new_segment =
@ -89,7 +99,8 @@ Status ChunkingHandler::OnMediaSample(
const int64_t segment_index =
timestamp < cue_offset_ ? 0
: (timestamp - cue_offset_) / segment_duration_;
if (!segment_start_time_ || segment_index != current_segment_index_) {
if (!segment_start_time_ ||
IsNewSegmentIndex(segment_index, current_segment_index_)) {
current_segment_index_ = segment_index;
// Reset subsegment index.
current_subsegment_index_ = 0;
@ -97,6 +108,7 @@ Status ChunkingHandler::OnMediaSample(
RETURN_IF_ERROR(EndSegmentIfStarted());
segment_start_time_ = timestamp;
subsegment_start_time_ = timestamp;
max_segment_time_ = timestamp + sample->duration();
started_new_segment = true;
}
}
@ -106,7 +118,7 @@ Status ChunkingHandler::OnMediaSample(
if (can_start_new_subsegment) {
const int64_t subsegment_index =
(timestamp - segment_start_time_.value()) / subsegment_duration_;
if (subsegment_index != current_subsegment_index_) {
if (IsNewSegmentIndex(subsegment_index, current_subsegment_index_)) {
current_subsegment_index_ = subsegment_index;
RETURN_IF_ERROR(EndSubsegmentIfStarted());
@ -118,11 +130,17 @@ Status ChunkingHandler::OnMediaSample(
VLOG(3) << "Sample ts: " << timestamp << " "
<< " duration: " << sample->duration() << " scale: " << time_scale_
<< (segment_start_time_ ? " dispatch " : " discard ");
// Discard samples before segment start. If the segment has started,
// |segment_start_time_| won't be null.
if (!segment_start_time_)
if (!segment_start_time_) {
DCHECK(!subsegment_start_time_);
// Discard samples before segment start. If the segment has started,
// |segment_start_time_| won't be null.
return Status::OK;
last_sample_end_timestamp_ = timestamp + sample->duration();
}
segment_start_time_ = std::min(segment_start_time_.value(), timestamp);
subsegment_start_time_ = std::min(subsegment_start_time_.value(), timestamp);
max_segment_time_ =
std::max(max_segment_time_, timestamp + sample->duration());
return DispatchMediaSample(kStreamIndex, std::move(sample));
}
@ -132,8 +150,7 @@ Status ChunkingHandler::EndSegmentIfStarted() const {
auto segment_info = std::make_shared<SegmentInfo>();
segment_info->start_timestamp = segment_start_time_.value();
segment_info->duration =
last_sample_end_timestamp_ - segment_start_time_.value();
segment_info->duration = max_segment_time_ - segment_start_time_.value();
return DispatchSegmentInfo(kStreamIndex, std::move(segment_info));
}
@ -144,7 +161,7 @@ Status ChunkingHandler::EndSubsegmentIfStarted() const {
auto subsegment_info = std::make_shared<SegmentInfo>();
subsegment_info->start_timestamp = subsegment_start_time_.value();
subsegment_info->duration =
last_sample_end_timestamp_ - subsegment_start_time_.value();
max_segment_time_ - subsegment_start_time_.value();
subsegment_info->is_subsegment = true;
return DispatchSegmentInfo(kStreamIndex, std::move(subsegment_info));
}

View File

@ -80,9 +80,8 @@ class ChunkingHandler : public MediaHandler {
base::Optional<int64_t> segment_start_time_;
base::Optional<int64_t> subsegment_start_time_;
int64_t max_segment_time_ = 0;
uint32_t time_scale_ = 0;
// The end timestamp of the last dispatched sample.
int64_t last_sample_end_timestamp_ = 0;
// The offset is applied to sample timestamps so a full segment is generated
// after cue points.