static void
gst_vaapi_decode_h264_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstVaapiDecodeH264Private *priv;
  GstVaapiDecoderH264 *decoder;

  priv = gst_vaapi_decode_h264_get_instance_private (object);

  switch (prop_id) {
    case GST_VAAPI_DECODER_H264_PROP_FORCE_LOW_LATENCY:
      priv->is_low_latency = g_value_get_boolean (value);
      decoder = GST_VAAPI_DECODER_H264 (GST_VAAPIDECODE (object)->decoder);
      if (decoder)
        gst_vaapi_decoder_h264_set_low_latency (decoder, priv->is_low_latency);
      break;
    case GST_VAAPI_DECODER_H264_PROP_BASE_ONLY:
      priv->base_only = g_value_get_boolean (value);
      decoder = GST_VAAPI_DECODER_H264 (GST_VAAPIDECODE (object)->decoder);
      if (decoder)
        gst_vaapi_decoder_h264_set_base_only (decoder, priv->base_only);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
Beispiel #2
0
static GstCaps *
gst_vaapidecode_sink_getcaps (GstVideoDecoder * vdec, GstCaps * filter)
{
  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
  GstCaps *result;

  if (decode->allowed_sinkpad_caps)
    goto bail;

  /* if we haven't a display yet, return our pad's template caps */
  if (!GST_VAAPI_PLUGIN_BASE_DISPLAY (decode))
    goto bail;

  /* if the allowed caps calculation fails, return an empty caps, so
   * the auto-plug can try other decoder */
  if (!gst_vaapidecode_ensure_allowed_sinkpad_caps (decode))
    return gst_caps_new_empty ();

bail:
  result = gst_video_decoder_proxy_getcaps (vdec, decode->allowed_sinkpad_caps,
      filter);

  GST_DEBUG_OBJECT (decode, "Returning sink caps %" GST_PTR_FORMAT, result);

  return result;
}
Beispiel #3
0
static gboolean
gst_vaapidecode_decide_allocation (GstVideoDecoder * vdec, GstQuery * query)
{
  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
  GstCaps *caps = NULL;

  gst_query_parse_allocation (query, &caps, NULL);
  if (!caps)
    goto error_no_caps;

  decode->has_texture_upload_meta = FALSE;

#if (USE_GLX || USE_EGL)
  decode->has_texture_upload_meta =
      gst_query_find_allocation_meta (query,
      GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL) &&
      gst_vaapi_caps_feature_contains (caps,
      GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META);
#endif

  return gst_vaapi_plugin_base_decide_allocation (GST_VAAPI_PLUGIN_BASE (vdec),
      query);

  /* ERRORS */
error_no_caps:
  {
    GST_ERROR_OBJECT (decode, "no caps specified");
    return FALSE;
  }
}
Beispiel #4
0
static void
gst_vaapidecode_finalize(GObject *object)
{
    GstVaapiDecode * const decode = GST_VAAPIDECODE(object);

    gst_vaapidecode_destroy(decode);

    if (decode->sinkpad_caps) {
        gst_caps_unref(decode->sinkpad_caps);
        decode->sinkpad_caps = NULL;
    }

    if (decode->srcpad_caps) {
        gst_caps_unref(decode->srcpad_caps);
        decode->srcpad_caps = NULL;
    }

    g_clear_object(&decode->display);

    if (decode->allowed_caps) {
        gst_caps_unref(decode->allowed_caps);
        decode->allowed_caps = NULL;
    }

    if (decode->delayed_new_seg) {
        gst_event_unref(decode->delayed_new_seg);
        decode->delayed_new_seg = NULL;
    }

    G_OBJECT_CLASS(gst_vaapidecode_parent_class)->finalize(object);
}
Beispiel #5
0
static void
gst_vaapidecode_set_video_context(GstVideoContext *context, const gchar *type,
    const GValue *value)
{
    GstVaapiDecode *decode = GST_VAAPIDECODE (context);
    gst_vaapi_set_display (type, value, &decode->display);
}
static GstFlowReturn
gst_vaapidecode_drain (GstVideoDecoder * vdec)
{
  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);

  if (!decode->decoder)
    return GST_FLOW_NOT_NEGOTIATED;

  return gst_vaapidecode_push_all_decoded_frames (decode);
}
Beispiel #7
0
static gboolean
gst_vaapidecode_src_event(GstPad *pad, GstEvent *event)
{
    GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));

    GST_DEBUG("handle src event '%s'", GST_EVENT_TYPE_NAME(event));

    /* Propagate event upstream */
    return gst_pad_push_event(decode->sinkpad, event);
}
static gboolean
gst_vaapidecode_close (GstVideoDecoder * vdec)
{
  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);

  gst_vaapi_decode_input_state_replace (decode, NULL);
  gst_vaapidecode_destroy (decode);
  gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (decode));
  return TRUE;
}
Beispiel #9
0
static gboolean
gst_vaapidecode_close (GstVideoDecoder * vdec)
{
  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);

  gst_vaapidecode_destroy (decode);
  gst_caps_replace (&decode->allowed_srcpad_caps, NULL);
  gst_caps_replace (&decode->allowed_sinkpad_caps, NULL);
  gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (decode));
  return TRUE;
}
Beispiel #10
0
static void
gst_vaapidecode_finalize (GObject * object)
{
  GstVaapiDecode *const decode = GST_VAAPIDECODE (object);

  g_cond_clear (&decode->surface_ready);
  g_mutex_clear (&decode->surface_ready_mutex);

  gst_vaapi_plugin_base_finalize (GST_VAAPI_PLUGIN_BASE (object));
  G_OBJECT_CLASS (parent_class)->finalize (object);
}
Beispiel #11
0
static void
gst_vaapi_decoder_notify_caps(GObject *obj, GParamSpec *pspec, void *user_data)
{
    GstVaapiDecode * const decode = GST_VAAPIDECODE(user_data);
    GstCaps *caps;

    g_assert(decode->decoder == GST_VAAPI_DECODER(obj));

    caps = gst_vaapi_decoder_get_caps(decode->decoder);
    gst_vaapidecode_update_src_caps(decode, caps);
}
Beispiel #12
0
static gboolean
gst_vaapidecode_stop (GstVideoDecoder * vdec)
{
  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);

  gst_vaapidecode_purge (decode);
  gst_vaapi_decode_input_state_replace (decode, NULL);
  gst_vaapi_decoder_replace (&decode->decoder, NULL);
  gst_caps_replace (&decode->sinkpad_caps, NULL);
  gst_caps_replace (&decode->srcpad_caps, NULL);
  return TRUE;
}
static gboolean
gst_vaapidecode_flush (GstVideoDecoder * vdec)
{
  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);

  if (decode->decoder && !gst_vaapidecode_internal_flush (vdec))
    return FALSE;

  /* There could be issues if we avoid the reset_full() while doing
   * seeking: we have to reset the internal state */
  return gst_vaapidecode_reset_full (decode, decode->sinkpad_caps, TRUE);
}
Beispiel #14
0
/* invoked if actual VASurface size (not the cropped values)
 * changed */
