static void
gst_vaapidecode_init (GstVaapiDecode * decode)
{
  GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);

  gst_vaapi_plugin_base_init (GST_VAAPI_PLUGIN_BASE (decode), GST_CAT_DEFAULT);

  decode->decoder = NULL;
  decode->decoder_caps = NULL;
  decode->allowed_caps = NULL;

  g_mutex_init (&decode->surface_ready_mutex);
  g_cond_init (&decode->surface_ready);

  gst_video_decoder_set_packetized (vdec, FALSE);

#if !GST_CHECK_VERSION(1,4,0)
  /* Pad through which data comes in to the element */
  GstPad *pad = GST_VAAPI_PLUGIN_BASE_SINK_PAD (decode);
  gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_vaapidecode_query));

  /* Pad through which data goes out of the element */
  pad = GST_VAAPI_PLUGIN_BASE_SRC_PAD (decode);
  gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_vaapidecode_query));
#endif
}
Esempio n. 2
0
static GstFlowReturn
gst_vaapiencode_finish (GstVideoEncoder * venc)
{
  GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc);
  GstVaapiEncoderStatus status;
  GstFlowReturn ret = GST_FLOW_OK;

  /* Don't try to destroy encoder if none was created in the first place.
     Return "not-negotiated" error since this means we did not even reach
     GstVideoEncoder::set_format() state, where the encoder could have
     been created */
  if (!encode->encoder)
    return GST_FLOW_NOT_NEGOTIATED;

  status = gst_vaapi_encoder_flush (encode->encoder);

  GST_VIDEO_ENCODER_STREAM_UNLOCK (encode);
  gst_pad_stop_task (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode));
  GST_VIDEO_ENCODER_STREAM_LOCK (encode);

  while (status == GST_VAAPI_ENCODER_STATUS_SUCCESS && ret == GST_FLOW_OK)
    ret = gst_vaapiencode_push_frame (encode, 0);

  if (ret == GST_VAAPI_ENCODE_FLOW_TIMEOUT)
    ret = GST_FLOW_OK;
  return ret;
}
static GstCaps *
gst_vaapiencode_h265_get_caps (GstVaapiEncode * base_encode)
{
  GstVaapiEncodeH265 *const encode = GST_VAAPIENCODE_H265_CAST (base_encode);
  GstCaps *caps, *allowed_caps;

  caps = gst_caps_from_string (GST_CODEC_CAPS);

  /* Check whether "stream-format" is hvcC mode */
  allowed_caps =
      gst_pad_get_allowed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode));
  if (allowed_caps) {
    const char *stream_format = NULL;
    GstStructure *structure;
    guint i, num_structures;

    num_structures = gst_caps_get_size (allowed_caps);
    for (i = 0; !stream_format && i < num_structures; i++) {
      structure = gst_caps_get_structure (allowed_caps, i);
      if (!gst_structure_has_field_typed (structure, "stream-format",
              G_TYPE_STRING))
        continue;
      stream_format = gst_structure_get_string (structure, "stream-format");
    }
    encode->is_hvc = stream_format && strcmp (stream_format, "hvc1") == 0;
    gst_caps_unref (allowed_caps);
  }
  gst_caps_set_simple (caps, "stream-format", G_TYPE_STRING,
      encode->is_hvc ? "hvc1" : "byte-stream", NULL);

  base_encode->need_codec_data = encode->is_hvc;

  /* XXX: update profile and level information */
  return caps;
}
Esempio n. 4
0
static gboolean
gst_vaapiencode_set_format (GstVideoEncoder * venc, GstVideoCodecState * state)
{
  GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc);
  gboolean ret;

  g_return_val_if_fail (state->caps != NULL, FALSE);

  if (!set_codec_state (encode, state))
    return FALSE;

  if (!gst_vaapi_plugin_base_set_caps (GST_VAAPI_PLUGIN_BASE (encode),
          state->caps, NULL))
    return FALSE;

  if (encode->input_state)
    gst_video_codec_state_unref (encode->input_state);
  encode->input_state = gst_video_codec_state_ref (state);
  encode->input_state_changed = TRUE;

  ret = gst_pad_start_task (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode),
      (GstTaskFunction) gst_vaapiencode_buffer_loop, encode, NULL);

  if (!ret)
    return FALSE;

  /* Store some tags */
  {
    GstTagList *tags = gst_tag_list_new_empty ();
    const gchar *encoder, *codec;
    guint bitrate = 0;

    g_object_get (encode, "bitrate", &bitrate, NULL);
    gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE,
        bitrate, NULL);

    if ((encoder =
            gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (encode),
                GST_ELEMENT_METADATA_LONGNAME)))
      gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, encoder,
          NULL);

    if ((codec =
            gst_vaapi_codec_get_name (gst_vaapi_profile_get_codec
                (gst_vaapi_profile_from_caps (state->caps)))))
      gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CODEC, codec,
          NULL);

    gst_video_encoder_merge_tags (venc, tags, GST_TAG_MERGE_REPLACE);
    gst_tag_list_unref (tags);
  }

  return TRUE;
}
Esempio n. 5
0
static void
gst_vaapiencode_buffer_loop (GstVaapiEncode * encode)
{
  GstFlowReturn ret;
  const gint64 timeout = 50000; /* microseconds */

  ret = gst_vaapiencode_push_frame (encode, timeout);
  if (ret == GST_FLOW_OK || ret == GST_VAAPI_ENCODE_FLOW_TIMEOUT)
    return;

  gst_pad_pause_task (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode));
}
Esempio n. 6
0
static GstStateChangeReturn
gst_vaapiencode_change_state (GstElement * element, GstStateChange transition)
{
  GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (element);

  switch (transition) {
    case GST_STATE_CHANGE_PAUSED_TO_READY:
      gst_pad_stop_task (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode));
      break;
    default:
      break;
  }
  return
      GST_ELEMENT_CLASS (gst_vaapiencode_parent_class)->change_state (element,
      transition);
}
static gboolean
gst_vaapiencode_h265_set_config (GstVaapiEncode * base_encode)
{
  GstVaapiEncoderH265 *const encoder =
      GST_VAAPI_ENCODER_H265 (base_encode->encoder);
  GstCaps *allowed_caps;
  GstVaapiProfile profile;

  /* Check for the largest profile that is supported */
  allowed_caps =
      gst_pad_get_allowed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (base_encode));
  if (!allowed_caps)
    return TRUE;

  profile = find_best_profile (allowed_caps);
  gst_caps_unref (allowed_caps);
  if (profile) {
    GST_INFO ("using %s profile as target decoder constraints",
        gst_vaapi_utils_h265_get_profile_string (profile));
    if (!gst_vaapi_encoder_h265_set_max_profile (encoder, profile))
      return FALSE;
  }
  return TRUE;
}
Esempio n. 8
0
static gboolean
gst_vaapiencode_set_format (GstVideoEncoder * venc, GstVideoCodecState * state)
{
  GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc);

  g_return_val_if_fail (state->caps != NULL, FALSE);

  if (!ensure_encoder (encode))
    return FALSE;
  if (!set_codec_state (encode, state))
    return FALSE;

  if (!gst_vaapi_plugin_base_set_caps (GST_VAAPI_PLUGIN_BASE (encode),
          state->caps, NULL))
    return FALSE;

  if (encode->input_state)
    gst_video_codec_state_unref (encode->input_state);
  encode->input_state = gst_video_codec_state_ref (state);
  encode->input_state_changed = TRUE;

  return gst_pad_start_task (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode),
      (GstTaskFunction) gst_vaapiencode_buffer_loop, encode, NULL);
}
Esempio n. 9
0
static gboolean
gst_vaapiencode_sink_event (GstVideoEncoder * venc, GstEvent * event)
{
  GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc);
  GstPad *const srcpad = GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode);
  gboolean ret;

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_CUSTOM_DOWNSTREAM:{
      const GstStructure *s = gst_event_get_structure (event);
      if (gst_structure_has_name (s, "GstVaapiEncoderRegionOfInterest")) {
        GstVaapiROI roi;

        if (!encode->encoder)
          return TRUE;

        if (!gst_structure_get_uint (s, "roi-x", &roi.rect.x) ||
            !gst_structure_get_uint (s, "roi-y", &roi.rect.y) ||
            !gst_structure_get_uint (s, "roi-width", &roi.rect.width) ||
            !gst_structure_get_uint (s, "roi-height", &roi.rect.height) ||
            !gst_structure_get_int (s, "roi-value", &roi.roi_value)) {
          return TRUE;
        }

        if (roi.roi_value == 0) {
          ret = gst_vaapi_encoder_del_roi (encode->encoder, &roi);
          if (ret) {
            GST_INFO_OBJECT (venc, "ROI: region with %d/%d/%d/%d is removed",
                roi.rect.x, roi.rect.y, roi.rect.width, roi.rect.height);
          }
        } else {
          ret = gst_vaapi_encoder_add_roi (encode->encoder, &roi);
          if (ret) {
            GST_INFO_OBJECT (venc, "ROI: region with %d/%d/%d/%d is added",
                roi.rect.x, roi.rect.y, roi.rect.width, roi.rect.height);
          }
        }
        gst_event_unref (event);
        return ret;
      }
      break;
    }
    default:
      break;
  }

  ret = GST_VIDEO_ENCODER_CLASS (gst_vaapiencode_parent_class)->sink_event
      (venc, event);
  if (!ret)
    return FALSE;

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_FLUSH_START:
      gst_pad_pause_task (srcpad);
      break;
    case GST_EVENT_FLUSH_STOP:
      ret = gst_pad_start_task (srcpad,
          (GstTaskFunction) gst_vaapiencode_buffer_loop, encode, NULL);
      break;
    default:
      break;
  }

  return ret;
}
Esempio n. 10
0
static gboolean
ensure_allowed_sinkpad_caps (GstVaapiEncode * encode)
{
  GstVaapiEncodeClass *klass = GST_VAAPIENCODE_GET_CLASS (encode);
  GstCaps *out_caps, *raw_caps = NULL;
  GArray *formats = NULL;
  gboolean ret = FALSE;
  GstVaapiProfile profile = GST_VAAPI_PROFILE_UNKNOWN;

  if (encode->allowed_sinkpad_caps)
    return TRUE;
  if (!encode->encoder)
    return TRUE;

  out_caps = gst_caps_from_string (GST_VAAPI_MAKE_SURFACE_CAPS);
  if (!out_caps)
    goto failed_create_va_caps;

  if (klass->get_profile) {
    GstCaps *allowed =
        gst_pad_get_allowed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode));
    if (allowed) {
      if (!gst_caps_is_empty (allowed) && !gst_caps_is_any (allowed))
        profile = klass->get_profile (allowed);
      gst_caps_unref (allowed);
    }
  }

  formats = gst_vaapi_encoder_get_surface_formats (encode->encoder, profile);
  if (!formats)
    goto failed_get_formats;

  raw_caps = gst_vaapi_video_format_new_template_caps_from_list (formats);
  if (!raw_caps)
    goto failed_create_raw_caps;

  out_caps = gst_caps_make_writable (out_caps);
  gst_caps_append (out_caps, gst_caps_copy (raw_caps));
  gst_caps_replace (&encode->allowed_sinkpad_caps, out_caps);
  GST_INFO_OBJECT (encode, "Allowed sink caps %" GST_PTR_FORMAT,
      encode->allowed_sinkpad_caps);

  ret = TRUE;

bail:
  if (out_caps)
    gst_caps_unref (out_caps);
  if (raw_caps)
    gst_caps_unref (raw_caps);
  if (formats)
    g_array_unref (formats);
  return ret;

failed_create_va_caps:
  {
    GST_WARNING_OBJECT (encode, "failed to create VA/GL sink caps");
    return FALSE;
  }
failed_get_formats:
  {
    GST_WARNING_OBJECT (encode, "failed to get allowed surface formats");
    goto bail;
  }
failed_create_raw_caps:
  {
    GST_WARNING_OBJECT (encode, "failed to create raw sink caps");
    goto bail;
  }
}