mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-15 00:44:19 +09:00
Refactored H264 encoding/decoding
Use YUV primitives now for all H264 operations
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user