blob: c497871693a9d575744023d030d135c9c0c0eae4 [file] [log] [blame]
// Copyright 2018 The Cobalt Authors. All Rights Reserved.
//
// 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
//
// http://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.
#include "starboard/shared/starboard/player/video_dmp_reader.h"
#include <functional>
#if SB_HAS(PLAYER_FILTER_TESTS)
namespace starboard {
namespace shared {
namespace starboard {
namespace player {
namespace video_dmp {
namespace {
template <typename AccessUnit>
int64_t CalculateAverageBitrate(const std::vector<AccessUnit>& access_units) {
if (access_units.empty()) {
return 0;
}
if (access_units.size() == 1) {
// A guestimated bitrate of 1k.
return 1024;
}
SbTime duration =
access_units.back().timestamp() - access_units.front().timestamp();
SB_DCHECK(duration > 0);
int64_t total_bitrate = 0;
for (auto& au : access_units) {
total_bitrate += au.data().size();
}
return total_bitrate * 8 * kSbTimeSecond / duration;
}
static void DeallocateSampleFunc(SbPlayer player,
void* context,
const void* sample_buffer) {
SB_UNREFERENCED_PARAMETER(player);
SB_UNREFERENCED_PARAMETER(context);
SB_UNREFERENCED_PARAMETER(sample_buffer);
}
} // namespace
using std::placeholders::_1;
using std::placeholders::_2;
VideoDmpReader::VideoDmpReader(const char* filename)
: reverse_byte_order_(false),
read_cb_(std::bind(&VideoDmpReader::ReadFromCache, this, _1, _2)) {
ScopedFile file(filename, kSbFileOpenOnly | kSbFileRead);
SB_CHECK(file.IsValid()) << "Failed to open " << filename;
int64_t file_size = file.GetSize();
SB_CHECK(file_size >= 0);
file_cache_.resize(file_size);
int bytes_read = file.Read(file_cache_.data(), file_size);
SB_CHECK(bytes_read == file_size);
Parse();
// To free memory used by |file_cache_|.
decltype(file_cache_) empty;
file_cache_.swap(empty);
}
VideoDmpReader::~VideoDmpReader() {}
scoped_refptr<InputBuffer> VideoDmpReader::GetAudioInputBuffer(
size_t index) const {
SB_DCHECK(index < audio_access_units_.size());
const AudioAccessUnit& au = audio_access_units_[index];
return new InputBuffer(kSbMediaTypeAudio, DeallocateSampleFunc, NULL, NULL,
au.data().data(), static_cast<int>(au.data().size()),
au.timestamp(), NULL, NULL);
}
scoped_refptr<InputBuffer> VideoDmpReader::GetVideoInputBuffer(
size_t index) const {
SB_DCHECK(index < video_access_units_.size());
const VideoAccessUnit& au = video_access_units_[index];
return new InputBuffer(kSbMediaTypeVideo, DeallocateSampleFunc, NULL, NULL,
au.data().data(), static_cast<int>(au.data().size()),
au.timestamp(), &au.video_sample_info(), NULL);
}
void VideoDmpReader::Parse() {
reverse_byte_order_ = false;
uint32_t byte_order_mark;
Read(read_cb_, reverse_byte_order_, &byte_order_mark);
if (byte_order_mark != kByteOrderMark) {
std::reverse(reinterpret_cast<uint8_t*>(&byte_order_mark),
reinterpret_cast<uint8_t*>(&byte_order_mark + 1));
SB_DCHECK(byte_order_mark == kByteOrderMark);
if (byte_order_mark != kByteOrderMark) {
SB_LOG(ERROR) << "Invalid BOM" << byte_order_mark;
return;
}
reverse_byte_order_ = true;
}
for (;;) {
uint32_t type;
int bytes_read = ReadFromCache(&type, sizeof(type));
if (bytes_read <= 0) {
break;
}
if (reverse_byte_order_) {
std::reverse(reinterpret_cast<uint8_t*>(&type),
reinterpret_cast<uint8_t*>(&type + 1));
}
switch (type) {
case kRecordTypeAudioConfig:
Read(read_cb_, reverse_byte_order_, &audio_codec_);
if (audio_codec_ != kSbMediaAudioCodecNone) {
Read(read_cb_, reverse_byte_order_, &audio_header_);
}
break;
case kRecordTypeVideoConfig:
Read(read_cb_, reverse_byte_order_, &video_codec_);
break;
case kRecordTypeAudioAccessUnit:
audio_access_units_.push_back(ReadAudioAccessUnit());
break;
case kRecordTypeVideoAccessUnit:
video_access_units_.push_back(ReadVideoAccessUnit());
break;
default:
SB_NOTREACHED() << type;
break;
}
}
audio_bitrate_ = CalculateAverageBitrate(audio_access_units_);
video_bitrate_ = CalculateAverageBitrate(video_access_units_);
// Guestimate the video fps.
if (video_access_units_.size() > 1) {
SbTime first_timestamp = video_access_units_.front().timestamp();
SbTime second_timestamp = video_access_units_.back().timestamp();
for (const auto& au : video_access_units_) {
if (au.timestamp() != first_timestamp &&
au.timestamp() < second_timestamp) {
second_timestamp = au.timestamp();
}
}
SB_DCHECK(first_timestamp < second_timestamp);
video_fps_ = kSbTimeSecond / (second_timestamp - first_timestamp);
}
}
VideoDmpReader::AudioAccessUnit VideoDmpReader::ReadAudioAccessUnit() {
SbTime timestamp;
Read(read_cb_, reverse_byte_order_, &timestamp);
bool drm_sample_info_present;
Read(read_cb_, reverse_byte_order_, &drm_sample_info_present);
SbDrmSampleInfoWithSubSampleMapping drm_sample_info;
if (drm_sample_info_present) {
Read(read_cb_, reverse_byte_order_, &drm_sample_info);
}
uint32_t size;
Read(read_cb_, reverse_byte_order_, &size);
std::vector<uint8_t> data(size);
Read(read_cb_, data.data(), size);
return AudioAccessUnit(timestamp,
drm_sample_info_present ? &drm_sample_info : NULL,
std::move(data));
}
VideoDmpReader::VideoAccessUnit VideoDmpReader::ReadVideoAccessUnit() {
SbTime timestamp;
Read(read_cb_, reverse_byte_order_, &timestamp);
bool drm_sample_info_present;
Read(read_cb_, reverse_byte_order_, &drm_sample_info_present);
SbDrmSampleInfoWithSubSampleMapping drm_sample_info;
if (drm_sample_info_present) {
Read(read_cb_, reverse_byte_order_, &drm_sample_info);
}
uint32_t size;
Read(read_cb_, reverse_byte_order_, &size);
std::vector<uint8_t> data(size);
Read(read_cb_, data.data(), size);
SbMediaVideoSampleInfoWithOptionalColorMetadata video_sample_info;
Read(read_cb_, reverse_byte_order_, &video_sample_info);
return VideoAccessUnit(timestamp,
drm_sample_info_present ? &drm_sample_info : NULL,
std::move(data), video_sample_info);
}
int VideoDmpReader::ReadFromCache(void* buffer, int bytes_to_read) {
bytes_to_read = std::min(
bytes_to_read, static_cast<int>(file_cache_.size()) - file_cache_offset_);
SbMemoryCopy(buffer, file_cache_.data() + file_cache_offset_, bytes_to_read);
file_cache_offset_ += bytes_to_read;
return bytes_to_read;
}
} // namespace video_dmp
} // namespace player
} // namespace starboard
} // namespace shared
} // namespace starboard
#endif // SB_HAS(PLAYER_FILTER_TESTS)