<commit_before>/*
 *  gstvaapidecoder_vp9.c - VP9 decoder
 *
 *  Copyright (C) 2014-2015 Intel Corporation
 *    Author: <NAME> <<EMAIL>>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2.1
 *  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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301 USA
 */

/**
 * SECTION:gstvaapidecoder_vp9
 * @short_description: VP9 decoder
 */

#include "sysdeps.h"
#include <gst/codecparsers/gstvp9parser.h>
#include "gstvaapidecoder_vp9.h"
#include "gstvaapidecoder_objects.h"
#include "gstvaapidecoder_priv.h"
#include "gstvaapidisplay_priv.h"
#include "gstvaapiobject_priv.h"

#include "gstvaapicompat.h"
#ifdef HAVE_VA_VA_DEC_VP9_H
#include <va/va_dec_vp9.h>
#endif

#define DEBUG 1
#include "gstvaapidebug.h"

#define GST_VAAPI_DECODER_VP9_CAST(decoder) \
  ((GstVaapiDecoderVp9 *)(decoder))

typedef struct _GstVaapiDecoderVp9Private GstVaapiDecoderVp9Private;
typedef struct _GstVaapiDecoderVp9Class GstVaapiDecoderVp9Class;

struct _GstVaapiDecoderVp9Private
{
  GstVaapiProfile profile;
  guint width;
  guint height;
  GstVp9Parser *parser;
  GstVp9FrameHdr frame_hdr;
  GstVaapiPicture *current_picture;
  GstVaapiPicture *ref_frames[GST_VP9_REF_FRAMES];      /* reference frames in ref_slots[max_ref] */

  guint num_frames;             /* number of frames in a super frame */
  guint frame_sizes[8];         /* size of frames in a super frame */
  guint frame_cnt;              /* frame count variable for super frame */
  guint total_idx_size;         /* super frame index size (full block size) */
  guint had_superframe_hdr:1;   /* indicate the presense of super frame */

  guint size_changed:1;
};

/**
 * GstVaapiDecoderVp9:
 *
 * A decoder based on Vp9.
 */
struct _GstVaapiDecoderVp9
{
  /*< private > */
  GstVaapiDecoder parent_instance;

  GstVaapiDecoderVp9Private priv;
};

/**
 * GstVaapiDecoderVp9Class:
 *
 * A decoder class based on Vp9.
 */
struct _GstVaapiDecoderVp9Class
{
  /*< private > */
  GstVaapiDecoderClass parent_class;
};

static GstVaapiDecoderStatus
get_status (GstVp9ParserResult result)
{
  GstVaapiDecoderStatus status;

  switch (result) {
    case GST_VP9_PARSER_OK:
      status = GST_VAAPI_DECODER_STATUS_SUCCESS;
      break;
    case GST_VP9_PARSER_ERROR:
      status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
      break;
    default:
      status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
      break;
  }
  return status;
}

static void
gst_vaapi_decoder_vp9_close (GstVaapiDecoderVp9 * decoder)
{
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
  guint i;

  for (i = 0; i < GST_VP9_REF_FRAMES; i++)
    gst_vaapi_picture_replace (&priv->ref_frames[i], NULL);

  if (priv->parser)
    gst_vp9_parser_free (priv->parser);
}

static gboolean
gst_vaapi_decoder_vp9_open (GstVaapiDecoderVp9 * decoder)
{
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;

  gst_vaapi_decoder_vp9_close (decoder);
  priv->parser = gst_vp9_parser_new ();
  return TRUE;
}

static void
gst_vaapi_decoder_vp9_destroy (GstVaapiDecoder * base_decoder)
{
  GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder);

  gst_vaapi_decoder_vp9_close (decoder);
}

static gboolean
gst_vaapi_decoder_vp9_create (GstVaapiDecoder * base_decoder)
{
  GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder);
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;

  if (!gst_vaapi_decoder_vp9_open (decoder))
    return FALSE;

  priv->profile = GST_VAAPI_PROFILE_UNKNOWN;
  return TRUE;
}

