msdkenc: Add support for YV12, YUY2, UYVY and BGRA

By doing conversion with VPP to NV12 before the actual encoding.

https://bugzilla.gnome.org/show_bug.cgi?id=789847
This commit is contained in:
Sebastian Dröge 2017-11-16 11:32:52 +02:00
parent 0ef2a41d84
commit d3eeb98f0c
3 changed files with 398 additions and 68 deletions

View file

@ -72,7 +72,7 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_SINK,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw, " GST_STATIC_CAPS ("video/x-raw, "
"format = (string) { NV12 }, " "format = (string) { NV12, I420, YV12, YUY2, UYVY, BGRA }, "
"framerate = (fraction) [0, MAX], " "framerate = (fraction) [0, MAX], "
"width = (int) [ 16, MAX ], height = (int) [ 16, MAX ]," "width = (int) [ 16, MAX ], height = (int) [ 16, MAX ],"
"interlace-mode = (string) progressive") "interlace-mode = (string) progressive")
@ -140,6 +140,65 @@ 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;
}
}
}
static gboolean static gboolean
gst_msdkenc_init_encoder (GstMsdkEnc * thiz) gst_msdkenc_init_encoder (GstMsdkEnc * thiz)
{ {
@ -147,7 +206,7 @@ gst_msdkenc_init_encoder (GstMsdkEnc * thiz)
GstVideoInfo *info; GstVideoInfo *info;
mfxSession session; mfxSession session;
mfxStatus status; mfxStatus status;
mfxFrameAllocRequest request; mfxFrameAllocRequest request[2];
guint i; guint i;
if (!thiz->input_state) { if (!thiz->input_state) {
@ -166,6 +225,104 @@ gst_msdkenc_init_encoder (GstMsdkEnc * thiz)
} }
GST_OBJECT_LOCK (thiz); GST_OBJECT_LOCK (thiz);
session = msdk_context_get_session (thiz->context);
thiz->has_vpp = FALSE;
if (info->finfo->format != GST_VIDEO_FORMAT_NV12) {
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);
thiz->vpp_param.vpp.In.CropW = info->width;
thiz->vpp_param.vpp.In.CropH = info->height;
thiz->vpp_param.vpp.In.FrameRateExtN = info->fps_n;
thiz->vpp_param.vpp.In.FrameRateExtD = info->fps_d;
thiz->vpp_param.vpp.In.AspectRatioW = info->par_n;
thiz->vpp_param.vpp.In.AspectRatioH = info->par_d;
thiz->vpp_param.vpp.In.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
switch (info->finfo->format) {
case GST_VIDEO_FORMAT_NV12:
thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_NV12;
thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
break;
case GST_VIDEO_FORMAT_YV12:
case GST_VIDEO_FORMAT_I420:
thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_YV12;
thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
break;
case GST_VIDEO_FORMAT_YUY2:
thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_YUY2;
thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
break;
case GST_VIDEO_FORMAT_UYVY:
thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_UYVY;
thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
break;
case GST_VIDEO_FORMAT_BGRA:
thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_RGB4;
thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
break;
default:
g_assert_not_reached ();
break;
}
thiz->vpp_param.vpp.Out = thiz->vpp_param.vpp.In;
thiz->vpp_param.vpp.Out.FourCC = MFX_FOURCC_NV12;
thiz->vpp_param.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
/* validate parameters and allow the Media SDK to make adjustments */
status = MFXVideoVPP_Query (session, &thiz->vpp_param, &thiz->vpp_param);
if (status < MFX_ERR_NONE) {
GST_ERROR_OBJECT (thiz, "Video VPP Query failed (%s)",
msdk_status_to_string (status));
goto no_vpp;
} else if (status > MFX_ERR_NONE) {
GST_WARNING_OBJECT (thiz, "Video VPP Query returned: %s",
msdk_status_to_string (status));
}
status = MFXVideoVPP_QueryIOSurf (session, &thiz->vpp_param, request);
if (status < MFX_ERR_NONE) {
GST_ERROR_OBJECT (thiz, "VPP Query IO surfaces failed (%s)",
msdk_status_to_string (status));
goto no_vpp;
} else if (status > MFX_ERR_NONE) {
GST_WARNING_OBJECT (thiz, "VPP Query IO surfaces returned: %s",
msdk_status_to_string (status));
}
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));
}
status = MFXVideoVPP_Init (session, &thiz->vpp_param);
if (status < MFX_ERR_NONE) {
GST_ERROR_OBJECT (thiz, "Init failed (%s)",
msdk_status_to_string (status));
goto no_vpp;
} else if (status > MFX_ERR_NONE) {
GST_WARNING_OBJECT (thiz, "Init returned: %s",
msdk_status_to_string (status));
}
status = MFXVideoVPP_GetVideoParam (session, &thiz->vpp_param);
if (status < MFX_ERR_NONE) {
GST_ERROR_OBJECT (thiz, "Get VPP Parameters failed (%s)",
msdk_status_to_string (status));
MFXVideoVPP_Close (session);
goto no_vpp;
} else if (status > MFX_ERR_NONE) {
GST_WARNING_OBJECT (thiz, "Get VPP Parameters returned: %s",
msdk_status_to_string (status));
}
thiz->has_vpp = TRUE;
}
thiz->param.AsyncDepth = thiz->async_depth; thiz->param.AsyncDepth = thiz->async_depth;
thiz->param.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY; thiz->param.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
@ -196,7 +353,6 @@ gst_msdkenc_init_encoder (GstMsdkEnc * thiz)
thiz->param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; thiz->param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12; thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12;
thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420; thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
thiz->param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
/* allow subclass configure further */ /* allow subclass configure further */
if (klass->configure) { if (klass->configure) {
@ -209,7 +365,6 @@ gst_msdkenc_init_encoder (GstMsdkEnc * thiz)
thiz->param.ExtParam = thiz->extra_params; thiz->param.ExtParam = thiz->extra_params;
} }
session = msdk_context_get_session (thiz->context);
/* validate parameters and allow the Media SDK to make adjustments */ /* validate parameters and allow the Media SDK to make adjustments */
status = MFXVideoENCODE_Query (session, &thiz->param, &thiz->param); status = MFXVideoENCODE_Query (session, &thiz->param, &thiz->param);
if (status < MFX_ERR_NONE) { if (status < MFX_ERR_NONE) {
@ -221,54 +376,51 @@ gst_msdkenc_init_encoder (GstMsdkEnc * thiz)
msdk_status_to_string (status)); msdk_status_to_string (status));
} }
status = MFXVideoENCODE_QueryIOSurf (session, &thiz->param, &request); status = MFXVideoENCODE_QueryIOSurf (session, &thiz->param, request);
if (status < MFX_ERR_NONE) { if (status < MFX_ERR_NONE) {
GST_ERROR_OBJECT (thiz, "Query IO surfaces failed (%s)", GST_ERROR_OBJECT (thiz, "Encode Query IO surfaces failed (%s)",
msdk_status_to_string (status)); msdk_status_to_string (status));
goto failed; goto failed;
} else if (status > MFX_ERR_NONE) { } else if (status > MFX_ERR_NONE) {
GST_WARNING_OBJECT (thiz, "Query IO surfaces returned: %s", GST_WARNING_OBJECT (thiz, "Encode Query IO surfaces returned: %s",
msdk_status_to_string (status)); msdk_status_to_string (status));
} }
if (request.NumFrameSuggested < thiz->param.AsyncDepth) { /* Maximum of VPP output and encoder input, if using VPP */
if (thiz->has_vpp)
request[0].NumFrameSuggested =
MAX (request[0].NumFrameSuggested, request[1].NumFrameSuggested);
if (request[0].NumFrameSuggested < thiz->param.AsyncDepth) {
GST_ERROR_OBJECT (thiz, "Required %d surfaces (%d suggested), async %d", GST_ERROR_OBJECT (thiz, "Required %d surfaces (%d suggested), async %d",
request.NumFrameMin, request.NumFrameSuggested, thiz->param.AsyncDepth); request[0].NumFrameMin, request[0].NumFrameSuggested,
thiz->param.AsyncDepth);
goto failed; goto failed;
} }
thiz->num_surfaces = request.NumFrameSuggested; /* These are VPP output (if any) and encoder input */
thiz->num_surfaces = request[0].NumFrameSuggested;
thiz->surfaces = g_new0 (mfxFrameSurface1, thiz->num_surfaces); thiz->surfaces = g_new0 (mfxFrameSurface1, thiz->num_surfaces);
for (i = 0; i < thiz->num_surfaces; i++) { for (i = 0; i < thiz->num_surfaces; i++) {
memcpy (&thiz->surfaces[i].Info, &thiz->param.mfx.FrameInfo, memcpy (&thiz->surfaces[i].Info, &thiz->param.mfx.FrameInfo,
sizeof (mfxFrameInfo)); sizeof (mfxFrameInfo));
} }
if (GST_ROUND_UP_32 (info->width) != info->width
|| GST_ROUND_UP_32 (info->height) != info->height) {
guint width = GST_ROUND_UP_32 (info->width);
guint height = GST_ROUND_UP_32 (info->height);
gsize Y_size = width * height;
gsize size = Y_size + (Y_size >> 1);
for (i = 0; i < thiz->num_surfaces; i++) {
mfxFrameSurface1 *surface = &thiz->surfaces[i];
mfxU8 *data = _aligned_alloc (32, size);
if (!data) {
GST_ERROR_OBJECT (thiz, "Memory allocation failed");
goto failed;
}
surface->Data.MemId = (mfxMemId) data;
surface->Data.Pitch = width;
surface->Data.Y = data;
surface->Data.UV = data + Y_size;
}
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, GST_DEBUG_OBJECT (thiz,
"Allocated aligned memory, pixel data will be copied"); "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", GST_DEBUG_OBJECT (thiz, "Required %d surfaces (%d suggested), allocated %d",
request.NumFrameMin, request.NumFrameSuggested, thiz->num_surfaces); request[0].NumFrameMin, request[0].NumFrameSuggested, thiz->num_surfaces);
status = MFXVideoENCODE_Init (session, &thiz->param); status = MFXVideoENCODE_Init (session, &thiz->param);
if (status < MFX_ERR_NONE) { if (status < MFX_ERR_NONE) {
@ -309,6 +461,7 @@ gst_msdkenc_init_encoder (GstMsdkEnc * thiz)
return TRUE; return TRUE;
no_vpp:
failed: failed:
GST_OBJECT_UNLOCK (thiz); GST_OBJECT_UNLOCK (thiz);
msdk_close_context (thiz->context); msdk_close_context (thiz->context);
@ -344,6 +497,16 @@ gst_msdkenc_close_encoder (GstMsdkEnc * thiz)
g_free (thiz->tasks); g_free (thiz->tasks);
thiz->tasks = NULL; thiz->tasks = NULL;
/* Close VPP before freeing the surfaces. They are shared between encoder
* and VPP */
if (thiz->has_vpp) {
status = MFXVideoVPP_Close (msdk_context_get_session (thiz->context));
if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
GST_WARNING_OBJECT (thiz, "VPP close failed (%s)",
msdk_status_to_string (status));
}
}
for (i = 0; i < thiz->num_surfaces; i++) { for (i = 0; i < thiz->num_surfaces; i++) {
mfxFrameSurface1 *surface = &thiz->surfaces[i]; mfxFrameSurface1 *surface = &thiz->surfaces[i];
if (surface->Data.MemId) if (surface->Data.MemId)
@ -352,6 +515,16 @@ gst_msdkenc_close_encoder (GstMsdkEnc * thiz)
g_free (thiz->surfaces); g_free (thiz->surfaces);
thiz->surfaces = NULL; 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;
}
msdk_close_context (thiz->context); msdk_close_context (thiz->context);
thiz->context = NULL; thiz->context = NULL;
memset (&thiz->param, 0, sizeof (thiz->param)); memset (&thiz->param, 0, sizeof (thiz->param));
@ -394,7 +567,8 @@ gst_msdkenc_dequeue_frame (GstMsdkEnc * thiz, GstVideoCodecFrame * frame)
if (fdata->frame != frame) if (fdata->frame != frame)
continue; continue;
gst_video_frame_unmap (&fdata->vframe); if (fdata->vframe.buffer)
gst_video_frame_unmap (&fdata->vframe);
gst_video_codec_frame_unref (fdata->frame); gst_video_codec_frame_unref (fdata->frame);
g_slice_free (FrameData, fdata); g_slice_free (FrameData, fdata);
@ -519,7 +693,7 @@ gst_msdkenc_encode_frame (GstMsdkEnc * thiz, mfxFrameSurface1 * surface,
if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) { if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) {
GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Encode frame failed."), GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Encode frame failed."),
("MSDK encode return code=%d", status)); ("MSDK encode error (%s)", msdk_status_to_string (status)));
gst_msdkenc_dequeue_frame (thiz, input_frame); gst_msdkenc_dequeue_frame (thiz, input_frame);
gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), input_frame); gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), input_frame);
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
@ -654,20 +828,75 @@ gst_msdkenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
if (G_UNLIKELY (thiz->context == NULL)) if (G_UNLIKELY (thiz->context == NULL))
goto not_inited; goto not_inited;
surface = msdk_get_free_surface (thiz->surfaces, thiz->num_surfaces); if (thiz->has_vpp) {
if (!surface) mfxFrameSurface1 *vpp_surface;
goto invalid_surface; GstVideoFrame vframe;
mfxSession session;
mfxSyncPoint vpp_sync_point = NULL;
mfxStatus status;
fdata = gst_msdkenc_queue_frame (thiz, frame, info); vpp_surface =
if (!fdata) msdk_get_free_surface (thiz->vpp_surfaces, thiz->num_vpp_surfaces);
goto invalid_frame; if (!vpp_surface)
goto invalid_surface;
surface = msdk_get_free_surface (thiz->surfaces, thiz->num_surfaces);
if (!surface)
goto invalid_surface;
msdk_frame_to_surface (&fdata->vframe, surface); if (!gst_video_frame_map (&vframe, info, frame->input_buffer, GST_MAP_READ))
if (frame->pts != GST_CLOCK_TIME_NONE) { goto invalid_frame;
surface->Data.TimeStamp =
gst_util_uint64_scale (frame->pts, 90000, GST_SECOND); msdk_frame_to_surface (&vframe, vpp_surface);
if (frame->pts != GST_CLOCK_TIME_NONE) {
vpp_surface->Data.TimeStamp =
gst_util_uint64_scale (frame->pts, 90000, GST_SECOND);
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;
}
session = msdk_context_get_session (thiz->context);
for (;;) {
status =
MFXVideoVPP_RunFrameVPPAsync (session, vpp_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 */
g_usleep (1000);
};
gst_video_frame_unmap (&vframe);
if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) {
GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Converting frame failed."),
("MSDK VPP error (%s)", msdk_status_to_string (status)));
gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), frame);
return GST_FLOW_ERROR;
}
fdata = g_slice_new0 (FrameData);
fdata->frame = gst_video_codec_frame_ref (frame);
thiz->pending_frames = g_list_prepend (thiz->pending_frames, fdata);
} else { } else {
surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN; surface = msdk_get_free_surface (thiz->surfaces, thiz->num_surfaces);
if (!surface)
goto invalid_surface;
fdata = gst_msdkenc_queue_frame (thiz, frame, info);
if (!fdata)
goto invalid_frame;
msdk_frame_to_surface (&fdata->vframe, surface);
if (frame->pts != GST_CLOCK_TIME_NONE) {
surface->Data.TimeStamp =
gst_util_uint64_scale (frame->pts, 90000, GST_SECOND);
} else {
surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
}
} }
return gst_msdkenc_encode_frame (thiz, surface, frame); return gst_msdkenc_encode_frame (thiz, surface, frame);

