diff options
author | Hyunjun Ko <zzoon@igalia.com> | 2018-02-13 13:48:32 -0900 |
---|---|---|
committer | Sreerenj Balachandran <sreerenj.balachandran@intel.com> | 2018-02-13 13:48:32 -0900 |
commit | 580a52ec4971c70f90df088f5c0b3fff9be3c639 (patch) | |
tree | 24bc580679296b4ec97abbd22bda33f22dffb13a | |
parent | 2542b2d34da53f44b259780acba19907aab3e04d (diff) | |
download | gstreamer-plugins-bad-580a52ec4971c70f90df088f5c0b3fff9be3c639.tar.gz |
msdkenc: use bufferpool
1\ Proposes msdk bufferpool to upstream.
- If upstream has accepted the proposed msdk bufferpool,
encoder can get msdk surface from the buffer directly.
- If not, encoder get msdk surface its own msdk bufferpool
and copy from upstream's frame to the surface.
2\ Replace arrays of surfaces with msdk bufferpool.
3\ In case of using VPP, there should be another msdk bufferpool
with NV12 info so that it could convert first and encode.
Calls gst_msdk_set_frame_allocator and uses video memory only on linux.
and uses system memory on Windows until d3d allocator is implemented.
https://bugzilla.gnome.org/show_bug.cgi?id=790752
-rw-r--r-- | sys/msdk/gstmsdkenc.c | 491 | ||||
-rw-r--r-- | sys/msdk/gstmsdkenc.h | 9 | ||||
-rw-r--r-- | sys/msdk/msdk.c | 31 | ||||
-rw-r--r-- | sys/msdk/msdk.h | 6 |
4 files changed, 382 insertions, 155 deletions
diff --git a/sys/msdk/gstmsdkenc.c b/sys/msdk/gstmsdkenc.c index aebd40550..45fe20ea1 100644 --- a/sys/msdk/gstmsdkenc.c +++ b/sys/msdk/gstmsdkenc.c @@ -45,6 +45,10 @@ #include <stdlib.h> #include "gstmsdkenc.h" +#include "gstmsdkbufferpool.h" +#include "gstmsdkvideomemory.h" +#include "gstmsdksystemmemory.h" +#include "gstmsdkallocator.h" static inline void * _aligned_alloc (size_t alignment, size_t size) @@ -131,6 +135,12 @@ gst_msdkenc_rate_control_get_type (void) #define gst_msdkenc_parent_class parent_class G_DEFINE_TYPE (GstMsdkEnc, gst_msdkenc, GST_TYPE_VIDEO_ENCODER); +typedef struct +{ + mfxFrameSurface1 *surface; + GstBuffer *buf; +} MsdkSurface; + void gst_msdkenc_add_extra_param (GstMsdkEnc * thiz, mfxExtBuffer * param) { @@ -140,78 +150,6 @@ gst_msdkenc_add_extra_param (GstMsdkEnc * thiz, mfxExtBuffer * param) } } -static void -gst_msdkenc_alloc_surfaces (GstMsdkEnc * thiz, GstVideoFormat format, - gint width, gint height, guint num_surfaces, mfxFrameSurface1 * surfaces) -{ - gsize Y_size = 0, U_size = 0; - gsize pitch; - gsize size; - gint i; - - width = GST_ROUND_UP_32 (width); - height = GST_ROUND_UP_32 (height); - - switch (format) { - case GST_VIDEO_FORMAT_NV12: - Y_size = width * height; - pitch = width; - size = Y_size + (Y_size >> 1); - break; - case GST_VIDEO_FORMAT_YV12: - case GST_VIDEO_FORMAT_I420: - Y_size = width * height; - pitch = width; - U_size = (width / 2) * (height / 2); - size = Y_size + 2 * U_size; - break; - case GST_VIDEO_FORMAT_YUY2: - case GST_VIDEO_FORMAT_UYVY: - size = 2 * width * height; - pitch = 2 * width; - break; - case GST_VIDEO_FORMAT_BGRA: - size = 4 * width * height; - pitch = 4 * width; - break; - default: - g_assert_not_reached (); - break; - } - - for (i = 0; i < num_surfaces; i++) { - mfxFrameSurface1 *surface = &surfaces[i]; - mfxU8 *data = _aligned_alloc (32, size); - if (!data) { - GST_ERROR_OBJECT (thiz, "Memory allocation failed"); - return; - } - - surface->Data.MemId = (mfxMemId) data; - surface->Data.Pitch = pitch; - surface->Data.Y = data; - if (U_size) { - surface->Data.U = data + Y_size; - surface->Data.V = data + Y_size + U_size; - } else if (Y_size) { - surface->Data.UV = data + Y_size; - } - - if (format == GST_VIDEO_FORMAT_YUY2) { - surface->Data.U = data + 1; - surface->Data.V = data + 3; - } else if (format == GST_VIDEO_FORMAT_UYVY) { - surface->Data.U = data + 1; - surface->Data.Y = data + 2; - surface->Data.V = data + 3; - } else if (format == GST_VIDEO_FORMAT_BGRA) { - surface->Data.R = data; - surface->Data.G = data + 1; - surface->Data.B = data + 2; - } - } -} - static gboolean gst_msdkenc_init_encoder (GstMsdkEnc * thiz) { @@ -241,9 +179,16 @@ gst_msdkenc_init_encoder (GstMsdkEnc * thiz) session = gst_msdk_context_get_session (thiz->context); thiz->has_vpp = FALSE; + if (thiz->use_video_memory) + gst_msdk_set_frame_allocator (thiz->context); + if (info->finfo->format != GST_VIDEO_FORMAT_NV12) { - thiz->vpp_param.IOPattern = - MFX_IOPATTERN_IN_SYSTEM_MEMORY | MFX_IOPATTERN_OUT_SYSTEM_MEMORY; + if (thiz->use_video_memory) + thiz->vpp_param.IOPattern = + MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY; + else + thiz->vpp_param.IOPattern = + MFX_IOPATTERN_IN_SYSTEM_MEMORY | MFX_IOPATTERN_OUT_SYSTEM_MEMORY; thiz->vpp_param.vpp.In.Width = GST_ROUND_UP_32 (info->width); thiz->vpp_param.vpp.In.Height = GST_ROUND_UP_32 (info->height); @@ -307,11 +252,10 @@ gst_msdkenc_init_encoder (GstMsdkEnc * thiz) } thiz->num_vpp_surfaces = request[0].NumFrameSuggested; - thiz->vpp_surfaces = g_new0 (mfxFrameSurface1, thiz->num_vpp_surfaces); - for (i = 0; i < thiz->num_vpp_surfaces; i++) { - memcpy (&thiz->vpp_surfaces[i].Info, &thiz->vpp_param.vpp.In, - sizeof (mfxFrameInfo)); - } + + if (thiz->use_video_memory) + gst_msdk_frame_alloc (thiz->context, &(request[0]), + &thiz->vpp_alloc_resp); status = MFXVideoVPP_Init (session, &thiz->vpp_param); if (status < MFX_ERR_NONE) { @@ -338,7 +282,10 @@ gst_msdkenc_init_encoder (GstMsdkEnc * thiz) } thiz->param.AsyncDepth = thiz->async_depth; - thiz->param.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY; + if (thiz->use_video_memory) + thiz->param.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY; + else + thiz->param.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY; thiz->param.mfx.RateControlMethod = thiz->rate_control; thiz->param.mfx.TargetKbps = thiz->bitrate; @@ -399,6 +346,9 @@ gst_msdkenc_init_encoder (GstMsdkEnc * thiz) msdk_status_to_string (status)); } + if (thiz->use_video_memory) + gst_msdk_frame_alloc (thiz->context, &(request[0]), &thiz->alloc_resp); + /* Maximum of VPP output and encoder input, if using VPP */ if (thiz->has_vpp) request[0].NumFrameSuggested = @@ -410,27 +360,8 @@ gst_msdkenc_init_encoder (GstMsdkEnc * thiz) goto failed; } - /* These are VPP output (if any) and encoder input */ + /* This is VPP output (if any) and encoder input */ thiz->num_surfaces = request[0].NumFrameSuggested; - thiz->surfaces = g_new0 (mfxFrameSurface1, thiz->num_surfaces); - for (i = 0; i < thiz->num_surfaces; i++) { - memcpy (&thiz->surfaces[i].Info, &thiz->param.mfx.FrameInfo, - sizeof (mfxFrameInfo)); - } - - if ((GST_ROUND_UP_32 (info->width) != info->width - || GST_ROUND_UP_32 (info->height) != info->height)) { - gst_msdkenc_alloc_surfaces (thiz, info->finfo->format, info->width, - info->height, - thiz->has_vpp ? thiz->num_vpp_surfaces : thiz->num_surfaces, - thiz->has_vpp ? thiz->vpp_surfaces : thiz->surfaces); - GST_DEBUG_OBJECT (thiz, - "Allocated aligned memory, pixel data will be copied"); - } - if (thiz->has_vpp) { - gst_msdkenc_alloc_surfaces (thiz, GST_VIDEO_FORMAT_NV12, info->width, - info->height, thiz->num_surfaces, thiz->surfaces); - } GST_DEBUG_OBJECT (thiz, "Required %d surfaces (%d suggested), allocated %d", request[0].NumFrameMin, request[0].NumFrameSuggested, thiz->num_surfaces); @@ -493,6 +424,12 @@ gst_msdkenc_close_encoder (GstMsdkEnc * thiz) GST_DEBUG_OBJECT (thiz, "Closing encoder 0x%p", thiz->context); + gst_object_replace ((GstObject **) & thiz->msdk_pool, NULL); + gst_object_replace ((GstObject **) & thiz->msdk_converted_pool, NULL); + + if (thiz->use_video_memory) + gst_msdk_frame_free (thiz->context, &thiz->alloc_resp); + status = MFXVideoENCODE_Close (gst_msdk_context_get_session (thiz->context)); if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) { GST_WARNING_OBJECT (thiz, "Encoder close failed (%s)", @@ -513,6 +450,9 @@ gst_msdkenc_close_encoder (GstMsdkEnc * thiz) /* Close VPP before freeing the surfaces. They are shared between encoder * and VPP */ if (thiz->has_vpp) { + if (thiz->use_video_memory) + gst_msdk_frame_free (thiz->context, &thiz->vpp_alloc_resp); + status = MFXVideoVPP_Close (gst_msdk_context_get_session (thiz->context)); if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) { GST_WARNING_OBJECT (thiz, "VPP close failed (%s)", @@ -520,24 +460,6 @@ gst_msdkenc_close_encoder (GstMsdkEnc * thiz) } } - for (i = 0; i < thiz->num_surfaces; i++) { - mfxFrameSurface1 *surface = &thiz->surfaces[i]; - if (surface->Data.MemId) - _aligned_free (surface->Data.MemId); - } - g_free (thiz->surfaces); - thiz->surfaces = NULL; - - if (thiz->has_vpp) { - for (i = 0; i < thiz->num_vpp_surfaces; i++) { - mfxFrameSurface1 *surface = &thiz->vpp_surfaces[i]; - if (surface->Data.MemId) - _aligned_free (surface->Data.MemId); - } - g_free (thiz->vpp_surfaces); - thiz->vpp_surfaces = NULL; - } - if (thiz->context) gst_object_replace ((GstObject **) & thiz->context, NULL); @@ -548,28 +470,56 @@ gst_msdkenc_close_encoder (GstMsdkEnc * thiz) typedef struct { GstVideoCodecFrame *frame; - GstVideoFrame vframe; + MsdkSurface *frame_surface; + MsdkSurface *converted_surface; } FrameData; static FrameData * gst_msdkenc_queue_frame (GstMsdkEnc * thiz, GstVideoCodecFrame * frame, GstVideoInfo * info) { - GstVideoFrame vframe; FrameData *fdata; - if (!gst_video_frame_map (&vframe, info, frame->input_buffer, GST_MAP_READ)) - return NULL; - fdata = g_slice_new (FrameData); fdata->frame = gst_video_codec_frame_ref (frame); - fdata->vframe = vframe; thiz->pending_frames = g_list_prepend (thiz->pending_frames, fdata); return fdata; } +static MsdkSurface * +gst_msdkenc_create_surface (mfxFrameSurface1 * surface, GstBuffer * buf) +{ + MsdkSurface *msdk_surface; + msdk_surface = g_slice_new0 (MsdkSurface); + msdk_surface->surface = surface; + msdk_surface->buf = buf; + + return msdk_surface; +} + +static void +gst_msdkenc_free_surface (MsdkSurface * surface) +{ + if (surface->buf) + gst_buffer_unref (surface->buf); + + g_slice_free (MsdkSurface, surface); +} + +static void +gst_msdkenc_free_frame_data (GstMsdkEnc * thiz, FrameData * fdata) +{ + if (fdata->frame_surface) + gst_msdkenc_free_surface (fdata->frame_surface); + if (thiz->has_vpp) + gst_msdkenc_free_surface (fdata->converted_surface); + + gst_video_codec_frame_unref (fdata->frame); + g_slice_free (FrameData, fdata); +} + static void gst_msdkenc_dequeue_frame (GstMsdkEnc * thiz, GstVideoCodecFrame * frame) { @@ -581,10 +531,7 @@ gst_msdkenc_dequeue_frame (GstMsdkEnc * thiz, GstVideoCodecFrame * frame) if (fdata->frame != frame) continue; - if (fdata->vframe.buffer) - gst_video_frame_unmap (&fdata->vframe); - gst_video_codec_frame_unref (fdata->frame); - g_slice_free (FrameData, fdata); + gst_msdkenc_free_frame_data (thiz, fdata); thiz->pending_frames = g_list_delete_link (thiz->pending_frames, l); return; @@ -599,9 +546,7 @@ gst_msdkenc_dequeue_all_frames (GstMsdkEnc * thiz) for (l = thiz->pending_frames; l; l = l->next) { FrameData *fdata = l->data; - gst_video_frame_unmap (&fdata->vframe); - gst_video_codec_frame_unref (fdata->frame); - g_slice_free (FrameData, fdata); + gst_msdkenc_free_frame_data (thiz, fdata); } g_list_free (thiz->pending_frames); thiz->pending_frames = NULL; @@ -821,6 +766,82 @@ gst_msdkenc_set_src_caps (GstMsdkEnc * thiz) return TRUE; } +static GstBufferPool * +gst_msdkenc_create_buffer_pool (GstMsdkEnc * thiz, GstCaps * caps, + guint num_buffers, gboolean set_align) +{ + GstBufferPool *pool = NULL; + GstStructure *config; + GstAllocator *allocator = NULL; + GstVideoInfo info; + GstVideoAlignment align; + GstAllocationParams params = { 0, 31, 0, 0, }; + mfxFrameAllocResponse *alloc_resp = NULL; + + if (thiz->has_vpp) + alloc_resp = set_align ? &thiz->vpp_alloc_resp : &thiz->alloc_resp; + else + alloc_resp = &thiz->alloc_resp; + + pool = gst_msdk_buffer_pool_new (thiz->context, alloc_resp); + if (!pool) + goto error_no_pool; + + if (!gst_video_info_from_caps (&info, caps)) { + GST_INFO_OBJECT (thiz, "failed to get video info"); + return FALSE; + } + + gst_msdk_set_video_alignment (&info, &align); + gst_video_info_align (&info, &align); + + if (thiz->use_video_memory) + allocator = gst_msdk_video_allocator_new (thiz->context, &info, alloc_resp); + else + allocator = gst_msdk_system_allocator_new (&info); + + if (!allocator) + goto error_no_allocator; + + config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); + gst_buffer_pool_config_set_params (config, caps, info.size, num_buffers, 0); + gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); + gst_buffer_pool_config_add_option (config, + GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT); + + if (thiz->use_video_memory) + gst_buffer_pool_config_add_option (config, + GST_BUFFER_POOL_OPTION_MSDK_USE_VIDEO_MEMORY); + + gst_buffer_pool_config_set_video_alignment (config, &align); + gst_buffer_pool_config_set_allocator (config, allocator, ¶ms); + gst_object_unref (allocator); + + if (!gst_buffer_pool_set_config (pool, config)) + goto error_pool_config; + + if (set_align) + thiz->aligned_info = info; + + return pool; + +error_no_pool: + { + GST_INFO_OBJECT (thiz, "failed to create bufferpool"); + return FALSE; + } +error_no_allocator: + { + GST_INFO_OBJECT (thiz, "failed to create allocator"); + return FALSE; + } +error_pool_config: + { + GST_INFO_OBJECT (thiz, "failed to set config"); + return FALSE; + } +} + static gboolean gst_msdkenc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state) { @@ -833,6 +854,18 @@ gst_msdkenc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state) thiz->input_state = gst_video_codec_state_ref (state); } + /* TODO: Currently d3d allocator is not implemented. + * So encoder uses system memory by default on Windows. + */ +#ifndef _WIN32 + thiz->use_video_memory = TRUE; +#else + thiz->use_video_memory = FALSE; +#endif + + GST_INFO_OBJECT (encoder, "This MSDK encoder uses %s memory", + thiz->use_video_memory ? "video" : "system"); + if (klass->set_format) { if (!klass->set_format (thiz)) return FALSE; @@ -846,18 +879,136 @@ gst_msdkenc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state) return FALSE; } + if (!thiz->msdk_pool) { + guint num_buffers = gst_msdkenc_maximum_delayed_frames (thiz) + 1; + thiz->msdk_pool = + gst_msdkenc_create_buffer_pool (thiz, thiz->input_state->caps, + num_buffers, TRUE); + } + gst_msdkenc_set_latency (thiz); + /* Create another bufferpool if VPP requires */ + if (thiz->has_vpp) { + GstVideoInfo *info = &thiz->input_state->info; + GstVideoInfo nv12_info; + GstCaps *caps; + GstBufferPool *pool = NULL; + + gst_video_info_init (&nv12_info); + gst_video_info_set_format (&nv12_info, GST_VIDEO_FORMAT_NV12, info->width, + info->height); + caps = gst_video_info_to_caps (&nv12_info); + + pool = + gst_msdkenc_create_buffer_pool (thiz, caps, thiz->num_surfaces, FALSE); + + thiz->msdk_converted_pool = pool; + gst_caps_unref (caps); + } + return TRUE; } +static MsdkSurface * +gst_msdkenc_get_surface_from_pool (GstMsdkEnc * thiz, GstBufferPool * pool, + GstBufferPoolAcquireParams * params) +{ + GstBuffer *new_buffer; + mfxFrameSurface1 *new_surface; + MsdkSurface *msdk_surface; + + if (!gst_buffer_pool_is_active (pool) && + !gst_buffer_pool_set_active (pool, TRUE)) { + GST_ERROR_OBJECT (pool, "failed to activate buffer pool"); + return NULL; + } + + if (gst_buffer_pool_acquire_buffer (pool, &new_buffer, params) != GST_FLOW_OK) { + GST_ERROR_OBJECT (pool, "failed to acquire a buffer from pool"); + return NULL; + } + + if (gst_msdk_is_msdk_buffer (new_buffer)) + new_surface = gst_msdk_get_surface_from_buffer (new_buffer); + else { + GST_ERROR_OBJECT (pool, "the acquired memory is not MSDK memory"); + return NULL; + } + + msdk_surface = gst_msdkenc_create_surface (new_surface, new_buffer); + + return msdk_surface; +} + +static MsdkSurface * +gst_msdkenc_get_surface_from_frame (GstMsdkEnc * thiz, + GstVideoCodecFrame * frame) +{ + GstVideoFrame src_frame, out_frame; + MsdkSurface *msdk_surface; + GstBuffer *inbuf; + + inbuf = frame->input_buffer; + if (gst_msdk_is_msdk_buffer (inbuf)) { + msdk_surface = g_slice_new0 (MsdkSurface); + msdk_surface->surface = gst_msdk_get_surface_from_buffer (inbuf); + return msdk_surface; + } + + /* If upstream hasn't accpeted the proposed msdk bufferpool, + * just copy frame to msdk buffer and take a surface from it. + */ + if (!(msdk_surface = + gst_msdkenc_get_surface_from_pool (thiz, thiz->msdk_pool, NULL))) + goto error; + + if (!gst_video_frame_map (&src_frame, &thiz->input_state->info, inbuf, + GST_MAP_READ)) { + GST_ERROR_OBJECT (thiz, "failed to map the frame for source"); + goto error; + } + + if (!gst_video_frame_map (&out_frame, &thiz->aligned_info, msdk_surface->buf, + GST_MAP_WRITE)) { + GST_ERROR_OBJECT (thiz, "failed to map the frame for destination"); + gst_video_frame_unmap (&src_frame); + goto error; + } + + if (!gst_video_frame_copy (&out_frame, &src_frame)) { + GST_ERROR_OBJECT (thiz, "failed to copy frame"); + gst_video_frame_unmap (&out_frame); + gst_video_frame_unmap (&src_frame); + goto error; + } + + gst_video_frame_unmap (&out_frame); + gst_video_frame_unmap (&src_frame); + + gst_buffer_replace (&frame->input_buffer, msdk_surface->buf); + gst_buffer_unref (msdk_surface->buf); + msdk_surface->buf = NULL; + + return msdk_surface; + +error: + if (msdk_surface) { + if (msdk_surface->buf) + gst_buffer_unref (msdk_surface->buf); + g_slice_free (MsdkSurface, msdk_surface); + } + + return NULL; +} + static GstFlowReturn gst_msdkenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame) { GstMsdkEnc *thiz = GST_MSDKENC (encoder); GstVideoInfo *info = &thiz->input_state->info; FrameData *fdata; - mfxFrameSurface1 *surface; + MsdkSurface *surface; if (thiz->reconfig) { gst_msdkenc_flush_frames (thiz, FALSE); @@ -868,39 +1019,39 @@ gst_msdkenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame) goto not_inited; if (thiz->has_vpp) { - mfxFrameSurface1 *vpp_surface; + MsdkSurface *vpp_surface; GstVideoFrame vframe; mfxSession session; mfxSyncPoint vpp_sync_point = NULL; mfxStatus status; - vpp_surface = - msdk_get_free_surface (thiz->vpp_surfaces, thiz->num_vpp_surfaces); + vpp_surface = gst_msdkenc_get_surface_from_frame (thiz, frame); if (!vpp_surface) goto invalid_surface; - surface = msdk_get_free_surface (thiz->surfaces, thiz->num_surfaces); + surface = + gst_msdkenc_get_surface_from_pool (thiz, thiz->msdk_converted_pool, + NULL); if (!surface) goto invalid_surface; if (!gst_video_frame_map (&vframe, info, frame->input_buffer, GST_MAP_READ)) goto invalid_frame; - msdk_frame_to_surface (&vframe, vpp_surface); if (frame->pts != GST_CLOCK_TIME_NONE) { - vpp_surface->Data.TimeStamp = + vpp_surface->surface->Data.TimeStamp = gst_util_uint64_scale (frame->pts, 90000, GST_SECOND); - surface->Data.TimeStamp = + surface->surface->Data.TimeStamp = gst_util_uint64_scale (frame->pts, 90000, GST_SECOND); } else { - vpp_surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN; - surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN; + vpp_surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN; + surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN; } session = gst_msdk_context_get_session (thiz->context); for (;;) { status = - MFXVideoVPP_RunFrameVPPAsync (session, vpp_surface, surface, NULL, - &vpp_sync_point); + MFXVideoVPP_RunFrameVPPAsync (session, vpp_surface->surface, + surface->surface, NULL, &vpp_sync_point); if (status != MFX_WRN_DEVICE_BUSY) break; /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */ @@ -918,10 +1069,12 @@ gst_msdkenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame) fdata = g_slice_new0 (FrameData); fdata->frame = gst_video_codec_frame_ref (frame); + fdata->frame_surface = vpp_surface; + fdata->converted_surface = surface; thiz->pending_frames = g_list_prepend (thiz->pending_frames, fdata); } else { - surface = msdk_get_free_surface (thiz->surfaces, thiz->num_surfaces); + surface = gst_msdkenc_get_surface_from_frame (thiz, frame); if (!surface) goto invalid_surface; @@ -929,16 +1082,17 @@ gst_msdkenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame) if (!fdata) goto invalid_frame; - msdk_frame_to_surface (&fdata->vframe, surface); + fdata->frame_surface = surface; + if (frame->pts != GST_CLOCK_TIME_NONE) { - surface->Data.TimeStamp = + surface->surface->Data.TimeStamp = gst_util_uint64_scale (frame->pts, 90000, GST_SECOND); } else { - surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN; + surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN; } } - return gst_msdkenc_encode_frame (thiz, surface, frame); + return gst_msdkenc_encode_frame (thiz, surface->surface, frame); /* ERRORS */ not_inited: @@ -1013,18 +1167,46 @@ static gboolean gst_msdkenc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query) { GstMsdkEnc *thiz = GST_MSDKENC (encoder); - GstVideoInfo *info; + GstVideoInfo info; + GstBufferPool *pool = NULL; + GstAllocator *allocator = NULL; + GstCaps *caps; guint num_buffers; - gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); - if (!thiz->input_state) return FALSE; - info = &thiz->input_state->info; + gst_query_parse_allocation (query, &caps, NULL); + + if (!caps) { + GST_INFO_OBJECT (encoder, "failed to get caps"); + return FALSE; + } + + if (!gst_video_info_from_caps (&info, caps)) { + GST_INFO_OBJECT (encoder, "failed to get video info"); + return FALSE; + } + num_buffers = gst_msdkenc_maximum_delayed_frames (thiz) + 1; + pool = gst_msdkenc_create_buffer_pool (thiz, caps, num_buffers, TRUE); + + gst_query_add_allocation_pool (query, pool, GST_VIDEO_INFO_SIZE (&info), + num_buffers, 0); + gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); + + if (pool) { + GstStructure *config; + GstAllocationParams params = { 0, 31, 0, 0, }; - gst_query_add_allocation_pool (query, NULL, info->size, num_buffers, 0); + config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); + + if (gst_buffer_pool_config_get_allocator (config, &allocator, NULL)) + gst_query_add_allocation_param (query, allocator, ¶ms); + gst_structure_free (config); + } + + gst_object_unref (pool); return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder, query); @@ -1157,6 +1339,9 @@ gst_msdkenc_finalize (GObject * object) gst_video_codec_state_unref (thiz->input_state); thiz->input_state = NULL; + gst_object_replace ((GstObject **) & thiz->msdk_pool, NULL); + gst_object_replace ((GstObject **) & thiz->msdk_converted_pool, NULL); + G_OBJECT_CLASS (parent_class)->finalize (object); } diff --git a/sys/msdk/gstmsdkenc.h b/sys/msdk/gstmsdkenc.h index 04be395bd..ae4f94c21 100644 --- a/sys/msdk/gstmsdkenc.h +++ b/sys/msdk/gstmsdkenc.h @@ -73,7 +73,6 @@ struct _GstMsdkEnc GstMsdkContext *context; mfxVideoParam param; guint num_surfaces; - mfxFrameSurface1 *surfaces; guint num_tasks; MsdkEncTask *tasks; guint next_task; @@ -82,11 +81,17 @@ struct _GstMsdkEnc mfxVideoParam vpp_param; guint num_vpp_surfaces; /* Input interfaces, output above */ - mfxFrameSurface1 *vpp_surfaces; + mfxFrameAllocResponse vpp_alloc_resp; + mfxFrameAllocResponse alloc_resp; mfxExtBuffer *extra_params[MAX_EXTRA_PARAMS]; guint num_extra_params; + GstBufferPool *msdk_pool; + GstBufferPool *msdk_converted_pool; + GstVideoInfo aligned_info; + gboolean use_video_memory; + /* element properties */ gboolean hardware; diff --git a/sys/msdk/msdk.c b/sys/msdk/msdk.c index 2c621b2b1..962aa58d5 100644 --- a/sys/msdk/msdk.c +++ b/sys/msdk/msdk.c @@ -30,6 +30,8 @@ */ #include "msdk.h" +#include "gstmsdkvideomemory.h" +#include "gstmsdksystemmemory.h" GST_DEBUG_CATEGORY_EXTERN (gst_msdkenc_debug); #define GST_CAT_DEFAULT gst_msdkenc_debug @@ -453,3 +455,32 @@ gst_msdk_set_mfx_frame_info_from_video_info (mfxFrameInfo * mfx_info, return; } + +gboolean +gst_msdk_is_msdk_buffer (GstBuffer * buf) +{ + GstAllocator *allocator; + GstMemory *mem = gst_buffer_peek_memory (buf, 0); + + allocator = GST_MEMORY_CAST (mem)->allocator; + + if (allocator && (GST_IS_MSDK_VIDEO_ALLOCATOR (allocator) || + GST_IS_MSDK_SYSTEM_ALLOCATOR (allocator))) + return TRUE; + else + return FALSE; +} + +mfxFrameSurface1 * +gst_msdk_get_surface_from_buffer (GstBuffer * buf) +{ + GstAllocator *allocator; + GstMemory *mem = gst_buffer_peek_memory (buf, 0); + + allocator = GST_MEMORY_CAST (mem)->allocator; + + if (GST_IS_MSDK_VIDEO_ALLOCATOR (allocator)) + return GST_MSDK_VIDEO_MEMORY_CAST (mem)->surface; + else + return GST_MSDK_SYSTEM_MEMORY_CAST (mem)->surface; +} diff --git a/sys/msdk/msdk.h b/sys/msdk/msdk.h index 0f574c05b..a764f2cfe 100644 --- a/sys/msdk/msdk.h +++ b/sys/msdk/msdk.h @@ -69,6 +69,12 @@ gint gst_msdk_get_mfx_fourcc_from_format (GstVideoFormat format); void gst_msdk_set_mfx_frame_info_from_video_info (mfxFrameInfo * mfx_info, GstVideoInfo * info); +gboolean +gst_msdk_is_msdk_buffer (GstBuffer * buf); + +mfxFrameSurface1 * +gst_msdk_get_surface_from_buffer (GstBuffer * buf); + G_END_DECLS #endif /* __MSDK_H__ */ |