[WebM] Move index segment after init segment
Cues used to be generated in the end of the file; if http range request is not supported, clients have to download the whole file to get to the cues. This CL updated TwoPassSingleSegmentSegmenter to write cues after writing webm header. This CL also updates libwebm dependency to latest. Closes #159 Change-Id: Ic73548e1b872e6b13a37627707e7d0ff3e556877
This commit is contained in:
parent
ac1d2692cf
commit
97fc9828f0
2
DEPS
2
DEPS
|
@ -50,7 +50,7 @@ deps = {
|
||||||
Var("chromium_git") + "/chromium/deps/icu@ef5c735307d0f86c7622f69620994c9468beba99",
|
Var("chromium_git") + "/chromium/deps/icu@ef5c735307d0f86c7622f69620994c9468beba99",
|
||||||
|
|
||||||
"src/packager/third_party/libwebm/src":
|
"src/packager/third_party/libwebm/src":
|
||||||
Var("chromium_git") + "/webm/libwebm@1ad314e297a43966605c4ef23a6442bb58e1d9be",
|
Var("chromium_git") + "/webm/libwebm@d6af52a1e688fade2e2d22b6d9b0c82f10d38e0b",
|
||||||
|
|
||||||
"src/packager/third_party/modp_b64":
|
"src/packager/third_party/modp_b64":
|
||||||
Var("chromium_git") + "/chromium/src/third_party/modp_b64@aae60754fa997799e8037f5e8ca1f56d58df763d", #405651
|
Var("chromium_git") + "/chromium/src/third_party/modp_b64@aae60754fa997799e8037f5e8ca1f56d58df763d", #405651
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -6,7 +6,7 @@
|
||||||
<Representation id="0" bandwidth="69362" codecs="vorbis" mimeType="audio/webm" audioSamplingRate="44100">
|
<Representation id="0" bandwidth="69362" codecs="vorbis" mimeType="audio/webm" audioSamplingRate="44100">
|
||||||
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||||
<BaseURL>output_audio.webm</BaseURL>
|
<BaseURL>output_audio.webm</BaseURL>
|
||||||
<SegmentBase indexRange="23950-23998" timescale="1000000">
|
<SegmentBase indexRange="4159-4207" timescale="1000000">
|
||||||
<Initialization range="0-4158"/>
|
<Initialization range="0-4158"/>
|
||||||
</SegmentBase>
|
</SegmentBase>
|
||||||
</Representation>
|
</Representation>
|
||||||
|
|
Binary file not shown.
|
@ -6,15 +6,15 @@
|
||||||
<Representation id="0" bandwidth="76531" codecs="opus" mimeType="audio/webm" audioSamplingRate="48000">
|
<Representation id="0" bandwidth="76531" codecs="opus" mimeType="audio/webm" audioSamplingRate="48000">
|
||||||
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||||
<BaseURL>output_audio.webm</BaseURL>
|
<BaseURL>output_audio.webm</BaseURL>
|
||||||
<SegmentBase indexRange="26555-26603" timescale="1000000">
|
<SegmentBase indexRange="323-371" timescale="1000000">
|
||||||
<Initialization range="0-322"/>
|
<Initialization range="0-322"/>
|
||||||
</SegmentBase>
|
</SegmentBase>
|
||||||
</Representation>
|
</Representation>
|
||||||
</AdaptationSet>
|
</AdaptationSet>
|
||||||
<AdaptationSet id="1" contentType="video" width="320" height="240" frameRate="1000000/34000" par="16:9">
|
<AdaptationSet id="1" contentType="video" width="320" height="240" frameRate="1000000/34000" par="16:9">
|
||||||
<Representation id="1" bandwidth="203348" codecs="vp9" mimeType="video/webm" sar="427:320">
|
<Representation id="1" bandwidth="203351" codecs="vp9" mimeType="video/webm" sar="427:320">
|
||||||
<BaseURL>output_video.webm</BaseURL>
|
<BaseURL>output_video.webm</BaseURL>
|
||||||
<SegmentBase indexRange="69497-69544" timescale="1000000">
|
<SegmentBase indexRange="299-347" timescale="1000000">
|
||||||
<Initialization range="0-298"/>
|
<Initialization range="0-298"/>
|
||||||
</SegmentBase>
|
</SegmentBase>
|
||||||
</Representation>
|
</Representation>
|
||||||
|
|
Binary file not shown.
|
@ -8,7 +8,7 @@
|
||||||
<cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA==</cenc:pssh>
|
<cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA==</cenc:pssh>
|
||||||
</ContentProtection>
|
</ContentProtection>
|
||||||
<BaseURL>output_video.webm</BaseURL>
|
<BaseURL>output_video.webm</BaseURL>
|
||||||
<SegmentBase indexRange="115225-115274" timescale="1000000">
|
<SegmentBase indexRange="340-389" timescale="1000000">
|
||||||
<Initialization range="0-339"/>
|
<Initialization range="0-339"/>
|
||||||
</SegmentBase>
|
</SegmentBase>
|
||||||
</Representation>
|
</Representation>
|
||||||
|
|
Binary file not shown.
|
@ -3,9 +3,9 @@
|
||||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.736S">
|
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.736S">
|
||||||
<Period id="0">
|
<Period id="0">
|
||||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="1000000/33000" par="16:9">
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="1000000/33000" par="16:9">
|
||||||
<Representation id="0" bandwidth="335454" codecs="vp8" mimeType="video/webm" sar="1:1">
|
<Representation id="0" bandwidth="335457" codecs="vp8" mimeType="video/webm" sar="1:1">
|
||||||
<BaseURL>output_video.webm</BaseURL>
|
<BaseURL>output_video.webm</BaseURL>
|
||||||
<SegmentBase indexRange="114676-114724" timescale="1000000">
|
<SegmentBase indexRange="289-338" timescale="1000000">
|
||||||
<Initialization range="0-288"/>
|
<Initialization range="0-288"/>
|
||||||
</SegmentBase>
|
</SegmentBase>
|
||||||
</Representation>
|
</Representation>
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -2,7 +2,6 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// 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 "packager/media/formats/webm/two_pass_single_segment_segmenter.h"
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
@ -39,16 +38,16 @@ const uint8_t kBasicSupportData[] = {
|
||||||
0x53, 0xac, 0x81, 0xb6,
|
0x53, 0xac, 0x81, 0xb6,
|
||||||
// ID: Seek, Payload Size: 12
|
// ID: Seek, Payload Size: 12
|
||||||
0x4d, 0xbb, 0x8c,
|
0x4d, 0xbb, 0x8c,
|
||||||
// SeekID: binary(4) (Cluster)
|
// SeekID: binary(4) (Cues)
|
||||||
0x53, 0xab, 0x84, 0x1f, 0x43, 0xb6, 0x75,
|
0x53, 0xab, 0x84, 0x1c, 0x53, 0xbb, 0x6b,
|
||||||
// SeekPosition: 279
|
// SeekPosition: 279
|
||||||
0x53, 0xac, 0x82, 0x01, 0x17,
|
0x53, 0xac, 0x82, 0x01, 0x17,
|
||||||
// ID: Seek, Payload Size: 12
|
// ID: Seek, Payload Size: 12
|
||||||
0x4d, 0xbb, 0x8c,
|
0x4d, 0xbb, 0x8c,
|
||||||
// SeekID: binary(4) (Cues)
|
// SeekID: binary(4) (Cluster)
|
||||||
0x53, 0xab, 0x84, 0x1c, 0x53, 0xbb, 0x6b,
|
0x53, 0xab, 0x84, 0x1f, 0x43, 0xb6, 0x75,
|
||||||
// SeekPosition: 398
|
// SeekPosition: 313
|
||||||
0x53, 0xac, 0x82, 0x01, 0x8e,
|
0x53, 0xac, 0x82, 0x01, 0x39,
|
||||||
// ID: Void, Payload Size: 24
|
// ID: Void, Payload Size: 24
|
||||||
0xec, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0xec, 0x98, 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, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
@ -115,6 +114,28 @@ const uint8_t kBasicSupportData[] = {
|
||||||
0x54, 0xb0, 0x81, 0x64,
|
0x54, 0xb0, 0x81, 0x64,
|
||||||
// DisplayHeight: 100
|
// DisplayHeight: 100
|
||||||
0x54, 0xba, 0x81, 0x64,
|
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
|
// ID: Cluster, Payload Size: 45
|
||||||
0x1f, 0x43, 0xb6, 0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d,
|
0x1f, 0x43, 0xb6, 0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d,
|
||||||
// Timecode: 0
|
// Timecode: 0
|
||||||
|
@ -165,28 +186,6 @@ const uint8_t kBasicSupportData[] = {
|
||||||
0xbf, 0x38, 0x72, 0x20, 0xac,
|
0xbf, 0x38, 0x72, 0x20, 0xac,
|
||||||
// BlockDuration: 1000
|
// BlockDuration: 1000
|
||||||
0x9b, 0x82, 0x03, 0xe8,
|
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
|
} // namespace
|
||||||
|
@ -200,7 +199,7 @@ class EncrypedSegmenterTest : public SegmentTestBase {
|
||||||
key_source_ =
|
key_source_ =
|
||||||
FixedKeySource::CreateFromHexStrings(kKeyId, kKey, kPsshData, kIv);
|
FixedKeySource::CreateFromHexStrings(kKeyId, kKey, kPsshData, kIv);
|
||||||
ASSERT_NO_FATAL_FAILURE(
|
ASSERT_NO_FATAL_FAILURE(
|
||||||
CreateAndInitializeSegmenter<webm::SingleSegmentSegmenter>(
|
CreateAndInitializeSegmenter<webm::TwoPassSingleSegmentSegmenter>(
|
||||||
options, info_.get(), key_source_.get(), &segmenter_));
|
options, info_.get(), key_source_.get(), &segmenter_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,19 +6,23 @@
|
||||||
|
|
||||||
#include "packager/media/formats/webm/seek_head.h"
|
#include "packager/media/formats/webm/seek_head.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
|
#include "packager/base/logging.h"
|
||||||
#include "packager/third_party/libwebm/src/mkvmuxerutil.hpp"
|
#include "packager/third_party/libwebm/src/mkvmuxerutil.hpp"
|
||||||
#include "packager/third_party/libwebm/src/webmids.hpp"
|
#include "packager/third_party/libwebm/src/webmids.hpp"
|
||||||
|
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
namespace media {
|
namespace media {
|
||||||
namespace {
|
namespace {
|
||||||
const mkvmuxer::uint64 kElementIds[] = {
|
|
||||||
mkvmuxer::kMkvInfo, mkvmuxer::kMkvTracks, mkvmuxer::kMkvCluster,
|
// Cluster, Cues, Info, Tracks.
|
||||||
mkvmuxer::kMkvCues,
|
const size_t kElementIdCount = 4u;
|
||||||
};
|
|
||||||
const int kElementIdCount = arraysize(kElementIds);
|
uint64_t EbmlMasterElementWithPayloadSize(mkvmuxer::MkvId id, uint64_t payload_size) {
|
||||||
|
return EbmlMasterElementSize(id, payload_size) + payload_size;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t MaxSeekEntrySize() {
|
uint64_t MaxSeekEntrySize() {
|
||||||
const uint64_t max_entry_payload_size =
|
const uint64_t max_entry_payload_size =
|
||||||
|
@ -27,57 +31,46 @@ uint64_t MaxSeekEntrySize() {
|
||||||
static_cast<mkvmuxer::uint64>(std::numeric_limits<uint32_t>::max())) +
|
static_cast<mkvmuxer::uint64>(std::numeric_limits<uint32_t>::max())) +
|
||||||
EbmlElementSize(mkvmuxer::kMkvSeekPosition,
|
EbmlElementSize(mkvmuxer::kMkvSeekPosition,
|
||||||
std::numeric_limits<mkvmuxer::uint64>::max());
|
std::numeric_limits<mkvmuxer::uint64>::max());
|
||||||
const uint64_t max_entry_size =
|
return EbmlMasterElementWithPayloadSize(mkvmuxer::kMkvSeek,
|
||||||
EbmlMasterElementSize(mkvmuxer::kMkvSeek, max_entry_payload_size) +
|
max_entry_payload_size);
|
||||||
max_entry_payload_size;
|
|
||||||
|
|
||||||
return max_entry_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
SeekHead::SeekHead()
|
SeekHead::SeekHead()
|
||||||
: cluster_pos_(-1),
|
: total_void_size_(EbmlMasterElementWithPayloadSize(
|
||||||
cues_pos_(-1),
|
mkvmuxer::kMkvSeekHead,
|
||||||
info_pos_(-1),
|
kElementIdCount * MaxSeekEntrySize())) {}
|
||||||
tracks_pos_(-1),
|
|
||||||
wrote_void_(false) {}
|
|
||||||
|
|
||||||
SeekHead::~SeekHead() {}
|
SeekHead::~SeekHead() {}
|
||||||
|
|
||||||
bool SeekHead::Write(mkvmuxer::IMkvWriter* writer) {
|
bool SeekHead::Write(mkvmuxer::IMkvWriter* writer) {
|
||||||
std::vector<uint64_t> element_sizes;
|
std::vector<SeekElement> seek_elements = CreateSeekElements();
|
||||||
const uint64_t payload_size = GetPayloadSize(&element_sizes);
|
if (seek_elements.empty())
|
||||||
|
|
||||||
if (payload_size == 0) {
|
|
||||||
return true;
|
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();
|
const int64_t start_pos = writer->Position();
|
||||||
if (!WriteEbmlMasterElement(writer, mkvmuxer::kMkvSeekHead, payload_size))
|
if (!WriteEbmlMasterElement(writer, mkvmuxer::kMkvSeekHead, payload_size))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const int64_t positions[] = {info_pos_, tracks_pos_, cluster_pos_, cues_pos_};
|
for (const SeekHead::SeekElement& element : seek_elements) {
|
||||||
for (int i = 0; i < kElementIdCount; ++i) {
|
if (!WriteEbmlMasterElement(writer, mkvmuxer::kMkvSeek, element.size) ||
|
||||||
if (element_sizes[i] == 0)
|
!WriteEbmlElement(writer, mkvmuxer::kMkvSeekID, element.id) ||
|
||||||
continue;
|
!WriteEbmlElement(writer, mkvmuxer::kMkvSeekPosition, element.position))
|
||||||
|
|
||||||
const mkvmuxer::uint64 position =
|
|
||||||
static_cast<mkvmuxer::uint64>(positions[i]);
|
|
||||||
if (!WriteEbmlMasterElement(writer, mkvmuxer::kMkvSeek, element_sizes[i]) ||
|
|
||||||
!WriteEbmlElement(writer, mkvmuxer::kMkvSeekID, kElementIds[i]) ||
|
|
||||||
!WriteEbmlElement(writer, mkvmuxer::kMkvSeekPosition, position))
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we wrote void before, then fill in the extra with void.
|
// If we wrote void before, then fill in the extra with void.
|
||||||
if (wrote_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 =
|
const uint64_t extra_void =
|
||||||
total_void_size - (writer->Position() - start_pos);
|
total_void_size_ - (writer->Position() - start_pos);
|
||||||
if (!WriteVoidElement(writer, extra_void))
|
if (!WriteVoidElement(writer, extra_void))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -86,38 +79,36 @@ bool SeekHead::Write(mkvmuxer::IMkvWriter* writer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SeekHead::WriteVoid(mkvmuxer::IMkvWriter* writer) {
|
bool SeekHead::WriteVoid(mkvmuxer::IMkvWriter* writer) {
|
||||||
const uint64_t payload_size = kElementIdCount * MaxSeekEntrySize();
|
const uint64_t written = WriteVoidElement(writer, total_void_size_);
|
||||||
const uint64_t total_size =
|
|
||||||
EbmlMasterElementSize(mkvmuxer::kMkvSeekHead, payload_size) +
|
|
||||||
payload_size;
|
|
||||||
|
|
||||||
wrote_void_ = true;
|
|
||||||
const uint64_t written = WriteVoidElement(writer, total_size);
|
|
||||||
if (!written)
|
if (!written)
|
||||||
return false;
|
return false;
|
||||||
|
wrote_void_ = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t SeekHead::GetPayloadSize(std::vector<uint64_t>* data) {
|
std::vector<SeekHead::SeekElement> SeekHead::CreateSeekElements() {
|
||||||
const int64_t positions[] = {info_pos_, tracks_pos_, cluster_pos_, cues_pos_};
|
std::vector<SeekHead::SeekElement> seek_elements;
|
||||||
uint64_t total_payload_size = 0;
|
if (info_pos_ != 0)
|
||||||
data->resize(kElementIdCount);
|
seek_elements.emplace_back(mkvmuxer::kMkvInfo, info_pos_);
|
||||||
for (int i = 0; i < kElementIdCount; ++i) {
|
if (tracks_pos_ != 0)
|
||||||
if (positions[i] < 0) {
|
seek_elements.emplace_back(mkvmuxer::kMkvTracks, tracks_pos_);
|
||||||
(*data)[i] = 0;
|
if (cues_pos_ != 0)
|
||||||
continue;
|
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 =
|
std::sort(seek_elements.begin(), seek_elements.end(),
|
||||||
static_cast<mkvmuxer::uint64>(positions[i]);
|
[](const SeekHead::SeekElement& left,
|
||||||
(*data)[i] = EbmlElementSize(mkvmuxer::kMkvSeekID, kElementIds[i]) +
|
const SeekHead::SeekElement& right) {
|
||||||
EbmlElementSize(mkvmuxer::kMkvSeekPosition, position);
|
return left.position < right.position;
|
||||||
total_payload_size +=
|
});
|
||||||
data->at(i) + EbmlMasterElementSize(mkvmuxer::kMkvSeek, data->at(i));
|
for (SeekHead::SeekElement& element : seek_elements) {
|
||||||
|
element.size =
|
||||||
|
EbmlElementSize(mkvmuxer::kMkvSeekID, element.id) +
|
||||||
|
EbmlElementSize(mkvmuxer::kMkvSeekPosition, element.position);
|
||||||
}
|
}
|
||||||
|
return seek_elements;
|
||||||
return total_payload_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "base/macros.h"
|
|
||||||
#include "packager/third_party/libwebm/src/mkvmuxer.hpp"
|
#include "packager/third_party/libwebm/src/mkvmuxer.hpp"
|
||||||
|
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
|
@ -35,15 +34,29 @@ class SeekHead {
|
||||||
void set_tracks_pos(uint64_t pos) { tracks_pos_ = pos; }
|
void set_tracks_pos(uint64_t pos) { tracks_pos_ = pos; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint64_t GetPayloadSize(std::vector<uint64_t>* data);
|
SeekHead(const SeekHead&) = delete;
|
||||||
|
SeekHead& operator=(const SeekHead&) = delete;
|
||||||
|
|
||||||
int64_t cluster_pos_;
|
struct SeekElement {
|
||||||
int64_t cues_pos_;
|
mkvmuxer::uint64 id;
|
||||||
int64_t info_pos_;
|
mkvmuxer::uint64 position;
|
||||||
int64_t tracks_pos_;
|
mkvmuxer::uint64 size;
|
||||||
bool wrote_void_;
|
|
||||||
|
|
||||||
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<SeekElement> 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
|
} // namespace media
|
||||||
|
|
|
@ -36,6 +36,7 @@ class SingleSegmentSegmenter : public Segmenter {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MkvWriter* writer() { return writer_.get(); }
|
MkvWriter* writer() { return writer_.get(); }
|
||||||
|
uint64_t init_end() { return init_end_; }
|
||||||
void set_init_end(uint64_t end) { init_end_ = end; }
|
void set_init_end(uint64_t end) { init_end_ = end; }
|
||||||
void set_index_start(uint64_t start) { index_start_ = start; }
|
void set_index_start(uint64_t start) { index_start_ = start; }
|
||||||
void set_index_end(uint64_t end) { index_end_ = end; }
|
void set_index_end(uint64_t end) { index_end_ = end; }
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// 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 "packager/media/formats/webm/two_pass_single_segment_segmenter.h"
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
@ -20,7 +19,7 @@ const uint8_t kBasicSupportData[] = {
|
||||||
// ID: Segment, Payload Size: 343
|
// ID: Segment, Payload Size: 343
|
||||||
0x18, 0x53, 0x80, 0x67, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x57,
|
0x18, 0x53, 0x80, 0x67, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x57,
|
||||||
// ID: SeekHead, Payload Size: 57
|
// ID: SeekHead, Payload Size: 57
|
||||||
0x11, 0x4d, 0x9b, 0x74, 0xb9,
|
0x11, 0x4d, 0x9b, 0x74, 0xb8,
|
||||||
// ID: Seek, Payload Size: 11
|
// ID: Seek, Payload Size: 11
|
||||||
0x4d, 0xbb, 0x8b,
|
0x4d, 0xbb, 0x8b,
|
||||||
// SeekID: binary(4) (Info)
|
// SeekID: binary(4) (Info)
|
||||||
|
@ -33,22 +32,22 @@ const uint8_t kBasicSupportData[] = {
|
||||||
0x53, 0xab, 0x84, 0x16, 0x54, 0xae, 0x6b,
|
0x53, 0xab, 0x84, 0x16, 0x54, 0xae, 0x6b,
|
||||||
// SeekPosition: 182
|
// SeekPosition: 182
|
||||||
0x53, 0xac, 0x81, 0xb6,
|
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
|
// ID: Seek, Payload Size: 11
|
||||||
0x4d, 0xbb, 0x8b,
|
0x4d, 0xbb, 0x8b,
|
||||||
// SeekID: binary(4) (Cluster)
|
// SeekID: binary(4) (Cluster)
|
||||||
0x53, 0xab, 0x84, 0x1f, 0x43, 0xb6, 0x75,
|
0x53, 0xab, 0x84, 0x1f, 0x43, 0xb6, 0x75,
|
||||||
// SeekPosition: 228
|
// SeekPosition: 246
|
||||||
0x53, 0xac, 0x81, 0xe4,
|
0x53, 0xac, 0x81, 0xf6,
|
||||||
// ID: Seek, Payload Size: 12
|
// ID: Void, Payload Size: 26
|
||||||
0x4d, 0xbb, 0x8c,
|
0xec, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
// 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,
|
|
||||||
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, 0x00, 0x00,
|
||||||
// ID: Info, Payload Size: 88
|
// ID: Info, Payload Size: 88
|
||||||
0x15, 0x49, 0xa9, 0x66, 0xd8,
|
0x15, 0x49, 0xa9, 0x66, 0xd8,
|
||||||
// TimecodeScale: 1000000
|
// TimecodeScale: 1000000
|
||||||
|
@ -89,6 +88,18 @@ const uint8_t kBasicSupportData[] = {
|
||||||
0x54, 0xb0, 0x81, 0x64,
|
0x54, 0xb0, 0x81, 0x64,
|
||||||
// DisplayHeight: 100
|
// DisplayHeight: 100
|
||||||
0x54, 0xba, 0x81, 0x64,
|
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
|
// ID: Cluster, Payload Size: 85
|
||||||
0x1f, 0x43, 0xb6, 0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55,
|
0x1f, 0x43, 0xb6, 0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55,
|
||||||
// Timecode: 0
|
// Timecode: 0
|
||||||
|
@ -117,48 +128,26 @@ const uint8_t kBasicSupportData[] = {
|
||||||
0xa1, 0x89, 0x81, 0x0f, 0xa0, 0x00, 0xde, 0xad, 0xbe, 0xef, 0x00,
|
0xa1, 0x89, 0x81, 0x0f, 0xa0, 0x00, 0xde, 0xad, 0xbe, 0xef, 0x00,
|
||||||
// BlockDuration: 1000
|
// BlockDuration: 1000
|
||||||
0x9b, 0x82, 0x03, 0xe8,
|
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
|
} // namespace
|
||||||
|
|
||||||
// This is a parameterized test that tests both SingleSegmentSegmenter and
|
class SingleSegmentSegmenterTest : public SegmentTestBase {
|
||||||
// TwoPassSingleSegmentSegmenter, since they should provide the exact same
|
|
||||||
// output.
|
|
||||||
class SingleSegmentSegmenterTest : public SegmentTestBase,
|
|
||||||
public ::testing::WithParamInterface<bool> {
|
|
||||||
public:
|
public:
|
||||||
SingleSegmentSegmenterTest() : info_(CreateVideoStreamInfo()) {}
|
SingleSegmentSegmenterTest() : info_(CreateVideoStreamInfo()) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void InitializeSegmenter(const MuxerOptions& options) {
|
void InitializeSegmenter(const MuxerOptions& options) {
|
||||||
if (!GetParam()) {
|
|
||||||
ASSERT_NO_FATAL_FAILURE(
|
|
||||||
CreateAndInitializeSegmenter<webm::SingleSegmentSegmenter>(
|
|
||||||
options, info_.get(), NULL, &segmenter_));
|
|
||||||
} else {
|
|
||||||
ASSERT_NO_FATAL_FAILURE(
|
ASSERT_NO_FATAL_FAILURE(
|
||||||
CreateAndInitializeSegmenter<webm::TwoPassSingleSegmentSegmenter>(
|
CreateAndInitializeSegmenter<webm::TwoPassSingleSegmentSegmenter>(
|
||||||
options, info_.get(), NULL, &segmenter_));
|
options, info_.get(), NULL, &segmenter_));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
scoped_refptr<StreamInfo> info_;
|
scoped_refptr<StreamInfo> info_;
|
||||||
std::unique_ptr<webm::Segmenter> segmenter_;
|
std::unique_ptr<webm::Segmenter> segmenter_;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_P(SingleSegmentSegmenterTest, BasicSupport) {
|
TEST_F(SingleSegmentSegmenterTest, BasicSupport) {
|
||||||
MuxerOptions options = CreateMuxerOptions();
|
MuxerOptions options = CreateMuxerOptions();
|
||||||
ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options));
|
ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options));
|
||||||
|
|
||||||
|
@ -175,7 +164,7 @@ TEST_P(SingleSegmentSegmenterTest, BasicSupport) {
|
||||||
ASSERT_FILE_ENDS_WITH(OutputFileName().c_str(), kBasicSupportData);
|
ASSERT_FILE_ENDS_WITH(OutputFileName().c_str(), kBasicSupportData);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(SingleSegmentSegmenterTest, SplitsClustersOnSegmentDuration) {
|
TEST_F(SingleSegmentSegmenterTest, SplitsClustersOnSegmentDuration) {
|
||||||
MuxerOptions options = CreateMuxerOptions();
|
MuxerOptions options = CreateMuxerOptions();
|
||||||
options.segment_duration = 4.5; // seconds
|
options.segment_duration = 4.5; // seconds
|
||||||
ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options));
|
ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options));
|
||||||
|
@ -196,7 +185,7 @@ TEST_P(SingleSegmentSegmenterTest, SplitsClustersOnSegmentDuration) {
|
||||||
EXPECT_EQ(3, parser.GetFrameCountForCluster(1));
|
EXPECT_EQ(3, parser.GetFrameCountForCluster(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(SingleSegmentSegmenterTest, IgnoresFragmentDuration) {
|
TEST_F(SingleSegmentSegmenterTest, IgnoresFragmentDuration) {
|
||||||
MuxerOptions options = CreateMuxerOptions();
|
MuxerOptions options = CreateMuxerOptions();
|
||||||
options.fragment_duration = 5; // seconds
|
options.fragment_duration = 5; // seconds
|
||||||
ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options));
|
ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options));
|
||||||
|
@ -216,7 +205,7 @@ TEST_P(SingleSegmentSegmenterTest, IgnoresFragmentDuration) {
|
||||||
EXPECT_EQ(8, parser.GetFrameCountForCluster(0));
|
EXPECT_EQ(8, parser.GetFrameCountForCluster(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(SingleSegmentSegmenterTest, RespectsSAPAlign) {
|
TEST_F(SingleSegmentSegmenterTest, RespectsSAPAlign) {
|
||||||
MuxerOptions options = CreateMuxerOptions();
|
MuxerOptions options = CreateMuxerOptions();
|
||||||
options.segment_duration = 3; // seconds
|
options.segment_duration = 3; // seconds
|
||||||
options.segment_sap_aligned = true;
|
options.segment_sap_aligned = true;
|
||||||
|
@ -242,9 +231,5 @@ TEST_P(SingleSegmentSegmenterTest, RespectsSAPAlign) {
|
||||||
EXPECT_EQ(4, parser.GetFrameCountForCluster(1));
|
EXPECT_EQ(4, parser.GetFrameCountForCluster(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTANTIATE_TEST_CASE_P(TrueIsTwoPass,
|
|
||||||
SingleSegmentSegmenterTest,
|
|
||||||
::testing::Bool());
|
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
} // namespace shaka
|
} // namespace shaka
|
||||||
|
|
|
@ -28,6 +28,26 @@ namespace shaka {
|
||||||
namespace media {
|
namespace media {
|
||||||
namespace webm {
|
namespace webm {
|
||||||
namespace {
|
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.
|
/// Create the temp file name using process/thread id and current time.
|
||||||
std::string TempFileName(const MuxerOptions& options) {
|
std::string TempFileName(const MuxerOptions& options) {
|
||||||
// TODO: Move to a common util function and remove other uses.
|
// TODO: Move to a common util function and remove other uses.
|
||||||
|
@ -93,17 +113,26 @@ Status TwoPassSingleSegmentSegmenter::DoFinalize() {
|
||||||
if (!cluster()->Finalize())
|
if (!cluster()->Finalize())
|
||||||
return Status(error::FILE_FAILURE, "Error finalizing cluster.");
|
return Status(error::FILE_FAILURE, "Error finalizing cluster.");
|
||||||
|
|
||||||
// Write the Cues to the end of the temp file.
|
const uint64_t header_size = init_end() + 1;
|
||||||
uint64_t cues_pos = writer()->Position();
|
const uint64_t cues_pos = header_size - segment_payload_pos();
|
||||||
set_index_start(cues_pos);
|
const uint64_t cues_size = UpdateCues(cues());
|
||||||
seek_head()->set_cues_pos(cues_pos - segment_payload_pos());
|
seek_head()->set_cues_pos(cues_pos);
|
||||||
if (!cues()->Write(writer()))
|
seek_head()->set_cluster_pos(cues_pos + cues_size);
|
||||||
return Status(error::FILE_FAILURE, "Error writing Cues data.");
|
|
||||||
|
|
||||||
// Write the header to the real output file.
|
// 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())
|
if (!temp.ok())
|
||||||
return temp;
|
return temp;
|
||||||
|
DCHECK_EQ(real_writer_->Position(), static_cast<int64_t>(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<int64_t>(segment_payload_pos() + cues_pos + cues_size));
|
||||||
|
|
||||||
// Close the temp file and open it for reading.
|
// Close the temp file and open it for reading.
|
||||||
set_writer(std::unique_ptr<MkvWriter>());
|
set_writer(std::unique_ptr<MkvWriter>());
|
||||||
|
@ -113,14 +142,14 @@ Status TwoPassSingleSegmentSegmenter::DoFinalize() {
|
||||||
return Status(error::FILE_FAILURE, "Error opening temp file.");
|
return Status(error::FILE_FAILURE, "Error opening temp file.");
|
||||||
|
|
||||||
// Skip the header that has already been written.
|
// Skip the header that has already been written.
|
||||||
uint64_t header_size = real_writer_->Position();
|
|
||||||
if (!ReadSkip(temp_reader.get(), header_size))
|
if (!ReadSkip(temp_reader.get(), header_size))
|
||||||
return Status(error::FILE_FAILURE, "Error reading temp file.");
|
return Status(error::FILE_FAILURE, "Error reading temp file.");
|
||||||
|
|
||||||
// Copy the rest of the data over.
|
// Copy the rest of the data over.
|
||||||
if (!CopyFileWithClusterRewrite(temp_reader.get(), real_writer_.get(),
|
if (!CopyFileWithClusterRewrite(temp_reader.get(), real_writer_.get(),
|
||||||
cluster()->Size()))
|
cluster()->Size())) {
|
||||||
return Status(error::FILE_FAILURE, "Error copying temp file.");
|
return Status(error::FILE_FAILURE, "Error copying temp file.");
|
||||||
|
}
|
||||||
|
|
||||||
// Close and delete the temp file.
|
// Close and delete the temp file.
|
||||||
temp_reader.reset();
|
temp_reader.reset();
|
||||||
|
@ -128,8 +157,6 @@ Status TwoPassSingleSegmentSegmenter::DoFinalize() {
|
||||||
LOG(WARNING) << "Unable to delete temporary file " << temp_file_name_;
|
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();
|
return real_writer_->Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,9 +202,9 @@ bool TwoPassSingleSegmentSegmenter::CopyFileWithClusterRewrite(
|
||||||
if (!ReadSkip(source, cluster_size_size))
|
if (!ReadSkip(source, cluster_size_size))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Copy the remaining data (i.e. Cues data).
|
// Copy the last cluster.
|
||||||
return dest->WriteFromFile(source) ==
|
return dest->WriteFromFile(source) ==
|
||||||
static_cast<int64_t>(last_cluster_payload_size + cues()->Size());
|
static_cast<int64_t>(last_cluster_payload_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace webm
|
} // namespace webm
|
||||||
|
|
|
@ -84,6 +84,7 @@
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
'../../../testing/gtest.gyp:gtest',
|
'../../../testing/gtest.gyp:gtest',
|
||||||
'../../../testing/gmock.gyp:gmock',
|
'../../../testing/gmock.gyp:gmock',
|
||||||
|
'../../../third_party/libwebm/libwebm.gyp:mkvmuxer',
|
||||||
'../../file/file.gyp:file',
|
'../../file/file.gyp:file',
|
||||||
'../../test/media_test.gyp:media_test_support',
|
'../../test/media_test.gyp:media_test_support',
|
||||||
'webm',
|
'webm',
|
||||||
|
|
|
@ -45,8 +45,6 @@ Status WebMMuxer::Initialize() {
|
||||||
|
|
||||||
if (!options().single_segment) {
|
if (!options().single_segment) {
|
||||||
segmenter_.reset(new MultiSegmentSegmenter(options()));
|
segmenter_.reset(new MultiSegmentSegmenter(options()));
|
||||||
} else if (writer->Seekable()) {
|
|
||||||
segmenter_.reset(new SingleSegmentSegmenter(options()));
|
|
||||||
} else {
|
} else {
|
||||||
segmenter_.reset(new TwoPassSingleSegmentSegmenter(options()));
|
segmenter_.reset(new TwoPassSingleSegmentSegmenter(options()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,26 @@
|
||||||
'target_name': 'mkvmuxer',
|
'target_name': 'mkvmuxer',
|
||||||
'type': 'static_library',
|
'type': 'static_library',
|
||||||
'sources': [
|
'sources': [
|
||||||
'src/mkvmuxer.cpp',
|
'src/common/webmids.h',
|
||||||
'src/mkvmuxer.hpp',
|
'src/mkvmuxer/mkvmuxer.cc',
|
||||||
'src/mkvmuxerutil.cpp',
|
'src/mkvmuxer/mkvmuxer.h',
|
||||||
'src/mkvmuxerutil.hpp',
|
'src/mkvmuxer/mkvmuxertypes.h',
|
||||||
'src/mkvwriter.cpp',
|
'src/mkvmuxer/mkvmuxerutil.cc',
|
||||||
'src/mkvwriter.hpp',
|
'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',
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue