Blob Blame History Raw
/*
 * Copyright 2016 Intel Corporation
 *
 * 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.
 */

/**
 * SECTION:vp9parser
 * @short_description: Convenience library for parsing vp9 video bitstream.
 *
 * For more details about the structures, you can refer to the
 * specifications:
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "bitReader.h"
#include "vp9quant.h"
#include "vp9parser.h"
#include <string.h>
#include <stdlib.h>
#include "common/log.h"

using YamiParser::BitReader;

#define MAX_LOOP_FILTER 63
#define MAX_PROB 255

typedef struct _ReferenceSize {
    uint32_t width;
    uint32_t height;
} ReferenceSize;

typedef struct _Vp9ParserPrivate {
    int8_t y_dc_delta_q;
    int8_t uv_dc_delta_q;
    int8_t uv_ac_delta_q;

    int16_t y_dequant[QINDEX_RANGE][2];
    int16_t uv_dequant[QINDEX_RANGE][2];

    /* for loop filters */
    int8_t ref_deltas[VP9_MAX_REF_LF_DELTAS];
    int8_t mode_deltas[VP9_MAX_MODE_LF_DELTAS];

    BOOL segmentation_abs_delta;
    Vp9SegmentationInfoData segmentation[VP9_MAX_SEGMENTS];

    ReferenceSize reference[VP9_REF_FRAMES];
} Vp9ParserPrivate;

void init_dequantizer(Vp9Parser* parser);

static void init_vp9_parser(Vp9Parser* parser, VP9_BIT_DEPTH bit_depth)
{
    Vp9ParserPrivate* priv = (Vp9ParserPrivate*)parser->priv;
    memset(parser, 0, sizeof(Vp9Parser));
    memset(priv, 0, sizeof(Vp9ParserPrivate));
    parser->priv = priv;
    parser->bit_depth = bit_depth;
    init_dequantizer(parser);
}

Vp9Parser* vp9_parser_new()
{
    Vp9Parser* parser = (Vp9Parser*)malloc(sizeof(Vp9Parser));
    if (!parser)
        return NULL;
    Vp9ParserPrivate* priv = (Vp9ParserPrivate*)malloc(sizeof(Vp9ParserPrivate));
    if (!priv) {
        free(parser);
        return NULL;
    }
    parser->priv = priv;
    init_vp9_parser(parser, VP9_BITS_8);
    return parser;
}

void vp9_parser_free(Vp9Parser* parser)
{
    if (parser) {
        if (parser->priv)
            free(parser->priv);
        free(parser);
    }
}

#define vp9_read_bit(br) br->read(1)
#define vp9_read_bits(br, bits) br->read(bits)

static int32_t vp9_read_signed_bits(BitReader* br, int bits)
{
    assert(bits < 32);
    const int32_t value = vp9_read_bits(br, bits);
    return vp9_read_bit(br) ? -value : value;
}

static BOOL verify_frame_marker(BitReader* br)
{
#define VP9_FRAME_MARKER 2
    uint8_t frame_marker = vp9_read_bits(br, 2);
    if (frame_marker != VP9_FRAME_MARKER)
        return FALSE;
    return TRUE;
}

static BOOL verify_sync_code(BitReader* const br)
{
#define VP9_SYNC_CODE_0 0x49
#define VP9_SYNC_CODE_1 0x83
#define VP9_SYNC_CODE_2 0x42
    return vp9_read_bits(br, 8) == VP9_SYNC_CODE_0 && vp9_read_bits(br, 8) == VP9_SYNC_CODE_1 && vp9_read_bits(br, 8) == VP9_SYNC_CODE_2;
}

static VP9_PROFILE read_profile(BitReader* br)
{
    uint8_t profile = vp9_read_bit(br);
    profile |= vp9_read_bit(br) << 1;
    if (profile > 2)
        profile += vp9_read_bit(br);
    return (VP9_PROFILE)profile;
}