View file

@ -77,6 +77,12 @@ struct _GstMsdkEnc
MsdkEncTask *tasks; MsdkEncTask *tasks;
guint next_task; guint next_task;
gboolean has_vpp;
mfxVideoParam vpp_param;
guint num_vpp_surfaces;
/* Input interfaces, output above */
mfxFrameSurface1 *vpp_surfaces;
mfxExtBuffer *extra_params[MAX_EXTRA_PARAMS]; mfxExtBuffer *extra_params[MAX_EXTRA_PARAMS];
guint num_extra_params; guint num_extra_params;

View file

@ -77,39 +77,134 @@ msdk_frame_to_surface (GstVideoFrame * frame, mfxFrameSurface1 * surface)
guint8 *src, *dst; guint8 *src, *dst;
guint sstride, dstride; guint sstride, dstride;
guint width, height; guint width, height;
guint i; guint i, p;
if (!surface->Data.MemId) { if (!surface->Data.MemId) {
surface->Data.Y = GST_VIDEO_FRAME_COMP_DATA (frame, 0); switch (frame->info.finfo->format) {
surface->Data.UV = GST_VIDEO_FRAME_COMP_DATA (frame, 1); case GST_VIDEO_FORMAT_NV12:
surface->Data.Pitch = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); surface->Data.Y = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
surface->Data.UV = GST_VIDEO_FRAME_COMP_DATA (frame, 1);
surface->Data.Pitch = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
break;
case GST_VIDEO_FORMAT_YV12:
case GST_VIDEO_FORMAT_I420:
surface->Data.Y = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
surface->Data.U = GST_VIDEO_FRAME_COMP_DATA (frame, 1);
surface->Data.V = GST_VIDEO_FRAME_COMP_DATA (frame, 2);
surface->Data.Pitch = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
break;
case GST_VIDEO_FORMAT_YUY2:
case GST_VIDEO_FORMAT_UYVY:
surface->Data.Y = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
surface->Data.Pitch = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
break;
case GST_VIDEO_FORMAT_BGRA:
surface->Data.R = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
surface->Data.Pitch = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
break;
default:
g_assert_not_reached ();
break;
}
return; return;
} }
/* Y Plane */
width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0);
height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0);
src = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
sstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
dst = surface->Data.Y;
dstride = surface->Data.Pitch;
for (i = 0; i < height; i++) { switch (frame->info.finfo->format) {
memcpy (dst, src, width); case GST_VIDEO_FORMAT_NV12:
src += sstride; width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0);
dst += dstride; for (p = 0; p < 2; p++) {
} height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, p);
src = GST_VIDEO_FRAME_COMP_DATA (frame, p);
sstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, p);
dst = p == 0 ? surface->Data.Y : surface->Data.UV;
dstride = surface->Data.Pitch;
/* UV Plane */ for (i = 0; i < height; i++) {
height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1); memcpy (dst, src, width);
src = GST_VIDEO_FRAME_COMP_DATA (frame, 1); src += sstride;
sstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); dst += dstride;
dst = surface->Data.UV; }
}
break;
for (i = 0; i < height; i++) { case GST_VIDEO_FORMAT_YV12:
memcpy (dst, src, width); case GST_VIDEO_FORMAT_I420:
src += sstride; for (p = 0; p < 3; p++) {
dst += dstride; width = GST_VIDEO_FRAME_COMP_WIDTH (frame, p);
height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, p);
src = GST_VIDEO_FRAME_COMP_DATA (frame, p);
sstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, p);
switch (p) {
case 0:
dst = surface->Data.Y;
break;
case 1:
dst = surface->Data.U;
break;
case 2:
dst = surface->Data.V;
break;
default:
g_assert_not_reached ();
break;
}
dstride = surface->Data.Pitch;
if (p > 0)
dstride = dstride / 2;
for (i = 0; i < height; i++) {
memcpy (dst, src, width);
src += sstride;
dst += dstride;
}
}
break;
case GST_VIDEO_FORMAT_YUY2:
case GST_VIDEO_FORMAT_UYVY:
width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0);
height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0);
src = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
sstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
dst = surface->Data.Y;
dstride = surface->Data.Pitch;
width *= 2;
width = MIN (sstride, width);
for (i = 0; i < height; i++) {
memcpy (dst, src, width);
src += sstride;
dst += dstride;
}
break;
case GST_VIDEO_FORMAT_BGRA:
width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0);
height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0);
src = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
sstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
dst = surface->Data.R;
dstride = surface->Data.Pitch;
width *= 4;
for (i = 0; i < height; i++) {
memcpy (dst, src, width);
src += sstride;
dst += dstride;
}
break;
default:
g_assert_not_reached ();
break;
} }
} }