From d07007a5d206ceb7a6fe39b851adfc5ea87101b9 Mon Sep 17 00:00:00 2001 From: Rintaro Kuroiwa Date: Wed, 22 Jan 2014 07:52:18 -0800 Subject: [PATCH] VodMediaInfoDumpMuxerListener unit tests Change-Id: Ib9ff3737f084fc835457fc931162c9a2e9c441bc --- .../vod_media_info_dump_muxer_listener.h | 1 + ...media_info_dump_muxer_listener_unittest.cc | 279 ++++++++++++++++++ packager.gyp | 55 ++-- 3 files changed, 316 insertions(+), 19 deletions(-) create mode 100644 media/event/vod_media_info_dump_muxer_listener_unittest.cc diff --git a/media/event/vod_media_info_dump_muxer_listener.h b/media/event/vod_media_info_dump_muxer_listener.h index bf941f9735..d5ea6fa02a 100644 --- a/media/event/vod_media_info_dump_muxer_listener.h +++ b/media/event/vod_media_info_dump_muxer_listener.h @@ -22,6 +22,7 @@ class MuxerOptions; namespace event { class VodMediaInfoDumpMuxerListener : public MuxerListener { + public: // This object does not own |output_file|. The file has to be open and be // ready for Write(). This will Flush() the file on write but it does not // Close() the file. diff --git a/media/event/vod_media_info_dump_muxer_listener_unittest.cc b/media/event/vod_media_info_dump_muxer_listener_unittest.cc new file mode 100644 index 0000000000..981f32c2d5 --- /dev/null +++ b/media/event/vod_media_info_dump_muxer_listener_unittest.cc @@ -0,0 +1,279 @@ +#include + +#include "base/file_util.h" +#include "base/files/file_path.h" +#include "media/event/vod_media_info_dump_muxer_listener.h" +#include "media/file/file.h" +#include "media/base/muxer_options.h" +#include "media/base/video_stream_info.h" +#include "mpd/base/media_info.pb.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/protobuf/src/google/protobuf/text_format.h" + +using dash_packager::MediaInfo; + +namespace media { +namespace event { + +namespace { +struct VideoStreamInfoParameters { + int track_id; + uint32 time_scale; + uint64 duration; + VideoCodec codec; + std::string codec_string; + std::string language; + uint16 width; + uint16 height; + uint8 nalu_length_size; + std::vector extra_data; + bool is_encrypted; +}; + +// Note that this does not have vector of StreamInfo pointer. +struct OnMediaEndParameters { + bool has_init_range; + uint64 init_range_start; + uint64 init_range_end; + bool has_index_range; + uint64 index_range_start; + uint64 index_range_end; + float duration_seconds; + uint64 file_size; +}; + +scoped_refptr CreateVideoStreamInfo( + const VideoStreamInfoParameters& param) { + return scoped_refptr( + new VideoStreamInfo(param.track_id, + param.time_scale, + param.duration, + param.codec, + param.codec_string, + param.language, + param.width, + param.height, + param.nalu_length_size, + ¶m.extra_data[0], + param.extra_data.size(), + param.is_encrypted)); +} + +VideoStreamInfoParameters GetDefaultVideoStreamInfoParams() { + const int kTrackId = 0; + const uint32 kTimeScale = 10; + const uint64 kVideoStreamDuration = 200; + const VideoCodec kH264Codec = kCodecH264; + const uint8 kH264Profile = 1; + const uint8 kH264CompatibleProfile = 1; + const uint8 kH264Level = 1; + const char* kLanuageUndefined = "und"; + const uint16 kWidth = 720; + const uint16 kHeight = 480; + const uint8 kNaluLengthSize = 1; + const std::vector kExtraData; + const bool kEncryptedFlag = false; + + return {kTrackId, kTimeScale, kVideoStreamDuration, kH264Codec, + VideoStreamInfo::GetCodecString( + kCodecH264, kH264Profile, kH264CompatibleProfile, kH264Level), + kLanuageUndefined, kWidth, kHeight, kNaluLengthSize, kExtraData, + kEncryptedFlag}; +} + +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 kInitRangeStart = 0; + const uint64 kInitRangeEnd = kInitRangeStart + 120; + const uint64 kHasIndexRange = true; + const uint64 kIndexRangeStart = kInitRangeEnd + 1; + const uint64 kIndexRangeEnd = kIndexRangeStart + 100; + const float kMediaDuration = 10.5f; + const uint64 kFileSize = 10000; + return {kHasInitRange, kInitRangeStart, kInitRangeEnd, kHasIndexRange, + kIndexRangeStart, kIndexRangeEnd, kMediaDuration, kFileSize}; +} + +void SetDefaultMuxerOptionsValues(MuxerOptions* muxer_options) { + muxer_options->single_segment = false; + muxer_options->segment_duration = 10.0; + muxer_options->fragment_duration = 10.0; + muxer_options->segment_sap_aligned = true; + muxer_options->fragment_sap_aligned = true; + muxer_options->num_subsegments_per_sidx = 0; + muxer_options->output_file_name = "test_output_file_name.mp4"; + muxer_options->segment_template.clear(); + muxer_options->temp_file_name.clear(); +} + +void ExpectMediaInfoEqual(const MediaInfo& expect, const MediaInfo& actual) { + // I found out here + // https://groups.google.com/forum/#!msg/protobuf/5sOExQkB2eQ/ZSBNZI0K54YJ + // that the best way to check equality is to serialize and check equality. + std::string expect_serialized; + std::string actual_serialized; + ASSERT_TRUE(expect.SerializeToString(&expect_serialized)); + ASSERT_TRUE(actual.SerializeToString(&actual_serialized)); + ASSERT_EQ(expect_serialized, actual_serialized); +} + +void ExpectTextFormatMediaInfoEqual(const std::string& expect, + const std::string& actual) { + MediaInfo expect_media_info; + MediaInfo actual_media_info; + typedef ::google::protobuf::TextFormat TextFormat; + ASSERT_TRUE(TextFormat::ParseFromString(expect, &expect_media_info)) + << "Failed to parse " << std::endl << expect; + ASSERT_TRUE(TextFormat::ParseFromString(actual, &actual_media_info)) + << "Failed to parse " << std::endl << actual; + ASSERT_NO_FATAL_FAILURE( + ExpectMediaInfoEqual(expect_media_info, actual_media_info)) + << "Expect:" << std::endl << expect << std::endl + << "Actual:" << std::endl << actual; +} +} // namespace + +class VodMediaInfoDumpMuxerListenerTest : public ::testing::Test { + public: + VodMediaInfoDumpMuxerListenerTest() {} + virtual ~VodMediaInfoDumpMuxerListenerTest() {} + + virtual void SetUp() OVERRIDE { + ASSERT_TRUE(file_util::CreateTemporaryFile(&temp_file_path_)); + DLOG(INFO) << "Created temp file: " << temp_file_path_.value(); + + temp_file_ = File::Open(temp_file_path_.value().c_str(), "w"); + ASSERT_TRUE(temp_file_); + listener_.reset(new VodMediaInfoDumpMuxerListener(temp_file_)); + } + + virtual void TearDown() OVERRIDE { + base::DeleteFile(temp_file_path_, false); + } + + void FireOnMediaStartWithDefaultValues( + const std::vector stream_infos) { + MuxerOptions muxer_options; + SetDefaultMuxerOptionsValues(&muxer_options); + const uint32 kReferenceTimeScale = 1000; + listener_->OnMediaStart(muxer_options, + stream_infos, + kReferenceTimeScale, + MuxerListener::kContainerMp4); + } + + void FireOnMediaEndWithParams(const std::vector stream_infos, + const OnMediaEndParameters& params) { + // On success, this writes the result to |temp_file_|. + listener_->OnMediaEnd(stream_infos, + 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, + params.file_size); + } + + void ExpectTempFileToEqual(const std::string& expected_protobuf) { + std::string temp_file_media_info_str; + ASSERT_TRUE(File::ReadFileToString(temp_file_path_.value().c_str(), + &temp_file_media_info_str)); + ASSERT_TRUE(!temp_file_media_info_str.empty()); + + ASSERT_NO_FATAL_FAILURE((ExpectTextFormatMediaInfoEqual( + expected_protobuf, temp_file_media_info_str))); + } + + protected: + File* temp_file_; + base::FilePath temp_file_path_; + scoped_ptr listener_; + + private: + DISALLOW_COPY_AND_ASSIGN(VodMediaInfoDumpMuxerListenerTest); +}; + +// TODO(rkuroiwa): Enable these when implemented. +TEST_F(VodMediaInfoDumpMuxerListenerTest, DISABLED_UnencryptedStream_Normal) { + VideoStreamInfoParameters params = GetDefaultVideoStreamInfoParams(); + params.is_encrypted = false; + + std::vector stream_infos; + scoped_refptr stream_info = CreateVideoStreamInfo(params); + stream_infos.push_back(stream_info.get()); + + FireOnMediaStartWithDefaultValues(stream_infos); + FireOnMediaEndWithParams(stream_infos, + GetDefaultOnMediaEndParams()); + ASSERT_TRUE(temp_file_->Close()); + + const char* kExpectedProtobufOutput = "\ + bandwidth: 7620\n\ + video_info {\n\ + codec: \"avc1.010101\"\n\ + width: 720\n\ + height: 480\n\ + time_scale: 10\n\ + }\n\ + init_range {\n\ + begin: 0\n\ + end: 120\n\ + }\n\ + index_range {\n\ + begin: 121\n\ + end: 221\n\ + }\n\ + reference_time_scale: 1000\n\ + container_type: 1\n\ + media_file_name: \"test_output_file_name.mp4\"\n\ + media_duration_seconds: 10.5\n"; + ASSERT_NO_FATAL_FAILURE(ExpectTempFileToEqual(kExpectedProtobufOutput)); +} + +TEST_F(VodMediaInfoDumpMuxerListenerTest, DISABLED_EncryptedStream_Normal) { + listener_->SetContentProtectionSchemeIdUri("http://foo.com/bar"); + + VideoStreamInfoParameters params = GetDefaultVideoStreamInfoParams(); + params.is_encrypted = true; + + std::vector stream_infos; + scoped_refptr stream_info = CreateVideoStreamInfo(params); + stream_infos.push_back(stream_info.get()); + + FireOnMediaStartWithDefaultValues(stream_infos); + FireOnMediaEndWithParams(stream_infos, + GetDefaultOnMediaEndParams()); + ASSERT_TRUE(temp_file_->Close()); + + const char* kExpectedProtobufOutput = "\ + bandwidth: 7620\n\ + video_info {\n\ + codec: \"avc1.010101\"\n\ + width: 720\n\ + height: 480\n\ + time_scale: 10\n\ + }\n\ + content_protections {\n\ + scheme_id_uri: \"http://foo.com/bar\"\n\ + }\n\ + init_range {\n\ + begin: 0\n\ + end: 120\n\ + }\n\ + index_range {\n\ + begin: 121\n\ + end: 221\n\ + }\n\ + reference_time_scale: 1000\n\ + container_type: 1\n\ + media_file_name: \"test_output_file_name.mp4\"\n\ + media_duration_seconds: 10.5\n"; + ASSERT_NO_FATAL_FAILURE(ExpectTempFileToEqual(kExpectedProtobufOutput)); +} + +} // namespace event +} // namespace media diff --git a/packager.gyp b/packager.gyp index 6e7460e3e4..53af15b001 100644 --- a/packager.gyp +++ b/packager.gyp @@ -191,25 +191,6 @@ 'media_base', ], }, - { - 'target_name': 'media_event', - 'type': 'static_library', - 'sources': [ - 'media/event/muxer_listener.h', - 'media/event/vod_media_info_dump_muxer_listener.cc', - 'media/event/vod_media_info_dump_muxer_listener.h', - 'media/event/vod_mpd_notify_muxer_listener.cc', - 'media/event/vod_mpd_notify_muxer_listener.h', - 'media/event/vod_muxer_listener_internal.cc', - 'media/event/vod_muxer_listener_internal.h', - ], - 'dependencies': [ - 'media_base', - 'mpd/mpd.gyp:media_info_proto', - # Depends on full protobuf to read/write with TextFormat. - 'third_party/protobuf/protobuf.gyp:protobuf_full_do_not_use', - ], - }, { 'target_name': 'mp4_unittest', 'type': 'executable', @@ -272,6 +253,42 @@ 'testing/gtest.gyp:gtest', ], }, + { + 'target_name': 'media_event', + 'type': '<(component)', + 'sources': [ + 'media/event/muxer_listener.h', + 'media/event/vod_media_info_dump_muxer_listener.cc', + 'media/event/vod_media_info_dump_muxer_listener.h', + 'media/event/vod_mpd_notify_muxer_listener.cc', + 'media/event/vod_mpd_notify_muxer_listener.h', + 'media/event/vod_muxer_listener_internal.cc', + 'media/event/vod_muxer_listener_internal.h', + ], + 'dependencies': [ + 'media_base', + 'mpd/mpd.gyp:media_info_proto', + # Depends on full protobuf to read/write with TextFormat. + 'third_party/protobuf/protobuf.gyp:protobuf_full_do_not_use', + ], + }, + { + 'target_name': 'media_event_unittest', + 'type': '<(gtest_target_type)', + 'sources': [ + 'media/event/vod_media_info_dump_muxer_listener_unittest.cc', + ], + 'dependencies': [ + 'base/base.gyp:base', + 'base/base.gyp:run_all_unittests', + 'file', + 'media_event', + 'mpd/mpd.gyp:media_info_proto', + 'testing/gtest.gyp:gtest', + # Depends on full protobuf to read/write with TextFormat. + 'third_party/protobuf/protobuf.gyp:protobuf_full_do_not_use', + ], + }, { 'target_name': 'packager_main', 'type': 'executable',