diff --git a/channels/video/CMakeLists.txt b/channels/video/CMakeLists.txt new file mode 100644 index 000000000..f03c85189 --- /dev/null +++ b/channels/video/CMakeLists.txt @@ -0,0 +1,22 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2017 David Fort +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +define_channel("video") + +if(WITH_CLIENT_CHANNELS) + add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() diff --git a/channels/video/ChannelOptions.cmake b/channels/video/ChannelOptions.cmake new file mode 100644 index 000000000..e7f9ce86d --- /dev/null +++ b/channels/video/ChannelOptions.cmake @@ -0,0 +1,12 @@ + +set(OPTION_DEFAULT OFF) +set(OPTION_CLIENT_DEFAULT ON) +set(OPTION_SERVER_DEFAULT OFF) + +define_channel_options(NAME "video" TYPE "dynamic" + DESCRIPTION "Video optimized remoting Virtual Channel Extension" + SPECIFICATIONS "[MS-RDPEVOR]" + DEFAULT ${OPTION_DEFAULT}) + +define_channel_client_options(${OPTION_CLIENT_DEFAULT}) + diff --git a/channels/video/client/CMakeLists.txt b/channels/video/client/CMakeLists.txt new file mode 100644 index 000000000..6c6b4d711 --- /dev/null +++ b/channels/video/client/CMakeLists.txt @@ -0,0 +1,39 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2013 Marc-Andre Moreau +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +define_channel_client("video") + +set(${MODULE_PREFIX}_SRCS + video_main.c + video_main.h) + +include_directories(..) + +add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry") + + + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + + +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT BUILTIN_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/video/client/video_main.c b/channels/video/client/video_main.c new file mode 100755 index 000000000..52a6af02f --- /dev/null +++ b/channels/video/client/video_main.c @@ -0,0 +1,510 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Video Optimized Remoting Virtual Channel Extension + * + * Copyright 2017 David Fort + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define TAG CHANNELS_TAG("video.client") + +#include "video_main.h" + +struct _VIDEO_CHANNEL_CALLBACK +{ + IWTSVirtualChannelCallback iface; + + IWTSPlugin* plugin; + IWTSVirtualChannelManager* channel_mgr; + IWTSVirtualChannel* channel; +}; +typedef struct _VIDEO_CHANNEL_CALLBACK VIDEO_CHANNEL_CALLBACK; + +struct _VIDEO_LISTENER_CALLBACK +{ + IWTSListenerCallback iface; + + IWTSPlugin* plugin; + IWTSVirtualChannelManager* channel_mgr; + VIDEO_CHANNEL_CALLBACK* channel_callback; +}; +typedef struct _VIDEO_LISTENER_CALLBACK VIDEO_LISTENER_CALLBACK; + +struct _VIDEO_PLUGIN +{ + IWTSPlugin wtsPlugin; + + IWTSListener* controlListener; + IWTSListener* dataListener; + VIDEO_LISTENER_CALLBACK* control_callback; + VIDEO_LISTENER_CALLBACK* data_callback; + + VideoClientContext *context; +}; +typedef struct _VIDEO_PLUGIN VIDEO_PLUGIN; + +static const char *video_command_name(BYTE cmd) +{ + switch(cmd) + { + case TSMM_START_PRESENTATION: + return "start"; + case TSMM_STOP_PRESENTATION: + return "stop"; + default: + return ""; + } +} + +static UINT video_read_tsmm_presentation_req(VideoClientContext *context, wStream *s) +{ + TSMM_PRESENTATION_REQUEST req; + UINT ret = CHANNEL_RC_OK; + + if (Stream_GetRemainingLength(s) < 60) + { + WLog_ERR(TAG, "not enough bytes for a TSMM_PRESENTATION_REQUEST"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT8(s, req.PresentationId); + Stream_Read_UINT8(s, req.Version); + Stream_Read_UINT8(s, req.Command); + Stream_Seek_UINT8(s); /* FrameRate - reserved and ignored */ + + Stream_Seek_UINT16(s); /* AverageBitrateKbps reserved and ignored */ + Stream_Seek_UINT16(s); /* reserved */ + + Stream_Read_UINT32(s, req.SourceWidth); + Stream_Read_UINT32(s, req.SourceHeight); + Stream_Read_UINT32(s, req.ScaledWidth); + Stream_Read_UINT32(s, req.ScaledHeight); + Stream_Read_UINT64(s, req.hnsTimestampOffset); + Stream_Read_UINT64(s, req.GeometryMappingId); + Stream_Read(s, req.VideoSubtypeId, 16); + + Stream_Read_UINT32(s, req.cbExtra); + + if (Stream_GetRemainingLength(s) < req.cbExtra) + { + WLog_ERR(TAG, "not enough bytes for cbExtra of TSMM_PRESENTATION_REQUEST"); + return ERROR_INVALID_DATA; + } + + req.pExtraData = Stream_Pointer(s); + + WLog_DBG(TAG, "presentationReq: id:%"PRIu8" version:%"PRIu8" command:%s srcWidth/srcHeight=%"PRIu32"x%"PRIu32 + " scaled Width/Height=%"PRIu32"x%"PRIu32" timestamp=%"PRIu64" mappingId=%"PRIx64"", + req.PresentationId, req.Version, video_command_name(req.Command), + req.SourceWidth, req.SourceHeight, req.ScaledWidth, req.ScaledHeight, + req.hnsTimestampOffset, req.GeometryMappingId); + + if (context->PresentationRequest) + ret = context->PresentationRequest(context, &req); + + return ret; +} + +static UINT video_control_send_presentation_response(VideoClientContext *context, TSMM_PRESENTATION_RESPONSE *resp) +{ + BYTE buf[12]; + wStream *s; + VIDEO_PLUGIN* video = (VIDEO_PLUGIN *)context->handle; + IWTSVirtualChannel* channel; + UINT ret; + + s = Stream_New(buf, 12); + if (!s) + return CHANNEL_RC_NO_MEMORY; + + Stream_Write_UINT32(s, 12); /* cbSize */ + Stream_Write_UINT32(s, TSMM_PACKET_TYPE_PRESENTATION_RESPONSE); /* PacketType */ + Stream_Write_UINT8(s, resp->PresentationId); + Stream_Zero(s, 3); + Stream_SealLength(s); + + channel = video->control_callback->channel_callback->channel; + ret = channel->Write(channel, 12, buf, NULL); + Stream_Free(s, FALSE); + + return ret; +} + + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT video_control_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *s) +{ + VIDEO_CHANNEL_CALLBACK* callback = (VIDEO_CHANNEL_CALLBACK*) pChannelCallback; + VIDEO_PLUGIN* video; + VideoClientContext *context; + UINT ret = CHANNEL_RC_OK; + UINT32 cbSize, packetType; + + video = (VIDEO_PLUGIN*) callback->plugin; + context = (VideoClientContext *)video->wtsPlugin.pInterface; + + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, cbSize); + if (cbSize < 8 || Stream_GetRemainingLength(s) < (cbSize-4)) + { + WLog_ERR(TAG, "invalid cbSize"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, packetType); + switch (packetType) + { + case TSMM_PACKET_TYPE_PRESENTATION_REQUEST: + ret = video_read_tsmm_presentation_req(context, s); + break; + default: + WLog_ERR(TAG, "not expecting packet type %"PRIu32"", packetType); + ret = ERROR_UNSUPPORTED_TYPE; + break; + } + + return ret; +} + +static UINT video_control_send_client_notification(VideoClientContext *context, TSMM_CLIENT_NOTIFICATION *notif) +{ + BYTE buf[30]; + wStream *s; + VIDEO_PLUGIN* video = (VIDEO_PLUGIN *)context->handle; + IWTSVirtualChannel* channel; + UINT ret; + UINT32 cbSize; + + s = Stream_New(buf, 30); + if (!s) + return CHANNEL_RC_NO_MEMORY; + + cbSize = 16; + Stream_Seek_UINT32(s); /* cbSize */ + Stream_Write_UINT32(s, TSMM_PACKET_TYPE_CLIENT_NOTIFICATION); /* PacketType */ + Stream_Write_UINT8(s, notif->PresentationId); + Stream_Write_UINT8(s, notif->NotificationType); + Stream_Zero(s, 2); + if (notif->NotificationType == TSMM_CLIENT_NOTIFICATION_TYPE_FRAMERATE_OVERRIDE) + { + Stream_Write_UINT32(s, 16); /* cbData */ + + /* TSMM_CLIENT_NOTIFICATION_FRAMERATE_OVERRIDE */ + Stream_Write_UINT32(s, notif->FramerateOverride.Flags); + Stream_Write_UINT32(s, notif->FramerateOverride.DesiredFrameRate); + Stream_Zero(s, 4 * 2); + + cbSize += 4 * 4; + } + else + { + Stream_Write_UINT32(s, 0); /* cbData */ + } + + Stream_SealLength(s); + Stream_SetPosition(s, 0); + Stream_Write_UINT32(s, cbSize); + + channel = video->control_callback->channel_callback->channel; + ret = channel->Write(channel, cbSize, buf, NULL); + Stream_Free(s, FALSE); + + return ret; +} + + +static UINT video_data_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *s) +{ + VIDEO_CHANNEL_CALLBACK* callback = (VIDEO_CHANNEL_CALLBACK*) pChannelCallback; + VIDEO_PLUGIN* video; + VideoClientContext *context; + UINT32 cbSize, packetType; + TSMM_VIDEO_DATA data; + + video = (VIDEO_PLUGIN*) callback->plugin; + context = (VideoClientContext *)video->wtsPlugin.pInterface; + + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, cbSize); + if (cbSize < 8 || Stream_GetRemainingLength(s) < (cbSize-4)) + { + WLog_ERR(TAG, "invalid cbSize"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, packetType); + if (packetType != TSMM_PACKET_TYPE_VIDEO_DATA) + { + WLog_ERR(TAG, "only expecting VIDEO_DATA on the data channel"); + return ERROR_INVALID_DATA; + } + + if (Stream_GetRemainingLength(s) < 32) + { + WLog_ERR(TAG, "not enough bytes for a TSMM_VIDEO_DATA"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT8(s, data.PresentationId); + Stream_Read_UINT8(s, data.Version); + Stream_Read_UINT8(s, data.Flags); + Stream_Seek_UINT8(s); /* reserved */ + Stream_Read_UINT64(s, data.hnsTimestamp); + Stream_Read_UINT64(s, data.hnsDuration); + Stream_Read_UINT16(s, data.CurrentPacketIndex); + Stream_Read_UINT16(s, data.PacketsInSample); + Stream_Read_UINT32(s, data.SampleNumber); + Stream_Read_UINT32(s, data.cbSample); + data.pSample = Stream_Pointer(s); + + WLog_DBG(TAG, "videoData: id:%"PRIu8" version:%"PRIu8" flags:0x%"PRIx8" timestamp=%"PRIu64" duration=%"PRIu64 + " curPacketIndex:%"PRIu16" packetInSample:%"PRIu16" sampleNumber:%"PRIu32" cbSample:%"PRIu32"", + data.PresentationId, data.Version, data.Flags, data.hnsTimestamp, data.hnsDuration, + data.CurrentPacketIndex, data.PacketsInSample, data.SampleNumber, data.cbSample); + + if (context->VideoData) + return context->VideoData(context, &data); + + return CHANNEL_RC_OK; +} + + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT video_control_on_close(IWTSVirtualChannelCallback* pChannelCallback) +{ + free(pChannelCallback); + return CHANNEL_RC_OK; +} + +static UINT video_data_on_close(IWTSVirtualChannelCallback* pChannelCallback) +{ + free(pChannelCallback); + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT video_control_on_new_channel_connection(IWTSListenerCallback* listenerCallback, + IWTSVirtualChannel* channel, BYTE* Data, BOOL* pbAccept, + IWTSVirtualChannelCallback** ppCallback) +{ + VIDEO_CHANNEL_CALLBACK* callback; + VIDEO_LISTENER_CALLBACK* listener_callback = (VIDEO_LISTENER_CALLBACK*) listenerCallback; + + callback = (VIDEO_CHANNEL_CALLBACK*) calloc(1, sizeof(VIDEO_CHANNEL_CALLBACK)); + if (!callback) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + callback->iface.OnDataReceived = video_control_on_data_received; + callback->iface.OnClose = video_control_on_close; + callback->plugin = listener_callback->plugin; + callback->channel_mgr = listener_callback->channel_mgr; + callback->channel = channel; + listener_callback->channel_callback = callback; + + *ppCallback = (IWTSVirtualChannelCallback*) callback; + + return CHANNEL_RC_OK; +} + +static UINT video_data_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, + IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, + IWTSVirtualChannelCallback** ppCallback) +{ + VIDEO_CHANNEL_CALLBACK* callback; + VIDEO_LISTENER_CALLBACK* listener_callback = (VIDEO_LISTENER_CALLBACK*) pListenerCallback; + + callback = (VIDEO_CHANNEL_CALLBACK*) calloc(1, sizeof(VIDEO_CHANNEL_CALLBACK)); + if (!callback) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + callback->iface.OnDataReceived = video_data_on_data_received; + callback->iface.OnClose = video_data_on_close; + callback->plugin = listener_callback->plugin; + callback->channel_mgr = listener_callback->channel_mgr; + callback->channel = pChannel; + listener_callback->channel_callback = callback; + + *ppCallback = (IWTSVirtualChannelCallback*) callback; + + return CHANNEL_RC_OK; +} + + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT video_plugin_initialize(IWTSPlugin* plugin, IWTSVirtualChannelManager* channelMgr) +{ + UINT status; + VIDEO_PLUGIN* video = (VIDEO_PLUGIN *)plugin; + VIDEO_LISTENER_CALLBACK *callback; + + video->control_callback = callback = (VIDEO_LISTENER_CALLBACK*) calloc(1, sizeof(VIDEO_LISTENER_CALLBACK)); + if (!callback) + { + WLog_ERR(TAG, "calloc for control callback failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + callback->iface.OnNewChannelConnection = video_control_on_new_channel_connection; + callback->plugin = plugin; + callback->channel_mgr = channelMgr; + + status = channelMgr->CreateListener(channelMgr, VIDEO_CONTROL_DVC_CHANNEL_NAME, 0, + (IWTSListenerCallback*)callback, &(video->controlListener)); + + if (status != CHANNEL_RC_OK) + return status; + video->controlListener->pInterface = video->wtsPlugin.pInterface; + + + video->data_callback = callback = (VIDEO_LISTENER_CALLBACK*) calloc(1, sizeof(VIDEO_LISTENER_CALLBACK)); + if (!callback) + { + WLog_ERR(TAG, "calloc for data callback failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + callback->iface.OnNewChannelConnection = video_data_on_new_channel_connection; + callback->plugin = plugin; + callback->channel_mgr = channelMgr; + + status = channelMgr->CreateListener(channelMgr, VIDEO_DATA_DVC_CHANNEL_NAME, 0, + (IWTSListenerCallback*)callback, &(video->dataListener)); + + if (status == CHANNEL_RC_OK) + video->dataListener->pInterface = video->wtsPlugin.pInterface; + + return status; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT video_plugin_terminated(IWTSPlugin* pPlugin) +{ + VIDEO_PLUGIN* video = (VIDEO_PLUGIN*) pPlugin; + free(video->control_callback); + free(video->wtsPlugin.pInterface); + free(pPlugin); + return CHANNEL_RC_OK; +} + +/** + * Channel Client Interface + */ + + +#ifdef BUILTIN_CHANNELS +#define DVCPluginEntry video_DVCPluginEntry +#else +#define DVCPluginEntry FREERDP_API DVCPluginEntry +#endif + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) +{ + UINT error = CHANNEL_RC_OK; + VIDEO_PLUGIN* videoPlugin; + VideoClientContext* context; + + videoPlugin = (VIDEO_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "video"); + if (!videoPlugin) + { + videoPlugin = (VIDEO_PLUGIN*) calloc(1, sizeof(VIDEO_PLUGIN)); + if (!videoPlugin) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + videoPlugin->wtsPlugin.Initialize = video_plugin_initialize; + videoPlugin->wtsPlugin.Connected = NULL; + videoPlugin->wtsPlugin.Disconnected = NULL; + videoPlugin->wtsPlugin.Terminated = video_plugin_terminated; + + context = (VideoClientContext*) calloc(1, sizeof(VideoClientContext)); + if (!context) + { + WLog_ERR(TAG, "calloc failed!"); + free(videoPlugin); + return CHANNEL_RC_NO_MEMORY; + } + + context->handle = (void*) videoPlugin; + context->PresentationResponse = video_control_send_presentation_response; + context->ClientNotification = video_control_send_client_notification; + + videoPlugin->wtsPlugin.pInterface = (void*) context; + videoPlugin->context = context; + + error = pEntryPoints->RegisterPlugin(pEntryPoints, "video", (IWTSPlugin*) videoPlugin); + } + else + { + WLog_ERR(TAG, "could not get video Plugin."); + return CHANNEL_RC_BAD_CHANNEL; + } + + return error; +} diff --git a/channels/video/client/video_main.h b/channels/video/client/video_main.h new file mode 100644 index 000000000..f5e5ac910 --- /dev/null +++ b/channels/video/client/video_main.h @@ -0,0 +1,35 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Video Optimized Remoting Virtual Channel Extension + * + * Copyright 2017 David Fort + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_VIDEO_CLIENT_MAIN_H +#define FREERDP_CHANNEL_VIDEO_CLIENT_MAIN_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include + + +#endif /* FREERDP_CHANNEL_GEOMETRY_CLIENT_MAIN_H */ + diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 1e9c24e9a..93b86e697 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -767,6 +767,11 @@ static int freerdp_client_command_line_post_filter(void* context, { settings->SupportGeometryTracking = TRUE; } + CommandLineSwitchCase(arg, "video") + { + settings->SupportGeometryTracking = TRUE; /* this requires geometry tracking */ + settings->SupportVideoOptimized = TRUE; + } CommandLineSwitchCase(arg, "sound") { char** p; @@ -3015,6 +3020,17 @@ BOOL freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings) return FALSE; } + if (settings->SupportVideoOptimized) + { + char* p[1]; + int count; + count = 1; + p[0] = "video"; + + if (!freerdp_client_add_dynamic_channel(settings, count, p)) + return FALSE; + } + if (settings->DynamicChannelCount) settings->SupportDynamicChannels = TRUE; diff --git a/include/freerdp/channels/video.h b/include/freerdp/channels/video.h new file mode 100644 index 000000000..cccc199aa --- /dev/null +++ b/include/freerdp/channels/video.h @@ -0,0 +1,114 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Video Optimized Remoting Virtual Channel Extension + * + * Copyright 2017 David Fort + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_VIDEO_H +#define FREERDP_CHANNEL_VIDEO_H + +#include +#include + +#define VIDEO_CONTROL_DVC_CHANNEL_NAME "Microsoft::Windows::RDS::Video::Control::v08.01" +#define VIDEO_DATA_DVC_CHANNEL_NAME "Microsoft::Windows::RDS::Video::Data::v08.01" + +/** @brief TSNM packet type */ +enum +{ + TSMM_PACKET_TYPE_PRESENTATION_REQUEST = 1, + TSMM_PACKET_TYPE_PRESENTATION_RESPONSE = 2, + TSMM_PACKET_TYPE_CLIENT_NOTIFICATION = 3, + TSMM_PACKET_TYPE_VIDEO_DATA = 4 +}; + +/** @brief TSMM_PRESENTATION_REQUEST commands */ +enum +{ + TSMM_START_PRESENTATION = 1, + TSMM_STOP_PRESENTATION = 2 +}; + +/** @brief presentation request struct */ +struct _TSMM_PRESENTATION_REQUEST +{ + BYTE PresentationId; + BYTE Version; + BYTE Command; + UINT32 SourceWidth, SourceHeight; + UINT32 ScaledWidth, ScaledHeight; + UINT64 hnsTimestampOffset; + UINT64 GeometryMappingId; + BYTE VideoSubtypeId[16]; + UINT32 cbExtra; + BYTE *pExtraData; +}; +typedef struct _TSMM_PRESENTATION_REQUEST TSMM_PRESENTATION_REQUEST; + +/** @brief response to a TSMM_PRESENTATION_REQUEST */ +struct _TSMM_PRESENTATION_RESPONSE +{ + BYTE PresentationId; +}; +typedef struct _TSMM_PRESENTATION_RESPONSE TSMM_PRESENTATION_RESPONSE; + +/** @brief TSMM_VIDEO_DATA flags */ +enum +{ + TSMM_VIDEO_DATA_FLAG_HAS_TIMESTAMPS = 0x01, + TSMM_VIDEO_DATA_FLAG_KEYFRAME = 0x02, + TSMM_VIDEO_DATA_FLAG_NEW_FRAMERATE = 0x04 +}; + +/** @brief a video data packet */ +struct _TSMM_VIDEO_DATA +{ + BYTE PresentationId; + BYTE Version; + BYTE Flags; + UINT64 hnsTimestamp; + UINT64 hnsDuration; + UINT16 CurrentPacketIndex; + UINT16 PacketsInSample; + UINT32 SampleNumber; + UINT32 cbSample; + BYTE *pSample; +}; +typedef struct _TSMM_VIDEO_DATA TSMM_VIDEO_DATA; + +enum +{ + TSMM_CLIENT_NOTIFICATION_TYPE_NETWORK_ERROR = 1, + TSMM_CLIENT_NOTIFICATION_TYPE_FRAMERATE_OVERRIDE = 2 +}; + +struct _TSMM_CLIENT_NOTIFICATION_FRAMERATE_OVERRIDE +{ + UINT32 Flags; + UINT32 DesiredFrameRate; +}; +typedef struct _TSMM_CLIENT_NOTIFICATION_FRAMERATE_OVERRIDE TSMM_CLIENT_NOTIFICATION_FRAMERATE_OVERRIDE; + +struct _TSMM_CLIENT_NOTIFICATION +{ + BYTE PresentationId; + BYTE NotificationType; + TSMM_CLIENT_NOTIFICATION_FRAMERATE_OVERRIDE FramerateOverride; +}; +typedef struct _TSMM_CLIENT_NOTIFICATION TSMM_CLIENT_NOTIFICATION; + + +#endif /* FREERDP_CHANNEL_VIDEO_H */ diff --git a/include/freerdp/client/video.h b/include/freerdp/client/video.h new file mode 100644 index 000000000..df0dd3a78 --- /dev/null +++ b/include/freerdp/client/video.h @@ -0,0 +1,45 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Video Optimized Remoting Virtual Channel Extension + * + * Copyright 2017 David Fort + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNELS_CLIENT_VIDEO_H +#define FREERDP_CHANNELS_CLIENT_VIDEO_H + +#include + +typedef struct _video_client_context VideoClientContext; + +typedef UINT (*pcPresentationRequest)(VideoClientContext* context, TSMM_PRESENTATION_REQUEST *req); +typedef UINT (*pcPresentationResponse)(VideoClientContext* context, TSMM_PRESENTATION_RESPONSE *resp); +typedef UINT (*pcVideoClientNotification)(VideoClientContext *context, TSMM_CLIENT_NOTIFICATION *notif); +typedef UINT (*pcVideoData)(VideoClientContext* context, TSMM_VIDEO_DATA *data); + +/** @brief context for the video (MS-RDPEVOR) channel */ +struct _video_client_context +{ + void* handle; + void* custom; + + pcPresentationRequest PresentationRequest; + pcPresentationResponse PresentationResponse; + pcVideoClientNotification ClientNotification; + pcVideoData VideoData; +}; + +#endif /* FREERDP_CHANNELS_CLIENT_VIDEO_H */ + diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index e0157417a..a5dcad846 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -1428,7 +1428,8 @@ struct rdp_settings ALIGN64 BOOL SupportDisplayControl; /* 5185 */ ALIGN64 BOOL SupportGeometryTracking; /* 5186 */ ALIGN64 BOOL SupportSSHAgentChannel; /* 5187 */ - UINT64 padding5312[5312 - 5188]; /* 5188 */ + ALIGN64 BOOL SupportVideoOptimized; /* 5188 */ + UINT64 padding5312[5312 - 5189]; /* 5189 */ /** * WARNING: End of ABI stable zone!