| // Copyright (c) 2016 The WebM 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 "common/vp9_header_parser.h" |
| |
| #include <stdio.h> |
| |
| namespace vp9_parser { |
| |
| bool Vp9HeaderParser::SetFrame(const uint8_t* frame, size_t length) { |
| if (!frame || length == 0) |
| return false; |
| |
| frame_ = frame; |
| frame_size_ = length; |
| bit_offset_ = 0; |
| profile_ = -1; |
| show_existing_frame_ = 0; |
| key_ = 0; |
| altref_ = 0; |
| error_resilient_mode_ = 0; |
| intra_only_ = 0; |
| reset_frame_context_ = 0; |
| color_space_ = 0; |
| color_range_ = 0; |
| subsampling_x_ = 0; |
| subsampling_y_ = 0; |
| refresh_frame_flags_ = 0; |
| return true; |
| } |
| |
| bool Vp9HeaderParser::ParseUncompressedHeader() { |
| const int frame_marker = VpxReadLiteral(2); |
| if (frame_marker != kVp9FrameMarker) { |
| fprintf(stderr, "Invalid VP9 frame_marker:%d\n", frame_marker); |
| return false; |
| } |
| |
| profile_ = ReadBit(); |
| profile_ |= ReadBit() << 1; |
| if (profile_ > 2) |
| profile_ += ReadBit(); |
| |
| // TODO(fgalligan): Decide how to handle show existing frames. |
| show_existing_frame_ = ReadBit(); |
| if (show_existing_frame_) |
| return true; |
| |
| key_ = !ReadBit(); |
| altref_ = !ReadBit(); |
| error_resilient_mode_ = ReadBit(); |
| if (key_) { |
| if (!ValidateVp9SyncCode()) { |
| fprintf(stderr, "Invalid Sync code!\n"); |
| return false; |
| } |
| |
| ParseColorSpace(); |
| ParseFrameResolution(); |
| ParseFrameParallelMode(); |
| ParseTileInfo(); |
| } else { |
| intra_only_ = altref_ ? ReadBit() : 0; |
| reset_frame_context_ = error_resilient_mode_ ? 0 : VpxReadLiteral(2); |
| if (intra_only_) { |
| if (!ValidateVp9SyncCode()) { |
| fprintf(stderr, "Invalid Sync code!\n"); |
| return false; |
| } |
| |
| if (profile_ > 0) { |
| ParseColorSpace(); |
| } else { |
| // NOTE: The intra-only frame header does not include the specification |
| // of either the color format or color sub-sampling in profile 0. VP9 |
| // specifies that the default color format should be YUV 4:2:0 in this |
| // case (normative). |
| color_space_ = kVpxCsBt601; |
| color_range_ = kVpxCrStudioRange; |
| subsampling_y_ = subsampling_x_ = 1; |
| bit_depth_ = 8; |
| } |
| |
| refresh_frame_flags_ = VpxReadLiteral(kRefFrames); |
| ParseFrameResolution(); |
| } else { |
| refresh_frame_flags_ = VpxReadLiteral(kRefFrames); |
| for (int i = 0; i < kRefsPerFrame; ++i) { |
| VpxReadLiteral(kRefFrames_LOG2); // Consume ref. |
| ReadBit(); // Consume ref sign bias. |
| } |
| |
| bool found = false; |
| for (int i = 0; i < kRefsPerFrame; ++i) { |
| if (ReadBit()) { |
| // Found previous reference, width and height did not change since |
| // last frame. |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) |
| ParseFrameResolution(); |
| } |
| } |
| return true; |
| } |
| |
| int Vp9HeaderParser::ReadBit() { |
| const size_t off = bit_offset_; |
| const size_t byte_offset = off >> 3; |
| const int bit_shift = 7 - static_cast<int>(off & 0x7); |
| if (byte_offset < frame_size_) { |
| const int bit = (frame_[byte_offset] >> bit_shift) & 1; |
| bit_offset_++; |
| return bit; |
| } else { |
| return 0; |
| } |
| } |
| |
| int Vp9HeaderParser::VpxReadLiteral(int bits) { |
| int value = 0; |
| for (int bit = bits - 1; bit >= 0; --bit) |
| value |= ReadBit() << bit; |
| return value; |
| } |
| |
| bool Vp9HeaderParser::ValidateVp9SyncCode() { |
| const int sync_code_0 = VpxReadLiteral(8); |
| const int sync_code_1 = VpxReadLiteral(8); |
| const int sync_code_2 = VpxReadLiteral(8); |
| return (sync_code_0 == 0x49 && sync_code_1 == 0x83 && sync_code_2 == 0x42); |
| } |
| |
| void Vp9HeaderParser::ParseColorSpace() { |
| bit_depth_ = 0; |
| if (profile_ >= 2) |
| bit_depth_ = ReadBit() ? 12 : 10; |
| else |
| bit_depth_ = 8; |
| color_space_ = VpxReadLiteral(3); |
| if (color_space_ != kVpxCsSrgb) { |
| color_range_ = ReadBit(); |
| if (profile_ == 1 || profile_ == 3) { |
| subsampling_x_ = ReadBit(); |
| subsampling_y_ = ReadBit(); |
| ReadBit(); |
| } else { |
| subsampling_y_ = subsampling_x_ = 1; |
| } |
| } else { |
| color_range_ = kVpxCrFullRange; |
| if (profile_ == 1 || profile_ == 3) { |
| subsampling_y_ = subsampling_x_ = 0; |
| ReadBit(); |
| } |
| } |
| } |
| |
| void Vp9HeaderParser::ParseFrameResolution() { |
| width_ = VpxReadLiteral(16) + 1; |
| height_ = VpxReadLiteral(16) + 1; |
| } |
| |
| void Vp9HeaderParser::ParseFrameParallelMode() { |
| if (ReadBit()) { |
| VpxReadLiteral(16); // display width |
| VpxReadLiteral(16); // display height |
| } |
| if (!error_resilient_mode_) { |
| ReadBit(); // Consume refresh frame context |
| frame_parallel_mode_ = ReadBit(); |
| } else { |
| frame_parallel_mode_ = 1; |
| } |
| } |
| |
| void Vp9HeaderParser::ParseTileInfo() { |
| VpxReadLiteral(2); // Consume frame context index |
| |
| // loopfilter |
| VpxReadLiteral(6); // Consume filter level |
| VpxReadLiteral(3); // Consume sharpness level |
| |
| const bool mode_ref_delta_enabled = ReadBit(); |
| if (mode_ref_delta_enabled) { |
| const bool mode_ref_delta_update = ReadBit(); |
| if (mode_ref_delta_update) { |
| const int kMaxRefLFDeltas = 4; |
| for (int i = 0; i < kMaxRefLFDeltas; ++i) { |
| if (ReadBit()) |
| VpxReadLiteral(7); // Consume ref_deltas + sign |
| } |
| |
| const int kMaxModeDeltas = 2; |
| for (int i = 0; i < kMaxModeDeltas; ++i) { |
| if (ReadBit()) |
| VpxReadLiteral(7); // Consume mode_delta + sign |
| } |
| } |
| } |
| |
| // quantization |
| VpxReadLiteral(8); // Consume base_q |
| SkipDeltaQ(); // y dc |
| SkipDeltaQ(); // uv ac |
| SkipDeltaQ(); // uv dc |
| |
| // segmentation |
| const bool segmentation_enabled = ReadBit(); |
| if (!segmentation_enabled) { |
| const int aligned_width = AlignPowerOfTwo(width_, kMiSizeLog2); |
| const int mi_cols = aligned_width >> kMiSizeLog2; |
| const int aligned_mi_cols = AlignPowerOfTwo(mi_cols, kMiSizeLog2); |
| const int sb_cols = aligned_mi_cols >> 3; // to_sbs(mi_cols); |
| int min_log2_n_tiles, max_log2_n_tiles; |
| |
| for (max_log2_n_tiles = 0; |
| (sb_cols >> max_log2_n_tiles) >= kMinTileWidthB64; |
| max_log2_n_tiles++) { |
| } |
| max_log2_n_tiles--; |
| if (max_log2_n_tiles < 0) |
| max_log2_n_tiles = 0; |
| |
| for (min_log2_n_tiles = 0; (kMaxTileWidthB64 << min_log2_n_tiles) < sb_cols; |
| min_log2_n_tiles++) { |
| } |
| |
| // columns |
| const int max_log2_tile_cols = max_log2_n_tiles; |
| const int min_log2_tile_cols = min_log2_n_tiles; |
| int max_ones = max_log2_tile_cols - min_log2_tile_cols; |
| int log2_tile_cols = min_log2_tile_cols; |
| while (max_ones-- && ReadBit()) |
| log2_tile_cols++; |
| |
| // rows |
| int log2_tile_rows = ReadBit(); |
| if (log2_tile_rows) |
| log2_tile_rows += ReadBit(); |
| |
| row_tiles_ = 1 << log2_tile_rows; |
| column_tiles_ = 1 << log2_tile_cols; |
| } |
| } |
| |
| void Vp9HeaderParser::SkipDeltaQ() { |
| if (ReadBit()) |
| VpxReadLiteral(4); |
| } |
| |
| int Vp9HeaderParser::AlignPowerOfTwo(int value, int n) { |
| return (((value) + ((1 << (n)) - 1)) & ~((1 << (n)) - 1)); |
| } |
| |
| } // namespace vp9_parser |