blob: b0da2e862873ca1727af1024ca1bd1285b0ce21f [file] [log] [blame]
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -----------------------------------------------------------------------------
//
// StreamDataSource implementation.
//
// Author: Yannis Guyon (yguyon@google.com)
#include "src/utils/data_source_stream.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include "src/dsp/math.h"
#include "src/utils/data_source.h"
#include "src/utils/utils.h"
#include "src/wp2/base.h"
namespace WP2 {
WP2Status StreamDataSource::AppendAsExternal(const uint8_t* bytes,
size_t size) {
if (num_new_bytes_to_discard_ > 0) {
const size_t num_discarded_new_bytes =
std::min(size, num_new_bytes_to_discard_);
bytes += num_discarded_new_bytes;
size -= num_discarded_new_bytes;
num_new_bytes_to_discard_ -= num_discarded_new_bytes;
}
if (size > 0) {
assert(bytes != nullptr);
WP2_CHECK_STATUS(AppendExternalToInternal()); // Make room if needed.
external_bytes_ = bytes;
num_external_bytes_ = size;
// Only one contiguous array is returned by TryGetNext(), so multiple
// buffers are merged. Thus StreamDataSource contains either external or
// internal data but never both at the same time.
if (!internal_data_.empty()) {
WP2_CHECK_STATUS(AppendExternalToInternal());
} else {
available_bytes_ = external_bytes_;
num_available_bytes_ = num_external_bytes_;
}
}
return WP2_STATUS_OK;
}
WP2Status StreamDataSource::AppendExternalToInternal() {
if (num_external_bytes_ > 0) {
assert(external_bytes_ != nullptr);
const uint8_t* const external_bytes = external_bytes_;
const size_t num_external_bytes = num_external_bytes_;
// Remove external reference even if error. AppendExternalToInternal() might
// get called again and external_bytes_ might not be valid anymore.
external_bytes_ = available_bytes_ = nullptr;
num_external_bytes_ = num_available_bytes_ = 0;
const size_t internal_size = internal_data_.size();
WP2_CHECK_ALLOC_OK(
internal_data_.resize(internal_size + num_external_bytes));
memcpy(internal_data_.data() + internal_size, external_bytes,
num_external_bytes);
available_bytes_ = internal_data_.data();
num_available_bytes_ = internal_data_.size();
}
return WP2_STATUS_OK;
}
void StreamDataSource::Reset() {
DataSource::Reset();
external_bytes_ = nullptr;
num_external_bytes_ = 0;
internal_data_.clear();
num_new_bytes_to_discard_ = 0;
}
bool StreamDataSource::Fetch(size_t num_requested_bytes) { return false; }
void StreamDataSource::OnDiscard(size_t num_bytes) {
if (num_external_bytes_ > 0) {
if (num_bytes >= num_external_bytes_) {
num_new_bytes_to_discard_ =
SafeAdd(num_new_bytes_to_discard_, num_bytes - num_external_bytes_);
external_bytes_ = nullptr;
num_external_bytes_ = 0;
} else {
assert(external_bytes_ != nullptr);
external_bytes_ += num_bytes;
num_external_bytes_ -= num_bytes;
}
available_bytes_ = external_bytes_;
num_available_bytes_ = num_external_bytes_;
} else {
if (num_bytes >= internal_data_.size()) {
num_new_bytes_to_discard_ =
SafeAdd(num_new_bytes_to_discard_, num_bytes - internal_data_.size());
internal_data_.clear();
} else {
const size_t new_size = internal_data_.size() - num_bytes;
memmove(internal_data_.data(), internal_data_.data() + num_bytes,
new_size);
const bool success = internal_data_.resize(new_size);
(void)success;
assert(success);
}
available_bytes_ = internal_data_.data();
num_available_bytes_ = internal_data_.size();
}
}
} // namespace WP2