| /* |
| * Copyright © 2018, VideoLAN and dav1d authors |
| * Copyright © 2018, Two Orioles, LLC |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, this |
| * list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| |
| #include <assert.h> |
| #include <errno.h> |
| #include <limits.h> |
| #include <stdio.h> |
| |
| #include "dav1d/data.h" |
| |
| #include "common/intops.h" |
| |
| #include "src/decode.h" |
| #include "src/getbits.h" |
| #include "src/levels.h" |
| #include "src/obu.h" |
| #include "src/ref.h" |
| #include "src/warpmv.h" |
| |
| static int parse_seq_hdr(Dav1dContext *const c, GetBits *const gb) { |
| const uint8_t *const init_ptr = gb->ptr; |
| Av1SequenceHeader *const hdr = &c->seq_hdr; |
| |
| #define DEBUG_SEQ_HDR 0 |
| |
| hdr->profile = get_bits(gb, 3); |
| if (hdr->profile > 2U) goto error; |
| #if DEBUG_SEQ_HDR |
| printf("SEQHDR: post-profile: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| hdr->still_picture = get_bits(gb, 1); |
| hdr->reduced_still_picture_header = get_bits(gb, 1); |
| if (hdr->reduced_still_picture_header && !hdr->still_picture) goto error; |
| #if DEBUG_SEQ_HDR |
| printf("SEQHDR: post-stillpicture_flags: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| if (hdr->reduced_still_picture_header) { |
| hdr->timing_info_present = 0; |
| hdr->decoder_model_info_present = 0; |
| hdr->display_model_info_present = 0; |
| hdr->num_operating_points = 1; |
| hdr->operating_points[0].idc = 0; |
| hdr->operating_points[0].major_level = get_bits(gb, 3); |
| hdr->operating_points[0].minor_level = get_bits(gb, 2); |
| hdr->operating_points[0].tier = 0; |
| hdr->operating_points[0].decoder_model_param_present = 0; |
| hdr->operating_points[0].display_model_param_present = 0; |
| } else { |
| hdr->timing_info_present = get_bits(gb, 1); |
| if (hdr->timing_info_present) { |
| hdr->num_units_in_tick = get_bits(gb, 32); |
| hdr->time_scale = get_bits(gb, 32); |
| hdr->equal_picture_interval = get_bits(gb, 1); |
| if (hdr->equal_picture_interval) |
| hdr->num_ticks_per_picture = get_vlc(gb) + 1; |
| |
| hdr->decoder_model_info_present = get_bits(gb, 1); |
| if (hdr->decoder_model_info_present) { |
| hdr->bitrate_scale = get_bits(gb, 4); |
| hdr->buffer_size_scale = get_bits(gb, 4); |
| hdr->encoder_decoder_buffer_delay_length = get_bits(gb, 5) + 1; |
| hdr->num_units_in_decoding_tick = get_bits(gb, 32); |
| hdr->buffer_removal_delay_length = get_bits(gb, 5) + 1; |
| hdr->frame_presentation_delay_length = get_bits(gb, 5) + 1; |
| } |
| } else { |
| hdr->decoder_model_info_present = 0; |
| } |
| #if DEBUG_SEQ_HDR |
| printf("SEQHDR: post-timinginfo: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| hdr->display_model_info_present = get_bits(gb, 1); |
| hdr->num_operating_points = get_bits(gb, 5) + 1; |
| for (int i = 0; i < c->seq_hdr.num_operating_points; i++) { |
| struct Av1SequenceHeaderOperatingPoint *const op = |
| &hdr->operating_points[i]; |
| op->idc = get_bits(gb, 12); |
| op->major_level = 2 + get_bits(gb, 3); |
| op->minor_level = get_bits(gb, 2); |
| op->tier = op->major_level > 3 ? get_bits(gb, 1) : 0; |
| op->decoder_model_param_present = |
| hdr->decoder_model_info_present && get_bits(gb, 1); |
| if (op->decoder_model_param_present) { |
| op->bitrate = get_vlc(gb) + 1; |
| op->buffer_size = get_vlc(gb) + 1; |
| op->cbr = get_bits(gb, 1); |
| op->decoder_buffer_delay = |
| get_bits(gb, hdr->encoder_decoder_buffer_delay_length); |
| op->encoder_buffer_delay = |
| get_bits(gb, hdr->encoder_decoder_buffer_delay_length); |
| op->low_delay_mode = get_bits(gb, 1); |
| } |
| op->display_model_param_present = |
| hdr->display_model_info_present && get_bits(gb, 1); |
| if (op->display_model_param_present) { |
| op->initial_display_delay = get_bits(gb, 4) + 1; |
| } |
| } |
| #if DEBUG_SEQ_HDR |
| printf("SEQHDR: post-operating-points: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| } |
| |
| hdr->width_n_bits = get_bits(gb, 4) + 1; |
| hdr->height_n_bits = get_bits(gb, 4) + 1; |
| hdr->max_width = get_bits(gb, hdr->width_n_bits) + 1; |
| hdr->max_height = get_bits(gb, hdr->height_n_bits) + 1; |
| #if DEBUG_SEQ_HDR |
| printf("SEQHDR: post-size: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| hdr->frame_id_numbers_present = |
| hdr->reduced_still_picture_header ? 0 : get_bits(gb, 1); |
| if (hdr->frame_id_numbers_present) { |
| hdr->delta_frame_id_n_bits = get_bits(gb, 4) + 2; |
| hdr->frame_id_n_bits = get_bits(gb, 3) + hdr->delta_frame_id_n_bits + 1; |
| } |
| #if DEBUG_SEQ_HDR |
| printf("SEQHDR: post-frame-id-numbers-present: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| hdr->sb128 = get_bits(gb, 1); |
| hdr->filter_intra = get_bits(gb, 1); |
| hdr->intra_edge_filter = get_bits(gb, 1); |
| if (hdr->reduced_still_picture_header) { |
| hdr->inter_intra = 0; |
| hdr->masked_compound = 0; |
| hdr->warped_motion = 0; |
| hdr->dual_filter = 0; |
| hdr->order_hint = 0; |
| hdr->jnt_comp = 0; |
| hdr->ref_frame_mvs = 0; |
| hdr->order_hint_n_bits = 0; |
| hdr->screen_content_tools = ADAPTIVE; |
| hdr->force_integer_mv = ADAPTIVE; |
| } else { |
| hdr->inter_intra = get_bits(gb, 1); |
| hdr->masked_compound = get_bits(gb, 1); |
| hdr->warped_motion = get_bits(gb, 1); |
| hdr->dual_filter = get_bits(gb, 1); |
| hdr->order_hint = get_bits(gb, 1); |
| if (hdr->order_hint) { |
| hdr->jnt_comp = get_bits(gb, 1); |
| hdr->ref_frame_mvs = get_bits(gb, 1); |
| } else { |
| hdr->jnt_comp = 0; |
| hdr->ref_frame_mvs = 0; |
| hdr->order_hint_n_bits = 0; |
| } |
| hdr->screen_content_tools = get_bits(gb, 1) ? ADAPTIVE : get_bits(gb, 1); |
| #if DEBUG_SEQ_HDR |
| printf("SEQHDR: post-screentools: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| hdr->force_integer_mv = hdr->screen_content_tools ? |
| get_bits(gb, 1) ? ADAPTIVE : get_bits(gb, 1) : 2; |
| if (hdr->order_hint) |
| hdr->order_hint_n_bits = get_bits(gb, 3) + 1; |
| } |
| hdr->super_res = get_bits(gb, 1); |
| hdr->cdef = get_bits(gb, 1); |
| hdr->restoration = get_bits(gb, 1); |
| #if DEBUG_SEQ_HDR |
| printf("SEQHDR: post-featurebits: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| const int hbd = get_bits(gb, 1); |
| hdr->bpc = hdr->profile == 2 && hbd ? 10 + 2 * get_bits(gb, 1): 8 + 2 * hbd; |
| hdr->hbd = hdr->bpc > 8; |
| const int monochrome = hdr->profile != 1 ? get_bits(gb, 1) : 0; |
| hdr->color_description_present = get_bits(gb, 1); |
| if (hdr->color_description_present) { |
| hdr->pri = get_bits(gb, 8); |
| hdr->trc = get_bits(gb, 8); |
| hdr->mtrx = get_bits(gb, 8); |
| } else { |
| hdr->pri = DAV1D_COLOR_PRI_UNKNOWN; |
| hdr->trc = DAV1D_TRC_UNKNOWN; |
| hdr->mtrx = DAV1D_MC_UNKNOWN; |
| } |
| if (monochrome) { |
| hdr->color_range = get_bits(gb, 1); |
| hdr->layout = DAV1D_PIXEL_LAYOUT_I400; |
| hdr->chr = DAV1D_CHR_UNKNOWN; |
| hdr->separate_uv_delta_q = 0; |
| } else if (hdr->pri == DAV1D_COLOR_PRI_BT709 && |
| hdr->trc == DAV1D_TRC_SRGB && |
| hdr->mtrx == DAV1D_MC_IDENTITY) |
| { |
| hdr->layout = DAV1D_PIXEL_LAYOUT_I444; |
| hdr->color_range = 1; |
| if (hdr->profile != 1 && !(hdr->profile == 2 && hdr->bpc == 12)) |
| goto error; |
| } else { |
| hdr->color_range = get_bits(gb, 1); |
| switch (hdr->profile) { |
| case 0: hdr->layout = DAV1D_PIXEL_LAYOUT_I420; break; |
| case 1: hdr->layout = DAV1D_PIXEL_LAYOUT_I444; break; |
| case 2: |
| if (hdr->bpc == 12) { |
| hdr->layout = get_bits(gb, 1) ? |
| get_bits(gb, 1) ? DAV1D_PIXEL_LAYOUT_I420 : |
| DAV1D_PIXEL_LAYOUT_I422 : |
| DAV1D_PIXEL_LAYOUT_I444; |
| } else |
| hdr->layout = DAV1D_PIXEL_LAYOUT_I422; |
| break; |
| } |
| if (hdr->layout == DAV1D_PIXEL_LAYOUT_I420) |
| hdr->chr = get_bits(gb, 2); |
| hdr->separate_uv_delta_q = get_bits(gb, 1); |
| } |
| #if DEBUG_SEQ_HDR |
| printf("SEQHDR: post-colorinfo: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| c->seq_hdr.film_grain_present = get_bits(gb, 1); |
| #if DEBUG_SEQ_HDR |
| printf("SEQHDR: post-filmgrain: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| get_bits(gb, 1); // dummy bit |
| |
| return flush_get_bits(gb) - init_ptr; |
| |
| error: |
| fprintf(stderr, "Error parsing sequence header\n"); |
| return -EINVAL; |
| } |
| |
| static int read_frame_size(Dav1dContext *const c, GetBits *const gb, |
| const int use_ref) |
| { |
| const Av1SequenceHeader *const seqhdr = &c->seq_hdr; |
| Av1FrameHeader *const hdr = &c->frame_hdr; |
| |
| if (use_ref) { |
| for (int i = 0; i < 7; i++) { |
| if (get_bits(gb, 1)) { |
| Dav1dThreadPicture *const ref = |
| &c->refs[c->frame_hdr.refidx[i]].p; |
| if (!ref->p.data[0]) return -1; |
| // FIXME render_* may be wrong |
| hdr->render_width = hdr->width = ref->p.p.w; |
| hdr->render_height = hdr->height = ref->p.p.h; |
| hdr->super_res = 0; // FIXME probably wrong |
| return 0; |
| } |
| } |
| } |
| |
| if (hdr->frame_size_override) { |
| hdr->width = get_bits(gb, seqhdr->width_n_bits) + 1; |
| hdr->height = get_bits(gb, seqhdr->height_n_bits) + 1; |
| } else { |
| hdr->width = seqhdr->max_width; |
| hdr->height = seqhdr->max_height; |
| } |
| hdr->super_res = seqhdr->super_res && get_bits(gb, 1); |
| if (hdr->super_res) return -1; // FIXME |
| hdr->have_render_size = get_bits(gb, 1); |
| if (hdr->have_render_size) { |
| hdr->render_width = get_bits(gb, seqhdr->width_n_bits) + 1; |
| hdr->render_height = get_bits(gb, seqhdr->height_n_bits) + 1; |
| } else { |
| hdr->render_width = hdr->width; |
| hdr->render_height = hdr->height; |
| } |
| return 0; |
| } |
| |
| static inline int tile_log2(int sz, int tgt) { |
| int k; |
| for (k = 0; (sz << k) < tgt; k++) ; |
| return k; |
| } |
| |
| static const Av1LoopfilterModeRefDeltas default_mode_ref_deltas = { |
| .mode_delta = { 0, 0 }, |
| .ref_delta = { 1, 0, 0, 0, -1, 0, -1, -1 }, |
| }; |
| |
| static int parse_frame_hdr(Dav1dContext *const c, GetBits *const gb, |
| const int have_trailing_bit) |
| { |
| const uint8_t *const init_ptr = gb->ptr; |
| const Av1SequenceHeader *const seqhdr = &c->seq_hdr; |
| Av1FrameHeader *const hdr = &c->frame_hdr; |
| int res; |
| |
| #define DEBUG_FRAME_HDR 0 |
| |
| hdr->show_existing_frame = |
| !seqhdr->reduced_still_picture_header && get_bits(gb, 1); |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-show_existing_frame: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| if (hdr->show_existing_frame) { |
| hdr->existing_frame_idx = get_bits(gb, 3); |
| if (seqhdr->frame_id_numbers_present) |
| hdr->frame_id = get_bits(gb, seqhdr->frame_id_n_bits); |
| goto end; |
| } |
| |
| hdr->frame_type = seqhdr->reduced_still_picture_header ? DAV1D_FRAME_TYPE_KEY : get_bits(gb, 2); |
| hdr->show_frame = seqhdr->reduced_still_picture_header || get_bits(gb, 1); |
| if (!hdr->show_frame) |
| hdr->showable_frame = get_bits(gb, 1); |
| hdr->error_resilient_mode = |
| (hdr->frame_type == DAV1D_FRAME_TYPE_KEY && hdr->show_frame) || |
| hdr->frame_type == DAV1D_FRAME_TYPE_SWITCH || |
| seqhdr->reduced_still_picture_header || get_bits(gb, 1); |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-frametype_bits: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| hdr->disable_cdf_update = get_bits(gb, 1); |
| hdr->allow_screen_content_tools = seqhdr->screen_content_tools == ADAPTIVE ? |
| get_bits(gb, 1) : seqhdr->screen_content_tools; |
| if (hdr->allow_screen_content_tools) |
| hdr->force_integer_mv = seqhdr->force_integer_mv == ADAPTIVE ? |
| get_bits(gb, 1) : seqhdr->force_integer_mv; |
| |
| if (seqhdr->frame_id_numbers_present) |
| hdr->frame_id = get_bits(gb, seqhdr->frame_id_n_bits); |
| |
| hdr->frame_size_override = seqhdr->reduced_still_picture_header ? 0 : |
| hdr->frame_type == DAV1D_FRAME_TYPE_SWITCH ? 1 : get_bits(gb, 1); |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-frame_size_override_flag: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| hdr->frame_offset = seqhdr->order_hint ? |
| get_bits(gb, seqhdr->order_hint_n_bits) : 0; |
| hdr->primary_ref_frame = !hdr->error_resilient_mode && hdr->frame_type & 1 ? |
| get_bits(gb, 3) : PRIMARY_REF_NONE; |
| |
| if (hdr->frame_type == DAV1D_FRAME_TYPE_KEY) { |
| hdr->refresh_frame_flags = hdr->show_frame ? 0xff : get_bits(gb, 8); |
| if ((res = read_frame_size(c, gb, 0)) < 0) goto error; |
| hdr->allow_intrabc = hdr->allow_screen_content_tools && |
| /* FIXME: no superres scaling && */ get_bits(gb, 1); |
| hdr->use_ref_frame_mvs = 0; |
| } else { |
| if (hdr->error_resilient_mode && seqhdr->order_hint) |
| for (int i = 0; i < 8; i++) |
| get_bits(gb, seqhdr->order_hint_n_bits); |
| |
| if (hdr->frame_type == DAV1D_FRAME_TYPE_INTRA) { |
| hdr->refresh_frame_flags = get_bits(gb, 8); |
| if ((res = read_frame_size(c, gb, 0)) < 0) goto error; |
| hdr->allow_intrabc = hdr->allow_screen_content_tools && |
| /* FIXME: no superres scaling && */ get_bits(gb, 1); |
| } else { |
| hdr->allow_intrabc = 0; |
| hdr->refresh_frame_flags = hdr->frame_type == DAV1D_FRAME_TYPE_SWITCH ? 0xff : |
| get_bits(gb, 8); |
| hdr->frame_ref_short_signaling = |
| seqhdr->order_hint && get_bits(gb, 1); |
| if (hdr->frame_ref_short_signaling) goto error; // FIXME |
| for (int i = 0; i < 7; i++) { |
| hdr->refidx[i] = get_bits(gb, 3); |
| if (seqhdr->frame_id_numbers_present) |
| get_bits(gb, seqhdr->delta_frame_id_n_bits); |
| } |
| const int use_ref = !hdr->error_resilient_mode && |
| hdr->frame_size_override; |
| if ((res = read_frame_size(c, gb, use_ref)) < 0) goto error; |
| hdr->hp = !hdr->force_integer_mv && get_bits(gb, 1); |
| hdr->subpel_filter_mode = get_bits(gb, 1) ? FILTER_SWITCHABLE : |
| get_bits(gb, 2); |
| hdr->switchable_motion_mode = get_bits(gb, 1); |
| hdr->use_ref_frame_mvs = !hdr->error_resilient_mode && |
| seqhdr->ref_frame_mvs && seqhdr->order_hint && |
| hdr->frame_type & 1 && get_bits(gb, 1); |
| } |
| } |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-frametype-specific-bits: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| hdr->refresh_context = !seqhdr->reduced_still_picture_header && |
| !hdr->disable_cdf_update && !get_bits(gb, 1); |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-refresh_context: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| // tile data |
| hdr->tiling.uniform = get_bits(gb, 1); |
| const int sbsz_min1 = (64 << seqhdr->sb128) - 1; |
| int sbsz_log2 = 6 + seqhdr->sb128; |
| int sbw = (hdr->width + sbsz_min1) >> sbsz_log2; |
| int sbh = (hdr->height + sbsz_min1) >> sbsz_log2; |
| int max_tile_width_sb = 4096 >> sbsz_log2, max_tile_height_sb; |
| int max_tile_area_sb = 4096 * 2304 >> (2 * sbsz_log2); |
| hdr->tiling.min_log2_cols = tile_log2(max_tile_width_sb, sbw); |
| hdr->tiling.max_log2_cols = tile_log2(1, imin(sbw, 1024)); |
| hdr->tiling.max_log2_rows = tile_log2(1, imin(sbh, 1024)); |
| int min_log2_tiles = imax(tile_log2(max_tile_area_sb, sbw * sbh), |
| hdr->tiling.min_log2_cols); |
| if (hdr->tiling.uniform) { |
| for (hdr->tiling.log2_cols = hdr->tiling.min_log2_cols; |
| hdr->tiling.log2_cols < hdr->tiling.max_log2_cols && get_bits(gb, 1); |
| hdr->tiling.log2_cols++) ; |
| const int tile_w = 1 + ((sbw - 1) >> hdr->tiling.log2_cols); |
| hdr->tiling.cols = 0; |
| for (int sbx = 0; sbx < sbw; sbx += tile_w, hdr->tiling.cols++) |
| hdr->tiling.col_start_sb[hdr->tiling.cols] = sbx; |
| hdr->tiling.min_log2_rows = |
| imax(min_log2_tiles - hdr->tiling.log2_cols, 0); |
| max_tile_height_sb = sbh >> hdr->tiling.min_log2_rows; |
| |
| for (hdr->tiling.log2_rows = hdr->tiling.min_log2_rows; |
| hdr->tiling.log2_rows < hdr->tiling.max_log2_rows && get_bits(gb, 1); |
| hdr->tiling.log2_rows++) ; |
| const int tile_h = 1 + ((sbh - 1) >> hdr->tiling.log2_rows); |
| hdr->tiling.rows = 0; |
| for (int sby = 0; sby < sbh; sby += tile_h, hdr->tiling.rows++) |
| hdr->tiling.row_start_sb[hdr->tiling.rows] = sby; |
| } else { |
| hdr->tiling.cols = 0; |
| int widest_tile = 0, max_tile_area_sb = sbw * sbh; |
| for (int sbx = 0; sbx < sbw; hdr->tiling.cols++) { |
| const int tile_w = get_uniform(gb, imin(sbw - sbx, |
| max_tile_width_sb)); |
| hdr->tiling.col_start_sb[hdr->tiling.cols] = sbx; |
| sbx += tile_w; |
| widest_tile = imax(widest_tile, tile_w); |
| } |
| hdr->tiling.log2_cols = tile_log2(1, hdr->tiling.cols); |
| if (min_log2_tiles) max_tile_area_sb >>= min_log2_tiles + 1; |
| max_tile_height_sb = imax(max_tile_area_sb / widest_tile, 1); |
| |
| hdr->tiling.rows = 0; |
| for (int sby = 0; sby < sbh; hdr->tiling.rows++) { |
| const int tile_h = get_uniform(gb, imin(sbh - sby, |
| max_tile_height_sb)); |
| hdr->tiling.row_start_sb[hdr->tiling.rows] = sby; |
| sby += tile_h; |
| } |
| hdr->tiling.log2_rows = tile_log2(1, hdr->tiling.rows); |
| } |
| hdr->tiling.col_start_sb[hdr->tiling.cols] = sbw; |
| hdr->tiling.row_start_sb[hdr->tiling.rows] = sbh; |
| if (hdr->tiling.log2_cols || hdr->tiling.log2_rows) { |
| hdr->tiling.update = get_bits(gb, hdr->tiling.log2_cols + |
| hdr->tiling.log2_rows); |
| hdr->tiling.n_bytes = get_bits(gb, 2) + 1; |
| } else { |
| hdr->tiling.n_bytes = hdr->tiling.update = 0; |
| } |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-tiling: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| // quant data |
| hdr->quant.yac = get_bits(gb, 8); |
| hdr->quant.ydc_delta = get_bits(gb, 1) ? get_sbits(gb, 6) : 0; |
| if (seqhdr->layout != DAV1D_PIXEL_LAYOUT_I400) { |
| hdr->quant.udc_delta = get_bits(gb, 1) ? get_sbits(gb, 6) : 0; |
| hdr->quant.uac_delta = get_bits(gb, 1) ? get_sbits(gb, 6) : 0; |
| if (seqhdr->separate_uv_delta_q) { |
| hdr->quant.vdc_delta = get_bits(gb, 1) ? get_sbits(gb, 6) : 0; |
| hdr->quant.vac_delta = get_bits(gb, 1) ? get_sbits(gb, 6) : 0; |
| } else { |
| hdr->quant.vdc_delta = hdr->quant.udc_delta; |
| hdr->quant.vac_delta = hdr->quant.uac_delta; |
| } |
| } |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-quant: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| hdr->quant.qm = get_bits(gb, 1); |
| if (hdr->quant.qm) { |
| hdr->quant.qm_y = get_bits(gb, 4); |
| hdr->quant.qm_u = get_bits(gb, 4); |
| hdr->quant.qm_v = seqhdr->separate_uv_delta_q ? get_bits(gb, 4) : |
| hdr->quant.qm_u; |
| } |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-qm: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| // segmentation data |
| hdr->segmentation.enabled = get_bits(gb, 1); |
| if (hdr->segmentation.enabled) { |
| if (hdr->primary_ref_frame == PRIMARY_REF_NONE) { |
| hdr->segmentation.update_map = 1; |
| hdr->segmentation.temporal = 0; |
| hdr->segmentation.update_data = 1; |
| } else { |
| hdr->segmentation.update_map = get_bits(gb, 1); |
| hdr->segmentation.temporal = |
| hdr->segmentation.update_map ? get_bits(gb, 1) : 0; |
| hdr->segmentation.update_data = get_bits(gb, 1); |
| } |
| |
| if (hdr->segmentation.update_data) { |
| hdr->segmentation.seg_data.preskip = 0; |
| hdr->segmentation.seg_data.last_active_segid = -1; |
| for (int i = 0; i < NUM_SEGMENTS; i++) { |
| Av1SegmentationData *const seg = |
| &hdr->segmentation.seg_data.d[i]; |
| if (get_bits(gb, 1)) { |
| seg->delta_q = get_sbits(gb, 8); |
| hdr->segmentation.seg_data.last_active_segid = i; |
| } else { |
| seg->delta_q = 0; |
| } |
| if (get_bits(gb, 1)) { |
| seg->delta_lf_y_v = get_sbits(gb, 6); |
| hdr->segmentation.seg_data.last_active_segid = i; |
| } else { |
| seg->delta_lf_y_v = 0; |
| } |
| if (get_bits(gb, 1)) { |
| seg->delta_lf_y_h = get_sbits(gb, 6); |
| hdr->segmentation.seg_data.last_active_segid = i; |
| } else { |
| seg->delta_lf_y_h = 0; |
| } |
| if (get_bits(gb, 1)) { |
| seg->delta_lf_u = get_sbits(gb, 6); |
| hdr->segmentation.seg_data.last_active_segid = i; |
| } else { |
| seg->delta_lf_u = 0; |
| } |
| if (get_bits(gb, 1)) { |
| seg->delta_lf_v = get_sbits(gb, 6); |
| hdr->segmentation.seg_data.last_active_segid = i; |
| } else { |
| seg->delta_lf_v = 0; |
| } |
| if (get_bits(gb, 1)) { |
| seg->ref = get_bits(gb, 3); |
| hdr->segmentation.seg_data.last_active_segid = i; |
| hdr->segmentation.seg_data.preskip = 1; |
| } else { |
| seg->ref = -1; |
| } |
| if ((seg->skip = get_bits(gb, 1))) { |
| hdr->segmentation.seg_data.last_active_segid = i; |
| hdr->segmentation.seg_data.preskip = 1; |
| } |
| if ((seg->globalmv = get_bits(gb, 1))) { |
| hdr->segmentation.seg_data.last_active_segid = i; |
| hdr->segmentation.seg_data.preskip = 1; |
| } |
| } |
| } else if (hdr->primary_ref_frame == PRIMARY_REF_NONE) { |
| memset(&hdr->segmentation.seg_data, 0, sizeof(Av1SegmentationDataSet)); |
| } else { |
| const int pri_ref = hdr->refidx[hdr->primary_ref_frame]; |
| hdr->segmentation.seg_data = c->refs[pri_ref].seg_data; |
| } |
| } else if (hdr->primary_ref_frame == PRIMARY_REF_NONE) { |
| memset(&hdr->segmentation.seg_data, 0, sizeof(Av1SegmentationDataSet)); |
| } else { |
| const int pri_ref = hdr->refidx[hdr->primary_ref_frame]; |
| hdr->segmentation.seg_data = c->refs[pri_ref].seg_data; |
| } |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-segmentation: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| // delta q |
| hdr->delta.q.present = hdr->quant.yac ? get_bits(gb, 1) : 0; |
| hdr->delta.q.res_log2 = hdr->delta.q.present ? get_bits(gb, 2) : 0; |
| hdr->delta.lf.present = hdr->delta.q.present && !hdr->allow_intrabc && |
| get_bits(gb, 1); |
| hdr->delta.lf.res_log2 = hdr->delta.lf.present ? get_bits(gb, 2) : 0; |
| hdr->delta.lf.multi = hdr->delta.lf.present ? get_bits(gb, 1) : 0; |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-delta_q_lf_flags: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| // derive lossless flags |
| const int delta_lossless = !hdr->quant.ydc_delta && !hdr->quant.udc_delta && |
| !hdr->quant.uac_delta && !hdr->quant.vdc_delta && !hdr->quant.vac_delta; |
| hdr->all_lossless = 1; |
| for (int i = 0; i < NUM_SEGMENTS; i++) { |
| hdr->segmentation.qidx[i] = hdr->segmentation.enabled ? |
| iclip_u8(hdr->quant.yac + hdr->segmentation.seg_data.d[i].delta_q) : |
| hdr->quant.yac; |
| hdr->segmentation.lossless[i] = |
| !hdr->segmentation.qidx[i] && delta_lossless; |
| hdr->all_lossless &= hdr->segmentation.lossless[i]; |
| } |
| |
| // loopfilter |
| if (hdr->all_lossless || hdr->allow_intrabc) { |
| hdr->loopfilter.level_y[0] = hdr->loopfilter.level_y[1] = 0; |
| hdr->loopfilter.level_u = hdr->loopfilter.level_v = 0; |
| hdr->loopfilter.sharpness = 0; |
| hdr->loopfilter.mode_ref_delta_enabled = 1; |
| hdr->loopfilter.mode_ref_delta_update = 1; |
| hdr->loopfilter.mode_ref_deltas = default_mode_ref_deltas; |
| } else { |
| hdr->loopfilter.level_y[0] = get_bits(gb, 6); |
| hdr->loopfilter.level_y[1] = get_bits(gb, 6); |
| if (seqhdr->layout != DAV1D_PIXEL_LAYOUT_I400 && |
| (hdr->loopfilter.level_y[0] || hdr->loopfilter.level_y[1])) |
| { |
| hdr->loopfilter.level_u = get_bits(gb, 6); |
| hdr->loopfilter.level_v = get_bits(gb, 6); |
| } |
| hdr->loopfilter.sharpness = get_bits(gb, 3); |
| |
| if (hdr->primary_ref_frame == PRIMARY_REF_NONE) { |
| hdr->loopfilter.mode_ref_deltas = default_mode_ref_deltas; |
| } else { |
| const int ref = hdr->refidx[hdr->primary_ref_frame]; |
| hdr->loopfilter.mode_ref_deltas = c->refs[ref].lf_mode_ref_deltas; |
| } |
| hdr->loopfilter.mode_ref_delta_enabled = get_bits(gb, 1); |
| if (hdr->loopfilter.mode_ref_delta_enabled) { |
| hdr->loopfilter.mode_ref_delta_update = get_bits(gb, 1); |
| if (hdr->loopfilter.mode_ref_delta_update) { |
| for (int i = 0; i < 8; i++) |
| if (get_bits(gb, 1)) |
| hdr->loopfilter.mode_ref_deltas.ref_delta[i] = |
| get_sbits(gb, 6); |
| for (int i = 0; i < 2; i++) |
| if (get_bits(gb, 1)) |
| hdr->loopfilter.mode_ref_deltas.mode_delta[i] = |
| get_sbits(gb, 6); |
| } |
| } |
| } |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-lpf: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| // cdef |
| if (!hdr->all_lossless && seqhdr->cdef && !hdr->allow_intrabc) { |
| hdr->cdef.damping = get_bits(gb, 2) + 3; |
| hdr->cdef.n_bits = get_bits(gb, 2); |
| for (int i = 0; i < (1 << hdr->cdef.n_bits); i++) { |
| hdr->cdef.y_strength[i] = get_bits(gb, 6); |
| if (seqhdr->layout != DAV1D_PIXEL_LAYOUT_I400) |
| hdr->cdef.uv_strength[i] = get_bits(gb, 6); |
| } |
| } else { |
| hdr->cdef.n_bits = 0; |
| hdr->cdef.y_strength[0] = 0; |
| hdr->cdef.uv_strength[0] = 0; |
| } |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-cdef: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| // restoration |
| if (!hdr->all_lossless && seqhdr->restoration && !hdr->allow_intrabc) { |
| hdr->restoration.type[0] = get_bits(gb, 2); |
| if (seqhdr->layout != DAV1D_PIXEL_LAYOUT_I400) { |
| hdr->restoration.type[1] = get_bits(gb, 2); |
| hdr->restoration.type[2] = get_bits(gb, 2); |
| } |
| |
| if (hdr->restoration.type[0] || hdr->restoration.type[1] || |
| hdr->restoration.type[2]) |
| { |
| // Log2 of the restoration unit size. |
| hdr->restoration.unit_size[0] = 6 + seqhdr->sb128; |
| if (get_bits(gb, 1)) { |
| hdr->restoration.unit_size[0]++; |
| if (!seqhdr->sb128) |
| hdr->restoration.unit_size[0] += get_bits(gb, 1); |
| } |
| hdr->restoration.unit_size[1] = hdr->restoration.unit_size[0]; |
| if ((hdr->restoration.type[1] || hdr->restoration.type[2]) && |
| seqhdr->layout == DAV1D_PIXEL_LAYOUT_I420) |
| { |
| hdr->restoration.unit_size[1] -= get_bits(gb, 1); |
| } |
| } else { |
| hdr->restoration.unit_size[0] = 8; |
| } |
| } else { |
| hdr->restoration.type[0] = RESTORATION_NONE; |
| hdr->restoration.type[1] = RESTORATION_NONE; |
| hdr->restoration.type[2] = RESTORATION_NONE; |
| } |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-restoration: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| hdr->txfm_mode = hdr->all_lossless ? TX_4X4_ONLY : |
| get_bits(gb, 1) ? TX_SWITCHABLE : TX_LARGEST; |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-txfmmode: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| hdr->switchable_comp_refs = hdr->frame_type & 1 ? get_bits(gb, 1) : 0; |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-refmode: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| hdr->skip_mode_allowed = 0; |
| if (hdr->switchable_comp_refs && hdr->frame_type & 1) { |
| const unsigned poc = hdr->frame_offset; |
| unsigned off_before[2] = { 0xFFFFFFFF, 0xFFFFFFFF }; |
| int off_after = -1; |
| int off_before_idx[2], off_after_idx; |
| for (int i = 0; i < 7; i++) { |
| const unsigned refpoc = c->refs[hdr->refidx[i]].p.p.poc; |
| |
| const int diff = get_poc_diff(seqhdr->order_hint_n_bits, refpoc, poc); |
| if (diff > 0) { |
| if (off_after == -1 || get_poc_diff(seqhdr->order_hint_n_bits, |
| off_after, refpoc) > 0) |
| { |
| off_after = refpoc; |
| off_after_idx = i; |
| } |
| } else if (diff < 0) { |
| if (off_before[0] == 0xFFFFFFFFU || |
| get_poc_diff(seqhdr->order_hint_n_bits, |
| refpoc, off_before[0]) > 0) |
| { |
| off_before[1] = off_before[0]; |
| off_before[0] = refpoc; |
| off_before_idx[1] = off_before_idx[0]; |
| off_before_idx[0] = i; |
| } else if (refpoc != off_before[0] && |
| (off_before[1] == 0xFFFFFFFFU || |
| get_poc_diff(seqhdr->order_hint_n_bits, |
| refpoc, off_before[1]) > 0)) |
| { |
| off_before[1] = refpoc; |
| off_before_idx[1] = i; |
| } |
| } |
| } |
| |
| if (off_before[0] != 0xFFFFFFFFU && off_after != -1) { |
| hdr->skip_mode_refs[0] = off_before_idx[0]; |
| hdr->skip_mode_refs[1] = off_after_idx; |
| hdr->skip_mode_allowed = 1; |
| } else if (off_before[0] != 0xFFFFFFFFU && |
| off_before[1] != 0xFFFFFFFFU) |
| { |
| hdr->skip_mode_refs[0] = off_before_idx[0]; |
| hdr->skip_mode_refs[1] = off_before_idx[1]; |
| hdr->skip_mode_allowed = 1; |
| } |
| } |
| hdr->skip_mode_enabled = hdr->skip_mode_allowed ? get_bits(gb, 1) : 0; |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-extskip: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| hdr->warp_motion = !hdr->error_resilient_mode && hdr->frame_type & 1 && |
| seqhdr->warped_motion && get_bits(gb, 1); |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-warpmotionbit: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| hdr->reduced_txtp_set = get_bits(gb, 1); |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-reducedtxtpset: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| for (int i = 0; i < 7; i++) |
| hdr->gmv[i] = default_wm_params; |
| |
| if (hdr->frame_type & 1) { |
| for (int i = 0; i < 7; i++) { |
| hdr->gmv[i].type = !get_bits(gb, 1) ? WM_TYPE_IDENTITY : |
| get_bits(gb, 1) ? WM_TYPE_ROT_ZOOM : |
| get_bits(gb, 1) ? WM_TYPE_TRANSLATION : |
| WM_TYPE_AFFINE; |
| |
| if (hdr->gmv[i].type == WM_TYPE_IDENTITY) continue; |
| |
| const WarpedMotionParams *const ref_gmv = |
| hdr->primary_ref_frame == PRIMARY_REF_NONE ? &default_wm_params : |
| &c->refs[hdr->refidx[hdr->primary_ref_frame]].gmv[i]; |
| int32_t *const mat = hdr->gmv[i].matrix; |
| const int32_t *const ref_mat = ref_gmv->matrix; |
| int bits, shift; |
| |
| if (hdr->gmv[i].type >= WM_TYPE_ROT_ZOOM) { |
| mat[2] = (1 << 16) + 2 * |
| get_bits_subexp(gb, (ref_mat[2] - (1 << 16)) >> 1, 12); |
| mat[3] = 2 * get_bits_subexp(gb, ref_mat[3] >> 1, 12); |
| |
| bits = 12; |
| shift = 10; |
| } else { |
| bits = 9 - !hdr->hp; |
| shift = 13 + !hdr->hp; |
| } |
| |
| if (hdr->gmv[i].type == WM_TYPE_AFFINE) { |
| mat[4] = 2 * get_bits_subexp(gb, ref_mat[4] >> 1, 12); |
| mat[5] = (1 << 16) + 2 * |
| get_bits_subexp(gb, (ref_mat[5] - (1 << 16)) >> 1, 12); |
| } else { |
| mat[4] = -mat[3]; |
| mat[5] = mat[2]; |
| } |
| |
| mat[0] = get_bits_subexp(gb, ref_mat[0] >> shift, bits) * (1 << shift); |
| mat[1] = get_bits_subexp(gb, ref_mat[1] >> shift, bits) * (1 << shift); |
| |
| if (get_shear_params(&hdr->gmv[i])) |
| goto error; |
| } |
| } |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-gmv: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| hdr->film_grain.present = seqhdr->film_grain_present && |
| (hdr->show_frame || hdr->showable_frame) && |
| get_bits(gb, 1); |
| if (hdr->film_grain.present) { |
| hdr->film_grain.seed = get_bits(gb, 16); |
| hdr->film_grain.update = hdr->frame_type != DAV1D_FRAME_TYPE_INTER || get_bits(gb, 1); |
| if (!hdr->film_grain.update) { |
| const int refidx = get_bits(gb, 3); |
| int i; |
| for (i = 0; i < 7; i++) |
| if (hdr->refidx[i] == refidx) |
| break; |
| if (i == 7) goto error; |
| hdr->film_grain.data = c->refs[refidx].film_grain; |
| } else { |
| Av1FilmGrainData *const fgd = &hdr->film_grain.data; |
| |
| fgd->num_y_points = get_bits(gb, 4); |
| if (fgd->num_y_points > 14) goto error; |
| for (int i = 0; i < fgd->num_y_points; i++) { |
| fgd->y_points[i][0] = get_bits(gb, 8); |
| if (i && fgd->y_points[i - 1][0] >= fgd->y_points[i][0]) |
| goto error; |
| fgd->y_points[i][1] = get_bits(gb, 8); |
| } |
| |
| fgd->chroma_scaling_from_luma = |
| seqhdr->layout != DAV1D_PIXEL_LAYOUT_I400 && get_bits(gb, 1); |
| if (seqhdr->layout == DAV1D_PIXEL_LAYOUT_I400 || |
| fgd->chroma_scaling_from_luma || |
| (seqhdr->layout == DAV1D_PIXEL_LAYOUT_I420 && !fgd->num_y_points)) |
| { |
| fgd->num_uv_points[0] = fgd->num_uv_points[1] = 0; |
| } else for (int pl = 0; pl < 2; pl++) { |
| fgd->num_uv_points[pl] = get_bits(gb, 4); |
| if (fgd->num_uv_points[pl] > 10) goto error; |
| for (int i = 0; i < fgd->num_uv_points[pl]; i++) { |
| fgd->uv_points[pl][i][0] = get_bits(gb, 8); |
| if (i && fgd->uv_points[pl][i - 1][0] >= fgd->uv_points[pl][i][0]) |
| goto error; |
| fgd->uv_points[pl][i][1] = get_bits(gb, 8); |
| } |
| } |
| |
| if (seqhdr->layout == DAV1D_PIXEL_LAYOUT_I420 && |
| !!fgd->num_uv_points[0] != !!fgd->num_uv_points[1]) |
| { |
| goto error; |
| } |
| |
| fgd->scaling_shift = get_bits(gb, 2) + 8; |
| fgd->ar_coeff_lag = get_bits(gb, 2); |
| const int num_y_pos = 2 * fgd->ar_coeff_lag * (fgd->ar_coeff_lag + 1); |
| if (fgd->num_y_points) |
| for (int i = 0; i < num_y_pos; i++) |
| fgd->ar_coeffs_y[i] = get_bits(gb, 8) - 128; |
| for (int pl = 0; pl < 2; pl++) |
| if (fgd->num_uv_points[pl] || fgd->chroma_scaling_from_luma) { |
| const int num_uv_pos = num_y_pos + !!fgd->num_y_points; |
| for (int i = 0; i < num_uv_pos; i++) |
| fgd->ar_coeffs_uv[pl][i] = get_bits(gb, 8) - 128; |
| } |
| fgd->ar_coeff_shift = get_bits(gb, 2) + 6; |
| fgd->grain_scale_shift = get_bits(gb, 2); |
| for (int pl = 0; pl < 2; pl++) |
| if (fgd->num_uv_points[pl]) { |
| fgd->uv_mult[pl] = get_bits(gb, 8); |
| fgd->uv_luma_mult[pl] = get_bits(gb, 8); |
| fgd->uv_offset[pl] = get_bits(gb, 9); |
| } |
| fgd->overlap_flag = get_bits(gb, 1); |
| fgd->clip_to_restricted_range = get_bits(gb, 1); |
| } |
| } else { |
| memset(&hdr->film_grain.data, 0, sizeof(hdr->film_grain)); |
| } |
| #if DEBUG_FRAME_HDR |
| printf("HDR: post-filmgrain: off=%ld\n", |
| (gb->ptr - init_ptr) * 8 - gb->bits_left); |
| #endif |
| |
| end: |
| |
| if (have_trailing_bit) |
| get_bits(gb, 1); // dummy bit |
| |
| return flush_get_bits(gb) - init_ptr; |
| |
| error: |
| fprintf(stderr, "Error parsing frame header\n"); |
| return -EINVAL; |
| } |
| |
| static int parse_tile_hdr(Dav1dContext *const c, GetBits *const gb) { |
| const uint8_t *const init_ptr = gb->ptr; |
| |
| int have_tile_pos = 0; |
| const int n_bits = c->frame_hdr.tiling.log2_cols + |
| c->frame_hdr.tiling.log2_rows; |
| if (n_bits) |
| have_tile_pos = get_bits(gb, 1); |
| |
| if (have_tile_pos) { |
| c->tile[c->n_tile_data].start = get_bits(gb, n_bits); |
| c->tile[c->n_tile_data].end = get_bits(gb, n_bits); |
| } else { |
| c->tile[c->n_tile_data].start = 0; |
| c->tile[c->n_tile_data].end = (1 << n_bits) - 1; |
| } |
| |
| return flush_get_bits(gb) - init_ptr; |
| } |
| |
| int parse_obus(Dav1dContext *const c, Dav1dData *const in) { |
| GetBits gb; |
| int res; |
| |
| init_get_bits(&gb, in->data, in->sz); |
| |
| // obu header |
| get_bits(&gb, 1); // obu_forbidden_bit |
| const enum ObuType type = get_bits(&gb, 4); |
| const int has_extension = get_bits(&gb, 1); |
| const int has_length_field = get_bits(&gb, 1); |
| if (!has_length_field) goto error; |
| get_bits(&gb, 1); // reserved |
| if (has_extension) { |
| get_bits(&gb, 3); // temporal_layer_id |
| get_bits(&gb, 2); // enhancement_layer_id |
| get_bits(&gb, 3); // reserved |
| } |
| |
| // obu length field |
| int len = 0, more, i = 0; |
| do { |
| more = get_bits(&gb, 1); |
| len |= get_bits(&gb, 7) << (i * 7); |
| if (more && ++i == 8) goto error; |
| } while (more); |
| if (gb.error) goto error; |
| |
| int off = flush_get_bits(&gb) - in->data; |
| const int init_off = off; |
| if (len > in->sz - off) goto error; |
| |
| switch (type) { |
| case OBU_SEQ_HDR: |
| if ((res = parse_seq_hdr(c, &gb)) < 0) |
| return res; |
| if (res != len) goto error; |
| c->have_seq_hdr = 1; |
| c->have_frame_hdr = 0; |
| break; |
| case OBU_FRAME: |
| case OBU_FRAME_HDR: |
| if (!c->have_seq_hdr) goto error; |
| if ((res = parse_frame_hdr(c, &gb, type == OBU_FRAME_HDR)) < 0) |
| return res; |
| c->have_frame_hdr = 1; |
| for (int n = 0; n < c->n_tile_data; n++) |
| dav1d_data_unref(&c->tile[n].data); |
| c->n_tile_data = 0; |
| c->tile_mask = 0; |
| if (type == OBU_FRAME_HDR) break; |
| off += res; |
| // fall-through |
| case OBU_TILE_GRP: |
| if (!c->have_frame_hdr) goto error; |
| if (c->n_tile_data >= 256) goto error; |
| if ((res = parse_tile_hdr(c, &gb)) < 0) |
| return res; |
| off += res; |
| dav1d_ref_inc(in->ref); |
| c->tile[c->n_tile_data].data.ref = in->ref; |
| c->tile[c->n_tile_data].data.data = in->data + off; |
| c->tile[c->n_tile_data].data.sz = len + init_off - off; |
| if (c->tile[c->n_tile_data].start > c->tile[c->n_tile_data].end) |
| goto error; |
| #define mask(a) ((1 << (a)) - 1) |
| const unsigned tile_mask = mask(c->tile[c->n_tile_data].end + 1) - |
| mask(c->tile[c->n_tile_data].start); |
| #undef mask |
| if (tile_mask & c->tile_mask) goto error; // tile overlap |
| c->tile_mask |= tile_mask; |
| c->n_tile_data++; |
| break; |
| case OBU_PADDING: |
| case OBU_TD: |
| case OBU_METADATA: |
| // ignore OBUs we don't care about |
| break; |
| default: |
| fprintf(stderr, "Unknown OBU type %d of size %d\n", type, len); |
| return -EINVAL; |
| } |
| |
| const int n_tiles = 1 << (c->frame_hdr.tiling.log2_cols + |
| c->frame_hdr.tiling.log2_rows); |
| if (c->have_seq_hdr && c->have_frame_hdr && |
| c->tile_mask == (1 << n_tiles) - 1) |
| { |
| assert(c->n_tile_data); |
| submit_frame(c); |
| assert(!c->n_tile_data); |
| c->have_frame_hdr = 0; |
| c->tile_mask = 0; |
| } else if (c->have_seq_hdr && c->have_frame_hdr && |
| c->frame_hdr.show_existing_frame) |
| { |
| if (c->n_fc == 1) { |
| dav1d_picture_ref(&c->out, |
| &c->refs[c->frame_hdr.existing_frame_idx].p.p); |
| } else { |
| // need to append this to the frame output queue |
| const unsigned next = c->frame_thread.next++; |
| if (c->frame_thread.next == c->n_fc) |
| c->frame_thread.next = 0; |
| |
| Dav1dFrameContext *const f = &c->fc[next]; |
| pthread_mutex_lock(&f->frame_thread.td.lock); |
| while (f->n_tile_data > 0) |
| pthread_cond_wait(&f->frame_thread.td.cond, |
| &f->frame_thread.td.lock); |
| Dav1dThreadPicture *const out_delayed = |
| &c->frame_thread.out_delayed[next]; |
| if (out_delayed->p.data[0]) { |
| if (out_delayed->visible && !out_delayed->flushed) |
| dav1d_picture_ref(&c->out, &out_delayed->p); |
| dav1d_thread_picture_unref(out_delayed); |
| } |
| dav1d_thread_picture_ref(out_delayed, |
| &c->refs[c->frame_hdr.existing_frame_idx].p); |
| out_delayed->visible = 1; |
| out_delayed->flushed = 0; |
| pthread_mutex_unlock(&f->frame_thread.td.lock); |
| } |
| c->have_frame_hdr = 0; |
| } |
| |
| return len + init_off; |
| |
| error: |
| fprintf(stderr, "Error parsing OBU data\n"); |
| return -EINVAL; |
| } |