Beispiel #1
0
static int qsv_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst,
                                const AVFrame *src)
{
    QSVFramesContext   *s = ctx->internal->priv;
    mfxFrameSurface1   in = {{ 0 }};
    mfxFrameSurface1 *out = (mfxFrameSurface1*)dst->data[3];

    mfxSyncPoint sync = NULL;
    mfxStatus err;

    in.Info = out->Info;
    in.Data.PitchLow = src->linesize[0];
    in.Data.Y        = src->data[0];
    in.Data.U        = src->data[1];
    in.Data.V        = src->data[2];
    in.Data.A        = src->data[3];

    do {
        err = MFXVideoVPP_RunFrameVPPAsync(s->session_upload, &in, out, NULL, &sync);
        if (err == MFX_WRN_DEVICE_BUSY)
            av_usleep(1);
    } while (err == MFX_WRN_DEVICE_BUSY);

    if (err < 0 || !sync) {
        av_log(ctx, AV_LOG_ERROR, "Error uploading the surface\n");
        return AVERROR_UNKNOWN;
    }

    do {
        err = MFXVideoCORE_SyncOperation(s->session_upload, sync, 1000);
    } while (err == MFX_WRN_IN_EXECUTION);
    if (err < 0) {
        av_log(ctx, AV_LOG_ERROR, "Error synchronizing the operation\n");
        return AVERROR_UNKNOWN;
    }

    return 0;
}
static GstFlowReturn
gst_msdkvpp_transform (GstBaseTransform * trans, GstBuffer * inbuf,
    GstBuffer * outbuf)
{
  GstMsdkVPP *thiz = GST_MSDKVPP (trans);
  GstClockTime timestamp;
  GstFlowReturn ret = GST_FLOW_OK;
  mfxSession session;
  mfxSyncPoint sync_point = NULL;
  mfxStatus status;
  MsdkSurface *in_surface = NULL;
  MsdkSurface *out_surface = NULL;

  timestamp = GST_BUFFER_TIMESTAMP (inbuf);

  in_surface = get_msdk_surface_from_input_buffer (thiz, inbuf);
  if (!in_surface)
    return GST_FLOW_ERROR;

  if (gst_msdk_is_msdk_buffer (outbuf)) {
    out_surface = g_slice_new0 (MsdkSurface);
    out_surface->surface = gst_msdk_get_surface_from_buffer (outbuf);
  } else {
    GST_ERROR ("Failed to get msdk outsurface!");
    return GST_FLOW_ERROR;
  }

  session = gst_msdk_context_get_session (thiz->context);

  /* outer loop is for handling FrameRate Control and deinterlace use cases */
  do {
    for (;;) {
      status =
          MFXVideoVPP_RunFrameVPPAsync (session, in_surface->surface,
          out_surface->surface, NULL, &sync_point);
      if (status != MFX_WRN_DEVICE_BUSY)
        break;
      /* If device is busy, wait 1ms and retry, as per MSDK's recommendation */
      g_usleep (1000);
    };

    if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA
        && status != MFX_ERR_MORE_SURFACE)
      goto vpp_error;

    /* No output generated */
    if (status == MFX_ERR_MORE_DATA)
      goto error_more_data;

    if (sync_point)
      MFXVideoCORE_SyncOperation (session, sync_point, 10000);

    /* More than one output buffers are generated */
    if (status == MFX_ERR_MORE_SURFACE) {
      GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
      GST_BUFFER_DURATION (outbuf) = thiz->buffer_duration;
      timestamp += thiz->buffer_duration;
      ret = gst_pad_push (GST_BASE_TRANSFORM_SRC_PAD (trans), outbuf);
      if (ret != GST_FLOW_OK)
        goto error_push_buffer;
      outbuf = create_output_buffer (thiz);
    } else {
      GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
      GST_BUFFER_DURATION (outbuf) = thiz->buffer_duration;
    }
  } while (status == MFX_ERR_MORE_SURFACE);

  free_msdk_surface (in_surface);
  return ret;