static GstVaapiDecoderStatus
ensure_context (GstVaapiDecoderVp9 * decoder)
{
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
  const GstVaapiProfile profile = GST_VAAPI_PROFILE_VP9;
  const GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
  gboolean reset_context = FALSE;

  if (priv->profile != profile) {
    if (!gst_vaapi_display_has_decoder (GST_VAAPI_DECODER_DISPLAY (decoder),
            profile, entrypoint))
      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;

    priv->profile = profile;
    reset_context = TRUE;
  }

  if (priv->size_changed) {
    GST_DEBUG ("size changed");
    priv->size_changed = FALSE;
    reset_context = TRUE;
  }

  if (reset_context) {
    GstVaapiContextInfo info;

    info.profile = priv->profile;
    info.entrypoint = entrypoint;
    info.chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
    info.width = priv->width;
    info.height = priv->height;
    info.ref_frames = 8;
    reset_context =
        gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info);

    if (!reset_context)
      return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
  }
  return GST_VAAPI_DECODER_STATUS_SUCCESS;
}

static void
init_picture (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture)
{
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
  GstVp9FrameHdr *const frame_hdr = &priv->frame_hdr;

  picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
  picture->type =
      (frame_hdr->frame_type ==
      GST_VP9_KEY_FRAME) ? GST_VAAPI_PICTURE_TYPE_I : GST_VAAPI_PICTURE_TYPE_P;
  picture->pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts;

  if (!frame_hdr->show_frame)
    GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED);
}

static void
vaapi_fill_ref_frames (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture,
    GstVp9FrameHdr * frame_hdr, VADecPictureParameterBufferVP9 * pic_param)
{
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
  guint i;

  if (frame_hdr->frame_type == GST_VP9_KEY_FRAME) {
    for (i = 0; i < G_N_ELEMENTS (priv->ref_frames); i++)
      pic_param->reference_frames[i] = picture->surface_id;

  } else {
    pic_param->pic_fields.bits.last_ref_frame =
        frame_hdr->ref_frame_indices[GST_VP9_REF_FRAME_LAST - 1];
    pic_param->pic_fields.bits.last_ref_frame_sign_bias =
        frame_hdr->ref_frame_sign_bias[GST_VP9_REF_FRAME_LAST - 1];

    if (frame_hdr->ref_frame_indices[1]) {
      pic_param->pic_fields.bits.golden_ref_frame =
          frame_hdr->ref_frame_indices[GST_VP9_REF_FRAME_GOLDEN - 1];
      pic_param->pic_fields.bits.golden_ref_frame_sign_bias =
          frame_hdr->ref_frame_sign_bias[GST_VP9_REF_FRAME_GOLDEN - 1];
      pic_param->pic_fields.bits.alt_ref_frame =
          frame_hdr->ref_frame_indices[GST_VP9_REF_FRAME_ALTREF - 1];
      pic_param->pic_fields.bits.alt_ref_frame_sign_bias =
          frame_hdr->ref_frame_sign_bias[GST_VP9_REF_FRAME_ALTREF - 1];
    }
  }
  for (i = 0; i < G_N_ELEMENTS (priv->ref_frames); i++) {
    pic_param->reference_frames[i] =
        priv->ref_frames[i] ? priv->
        ref_frames[i]->surface_id : VA_INVALID_SURFACE;
  }
}