static void read_frame_size(BitReader* br,
    uint32_t* width, uint32_t* height)
{
    const uint32_t w = vp9_read_bits(br, 16) + 1;
    const uint32_t h = vp9_read_bits(br, 16) + 1;
    *width = w;
    *height = h;
}

static void read_display_frame_size(Vp9FrameHdr* frame_hdr, BitReader* br)
{
    frame_hdr->display_size_enabled = vp9_read_bit(br);
    if (frame_hdr->display_size_enabled) {
        read_frame_size(br, &frame_hdr->display_width, &frame_hdr->display_height);
    }
}

static void read_frame_size_from_refs(const Vp9Parser* parser, Vp9FrameHdr* frame_hdr, BitReader* br)
{
    BOOL found = FALSE;
    int i;
    const Vp9ParserPrivate* priv = (Vp9ParserPrivate*)parser->priv;
    for (i = 0; i < VP9_REFS_PER_FRAME; i++) {
        found = vp9_read_bit(br);
        if (found) {
            uint8_t idx = frame_hdr->ref_frame_indices[i];
            frame_hdr->size_from_ref[i] = TRUE;
            frame_hdr->width = priv->reference[idx].width;
            frame_hdr->height = priv->reference[idx].height;
            break;
        }
    }
    if (!found) {
        read_frame_size(br, &frame_hdr->width, &frame_hdr->height);
    }
}

static VP9_INTERP_FILTER read_interp_filter(BitReader* br)
{
    const VP9_INTERP_FILTER filter_map[] = { VP9_EIGHTTAP_SMOOTH,
        VP9_EIGHTTAP,
        VP9_EIGHTTAP_SHARP,
        VP9_BILINEAR };
    return vp9_read_bit(br) ? VP9_SWITCHABLE
                            : filter_map[vp9_read_bits(br, 2)];
}

static void read_loopfilter(Vp9LoopFilter* lf, BitReader* br)
{
    lf->filter_level = vp9_read_bits(br, 6);
    lf->sharpness_level = vp9_read_bits(br, 3);

    lf->mode_ref_delta_update = 0;

    lf->mode_ref_delta_enabled = vp9_read_bit(br);
    if (lf->mode_ref_delta_enabled) {
        lf->mode_ref_delta_update = vp9_read_bit(br);
        if (lf->mode_ref_delta_update) {
            int i;
            for (i = 0; i < VP9_MAX_REF_LF_DELTAS; i++) {
                lf->update_ref_deltas[i] = vp9_read_bit(br);
                if (lf->update_ref_deltas[i])
                    lf->ref_deltas[i] = vp9_read_signed_bits(br, 6);
            }

            for (i = 0; i < VP9_MAX_MODE_LF_DELTAS; i++) {
                lf->update_mode_deltas[i] = vp9_read_bit(br);
                if (lf->update_mode_deltas[i])
                    lf->mode_deltas[i] = vp9_read_signed_bits(br, 6);
            }
        }
    }
}

static int8_t read_delta_q(BitReader* br)
{
    return vp9_read_bit(br) ? vp9_read_signed_bits(br, 4) : 0;
}

static void read_quantization(Vp9FrameHdr* frame_hdr, BitReader* br)
{
    frame_hdr->base_qindex = vp9_read_bits(br, QINDEX_BITS);
    frame_hdr->y_dc_delta_q = read_delta_q(br);
    frame_hdr->uv_dc_delta_q = read_delta_q(br);
    frame_hdr->uv_ac_delta_q = read_delta_q(br);
}