static void
gst_vaapi_decoder_state_changed (GstVaapiDecoder * decoder,
    const GstVideoCodecState * codec_state, gpointer user_data)
{
  GstVaapiDecode *const decode = GST_VAAPIDECODE (user_data);

  g_assert (decode->decoder == decoder);

  if (!gst_vaapi_decode_input_state_replace (decode, codec_state))
    return;
  if (!gst_vaapidecode_update_sink_caps (decode, decode->input_state->caps))
    return;
}
Beispiel #15
0
static GstFlowReturn
gst_vaapidecode_drain (GstVideoDecoder * vdec)
{
  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);

  if (!decode->decoder)
    return GST_FLOW_NOT_NEGOTIATED;

  GST_LOG_OBJECT (decode, "drain");

  gst_vaapidecode_flush_output_adapter (decode);
  return gst_vaapidecode_push_all_decoded_frames (decode);
}
Beispiel #16
0
static GstCaps *
gst_vaapidecode_get_caps(GstPad *pad)
{
    GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));

    if (!decode->is_ready)
        return gst_static_pad_template_get_caps(&gst_vaapidecode_sink_factory);

    if (!gst_vaapidecode_ensure_allowed_caps(decode))
        return gst_caps_new_empty();

    return gst_caps_ref(decode->allowed_caps);
}
Beispiel #17
0
static gboolean
gst_vaapidecode_open (GstVideoDecoder * vdec)
{
  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);

  if (!gst_vaapi_plugin_base_open (GST_VAAPI_PLUGIN_BASE (decode)))
    return FALSE;

  decode->display_width = 0;
  decode->display_height = 0;
  gst_video_info_init (&decode->decoded_info);

  return TRUE;
}
Beispiel #18
0
static GstFlowReturn
gst_vaapidecode_parse_frame (GstVideoDecoder * vdec,
    GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos)
{
  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
  GstVaapiDecoderStatus status;
  GstFlowReturn ret;
  guint got_unit_size;
  gboolean got_frame;

  status = gst_vaapi_decoder_parse (decode->decoder, frame,
      adapter, at_eos, &got_unit_size, &got_frame);

  switch (status) {
    case GST_VAAPI_DECODER_STATUS_SUCCESS:
      if (got_unit_size > 0) {
        gst_video_decoder_add_to_frame (vdec, got_unit_size);
        decode->current_frame_size += got_unit_size;
      }
      if (got_frame) {
        ret = gst_video_decoder_have_frame (vdec);
        decode->current_frame_size = 0;
      } else
        ret = GST_VAAPI_DECODE_FLOW_PARSE_DATA;
      break;
    case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
      ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
      break;
    case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
    case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
    case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
      GST_WARNING ("parse error %d", status);
      ret = GST_FLOW_NOT_SUPPORTED;
      decode->current_frame_size = 0;
      break;
    default:
      GST_WARNING ("parse error %d", status);
      /* just keep parsing, the decoder should have flushed the broken unit */
      ret = GST_VAAPI_DECODE_FLOW_PARSE_DATA;
      decode->current_frame_size = 0;

      GST_INFO ("requesting upstream a key unit");
      gst_pad_push_event (GST_VIDEO_DECODER_SINK_PAD (decode),
          gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,
              FALSE, 0));
      break;
  }
  return ret;
}
Beispiel #19
0
static gboolean
gst_vaapidecode_query (GstPad *pad, GstQuery *query) {
    GstVaapiDecode *decode = GST_VAAPIDECODE (gst_pad_get_parent_element (pad));
    gboolean res;

    GST_DEBUG ("sharing display %p", decode->display);

    if (gst_vaapi_reply_to_query (query, decode->display))
      res = TRUE;
    else
      res = gst_pad_query_default (pad, query);

    g_object_unref (decode);
    return res;
}
Beispiel #20
0
static gboolean
gst_vaapidecode_flush (GstVideoDecoder * vdec)
{
  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
  if (!decode->decoder)
    return FALSE;

  GST_LOG_OBJECT (vdec, "flushing");

  gst_vaapidecode_purge (decode);

  /* There could be issues if we avoid the reset() while doing
   * seeking: we have to reset the internal state */
  return gst_vaapidecode_reset (decode, decode->sinkpad_caps, TRUE);
}
static GstFlowReturn
gst_vaapidecode_finish (GstVideoDecoder * vdec)
{
  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
  gboolean flushed;
  GstFlowReturn ret;

  if (!decode->decoder)
    return GST_FLOW_OK;

  flushed = gst_vaapidecode_internal_flush (vdec);
  ret = gst_vaapidecode_push_all_decoded_frames (decode);
  if (!flushed)
    return GST_FLOW_ERROR;
  return ret;
}
Beispiel #22
0
static gboolean
gst_vaapidecode_set_format (GstVideoDecoder * vdec, GstVideoCodecState * state)
{
  GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (vdec);
  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);

  if (!gst_vaapi_decode_input_state_replace (decode, state))
    return TRUE;
  if (!gst_vaapidecode_update_sink_caps (decode, state->caps))
    return FALSE;
  if (!gst_vaapi_plugin_base_set_caps (plugin, decode->sinkpad_caps, NULL))
    return FALSE;
  if (!gst_vaapidecode_reset (decode, decode->sinkpad_caps, FALSE))
    return FALSE;

  return TRUE;
}
static gboolean
gst_vaapidecode_src_query (GstVideoDecoder * vdec, GstQuery * query)
{
  gboolean ret = TRUE;
  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
  GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (decode);

  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_CAPS:{
      GstCaps *caps, *filter = NULL;
      GstPad *pad = GST_VIDEO_DECODER_SRC_PAD (vdec);

      gst_query_parse_caps (query, &filter);
      caps = gst_pad_get_pad_template_caps (pad);

      if (filter) {
        GstCaps *tmp = caps;
        caps = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
        gst_caps_unref (tmp);
      }

      gst_query_set_caps_result (query, caps);
      gst_caps_unref (caps);
      break;
    }
    case GST_QUERY_CONTEXT:{
      ret = gst_vaapi_handle_context_query (query, plugin->display);
      break;
    }
    default:{
#if GST_CHECK_VERSION(1,4,0)
      ret = GST_VIDEO_DECODER_CLASS (gst_vaapidecode_parent_class)->src_query
          (vdec, query);
#else
      GstPad *pad = GST_VIDEO_DECODER_SRC_PAD (vdec);
      GstObject *parent = gst_pad_get_parent (pad);
      ret = plugin->srcpad_query (pad, parent, query);
      if (parent)
        gst_object_unref (parent);
#endif
      break;
    }
  }

  return ret;
}
Beispiel #24
0
static GstFlowReturn
gst_vaapidecode_chain(GstPad *pad, GstBuffer *buf)
{
    GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));

    if (!gst_vaapi_decoder_put_buffer(decode->decoder, buf))
        goto error_push_buffer;

    gst_buffer_unref(buf);
    return gst_vaapidecode_step(decode);

    /* ERRORS */
