Add HlsNotifyMuxerListener

- A MuxerListener implementation that uses HlsNotifier.

Issue #85

Change-Id: I4c94c025be112d2bd02a78123da3f275e09c3a06
This commit is contained in:
Rintaro Kuroiwa 2016-03-28 00:52:58 -07:00
parent 102f3f7062
commit 66b82f87dd
4 changed files with 293 additions and 0 deletions

View File

@ -0,0 +1,80 @@
// Copyright 2016 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
#include "packager/media/event/hls_notify_muxer_listener.h"
#include "packager/base/logging.h"
#include "packager/base/memory/scoped_ptr.h"
#include "packager/hls/base/hls_notifier.h"
#include "packager/media/base/muxer_options.h"
#include "packager/media/base/protection_system_specific_info.h"
#include "packager/media/event/muxer_listener_internal.h"
namespace edash_packager {
namespace media {
HlsNotifyMuxerListener::HlsNotifyMuxerListener(const std::string& playlist_name,
hls::HlsNotifier* hls_notifier)
: playlist_name_(playlist_name), hls_notifier_(hls_notifier) {
DCHECK(hls_notifier);
}
HlsNotifyMuxerListener::~HlsNotifyMuxerListener() {}
void HlsNotifyMuxerListener::OnEncryptionInfoReady(
bool is_initial_encryption_info,
const std::vector<uint8_t>& key_id,
const std::vector<uint8_t>& iv,
const std::vector<ProtectionSystemSpecificInfo>& key_system_infos) {
for (const ProtectionSystemSpecificInfo& info : key_system_infos) {
const bool result = hls_notifier_->NotifyEncryptionUpdate(
stream_id_, key_id, info.system_id(), iv, info.pssh_data());
LOG_IF(WARNING, !result) << "Failed to add encryption info.";
}
}
void HlsNotifyMuxerListener::OnMediaStart(const MuxerOptions& muxer_options,
const StreamInfo& stream_info,
uint32_t time_scale,
ContainerType container_type) {
MediaInfo media_info;
if (!internal::GenerateMediaInfo(muxer_options, stream_info, time_scale,
container_type, &media_info)) {
LOG(ERROR) << "Failed to generate MediaInfo from input.";
return;
}
const bool result = hls_notifier_->NotifyNewStream(
media_info, playlist_name_, muxer_options.hls_name,
muxer_options.hls_group_id, &stream_id_);
LOG_IF(WARNING, !result) << "Failed to notify new stream.";
}
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,
float duration_seconds,
uint64_t file_size) {
const bool result = hls_notifier_->Flush();
LOG_IF(WARNING, !result) << "Failed to flush.";
}
void HlsNotifyMuxerListener::OnNewSegment(const std::string& file_name,
uint64_t start_time,
uint64_t duration,
uint64_t segment_file_size) {
const bool result = hls_notifier_->NotifyNewSegment(
stream_id_, file_name, start_time, duration, segment_file_size);
LOG_IF(WARNING, !result) << "Failed to add new segment.";
}
} // namespace media
} // namespace edash_packager

View File

@ -0,0 +1,68 @@
// Copyright 2016 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_MEDIA_EVENT_HLS_NOTIFY_MUXER_LISTENER_H_
#define PACKAGER_MEDIA_EVENT_HLS_NOTIFY_MUXER_LISTENER_H_
#include <string>
#include "packager/base/macros.h"
#include "packager/media/event/muxer_listener.h"
namespace edash_packager {
namespace hls {
class HlsNotifier;
} // namespace hls
namespace media {
/// MuxerListener that uses HlsNotifier.
class HlsNotifyMuxerListener : public MuxerListener {
public:
/// @param playlist_name is the name of the playlist for the muxer's stream.
/// @param hls_notifier used by this listener. Ownership does not transfer.
HlsNotifyMuxerListener(const std::string& playlist_name,
hls::HlsNotifier* hls_notifier);
~HlsNotifyMuxerListener() override;
/// @name MuxerListener implementation overrides.
/// @{
void OnEncryptionInfoReady(bool is_initial_encryption_info,
const std::vector<uint8_t>& key_id,
const std::vector<uint8_t>& iv,
const std::vector<ProtectionSystemSpecificInfo>&
key_system_info) override;
void OnMediaStart(const MuxerOptions& muxer_options,
const StreamInfo& stream_info,
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,
float duration_seconds,
uint64_t file_size) override;
void OnNewSegment(const std::string& file_name,
uint64_t start_time,
uint64_t duration,
uint64_t segment_file_size) override;
/// @}
private:
const std::string playlist_name_;
hls::HlsNotifier* const hls_notifier_;
uint32_t stream_id_ = 0;
DISALLOW_COPY_AND_ASSIGN(HlsNotifyMuxerListener);
};
} // namespace media
} // namespace edash_packager
#endif // PACKAGER_MEDIA_EVENT_HLS_NOTIFY_MUXER_LISTENER_H_

View File