static gboolean
fill_picture (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture)
{
  GstVaapiDecoderVp9Private *priv = &decoder->priv;
  VADecPictureParameterBufferVP9 *pic_param = picture->param;
  GstVp9Parser *parser = priv->parser;
  GstVp9FrameHdr *frame_hdr = &priv->frame_hdr;

  /* Fill in VAPictureParameterBufferVP9 */
  pic_param->frame_width = frame_hdr->width;
  pic_param->frame_height = frame_hdr->height;

  /* Fill in ReferenceFrames */
  vaapi_fill_ref_frames (decoder, picture, frame_hdr, pic_param);

#define COPY_FIELD(s, f) \
    pic_param->f = (s)->f
#define COPY_BFM(a, s, f) \
    pic_param->a.bits.f = (s)->f

  COPY_BFM (pic_fields, frame_hdr, subsampling_x);
  COPY_BFM (pic_fields, frame_hdr, subsampling_y);
  COPY_BFM (pic_fields, frame_hdr, frame_type);
  COPY_BFM (pic_fields, frame_hdr, show_frame);
  COPY_BFM (pic_fields, frame_hdr, error_resilient_mode);
  COPY_BFM (pic_fields, frame_hdr, intra_only);
  COPY_BFM (pic_fields, frame_hdr, allow_high_precision_mv);
  COPY_BFM (pic_fields, frame_hdr, mcomp_filter_type);
  COPY_BFM (pic_fields, frame_hdr, frame_parallel_decoding_mode);
  COPY_BFM (pic_fields, frame_hdr, reset_frame_context);
  COPY_BFM (pic_fields, frame_hdr, refresh_frame_context);
  COPY_BFM (pic_fields, frame_hdr, frame_context_idx);
  COPY_BFM (pic_fields, frame_hdr, lossless_flag);

  pic_param->pic_fields.bits.segmentation_enabled =
      frame_hdr->segmentation.enabled;
  pic_param->pic_fields.bits.segmentation_temporal_update =
      frame_hdr->segmentation.temporal_update;
  pic_param->pic_fields.bits.segmentation_update_map =
      frame_hdr->segmentation.update_map;

  COPY_FIELD (&frame_hdr->loopfilter, filter_level);
  COPY_FIELD (&frame_hdr->loopfilter, sharpness_level);
  COPY_FIELD (frame_hdr, log2_tile_rows);
  COPY_FIELD (frame_hdr, log2_tile_columns);
  COPY_FIELD (frame_hdr, frame_header_length_in_bytes);
  COPY_FIELD (frame_hdr, first_partition_size);

  g_assert (G_N_ELEMENTS (pic_param->mb_segment_tree_probs) ==
      G_N_ELEMENTS (parser->mb_segment_tree_probs));
  g_assert (G_N_ELEMENTS (pic_param->segment_pred_probs) ==
      G_N_ELEMENTS (parser->segment_pred_probs));

  memcpy (pic_param->mb_segment_tree_probs, parser->mb_segment_tree_probs,
      sizeof (parser->mb_segment_tree_probs));
  memcpy (pic_param->segment_pred_probs, parser->segment_pred_probs,
      sizeof (parser->segment_pred_probs));

  return TRUE;
}

static gboolean
fill_slice (GstVaapiDecoderVp9 * decoder, GstVaapiSlice * slice)
{
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
  GstVp9Parser *parser = priv->parser;
  VASliceParameterBufferVP9 *const slice_param = slice->param;
  guint i;

#define COPY_SEG_FIELD(s, f) \
    seg_param->f = (s)->f

  /* Fill in VASliceParameterBufferVP9 */
  for (i = 0; i < GST_VP9_MAX_SEGMENTS; i++) {
    VASegmentParameterVP9 *seg_param = &slice_param->seg_param[i];
    GstVp9Segmentation *seg = &parser->segmentation[i];

    memcpy (seg_param->filter_level, seg->filter_level,
        sizeof (seg->filter_level));
    COPY_SEG_FIELD (seg, luma_ac_quant_scale);
    COPY_SEG_FIELD (seg, luma_dc_quant_scale);
    COPY_SEG_FIELD (seg, chroma_ac_quant_scale);
    COPY_SEG_FIELD (seg, chroma_dc_quant_scale);

    seg_param->segment_flags.fields.segment_reference_skipped =
        seg->reference_skip;
    seg_param->segment_flags.fields.segment_reference_enabled =
        seg->reference_frame_enabled;
    seg_param->segment_flags.fields.segment_reference = seg->reference_frame;

  }
  /* Fixme: When segmentation is disabled, only seg_param[0] has valid values,
   * all other entries should be populated with 0  ? */

  return TRUE;
}