error_push_buffer:
    {
        GST_DEBUG("failed to push input buffer to decoder");
        gst_buffer_unref(buf);
        return GST_FLOW_UNEXPECTED;
    }
}
static gboolean
gst_vaapidecode_query (GstPad * pad, GstObject * parent, GstQuery * query)
{
  GstVaapiDecode *const decode =
      GST_VAAPIDECODE (gst_pad_get_parent_element (pad));
  GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
  gboolean res;

  GST_INFO_OBJECT (decode, "query type %s on %s pad",
      GST_QUERY_TYPE_NAME (query), GST_PAD_IS_SINK (pad) ? "sink" : "src");

  if (GST_PAD_IS_SINK (pad))
    res = gst_vaapidecode_sink_query (vdec, query);
  else
    res = gst_vaapidecode_src_query (vdec, query);

  gst_object_unref (vdec);
  return res;
}
Beispiel #26
0
static GstFlowReturn
gst_vaapidecode_parse_frame (GstVideoDecoder * vdec,
    GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos)
{
  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
  GstVaapiDecoderStatus status;
  GstFlowReturn ret;
  guint got_unit_size;
  gboolean got_frame;

  status = gst_vaapi_decoder_parse (decode->decoder, frame,
      adapter, at_eos, &got_unit_size, &got_frame);

  switch (status) {
    case GST_VAAPI_DECODER_STATUS_SUCCESS:
      if (got_unit_size > 0) {
        gst_video_decoder_add_to_frame (vdec, got_unit_size);
        decode->current_frame_size += got_unit_size;
      }
      if (got_frame) {
        ret = gst_video_decoder_have_frame (vdec);
        decode->current_frame_size = 0;
      } else
        ret = GST_VAAPI_DECODE_FLOW_PARSE_DATA;
      break;
    case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
      ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
      break;
    case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
    case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
    case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
      GST_WARNING ("parse error %d", status);
      ret = GST_FLOW_NOT_SUPPORTED;
      decode->current_frame_size = 0;
      break;
    default:
      GST_ERROR ("parse error %d", status);
      ret = GST_FLOW_EOS;
      decode->current_frame_size = 0;
      break;
  }
  return ret;
}
static GstCaps *
gst_vaapidecode_get_caps (GstPad * pad)
{
  GstVaapiDecode *const decode = GST_VAAPIDECODE (GST_OBJECT_PARENT (pad));

  if (decode->allowed_caps)
    goto bail;

  /* if we haven't a display yet, return our pad's template caps */
  if (!GST_VAAPI_PLUGIN_BASE_DISPLAY (decode))
    return gst_pad_get_pad_template_caps (pad);

  /* if the allowed caps calculation fails, return an empty caps, so
   * the auto-plug can try other decoder */
  if (!gst_vaapidecode_ensure_allowed_caps (decode))
    return gst_caps_new_empty ();

bail:
  return gst_caps_ref (decode->allowed_caps);
}
Beispiel #28
0
static gboolean
gst_vaapidecode_sink_event (GstVideoDecoder * vdec, GstEvent * event)
{
  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_SEGMENT:
    {
      /* Keep segment event to refer to rate so that
       * vaapidecode can handle reverse playback
       */
      gst_event_copy_segment (event, &decode->in_segment);
      break;
    }
    default:
      break;
  }

  return GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (vdec, event);
}
Beispiel #29
0
static gboolean
gst_vaapidecode_start (GstVideoDecoder * vdec)
{
  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
  GstVaapiDisplay *const old_display = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode);
  gboolean success;

  /* Let GstVideoContext ask for a proper display to its neighbours */
  /* Note: steal old display that may be allocated from get_caps()
     so that to retain a reference to it, thus avoiding extra
     initialization steps if we turn out to simply re-use the
     existing (cached) VA display */
  GST_VAAPI_PLUGIN_BASE_DISPLAY (decode) = NULL;
  success =
      gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (decode));
  if (old_display)
    gst_vaapi_display_unref (old_display);

  return success;
}
Beispiel #30
0
static gboolean
gst_vaapidecode_set_caps(GstPad *pad, GstCaps *caps)
{
    GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));

    g_return_val_if_fail(pad == decode->sinkpad, FALSE);

    if (!gst_vaapidecode_update_sink_caps(decode, caps))
        return FALSE;
    if (!gst_vaapidecode_update_src_caps(decode, caps))
        return FALSE;
    if (!gst_vaapidecode_reset(decode, decode->sinkpad_caps))
        return FALSE;

    /* Propagate NEWSEGMENT event downstream, now that pads are linked */
    if (decode->delayed_new_seg) {
        if (gst_pad_push_event(decode->srcpad, decode->delayed_new_seg))
            gst_event_unref(decode->delayed_new_seg);
        decode->delayed_new_seg = NULL;
    }
    return TRUE;
}