shaka-packager/packager/media/formats/webm/seek_head.cc

115 lines
3.7 KiB
C++

// Copyright 2015 Google LLC. 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/formats/webm/seek_head.h"
#include <algorithm>
#include <limits>
#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 {
// 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 =
EbmlElementSize(
mkvmuxer::kMkvSeekID,
static_cast<mkvmuxer::uint64>(std::numeric_limits<uint32_t>::max())) +
EbmlElementSize(mkvmuxer::kMkvSeekPosition,
std::numeric_limits<mkvmuxer::uint64>::max());
return EbmlMasterElementWithPayloadSize(mkvmuxer::kMkvSeek,
max_entry_payload_size);
}
} // namespace
SeekHead::SeekHead()
: total_void_size_(EbmlMasterElementWithPayloadSize(
mkvmuxer::kMkvSeekHead,
kElementIdCount * MaxSeekEntrySize())) {}
SeekHead::~SeekHead() {}
bool SeekHead::Write(mkvmuxer::IMkvWriter* writer) {
std::vector<SeekElement> seek_elements = CreateSeekElements();
if (seek_elements.empty())
return true;
uint64_t payload_size = 0;
for (const SeekHead::SeekElement& seek_element : seek_elements) {
payload_size +=
EbmlMasterElementWithPayloadSize(mkvmuxer::kMkvSeek, seek_element.size);
}
const int64_t start_pos = writer->Position();
if (!WriteEbmlMasterElement(writer, mkvmuxer::kMkvSeekHead, payload_size))
return false;
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 extra_void =
total_void_size_ - (writer->Position() - start_pos);
if (!WriteVoidElement(writer, extra_void))
return false;
}
return true;
}
bool SeekHead::WriteVoid(mkvmuxer::IMkvWriter* writer) {
const uint64_t written = WriteVoidElement(writer, total_void_size_);
if (!written)
return false;
wrote_void_ = true;
return true;
}
std::vector<SeekHead::SeekElement> SeekHead::CreateSeekElements() {
std::vector<SeekHead::SeekElement> 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);
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 seek_elements;
}
} // namespace media
} // namespace shaka