vpp_error:
  GST_ERROR_OBJECT (thiz, "MSDK Failed to do VPP");
  free_msdk_surface (in_surface);
  free_msdk_surface (out_surface);
  return GST_FLOW_ERROR;

error_more_data:
  GST_WARNING_OBJECT (thiz,
      "MSDK Requries additional input for processing, "
      "Retruning FLOW_DROPPED since no output buffer was generated");
  free_msdk_surface (in_surface);
  return GST_BASE_TRANSFORM_FLOW_DROPPED;

error_push_buffer:
  {
    free_msdk_surface (in_surface);
    free_msdk_surface (out_surface);
    GST_DEBUG_OBJECT (thiz, "failed to push output buffer: %s",
        gst_flow_get_name (ret));
    return ret;
  }
}
static int qsvscale_filter_frame(AVFilterLink *link, AVFrame *in)
{
    AVFilterContext             *ctx = link->dst;
    QSVScaleContext               *s = ctx->priv;
    AVFilterLink            *outlink = ctx->outputs[0];

    mfxSyncPoint sync = NULL;
    mfxStatus err;

    AVFrame *out = NULL;
    int ret = 0;

    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
    if (!out) {
        ret = AVERROR(ENOMEM);
        goto fail;
    }

    do {
        err = MFXVideoVPP_RunFrameVPPAsync(s->session,
                                           (mfxFrameSurface1*)in->data[3],
                                           (mfxFrameSurface1*)out->data[3],
                                           NULL, &sync);
        if (err == MFX_WRN_DEVICE_BUSY)
            av_usleep(1);
    } while (err == MFX_WRN_DEVICE_BUSY);

    if (err < 0 || !sync) {
        av_log(ctx, AV_LOG_ERROR, "Error during scaling\n");
        ret = AVERROR_UNKNOWN;
        goto fail;
    }

    do {
        err = MFXVideoCORE_SyncOperation(s->session, sync, 1000);
    } while (err == MFX_WRN_IN_EXECUTION);
    if (err < 0) {
        av_log(ctx, AV_LOG_ERROR, "Error synchronizing the operation: %d\n", err);
        ret = AVERROR_UNKNOWN;
        goto fail;
    }

    ret = av_frame_copy_props(out, in);
    if (ret < 0)
        goto fail;

    out->width  = outlink->w;
    out->height = outlink->h;

    av_reduce(&out->sample_aspect_ratio.num, &out->sample_aspect_ratio.den,
              (int64_t)in->sample_aspect_ratio.num * outlink->h * link->w,
              (int64_t)in->sample_aspect_ratio.den * outlink->w * link->h,
              INT_MAX);

    av_frame_free(&in);
    return ff_filter_frame(outlink, out);
fail:
    av_frame_free(&in);
    av_frame_free(&out);
    return ret;
}
Beispiel #4
0
static int qsv_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst,
                                const AVFrame *src)
{
    QSVFramesContext   *s = ctx->internal->priv;
    mfxFrameSurface1   in = {{ 0 }};
    mfxFrameSurface1 *out = (mfxFrameSurface1*)dst->data[3];

    mfxSyncPoint sync = NULL;
    mfxStatus err;
    int ret;

    while (!s->session_upload_init && !s->session_upload && !ret) {
#if HAVE_PTHREADS
        if (pthread_mutex_trylock(&s->session_lock) == 0) {
#endif
            if (!s->session_upload_init) {
                ret = qsv_init_internal_session(ctx, &s->session_upload, 1);
                if (s->session_upload)
                    s->session_upload_init = 1;
            }
#if HAVE_PTHREADS
            pthread_mutex_unlock(&s->session_lock);
            pthread_cond_signal(&s->session_cond);
        } else {
            pthread_mutex_lock(&s->session_lock);
            while (!s->session_upload_init && !s->session_upload) {
                pthread_cond_wait(&s->session_cond, &s->session_lock);
            }
            pthread_mutex_unlock(&s->session_lock);
        }
#endif
    }
    if (ret < 0)
        return ret;

    if (!s->session_upload) {
        if (s->child_frames_ref)
            return qsv_transfer_data_child(ctx, dst, src);

        av_log(ctx, AV_LOG_ERROR, "Surface upload not possible\n");
        return AVERROR(ENOSYS);
    }

    in.Info = out->Info;
    in.Data.PitchLow = src->linesize[0];
    in.Data.Y        = src->data[0];
    in.Data.U        = src->data[1];
    in.Data.V        = src->data[2];
    in.Data.A        = src->data[3];

    do {
        err = MFXVideoVPP_RunFrameVPPAsync(s->session_upload, &in, out, NULL, &sync);
        if (err == MFX_WRN_DEVICE_BUSY)
            av_usleep(1);
    } while (err == MFX_WRN_DEVICE_BUSY);

    if (err < 0 || !sync) {
        av_log(ctx, AV_LOG_ERROR, "Error uploading the surface\n");
        return AVERROR_UNKNOWN;
    }

    do {
        err = MFXVideoCORE_SyncOperation(s->session_upload, sync, 1000);
    } while (err == MFX_WRN_IN_EXECUTION);
    if (err < 0) {
        av_log(ctx, AV_LOG_ERROR, "Error synchronizing the operation\n");
        return AVERROR_UNKNOWN;
    }

    return 0;
}
GstMfxFilterStatus
gst_mfx_filter_process (GstMfxFilter * filter, GstMfxSurface * surface,
    GstMfxSurface ** out_surface)
{
  mfxFrameSurface1 *insurf, *outsurf = NULL;
  mfxSyncPoint syncp;
  mfxStatus sts = MFX_ERR_NONE;
  GstMfxFilterStatus ret = GST_MFX_FILTER_STATUS_SUCCESS;
  gboolean more_surface = FALSE;

  /* Delayed VPP initialization to enable surface pool sharing with
   * encoder plugin */
  if (G_UNLIKELY (!filter->inited)) {
    ret = gst_mfx_filter_start (filter);
    if (ret != GST_MFX_FILTER_STATUS_SUCCESS)
      return ret;
    filter->inited = TRUE;
  }

  insurf = gst_mfx_surface_get_frame_surface (surface);

  do {
    *out_surface = gst_mfx_surface_new_from_pool (filter->vpp_pool[1]);
    if (!*out_surface)
      return GST_MFX_FILTER_STATUS_ERROR_ALLOCATION_FAILED;

    outsurf = gst_mfx_surface_get_frame_surface (*out_surface);
    sts =
        MFXVideoVPP_RunFrameVPPAsync (filter->session, insurf, outsurf, NULL,
        &syncp);

    if (MFX_WRN_INCOMPATIBLE_VIDEO_PARAM == sts)
      sts = MFX_ERR_NONE;

    if (MFX_WRN_DEVICE_BUSY == sts)
      g_usleep (500);
  } while (MFX_WRN_DEVICE_BUSY == sts);

  if (MFX_ERR_MORE_DATA == sts)
    return GST_MFX_FILTER_STATUS_ERROR_MORE_DATA;

  /* The current frame is ready. Hence treat it
   * as MFX_ERR_NONE and request for more surface
   */
  if (MFX_ERR_MORE_SURFACE == sts) {
    sts = MFX_ERR_NONE;
    more_surface = TRUE;
  }

  if (MFX_ERR_NONE != sts) {
    GST_ERROR ("Error during MFX filter process.");
    return GST_MFX_FILTER_STATUS_ERROR_OPERATION_FAILED;
  }

  if (syncp) {
    if (!gst_mfx_task_has_type (filter->vpp[1], GST_MFX_TASK_ENCODER))
      do {
        sts = MFXVideoCORE_SyncOperation (filter->session, syncp, 1000);
      } while (MFX_WRN_IN_EXECUTION == sts);

    *out_surface =
        gst_mfx_surface_pool_find_surface (filter->vpp_pool[1], outsurf);
  }

  if (more_surface)
    return GST_MFX_FILTER_STATUS_ERROR_MORE_SURFACE;

  return GST_MFX_FILTER_STATUS_SUCCESS;
}