static void read_segmentation(Vp9SegmentationInfo* seg, BitReader* br)
{
    int i;

    seg->update_map = FALSE;
    seg->update_data = FALSE;

    seg->enabled = vp9_read_bit(br);
    if (!seg->enabled)
        return;
    seg->update_map = vp9_read_bit(br);
    if (seg->update_map) {
        for (i = 0; i < VP9_SEG_TREE_PROBS; i++) {
            seg->update_tree_probs[i] = vp9_read_bit(br);
            seg->tree_probs[i] = seg->update_tree_probs[i] ? vp9_read_bits(br, 8) : MAX_PROB;
        }
        seg->temporal_update = vp9_read_bit(br);
        if (seg->temporal_update) {
            for (i = 0; i < VP9_PREDICTION_PROBS; i++) {
                seg->update_pred_probs[i] = vp9_read_bit(br);
                seg->pred_probs[i] = seg->update_pred_probs[i] ? vp9_read_bits(br, 8) : MAX_PROB;
            }
        }
        else {
            for (i = 0; i < VP9_PREDICTION_PROBS; i++) {
                seg->pred_probs[i] = MAX_PROB;
            }
        }
    }

    seg->update_data = vp9_read_bit(br);

    if (seg->update_data) {
        /* clear all features */
        memset(seg->data, 0, sizeof(seg->data));

        seg->abs_delta = vp9_read_bit(br);
        for (i = 0; i < VP9_MAX_SEGMENTS; i++) {
            Vp9SegmentationInfoData* seg_data = seg->data + i;
            uint8_t data;
            /* SEG_LVL_ALT_Q */
            seg_data->alternate_quantizer_enabled = vp9_read_bit(br);
            if (seg_data->alternate_quantizer_enabled) {
                data = vp9_read_bits(br, 8);
                seg_data->alternate_quantizer = vp9_read_bit(br) ? -data : data;
            }
            /* SEG_LVL_ALT_LF */
            seg_data->alternate_loop_filter_enabled = vp9_read_bit(br);
            if (seg_data->alternate_loop_filter_enabled) {
                data = vp9_read_bits(br, 6);
                seg_data->alternate_loop_filter = vp9_read_bit(br) ? -data : data;
            }
            /* SEG_LVL_REF_FRAME */
            seg_data->reference_frame_enabled = vp9_read_bit(br);
            if (seg_data->reference_frame_enabled) {
                seg_data->reference_frame = vp9_read_bits(br, 2);
            }
            seg_data->reference_skip = vp9_read_bit(br);
        }
    }
}

#define MIN_TILE_WIDTH_B64 4
#define MAX_TILE_WIDTH_B64 64
uint32_t get_max_lb_tile_cols(uint32_t sb_cols)
{
    int log2 = 0;
    while ((sb_cols >> log2) >= MIN_TILE_WIDTH_B64)
        ++log2;
    if (log2)
        log2--;
    return log2;
}

uint32_t get_min_lb_tile_cols(uint32_t sb_cols)
{
    uint32_t log2 = 0;
    while ((uint64_t)(MAX_TILE_WIDTH_B64 << log2) < sb_cols)
        ++log2;
    return log2;
}

/* align to 64, follow specification 6.2.6 Compute image size syntax */
#define SB_ALIGN(w) (((w) + 63) >> 6)
static BOOL read_tile_info(Vp9FrameHdr* frame_hdr, BitReader* br)
{
    const uint32_t sb_cols = SB_ALIGN(frame_hdr->width);
    uint32_t min_lb_tile_cols = get_min_lb_tile_cols(sb_cols);
    uint32_t max_lb_tile_cols = get_max_lb_tile_cols(sb_cols);
    uint32_t max_ones = max_lb_tile_cols - min_lb_tile_cols;

    /* columns */
    frame_hdr->log2_tile_columns = min_lb_tile_cols;
    while (max_ones-- && vp9_read_bit(br))
        frame_hdr->log2_tile_columns++;

    /* row */
    frame_hdr->log2_tile_rows = vp9_read_bit(br);
    if (frame_hdr->log2_tile_rows)
        frame_hdr->log2_tile_rows += vp9_read_bit(br);
    return TRUE;
}

