| // Copyright 2022 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/media/parsed_mime_info.h" |
| |
| #include <string> |
| |
| #include "starboard/common/log.h" |
| #include "starboard/common/media.h" |
| #include "starboard/shared/starboard/media/codec_util.h" |
| |
| namespace starboard { |
| namespace shared { |
| namespace starboard { |
| namespace media { |
| |
| namespace { |
| |
| const int64_t kDefaultAudioChannels = 2; |
| |
| // Turns |eotf| into value of SbMediaTransferId. If |eotf| isn't recognized the |
| // function returns kSbMediaTransferIdUnknown. |
| // This function supports all eotfs required by YouTube TV HTML5 Technical |
| // Requirements. |
| SbMediaTransferId GetTransferIdFromString(const std::string& transfer_id) { |
| if (transfer_id == "bt709") { |
| return kSbMediaTransferIdBt709; |
| } else if (transfer_id == "smpte2084") { |
| return kSbMediaTransferIdSmpteSt2084; |
| } else if (transfer_id == "arib-std-b67") { |
| return kSbMediaTransferIdAribStdB67; |
| } |
| return kSbMediaTransferIdUnknown; |
| } |
| |
| } // namespace |
| |
| ParsedMimeInfo::ParsedMimeInfo(const std::string& mime_string) |
| : mime_type_(mime_string) { |
| ParseMimeInfo(); |
| } |
| |
| void ParsedMimeInfo::SetBitrate(int bitrate) { |
| audio_info_.bitrate = bitrate; |
| video_info_.bitrate = bitrate; |
| } |
| |
| void ParsedMimeInfo::ParseMimeInfo() { |
| if (!mime_type_.is_valid()) { |
| is_valid_ = false; |
| return; |
| } |
| |
| // Read "disablecache". |
| if (!mime_type_.ValidateBoolParameter("disablecache")) { |
| is_valid_ = false; |
| return; |
| } |
| disable_cache_ = mime_type_.GetParamBoolValue("disablecache", false); |
| |
| // We only support audio or video type. |
| if (mime_type_.type() != "audio" && mime_type_.type() != "video") { |
| is_valid_ = false; |
| return; |
| } |
| |
| auto codecs = mime_type_.GetCodecs(); |
| // We only support up to one audio codec and one video codec. |
| if (codecs.size() > 2) { |
| is_valid_ = false; |
| return; |
| } |
| |
| for (const auto& codec : codecs) { |
| if (!has_audio_info() && ParseAudioInfo(codec)) { |
| continue; |
| } |
| if (!has_video_info() && ParseVideoInfo(codec)) { |
| continue; |
| } |
| // It either has an invalid codec or has two codecs of same type. |
| ResetCodecInfos(); |
| is_valid_ = false; |
| return; |
| } |
| } |
| |
| bool ParsedMimeInfo::ParseAudioInfo(const std::string& codec) { |
| SB_DCHECK(mime_type_.is_valid()); |
| SB_DCHECK(!has_audio_info()); |
| |
| SbMediaAudioCodec audio_codec = GetAudioCodecFromString(codec.c_str()); |
| if (audio_codec == kSbMediaAudioCodecNone) { |
| return false; |
| } |
| if (!mime_type_.ValidateIntParameter("channels") || |
| !mime_type_.ValidateIntParameter("bitrate")) { |
| return false; |
| } |
| audio_info_.codec = audio_codec; |
| audio_info_.channels = |
| mime_type_.GetParamIntValue("channels", kDefaultAudioChannels); |
| audio_info_.bitrate = mime_type_.GetParamIntValue("bitrate", 0); |
| |
| return audio_info_.channels >= 0 && audio_info_.bitrate >= 0; |
| } |
| |
| bool ParsedMimeInfo::ParseVideoInfo(const std::string& codec) { |
| SB_DCHECK(mime_type_.is_valid()); |
| SB_DCHECK(!has_video_info()); |
| |
| if (!ParseVideoCodec(codec.c_str(), &video_info_.codec, &video_info_.profile, |
| &video_info_.level, &video_info_.bit_depth, |
| &video_info_.primary_id, &video_info_.transfer_id, |
| &video_info_.matrix_id)) { |
| return false; |
| } |
| |
| if (video_info_.codec == kSbMediaVideoCodecNone) { |
| return false; |
| } |
| |
| std::string eotf = mime_type_.GetParamStringValue("eotf", ""); |
| if (!eotf.empty()) { |
| SbMediaTransferId transfer_id_from_eotf = GetTransferIdFromString(eotf); |
| if (transfer_id_from_eotf == kSbMediaTransferIdUnknown) { |
| // The eotf is an unknown value, mark the codec info as invalid. |
| SB_LOG(WARNING) << "Unknown eotf " << eotf << "."; |
| return false; |
| } |
| SB_LOG_IF(WARNING, |
| video_info_.transfer_id != kSbMediaTransferIdUnspecified && |
| video_info_.transfer_id != transfer_id_from_eotf) |
| << "transfer_id " << video_info_.transfer_id |
| << " set by the codec string \"" << video_info_.codec |
| << "\" will be overwritten by the eotf attribute " << eotf; |
| video_info_.transfer_id = transfer_id_from_eotf; |
| } |
| |
| if (!mime_type_.ValidateIntParameter("width") || |
| !mime_type_.ValidateIntParameter("height") || |
| !mime_type_.ValidateIntParameter("framerate") || |
| !mime_type_.ValidateIntParameter("bitrate") || |
| !mime_type_.ValidateBoolParameter("decode-to-texture")) { |
| return false; |
| } |
| |
| video_info_.frame_width = mime_type_.GetParamIntValue("width", 0); |
| video_info_.frame_height = mime_type_.GetParamIntValue("height", 0); |
| video_info_.fps = mime_type_.GetParamIntValue("framerate", 0); |
| video_info_.bitrate = mime_type_.GetParamIntValue("bitrate", 0); |
| video_info_.decode_to_texture_required = |
| mime_type_.GetParamBoolValue("decode-to-texture", false); |
| |
| return video_info_.frame_width >= 0 && video_info_.frame_height >= 0 && |
| video_info_.fps >= 0 && video_info_.bitrate >= 0; |
| } |
| |
| void ParsedMimeInfo::ResetCodecInfos() { |
| audio_info_.codec = kSbMediaAudioCodecNone; |
| video_info_.codec = kSbMediaVideoCodecNone; |
| } |
| |
| } // namespace media |
| } // namespace starboard |
| } // namespace shared |
| } // namespace starboard |