Refactored H264 encoding/decoding

Use YUV primitives now for all H264 operations
This commit is contained in:
akallabeth
2020-10-22 18:11:21 +02:00
committed by akallabeth
parent c67e4df96b
commit 50acf72615
11 changed files with 680 additions and 338 deletions

View File

@@ -76,7 +76,6 @@ struct _VIDEO_PLUGIN
VIDEO_LISTENER_CALLBACK* data_callback;
VideoClientContext* context;
rdpSettings* settings;
BOOL initialized;
};
typedef struct _VIDEO_PLUGIN VIDEO_PLUGIN;
@@ -127,7 +126,6 @@ struct _PresentationContext
UINT64 startTimeStamp;
UINT64 publishOffset;
H264_CONTEXT* h264;
YUV_CONTEXT* yuv;
wStream* currentSample;
UINT64 lastPublishTime, nextPublishTime;
volatile LONG refCounter;
@@ -135,6 +133,7 @@ struct _PresentationContext
VideoSurface* surface;
};
static void PresentationContext_unref(PresentationContext* presentation);
static const char* video_command_name(BYTE cmd)
{
switch (cmd)
@@ -148,28 +147,6 @@ static const char* video_command_name(BYTE cmd)
}
}
static BOOL yuv_to_rgb(PresentationContext* presentation, BYTE* dest)
{
const BYTE* pYUVPoint[3];
H264_CONTEXT* h264 = presentation->h264;
BYTE** ppYUVData;
ppYUVData = h264->pYUVData;
pYUVPoint[0] = ppYUVData[0];
pYUVPoint[1] = ppYUVData[1];
pYUVPoint[2] = ppYUVData[2];
if (!yuv_context_decode(presentation->yuv, pYUVPoint, h264->iStride, PIXEL_FORMAT_BGRX32, dest,
h264->width * 4))
{
WLog_ERR(TAG, "error in yuv_to_rgb conversion");
return FALSE;
}
return TRUE;
}
static void video_client_context_set_geometry(VideoClientContext* video,
GeometryClientContext* geometry)
{
@@ -220,8 +197,7 @@ error_frames:
}
static PresentationContext* PresentationContext_new(VideoClientContext* video, BYTE PresentationId,
UINT32 x, UINT32 y, UINT32 width, UINT32 height,
BOOL disable_threads)
UINT32 x, UINT32 y, UINT32 width, UINT32 height)
{
size_t s;
VideoClientContextPriv* priv = video->priv;
@@ -241,7 +217,7 @@ static PresentationContext* PresentationContext_new(VideoClientContext* video, B
if (!ret->h264)
{
WLog_ERR(TAG, "unable to create a h264 context");
goto error_h264;
goto fail;
}
h264_context_reset(ret->h264, width, height);
@@ -249,44 +225,28 @@ static PresentationContext* PresentationContext_new(VideoClientContext* video, B
if (!ret->currentSample)
{
WLog_ERR(TAG, "unable to create current packet stream");
goto error_currentSample;
goto fail;
}
ret->surfaceData = BufferPool_Take(priv->surfacePool, s);
if (!ret->surfaceData)
{
WLog_ERR(TAG, "unable to allocate surfaceData");
goto error_surfaceData;
goto fail;
}
ret->surface = video->createSurface(video, ret->surfaceData, x, y, width, height);
if (!ret->surface)
{
WLog_ERR(TAG, "unable to create surface");
goto error_surface;
goto fail;
}
ret->yuv = yuv_context_new(FALSE, disable_threads);
if (!ret->yuv)
{
WLog_ERR(TAG, "unable to create YUV decoder");
goto error_yuv;
}
yuv_context_reset(ret->yuv, width, height);
ret->refCounter = 1;
return ret;
error_yuv:
video->deleteSurface(video, ret->surface);
error_surface:
BufferPool_Return(priv->surfacePool, ret->surfaceData);
error_surfaceData:
Stream_Free(ret->currentSample, TRUE);
error_currentSample:
h264_context_free(ret->h264);
error_h264:
free(ret);
fail:
PresentationContext_unref(ret);
return NULL;
}
@@ -298,7 +258,7 @@ static void PresentationContext_unref(PresentationContext* presentation)
if (!presentation)
return;
if (InterlockedDecrement(&presentation->refCounter) != 0)
if (InterlockedDecrement(&presentation->refCounter) > 0)
return;
geometry = presentation->geometry;
@@ -316,7 +276,6 @@ static void PresentationContext_unref(PresentationContext* presentation)
Stream_Free(presentation->currentSample, TRUE);
presentation->video->deleteSurface(presentation->video, presentation->surface);
BufferPool_Return(priv->surfacePool, presentation->surfaceData);
yuv_context_free(presentation->yuv);
free(presentation);
}
@@ -408,8 +367,7 @@ static BOOL video_onMappedGeometryClear(MAPPED_GEOMETRY* geometry)
return TRUE;
}
static UINT video_PresentationRequest(VideoClientContext* video, TSMM_PRESENTATION_REQUEST* req,
BOOL disable_threads)
static UINT video_PresentationRequest(VideoClientContext* video, TSMM_PRESENTATION_REQUEST* req)
{
VideoClientContextPriv* priv = video->priv;
PresentationContext* presentation;
@@ -458,7 +416,7 @@ static UINT video_PresentationRequest(VideoClientContext* video, TSMM_PRESENTATI
WLog_DBG(TAG, "creating presentation 0x%x", req->PresentationId);
presentation = PresentationContext_new(
video, req->PresentationId, geom->topLevelLeft + geom->left,
geom->topLevelTop + geom->top, req->SourceWidth, req->SourceHeight, disable_threads);
geom->topLevelTop + geom->top, req->SourceWidth, req->SourceHeight);
if (!presentation)
{
WLog_ERR(TAG, "unable to create presentation video");
@@ -501,8 +459,7 @@ static UINT video_PresentationRequest(VideoClientContext* video, TSMM_PRESENTATI
return ret;
}
static UINT video_read_tsmm_presentation_req(VideoClientContext* context, wStream* s,
BOOL disable_threads)
static UINT video_read_tsmm_presentation_req(VideoClientContext* context, wStream* s)
{
TSMM_PRESENTATION_REQUEST req;
@@ -546,7 +503,7 @@ static UINT video_read_tsmm_presentation_req(VideoClientContext* context, wStrea
req.SourceHeight, req.ScaledWidth, req.ScaledHeight, req.hnsTimestampOffset,
req.GeometryMappingId);
return video_PresentationRequest(context, &req, disable_threads);
return video_PresentationRequest(context, &req);
}
/**
@@ -579,8 +536,7 @@ static UINT video_control_on_data_received(IWTSVirtualChannelCallback* pChannelC
switch (packetType)
{
case TSMM_PACKET_TYPE_PRESENTATION_REQUEST:
ret = video_read_tsmm_presentation_req(
context, s, video->settings->ThreadingFlags & THREADING_FLAGS_DISABLE_THREADS);
ret = video_read_tsmm_presentation_req(context, s);
break;
default:
WLog_ERR(TAG, "not expecting packet type %" PRIu32 "", packetType);
@@ -761,6 +717,7 @@ static UINT video_VideoData(VideoClientContext* context, TSMM_VIDEO_DATA* data)
VideoClientContextPriv* priv = context->priv;
PresentationContext* presentation;
int status;
const UINT32 format = PIXEL_FORMAT_BGRX32;
presentation = priv->currentPresentation;
if (!presentation)
@@ -790,17 +747,10 @@ static UINT video_VideoData(VideoClientContext* context, TSMM_VIDEO_DATA* data)
UINT64 startTime = GetTickCount64(), timeAfterH264;
MAPPED_GEOMETRY* geom = presentation->geometry;
const RECTANGLE_16 rect = { 0, 0, presentation->SourceWidth, presentation->SourceHeight };
Stream_SealLength(presentation->currentSample);
Stream_SetPosition(presentation->currentSample, 0);
status = h264->subsystem->Decompress(h264, Stream_Pointer(presentation->currentSample),
Stream_Length(presentation->currentSample));
if (status == 0)
return CHANNEL_RC_OK;
if (status < 0)
return CHANNEL_RC_OK;
timeAfterH264 = GetTickCount64();
if (data->SampleNumber == 1)
{
@@ -813,8 +763,13 @@ static UINT video_VideoData(VideoClientContext* context, TSMM_VIDEO_DATA* data)
int dropped = 0;
/* if the frame is to be published in less than 10 ms, let's consider it's now */
yuv_to_rgb(presentation, presentation->surfaceData);
status = avc420_decompress(h264, Stream_Pointer(presentation->currentSample),
Stream_Length(presentation->currentSample),
presentation->surfaceData, format, 0, rect.right,
rect.bottom, &rect, 1);
if (status < 0)
return CHANNEL_RC_OK;
context->showSurface(context, presentation->surface);
priv->publishedFrames++;
@@ -862,14 +817,13 @@ static UINT video_VideoData(VideoClientContext* context, TSMM_VIDEO_DATA* data)
return CHANNEL_RC_NO_MEMORY;
}
if (!yuv_to_rgb(presentation, frame->surfaceData))
{
WLog_ERR(TAG, "error during YUV->RGB conversion");
BufferPool_Return(priv->surfacePool, frame->surfaceData);
mappedGeometryUnref(geom);
free(frame);
return CHANNEL_RC_NO_MEMORY;
}
status =
avc420_decompress(h264, Stream_Pointer(presentation->currentSample),
Stream_Length(presentation->currentSample), frame->surfaceData,
format, 0, rect.right, rect.bottom, &rect, 1);
if (status < 0)
return CHANNEL_RC_OK;
InterlockedIncrement(&presentation->refCounter);
@@ -1151,8 +1105,6 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
return CHANNEL_RC_NO_MEMORY;
}
videoPlugin->settings = pEntryPoints->GetRdpSettings(pEntryPoints);
videoPlugin->wtsPlugin.Initialize = video_plugin_initialize;
videoPlugin->wtsPlugin.Connected = NULL;
videoPlugin->wtsPlugin.Disconnected = NULL;