From b245e0f16c63c798da3ae3f5a331fdc27c5dcb31 Mon Sep 17 00:00:00 2001 From: Sreerenj Balachandran Date: Wed, 30 Dec 2015 11:19:33 +0200 Subject: [PATCH] codecparsers: Add VP9 codec parser https://bugzilla.gnome.org/show_bug.cgi?id=757597 --- gst-libs/gst/codecparsers/Makefile.am | 9 +- gst-libs/gst/codecparsers/gstvp9parser.c | 815 +++++++++++++++++++++ gst-libs/gst/codecparsers/gstvp9parser.h | 464 ++++++++++++ gst-libs/gst/codecparsers/vp9utils.AUTHORS | 100 +++ gst-libs/gst/codecparsers/vp9utils.LICENSE | 30 + gst-libs/gst/codecparsers/vp9utils.PATENTS | 22 + gst-libs/gst/codecparsers/vp9utils.c | 263 +++++++ gst-libs/gst/codecparsers/vp9utils.h | 26 + 8 files changed, 1726 insertions(+), 3 deletions(-) create mode 100644 gst-libs/gst/codecparsers/gstvp9parser.c create mode 100644 gst-libs/gst/codecparsers/gstvp9parser.h create mode 100644 gst-libs/gst/codecparsers/vp9utils.AUTHORS create mode 100644 gst-libs/gst/codecparsers/vp9utils.LICENSE create mode 100644 gst-libs/gst/codecparsers/vp9utils.PATENTS create mode 100644 gst-libs/gst/codecparsers/vp9utils.c create mode 100644 gst-libs/gst/codecparsers/vp9utils.h diff --git a/gst-libs/gst/codecparsers/Makefile.am b/gst-libs/gst/codecparsers/Makefile.am index e2498dbfdd..00c78e2091 100644 --- a/gst-libs/gst/codecparsers/Makefile.am +++ b/gst-libs/gst/codecparsers/Makefile.am @@ -5,7 +5,8 @@ libgstcodecparsers_@GST_API_VERSION@_la_SOURCES = \ gsth265parser.c gstvp8parser.c gstvp8rangedecoder.c \ parserutils.c nalutils.c dboolhuff.c vp8utils.c \ gstjpegparser.c \ - gstmpegvideometa.c + gstmpegvideometa.c \ + gstvp9parser.c vp9utils.c libgstcodecparsers_@GST_API_VERSION@includedir = \ $(includedir)/gstreamer-@GST_API_VERSION@/gst/codecparsers @@ -16,7 +17,8 @@ libgstcodecparsers_@GST_API_VERSION@include_HEADERS = \ gstmpegvideoparser.h gsth264parser.h gstvc1parser.h gstmpeg4parser.h \ gsth265parser.h gstvp8parser.h gstvp8rangedecoder.h \ gstjpegparser.h \ - gstmpegvideometa.h + gstmpegvideometa.h \ + gstvp9parser.h vp9utils.h libgstcodecparsers_@GST_API_VERSION@_la_CFLAGS = \ $(GST_PLUGINS_BAD_CFLAGS) \ @@ -36,4 +38,5 @@ libgstcodecparsers_@GST_API_VERSION@_la_LDFLAGS = \ $(GST_ALL_LDFLAGS) \ $(GST_LT_LDFLAGS) -EXTRA_DIST = dboolhuff.LICENSE dboolhuff.PATENTS dboolhuff.AUTHORS +EXTRA_DIST = dboolhuff.LICENSE dboolhuff.PATENTS dboolhuff.AUTHORS \ + vp9utils.LICENSE vp9utils.PATENTS vp9utils.AUTHORS diff --git a/gst-libs/gst/codecparsers/gstvp9parser.c b/gst-libs/gst/codecparsers/gstvp9parser.c new file mode 100644 index 0000000000..598e8cda91 --- /dev/null +++ b/gst-libs/gst/codecparsers/gstvp9parser.c @@ -0,0 +1,815 @@ +/* gstvp9parser.c + * + * Copyright (C) 2013-2014 Intel Corporation + * Copyright (C) 2015 Intel Corporation + * Author: XuGuangxin + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +/** + * SECTION:gstvp9parser + * @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 +#include +#include +#include "vp9utils.h" +#include "gstvp9parser.h" + +#define MIN_TILE_WIDTH_B64 4 +#define MAX_TILE_WIDTH_B64 64 + +/* order of sb64, where sb64 = 64x64 */ +#define ALIGN_SB64(w) ((w + 63) >> 6) + +GST_DEBUG_CATEGORY (gst_vp9_parser_debug); +#define GST_CAT_DEFAULT gst_vp9_parser_debug + +static gboolean initialized = FALSE; +#define INITIALIZE_DEBUG_CATEGORY \ + if (!initialized) { \ + GST_DEBUG_CATEGORY_INIT (gst_vp9_parser_debug, "codecparsers_vp9", 0, \ + "vp9 parser library"); \ + initialized = TRUE; \ + } + +#define gst_vp9_read_bit(br) gst_bit_reader_get_bits_uint8_unchecked(br, 1) +#define gst_vp9_read_bits(br, bits) gst_bit_reader_get_bits_uint32_unchecked(br, bits) + +#define GST_VP9_PARSER_GET_PRIVATE(parser) ((GstVp9ParserPrivate *)(parser->priv)) + +typedef struct _ReferenceSize +{ + guint32 width; + guint32 height; +} ReferenceSize; + +typedef struct +{ + /* for loop filters */ + gint8 ref_deltas[GST_VP9_MAX_REF_LF_DELTAS]; + gint8 mode_deltas[GST_VP9_MAX_MODE_LF_DELTAS]; + + guint8 segmentation_abs_delta; + GstVp9SegmentationInfoData segmentation[GST_VP9_MAX_SEGMENTS]; + + ReferenceSize reference[GST_VP9_REF_FRAMES]; +} GstVp9ParserPrivate; + +static gint32 +gst_vp9_read_signed_bits (GstBitReader * br, int bits) +{ + const gint32 value = gst_vp9_read_bits (br, bits); + return gst_vp9_read_bit (br) ? -value : value; +} + +static gboolean +verify_frame_marker (GstBitReader * br) +{ + guint8 frame_marker = gst_vp9_read_bits (br, 2); + if (frame_marker != GST_VP9_FRAME_MARKER) { + GST_ERROR ("Invalid VP9 Frame Marker !"); + return FALSE; + } + return TRUE; +} + +static gboolean +verify_sync_code (GstBitReader * const br) +{ + return (gst_vp9_read_bits (br, 24) == GST_VP9_SYNC_CODE); +} + +static gboolean +parse_bitdepth_colorspace_sampling (GstBitReader * const br, + GstVp9FrameHdr * frame_hdr) +{ + if (frame_hdr->profile > GST_VP9_PROFILE_1) + frame_hdr->bit_depth = + gst_vp9_read_bit (br) ? GST_VP9_BIT_DEPTH_12 : GST_VP9_BIT_DEPTH_10; + else + frame_hdr->bit_depth = GST_VP9_BIT_DEPTH_8; + + frame_hdr->color_space = gst_vp9_read_bits (br, 3); + if (frame_hdr->color_space != GST_VP9_CS_SRGB) { + frame_hdr->color_range = gst_vp9_read_bit (br); + + if (frame_hdr->profile == GST_VP9_PROFILE_1 + || frame_hdr->profile == GST_VP9_PROFILE_3) { + + frame_hdr->subsampling_x = gst_vp9_read_bit (br); + frame_hdr->subsampling_y = gst_vp9_read_bit (br); + + if (frame_hdr->subsampling_x == 1 && frame_hdr->subsampling_y == 1) { + GST_ERROR + ("4:2:0 subsampling is not supported in profile_1 or profile_3"); + goto error; + } + + if (gst_vp9_read_bit (br)) { + GST_ERROR ("Reserved bit set!"); + goto error; + } + } else { + frame_hdr->subsampling_y = frame_hdr->subsampling_x = 1; + } + } else { + frame_hdr->color_range = GST_VP9_CR_FULL; + + if (frame_hdr->profile == GST_VP9_PROFILE_1 + || frame_hdr->profile == GST_VP9_PROFILE_3) { + if (gst_vp9_read_bit (br)) { + GST_ERROR ("Reserved bit set!"); + goto error; + } + } else { + GST_ERROR + ("4:4:4 subsampling is not supported in profile_0 and profile_2"); + goto error; + } + } + return TRUE; + +error: + return FALSE; +} + +static guint +parse_profile (GstBitReader * br) +{ + guint8 profile = gst_vp9_read_bit (br); + profile |= gst_vp9_read_bit (br) << 1; + if (profile > 2) + profile += gst_vp9_read_bit (br); + return profile; +} + +static void +parse_frame_size (GstBitReader * br, guint32 * width, guint32 * height) +{ + const guint32 w = gst_vp9_read_bits (br, 16) + 1; + const guint32 h = gst_vp9_read_bits (br, 16) + 1; + *width = w; + *height = h; +} + +static void +parse_display_frame_size (GstBitReader * br, GstVp9FrameHdr * frame_hdr) +{ + frame_hdr->display_size_enabled = gst_vp9_read_bit (br); + if (frame_hdr->display_size_enabled) + parse_frame_size (br, &frame_hdr->display_width, + &frame_hdr->display_height); +} + +static void +parse_frame_size_from_refs (const GstVp9Parser * parser, + GstVp9FrameHdr * frame_hdr, GstBitReader * br) +{ + gboolean found = FALSE; + int i; + GstVp9ParserPrivate *priv = GST_VP9_PARSER_GET_PRIVATE (parser); + + for (i = 0; i < GST_VP9_REFS_PER_FRAME; i++) { + found = gst_vp9_read_bit (br); + + if (found) { + guint8 idx = frame_hdr->ref_frame_indices[i]; + frame_hdr->width = priv->reference[idx].width; + frame_hdr->height = priv->reference[idx].height; + break; + } + } + if (!found) + parse_frame_size (br, &frame_hdr->width, &frame_hdr->height); +} + +static GstVp9InterpFilter +parse_interp_filter (GstBitReader * br) +{ + const GstVp9InterpFilter filter_map[] = { + GST_VP9_INTERP_FILTER_EIGHTTAP_SMOOTH, + GST_VP9_INTERP_FILTER_EIGHTTAP, + GST_VP9_INTERP_FILTER_EIGHTTAP_SHARP, + GST_VP9_INTERP_FILTER_BILINEAR + }; + + return gst_vp9_read_bit (br) ? GST_VP9_INTERP_FILTER_SWITCHABLE : + filter_map[gst_vp9_read_bits (br, 2)]; +} + +static void +parse_loopfilter (GstVp9LoopFilter * lf, GstBitReader * br) +{ + lf->filter_level = gst_vp9_read_bits (br, 6); + lf->sharpness_level = gst_vp9_read_bits (br, 3); + + lf->mode_ref_delta_update = 0; + + lf->mode_ref_delta_enabled = gst_vp9_read_bit (br); + if (lf->mode_ref_delta_enabled) { + lf->mode_ref_delta_update = gst_vp9_read_bit (br); + if (lf->mode_ref_delta_update) { + int i; + for (i = 0; i < GST_VP9_MAX_REF_LF_DELTAS; i++) { + lf->update_ref_deltas[i] = gst_vp9_read_bit (br); + if (lf->update_ref_deltas[i]) + lf->ref_deltas[i] = gst_vp9_read_signed_bits (br, 6); + } + + for (i = 0; i < GST_VP9_MAX_MODE_LF_DELTAS; i++) { + lf->update_mode_deltas[i] = gst_vp9_read_bit (br); + if (lf->update_mode_deltas[i]) + lf->mode_deltas[i] = gst_vp9_read_signed_bits (br, 6); + } + } + } +} + +static gint8 +parse_delta_q (GstBitReader * br) +{ + return gst_vp9_read_bit (br) ? gst_vp9_read_signed_bits (br, 4) : 0; +} + +static void +parse_quantization (GstVp9QuantIndices * quant_indices, GstBitReader * br) +{ + quant_indices->y_ac_qi = gst_vp9_read_bits (br, QINDEX_BITS); + quant_indices->y_dc_delta = parse_delta_q (br); + quant_indices->uv_dc_delta = parse_delta_q (br); + quant_indices->uv_ac_delta = parse_delta_q (br); +} + +static void +parse_segmentation (GstVp9SegmentationInfo * seg, GstBitReader * br) +{ + int i; + + seg->update_map = FALSE; + seg->update_data = FALSE; + + seg->enabled = gst_vp9_read_bit (br); + if (!seg->enabled) + return; + + /* Segmentation map update */ + seg->update_map = gst_vp9_read_bit (br); + if (seg->update_map) { + for (i = 0; i < GST_VP9_SEG_TREE_PROBS; i++) { + seg->update_tree_probs[i] = gst_vp9_read_bit (br); + seg->tree_probs[i] = seg->update_tree_probs[i] ? + gst_vp9_read_bits (br, 8) : GST_VP9_MAX_PROB; + } + + seg->temporal_update = gst_vp9_read_bit (br); + if (seg->temporal_update) { + for (i = 0; i < GST_VP9_PREDICTION_PROBS; i++) { + seg->update_pred_probs[i] = gst_vp9_read_bit (br); + seg->pred_probs[i] = seg->update_pred_probs[i] ? + gst_vp9_read_bits (br, 8) : GST_VP9_MAX_PROB; + } + } else { + for (i = 0; i < GST_VP9_PREDICTION_PROBS; i++) + seg->pred_probs[i] = GST_VP9_MAX_PROB; + } + } + + /* Segmentation data update */ + seg->update_data = gst_vp9_read_bit (br); + + if (seg->update_data) { + /* clear all features */ + memset (seg->data, 0, sizeof (seg->data)); + + seg->abs_delta = gst_vp9_read_bit (br); + + for (i = 0; i < GST_VP9_MAX_SEGMENTS; i++) { + GstVp9SegmentationInfoData *seg_data = seg->data + i; + guint8 data; + + /* SEG_LVL_ALT_Q */ + seg_data->alternate_quantizer_enabled = gst_vp9_read_bit (br); + if (seg_data->alternate_quantizer_enabled) { + data = gst_vp9_read_bits (br, 8); + seg_data->alternate_quantizer = gst_vp9_read_bit (br) ? -data : data; + } + + /* SEG_LVL_ALT_LF */ + seg_data->alternate_loop_filter_enabled = gst_vp9_read_bit (br); + if (seg_data->alternate_loop_filter_enabled) { + data = gst_vp9_read_bits (br, 6); + seg_data->alternate_loop_filter = gst_vp9_read_bit (br) ? -data : data; + } + + /* SEG_LVL_REF_FRAME */ + seg_data->reference_frame_enabled = gst_vp9_read_bit (br); + if (seg_data->reference_frame_enabled) { + seg_data->reference_frame = gst_vp9_read_bits (br, 2); + } + + seg_data->reference_skip = gst_vp9_read_bit (br); + } + } +} + +static guint32 +get_max_lb_tile_cols (guint32 sb_cols) +{ + gint max_log2 = 1; + while ((sb_cols >> max_log2) >= MIN_TILE_WIDTH_B64) + ++max_log2; + return max_log2 - 1; +} + +static guint32 +get_min_lb_tile_cols (guint32 sb_cols) +{ + gint min_log2 = 0; + while ((MAX_TILE_WIDTH_B64 << min_log2) < sb_cols) + ++min_log2; + return min_log2; +} + +static gboolean +parse_tile_info (GstVp9FrameHdr * frame_hdr, GstBitReader * br) +{ + guint32 max_ones; + const guint32 sb_cols = ALIGN_SB64 (frame_hdr->width); + guint32 min_lb_tile_cols = get_min_lb_tile_cols (sb_cols); + guint32 max_lb_tile_cols = get_max_lb_tile_cols (sb_cols); + + g_assert (min_lb_tile_cols <= max_lb_tile_cols); + max_ones = max_lb_tile_cols - min_lb_tile_cols; + + /* columns */ + frame_hdr->log2_tile_columns = min_lb_tile_cols; + while (max_ones-- && gst_vp9_read_bit (br)) + frame_hdr->log2_tile_columns++; + + if (frame_hdr->log2_tile_columns > 6) { + GST_ERROR ("Invalid number of tile columns..!"); + return FALSE; + } + + /* row */ + frame_hdr->log2_tile_rows = gst_vp9_read_bit (br); + if (frame_hdr->log2_tile_rows) + frame_hdr->log2_tile_rows += gst_vp9_read_bit (br); + + return TRUE; +} + +static void +loop_filter_update (GstVp9Parser * parser, const GstVp9LoopFilter * lf) +{ + GstVp9ParserPrivate *priv = GST_VP9_PARSER_GET_PRIVATE (parser); + int i; + + for (i = 0; i < GST_VP9_MAX_REF_LF_DELTAS; i++) { + if (lf->update_ref_deltas[i]) + priv->ref_deltas[i] = lf->ref_deltas[i]; + } + + for (i = 0; i < GST_VP9_MAX_MODE_LF_DELTAS; i++) { + if (lf->update_mode_deltas[i]) + priv->mode_deltas[i] = lf->mode_deltas[i]; + } +} + +static guint8 +seg_get_base_qindex (const GstVp9Parser * parser, + const GstVp9FrameHdr * frame_hdr, int segid) +{ + int seg_base = frame_hdr->quant_indices.y_ac_qi; + GstVp9ParserPrivate *priv = GST_VP9_PARSER_GET_PRIVATE (parser); + const GstVp9SegmentationInfoData *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); +} + +static guint8 +seg_get_filter_level (const GstVp9Parser * parser, + const GstVp9FrameHdr * frame_hdr, int segid) +{ + int seg_filter = frame_hdr->loopfilter.filter_level; + GstVp9ParserPrivate *priv = GST_VP9_PARSER_GET_PRIVATE (parser); + const GstVp9SegmentationInfoData *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, GST_VP9_MAX_LOOP_FILTER); +} + +/*save segmentation info from frame header to parser*/ +static void +segmentation_save (GstVp9Parser * parser, const GstVp9FrameHdr * frame_hdr) +{ + const GstVp9SegmentationInfo *info = &frame_hdr->segmentation; + if (!info->enabled) + return; + + if (info->update_map) { + g_assert (G_N_ELEMENTS (parser->mb_segment_tree_probs) == + G_N_ELEMENTS (info->tree_probs)); + g_assert (G_N_ELEMENTS (parser->segment_pred_probs) == + G_N_ELEMENTS (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) { + GstVp9ParserPrivate *priv = GST_VP9_PARSER_GET_PRIVATE (parser); + priv->segmentation_abs_delta = info->abs_delta; + g_assert (G_N_ELEMENTS (priv->segmentation) == G_N_ELEMENTS (info->data)); + memcpy (priv->segmentation, info->data, sizeof (info->data)); + } +} + +static void +segmentation_update (GstVp9Parser * parser, const GstVp9FrameHdr * frame_hdr) +{ + int i = 0; + const GstVp9ParserPrivate *priv = GST_VP9_PARSER_GET_PRIVATE (parser); + const GstVp9LoopFilter *lf = &frame_hdr->loopfilter; + const GstVp9QuantIndices *quant_indices = &frame_hdr->quant_indices; + int default_filter = lf->filter_level; + const int scale = 1 << (default_filter >> 5); + + segmentation_save (parser, frame_hdr); + + for (i = 0; i < GST_VP9_MAX_SEGMENTS; i++) { + guint8 q = seg_get_base_qindex (parser, frame_hdr, i); + + GstVp9Segmentation *seg = parser->segmentation + i; + const GstVp9SegmentationInfoData *info = priv->segmentation + i; + + seg->luma_dc_quant_scale = + vp9_dc_quant (q, quant_indices->y_dc_delta, frame_hdr->bit_depth); + seg->luma_ac_quant_scale = vp9_ac_quant (q, 0, frame_hdr->bit_depth); + seg->chroma_dc_quant_scale = + vp9_dc_quant (q, quant_indices->uv_dc_delta, frame_hdr->bit_depth); + seg->chroma_ac_quant_scale = + vp9_ac_quant (q, quant_indices->uv_ac_delta, frame_hdr->bit_depth); + + if (lf->filter_level) { + guint8 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[GST_VP9_REF_FRAME_INTRA] * scale; + seg->filter_level[GST_VP9_REF_FRAME_INTRA][0] = + clamp (intra_filter, 0, GST_VP9_MAX_LOOP_FILTER); + for (ref = GST_VP9_REF_FRAME_LAST; ref < GST_VP9_REF_FRAME_MAX; ++ref) { + for (mode = 0; mode < GST_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, GST_VP9_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 (GstVp9Parser * parser, const GstVp9FrameHdr * const frame_hdr) +{ + guint8 flag = 1; + guint8 refresh_frame_flags; + int i; + GstVp9ParserPrivate *priv = GST_VP9_PARSER_GET_PRIVATE (parser); + ReferenceSize *reference = priv->reference; + if (frame_hdr->frame_type == GST_VP9_KEY_FRAME) { + refresh_frame_flags = 0xff; + } else { + refresh_frame_flags = frame_hdr->refresh_frame_flags; + } + for (i = 0; i < GST_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 +frame_is_intra_only (const GstVp9FrameHdr * frame_hdr) +{ + return frame_hdr->frame_type == GST_VP9_KEY_FRAME || frame_hdr->intra_only; +} + +static void +set_default_lf_deltas (GstVp9Parser * parser) +{ + GstVp9ParserPrivate *priv = GST_VP9_PARSER_GET_PRIVATE (parser); + priv->ref_deltas[GST_VP9_REF_FRAME_INTRA] = 1; + priv->ref_deltas[GST_VP9_REF_FRAME_LAST] = 0; + priv->ref_deltas[GST_VP9_REF_FRAME_GOLDEN] = -1; + priv->ref_deltas[GST_VP9_REF_FRAME_ALTREF] = -1; + + priv->mode_deltas[0] = 0; + priv->mode_deltas[1] = 0; +} + +static void +set_default_segmentation_info (GstVp9Parser * parser) +{ + GstVp9ParserPrivate *priv = GST_VP9_PARSER_GET_PRIVATE (parser); + + memset (priv->segmentation, 0, sizeof (priv->segmentation)); + + priv->segmentation_abs_delta = FALSE; +} + +static void +setup_past_independence (GstVp9Parser * parser, + GstVp9FrameHdr * 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 void +gst_vp9_parser_init (GstVp9Parser * parser) +{ + GstVp9ParserPrivate *priv = parser->priv; + + memset (parser, 0, sizeof (GstVp9Parser)); + memset (priv, 0, sizeof (GstVp9ParserPrivate)); + + parser->priv = priv; +} + +static GstVp9ParserResult +gst_vp9_parser_update (GstVp9Parser * parser, GstVp9FrameHdr * const frame_hdr) +{ + if (frame_hdr->frame_type == GST_VP9_KEY_FRAME) + gst_vp9_parser_init (parser); + + if (frame_is_intra_only (frame_hdr) || frame_hdr->error_resilient_mode) + setup_past_independence (parser, frame_hdr); + + loop_filter_update (parser, &frame_hdr->loopfilter); + segmentation_update (parser, frame_hdr); + reference_update (parser, frame_hdr); + + return GST_VP9_PARSER_OK; +} + + +/******** API *************/ + +/** + * gst_vp9_parser_new: + * + * Creates a new #GstVp9Parser. It should be freed with + * gst_vp9_parser_free after use. + * + * Returns: a new #GstVp9Parser + */ +GstVp9Parser * +gst_vp9_parser_new (void) +{ + GstVp9Parser *parser; + GstVp9ParserPrivate *priv; + + INITIALIZE_DEBUG_CATEGORY; + GST_DEBUG ("Create VP9 Parser"); + + parser = g_slice_new (GstVp9Parser); + if (!parser) + return NULL; + + priv = g_slice_new (GstVp9ParserPrivate); + if (!priv) + return NULL; + + parser->priv = priv; + gst_vp9_parser_init (parser); + + return parser; +} + +/** + * gst_vp9_parser_free: + * @parser: the #GstVp9Parser to free + * + * Frees @parser and sets it to %NULL + */ +void +gst_vp9_parser_free (GstVp9Parser * parser) +{ + if (parser) { + if (parser->priv) { + g_slice_free (GstVp9ParserPrivate, parser->priv); + parser->priv = NULL; + } + g_slice_free (GstVp9Parser, parser); + parser = NULL; + } +} + +/** + * gst_vp9_parser_parse_frame_header: + * @parser: The #GstVp9Parser + * @frame_hdr: The #GstVp9FrameHdr to fill + * @data: The data to parse + * @size: The size of the @data to parse + * + * Parses the VP9 bitstream contained in @data, and fills in @frame_hdr + * with the information. The @size argument represent the whole frame size. + * + * Returns: a #GstVp9ParserResult + * + */ +GstVp9ParserResult +gst_vp9_parser_parse_frame_header (GstVp9Parser * parser, + GstVp9FrameHdr * frame_hdr, const guint8 * data, gsize size) +{ + GstBitReader bit_reader; + GstBitReader *br = &bit_reader; + + gst_bit_reader_init (br, data, size); + memset (frame_hdr, 0, sizeof (*frame_hdr)); + + /* Parsing Uncompressed Data Chunk */ + + if (!verify_frame_marker (br)) + goto error; + + frame_hdr->profile = parse_profile (br); + if (frame_hdr->profile > GST_VP9_PROFILE_UNDEFINED) { + GST_ERROR ("Stream has undefined VP9 profile !"); + goto error; + } + + frame_hdr->show_existing_frame = gst_vp9_read_bit (br); + if (frame_hdr->show_existing_frame) { + frame_hdr->frame_to_show = gst_vp9_read_bits (br, GST_VP9_REF_FRAMES_LOG2); + return GST_VP9_PARSER_OK; + } + + frame_hdr->frame_type = gst_vp9_read_bit (br); + frame_hdr->show_frame = gst_vp9_read_bit (br); + frame_hdr->error_resilient_mode = gst_vp9_read_bit (br); + + if (frame_hdr->frame_type == GST_VP9_KEY_FRAME) { + + if (!verify_sync_code (br)) { + GST_ERROR ("Invalid VP9 Key-frame sync code !"); + goto error; + } + + if (!parse_bitdepth_colorspace_sampling (br, frame_hdr)) { + GST_ERROR ("Failed to parse color_space/bit_depth info !"); + goto error; + } + + parse_frame_size (br, &frame_hdr->width, &frame_hdr->height); + + parse_display_frame_size (br, frame_hdr); + + } else { + frame_hdr->intra_only = frame_hdr->show_frame ? 0 : gst_vp9_read_bit (br); + frame_hdr->reset_frame_context = frame_hdr->error_resilient_mode ? + 0 : gst_vp9_read_bits (br, 2); + + if (frame_hdr->intra_only) { + + if (!verify_sync_code (br)) { + GST_ERROR ("Invalid VP9 sync code in intra-only frame !"); + goto error; + } + + if (frame_hdr->profile > GST_VP9_PROFILE_0) { + if (!parse_bitdepth_colorspace_sampling (br, frame_hdr)) { + GST_ERROR ("Failed to parse color_space/bit_depth info !"); + goto error; + } + } else { + frame_hdr->color_space = GST_VP9_CS_BT_601; + frame_hdr->color_range = GST_VP9_CR_LIMITED; + frame_hdr->subsampling_y = frame_hdr->subsampling_x = 1; + frame_hdr->bit_depth = GST_VP9_BIT_DEPTH_8; + } + + frame_hdr->refresh_frame_flags = + gst_vp9_read_bits (br, GST_VP9_REF_FRAMES); + parse_frame_size (br, &frame_hdr->width, &frame_hdr->height); + parse_display_frame_size (br, frame_hdr); + + } else { + int i; + frame_hdr->refresh_frame_flags = + gst_vp9_read_bits (br, GST_VP9_REF_FRAMES); + + for (i = 0; i < GST_VP9_REFS_PER_FRAME; i++) { + frame_hdr->ref_frame_indices[i] = + gst_vp9_read_bits (br, GST_VP9_REF_FRAMES_LOG2); + frame_hdr->ref_frame_sign_bias[i] = gst_vp9_read_bit (br); + } + + parse_frame_size_from_refs (parser, frame_hdr, br); + parse_display_frame_size (br, frame_hdr); + + frame_hdr->allow_high_precision_mv = gst_vp9_read_bit (br); + frame_hdr->mcomp_filter_type = parse_interp_filter (br); + + /* Assing defalut values */ + frame_hdr->color_space = GST_VP9_CS_BT_601; + frame_hdr->color_range = GST_VP9_CR_LIMITED; + frame_hdr->subsampling_y = frame_hdr->subsampling_x = 1; + frame_hdr->bit_depth = GST_VP9_BIT_DEPTH_8; + } + } + + frame_hdr->refresh_frame_context = + frame_hdr->error_resilient_mode ? 0 : gst_vp9_read_bit (br); + frame_hdr->frame_parallel_decoding_mode = + frame_hdr->error_resilient_mode ? 1 : gst_vp9_read_bit (br); + frame_hdr->frame_context_idx = + gst_vp9_read_bits (br, GST_FRAME_CONTEXTS_LOG2); + + /* loopfilter header */ + parse_loopfilter (&frame_hdr->loopfilter, br); + + /* quantization header */ + parse_quantization (&frame_hdr->quant_indices, br); + /* set lossless_flag */ + frame_hdr->lossless_flag = frame_hdr->quant_indices.y_ac_qi == 0 && + frame_hdr->quant_indices.y_dc_delta == 0 && + frame_hdr->quant_indices.uv_dc_delta == 0 + && frame_hdr->quant_indices.uv_ac_delta == 0; + + /* segmentation header */ + parse_segmentation (&frame_hdr->segmentation, br); + + /* tile header */ + if (!parse_tile_info (frame_hdr, br)) { + GST_ERROR ("Failed to parse tile info...!"); + goto error; + } + + /* size of the rest of the header */ + frame_hdr->first_partition_size = gst_vp9_read_bits (br, 16); + if (!frame_hdr->first_partition_size) { + GST_ERROR ("Failed to parse the first partition size...!"); + goto error; + } + + frame_hdr->frame_header_length_in_bytes = + (gst_bit_reader_get_pos (br) + 7) / 8; + + return gst_vp9_parser_update (parser, frame_hdr); + +error: + return GST_VP9_PARSER_ERROR; +} diff --git a/gst-libs/gst/codecparsers/gstvp9parser.h b/gst-libs/gst/codecparsers/gstvp9parser.h new file mode 100644 index 0000000000..21ae7ee7ff --- /dev/null +++ b/gst-libs/gst/codecparsers/gstvp9parser.h @@ -0,0 +1,464 @@ +/* + * gstvp9parser.h + * + * Copyright (C) 2013-2014 Intel Corporation + * Copyright (C) 2015 Intel Corporation + * Author: XuGuangxin + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef GST_VP9_PARSER_H +#define GST_VP9_PARSER_H + +#ifndef GST_USE_UNSTABLE_API +#warning "The VP9 parsing library is unstable API and may change in future." +#warning "You can define GST_USE_UNSTABLE_API to avoid this warning." +#endif + +#include + +G_BEGIN_DECLS + +#define GST_VP9_FRAME_MARKER 0x02 +#define GST_VP9_SYNC_CODE 0x498342 + +#define GST_VP9_MAX_LOOP_FILTER 63 +#define GST_VP9_MAX_PROB 255 + +#define GST_VP9_REFS_PER_FRAME 3 +#define GST_VP9_REF_FRAMES_LOG2 3 +#define GST_VP9_REF_FRAMES (1 << GST_VP9_REF_FRAMES_LOG2) + +#define GST_FRAME_CONTEXTS_LOG2 2 + +#define GST_VP9_MAX_LOOP_FILTER 63 +#define GST_VP9_MAX_SHARPNESS 7 + +#define GST_VP9_MAX_REF_LF_DELTAS 4 +#define GST_VP9_MAX_MODE_LF_DELTAS 2 + +#define GST_VP9_SEGMENT_DELTADATA 0 +#define GST_VP9_SEGMENT_ABSDATA 1 + +#define GST_VP9_MAX_SEGMENTS 8 +#define GST_VP9_SEG_TREE_PROBS (GST_VP9_MAX_SEGMENTS-1) + +#define GST_VP9_PREDICTION_PROBS 3 + +typedef struct _GstVp9Parser GstVp9Parser; +typedef struct _GstVp9FrameHdr GstVp9FrameHdr; +typedef struct _GstVp9LoopFilter GstVp9LoopFilter; +typedef struct _GstVp9QuantIndices GstVp9QuantIndices; +typedef struct _GstVp9Segmentation GstVp9Segmentation; +typedef struct _GstVp9SegmentationInfo GstVp9SegmentationInfo; +typedef struct _GstVp9SegmentationInfoData GstVp9SegmentationInfoData; + +/** + * GstVp9ParseResult: + * @GST_VP9_PARSER_OK: The parsing went well + * @GST_VP9_PARSER_BROKEN_DATA: The data to parse is broken + * @GST_VP9_PARSER_NO_PACKET_ERROR: An error accured durint the parsing + * + * Result type of any parsing function. + */ +typedef enum +{ + GST_VP9_PARSER_OK, + GST_VP9_PARSER_BROKEN_DATA, + GST_VP9_PARSER_ERROR, +} GstVp9ParserResult; + +/** + * GstVp9Profile: Bitstream profiles indicated by 2-3 bits in the uncompressed header + * @GST_VP9_PROFILE_0: Profile 0, 8-bit 4:2:0 only. + * @GST_VP9_PROFILE_1: Profile 1, 8-bit 4:4:4, 4:2:2, and 4:4:0. + * @GST_VP9_PROFILE_2: Profile 2, 10-bit and 12-bit color only, with 4:2:0 sampling. + * @GST_VP9_PROFILE_3: Profile 3, 10-bit and 12-bit color only, with 4:2:2/4:4:4/4:4:0 sampling. + * @GST_VP9_PROFILE_UNDEFINED: Undefined profile + * + * VP9 Profiles + */ +typedef enum { + GST_VP9_PROFILE_0, + GST_VP9_PROFILE_1, + GST_VP9_PROFILE_2, + GST_VP9_PROFILE_3, + GST_VP9_PROFILE_UNDEFINED +} GstVP9Profile; + +/** + * GstVp9FrameType: + * @GST_VP9_KEY_FRAME: Key frame, only have intra blocks + * @GST_VP9_INTER_FRAME: Inter frame, both intra and inter blocks + * + * VP9 frame types + */ +typedef enum { + GST_VP9_KEY_FRAME = 0, + GST_VP9_INTER_FRAME = 1 +} GstVp9FrameType; + +/** + * GstVp9BitDepth: + * @GST_VP9_BIT_DEPTH_8: Bit depth is 8 + * @GST_VP9_BIT_DEPTH_10 Bit depth is 10 + * @GST_VP9_BIT_DEPTH_12:Bit depth is 12 + * + * Bit depths of encoded frames + */ +typedef enum { + GST_VP9_BIT_DEPTH_8 = 8, + GST_VP9_BIT_DEPTH_10 = 10, + GST_VP9_BIT_DEPTH_12 = 12 +} GstVp9BitDepth; + +/** + * GstVp9ColorSpace: + * @GST_VP9_CS_UNKNOWN: Unknown color space + * @GST_VP9_CS_BT_601: BT.601 + * @GST_VP9_CS_BT_709: BT.709 + * @GST_VP9_CS_SMPTE_170: SMPTE.170 + * @GST_VP9_CS_SMPTE_240: SMPTE.240 + * @GST_VP9_CS_BT_2020: BT.2020 + * @GST_VP9_CS_RESERVED: Reserved + * @GST_VP9_CS_SRGB: sRGB + * + * Supported ColorSpace standards + */ +typedef enum { + GST_VP9_CS_UNKNOWN = 0, + GST_VP9_CS_BT_601 = 1, + GST_VP9_CS_BT_709 = 2, + GST_VP9_CS_SMPTE_170 = 3, + GST_VP9_CS_SMPTE_240 = 4, + GST_VP9_CS_BT_2020 = 5, + GST_VP9_CS_RESERVED_2 = 6, + GST_VP9_CS_SRGB = 7 +} GstVp9ColorSpace; + +/** + * GstVp9ColorRange: + * @GST_VP9_CR_LIMITED: Y range is [16-235], UV range is [16-240] + * @GST_VP9_CR_FULL: Full range for Y,U and V [0-255] + * + * Possible color value ranges + */ +typedef enum { + GST_VP9_CR_LIMITED, + GST_VP9_CR_FULL +} GstVp9ColorRange; + +/** + * GstVp9InterpFilter: + * @GST_VP9_INTERP_FILTER_EIGHTTAP: EightTap interpolation filter + * @GST_VP9_INTERP_FILTER_EIGHTTAP_SMOOTH: Smooth interpolation filter + * @GST_VP9_INTERP_FILTER_EIGHTTAP_SHARP: Shart interpolation filter + * @GST_VP9_INTERP_FILTER_BILINEAR: Bilinear interpolation filter + * @GST_VP9_INTERP_FILTER_SWITCHABLE: Selectable interpolation filter + * + * Interpolation Filters Types + */ +typedef enum { + GST_VP9_INTERP_FILTER_EIGHTTAP = 0, + GST_VP9_INTERP_FILTER_EIGHTTAP_SMOOTH = 1, + GST_VP9_INTERP_FILTER_EIGHTTAP_SHARP = 2, + GST_VP9_INTERP_FILTER_BILINEAR = 3, + GST_VP9_INTERP_FILTER_SWITCHABLE = 4 +} GstVp9InterpFilter; + +/** + * GstVp9RefFrameType: + * @GST_VP9_REF_FRAME_INTRA: Intra reference frame + * @GST_VP9_REF_FRAME_LAST: Last Reference frame + * @GST_VP9_REF_FRAME_GOLDEN: Golden Reference frame + * @GST_VP9_REF_FRAME_ALTREF: Alternate Reference frame + * @GST_VP9_REF_FRAME_MAX: + * + * Reference Frame types + */ +typedef enum { + GST_VP9_REF_FRAME_INTRA = 0, + GST_VP9_REF_FRAME_LAST = 1, + GST_VP9_REF_FRAME_GOLDEN = 2, + GST_VP9_REF_FRAME_ALTREF = 3, + GST_VP9_REF_FRAME_MAX = 4 +} GstVp9RefFrameType; + +/** + * GstVp9QuantIndices: + * @y_ac_qi: indicates the dequantization table index used for the + * luma AC coefficients + * @y_dc_delta: indicates the delta value that is added to the + * baseline index to obtain the luma DC coefficient dequantization + * index + * @uv_dc_delta: indicates the delta value that is added to the + * baseline index to obtain the chroma DC coefficient dequantization + * index + * @uv_ac_delta: indicates the delta value that is added to the + * baseline index to obtain the chroma AC coefficient dequantization + * index + * + * Dequantization indices. + */ +struct _GstVp9QuantIndices +{ + guint8 y_ac_qi; + gint8 y_dc_delta; + gint8 uv_dc_delta; + gint8 uv_ac_delta; +}; + +/** + * GstVp9MbLoofFilter: + * @filter_level: indicates loop filter level for the current frame + * @sharpness_level: indicates sharpness level for thecurrent frame + * @mode_ref_delta_enabled: indicate if filter adjust is on + * @mode_ref_delta_update: indicates if the delta values used in an + * adjustment are updated in the current frame + * @update_ref_deltas: indicate which ref deltas are updated + * @ref_deltas: Loop filter strength adjustments based on + * frame type (intra, inter) + * @update_mode_deltas: indicate with mode deltas are updated + * @mode_deltas: Loop filter strength adjustments based on + * mode (zero, new mv) + * + * Loop filter values + */ +struct _GstVp9LoopFilter { + gint filter_level; + gint sharpness_level; + + guint8 mode_ref_delta_enabled; + guint8 mode_ref_delta_update; + guint8 update_ref_deltas[GST_VP9_MAX_REF_LF_DELTAS]; + gint8 ref_deltas[GST_VP9_MAX_REF_LF_DELTAS]; + guint8 update_mode_deltas[GST_VP9_MAX_MODE_LF_DELTAS]; + gint8 mode_deltas[GST_VP9_MAX_MODE_LF_DELTAS]; +}; + +/** +* GstVp9SegmentationInfoData: +* @alternate_quantizer_enabled: indicate alternate quantizer enabled at segment level +* @alternate_quantizer: alternate quantizer value +* @alternate_loop_filter_enabled: indicate alternate loop filter enabled at segment level +* @alternate_loop_filter: alternate loop filter +* @reference_frame_enabled: indicate alternate reference frame at segment level +* @reference_frame: alternate reference frame +* @reference_skip: a block skip mode that implies both the use of a (0,0) +* motion vector and that no residual will be coded. +* +* Segemtnation info for each segment +* +*/ +struct _GstVp9SegmentationInfoData { + /* SEG_LVL_ALT_Q */ + guint8 alternate_quantizer_enabled; + gint16 alternate_quantizer; + + /* SEG_LVL_ALT_LF */ + guint8 alternate_loop_filter_enabled; + gint8 alternate_loop_filter; + + /* SEG_LVL_REF_FRAME */ + guint8 reference_frame_enabled; + gint reference_frame; + + guint8 reference_skip; +}; + +/** + * GstVp9SegmentationInfo: + * @enabled: enables the segmentation feature for the current frame + * @update_map: determines if segmentation is updated in the current frame + * @update_tree_probs: determines if tree probabilities updated or not + * @tree_probs: segment tree probabilities + * @update_pred_probs:determines if prediction probabilities updated or not + * @pred_probs: prediction probabilities + * @abs_delta: interpretation of segment data values + * @temporal_update: type of map update + * @update_data: indicates if the segment feature data + * is updated in the current frame + * @data: segment feature data + * + * Segmentation info + */ +struct _GstVp9SegmentationInfo { + /* enable in setup_segmentation*/ + guint8 enabled; + /* update_map in setup_segmentation*/ + guint8 update_map; + /* tree_probs exist or not*/ + guint8 update_tree_probs[GST_VP9_SEG_TREE_PROBS]; + guint8 tree_probs[GST_VP9_SEG_TREE_PROBS]; + /* pred_probs exist or not*/ + guint8 update_pred_probs[GST_VP9_PREDICTION_PROBS]; + guint8 pred_probs[GST_VP9_PREDICTION_PROBS]; + + /* abs_delta in setup_segmentation */ + guint8 abs_delta; + /* temporal_update in setup_segmentation */ + guint8 temporal_update; + + /* update_data in setup_segmentation*/ + guint8 update_data; + GstVp9SegmentationInfoData data[GST_VP9_MAX_SEGMENTS]; +}; + +/** + * GstVp9FrameHdr: + * @profile: encoded profile + * @show_existing_frame: display already decoded frame instead of doing the decoding + * @frame_to_show: which frame to show if show_existing_frame is true + * @frame_type: frame type + * @show_frame: indicate whether is it displayable frame or not + * @error_resilient_mode: error resilent mode + * @subsampling_x: horizontal subsampling + * @subsampling_y: vertical subsampling + * @width: frame width + * @height: frame height + * @display_size_enabled: display size enabled (cropping) + * @display_width: display width + * @display_height: display height + * @frame_context_idx: frame context index + * @bit_depth: bit depth of the stream + * @color_space: color space standard + * @color_range: color range standard + * @intra_only: intra only frame + * @reset_frame_context: reset frame context + * @refresh_frame_flags: refresh reference frame flags + * @ref_frame_indices: reference frame index + * @ref_frame_sign_bias: sign bias for selecting altref,last and golden frames + * @allow_high_precision_mv: allow hight precision motion vector + * @mcomp_filter_type: interpolation filter type + * @refresh_frame_context: refresh frame context indicator + * @frame_parallel_decoding_mode: enable or disable parallel decoding support. + * @loopfilter: loopfilter values + * @quant_indices: quantization indeces + * @segmentation: segmentation info + * @log2_tile_rows: tile row indicator + * @log2_tile_columns: tile column indicator + * @first_partition_size: first partition size (after the uncompressed header) + * @lossless_flag: lossless mode decode + * @frame_header_length_in_bytes: length of uncompressed header + * + * Frame header + */ +struct _GstVp9FrameHdr +{ + guint profile; + guint8 show_existing_frame; + gint frame_to_show; + guint frame_type; + guint8 show_frame; + guint8 error_resilient_mode; + gint subsampling_x; + gint subsampling_y; + guint32 width; + guint32 height; + guint8 display_size_enabled; + guint32 display_width; + guint32 display_height; + guint frame_context_idx; + + guint bit_depth; + guint color_space; + guint color_range; + + guint8 intra_only; + gint reset_frame_context; + gint refresh_frame_flags; + + gint ref_frame_indices[GST_VP9_REFS_PER_FRAME]; + gint ref_frame_sign_bias[GST_VP9_REFS_PER_FRAME]; + gint allow_high_precision_mv; + guint8 mcomp_filter_type; + + gint refresh_frame_context; + /* frame_parallel_decoding_mode in vp9 code*/ + gint frame_parallel_decoding_mode; + + GstVp9LoopFilter loopfilter; + GstVp9QuantIndices quant_indices; + GstVp9SegmentationInfo segmentation; + + gint log2_tile_rows; + gint log2_tile_columns; + + guint32 first_partition_size; + + /* calculated values */ + guint lossless_flag; + guint32 frame_header_length_in_bytes; +}; + +/** + * GstVp9Segmentation: + * @filter_level: loop filter level + * @luma_ac_quant_scale: AC quant scale for luma(Y) component + * @luma_dc_quant_scale: DC quant scale for luma(Y) component + * @chroma_ac_quant_scale AC quant scale for chroma(U/V) component + * @chroma_dc_quant_scale: DC quant scale for chroma (U/V) component + * @reference_frame_enabled: alternate reference frame enablement + * @reference_frame: alternate reference frame + * @reference_skip: a block skip mode that implies both the use of a (0,0) + * motion vector and that no residual will be coded + * + * Segmentation info kept across multipe frames + */ +struct _GstVp9Segmentation +{ + guint8 filter_level[4][2]; + gint16 luma_ac_quant_scale; + gint16 luma_dc_quant_scale; + gint16 chroma_ac_quant_scale; + gint16 chroma_dc_quant_scale; + + guint8 reference_frame_enabled; + gint reference_frame; + + guint8 reference_skip; +}; + +/** + * GstVp9Parser: + * @priv: GstVp9ParserPrivate struct to keep track of state variables + * @mb_segment_tree_probs: decoding tree probabilities + * @segment_pred_probs: segement prediction probabiilties + * @segmentation: Segemenation info + * + * Parser context that needs to be live across frames + */ +struct _GstVp9Parser +{ + /* private stuct for tracking state variables across frames */ + void *priv; + + guint8 mb_segment_tree_probs[GST_VP9_SEG_TREE_PROBS]; + guint8 segment_pred_probs[GST_VP9_PREDICTION_PROBS]; + GstVp9Segmentation segmentation[GST_VP9_MAX_SEGMENTS]; +}; + +GstVp9Parser * gst_vp9_parser_new (void); + +GstVp9ParserResult gst_vp9_parser_parse_frame_header (GstVp9Parser* parser, GstVp9FrameHdr * frame_hdr, const guint8 * data, gsize size); + +void gst_vp9_parser_free (GstVp9Parser * parser); + +G_END_DECLS + +#endif /* GST_VP9_PARSER_H */ diff --git a/gst-libs/gst/codecparsers/vp9utils.AUTHORS b/gst-libs/gst/codecparsers/vp9utils.AUTHORS new file mode 100644 index 0000000000..a9aa481063 --- /dev/null +++ b/gst-libs/gst/codecparsers/vp9utils.AUTHORS @@ -0,0 +1,100 @@ +# This file is automatically generated from the git commit history +# by tools/gen_authors.sh. + +Aaron Watry +Abo Talib Mahfoodh +Adrian Grange +Ahmad Sharif +Alexander Voronov +Alex Converse +Alexis Ballier +Alok Ahuja +Alpha Lam +A.Mahfoodh +Ami Fischman +Andoni Morales Alastruey +Andres Mejia +Aron Rosenberg +Attila Nagy +changjun.yang +chm +Christian Duvivier +Daniel Kang +Deb Mukherjee +Dmitry Kovalev +Dragan Mrdjan +Erik Niemeyer +Fabio Pedretti +Frank Galligan +Fredrik Söderquist +Fritz Koenig +Gaute Strokkenes +Giuseppe Scrivano +Guillaume Martres +Guillermo Ballester Valor +Hangyu Kuang +Henrik Lundin +Hui Su +Ivan Maltz +James Berry +James Zern +Jan Kratochvil +Janne Salonen +Jeff Faust +Jeff Muizelaar +Jeff Petkau +Jim Bankoski +Jingning Han +Johann Koenig +John Koleszar +Joshua Bleecher Snyder +Joshua Litt +Justin Clift +Justin Lebar +KO Myung-Hun +Lou Quillio +Luca Barbato +Makoto Kato +Mans Rullgard +Marco Paniconi +Mark Mentovai +Martin Ettl +Martin Storsjo +Matthew Heaney +Michael Kohler +Mike Frysinger +Mike Hommey +Mikhal Shemer +Morton Jonuschat +Parag Salasakar +Pascal Massimino +Patrik Westin +Paul Wilkins +Pavol Rusnak +Paweł Hajdan +Philip Jägenstedt +Priit Laes +Rafael Ávila de Espíndola +Rafaël Carré +Ralph Giles +Rob Bradford +Ronald S. Bultje +Sami Pietilä +Scott Graham +Scott LaVarnway +Shimon Doodkin +Stefan Holmer +Suman Sunkara +Taekhyun Kim +Takanori MATSUURA +Tamar Levy +Tero Rintaluoma +Thijs Vermeir +Timothy B. Terriberry +Tom Finegan +Vignesh Venkatasubramanian +Yaowu Xu +Yunqing Wang +Google Inc. +The Mozilla Foundation +The Xiph.Org Foundation diff --git a/gst-libs/gst/codecparsers/vp9utils.LICENSE b/gst-libs/gst/codecparsers/vp9utils.LICENSE new file mode 100644 index 0000000000..83ef339ecd --- /dev/null +++ b/gst-libs/gst/codecparsers/vp9utils.LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2010, The WebM Project authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of Google, nor the WebM Project, nor the names + of its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +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 +HOLDER 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. diff --git a/gst-libs/gst/codecparsers/vp9utils.PATENTS b/gst-libs/gst/codecparsers/vp9utils.PATENTS new file mode 100644 index 0000000000..4414d83850 --- /dev/null +++ b/gst-libs/gst/codecparsers/vp9utils.PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the WebM Project. + +Google hereby grants to you a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer, and otherwise run, modify and propagate the contents of this +implementation of VP8, where such license applies only to those patent +claims, both currently owned by Google and acquired in the future, +licensable by Google that are necessarily infringed by this +implementation of VP8. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of VP8 or any code incorporated within this +implementation of VP8 constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of VP8 +shall terminate as of the date such litigation is filed. diff --git a/gst-libs/gst/codecparsers/vp9utils.c b/gst-libs/gst/codecparsers/vp9utils.c new file mode 100644 index 0000000000..71c5a4e2d6 --- /dev/null +++ b/gst-libs/gst/codecparsers/vp9utils.c @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2010 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "vp9utils.h" + +static const int16_t dc_qlookup[QINDEX_RANGE] = { + 4, 8, 8, 9, 10, 11, 12, 12, + 13, 14, 15, 16, 17, 18, 19, 19, + 20, 21, 22, 23, 24, 25, 26, 26, + 27, 28, 29, 30, 31, 32, 32, 33, + 34, 35, 36, 37, 38, 38, 39, 40, + 41, 42, 43, 43, 44, 45, 46, 47, + 48, 48, 49, 50, 51, 52, 53, 53, + 54, 55, 56, 57, 57, 58, 59, 60, + 61, 62, 62, 63, 64, 65, 66, 66, + 67, 68, 69, 70, 70, 71, 72, 73, + 74, 74, 75, 76, 77, 78, 78, 79, + 80, 81, 81, 82, 83, 84, 85, 85, + 87, 88, 90, 92, 93, 95, 96, 98, + 99, 101, 102, 104, 105, 107, 108, 110, + 111, 113, 114, 116, 117, 118, 120, 121, + 123, 125, 127, 129, 131, 134, 136, 138, + 140, 142, 144, 146, 148, 150, 152, 154, + 156, 158, 161, 164, 166, 169, 172, 174, + 177, 180, 182, 185, 187, 190, 192, 195, + 199, 202, 205, 208, 211, 214, 217, 220, + 223, 226, 230, 233, 237, 240, 243, 247, + 250, 253, 257, 261, 265, 269, 272, 276, + 280, 284, 288, 292, 296, 300, 304, 309, + 313, 317, 322, 326, 330, 335, 340, 344, + 349, 354, 359, 364, 369, 374, 379, 384, + 389, 395, 400, 406, 411, 417, 423, 429, + 435, 441, 447, 454, 461, 467, 475, 482, + 489, 497, 505, 513, 522, 530, 539, 549, + 559, 569, 579, 590, 602, 614, 626, 640, + 654, 668, 684, 700, 717, 736, 755, 775, + 796, 819, 843, 869, 896, 925, 955, 988, + 1022, 1058, 1098, 1139, 1184, 1232, 1282, 1336, +}; + +static const int16_t dc_qlookup_10[QINDEX_RANGE] = { + 4, 9, 10, 13, 15, 17, 20, 22, + 25, 28, 31, 34, 37, 40, 43, 47, + 50, 53, 57, 60, 64, 68, 71, 75, + 78, 82, 86, 90, 93, 97, 101, 105, + 109, 113, 116, 120, 124, 128, 132, 136, + 140, 143, 147, 151, 155, 159, 163, 166, + 170, 174, 178, 182, 185, 189, 193, 197, + 200, 204, 208, 212, 215, 219, 223, 226, + 230, 233, 237, 241, 244, 248, 251, 255, + 259, 262, 266, 269, 273, 276, 280, 283, + 287, 290, 293, 297, 300, 304, 307, 310, + 314, 317, 321, 324, 327, 331, 334, 337, + 343, 350, 356, 362, 369, 375, 381, 387, + 394, 400, 406, 412, 418, 424, 430, 436, + 442, 448, 454, 460, 466, 472, 478, 484, + 490, 499, 507, 516, 525, 533, 542, 550, + 559, 567, 576, 584, 592, 601, 609, 617, + 625, 634, 644, 655, 666, 676, 687, 698, + 708, 718, 729, 739, 749, 759, 770, 782, + 795, 807, 819, 831, 844, 856, 868, 880, + 891, 906, 920, 933, 947, 961, 975, 988, + 1001, 1015, 1030, 1045, 1061, 1076, 1090, 1105, + 1120, 1137, 1153, 1170, 1186, 1202, 1218, 1236, + 1253, 1271, 1288, 1306, 1323, 1342, 1361, 1379, + 1398, 1416, 1436, 1456, 1476, 1496, 1516, 1537, + 1559, 1580, 1601, 1624, 1647, 1670, 1692, 1717, + 1741, 1766, 1791, 1817, 1844, 1871, 1900, 1929, + 1958, 1990, 2021, 2054, 2088, 2123, 2159, 2197, + 2236, 2276, 2319, 2363, 2410, 2458, 2508, 2561, + 2616, 2675, 2737, 2802, 2871, 2944, 3020, 3102, + 3188, 3280, 3375, 3478, 3586, 3702, 3823, 3953, + 4089, 4236, 4394, 4559, 4737, 4929, 5130, 5347, +}; + +static const int16_t dc_qlookup_12[QINDEX_RANGE] = { + 4, 12, 18, 25, 33, 41, 50, 60, + 70, 80, 91, 103, 115, 127, 140, 153, + 166, 180, 194, 208, 222, 237, 251, 266, + 281, 296, 312, 327, 343, 358, 374, 390, + 405, 421, 437, 453, 469, 484, 500, 516, + 532, 548, 564, 580, 596, 611, 627, 643, + 659, 674, 690, 706, 721, 737, 752, 768, + 783, 798, 814, 829, 844, 859, 874, 889, + 904, 919, 934, 949, 964, 978, 993, 1008, + 1022, 1037, 1051, 1065, 1080, 1094, 1108, 1122, + 1136, 1151, 1165, 1179, 1192, 1206, 1220, 1234, + 1248, 1261, 1275, 1288, 1302, 1315, 1329, 1342, + 1368, 1393, 1419, 1444, 1469, 1494, 1519, 1544, + 1569, 1594, 1618, 1643, 1668, 1692, 1717, 1741, + 1765, 1789, 1814, 1838, 1862, 1885, 1909, 1933, + 1957, 1992, 2027, 2061, 2096, 2130, 2165, 2199, + 2233, 2267, 2300, 2334, 2367, 2400, 2434, 2467, + 2499, 2532, 2575, 2618, 2661, 2704, 2746, 2788, + 2830, 2872, 2913, 2954, 2995, 3036, 3076, 3127, + 3177, 3226, 3275, 3324, 3373, 3421, 3469, 3517, + 3565, 3621, 3677, 3733, 3788, 3843, 3897, 3951, + 4005, 4058, 4119, 4181, 4241, 4301, 4361, 4420, + 4479, 4546, 4612, 4677, 4742, 4807, 4871, 4942, + 5013, 5083, 5153, 5222, 5291, 5367, 5442, 5517, + 5591, 5665, 5745, 5825, 5905, 5984, 6063, 6149, + 6234, 6319, 6404, 6495, 6587, 6678, 6769, 6867, + 6966, 7064, 7163, 7269, 7376, 7483, 7599, 7715, + 7832, 7958, 8085, 8214, 8352, 8492, 8635, 8788, + 8945, 9104, 9275, 9450, 9639, 9832, 10031, 10245, + 10465, 10702, 10946, 11210, 11482, 11776, 12081, 12409, + 12750, 13118, 13501, 13913, 14343, 14807, 15290, 15812, + 16356, 16943, 17575, 18237, 18949, 19718, 20521, 21387, +}; + +static const int16_t ac_qlookup[QINDEX_RANGE] = { + 4, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, + 104, 106, 108, 110, 112, 114, 116, 118, + 120, 122, 124, 126, 128, 130, 132, 134, + 136, 138, 140, 142, 144, 146, 148, 150, + 152, 155, 158, 161, 164, 167, 170, 173, + 176, 179, 182, 185, 188, 191, 194, 197, + 200, 203, 207, 211, 215, 219, 223, 227, + 231, 235, 239, 243, 247, 251, 255, 260, + 265, 270, 275, 280, 285, 290, 295, 300, + 305, 311, 317, 323, 329, 335, 341, 347, + 353, 359, 366, 373, 380, 387, 394, 401, + 408, 416, 424, 432, 440, 448, 456, 465, + 474, 483, 492, 501, 510, 520, 530, 540, + 550, 560, 571, 582, 593, 604, 615, 627, + 639, 651, 663, 676, 689, 702, 715, 729, + 743, 757, 771, 786, 801, 816, 832, 848, + 864, 881, 898, 915, 933, 951, 969, 988, + 1007, 1026, 1046, 1066, 1087, 1108, 1129, 1151, + 1173, 1196, 1219, 1243, 1267, 1292, 1317, 1343, + 1369, 1396, 1423, 1451, 1479, 1508, 1537, 1567, + 1597, 1628, 1660, 1692, 1725, 1759, 1793, 1828, +}; + +static const int16_t ac_qlookup_10[QINDEX_RANGE] = { + 4, 9, 11, 13, 16, 18, 21, 24, + 27, 30, 33, 37, 40, 44, 48, 51, + 55, 59, 63, 67, 71, 75, 79, 83, + 88, 92, 96, 100, 105, 109, 114, 118, + 122, 127, 131, 136, 140, 145, 149, 154, + 158, 163, 168, 172, 177, 181, 186, 190, + 195, 199, 204, 208, 213, 217, 222, 226, + 231, 235, 240, 244, 249, 253, 258, 262, + 267, 271, 275, 280, 284, 289, 293, 297, + 302, 306, 311, 315, 319, 324, 328, 332, + 337, 341, 345, 349, 354, 358, 362, 367, + 371, 375, 379, 384, 388, 392, 396, 401, + 409, 417, 425, 433, 441, 449, 458, 466, + 474, 482, 490, 498, 506, 514, 523, 531, + 539, 547, 555, 563, 571, 579, 588, 596, + 604, 616, 628, 640, 652, 664, 676, 688, + 700, 713, 725, 737, 749, 761, 773, 785, + 797, 809, 825, 841, 857, 873, 889, 905, + 922, 938, 954, 970, 986, 1002, 1018, 1038, + 1058, 1078, 1098, 1118, 1138, 1158, 1178, 1198, + 1218, 1242, 1266, 1290, 1314, 1338, 1362, 1386, + 1411, 1435, 1463, 1491, 1519, 1547, 1575, 1603, + 1631, 1663, 1695, 1727, 1759, 1791, 1823, 1859, + 1895, 1931, 1967, 2003, 2039, 2079, 2119, 2159, + 2199, 2239, 2283, 2327, 2371, 2415, 2459, 2507, + 2555, 2603, 2651, 2703, 2755, 2807, 2859, 2915, + 2971, 3027, 3083, 3143, 3203, 3263, 3327, 3391, + 3455, 3523, 3591, 3659, 3731, 3803, 3876, 3952, + 4028, 4104, 4184, 4264, 4348, 4432, 4516, 4604, + 4692, 4784, 4876, 4972, 5068, 5168, 5268, 5372, + 5476, 5584, 5692, 5804, 5916, 6032, 6148, 6268, + 6388, 6512, 6640, 6768, 6900, 7036, 7172, 7312, +}; + +static const int16_t ac_qlookup_12[QINDEX_RANGE] = { + 4, 13, 19, 27, 35, 44, 54, 64, + 75, 87, 99, 112, 126, 139, 154, 168, + 183, 199, 214, 230, 247, 263, 280, 297, + 314, 331, 349, 366, 384, 402, 420, 438, + 456, 475, 493, 511, 530, 548, 567, 586, + 604, 623, 642, 660, 679, 698, 716, 735, + 753, 772, 791, 809, 828, 846, 865, 884, + 902, 920, 939, 957, 976, 994, 1012, 1030, + 1049, 1067, 1085, 1103, 1121, 1139, 1157, 1175, + 1193, 1211, 1229, 1246, 1264, 1282, 1299, 1317, + 1335, 1352, 1370, 1387, 1405, 1422, 1440, 1457, + 1474, 1491, 1509, 1526, 1543, 1560, 1577, 1595, + 1627, 1660, 1693, 1725, 1758, 1791, 1824, 1856, + 1889, 1922, 1954, 1987, 2020, 2052, 2085, 2118, + 2150, 2183, 2216, 2248, 2281, 2313, 2346, 2378, + 2411, 2459, 2508, 2556, 2605, 2653, 2701, 2750, + 2798, 2847, 2895, 2943, 2992, 3040, 3088, 3137, + 3185, 3234, 3298, 3362, 3426, 3491, 3555, 3619, + 3684, 3748, 3812, 3876, 3941, 4005, 4069, 4149, + 4230, 4310, 4390, 4470, 4550, 4631, 4711, 4791, + 4871, 4967, 5064, 5160, 5256, 5352, 5448, 5544, + 5641, 5737, 5849, 5961, 6073, 6185, 6297, 6410, + 6522, 6650, 6778, 6906, 7034, 7162, 7290, 7435, + 7579, 7723, 7867, 8011, 8155, 8315, 8475, 8635, + 8795, 8956, 9132, 9308, 9484, 9660, 9836, 10028, + 10220, 10412, 10604, 10812, 11020, 11228, 11437, 11661, + 11885, 12109, 12333, 12573, 12813, 13053, 13309, 13565, + 13821, 14093, 14365, 14637, 14925, 15213, 15502, 15806, + 16110, 16414, 16734, 17054, 17390, 17726, 18062, 18414, + 18766, 19134, 19502, 19886, 20270, 20670, 21070, 21486, + 21902, 22334, 22766, 23214, 23662, 24126, 24590, 25070, + 25551, 26047, 26559, 27071, 27599, 28143, 28687, 29247, +}; + +int clamp(int value, int low, int high) +{ + return value < low ? low : (value > high ? high : value); +} + +int16_t vp9_dc_quant(int qindex, int delta, int bit_depth) +{ + const uint8_t q_table_idx = clamp(qindex + delta, 0, MAXQ); + + switch (bit_depth) { + case 8: + return dc_qlookup[q_table_idx]; + case 10: + return dc_qlookup_10[q_table_idx]; + case 12: + return dc_qlookup_12[q_table_idx]; + default: + return -1; + } + return -1; +} + +int16_t vp9_ac_quant(int qindex, int delta, int bit_depth) +{ + const uint8_t q_table_idx = clamp(qindex + delta, 0, MAXQ); + + switch (bit_depth) { + case 8: + return ac_qlookup[q_table_idx]; + case 10: + return ac_qlookup_10[q_table_idx]; + case 12: + return ac_qlookup_12[q_table_idx]; + default: + return -1; + } + return -1; +} diff --git a/gst-libs/gst/codecparsers/vp9utils.h b/gst-libs/gst/codecparsers/vp9utils.h new file mode 100644 index 0000000000..0a6feb1fe2 --- /dev/null +++ b/gst-libs/gst/codecparsers/vp9utils.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2010 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. + */ +#ifndef __VP9_QUANT_H__ +#define __VP9_QUANT_H__ + +#include + +#define MAXQ 255 +#define QINDEX_RANGE 256 +#define QINDEX_BITS 8 + +int clamp(int value, int low, int high); + +int16_t vp9_dc_quant(int qindex, int delta, int bit_depth); + +int16_t vp9_ac_quant(int qindex, int delta, int bit_depth); + + +#endif //__VP9_QUANT_H__