Change MuxerListener::OnMediaEnd to take ranges
- Changed OnMediaEnd() to take (sub)segment ranges. - Define a structure to pass the ranges. - This requires muxers to "cache" the segment ranges but in most cases, they already do it, e.g. 'sidx' for mp4. Change-Id: I16b974c1f0f54ca658cc6dbe605efff84a3f52eb
This commit is contained in:
parent
2db1867951
commit
0dfdace280
|
@ -75,6 +75,7 @@
|
|||
'producer_consumer_queue.h',
|
||||
'protection_system_specific_info.cc',
|
||||
'protection_system_specific_info.h',
|
||||
'range.h',
|
||||
'rcheck.h',
|
||||
'request_signer.cc',
|
||||
'request_signer.h',
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2017 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
|
||||
//
|
||||
// Event handler for events fired by Muxer.
|
||||
|
||||
#ifndef PACKAGER_MEDIA_BASE_RANGE_H_
|
||||
#define PACKAGER_MEDIA_BASE_RANGE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace shaka {
|
||||
namespace media {
|
||||
|
||||
/// Structure for specifying a range.
|
||||
/// The start and end are inclusive which is equivalent to [start, end].
|
||||
struct Range {
|
||||
uint64_t start;
|
||||
uint64_t end;
|
||||
};
|
||||
|
||||
} // namespace media
|
||||
} // namespace shaka
|
||||
|
||||
#endif // PACKAGER_MEDIA_BASE_RANGE_H_
|
|
@ -110,12 +110,7 @@ void HlsNotifyMuxerListener::OnMediaStart(const MuxerOptions& muxer_options,
|
|||
|
||||
void HlsNotifyMuxerListener::OnSampleDurationReady(uint32_t sample_duration) {}
|
||||
|
||||
void HlsNotifyMuxerListener::OnMediaEnd(bool has_init_range,
|
||||
uint64_t init_range_start,
|
||||
uint64_t init_range_end,
|
||||
bool has_index_range,
|
||||
uint64_t index_range_start,
|
||||
uint64_t index_range_end,
|
||||
void HlsNotifyMuxerListener::OnMediaEnd(const MediaRanges& media_ranges,
|
||||
float duration_seconds,
|
||||
uint64_t file_size) {
|
||||
// TODO(kqyang): Should we just Flush here to avoid calling Flush explicitly?
|
||||
|
|
|
@ -51,12 +51,7 @@ class HlsNotifyMuxerListener : public MuxerListener {
|
|||
uint32_t time_scale,
|
||||
ContainerType container_type) override;
|
||||
void OnSampleDurationReady(uint32_t sample_duration) override;
|
||||
void OnMediaEnd(bool has_init_range,
|
||||
uint64_t init_range_start,
|
||||
uint64_t init_range_end,
|
||||
bool has_index_range,
|
||||
uint64_t index_range_start,
|
||||
uint64_t index_range_end,
|
||||
void OnMediaEnd(const MediaRanges& media_ranges,
|
||||
float duration_seconds,
|
||||
uint64_t file_size) override;
|
||||
void OnNewSegment(const std::string& file_name,
|
||||
|
|
|
@ -313,7 +313,7 @@ TEST_F(HlsNotifyMuxerListenerTest, OnSampleDurationReady) {
|
|||
// Make sure it doesn't crash.
|
||||
TEST_F(HlsNotifyMuxerListenerTest, OnMediaEnd) {
|
||||
// None of these values matter, they are not used.
|
||||
listener_.OnMediaEnd(false, 0, 0, false, 0, 0, 0, 0);
|
||||
listener_.OnMediaEnd(MuxerListener::MediaRanges(), 0, 0);
|
||||
}
|
||||
|
||||
TEST_F(HlsNotifyMuxerListenerTest, OnNewSegment) {
|
||||
|
|
|
@ -12,5 +12,25 @@ namespace media {
|
|||
MockMuxerListener::MockMuxerListener() {}
|
||||
MockMuxerListener::~MockMuxerListener() {}
|
||||
|
||||
void MockMuxerListener::OnMediaEnd(const MediaRanges& range,
|
||||
float duration_seconds,
|
||||
uint64_t file_size) {
|
||||
const bool has_init_range = static_cast<bool>(range.init_range);
|
||||
Range init_range = {};
|
||||
if (has_init_range) {
|
||||
init_range = range.init_range.value();
|
||||
}
|
||||
const bool has_index_range = static_cast<bool>(range.index_range);
|
||||
Range index_range = {};
|
||||
if (has_index_range) {
|
||||
index_range = range.index_range.value();
|
||||
}
|
||||
|
||||
OnMediaEndMock(has_init_range, init_range.start, init_range.end,
|
||||
has_index_range, index_range.start, index_range.end,
|
||||
!range.subsegment_ranges.empty(), range.subsegment_ranges,
|
||||
duration_seconds, file_size);
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace shaka
|
||||
|
|
|
@ -40,15 +40,23 @@ class MockMuxerListener : public MuxerListener {
|
|||
|
||||
MOCK_METHOD1(OnSampleDurationReady, void(uint32_t sample_duration));
|
||||
|
||||
MOCK_METHOD8(OnMediaEnd,
|
||||
void(bool has_init_range,
|
||||
uint64_t init_range_start,
|
||||
uint64_t init_range_end,
|
||||
bool has_index_range,
|
||||
uint64_t index_range_start,
|
||||
uint64_t index_range_end,
|
||||
float duration_seconds,
|
||||
uint64_t file_size));
|
||||
MOCK_METHOD10(OnMediaEndMock,
|
||||
void(bool has_init_range,
|
||||
uint64_t init_range_start,
|
||||
uint64_t init_range_end,
|
||||
bool has_index_range,
|
||||
uint64_t index_range_start,
|
||||
uint64_t index_range_end,
|
||||
bool has_subsegment_ranges,
|
||||
const std::vector<Range> subsegment_ranges,
|
||||
float duration_seconds,
|
||||
uint64_t file_size));
|
||||
|
||||
// Windows 32 bit cannot mock MediaRanges because it has Optionals that use
|
||||
// memory alignment of 8 bytes. The compiler fails if it is mocked.
|
||||
void OnMediaEnd(const MediaRanges& range,
|
||||
float duration_seconds,
|
||||
uint64_t file_size) override;
|
||||
|
||||
MOCK_METHOD4(OnNewSegment,
|
||||
void(const std::string& segment_name,
|
||||
|
|
|
@ -109,12 +109,7 @@ void MpdNotifyMuxerListener::OnSampleDurationReady(
|
|||
media_info_->mutable_video_info()->set_frame_duration(sample_duration);
|
||||
}
|
||||
|
||||
void MpdNotifyMuxerListener::OnMediaEnd(bool has_init_range,
|
||||
uint64_t init_range_start,
|
||||
uint64_t init_range_end,
|
||||
bool has_index_range,
|
||||
uint64_t index_range_start,
|
||||
uint64_t index_range_end,
|
||||
void MpdNotifyMuxerListener::OnMediaEnd(const MediaRanges& media_ranges,
|
||||
float duration_seconds,
|
||||
uint64_t file_size) {
|
||||
if (mpd_notifier_->dash_profile() == DashProfile::kLive) {
|
||||
|
@ -127,14 +122,7 @@ void MpdNotifyMuxerListener::OnMediaEnd(bool has_init_range,
|
|||
}
|
||||
|
||||
DCHECK(media_info_);
|
||||
if (!internal::SetVodInformation(has_init_range,
|
||||
init_range_start,
|
||||
init_range_end,
|
||||
has_index_range,
|
||||
index_range_start,
|
||||
index_range_end,
|
||||
duration_seconds,
|
||||
file_size,
|
||||
if (!internal::SetVodInformation(media_ranges, duration_seconds, file_size,
|
||||
media_info_.get())) {
|
||||
LOG(ERROR) << "Failed to generate VOD information from input.";
|
||||
return;
|
||||
|
@ -143,6 +131,8 @@ void MpdNotifyMuxerListener::OnMediaEnd(bool has_init_range,
|
|||
uint32_t id;
|
||||
// TODO(kqyang): Check return result.
|
||||
mpd_notifier_->NotifyNewContainer(*media_info_, &id);
|
||||
// TODO(rkuroiwa): Use media_ranges.subsegment_ranges instead of caching the
|
||||
// subsegments.
|
||||
for (std::list<SubsegmentInfo>::const_iterator it = subsegments_.begin();
|
||||
it != subsegments_.end(); ++it) {
|
||||
mpd_notifier_->NotifyNewSegment(id, it->start_time, it->duration,
|
||||
|
|
|
@ -45,12 +45,7 @@ class MpdNotifyMuxerListener : public MuxerListener {
|
|||
uint32_t time_scale,
|
||||
ContainerType container_type) override;
|
||||
void OnSampleDurationReady(uint32_t sample_duration) override;
|
||||
void OnMediaEnd(bool has_init_range,
|
||||
uint64_t init_range_start,
|
||||
uint64_t init_range_end,
|
||||
bool has_index_range,
|
||||
uint64_t index_range_start,
|
||||
uint64_t index_range_end,
|
||||
void OnMediaEnd(const MediaRanges& media_ranges,
|
||||
float duration_seconds,
|
||||
uint64_t file_size) override;
|
||||
void OnNewSegment(const std::string& file_name,
|
||||
|
|
|
@ -83,13 +83,7 @@ class MpdNotifyMuxerListenerTest : public ::testing::TestWithParam<MpdType> {
|
|||
|
||||
void FireOnMediaEndWithParams(const OnMediaEndParameters& params) {
|
||||
// On success, this writes the result to |temp_file_path_|.
|
||||
listener_->OnMediaEnd(params.has_init_range,
|
||||
params.init_range_start,
|
||||
params.init_range_end,
|
||||
params.has_index_range,
|
||||
params.index_range_start,
|
||||
params.index_range_end,
|
||||
params.duration_seconds,
|
||||
listener_->OnMediaEnd(params.media_ranges, params.duration_seconds,
|
||||
params.file_size);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "packager/base/optional.h"
|
||||
#include "packager/media/base/fourccs.h"
|
||||
#include "packager/media/base/range.h"
|
||||
|
||||
namespace shaka {
|
||||
namespace media {
|
||||
|
@ -36,6 +38,20 @@ class MuxerListener {
|
|||
kContainerWebM
|
||||
};
|
||||
|
||||
/// Structure for specifying ranges within a media file. This is mainly for
|
||||
/// VOD content where OnMediaEnd() is actually used for finalization e.g.
|
||||
/// writing out manifests.
|
||||
struct MediaRanges {
|
||||
/// Range of the initialization section of a segment.
|
||||
base::Optional<Range> init_range;
|
||||
/// Range of the index section of a segment.
|
||||
base::Optional<Range> index_range;
|
||||
/// Ranges of the subsegments (e.g. fragments).
|
||||
/// The vector is empty if ranges are not specified. For example it
|
||||
/// may not be a single file.
|
||||
std::vector<Range> subsegment_ranges;
|
||||
};
|
||||
|
||||
virtual ~MuxerListener() {};
|
||||
|
||||
/// Called when the media's encryption information is ready.
|
||||
|
@ -89,24 +105,10 @@ class MuxerListener {
|
|||
/// Called when all files are written out and the muxer object does not output
|
||||
/// any more files.
|
||||
/// Note: This event might not be very interesting to MPEG DASH Live profile.
|
||||
/// @param has_init_range is true if @a init_range_start and @a init_range_end
|
||||
/// actually define an initialization range of a segment. The range is
|
||||
/// inclusive for both start and end.
|
||||
/// @param init_range_start is the start of the initialization range.
|
||||
/// @param init_range_end is the end of the initialization range.
|
||||
/// @param has_index_range is true if @a index_range_start and @a
|
||||
/// index_range_end actually define an index range of a segment. The
|
||||
/// range is inclusive for both start and end.
|
||||
/// @param index_range_start is the start of the index range.
|
||||
/// @param index_range_end is the end of the index range.
|
||||
/// @param media_ranges is the ranges of the media file.
|
||||
/// @param duration_seconds is the length of the media in seconds.
|
||||
/// @param file_size is the size of the file in bytes.
|
||||
virtual void OnMediaEnd(bool has_init_range,
|
||||
uint64_t init_range_start,
|
||||
uint64_t init_range_end,
|
||||
bool has_index_range,
|
||||
uint64_t index_range_start,
|
||||
uint64_t index_range_end,
|
||||
virtual void OnMediaEnd(const MediaRanges& media_ranges,
|
||||
float duration_seconds,
|
||||
uint64_t file_size) = 0;
|
||||
|
||||
|
|
|
@ -36,30 +36,14 @@ uint32_t EstimateRequiredBandwidth(uint64_t file_size, float duration_seconds) {
|
|||
return static_cast<uint32_t>(ceil(bits_per_second));
|
||||
}
|
||||
|
||||
void SetRange(uint64_t begin, uint64_t end, Range* range) {
|
||||
// TODO(rkuroiwa): There is shaka::Range in MediaInfo proto and
|
||||
// shaka::media::Range in media/base. Find better names.
|
||||
void SetRange(uint64_t begin, uint64_t end, shaka::Range* range) {
|
||||
DCHECK(range);
|
||||
range->set_begin(begin);
|
||||
range->set_end(end);
|
||||
}
|
||||
|
||||
void SetMediaInfoRanges(bool has_init_range,
|
||||
uint64_t init_range_start,
|
||||
uint64_t init_range_end,
|
||||
bool has_index_range,
|
||||
uint64_t index_range_start,
|
||||
uint64_t index_range_end,
|
||||
MediaInfo* media_info) {
|
||||
if (has_init_range) {
|
||||
SetRange(
|
||||
init_range_start, init_range_end, media_info->mutable_init_range());
|
||||
}
|
||||
|
||||
if (has_index_range) {
|
||||
SetRange(
|
||||
index_range_start, index_range_end, media_info->mutable_index_range());
|
||||
}
|
||||
}
|
||||
|
||||
void SetMediaInfoContainerType(MuxerListener::ContainerType container_type,
|
||||
MediaInfo* media_info) {
|
||||
DCHECK(media_info);
|
||||
|
@ -205,12 +189,7 @@ bool GenerateMediaInfo(const MuxerOptions& muxer_options,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SetVodInformation(bool has_init_range,
|
||||
uint64_t init_range_start,
|
||||
uint64_t init_range_end,
|
||||
bool has_index_range,
|
||||
uint64_t index_range_start,
|
||||
uint64_t index_range_end,
|
||||
bool SetVodInformation(const MuxerListener::MediaRanges& media_ranges,
|
||||
float duration_seconds,
|
||||
uint64_t file_size,
|
||||
MediaInfo* media_info) {
|
||||
|
@ -226,13 +205,16 @@ bool SetVodInformation(bool has_init_range,
|
|||
return false;
|
||||
}
|
||||
|
||||
SetMediaInfoRanges(has_init_range,
|
||||
init_range_start,
|
||||
init_range_end,
|
||||
has_index_range,
|
||||
index_range_start,
|
||||
index_range_end,
|
||||
media_info);
|
||||
|
||||
if (media_ranges.init_range) {
|
||||
SetRange(media_ranges.init_range->start, media_ranges.init_range->end,
|
||||
media_info->mutable_init_range());
|
||||
}
|
||||
|
||||
if (media_ranges.index_range) {
|
||||
SetRange(media_ranges.index_range->start, media_ranges.index_range->end,
|
||||
media_info->mutable_index_range());
|
||||
}
|
||||
|
||||
media_info->set_media_duration_seconds(duration_seconds);
|
||||
|
||||
|
|
|
@ -35,12 +35,7 @@ bool GenerateMediaInfo(const MuxerOptions& muxer_options,
|
|||
|
||||
/// @param[in,out] media_info points to the MediaInfo object to be filled.
|
||||
/// @return true on success, false otherwise.
|
||||
bool SetVodInformation(bool has_init_range,
|
||||
uint64_t init_range_start,
|
||||
uint64_t init_range_end,
|
||||
bool has_index_range,
|
||||
uint64_t index_range_start,
|
||||
uint64_t index_range_end,
|
||||
bool SetVodInformation(const MuxerListener::MediaRanges& media_ranges,
|
||||
float duration_seconds,
|
||||
uint64_t file_size,
|
||||
MediaInfo* media_info);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#include "packager/media/event/muxer_listener_test_helper.h"
|
||||
#include "packager/media/event/muxer_listener.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
@ -59,17 +60,23 @@ VideoStreamInfoParameters GetDefaultVideoStreamInfoParams() {
|
|||
OnMediaEndParameters GetDefaultOnMediaEndParams() {
|
||||
// Values for {init, index} range {start, end} are arbitrary, but makes sure
|
||||
// that it is monotonically increasing and contiguous.
|
||||
const bool kHasInitRange = true;
|
||||
const uint64_t kInitRangeStart = 0;
|
||||
const uint64_t kInitRangeEnd = kInitRangeStart + 120;
|
||||
const uint64_t kHasIndexRange = true;
|
||||
const uint64_t kIndexRangeStart = kInitRangeEnd + 1;
|
||||
const uint64_t kIndexRangeEnd = kIndexRangeStart + 100;
|
||||
const float kMediaDuration = 10.5f;
|
||||
const uint64_t kFileSize = 10000;
|
||||
OnMediaEndParameters param = {
|
||||
kHasInitRange, kInitRangeStart, kInitRangeEnd, kHasIndexRange,
|
||||
kIndexRangeStart, kIndexRangeEnd, kMediaDuration, kFileSize};
|
||||
MuxerListener::MediaRanges media_ranges;
|
||||
Range init_range;
|
||||
init_range.start = kInitRangeStart;
|
||||
init_range.end = kInitRangeEnd;
|
||||
media_ranges.init_range = init_range;
|
||||
Range index_range;
|
||||
index_range.start = kIndexRangeStart;
|
||||
index_range.end = kIndexRangeEnd;
|
||||
media_ranges.index_range =index_range;
|
||||
|
||||
OnMediaEndParameters param = {media_ranges, kMediaDuration, kFileSize};
|
||||
return param;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "packager/media/base/muxer_options.h"
|
||||
#include "packager/media/base/stream_info.h"
|
||||
#include "packager/media/base/video_stream_info.h"
|
||||
#include "packager/media/event/muxer_listener.h"
|
||||
#include "packager/mpd/base/media_info.pb.h"
|
||||
|
||||
namespace shaka {
|
||||
|
@ -73,12 +74,7 @@ struct VideoStreamInfoParameters {
|
|||
|
||||
// Note that this does not have vector of StreamInfo pointer.
|
||||
struct OnMediaEndParameters {
|
||||
bool has_init_range;
|
||||
uint64_t init_range_start;
|
||||
uint64_t init_range_end;
|
||||
bool has_index_range;
|
||||
uint64_t index_range_start;
|
||||
uint64_t index_range_end;
|
||||
MuxerListener::MediaRanges media_ranges;
|
||||
float duration_seconds;
|
||||
uint64_t file_size;
|
||||
};
|
||||
|
|
|
@ -72,23 +72,11 @@ void VodMediaInfoDumpMuxerListener::OnSampleDurationReady(
|
|||
}
|
||||
}
|
||||
|
||||
void VodMediaInfoDumpMuxerListener::OnMediaEnd(bool has_init_range,
|
||||
uint64_t init_range_start,
|
||||
uint64_t init_range_end,
|
||||
bool has_index_range,
|
||||
uint64_t index_range_start,
|
||||
uint64_t index_range_end,
|
||||
void VodMediaInfoDumpMuxerListener::OnMediaEnd(const MediaRanges& media_ranges,
|
||||
float duration_seconds,
|
||||
uint64_t file_size) {
|
||||
DCHECK(media_info_);
|
||||
if (!internal::SetVodInformation(has_init_range,
|
||||
init_range_start,
|
||||
init_range_end,
|
||||
has_index_range,
|
||||
index_range_start,
|
||||
index_range_end,
|
||||
duration_seconds,
|
||||
file_size,
|
||||
if (!internal::SetVodInformation(media_ranges, duration_seconds, file_size,
|
||||
media_info_.get())) {
|
||||
LOG(ERROR) << "Failed to generate VOD information from input.";
|
||||
return;
|
||||
|
|
|
@ -44,12 +44,7 @@ class VodMediaInfoDumpMuxerListener : public MuxerListener {
|
|||
uint32_t time_scale,
|
||||
ContainerType container_type) override;
|
||||
void OnSampleDurationReady(uint32_t sample_duration) override;
|
||||
void OnMediaEnd(bool has_init_range,
|
||||
uint64_t init_range_start,
|
||||
uint64_t init_range_end,
|
||||
bool has_index_range,
|
||||
uint64_t index_range_start,
|
||||
uint64_t index_range_end,
|
||||
void OnMediaEnd(const MediaRanges& media_ranges,
|
||||
float duration_seconds,
|
||||
uint64_t file_size) override;
|
||||
void OnNewSegment(const std::string& file_name,
|
||||
|
|
|
@ -95,12 +95,7 @@ class VodMediaInfoDumpMuxerListenerTest : public ::testing::Test {
|
|||
|
||||
void FireOnMediaEndWithParams(const OnMediaEndParameters& params) {
|
||||
// On success, this writes the result to |temp_file_path_|.
|
||||
listener_->OnMediaEnd(params.has_init_range,
|
||||
params.init_range_start,
|
||||
params.init_range_end,
|
||||
params.has_index_range,
|
||||
params.index_range_start,
|
||||
params.index_range_end,
|
||||
listener_->OnMediaEnd(params.media_ranges,
|
||||
params.duration_seconds,
|
||||
params.file_size);
|
||||
}
|
||||
|
|
|
@ -59,11 +59,9 @@ void TsMuxer::FireOnMediaEndEvent() {
|
|||
return;
|
||||
|
||||
// For now, there is no single file TS segmenter. So all the values passed
|
||||
// here are false and 0. Called just to notify the MuxerListener.
|
||||
const bool kHasInitRange = true;
|
||||
const bool kHasIndexRange = true;
|
||||
muxer_listener()->OnMediaEnd(!kHasInitRange, 0, 0, !kHasIndexRange, 0, 0, 0,
|
||||
0);
|
||||
// here are left empty.
|
||||
MuxerListener::MediaRanges range;
|
||||
muxer_listener()->OnMediaEnd(range, 0, 0);
|
||||
}
|
||||
|
||||
} // namespace mp2t
|
||||
|
|
|
@ -32,12 +32,11 @@ namespace {
|
|||
// |start| and |end| are for byte-range-spec specified in RFC2616.
|
||||
void SetStartAndEndFromOffsetAndSize(size_t offset,
|
||||
size_t size,
|
||||
uint32_t* start,
|
||||
uint32_t* end) {
|
||||
DCHECK(start && end);
|
||||
*start = static_cast<uint32_t>(offset);
|
||||
Range* range) {
|
||||
DCHECK(range);
|
||||
range->start = static_cast<uint32_t>(offset);
|
||||
// Note that ranges are inclusive. So we need - 1.
|
||||
*end = *start + static_cast<uint32_t>(size) - 1;
|
||||
range->end = range->start + static_cast<uint32_t>(size) - 1;
|
||||
}
|
||||
|
||||
FourCC CodecToFourCC(Codec codec, H26xStreamFormat h26x_stream_format) {
|
||||
|
@ -419,30 +418,30 @@ void MP4Muxer::GenerateTextTrak(const TextStreamInfo* text_info,
|
|||
<< " handling not implemented yet.";
|
||||
}
|
||||
|
||||
bool MP4Muxer::GetInitRangeStartAndEnd(uint32_t* start, uint32_t* end) {
|
||||
DCHECK(start && end);
|
||||
base::Optional<Range> MP4Muxer::GetInitRangeStartAndEnd() {
|
||||
size_t range_offset = 0;
|
||||
size_t range_size = 0;
|
||||
const bool has_range = segmenter_->GetInitRange(&range_offset, &range_size);
|
||||
|
||||
if (!has_range)
|
||||
return false;
|
||||
return base::nullopt;
|
||||
|
||||
SetStartAndEndFromOffsetAndSize(range_offset, range_size, start, end);
|
||||
return true;
|
||||
Range range;
|
||||
SetStartAndEndFromOffsetAndSize(range_offset, range_size, &range);
|
||||
return range;
|
||||
}
|
||||
|
||||
bool MP4Muxer::GetIndexRangeStartAndEnd(uint32_t* start, uint32_t* end) {
|
||||
DCHECK(start && end);
|
||||
base::Optional<Range> MP4Muxer::GetIndexRangeStartAndEnd() {
|
||||
size_t range_offset = 0;
|
||||
size_t range_size = 0;
|
||||
const bool has_range = segmenter_->GetIndexRange(&range_offset, &range_size);
|
||||
|
||||
if (!has_range)
|
||||
return false;
|
||||
return base::nullopt;
|
||||
|
||||
SetStartAndEndFromOffsetAndSize(range_offset, range_size, start, end);
|
||||
return true;
|
||||
Range range;
|
||||
SetStartAndEndFromOffsetAndSize(range_offset, range_size, &range);
|
||||
return range;
|
||||
}
|
||||
|
||||
void MP4Muxer::FireOnMediaStartEvent() {
|
||||
|
@ -464,15 +463,10 @@ void MP4Muxer::FireOnMediaEndEvent() {
|
|||
if (!muxer_listener())
|
||||
return;
|
||||
|
||||
uint32_t init_range_start = 0;
|
||||
uint32_t init_range_end = 0;
|
||||
const bool has_init_range =
|
||||
GetInitRangeStartAndEnd(&init_range_start, &init_range_end);
|
||||
|
||||
uint32_t index_range_start = 0;
|
||||
uint32_t index_range_end = 0;
|
||||
const bool has_index_range =
|
||||
GetIndexRangeStartAndEnd(&index_range_start, &index_range_end);
|
||||
MuxerListener::MediaRanges media_range;
|
||||
media_range.init_range = GetInitRangeStartAndEnd();
|
||||
media_range.index_range = GetIndexRangeStartAndEnd();
|
||||
media_range.subsegment_ranges = segmenter_->GetSegmentRanges();
|
||||
|
||||
const float duration_seconds = static_cast<float>(segmenter_->GetDuration());
|
||||
|
||||
|
@ -483,14 +477,7 @@ void MP4Muxer::FireOnMediaEndEvent() {
|
|||
return;
|
||||
}
|
||||
|
||||
muxer_listener()->OnMediaEnd(has_init_range,
|
||||
init_range_start,
|
||||
init_range_end,
|
||||
has_index_range,
|
||||
index_range_start,
|
||||
index_range_end,
|
||||
duration_seconds,
|
||||
file_size);
|
||||
muxer_listener()->OnMediaEnd(media_range, duration_seconds, file_size);
|
||||
}
|
||||
|
||||
uint64_t MP4Muxer::IsoTimeNow() {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include "packager/base/optional.h"
|
||||
#include "packager/media/base/muxer.h"
|
||||
|
||||
namespace shaka {
|
||||
|
@ -57,11 +58,11 @@ class MP4Muxer : public Muxer {
|
|||
|
||||
// Gets |start| and |end| initialization range. Returns true if there is an
|
||||
// init range and sets start-end byte-range-spec specified in RFC2616.
|
||||
bool GetInitRangeStartAndEnd(uint32_t* start, uint32_t* end);
|
||||
base::Optional<Range> GetInitRangeStartAndEnd();
|
||||
|
||||
// Gets |start| and |end| index range. Returns true if there is an index range
|
||||
// and sets start-end byte-range-spec specified in RFC2616.
|
||||
bool GetIndexRangeStartAndEnd(uint32_t* start, uint32_t* end);
|
||||
base::Optional<Range> GetIndexRangeStartAndEnd();
|
||||
|
||||
// Fire events if there are no errors and Muxer::muxer_listener() is not NULL.
|
||||
void FireOnMediaStartEvent();
|
||||
|
|
|
@ -38,16 +38,21 @@ MultiSegmentSegmenter::MultiSegmentSegmenter(const MuxerOptions& options,
|
|||
MultiSegmentSegmenter::~MultiSegmentSegmenter() {}
|
||||
|
||||
bool MultiSegmentSegmenter::GetInitRange(size_t* offset, size_t* size) {
|
||||
DLOG(INFO) << "MultiSegmentSegmenter outputs init segment: "
|
||||
<< options().output_file_name;
|
||||
VLOG(1) << "MultiSegmentSegmenter outputs init segment: "
|
||||
<< options().output_file_name;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MultiSegmentSegmenter::GetIndexRange(size_t* offset, size_t* size) {
|
||||
DLOG(INFO) << "MultiSegmentSegmenter does not have index range.";
|
||||
VLOG(1) << "MultiSegmentSegmenter does not have index range.";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<Range> MultiSegmentSegmenter::GetSegmentRanges() {
|
||||
VLOG(1) << "MultiSegmentSegmenter does not have media segment ranges.";
|
||||
return std::vector<Range>();
|
||||
}
|
||||
|
||||
Status MultiSegmentSegmenter::DoInitialize() {
|
||||
DCHECK(ftyp());
|
||||
DCHECK(moov());
|
||||
|
|
|
@ -39,6 +39,7 @@ class MultiSegmentSegmenter : public Segmenter {
|
|||
/// @{
|
||||
bool GetInitRange(size_t* offset, size_t* size) override;
|
||||
bool GetIndexRange(size_t* offset, size_t* size) override;
|
||||
std::vector<Range> GetSegmentRanges() override;
|
||||
/// @}
|
||||
|
||||
private:
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "packager/base/optional.h"
|
||||
#include "packager/media/base/fourccs.h"
|
||||
#include "packager/media/base/range.h"
|
||||
#include "packager/media/formats/mp4/box_definitions.h"
|
||||
#include "packager/status.h"
|
||||
|
||||
|
@ -73,6 +75,8 @@ class Segmenter {
|
|||
Status FinalizeSegment(size_t stream_id,
|
||||
std::shared_ptr<SegmentInfo> segment_info);
|
||||
|
||||
// TODO(rkuroiwa): Change these Get*Range() methods to return
|
||||
// base::Optional<Range> as well.
|
||||
/// @return true if there is an initialization range, while setting @a offset
|
||||
/// and @a size; or false if initialization range does not apply.
|
||||
virtual bool GetInitRange(size_t* offset, size_t* size) = 0;
|
||||
|
@ -81,6 +85,11 @@ class Segmenter {
|
|||
/// and @a size; or false if index byte range does not apply.
|
||||
virtual bool GetIndexRange(size_t* offset, size_t* size) = 0;
|
||||
|
||||
// Returns an empty vector if there are no specific ranges for the segments,
|
||||
// e.g. the media is in multiple files.
|
||||
// Otherwise, a vector of ranges for the media segments are returned.
|
||||
virtual std::vector<Range> GetSegmentRanges() = 0;
|
||||
|
||||
uint32_t GetReferenceTimeScale() const;
|
||||
|
||||
/// @return The total length, in seconds, of segmented media files.
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#include "packager/media/base/buffer_writer.h"
|
||||
#include "packager/media/base/muxer_options.h"
|
||||
#include "packager/media/event/muxer_listener.h"
|
||||
#include "packager/media/event/progress_listener.h"
|
||||
#include "packager/media/file/file.h"
|
||||
#include "packager/media/file/file_util.h"
|
||||
|
@ -49,6 +48,22 @@ bool SingleSegmentSegmenter::GetIndexRange(size_t* offset, size_t* size) {
|
|||
return true;
|
||||
}
|
||||
|
||||
std::vector<Range> SingleSegmentSegmenter::GetSegmentRanges() {
|
||||
std::vector<Range> ranges;
|
||||
uint64_t next_offset =
|
||||
ftyp()->ComputeSize() + moov()->ComputeSize() + vod_sidx_->ComputeSize() +
|
||||
vod_sidx_->first_offset;
|
||||
for (const SegmentReference& segment_reference : vod_sidx_->references) {
|
||||
Range r;
|
||||
r.start = next_offset;
|
||||
// Ranges are inclusive, so -1 to the size.
|
||||
r.end = r.start + segment_reference.referenced_size - 1;
|
||||
next_offset = r.end + 1;
|
||||
ranges.push_back(r);
|
||||
}
|
||||
return ranges;
|
||||
}
|
||||
|
||||
Status SingleSegmentSegmenter::DoInitialize() {
|
||||
// Single segment segmentation involves two stages:
|
||||
// Stage 1: Create media subsegments from media samples
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#ifndef MEDIA_FORMATS_MP4_SINGLE_SEGMENT_SEGMENTER_H_
|
||||
#define MEDIA_FORMATS_MP4_SINGLE_SEGMENT_SEGMENTER_H_
|
||||
|
||||
#include "packager/media/event/muxer_listener.h"
|
||||
#include "packager/media/file/file_closer.h"
|
||||
#include "packager/media/formats/mp4/segmenter.h"
|
||||
|
||||
|
@ -36,6 +37,7 @@ class SingleSegmentSegmenter : public Segmenter {
|
|||
/// @{
|
||||
bool GetInitRange(size_t* offset, size_t* size) override;
|
||||
bool GetIndexRange(size_t* offset, size_t* size) override;
|
||||
std::vector<Range> GetSegmentRanges() override;
|
||||
/// @}
|
||||
|
||||
private:
|
||||
|
|
|
@ -52,6 +52,10 @@ bool MultiSegmentSegmenter::GetIndexRangeStartAndEnd(uint64_t* start,
|
|||
return false;
|
||||
}
|
||||
|
||||
std::vector<Range> MultiSegmentSegmenter::GetSegmentRanges() {
|
||||
return std::vector<Range>();
|
||||
}
|
||||
|
||||
Status MultiSegmentSegmenter::DoInitialize() {
|
||||
std::unique_ptr<MkvWriter> writer(new MkvWriter);
|
||||
Status status = writer->Open(options().output_file_name);
|
||||
|
|
|
@ -33,6 +33,7 @@ class MultiSegmentSegmenter : public Segmenter {
|
|||
bool is_subsegment) override;
|
||||
bool GetInitRangeStartAndEnd(uint64_t* start, uint64_t* end) override;
|
||||
bool GetIndexRangeStartAndEnd(uint64_t* start, uint64_t* end) override;
|
||||
std::vector<Range> GetSegmentRanges() override;
|
||||
/// @}
|
||||
|
||||
protected:
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
#define MEDIA_FORMATS_WEBM_SEGMENTER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "packager/base/optional.h"
|
||||
#include "packager/media/base/range.h"
|
||||
#include "packager/media/formats/webm/mkv_writer.h"
|
||||
#include "packager/media/formats/webm/seek_head.h"
|
||||
#include "packager/status.h"
|
||||
|
@ -64,6 +67,11 @@ class Segmenter {
|
|||
/// and @a end; or false if index byte range does not apply.
|
||||
virtual bool GetIndexRangeStartAndEnd(uint64_t* start, uint64_t* end) = 0;
|
||||
|
||||
// Returns an empty vector if there are no specific ranges for the segments,
|
||||
// e.g. the media is in multiple files.
|
||||
// Otherwise, a vector of ranges for the media segments are returned.
|
||||
virtual std::vector<Range> GetSegmentRanges() = 0;
|
||||
|
||||
/// @return The total length, in seconds, of segmented media files.
|
||||
float GetDurationInSeconds() const;
|
||||
|
||||
|
|
|
@ -36,8 +36,6 @@ Status SingleSegmentSegmenter::FinalizeSegment(uint64_t start_timestamp,
|
|||
|
||||
bool SingleSegmentSegmenter::GetInitRangeStartAndEnd(uint64_t* start,
|
||||
uint64_t* end) {
|
||||
// The init range is the header, from the start of the file to the size of
|
||||
// the header.
|
||||
*start = 0;
|
||||
*end = init_end_;
|
||||
return true;
|
||||
|
@ -45,13 +43,33 @@ bool SingleSegmentSegmenter::GetInitRangeStartAndEnd(uint64_t* start,
|
|||
|
||||
bool SingleSegmentSegmenter::GetIndexRangeStartAndEnd(uint64_t* start,
|
||||
uint64_t* end) {
|
||||
// The index is the Cues element, which is always placed at the end of the
|
||||
// file.
|
||||
*start = index_start_;
|
||||
*end = index_end_;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<Range> SingleSegmentSegmenter::GetSegmentRanges() {
|
||||
std::vector<Range> ranges;
|
||||
if (cues()->cue_entries_size() == 0) {
|
||||
return ranges;
|
||||
}
|
||||
for (int32_t i = 0; i < cues()->cue_entries_size() - 1; ++i) {
|
||||
const mkvmuxer::CuePoint* cue_point = cues()->GetCueByIndex(i);
|
||||
Range r;
|
||||
r.start = cue_point->cluster_pos();
|
||||
r.end = cues()->GetCueByIndex(i + 1)->cluster_pos() - 1;
|
||||
ranges.push_back(r);
|
||||
}
|
||||
|
||||
Range last_range;
|
||||
const mkvmuxer::CuePoint* last_cue_point =
|
||||
cues()->GetCueByIndex(cues()->cue_entries_size() - 1);
|
||||
last_range.start = last_cue_point->cluster_pos();
|
||||
last_range.end = last_range.start + cluster()->Size() - 1;
|
||||
ranges.push_back(last_range);
|
||||
return ranges;
|
||||
}
|
||||
|
||||
Status SingleSegmentSegmenter::DoInitialize() {
|
||||
if (!writer_) {
|
||||
std::unique_ptr<MkvWriter> writer(new MkvWriter);
|
||||
|
|
|
@ -35,6 +35,7 @@ class SingleSegmentSegmenter : public Segmenter {
|
|||
bool is_subsegment) override;
|
||||
bool GetInitRangeStartAndEnd(uint64_t* start, uint64_t* end) override;
|
||||
bool GetIndexRangeStartAndEnd(uint64_t* start, uint64_t* end) override;
|
||||
std::vector<Range> GetSegmentRanges() override;
|
||||
/// @}
|
||||
|
||||
protected:
|
||||
|
|
|
@ -95,15 +95,31 @@ void WebMMuxer::FireOnMediaEndEvent() {
|
|||
if (!muxer_listener())
|
||||
return;
|
||||
|
||||
MuxerListener::MediaRanges media_range;
|
||||
|
||||
uint64_t init_range_start = 0;
|
||||
uint64_t init_range_end = 0;
|
||||
const bool has_init_range =
|
||||
segmenter_->GetInitRangeStartAndEnd(&init_range_start, &init_range_end);
|
||||
if (has_init_range) {
|
||||
Range r;
|
||||
r.start = init_range_start;
|
||||
r.end = init_range_end;
|
||||
media_range.init_range = r;
|
||||
}
|
||||
|
||||
uint64_t index_range_start = 0;
|
||||
uint64_t index_range_end = 0;
|
||||
const bool has_index_range = segmenter_->GetIndexRangeStartAndEnd(
|
||||
&index_range_start, &index_range_end);
|
||||
if (has_index_range) {
|
||||
Range r;
|
||||
r.start = index_range_start;
|
||||
r.end = index_range_end;
|
||||
media_range.index_range = r;
|
||||
}
|
||||
|
||||
media_range.subsegment_ranges = segmenter_->GetSegmentRanges();
|
||||
|
||||
const float duration_seconds = segmenter_->GetDurationInSeconds();
|
||||
|
||||
|
@ -114,9 +130,7 @@ void WebMMuxer::FireOnMediaEndEvent() {
|
|||
return;
|
||||
}
|
||||
|
||||
muxer_listener()->OnMediaEnd(has_init_range, init_range_start, init_range_end,
|
||||
has_index_range, index_range_start,
|
||||
index_range_end, duration_seconds, file_size);
|
||||
muxer_listener()->OnMediaEnd(media_range, duration_seconds, file_size);
|
||||
}
|
||||
|
||||
} // namespace webm
|
||||
|
|
Loading…
Reference in New Issue