static void loop_filter_update(Vp9Parser* parser, const Vp9LoopFilter* lf)
{
    Vp9ParserPrivate* priv = (Vp9ParserPrivate*)parser->priv;
    int i;

    for (i = 0; i < VP9_MAX_REF_LF_DELTAS; i++) {
        if (lf->update_ref_deltas[i])
            priv->ref_deltas[i] = lf->ref_deltas[i];
    }

    for (i = 0; i < VP9_MAX_MODE_LF_DELTAS; i++) {
        if (lf->update_mode_deltas[i])
            priv->mode_deltas[i] = lf->mode_deltas[i];
    }
}

BOOL compare_and_set(int8_t* dest, const int8_t src)
{
    const int8_t old = *dest;
    *dest = src;
    return old != src;
}

void init_dequantizer(Vp9Parser* parser)
{
    Vp9ParserPrivate* priv = (Vp9ParserPrivate*)parser->priv;
    int q;
    for (q = 0; q < QINDEX_RANGE; q++) {
        priv->y_dequant[q][0] = vp9_dc_quant(parser->bit_depth, q, priv->y_dc_delta_q);
        priv->y_dequant[q][1] = vp9_ac_quant(parser->bit_depth, q, 0);
        priv->uv_dequant[q][0] = vp9_dc_quant(parser->bit_depth, q, priv->uv_dc_delta_q);
        priv->uv_dequant[q][1] = vp9_ac_quant(parser->bit_depth, q, priv->uv_ac_delta_q);
    }
}
static void quantization_update(Vp9Parser* parser, const Vp9FrameHdr* frame_hdr)
{
    BOOL update = FALSE;
    Vp9ParserPrivate* priv = (Vp9ParserPrivate*)parser->priv;
    update |= compare_and_set(&priv->y_dc_delta_q, frame_hdr->y_dc_delta_q);
    update |= compare_and_set(&priv->uv_dc_delta_q, frame_hdr->uv_dc_delta_q);
    update |= compare_and_set(&priv->uv_ac_delta_q, frame_hdr->uv_ac_delta_q);
    if (update) {
        init_dequantizer(parser);
    }
    parser->lossless_flag = frame_hdr->base_qindex == 0 && frame_hdr->y_dc_delta_q == 0 && frame_hdr->uv_dc_delta_q == 0 && frame_hdr->uv_ac_delta_q == 0;
}

uint8_t seg_get_base_qindex(const Vp9Parser* parser, const Vp9FrameHdr* frame_hdr, int segid)
{
    int seg_base = frame_hdr->base_qindex;
    Vp9ParserPrivate* priv = (Vp9ParserPrivate*)parser->priv;
    const Vp9SegmentationInfoData* seg = priv->segmentation + segid;
    /* DEBUG("id = %d, seg_base = %d, seg enable = %d, alt eanble = %d, abs = %d, alt= %d\n",segid,
     seg_base, frame_hdr->segmentation.enabled, seg->alternate_quantizer_enabled, priv->segmentation_abs_delta,  seg->alternate_quantizer);
 */
    if (frame_hdr->segmentation.enabled && seg->alternate_quantizer_enabled) {
        if (priv->segmentation_abs_delta)
            seg_base = seg->alternate_quantizer;
        else
            seg_base += seg->alternate_quantizer;
    }
    return clamp(seg_base, 0, MAXQ);
}

uint8_t seg_get_filter_level(const Vp9Parser* parser, const Vp9FrameHdr* frame_hdr, int segid)
{
    int seg_filter = frame_hdr->loopfilter.filter_level;
    Vp9ParserPrivate* priv = (Vp9ParserPrivate*)parser->priv;
    const Vp9SegmentationInfoData* seg = priv->segmentation + segid;

    if (frame_hdr->segmentation.enabled && seg->alternate_loop_filter_enabled) {
        if (priv->segmentation_abs_delta)
            seg_filter = seg->alternate_loop_filter;
        else
            seg_filter += seg->alternate_loop_filter;
    }
    return clamp(seg_filter, 0, MAX_LOOP_FILTER);
}