@ -0,0 +1,142 @@
// Copyright 2016 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
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "packager/hls/base/hls_notifier.h"
#include "packager/media/base/muxer_options.h"
#include "packager/media/base/protection_system_specific_info.h"
#include "packager/media/event/hls_notify_muxer_listener.h"
#include "packager/media/event/muxer_listener_test_helper.h"
namespace edash_packager {
namespace media {
using ::testing::Return;
using ::testing::StrEq;
using ::testing::_;
namespace {
class MockHlsNotifier : public hls::HlsNotifier {
public:
MockHlsNotifier()
: HlsNotifier(hls::HlsNotifier::HlsProfile::kOnDemandProfile) {}
MOCK_METHOD0(Init, bool());
MOCK_METHOD5(NotifyNewStream,
bool(const MediaInfo& media_info,
const std::string& playlist_name,
const std::string& name,
const std::string& group_id,
uint32_t* stream_id));
MOCK_METHOD5(NotifyNewSegment,
bool(uint32_t stream_id,
const std::string& segment_name,
uint64_t start_time,
uint64_t duration,
uint64_t size));
MOCK_METHOD5(
NotifyEncryptionUpdate,
bool(uint32_t stream_id,
const std::vector<uint8_t>& key_id,
const std::vector<uint8_t>& system_id,
const std::vector<uint8_t>& iv,
const std::vector<uint8_t>& protection_system_specific_data));
MOCK_METHOD0(Flush, bool());
};
// Doesn't really matter what the values are as long as it is a system ID (16
// bytes).
const uint8_t kAnySystemId[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
};
const uint8_t kAnyData[] = {
0xFF, 0x78, 0xAA, 0x6B,
};
// This value doesn't really affect the test, it's not used by the
// implementation.
const bool kInitialEncryptionInfo = true;
const char kDefaultPlaylistName[] = "default_playlist.m3u8";
} // namespace
class HlsNotifyMuxerListenerTest : public ::testing::Test {
protected:
HlsNotifyMuxerListenerTest()
: listener_(kDefaultPlaylistName, &mock_notifier_) {}
MockHlsNotifier mock_notifier_;
HlsNotifyMuxerListener listener_;
};
TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionInfoReady) {
ProtectionSystemSpecificInfo info;
std::vector<uint8_t> system_id(kAnySystemId,
kAnySystemId + arraysize(kAnySystemId));
info.set_system_id(system_id.data(), system_id.size());
std::vector<uint8_t> pssh_data(kAnyData, kAnyData + arraysize(kAnyData));
info.set_pssh_data(pssh_data);
std::vector<uint8_t> key_id(16, 0x05);
std::vector<ProtectionSystemSpecificInfo> key_system_infos;
key_system_infos.push_back(info);
std::vector<uint8_t> iv(16, 0x54);
EXPECT_CALL(mock_notifier_,
NotifyEncryptionUpdate(_, key_id, system_id, iv, pssh_data))
.WillOnce(Return(true));
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, key_id, iv,
key_system_infos);
}
TEST_F(HlsNotifyMuxerListenerTest, OnMediaStart) {
MuxerOptions muxer_options;
muxer_options.hls_name = "Name";
muxer_options.hls_group_id = "GroupID";
SetDefaultMuxerOptionsValues(&muxer_options);
VideoStreamInfoParameters video_params = GetDefaultVideoStreamInfoParams();
scoped_refptr<StreamInfo> video_stream_info =
CreateVideoStreamInfo(video_params);
EXPECT_CALL(mock_notifier_,
NotifyNewStream(_, StrEq(kDefaultPlaylistName), StrEq("Name"),
StrEq("GroupID"), _))
.WillOnce(Return(true));
listener_.OnMediaStart(muxer_options, *video_stream_info, 90000,
MuxerListener::kContainerMpeg2ts);
}
TEST_F(HlsNotifyMuxerListenerTest, OnSampleDurationReady) {
listener_.OnSampleDurationReady(2340);
}
TEST_F(HlsNotifyMuxerListenerTest, OnMediaEnd) {
EXPECT_CALL(mock_notifier_, Flush()).WillOnce(Return(true));
// None of these values matter, they are not used.
listener_.OnMediaEnd(false, 0, 0, false, 0, 0, 0, 0);
}
TEST_F(HlsNotifyMuxerListenerTest, OnNewSegment) {
const uint64_t kStartTime = 19283;
const uint64_t kDuration = 98028;
const uint64_t kFileSize = 756739;
EXPECT_CALL(mock_notifier_,
NotifyNewSegment(_, StrEq("new_segment_name10.ts"), kStartTime,
kDuration, kFileSize));
listener_.OnNewSegment("new_segment_name10.ts", kStartTime, kDuration,
kFileSize);
}
} // namespace media
} // namespace edash_packager

View File

@ -13,6 +13,8 @@
'target_name': 'media_event', 'target_name': 'media_event',
'type': '<(component)', 'type': '<(component)',
'sources': [ 'sources': [
'hls_notify_muxer_listener.cc',
'hls_notify_muxer_listener.h',
'mpd_notify_muxer_listener.cc', 'mpd_notify_muxer_listener.cc',
'mpd_notify_muxer_listener.h', 'mpd_notify_muxer_listener.h',
'muxer_listener.h', 'muxer_listener.h',
@ -34,6 +36,7 @@
'target_name': 'media_event_unittest', 'target_name': 'media_event_unittest',
'type': '<(gtest_target_type)', 'type': '<(gtest_target_type)',
'sources': [ 'sources': [
'hls_notify_muxer_listener_unittest.cc',
'mpd_notify_muxer_listener_unittest.cc', 'mpd_notify_muxer_listener_unittest.cc',
'muxer_listener_test_helper.cc', 'muxer_listener_test_helper.cc',
'muxer_listener_test_helper.h', 'muxer_listener_test_helper.h',