static GstVaapiDecoderStatus
decode_slice (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture,
    const guchar * buf, guint buf_size)
{
  GstVaapiSlice *slice;

  slice = GST_VAAPI_SLICE_NEW (VP9, decoder, buf, buf_size);
  if (!slice) {
    GST_ERROR ("failed to allocate slice");
    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
  }

  if (!fill_slice (decoder, slice)) {
    gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (slice));
    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
  }

  gst_vaapi_picture_add_slice (GST_VAAPI_PICTURE_CAST (picture), slice);
  return GST_VAAPI_DECODER_STATUS_SUCCESS;
}

static void
update_ref_frames (GstVaapiDecoderVp9 * decoder)
{
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
  GstVaapiPicture *picture = priv->current_picture;
  GstVp9FrameHdr *const frame_hdr = &priv->frame_hdr;
  guint8 refresh_frame_flags, mask, i = 0;

  if (frame_hdr->frame_type == GST_VP9_KEY_FRAME)
    refresh_frame_flags = (1 << GST_VP9_REF_FRAMES) - 1;
  else
    refresh_frame_flags = frame_hdr->refresh_frame_flags;

  for (mask = refresh_frame_flags; mask; mask >>= 1, ++i) {
    if (mask & 1)
      gst_vaapi_picture_replace (&priv->ref_frames[i], picture);
  }
}

#ifdef GST_VAAPI_PICTURE_NEW
#undef GST_VAAPI_PICTURE_NEW
#endif

#define GST_VAAPI_PICTURE_NEW(codec, decoder)                   \
  gst_vaapi_picture_new (GST_VAAPI_DECODER_CAST (decoder),      \
      NULL, sizeof (G_PASTE (VADecPictureParameterBuffer, codec)))

static GstVaapiDecoderStatus
decode_picture (GstVaapiDecoderVp9 * decoder, const guchar * buf,
    guint buf_size)
{
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
  GstVp9FrameHdr *frame_hdr = &priv->frame_hdr;
  GstVaapiPicture *picture;
  GstVaapiDecoderStatus status;
  guint crop_width = 0, crop_height = 0;

  status = ensure_context (decoder);
  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
    return status;

  /* Fixme: handle show_existing_frame */

  /* Create new picture */
  picture = GST_VAAPI_PICTURE_NEW (VP9, decoder);
  if (!picture) {
    GST_ERROR ("failed to allocate picture");
    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
  }
  gst_vaapi_picture_replace (&priv->current_picture, picture);
  gst_vaapi_picture_unref (picture);

  if (frame_hdr->display_size_enabled) {
    crop_width = frame_hdr->display_width;
    crop_height = frame_hdr->display_height;
  } else if (priv->width > frame_hdr->width
      || priv->height > frame_hdr->height) {
    crop_width = frame_hdr->width;
    crop_height = frame_hdr->height;
  }
  if (crop_width || crop_height) {
    GstVaapiRectangle crop_rect;
    crop_rect.x = 0;
    crop_rect.y = 0;
    crop_rect.width = crop_width;
    crop_rect.height = crop_height;
    gst_vaapi_picture_set_crop_rect (picture, &crop_rect);
  }

  init_picture (decoder, picture);
  if (!fill_picture (decoder, picture))
    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;

  return decode_slice (decoder, picture, buf, buf_size);
}


static GstVaapiDecoderStatus
decode_current_picture (GstVaapiDecoderVp9 * decoder)
{
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
  GstVaapiPicture *const picture = priv->current_picture;
  GstVp9FrameHdr *const frame_hdr = &priv->frame_hdr;
<commit_msg>decoder: vp9: Add repeat-frame display handling<commit_after>/*
 *  gstvaapidecoder_vp9.c - VP9 decoder
 *
 *  Copyright (C) 2014-2015 Intel Corporation
 *    Author: <NAME> <<EMAIL>>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2.1
 *  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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301 USA
 */

/**
 * SECTION:gstvaapidecoder_vp9
 * @short_description: VP9 decoder
 */

#include "sysdeps.h"
#include <gst/codecparsers/gstvp9parser.h>
#include "gstvaapidecoder_vp9.h"
#include "gstvaapidecoder_objects.h"
#include "gstvaapidecoder_priv.h"
#include "gstvaapidisplay_priv.h"
#include "gstvaapiobject_priv.h"

#include "gstvaapicompat.h"
#ifdef HAVE_VA_VA_DEC_VP9_H
#include <va/va_dec_vp9.h>
#endif

#define DEBUG 1
#include "gstvaapidebug.h"

#define GST_VAAPI_DECODER_VP9_CAST(decoder) \
  ((GstVaapiDecoderVp9 *)(decoder))

typedef struct _GstVaapiDecoderVp9Private GstVaapiDecoderVp9Private;
typedef struct _GstVaapiDecoderVp9Class GstVaapiDecoderVp9Class;

struct _GstVaapiDecoderVp9Private
{
  GstVaapiProfile profile;
  guint width;
  guint height;
  GstVp9Parser *parser;
  GstVp9FrameHdr frame_hdr;
  GstVaapiPicture *current_picture;
  GstVaapiPicture *ref_frames[GST_VP9_REF_FRAMES];      /* reference frames in ref_slots[max_ref] */

  guint num_frames;             /* number of frames in a super frame */
  guint frame_sizes[8];         /* size of frames in a super frame */
  guint frame_cnt;              /* frame count variable for super frame */
  guint total_idx_size;         /* super frame index size (full block size) */
  guint had_superframe_hdr:1;   /* indicate the presense of super frame */

  guint size_changed:1;
};

/**
 * GstVaapiDecoderVp9:
 *
 * A decoder based on Vp9.
 */
struct _GstVaapiDecoderVp9
{
  /*< private > */
  GstVaapiDecoder parent_instance;

  GstVaapiDecoderVp9Private priv;
};

/**
 * GstVaapiDecoderVp9Class:
 *
 * A decoder class based on Vp9.
 */
struct _GstVaapiDecoderVp9Class
{
  /*< private > */
  GstVaapiDecoderClass parent_class;
};

static GstVaapiDecoderStatus
get_status (GstVp9ParserResult result)
{
  GstVaapiDecoderStatus status;

  switch (result) {
    case GST_VP9_PARSER_OK:
      status = GST_VAAPI_DECODER_STATUS_SUCCESS;
      break;
    case GST_VP9_PARSER_ERROR:
      status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
      break;
    default:
      status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
      break;
  }
  return status;
}

static void
gst_vaapi_decoder_vp9_close (GstVaapiDecoderVp9 * decoder)
{
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
  guint i;

  for (i = 0; i < GST_VP9_REF_FRAMES; i++)
    gst_vaapi_picture_replace (&priv->ref_frames[i], NULL);

  if (priv->parser)
    gst_vp9_parser_free (priv->parser);
}

static gboolean
gst_vaapi_decoder_vp9_open (GstVaapiDecoderVp9 * decoder)
{
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;

  gst_vaapi_decoder_vp9_close (decoder);
  priv->parser = gst_vp9_parser_new ();
  return TRUE;
}

static void
gst_vaapi_decoder_vp9_destroy (GstVaapiDecoder * base_decoder)
{
  GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder);

  gst_vaapi_decoder_vp9_close (decoder);
}

static gboolean
gst_vaapi_decoder_vp9_create (GstVaapiDecoder * base_decoder)
{
  GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder);
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;

  if (!gst_vaapi_decoder_vp9_open (decoder))
    return FALSE;

  priv->profile = GST_VAAPI_PROFILE_UNKNOWN;
  return TRUE;
}

static GstVaapiDecoderStatus
ensure_context (GstVaapiDecoderVp9 * decoder)
{
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
  const GstVaapiProfile profile = GST_VAAPI_PROFILE_VP9;
  const GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
  gboolean reset_context = FALSE;

  if (priv->profile != profile) {
    if (!gst_vaapi_display_has_decoder (GST_VAAPI_DECODER_DISPLAY (decoder),
            profile, entrypoint))
      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;

    priv->profile = profile;
    reset_context = TRUE;
  }

  if (priv->size_changed) {
    GST_DEBUG ("size changed");
    priv->size_changed = FALSE;
    reset_context = TRUE;
  }

  if (reset_context) {
    GstVaapiContextInfo info;

    info.profile = priv->profile;
    info.entrypoint = entrypoint;
    info.chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
    info.width = priv->width;
    info.height = priv->height;
    info.ref_frames = 8;
    reset_context =
        gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info);

    if (!reset_context)
      return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
  }
  return GST_VAAPI_DECODER_STATUS_SUCCESS;
}

static void
init_picture (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture)
{
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
  GstVp9FrameHdr *const frame_hdr = &priv->frame_hdr;

  picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
  picture->type =
      (frame_hdr->frame_type ==
      GST_VP9_KEY_FRAME) ? GST_VAAPI_PICTURE_TYPE_I : GST_VAAPI_PICTURE_TYPE_P;
  picture->pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts;

  if (!frame_hdr->show_frame)
    GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED);
}

static void
vaapi_fill_ref_frames (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture,
    GstVp9FrameHdr * frame_hdr, VADecPictureParameterBufferVP9 * pic_param)
{
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
  guint i;

  if (frame_hdr->frame_type == GST_VP9_KEY_FRAME) {
    for (i = 0; i < G_N_ELEMENTS (priv->ref_frames); i++)
      pic_param->reference_frames[i] = picture->surface_id;

  } else {
    pic_param->pic_fields.bits.last_ref_frame =
        frame_hdr->ref_frame_indices[GST_VP9_REF_FRAME_LAST - 1];
    pic_param->pic_fields.bits.last_ref_frame_sign_bias =
        frame_hdr->ref_frame_sign_bias[GST_VP9_REF_FRAME_LAST - 1];

    if (frame_hdr->ref_frame_indices[1]) {
      pic_param->pic_fields.bits.golden_ref_frame =
          frame_hdr->ref_frame_indices[GST_VP9_REF_FRAME_GOLDEN - 1];
      pic_param->pic_fields.bits.golden_ref_frame_sign_bias =
          frame_hdr->ref_frame_sign_bias[GST_VP9_REF_FRAME_GOLDEN - 1];
      pic_param->pic_fields.bits.alt_ref_frame =
          frame_hdr->ref_frame_indices[GST_VP9_REF_FRAME_ALTREF - 1];
      pic_param->pic_fields.bits.alt_ref_frame_sign_bias =
          frame_hdr->ref_frame_sign_bias[GST_VP9_REF_FRAME_ALTREF - 1];
    }
  }
  for (i = 0; i < G_N_ELEMENTS (priv->ref_frames); i++) {
    pic_param->reference_frames[i] =
        priv->ref_frames[i] ? priv->
        ref_frames[i]->surface_id : VA_INVALID_SURFACE;
  }
}

static gboolean
fill_picture (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture)
{
  GstVaapiDecoderVp9Private *priv = &decoder->priv;
  VADecPictureParameterBufferVP9 *pic_param = picture->param;
  GstVp9Parser *parser = priv->parser;
  GstVp9FrameHdr *frame_hdr = &priv->frame_hdr;

  /* Fill in VAPictureParameterBufferVP9 */
  pic_param->frame_width = frame_hdr->width;
  pic_param->frame_height = frame_hdr->height;

  /* Fill in ReferenceFrames */
  vaapi_fill_ref_frames (decoder, picture, frame_hdr, pic_param);

#define COPY_FIELD(s, f) \
    pic_param->f = (s)->f
#define COPY_BFM(a, s, f) \
    pic_param->a.bits.f = (s)->f

  COPY_BFM (pic_fields, frame_hdr, subsampling_x);
  COPY_BFM (pic_fields, frame_hdr, subsampling_y);
  COPY_BFM (pic_fields, frame_hdr, frame_type);
  COPY_BFM (pic_fields, frame_hdr, show_frame);
  COPY_BFM (pic_fields, frame_hdr, error_resilient_mode);
  COPY_BFM (pic_fields, frame_hdr, intra_only);
  COPY_BFM (pic_fields, frame_hdr, allow_high_precision_mv);
  COPY_BFM (pic_fields, frame_hdr, mcomp_filter_type);
  COPY_BFM (pic_fields, frame_hdr, frame_parallel_decoding_mode);
  COPY_BFM (pic_fields, frame_hdr, reset_frame_context);
  COPY_BFM (pic_fields, frame_hdr, refresh_frame_context);
  COPY_BFM (pic_fields, frame_hdr, frame_context_idx);
  COPY_BFM (pic_fields, frame_hdr, lossless_flag);

  pic_param->pic_fields.bits.segmentation_enabled =
      frame_hdr->segmentation.enabled;
  pic_param->pic_fields.bits.segmentation_temporal_update =
      frame_hdr->segmentation.temporal_update;
  pic_param->pic_fields.bits.segmentation_update_map =
      frame_hdr->segmentation.update_map;

  COPY_FIELD (&frame_hdr->loopfilter, filter_level);
  COPY_FIELD (&frame_hdr->loopfilter, sharpness_level);
  COPY_FIELD (frame_hdr, log2_tile_rows);
  COPY_FIELD (frame_hdr, log2_tile_columns);
  COPY_FIELD (frame_hdr, frame_header_length_in_bytes);
  COPY_FIELD (frame_hdr, first_partition_size);

  g_assert (G_N_ELEMENTS (pic_param->mb_segment_tree_probs) ==
      G_N_ELEMENTS (parser->mb_segment_tree_probs));
  g_assert (G_N_ELEMENTS (pic_param->segment_pred_probs) ==
      G_N_ELEMENTS (parser->segment_pred_probs));

  memcpy (pic_param->mb_segment_tree_probs, parser->mb_segment_tree_probs,
      sizeof (parser->mb_segment_tree_probs));
  memcpy (pic_param->segment_pred_probs, parser->segment_pred_probs,
      sizeof (parser->segment_pred_probs));

  return TRUE;
}

static gboolean
fill_slice (GstVaapiDecoderVp9 * decoder, GstVaapiSlice * slice)
{
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
  GstVp9Parser *parser = priv->parser;
  VASliceParameterBufferVP9 *const slice_param = slice->param;
  guint i;

#define COPY_SEG_FIELD(s, f) \
    seg_param->f = (s)->f

  /* Fill in VASliceParameterBufferVP9 */
  for (i = 0; i < GST_VP9_MAX_SEGMENTS; i++) {
    VASegmentParameterVP9 *seg_param = &slice_param->seg_param[i];
    GstVp9Segmentation *seg = &parser->segmentation[i];

    memcpy (seg_param->filter_level, seg->filter_level,
        sizeof (seg->filter_level));
    COPY_SEG_FIELD (seg, luma_ac_quant_scale);
    COPY_SEG_FIELD (seg, luma_dc_quant_scale);
    COPY_SEG_FIELD (seg, chroma_ac_quant_scale);
    COPY_SEG_FIELD (seg, chroma_dc_quant_scale);

    seg_param->segment_flags.fields.segment_reference_skipped =
        seg->reference_skip;
    seg_param->segment_flags.fields.segment_reference_enabled =
        seg->reference_frame_enabled;
    seg_param->segment_flags.fields.segment_reference = seg->reference_frame;

  }
  /* Fixme: When segmentation is disabled, only seg_param[0] has valid values,
   * all other entries should be populated with 0  ? */

  return TRUE;
}

static GstVaapiDecoderStatus
decode_slice (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture,
    const guchar * buf, guint buf_size)
{
  GstVaapiSlice *slice;

  slice = GST_VAAPI_SLICE_NEW (VP9, decoder, buf, buf_size);
  if (!slice) {
    GST_ERROR ("failed to allocate slice");
    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
  }

  if (!fill_slice (decoder, slice)) {
    gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (slice));
    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
  }

  gst_vaapi_picture_add_slice (GST_VAAPI_PICTURE_CAST (picture), slice);
  return GST_VAAPI_DECODER_STATUS_SUCCESS;
}

static void
update_ref_frames (GstVaapiDecoderVp9 * decoder)
{
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
  GstVaapiPicture *picture = priv->current_picture;
  GstVp9FrameHdr *const frame_hdr = &priv->frame_hdr;
  guint8 refresh_frame_flags, mask, i = 0;

  if (frame_hdr->frame_type == GST_VP9_KEY_FRAME)
    refresh_frame_flags = (1 << GST_VP9_REF_FRAMES) - 1;
  else
    refresh_frame_flags = frame_hdr->refresh_frame_flags;

  for (mask = refresh_frame_flags; mask; mask >>= 1, ++i) {
    if (mask & 1)
      gst_vaapi_picture_replace (&priv->ref_frames[i], picture);
  }
}

#ifdef GST_VAAPI_PICTURE_NEW
#undef GST_VAAPI_PICTURE_NEW
#endif

#define GST_VAAPI_PICTURE_NEW(codec, decoder)                   \
  gst_vaapi_picture_new (GST_VAAPI_DECODER_CAST (decoder),      \
      NULL, sizeof (G_PASTE (VADecPictureParameterBuffer, codec)))

static GstVaapiDecoderStatus
decode_picture (GstVaapiDecoderVp9 * decoder, const guchar * buf,
    guint buf_size)
{
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
  GstVp9FrameHdr *frame_hdr = &priv->frame_hdr;
  GstVaapiPicture *picture;
  GstVaapiDecoderStatus status;
  guint crop_width = 0, crop_height = 0;
  gboolean is_clone_pic = FALSE;

  status = ensure_context (decoder);
  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
    return status;

  /* if show_exising_frame flag is true, we just need to return
   * the existing frame in ref frame array, so creating a clone
   * of already decoded frame */
  if (frame_hdr->show_existing_frame) {
    GstVaapiPicture *existing_frame =
        priv->ref_frames[frame_hdr->frame_to_show];

    if (!existing_frame) {
      GST_ERROR ("Failed to get the existing frame from dpb");
      return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
    }

    picture = gst_vaapi_picture_new_clone (existing_frame);
    if (!picture) {
      GST_ERROR ("Failed to create clone picture");
      return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
    }

    is_clone_pic = TRUE;
  } else {
    /* Create new picture */
    picture = GST_VAAPI_PICTURE_NEW (VP9, decoder);
    if (!picture) {
      GST_ERROR ("failed to allocate picture");
      return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
    }
  }
  gst_vaapi_picture_replace (&priv->current_picture, picture);
  gst_vaapi_picture_unref (picture);

  if (is_clone_pic)
    return GST_VAAPI_DECODER_STATUS_SUCCESS;

  if (frame_hdr->display_size_enabled) {
    crop_width = frame_hdr->display_width;
    crop_height = frame_hdr->display_height;
  } else if (priv->width > frame_hdr->width || priv->height > frame_hdr->height) {
    crop_width = frame_hdr->width;
    crop_height = frame_hdr->height;
  }
  if (crop_width || crop_height) {
    GstVaapiRectangle crop_rect;
    crop_rect.x = 0;
    crop_rect.y = 0;
    crop_rect.width = crop_width;
    crop_rect.height = crop_height;
    gst_vaapi_picture_set_crop_rect (picture, &crop_rect);
  }

  init_picture (decoder, picture);
  if (!fill_picture (decoder, picture))
    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;

  return decode_slice (decoder, picture, buf, buf_size);
}


static GstVaapiDecoderStatus
decode_current_picture (GstVaapiDecoderVp9 * decoder)
{
  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
  GstVaapiPicture *const picture = priv->current_picture;
  GstVp9FrameHdr *const frame_hdr = &priv->frame_hdr;

{'fraction_non_alphanumeric': 0.09419743782969103, 'fraction_numerical': 0.01010481605809413, 'mean_word_length': 4.640455950540958, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 256, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6331889', 'n_tokens_mistral': 11137, 'n_tokens_neox': 10602, 'n_words': 2016}