| /* |
| * 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 |