diff --git a/DEPS b/DEPS index dc917af8b4..685ea75291 100644 --- a/DEPS +++ b/DEPS @@ -50,7 +50,7 @@ deps = { Var("chromium_git") + "/chromium/deps/icu@ef5c735307d0f86c7622f69620994c9468beba99", "src/packager/third_party/libwebm/src": - Var("chromium_git") + "/webm/libwebm@1ad314e297a43966605c4ef23a6442bb58e1d9be", + Var("chromium_git") + "/webm/libwebm@d6af52a1e688fade2e2d22b6d9b0c82f10d38e0b", "src/packager/third_party/modp_b64": Var("chromium_git") + "/chromium/src/third_party/modp_b64@aae60754fa997799e8037f5e8ca1f56d58df763d", #405651 diff --git a/packager/app/test/testdata/bear-320x240-opus-golden.webm b/packager/app/test/testdata/bear-320x240-opus-golden.webm index 3dc7e7e532..ed155bc28b 100644 Binary files a/packager/app/test/testdata/bear-320x240-opus-golden.webm and b/packager/app/test/testdata/bear-320x240-opus-golden.webm differ diff --git a/packager/app/test/testdata/bear-320x240-vorbis-golden.webm b/packager/app/test/testdata/bear-320x240-vorbis-golden.webm index 57b0b1e605..b764a53aa8 100644 Binary files a/packager/app/test/testdata/bear-320x240-vorbis-golden.webm and b/packager/app/test/testdata/bear-320x240-vorbis-golden.webm differ diff --git a/packager/app/test/testdata/bear-320x240-vorbis-webm-golden.mpd b/packager/app/test/testdata/bear-320x240-vorbis-webm-golden.mpd index d2d2096478..69dfdd1dc1 100644 --- a/packager/app/test/testdata/bear-320x240-vorbis-webm-golden.mpd +++ b/packager/app/test/testdata/bear-320x240-vorbis-webm-golden.mpd @@ -6,7 +6,7 @@ output_audio.webm - + diff --git a/packager/app/test/testdata/bear-320x240-vp9-golden.webm b/packager/app/test/testdata/bear-320x240-vp9-golden.webm index 3b18d7666f..0618a8009c 100644 Binary files a/packager/app/test/testdata/bear-320x240-vp9-golden.webm and b/packager/app/test/testdata/bear-320x240-vp9-golden.webm differ diff --git a/packager/app/test/testdata/bear-320x240-vp9-opus-webm-golden.mpd b/packager/app/test/testdata/bear-320x240-vp9-opus-webm-golden.mpd index 3efd0d4cfd..39376b4a83 100644 --- a/packager/app/test/testdata/bear-320x240-vp9-opus-webm-golden.mpd +++ b/packager/app/test/testdata/bear-320x240-vp9-opus-webm-golden.mpd @@ -6,15 +6,15 @@ output_audio.webm - + - + output_video.webm - + diff --git a/packager/app/test/testdata/bear-640x360-vp8-cenc-golden.webm b/packager/app/test/testdata/bear-640x360-vp8-cenc-golden.webm index 6a90df191b..91d57aa5fd 100644 Binary files a/packager/app/test/testdata/bear-640x360-vp8-cenc-golden.webm and b/packager/app/test/testdata/bear-640x360-vp8-cenc-golden.webm differ diff --git a/packager/app/test/testdata/bear-640x360-vp8-cenc-webm-golden.mpd b/packager/app/test/testdata/bear-640x360-vp8-cenc-webm-golden.mpd index cca18189b7..d2f0a15b71 100644 --- a/packager/app/test/testdata/bear-640x360-vp8-cenc-webm-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-vp8-cenc-webm-golden.mpd @@ -8,7 +8,7 @@ AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== output_video.webm - + diff --git a/packager/app/test/testdata/bear-640x360-vp8-golden.webm b/packager/app/test/testdata/bear-640x360-vp8-golden.webm index d9f9436ac9..5fa81b7d88 100644 Binary files a/packager/app/test/testdata/bear-640x360-vp8-golden.webm and b/packager/app/test/testdata/bear-640x360-vp8-golden.webm differ diff --git a/packager/app/test/testdata/bear-640x360-vp8-webm-golden.mpd b/packager/app/test/testdata/bear-640x360-vp8-webm-golden.mpd index c108e7f2b2..68a6b1d3ec 100644 --- a/packager/app/test/testdata/bear-640x360-vp8-webm-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-vp8-webm-golden.mpd @@ -3,9 +3,9 @@ - + output_video.webm - + diff --git a/packager/app/test/testdata/bear-640x360-vp9-altref-dec-golden.webm b/packager/app/test/testdata/bear-640x360-vp9-altref-dec-golden.webm index d5df056ea4..ae1c97b480 100644 Binary files a/packager/app/test/testdata/bear-640x360-vp9-altref-dec-golden.webm and b/packager/app/test/testdata/bear-640x360-vp9-altref-dec-golden.webm differ diff --git a/packager/app/test/testdata/bear-640x360-vp9-altref-enc-golden.webm b/packager/app/test/testdata/bear-640x360-vp9-altref-enc-golden.webm index 06b7a34567..6493afa80c 100644 Binary files a/packager/app/test/testdata/bear-640x360-vp9-altref-enc-golden.webm and b/packager/app/test/testdata/bear-640x360-vp9-altref-enc-golden.webm differ diff --git a/packager/app/test/testdata/bear-vp9-blockgroup-golden.webm b/packager/app/test/testdata/bear-vp9-blockgroup-golden.webm index 9ab11de170..aeda2e9b36 100644 Binary files a/packager/app/test/testdata/bear-vp9-blockgroup-golden.webm and b/packager/app/test/testdata/bear-vp9-blockgroup-golden.webm differ diff --git a/packager/media/formats/webm/encrypted_segmenter_unittest.cc b/packager/media/formats/webm/encrypted_segmenter_unittest.cc index 8af360d76f..b263f94d00 100644 --- a/packager/media/formats/webm/encrypted_segmenter_unittest.cc +++ b/packager/media/formats/webm/encrypted_segmenter_unittest.cc @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "packager/media/formats/webm/single_segment_segmenter.h" #include "packager/media/formats/webm/two_pass_single_segment_segmenter.h" #include @@ -39,16 +38,16 @@ const uint8_t kBasicSupportData[] = { 0x53, 0xac, 0x81, 0xb6, // ID: Seek, Payload Size: 12 0x4d, 0xbb, 0x8c, - // SeekID: binary(4) (Cluster) - 0x53, 0xab, 0x84, 0x1f, 0x43, 0xb6, 0x75, + // SeekID: binary(4) (Cues) + 0x53, 0xab, 0x84, 0x1c, 0x53, 0xbb, 0x6b, // SeekPosition: 279 0x53, 0xac, 0x82, 0x01, 0x17, // ID: Seek, Payload Size: 12 0x4d, 0xbb, 0x8c, - // SeekID: binary(4) (Cues) - 0x53, 0xab, 0x84, 0x1c, 0x53, 0xbb, 0x6b, - // SeekPosition: 398 - 0x53, 0xac, 0x82, 0x01, 0x8e, + // SeekID: binary(4) (Cluster) + 0x53, 0xab, 0x84, 0x1f, 0x43, 0xb6, 0x75, + // SeekPosition: 313 + 0x53, 0xac, 0x82, 0x01, 0x39, // ID: Void, Payload Size: 24 0xec, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -115,6 +114,28 @@ const uint8_t kBasicSupportData[] = { 0x54, 0xb0, 0x81, 0x64, // DisplayHeight: 100 0x54, 0xba, 0x81, 0x64, + // ID: Cues, Payload Size: 29 + 0x1c, 0x53, 0xbb, 0x6b, 0x9d, + // ID: CuePoint, Payload Size: 12 + 0xbb, 0x8c, + // CueTime: 0 + 0xb3, 0x81, 0x00, + // ID: CueTrackPositions, Payload Size: 7 + 0xb7, 0x87, + // CueTrack: 1 + 0xf7, 0x81, 0x01, + // CueClusterPosition: 313 + 0xf1, 0x82, 0x01, 0x39, + // ID: CuePoint, Payload Size: 13 + 0xbb, 0x8d, + // CueTime: 3000 + 0xb3, 0x82, 0x0b, 0xb8, + // ID: CueTrackPositions, Payload Size: 7 + 0xb7, 0x87, + // CueTrack: 1 + 0xf7, 0x81, 0x01, + // CueClusterPosition: 370 + 0xf1, 0x82, 0x01, 0x72, // ID: Cluster, Payload Size: 45 0x1f, 0x43, 0xb6, 0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, // Timecode: 0 @@ -165,28 +186,6 @@ const uint8_t kBasicSupportData[] = { 0xbf, 0x38, 0x72, 0x20, 0xac, // BlockDuration: 1000 0x9b, 0x82, 0x03, 0xe8, - // ID: Cues, Payload Size: 29 - 0x1c, 0x53, 0xbb, 0x6b, 0x9d, - // ID: CuePoint, Payload Size: 12 - 0xbb, 0x8c, - // CueTime: 0 - 0xb3, 0x81, 0x00, - // ID: CueTrackPositions, Payload Size: 7 - 0xb7, 0x87, - // CueTrack: 1 - 0xf7, 0x81, 0x01, - // CueClusterPosition: 279 - 0xf1, 0x82, 0x01, 0x17, - // ID: CuePoint, Payload Size: 13 - 0xbb, 0x8d, - // CueTime: 3000 - 0xb3, 0x82, 0x0b, 0xb8, - // ID: CueTrackPositions, Payload Size: 7 - 0xb7, 0x87, - // CueTrack: 1 - 0xf7, 0x81, 0x01, - // CueClusterPosition: 336 - 0xf1, 0x82, 0x01, 0x50, }; } // namespace @@ -200,7 +199,7 @@ class EncrypedSegmenterTest : public SegmentTestBase { key_source_ = FixedKeySource::CreateFromHexStrings(kKeyId, kKey, kPsshData, kIv); ASSERT_NO_FATAL_FAILURE( - CreateAndInitializeSegmenter( + CreateAndInitializeSegmenter( options, info_.get(), key_source_.get(), &segmenter_)); } diff --git a/packager/media/formats/webm/seek_head.cc b/packager/media/formats/webm/seek_head.cc index 15f21ea1b5..7579bd9513 100644 --- a/packager/media/formats/webm/seek_head.cc +++ b/packager/media/formats/webm/seek_head.cc @@ -6,19 +6,23 @@ #include "packager/media/formats/webm/seek_head.h" +#include #include +#include "packager/base/logging.h" #include "packager/third_party/libwebm/src/mkvmuxerutil.hpp" #include "packager/third_party/libwebm/src/webmids.hpp" namespace shaka { namespace media { namespace { -const mkvmuxer::uint64 kElementIds[] = { - mkvmuxer::kMkvInfo, mkvmuxer::kMkvTracks, mkvmuxer::kMkvCluster, - mkvmuxer::kMkvCues, -}; -const int kElementIdCount = arraysize(kElementIds); + +// Cluster, Cues, Info, Tracks. +const size_t kElementIdCount = 4u; + +uint64_t EbmlMasterElementWithPayloadSize(mkvmuxer::MkvId id, uint64_t payload_size) { + return EbmlMasterElementSize(id, payload_size) + payload_size; +} uint64_t MaxSeekEntrySize() { const uint64_t max_entry_payload_size = @@ -27,57 +31,46 @@ uint64_t MaxSeekEntrySize() { static_cast(std::numeric_limits::max())) + EbmlElementSize(mkvmuxer::kMkvSeekPosition, std::numeric_limits::max()); - const uint64_t max_entry_size = - EbmlMasterElementSize(mkvmuxer::kMkvSeek, max_entry_payload_size) + - max_entry_payload_size; - - return max_entry_size; + return EbmlMasterElementWithPayloadSize(mkvmuxer::kMkvSeek, + max_entry_payload_size); } + } // namespace SeekHead::SeekHead() - : cluster_pos_(-1), - cues_pos_(-1), - info_pos_(-1), - tracks_pos_(-1), - wrote_void_(false) {} + : total_void_size_(EbmlMasterElementWithPayloadSize( + mkvmuxer::kMkvSeekHead, + kElementIdCount * MaxSeekEntrySize())) {} SeekHead::~SeekHead() {} bool SeekHead::Write(mkvmuxer::IMkvWriter* writer) { - std::vector element_sizes; - const uint64_t payload_size = GetPayloadSize(&element_sizes); - - if (payload_size == 0) { + std::vector seek_elements = CreateSeekElements(); + if (seek_elements.empty()) return true; + + uint64_t payload_size = 0; + for (const SeekHead::SeekElement& seek_element : seek_elements) { + payload_size += + seek_element.size + + EbmlMasterElementSize(mkvmuxer::kMkvSeek, seek_element.size); } const int64_t start_pos = writer->Position(); if (!WriteEbmlMasterElement(writer, mkvmuxer::kMkvSeekHead, payload_size)) return false; - const int64_t positions[] = {info_pos_, tracks_pos_, cluster_pos_, cues_pos_}; - for (int i = 0; i < kElementIdCount; ++i) { - if (element_sizes[i] == 0) - continue; - - const mkvmuxer::uint64 position = - static_cast(positions[i]); - if (!WriteEbmlMasterElement(writer, mkvmuxer::kMkvSeek, element_sizes[i]) || - !WriteEbmlElement(writer, mkvmuxer::kMkvSeekID, kElementIds[i]) || - !WriteEbmlElement(writer, mkvmuxer::kMkvSeekPosition, position)) + for (const SeekHead::SeekElement& element : seek_elements) { + if (!WriteEbmlMasterElement(writer, mkvmuxer::kMkvSeek, element.size) || + !WriteEbmlElement(writer, mkvmuxer::kMkvSeekID, element.id) || + !WriteEbmlElement(writer, mkvmuxer::kMkvSeekPosition, element.position)) return false; } // If we wrote void before, then fill in the extra with void. if (wrote_void_) { - const uint64_t max_payload_size = kElementIdCount * MaxSeekEntrySize(); - const uint64_t total_void_size = - EbmlMasterElementSize(mkvmuxer::kMkvSeekHead, max_payload_size) + - max_payload_size; - const uint64_t extra_void = - total_void_size - (writer->Position() - start_pos); + total_void_size_ - (writer->Position() - start_pos); if (!WriteVoidElement(writer, extra_void)) return false; } @@ -86,38 +79,36 @@ bool SeekHead::Write(mkvmuxer::IMkvWriter* writer) { } bool SeekHead::WriteVoid(mkvmuxer::IMkvWriter* writer) { - const uint64_t payload_size = kElementIdCount * MaxSeekEntrySize(); - const uint64_t total_size = - EbmlMasterElementSize(mkvmuxer::kMkvSeekHead, payload_size) + - payload_size; - - wrote_void_ = true; - const uint64_t written = WriteVoidElement(writer, total_size); + const uint64_t written = WriteVoidElement(writer, total_void_size_); if (!written) return false; - + wrote_void_ = true; return true; } -uint64_t SeekHead::GetPayloadSize(std::vector* data) { - const int64_t positions[] = {info_pos_, tracks_pos_, cluster_pos_, cues_pos_}; - uint64_t total_payload_size = 0; - data->resize(kElementIdCount); - for (int i = 0; i < kElementIdCount; ++i) { - if (positions[i] < 0) { - (*data)[i] = 0; - continue; - } +std::vector SeekHead::CreateSeekElements() { + std::vector seek_elements; + if (info_pos_ != 0) + seek_elements.emplace_back(mkvmuxer::kMkvInfo, info_pos_); + if (tracks_pos_ != 0) + seek_elements.emplace_back(mkvmuxer::kMkvTracks, tracks_pos_); + if (cues_pos_ != 0) + seek_elements.emplace_back(mkvmuxer::kMkvCues, cues_pos_); + if (cluster_pos_ != 0) + seek_elements.emplace_back(mkvmuxer::kMkvCluster, cluster_pos_); + DCHECK_LE(seek_elements.size(), kElementIdCount); - const mkvmuxer::uint64 position = - static_cast(positions[i]); - (*data)[i] = EbmlElementSize(mkvmuxer::kMkvSeekID, kElementIds[i]) + - EbmlElementSize(mkvmuxer::kMkvSeekPosition, position); - total_payload_size += - data->at(i) + EbmlMasterElementSize(mkvmuxer::kMkvSeek, data->at(i)); + std::sort(seek_elements.begin(), seek_elements.end(), + [](const SeekHead::SeekElement& left, + const SeekHead::SeekElement& right) { + return left.position < right.position; + }); + for (SeekHead::SeekElement& element : seek_elements) { + element.size = + EbmlElementSize(mkvmuxer::kMkvSeekID, element.id) + + EbmlElementSize(mkvmuxer::kMkvSeekPosition, element.position); } - - return total_payload_size; + return seek_elements; } } // namespace media diff --git a/packager/media/formats/webm/seek_head.h b/packager/media/formats/webm/seek_head.h index ccd5188d85..a4c3c019d6 100644 --- a/packager/media/formats/webm/seek_head.h +++ b/packager/media/formats/webm/seek_head.h @@ -10,7 +10,6 @@ #include #include -#include "base/macros.h" #include "packager/third_party/libwebm/src/mkvmuxer.hpp" namespace shaka { @@ -35,15 +34,29 @@ class SeekHead { void set_tracks_pos(uint64_t pos) { tracks_pos_ = pos; } private: - uint64_t GetPayloadSize(std::vector* data); + SeekHead(const SeekHead&) = delete; + SeekHead& operator=(const SeekHead&) = delete; - int64_t cluster_pos_; - int64_t cues_pos_; - int64_t info_pos_; - int64_t tracks_pos_; - bool wrote_void_; + struct SeekElement { + mkvmuxer::uint64 id; + mkvmuxer::uint64 position; + mkvmuxer::uint64 size; - DISALLOW_COPY_AND_ASSIGN(SeekHead); + SeekElement(uint64_t seek_id, uint64_t seek_position) + : id(seek_id), position(seek_position), size(0) {} + }; + + // Create seek element vector from positions. + std::vector CreateSeekElements(); + + // In practice, these positions, if set, will never be 0, so we use a zero + // value to denote that they are not set. + uint64_t cluster_pos_ = 0; + uint64_t cues_pos_ = 0; + uint64_t info_pos_ = 0; + uint64_t tracks_pos_ = 0; + bool wrote_void_ = false; + const uint64_t total_void_size_ = 0; }; } // namespace media diff --git a/packager/media/formats/webm/single_segment_segmenter.h b/packager/media/formats/webm/single_segment_segmenter.h index 1044a810d5..ff8efd54f2 100644 --- a/packager/media/formats/webm/single_segment_segmenter.h +++ b/packager/media/formats/webm/single_segment_segmenter.h @@ -36,6 +36,7 @@ class SingleSegmentSegmenter : public Segmenter { protected: MkvWriter* writer() { return writer_.get(); } + uint64_t init_end() { return init_end_; } void set_init_end(uint64_t end) { init_end_ = end; } void set_index_start(uint64_t start) { index_start_ = start; } void set_index_end(uint64_t end) { index_end_ = end; } diff --git a/packager/media/formats/webm/single_segment_segmenter_unittest.cc b/packager/media/formats/webm/single_segment_segmenter_unittest.cc index f24bda7630..7f6d01a219 100644 --- a/packager/media/formats/webm/single_segment_segmenter_unittest.cc +++ b/packager/media/formats/webm/single_segment_segmenter_unittest.cc @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "packager/media/formats/webm/single_segment_segmenter.h" #include "packager/media/formats/webm/two_pass_single_segment_segmenter.h" #include @@ -20,7 +19,7 @@ const uint8_t kBasicSupportData[] = { // ID: Segment, Payload Size: 343 0x18, 0x53, 0x80, 0x67, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x57, // ID: SeekHead, Payload Size: 57 - 0x11, 0x4d, 0x9b, 0x74, 0xb9, + 0x11, 0x4d, 0x9b, 0x74, 0xb8, // ID: Seek, Payload Size: 11 0x4d, 0xbb, 0x8b, // SeekID: binary(4) (Info) @@ -33,22 +32,22 @@ const uint8_t kBasicSupportData[] = { 0x53, 0xab, 0x84, 0x16, 0x54, 0xae, 0x6b, // SeekPosition: 182 0x53, 0xac, 0x81, 0xb6, + // ID: Seek, Payload Size: 12 + 0x4d, 0xbb, 0x8b, + // SeekID: binary(4) (Cues) + 0x53, 0xab, 0x84, 0x1c, 0x53, 0xbb, 0x6b, + // SeekPosition: 228 + 0x53, 0xac, 0x81, 0xe4, // ID: Seek, Payload Size: 11 0x4d, 0xbb, 0x8b, // SeekID: binary(4) (Cluster) 0x53, 0xab, 0x84, 0x1f, 0x43, 0xb6, 0x75, - // SeekPosition: 228 - 0x53, 0xac, 0x81, 0xe4, - // ID: Seek, Payload Size: 12 - 0x4d, 0xbb, 0x8c, - // SeekID: binary(4) (Cues) - 0x53, 0xab, 0x84, 0x1c, 0x53, 0xbb, 0x6b, - // SeekPosition: 325 - 0x53, 0xac, 0x82, 0x01, 0x45, - // ID: Void, Payload Size: 25 - 0xec, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // SeekPosition: 246 + 0x53, 0xac, 0x81, 0xf6, + // ID: Void, Payload Size: 26 + 0xec, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // ID: Info, Payload Size: 88 0x15, 0x49, 0xa9, 0x66, 0xd8, // TimecodeScale: 1000000 @@ -89,6 +88,18 @@ const uint8_t kBasicSupportData[] = { 0x54, 0xb0, 0x81, 0x64, // DisplayHeight: 100 0x54, 0xba, 0x81, 0x64, + // ID: Cues, Payload Size: 13 + 0x1c, 0x53, 0xbb, 0x6b, 0x8d, + // ID: CuePoint, Payload Size: 11 + 0xbb, 0x8b, + // CueTime: 0 + 0xb3, 0x81, 0x00, + // ID: CueTrackPositions, Payload Size: 6 + 0xb7, 0x86, + // CueTrack: 1 + 0xf7, 0x81, 0x01, + // CueClusterPosition: 246 + 0xf1, 0x81, 0xf6, // ID: Cluster, Payload Size: 85 0x1f, 0x43, 0xb6, 0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, // Timecode: 0 @@ -117,48 +128,26 @@ const uint8_t kBasicSupportData[] = { 0xa1, 0x89, 0x81, 0x0f, 0xa0, 0x00, 0xde, 0xad, 0xbe, 0xef, 0x00, // BlockDuration: 1000 0x9b, 0x82, 0x03, 0xe8, - // ID: Cues, Payload Size: 13 - 0x1c, 0x53, 0xbb, 0x6b, 0x8d, - // ID: CuePoint, Payload Size: 11 - 0xbb, 0x8b, - // CueTime: 0 - 0xb3, 0x81, 0x00, - // ID: CueTrackPositions, Payload Size: 6 - 0xb7, 0x86, - // CueTrack: 1 - 0xf7, 0x81, 0x01, - // CueClusterPosition: 228 - 0xf1, 0x81, 0xe4 }; } // namespace -// This is a parameterized test that tests both SingleSegmentSegmenter and -// TwoPassSingleSegmentSegmenter, since they should provide the exact same -// output. -class SingleSegmentSegmenterTest : public SegmentTestBase, - public ::testing::WithParamInterface { +class SingleSegmentSegmenterTest : public SegmentTestBase { public: SingleSegmentSegmenterTest() : info_(CreateVideoStreamInfo()) {} protected: void InitializeSegmenter(const MuxerOptions& options) { - if (!GetParam()) { - ASSERT_NO_FATAL_FAILURE( - CreateAndInitializeSegmenter( - options, info_.get(), NULL, &segmenter_)); - } else { - ASSERT_NO_FATAL_FAILURE( - CreateAndInitializeSegmenter( - options, info_.get(), NULL, &segmenter_)); - } + ASSERT_NO_FATAL_FAILURE( + CreateAndInitializeSegmenter( + options, info_.get(), NULL, &segmenter_)); } scoped_refptr info_; std::unique_ptr segmenter_; }; -TEST_P(SingleSegmentSegmenterTest, BasicSupport) { +TEST_F(SingleSegmentSegmenterTest, BasicSupport) { MuxerOptions options = CreateMuxerOptions(); ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options)); @@ -175,7 +164,7 @@ TEST_P(SingleSegmentSegmenterTest, BasicSupport) { ASSERT_FILE_ENDS_WITH(OutputFileName().c_str(), kBasicSupportData); } -TEST_P(SingleSegmentSegmenterTest, SplitsClustersOnSegmentDuration) { +TEST_F(SingleSegmentSegmenterTest, SplitsClustersOnSegmentDuration) { MuxerOptions options = CreateMuxerOptions(); options.segment_duration = 4.5; // seconds ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options)); @@ -196,7 +185,7 @@ TEST_P(SingleSegmentSegmenterTest, SplitsClustersOnSegmentDuration) { EXPECT_EQ(3, parser.GetFrameCountForCluster(1)); } -TEST_P(SingleSegmentSegmenterTest, IgnoresFragmentDuration) { +TEST_F(SingleSegmentSegmenterTest, IgnoresFragmentDuration) { MuxerOptions options = CreateMuxerOptions(); options.fragment_duration = 5; // seconds ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options)); @@ -216,7 +205,7 @@ TEST_P(SingleSegmentSegmenterTest, IgnoresFragmentDuration) { EXPECT_EQ(8, parser.GetFrameCountForCluster(0)); } -TEST_P(SingleSegmentSegmenterTest, RespectsSAPAlign) { +TEST_F(SingleSegmentSegmenterTest, RespectsSAPAlign) { MuxerOptions options = CreateMuxerOptions(); options.segment_duration = 3; // seconds options.segment_sap_aligned = true; @@ -242,9 +231,5 @@ TEST_P(SingleSegmentSegmenterTest, RespectsSAPAlign) { EXPECT_EQ(4, parser.GetFrameCountForCluster(1)); } -INSTANTIATE_TEST_CASE_P(TrueIsTwoPass, - SingleSegmentSegmenterTest, - ::testing::Bool()); - } // namespace media } // namespace shaka diff --git a/packager/media/formats/webm/two_pass_single_segment_segmenter.cc b/packager/media/formats/webm/two_pass_single_segment_segmenter.cc index a8166c4248..52a7c63758 100644 --- a/packager/media/formats/webm/two_pass_single_segment_segmenter.cc +++ b/packager/media/formats/webm/two_pass_single_segment_segmenter.cc @@ -28,6 +28,26 @@ namespace shaka { namespace media { namespace webm { namespace { +// Cues will be inserted before clusters. All clusters will be shifted down by +// the size of cues. However, cluster positions affect the size of cues. This +// function adjusts cues size iteratively until it is stable. +// Returns the size of updated Cues. +uint64_t UpdateCues(mkvmuxer::Cues* cues) { + uint64_t cues_size = cues->Size(); + uint64_t adjustment = cues_size; + while (adjustment != 0) { + for (int i = 0; i < cues->cue_entries_size(); ++i) { + mkvmuxer::CuePoint* cue = cues->GetCueByIndex(i); + cue->set_cluster_pos(cue->cluster_pos() + adjustment); + } + uint64_t new_cues_size = cues->Size(); + DCHECK_LE(cues_size, new_cues_size); + adjustment = new_cues_size - cues_size; + cues_size = new_cues_size; + } + return cues_size; +} + /// Create the temp file name using process/thread id and current time. std::string TempFileName(const MuxerOptions& options) { // TODO: Move to a common util function and remove other uses. @@ -93,17 +113,26 @@ Status TwoPassSingleSegmentSegmenter::DoFinalize() { if (!cluster()->Finalize()) return Status(error::FILE_FAILURE, "Error finalizing cluster."); - // Write the Cues to the end of the temp file. - uint64_t cues_pos = writer()->Position(); - set_index_start(cues_pos); - seek_head()->set_cues_pos(cues_pos - segment_payload_pos()); - if (!cues()->Write(writer())) - return Status(error::FILE_FAILURE, "Error writing Cues data."); + const uint64_t header_size = init_end() + 1; + const uint64_t cues_pos = header_size - segment_payload_pos(); + const uint64_t cues_size = UpdateCues(cues()); + seek_head()->set_cues_pos(cues_pos); + seek_head()->set_cluster_pos(cues_pos + cues_size); // Write the header to the real output file. - Status temp = WriteSegmentHeader(writer()->Position(), real_writer_.get()); + const uint64_t file_size = writer()->Position() + cues_size; + Status temp = WriteSegmentHeader(file_size, real_writer_.get()); if (!temp.ok()) return temp; + DCHECK_EQ(real_writer_->Position(), static_cast(header_size)); + + // Write the cues to the real output file. + set_index_start(real_writer_->Position()); + if (!cues()->Write(real_writer_.get())) + return Status(error::FILE_FAILURE, "Error writing Cues data."); + set_index_end(real_writer_->Position() - 1); + DCHECK_EQ(real_writer_->Position(), + static_cast(segment_payload_pos() + cues_pos + cues_size)); // Close the temp file and open it for reading. set_writer(std::unique_ptr()); @@ -113,14 +142,14 @@ Status TwoPassSingleSegmentSegmenter::DoFinalize() { return Status(error::FILE_FAILURE, "Error opening temp file."); // Skip the header that has already been written. - uint64_t header_size = real_writer_->Position(); if (!ReadSkip(temp_reader.get(), header_size)) return Status(error::FILE_FAILURE, "Error reading temp file."); // Copy the rest of the data over. if (!CopyFileWithClusterRewrite(temp_reader.get(), real_writer_.get(), - cluster()->Size())) + cluster()->Size())) { return Status(error::FILE_FAILURE, "Error copying temp file."); + } // Close and delete the temp file. temp_reader.reset(); @@ -128,8 +157,6 @@ Status TwoPassSingleSegmentSegmenter::DoFinalize() { LOG(WARNING) << "Unable to delete temporary file " << temp_file_name_; } - // The WebM index is at the end of the file. - set_index_end(real_writer_->file()->Size() - 1); return real_writer_->Close(); } @@ -175,9 +202,9 @@ bool TwoPassSingleSegmentSegmenter::CopyFileWithClusterRewrite( if (!ReadSkip(source, cluster_size_size)) return false; - // Copy the remaining data (i.e. Cues data). + // Copy the last cluster. return dest->WriteFromFile(source) == - static_cast(last_cluster_payload_size + cues()->Size()); + static_cast(last_cluster_payload_size); } } // namespace webm diff --git a/packager/media/formats/webm/webm.gyp b/packager/media/formats/webm/webm.gyp index 7557405d27..1aeb63c9ec 100644 --- a/packager/media/formats/webm/webm.gyp +++ b/packager/media/formats/webm/webm.gyp @@ -84,6 +84,7 @@ 'dependencies': [ '../../../testing/gtest.gyp:gtest', '../../../testing/gmock.gyp:gmock', + '../../../third_party/libwebm/libwebm.gyp:mkvmuxer', '../../file/file.gyp:file', '../../test/media_test.gyp:media_test_support', 'webm', diff --git a/packager/media/formats/webm/webm_muxer.cc b/packager/media/formats/webm/webm_muxer.cc index d4ac37db70..3f3d55e552 100644 --- a/packager/media/formats/webm/webm_muxer.cc +++ b/packager/media/formats/webm/webm_muxer.cc @@ -45,8 +45,6 @@ Status WebMMuxer::Initialize() { if (!options().single_segment) { segmenter_.reset(new MultiSegmentSegmenter(options())); - } else if (writer->Seekable()) { - segmenter_.reset(new SingleSegmentSegmenter(options())); } else { segmenter_.reset(new TwoPassSingleSegmentSegmenter(options())); } diff --git a/packager/third_party/libwebm/libwebm.gyp b/packager/third_party/libwebm/libwebm.gyp index 882a43023f..0d4bcabb48 100644 --- a/packager/third_party/libwebm/libwebm.gyp +++ b/packager/third_party/libwebm/libwebm.gyp @@ -12,13 +12,26 @@ 'target_name': 'mkvmuxer', 'type': 'static_library', 'sources': [ - 'src/mkvmuxer.cpp', - 'src/mkvmuxer.hpp', - 'src/mkvmuxerutil.cpp', - 'src/mkvmuxerutil.hpp', - 'src/mkvwriter.cpp', - 'src/mkvwriter.hpp', + 'src/common/webmids.h', + 'src/mkvmuxer/mkvmuxer.cc', + 'src/mkvmuxer/mkvmuxer.h', + 'src/mkvmuxer/mkvmuxertypes.h', + 'src/mkvmuxer/mkvmuxerutil.cc', + 'src/mkvmuxer/mkvmuxerutil.h', + 'src/mkvmuxer/mkvwriter.cc', + 'src/mkvmuxer/mkvwriter.h', + 'src/mkvmuxer.hpp' + 'src/mkvmuxerutil.hpp' + 'src/webmids.hpp' ], + 'include_dirs': [ + 'src', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + 'src', + ], + }, }, ], }