Generate full segment after cue point
Also added RETURN_IF_ERROR status macro. Change-Id: I04643b6252ea5623128f9a16fa744a255c91be17
This commit is contained in:
parent
8f565bf388
commit
db45e0868a
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "packager/base/logging.h"
|
||||
#include "packager/media/base/media_sample.h"
|
||||
#include "packager/status_macros.h"
|
||||
|
||||
namespace shaka {
|
||||
namespace media {
|
||||
|
@ -49,9 +50,7 @@ Status ChunkingHandler::Process(std::unique_ptr<StreamData> stream_data) {
|
|||
}
|
||||
|
||||
Status ChunkingHandler::OnFlushRequest(size_t input_stream_index) {
|
||||
Status status = EndSegmentIfStarted();
|
||||
if (!status.ok())
|
||||
return status;
|
||||
RETURN_IF_ERROR(EndSegmentIfStarted());
|
||||
return FlushDownstream(kStreamIndex);
|
||||
}
|
||||
|
||||
|
@ -65,12 +64,16 @@ Status ChunkingHandler::OnStreamInfo(std::shared_ptr<const StreamInfo> info) {
|
|||
}
|
||||
|
||||
Status ChunkingHandler::OnCueEvent(std::shared_ptr<const CueEvent> event) {
|
||||
Status status = EndSegmentIfStarted();
|
||||
if (!status.ok())
|
||||
return status;
|
||||
RETURN_IF_ERROR(EndSegmentIfStarted());
|
||||
const double event_time_in_seconds = event->time_in_seconds;
|
||||
RETURN_IF_ERROR(DispatchCueEvent(kStreamIndex, std::move(event)));
|
||||
|
||||
// Force start new segment after cue event.
|
||||
segment_start_time_ = base::nullopt;
|
||||
return DispatchCueEvent(kStreamIndex, std::move(event));
|
||||
// |cue_offset_| will be applied to sample timestamp so the segment after cue
|
||||
// point have duration ~= |segment_duration_|.
|
||||
cue_offset_ = event_time_in_seconds * time_scale_;
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
Status ChunkingHandler::OnMediaSample(
|
||||
|
@ -83,15 +86,15 @@ Status ChunkingHandler::OnMediaSample(
|
|||
const bool can_start_new_segment =
|
||||
sample->is_key_frame() || !chunking_params_.segment_sap_aligned;
|
||||
if (can_start_new_segment) {
|
||||
const int64_t segment_index = timestamp / segment_duration_;
|
||||
const int64_t segment_index =
|
||||
timestamp < cue_offset_ ? 0
|
||||
: (timestamp - cue_offset_) / segment_duration_;
|
||||
if (!segment_start_time_ || segment_index != current_segment_index_) {
|
||||
current_segment_index_ = segment_index;
|
||||
// Reset subsegment index.
|
||||
current_subsegment_index_ = 0;
|
||||
|
||||
Status status = EndSegmentIfStarted();
|
||||
if (!status.ok())
|
||||
return status;
|
||||
RETURN_IF_ERROR(EndSegmentIfStarted());
|
||||
segment_start_time_ = timestamp;
|
||||
subsegment_start_time_ = timestamp;
|
||||
started_new_segment = true;
|
||||
|
@ -106,9 +109,7 @@ Status ChunkingHandler::OnMediaSample(
|
|||
if (subsegment_index != current_subsegment_index_) {
|
||||
current_subsegment_index_ = subsegment_index;
|
||||
|
||||
Status status = EndSubsegmentIfStarted();
|
||||
if (!status.ok())
|
||||
return status;
|
||||
RETURN_IF_ERROR(EndSubsegmentIfStarted());
|
||||
subsegment_start_time_ = timestamp;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,6 +83,10 @@ class ChunkingHandler : public MediaHandler {
|
|||
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.
|
||||
int64_t cue_offset_ = 0;
|
||||
};
|
||||
|
||||
} // namespace media
|
||||
|
|
|
@ -161,6 +161,7 @@ TEST_F(ChunkingHandlerTest, CueEvent) {
|
|||
|
||||
ASSERT_OK(Process(StreamData::FromStreamInfo(
|
||||
kStreamIndex, GetVideoStreamInfo(kTimeScale1))));
|
||||
ClearOutputStreamDataVector();
|
||||
|
||||
const int64_t kVideoStartTimestamp = 12345;
|
||||
const double kCueTimeInSeconds =
|
||||
|
@ -169,7 +170,7 @@ TEST_F(ChunkingHandlerTest, CueEvent) {
|
|||
auto cue_event = std::make_shared<CueEvent>();
|
||||
cue_event->time_in_seconds = kCueTimeInSeconds;
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
const bool is_key_frame = true;
|
||||
ASSERT_OK(Process(StreamData::FromMediaSample(
|
||||
kStreamIndex, GetMediaSample(kVideoStartTimestamp + i * kDuration,
|
||||
|
@ -182,7 +183,6 @@ TEST_F(ChunkingHandlerTest, CueEvent) {
|
|||
EXPECT_THAT(
|
||||
GetOutputStreamDataVector(),
|
||||
ElementsAre(
|
||||
IsStreamInfo(kStreamIndex, kTimeScale1, !kEncrypted),
|
||||
IsMediaSample(kStreamIndex, kVideoStartTimestamp, kDuration,
|
||||
!kEncrypted),
|
||||
// A new segment is created due to the existance of Cue.
|
||||
|
@ -192,6 +192,16 @@ TEST_F(ChunkingHandlerTest, CueEvent) {
|
|||
IsMediaSample(kStreamIndex, kVideoStartTimestamp + kDuration * 1,
|
||||
kDuration, !kEncrypted),
|
||||
IsMediaSample(kStreamIndex, kVideoStartTimestamp + kDuration * 2,
|
||||
kDuration, !kEncrypted),
|
||||
IsSegmentInfo(kStreamIndex, kVideoStartTimestamp + kDuration,
|
||||
kDuration * 2, kIsSubsegment, !kEncrypted),
|
||||
IsMediaSample(kStreamIndex, kVideoStartTimestamp + kDuration * 3,
|
||||
kDuration, !kEncrypted),
|
||||
IsMediaSample(kStreamIndex, kVideoStartTimestamp + kDuration * 4,
|
||||
kDuration, !kEncrypted),
|
||||
IsSegmentInfo(kStreamIndex, kVideoStartTimestamp + kDuration,
|
||||
kDuration * 4, !kIsSubsegment, !kEncrypted),
|
||||
IsMediaSample(kStreamIndex, kVideoStartTimestamp + kDuration * 5,
|
||||
kDuration, !kEncrypted)));
|
||||
}
|
||||
|
||||
|
|
|
@ -156,6 +156,7 @@
|
|||
'sources': [
|
||||
'status.cc',
|
||||
'status.h',
|
||||
'status_macros.h',
|
||||
],
|
||||
'dependencies': [
|
||||
'base/base.gyp:base',
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2018 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#ifndef PACKAGER_STATUS_MACROS_H_
|
||||
#define PACKAGER_STATUS_MACROS_H_
|
||||
|
||||
#include "packager/status.h"
|
||||
|
||||
// Evaluates an expression that produces a `Status`. If the status is not
|
||||
// ok, returns it from the current function.
|
||||
#define RETURN_IF_ERROR(expr) \
|
||||
do { \
|
||||
/* Using _status below to avoid capture problems if expr is "status". */ \
|
||||
shaka::Status _status = (expr); \
|
||||
if (!_status.ok()) \
|
||||
return _status; \
|
||||
} while (0)
|
||||
|
||||
// TODO(kqyang): Support build Status and update Status message through "<<".
|
||||
|
||||
#endif // PACKAGER_STATUS_MACROS_H_
|
Loading…
Reference in New Issue