/*save segmentation info from frame header to parser*/
static void segmentation_save(Vp9Parser* parser, const Vp9FrameHdr* frame_hdr)
{
    const Vp9SegmentationInfo* info = &frame_hdr->segmentation;
    if (!info->enabled)
        return;
    if (info->update_map) {
        ASSERT(sizeof(parser->mb_segment_tree_probs) == sizeof(info->tree_probs));
        ASSERT(sizeof(parser->segment_pred_probs) == sizeof(info->pred_probs));
        memcpy(parser->mb_segment_tree_probs, info->tree_probs, sizeof(info->tree_probs));
        memcpy(parser->segment_pred_probs, info->pred_probs, sizeof(info->pred_probs));
    }
    if (info->update_data) {
        Vp9ParserPrivate* priv = (Vp9ParserPrivate*)parser->priv;
        priv->segmentation_abs_delta = info->abs_delta;
        ASSERT(sizeof(priv->segmentation) == sizeof(info->data));
        memcpy(priv->segmentation, info->data, sizeof(info->data));
    }
}

static void segmentation_update(Vp9Parser* parser, const Vp9FrameHdr* frame_hdr)
{
    int i = 0;
    const Vp9ParserPrivate* priv = (Vp9ParserPrivate*)parser->priv;
    const Vp9LoopFilter* lf = &frame_hdr->loopfilter;
    int default_filter = lf->filter_level;
    const int scale = 1 << (default_filter >> 5);

    segmentation_save(parser, frame_hdr);

    for (i = 0; i < VP9_MAX_SEGMENTS; i++) {
        uint8_t q = seg_get_base_qindex(parser, frame_hdr, i);

        Vp9Segmentation* seg = parser->segmentation + i;
        const Vp9SegmentationInfoData* info = priv->segmentation + i;

        seg->luma_dc_quant_scale = priv->y_dequant[q][0];
        seg->luma_ac_quant_scale = priv->y_dequant[q][1];
        seg->chroma_dc_quant_scale = priv->uv_dequant[q][0];
        seg->chroma_ac_quant_scale = priv->uv_dequant[q][1];

        if (lf->filter_level) {
            uint8_t filter = seg_get_filter_level(parser, frame_hdr, i);

            if (!lf->mode_ref_delta_enabled) {
                memset(seg->filter_level, filter, sizeof(seg->filter_level));
            }
            else {
                int ref, mode;
                const int intra_filter = filter + priv->ref_deltas[VP9_INTRA_FRAME] * scale;
                seg->filter_level[VP9_INTRA_FRAME][0] = clamp(intra_filter, 0, MAX_LOOP_FILTER);
                for (ref = VP9_LAST_FRAME; ref < VP9_MAX_REF_FRAMES; ++ref) {
                    for (mode = 0; mode < VP9_MAX_MODE_LF_DELTAS; ++mode) {
                        const int inter_filter = filter + priv->ref_deltas[ref] * scale
                            + priv->mode_deltas[mode] * scale;
                        seg->filter_level[ref][mode] = clamp(inter_filter, 0, MAX_LOOP_FILTER);
                    }
                }
            }
        }
        seg->reference_frame_enabled = info->reference_frame_enabled;
        ;
        seg->reference_frame = info->reference_frame;
        seg->reference_skip = info->reference_skip;
    }
}

static void reference_update(Vp9Parser* parser, const Vp9FrameHdr* const frame_hdr)
{
    uint8_t flag = 1;
    uint8_t refresh_frame_flags;
    int i;
    Vp9ParserPrivate* priv = (Vp9ParserPrivate*)parser->priv;
    ReferenceSize* reference = priv->reference;
    if (frame_hdr->frame_type == VP9_KEY_FRAME) {
        refresh_frame_flags = 0xff;
    }
    else {
        refresh_frame_flags = frame_hdr->refresh_frame_flags;
    }
    for (i = 0; i < VP9_REF_FRAMES; i++) {
        if (refresh_frame_flags & flag) {
            reference[i].width = frame_hdr->width;
            reference[i].height = frame_hdr->height;
        }
        flag <<= 1;
    }
}

