| /* | |
| * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. | |
| * | |
| * Use of this source code is governed by a BSD-style license | |
| * that can be found in the LICENSE file in the root of the source | |
| * tree. An additional intellectual property rights grant can be found | |
| * in the file PATENTS. All contributing project authors may | |
| * be found in the AUTHORS file in the root of the source tree. | |
| */ | |
| #include "modules/video_coding/utility/vp9_uncompressed_header_parser.h" | |
| #include "rtc_base/bitbuffer.h" | |
| #include "rtc_base/logging.h" | |
| namespace webrtc { | |
| #define RETURN_FALSE_IF_ERROR(x) \ | |
| if (!(x)) { \ | |
| return false; \ | |
| } | |
| namespace vp9 { | |
| namespace { | |
| const size_t kVp9NumRefsPerFrame = 3; | |
| const size_t kVp9MaxRefLFDeltas = 4; | |
| const size_t kVp9MaxModeLFDeltas = 2; | |
| bool Vp9ReadProfile(rtc::BitBuffer* br, uint8_t* profile) { | |
| uint32_t high_bit; | |
| uint32_t low_bit; | |
| RETURN_FALSE_IF_ERROR(br->ReadBits(&low_bit, 1)); | |
| RETURN_FALSE_IF_ERROR(br->ReadBits(&high_bit, 1)); | |
| *profile = (high_bit << 1) + low_bit; | |
| if (*profile > 2) { | |
| uint32_t reserved_bit; | |
| RETURN_FALSE_IF_ERROR(br->ReadBits(&reserved_bit, 1)); | |
| if (reserved_bit) { | |
| RTC_LOG(LS_WARNING) << "Failed to get QP. Unsupported bitstream profile."; | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| bool Vp9ReadSyncCode(rtc::BitBuffer* br) { | |
| uint32_t sync_code; | |
| RETURN_FALSE_IF_ERROR(br->ReadBits(&sync_code, 24)); | |
| if (sync_code != 0x498342) { | |
| RTC_LOG(LS_WARNING) << "Failed to get QP. Invalid sync code."; | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool Vp9ReadColorConfig(rtc::BitBuffer* br, uint8_t profile) { | |
| if (profile == 2 || profile == 3) { | |
| // Bitdepth. | |
| RETURN_FALSE_IF_ERROR(br->ConsumeBits(1)); | |
| } | |
| uint32_t color_space; | |
| RETURN_FALSE_IF_ERROR(br->ReadBits(&color_space, 3)); | |
| // SRGB is 7. | |
| if (color_space != 7) { | |
| // YUV range flag. | |
| RETURN_FALSE_IF_ERROR(br->ConsumeBits(1)); | |
| if (profile == 1 || profile == 3) { | |
| // 1 bit: subsampling x. | |
| // 1 bit: subsampling y. | |
| RETURN_FALSE_IF_ERROR(br->ConsumeBits(2)); | |
| uint32_t reserved_bit; | |
| RETURN_FALSE_IF_ERROR(br->ReadBits(&reserved_bit, 1)); | |
| if (reserved_bit) { | |
| RTC_LOG(LS_WARNING) << "Failed to get QP. Reserved bit set."; | |
| return false; | |
| } | |
| } | |
| } else { | |
| if (profile == 1 || profile == 3) { | |
| uint32_t reserved_bit; | |
| RETURN_FALSE_IF_ERROR(br->ReadBits(&reserved_bit, 1)); | |
| if (reserved_bit) { | |
| RTC_LOG(LS_WARNING) << "Failed to get QP. Reserved bit set."; | |
| return false; | |
| } | |
| } else { | |
| RTC_LOG(LS_WARNING) << "Failed to get QP. 4:4:4 color not supported in " | |
| "profile 0 or 2."; | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| bool Vp9ReadFrameSize(rtc::BitBuffer* br) { | |
| // 2 bytes: frame width. | |
| // 2 bytes: frame height. | |
| return br->ConsumeBytes(4); | |
| } | |
| bool Vp9ReadRenderSize(rtc::BitBuffer* br) { | |
| uint32_t bit; | |
| RETURN_FALSE_IF_ERROR(br->ReadBits(&bit, 1)); | |
| if (bit) { | |
| // 2 bytes: render width. | |
| // 2 bytes: render height. | |
| RETURN_FALSE_IF_ERROR(br->ConsumeBytes(4)); | |
| } | |
| return true; | |
| } | |
| bool Vp9ReadFrameSizeFromRefs(rtc::BitBuffer* br) { | |
| uint32_t found_ref = 0; | |
| for (size_t i = 0; i < kVp9NumRefsPerFrame; i++) { | |
| // Size in refs. | |
| RETURN_FALSE_IF_ERROR(br->ReadBits(&found_ref, 1)); | |
| if (found_ref) | |
| break; | |
| } | |
| if (!found_ref) { | |
| if (!Vp9ReadFrameSize(br)) { | |
| return false; | |
| } | |
| } | |
| return Vp9ReadRenderSize(br); | |
| } | |
| bool Vp9ReadInterpolationFilter(rtc::BitBuffer* br) { | |
| uint32_t bit; | |
| RETURN_FALSE_IF_ERROR(br->ReadBits(&bit, 1)); | |
| if (bit) | |
| return true; | |
| return br->ConsumeBits(2); | |
| } | |
| bool Vp9ReadLoopfilter(rtc::BitBuffer* br) { | |
| // 6 bits: filter level. | |
| // 3 bits: sharpness level. | |
| RETURN_FALSE_IF_ERROR(br->ConsumeBits(9)); | |
| uint32_t mode_ref_delta_enabled; | |
| RETURN_FALSE_IF_ERROR(br->ReadBits(&mode_ref_delta_enabled, 1)); | |
| if (mode_ref_delta_enabled) { | |
| uint32_t mode_ref_delta_update; | |
| RETURN_FALSE_IF_ERROR(br->ReadBits(&mode_ref_delta_update, 1)); | |
| if (mode_ref_delta_update) { | |
| uint32_t bit; | |
| for (size_t i = 0; i < kVp9MaxRefLFDeltas; i++) { | |
| RETURN_FALSE_IF_ERROR(br->ReadBits(&bit, 1)); | |
| if (bit) { | |
| RETURN_FALSE_IF_ERROR(br->ConsumeBits(7)); | |
| } | |
| } | |
| for (size_t i = 0; i < kVp9MaxModeLFDeltas; i++) { | |
| RETURN_FALSE_IF_ERROR(br->ReadBits(&bit, 1)); | |
| if (bit) { | |
| RETURN_FALSE_IF_ERROR(br->ConsumeBits(7)); | |
| } | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| } // namespace | |
| bool GetQp(const uint8_t* buf, size_t length, int* qp) { | |
| rtc::BitBuffer br(buf, length); | |
| // Frame marker. | |
| uint32_t frame_marker; | |
| RETURN_FALSE_IF_ERROR(br.ReadBits(&frame_marker, 2)); | |
| if (frame_marker != 0x2) { | |
| RTC_LOG(LS_WARNING) << "Failed to get QP. Frame marker should be 2."; | |
| return false; | |
| } | |
| // Profile. | |
| uint8_t profile; | |
| if (!Vp9ReadProfile(&br, &profile)) | |
| return false; | |
| // Show existing frame. | |
| uint32_t show_existing_frame; | |
| RETURN_FALSE_IF_ERROR(br.ReadBits(&show_existing_frame, 1)); | |
| if (show_existing_frame) | |
| return false; | |
| // Frame type: KEY_FRAME(0), INTER_FRAME(1). | |
| uint32_t frame_type; | |
| uint32_t show_frame; | |
| uint32_t error_resilient; | |
| RETURN_FALSE_IF_ERROR(br.ReadBits(&frame_type, 1)); | |
| RETURN_FALSE_IF_ERROR(br.ReadBits(&show_frame, 1)); | |
| RETURN_FALSE_IF_ERROR(br.ReadBits(&error_resilient, 1)); | |
| if (!frame_type) { | |
| if (!Vp9ReadSyncCode(&br)) | |
| return false; | |
| if (!Vp9ReadColorConfig(&br, profile)) | |
| return false; | |
| if (!Vp9ReadFrameSize(&br)) | |
| return false; | |
| if (!Vp9ReadRenderSize(&br)) | |
| return false; | |
| } else { | |
| uint32_t intra_only = 0; | |
| if (!show_frame) | |
| RETURN_FALSE_IF_ERROR(br.ReadBits(&intra_only, 1)); | |
| if (!error_resilient) | |
| RETURN_FALSE_IF_ERROR(br.ConsumeBits(2)); // Reset frame context. | |
| if (intra_only) { | |
| if (!Vp9ReadSyncCode(&br)) | |
| return false; | |
| if (profile > 0) { | |
| if (!Vp9ReadColorConfig(&br, profile)) | |
| return false; | |
| } | |
| // Refresh frame flags. | |
| RETURN_FALSE_IF_ERROR(br.ConsumeBits(8)); | |
| if (!Vp9ReadFrameSize(&br)) | |
| return false; | |
| if (!Vp9ReadRenderSize(&br)) | |
| return false; | |
| } else { | |
| // Refresh frame flags. | |
| RETURN_FALSE_IF_ERROR(br.ConsumeBits(8)); | |
| for (size_t i = 0; i < kVp9NumRefsPerFrame; i++) { | |
| // 3 bits: Ref frame index. | |
| // 1 bit: Ref frame sign biases. | |
| RETURN_FALSE_IF_ERROR(br.ConsumeBits(4)); | |
| } | |
| if (!Vp9ReadFrameSizeFromRefs(&br)) | |
| return false; | |
| // Allow high precision mv. | |
| RETURN_FALSE_IF_ERROR(br.ConsumeBits(1)); | |
| // Interpolation filter. | |
| if (!Vp9ReadInterpolationFilter(&br)) | |
| return false; | |
| } | |
| } | |
| if (!error_resilient) { | |
| // 1 bit: Refresh frame context. | |
| // 1 bit: Frame parallel decoding mode. | |
| RETURN_FALSE_IF_ERROR(br.ConsumeBits(2)); | |
| } | |
| // Frame context index. | |
| RETURN_FALSE_IF_ERROR(br.ConsumeBits(2)); | |
| if (!Vp9ReadLoopfilter(&br)) | |
| return false; | |
| // Base QP. | |
| uint8_t base_q0; | |
| RETURN_FALSE_IF_ERROR(br.ReadUInt8(&base_q0)); | |
| *qp = base_q0; | |
| return true; | |
| } | |
| } // namespace vp9 | |
| } // namespace webrtc |