static vpx_codec_err_t vp9_peek_si(const uint8_t *data, unsigned int data_sz, vpx_codec_stream_info_t *si) { if (data_sz <= 8) return VPX_CODEC_UNSUP_BITSTREAM; if (data + data_sz <= data) return VPX_CODEC_INVALID_PARAM; si->is_kf = 0; si->w = si->h = 0; { struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL }; const int frame_marker = vp9_rb_read_literal(&rb, 2); const int version = vp9_rb_read_bit(&rb); (void) vp9_rb_read_bit(&rb); // unused version bit if (frame_marker != VP9_FRAME_MARKER) return VPX_CODEC_UNSUP_BITSTREAM; if (version > 1) return VPX_CODEC_UNSUP_BITSTREAM; if (vp9_rb_read_bit(&rb)) { // show an existing frame return VPX_CODEC_OK; } si->is_kf = !vp9_rb_read_bit(&rb); if (si->is_kf) { const int sRGB = 7; int colorspace; rb.bit_offset += 1; // show frame rb.bit_offset += 1; // error resilient if (vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_0 || vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_1 || vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_2) { return VPX_CODEC_UNSUP_BITSTREAM; } colorspace = vp9_rb_read_literal(&rb, 3); if (colorspace != sRGB) { rb.bit_offset += 1; // [16,235] (including xvycc) vs [0,255] range if (version == 1) { rb.bit_offset += 2; // subsampling x/y rb.bit_offset += 1; // has extra plane } } else { if (version == 1) { rb.bit_offset += 1; // has extra plane } else { // RGB is only available in version 1 return VPX_CODEC_UNSUP_BITSTREAM; } } // TODO(jzern): these are available on non-keyframes in intra only mode. si->w = vp9_rb_read_literal(&rb, 16) + 1; si->h = vp9_rb_read_literal(&rb, 16) + 1; } } return VPX_CODEC_OK; }
static int parse_bitdepth_colorspace_sampling( BITSTREAM_PROFILE profile, struct vp9_read_bit_buffer *rb) { vpx_color_space_t color_space; if (profile >= PROFILE_2) rb->bit_offset += 1; // Bit-depth 10 or 12. color_space = (vpx_color_space_t)vp9_rb_read_literal(rb, 3); if (color_space != VPX_CS_SRGB) { rb->bit_offset += 1; // [16,235] (including xvycc) vs [0,255] range. if (profile == PROFILE_1 || profile == PROFILE_3) { rb->bit_offset += 2; // subsampling x/y. rb->bit_offset += 1; // unused. } } else { if (profile == PROFILE_1 || profile == PROFILE_3) { rb->bit_offset += 1; // unused } else { // RGB is only available in version 1. return 0; } } return 1; }
static int decode_unsigned_max(struct vp9_read_bit_buffer *rb, int max) { const int data = vp9_rb_read_literal(rb, get_unsigned_bits(max)); return data > max ? max : data; }
static vpx_codec_err_t decoder_peek_si_internal(const uint8_t *data, unsigned int data_sz, vpx_codec_stream_info_t *si, int *is_intra_only, vpx_decrypt_cb decrypt_cb, void *decrypt_state) { int intra_only_flag = 0; uint8_t clear_buffer[9]; if (data + data_sz <= data) return VPX_CODEC_INVALID_PARAM; si->is_kf = 0; si->w = si->h = 0; if (decrypt_cb) { data_sz = MIN(sizeof(clear_buffer), data_sz); decrypt_cb(decrypt_state, data, clear_buffer, data_sz); data = clear_buffer; } { int show_frame; int error_resilient; struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL }; const int frame_marker = vp9_rb_read_literal(&rb, 2); const BITSTREAM_PROFILE profile = vp9_read_profile(&rb); if (frame_marker != VP9_FRAME_MARKER) return VPX_CODEC_UNSUP_BITSTREAM; if (profile >= MAX_PROFILES) return VPX_CODEC_UNSUP_BITSTREAM; if ((profile >= 2 && data_sz <= 1) || data_sz < 1) return VPX_CODEC_UNSUP_BITSTREAM; if (vp9_rb_read_bit(&rb)) { // show an existing frame vp9_rb_read_literal(&rb, 3); // Frame buffer to show. return VPX_CODEC_OK; } if (data_sz <= 8) return VPX_CODEC_UNSUP_BITSTREAM; si->is_kf = !vp9_rb_read_bit(&rb); show_frame = vp9_rb_read_bit(&rb); error_resilient = vp9_rb_read_bit(&rb); if (si->is_kf) { if (!vp9_read_sync_code(&rb)) return VPX_CODEC_UNSUP_BITSTREAM; if (!parse_bitdepth_colorspace_sampling(profile, &rb)) return VPX_CODEC_UNSUP_BITSTREAM; vp9_read_frame_size(&rb, (int *)&si->w, (int *)&si->h); } else { intra_only_flag = show_frame ? 0 : vp9_rb_read_bit(&rb); rb.bit_offset += error_resilient ? 0 : 2; // reset_frame_context if (intra_only_flag) { if (!vp9_read_sync_code(&rb)) return VPX_CODEC_UNSUP_BITSTREAM; if (profile > PROFILE_0) { if (!parse_bitdepth_colorspace_sampling(profile, &rb)) return VPX_CODEC_UNSUP_BITSTREAM; } rb.bit_offset += REF_FRAMES; // refresh_frame_flags vp9_read_frame_size(&rb, (int *)&si->w, (int *)&si->h); } } } if (is_intra_only != NULL) *is_intra_only = intra_only_flag; return VPX_CODEC_OK; }