static inline int key_or_intra_only(const Vp9FrameHdr* frame_hdr)
{
    return frame_hdr->frame_type == VP9_KEY_FRAME || frame_hdr->intra_only;
}

static void set_default_lf_deltas(Vp9Parser* parser)
{
    Vp9ParserPrivate* priv = (Vp9ParserPrivate*)parser->priv;
    priv->ref_deltas[VP9_INTRA_FRAME] = 1;
    priv->ref_deltas[VP9_LAST_FRAME] = 0;
    priv->ref_deltas[VP9_GOLDEN_FRAME] = -1;
    priv->ref_deltas[VP9_ALTREF_FRAME] = -1;

    priv->mode_deltas[0] = 0;
    priv->mode_deltas[1] = 0;
}

static void set_default_segmentation_info(Vp9Parser* parser)
{
    Vp9ParserPrivate* priv = (Vp9ParserPrivate*)parser->priv;

    memset(priv->segmentation, 0, sizeof(priv->segmentation));
    priv->segmentation_abs_delta = FALSE;
}

static void setup_past_independence(Vp9Parser* parser, Vp9FrameHdr* const frame_hdr)
{
    set_default_lf_deltas(parser);
    set_default_segmentation_info(parser);
    memset(frame_hdr->ref_frame_sign_bias, 0, sizeof(frame_hdr->ref_frame_sign_bias));
}

static Vp9ParseResult vp9_parser_update(Vp9Parser* parser, Vp9FrameHdr* const frame_hdr)
{
    if (frame_hdr->frame_type == VP9_KEY_FRAME) {
        init_vp9_parser(parser, frame_hdr->bit_depth);
    }
    if (key_or_intra_only(frame_hdr) || frame_hdr->error_resilient_mode) {
        setup_past_independence(parser, frame_hdr);
    }
    loop_filter_update(parser, &frame_hdr->loopfilter);
    quantization_update(parser, frame_hdr);
    segmentation_update(parser, frame_hdr);
    reference_update(parser, frame_hdr);
    return VP9_PARSER_OK;
}

static Vp9ParseResult vp9_color_config(Vp9Parser* parser, Vp9FrameHdr* frame_hdr, BitReader* br)
{
    if (frame_hdr->profile >= VP9_PROFILE_2) {
        frame_hdr->bit_depth = vp9_read_bit(br) ? VP9_BITS_12 : VP9_BITS_10;
        if (VP9_BITS_12 == frame_hdr->bit_depth) {
            ERROR("vp9 12 bits-depth is unsupported by now!");
            return VP9_PARSER_UNSUPPORTED;
        }
    }
    else {
        frame_hdr->bit_depth = VP9_BITS_8;
    }

    frame_hdr->color_space = (VP9_COLOR_SPACE)vp9_read_bits(br, 3);
    if (frame_hdr->color_space != VP9_SRGB) {
        vp9_read_bit(br); //color_range
        if (frame_hdr->profile == VP9_PROFILE_1 || frame_hdr->profile == VP9_PROFILE_3) {
            frame_hdr->subsampling_x = vp9_read_bit(br);
            frame_hdr->subsampling_y = vp9_read_bit(br);

            if (vp9_read_bit(br)) { //reserved_zero
                ERROR("reserved bit");
                return VP9_PARSER_ERROR;
            }
        }
        else {
            frame_hdr->subsampling_y = frame_hdr->subsampling_x = 1;
        }
    }
    else {
        ERROR("do not support SRGB");
        return VP9_PARSER_UNSUPPORTED;
    }

    return VP9_PARSER_OK;
}

