| // Copyright 2018 Google Inc. 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::ReadFromFile, this, _1, _2)) { |
| SB_CHECK(SbFileCanOpen(filename, kSbFileOpenOnly | kSbFileRead)) |
| << "Can't open " << filename; |
| file_ = SbFileOpen(filename, kSbFileOpenOnly | kSbFileRead, NULL, NULL); |
| SB_DCHECK(SbFileIsValid(file_)); |
| |
| Parse(); |
| |
| SbFileClose(file_); |
| } |
| |
| 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 = ReadFromFile(&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_, ×tamp); |
| |
| 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_, ×tamp); |
| |
| 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::ReadFromFile(void* buffer, int bytes_to_read) { |
| return SbFileRead(file_, static_cast<char*>(buffer), bytes_to_read); |
| } |
| |
| } // namespace video_dmp |
| } // namespace player |
| } // namespace starboard |
| } // namespace shared |
| } // namespace starboard |
| #endif // SB_HAS(PLAYER_FILTER_TESTS) |