Vp9ParseResult
vp9_parse_frame_header(Vp9Parser* parser, Vp9FrameHdr* frame_hdr, const uint8_t* data, uint32_t size)
{
#define FRAME_CONTEXTS_BITS 2
    BitReader bit_reader(data, size);
    BitReader* br = &bit_reader;
    memset(frame_hdr, 0, sizeof(*frame_hdr));
    /* Uncompressed Data Chunk */
    if (!verify_frame_marker(br))
        goto error;
    frame_hdr->profile = read_profile(br);
    if (frame_hdr->profile > MAX_VP9_PROFILES)
        goto error;
    frame_hdr->show_existing_frame = vp9_read_bit(br);
    if (frame_hdr->show_existing_frame) {
        frame_hdr->frame_to_show = vp9_read_bits(br, VP9_REF_FRAMES_LOG2);
        return VP9_PARSER_OK;
    }
    frame_hdr->frame_type = (VP9_FRAME_TYPE)vp9_read_bit(br);
    frame_hdr->show_frame = vp9_read_bit(br);
    frame_hdr->error_resilient_mode = vp9_read_bit(br);
    if (frame_hdr->frame_type == VP9_KEY_FRAME) {
        if (!verify_sync_code(br))
            goto error;
        if (vp9_color_config(parser, frame_hdr, br) != VP9_PARSER_OK)
            goto error;
        read_frame_size(br, &frame_hdr->width, &frame_hdr->height);
        read_display_frame_size(frame_hdr, br);
    }
    else {
        frame_hdr->intra_only = frame_hdr->show_frame ? 0 : vp9_read_bit(br);
        frame_hdr->reset_frame_context = frame_hdr->error_resilient_mode ? 0 : vp9_read_bits(br, 2);
        if (frame_hdr->intra_only) {
            if (!verify_sync_code(br))
                goto error;
            if (frame_hdr->profile > VP9_PROFILE_0) {
                if (vp9_color_config(parser, frame_hdr, br) != VP9_PARSER_OK)
                    goto error;
            }
            else {
                frame_hdr->color_space = VP9_BT_601;
                frame_hdr->subsampling_y = frame_hdr->subsampling_x = 1;
                frame_hdr->bit_depth = VP9_BITS_8;
            }

            frame_hdr->refresh_frame_flags = vp9_read_bits(br, VP9_REF_FRAMES);
            read_frame_size(br, &frame_hdr->width, &frame_hdr->height);
            read_display_frame_size(frame_hdr, br);
        }
        else {
            int i;
            frame_hdr->refresh_frame_flags = vp9_read_bits(br, VP9_REF_FRAMES);
            for (i = 0; i < VP9_REFS_PER_FRAME; i++) {
                frame_hdr->ref_frame_indices[i] = vp9_read_bits(br, VP9_REF_FRAMES_LOG2);
                frame_hdr->ref_frame_sign_bias[i] = vp9_read_bit(br);
            }
            read_frame_size_from_refs(parser, frame_hdr, br);
            read_display_frame_size(frame_hdr, br);
            frame_hdr->allow_high_precision_mv = vp9_read_bit(br);
            frame_hdr->mcomp_filter_type = read_interp_filter(br);
        }
    }
    if (!frame_hdr->error_resilient_mode) {
        frame_hdr->refresh_frame_context = vp9_read_bit(br);
        frame_hdr->frame_parallel_decoding_mode = vp9_read_bit(br);
    }
    else {
        frame_hdr->frame_parallel_decoding_mode = TRUE;
    }
    frame_hdr->frame_context_idx = vp9_read_bits(br, FRAME_CONTEXTS_BITS);
    read_loopfilter(&frame_hdr->loopfilter, br);
    read_quantization(frame_hdr, br);
    read_segmentation(&frame_hdr->segmentation, br);
    if (!read_tile_info(frame_hdr, br))
        goto error;
    frame_hdr->first_partition_size = vp9_read_bits(br, 16);
    if (!frame_hdr->first_partition_size)
        goto error;
    frame_hdr->frame_header_length_in_bytes = (br->getPos() + 7) / 8;
    return vp9_parser_update(parser, frame_hdr);
error:
    return VP9_PARSER_ERROR;
}