Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/neutrinolabs/NeutrinoRDP.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaxmikant Rashinkar <LK.Rashinkar@gmail.com>2012-10-22 03:52:28 +0400
committerLaxmikant Rashinkar <LK.Rashinkar@gmail.com>2012-10-22 03:52:28 +0400
commit211c036b1f218cad5190c507457677f0bb0e91e9 (patch)
treefd08d6ee96dd1b8373491ee207cc8f4a39785cd8 /channels
parent2ef1293fc4671b2407b301da7525bc0aa2ddacb9 (diff)
o Added xrdpvr (xrdp video redirection) plugin that does NOT make use of TSMF
o this is a development checkin - the plugin is not complete
Diffstat (limited to 'channels')
-rw-r--r--channels/xrdpvr/CMakeLists.txt26
-rw-r--r--channels/xrdpvr/xrdpvr_common.h38
-rw-r--r--channels/xrdpvr/xrdpvr_ffmpeg.c525
-rw-r--r--channels/xrdpvr/xrdpvr_main.c305
-rw-r--r--channels/xrdpvr/xrdpvr_main.h29
5 files changed, 923 insertions, 0 deletions
diff --git a/channels/xrdpvr/CMakeLists.txt b/channels/xrdpvr/CMakeLists.txt
new file mode 100644
index 0000000..445518d
--- /dev/null
+++ b/channels/xrdpvr/CMakeLists.txt
@@ -0,0 +1,26 @@
+# FreeRDP: A Remote Desktop Protocol Client
+# FreeRDP cmake build script
+#
+# 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.
+
+set(XRDPVR_SRCS
+ xrdpvr_ffmpeg.c
+ xrdpvr_main.c)
+
+add_library(xrdpvr ${XRDPVR_SRCS})
+set_target_properties(xrdpvr PROPERTIES PREFIX "")
+
+target_link_libraries(xrdpvr freerdp-utils -lavcodec -lavutil -lavformat)
+
+install(TARGETS xrdpvr DESTINATION ${FREERDP_PLUGIN_PATH})
+
diff --git a/channels/xrdpvr/xrdpvr_common.h b/channels/xrdpvr/xrdpvr_common.h
new file mode 100644
index 0000000..2c7aed0
--- /dev/null
+++ b/channels/xrdpvr/xrdpvr_common.h
@@ -0,0 +1,38 @@
+#ifndef __XRDPVR_COMMON_H__
+#define __XRDPVR_COMMON_H__
+
+#include "freerdp/types.h"
+
+typedef struct _XrdpMediaInfo
+{
+ int MajorType;
+ int SubType;
+ int FormatType;
+ int width;
+ int height;
+ int bit_rate;
+ int samples_per_sec_num;
+ int samples_per_sec_den;
+ uint32 ExtraDataSize;
+ uint8* ExtraData;
+ uint32 stream_id;
+} XrdpMediaInfo;
+
+void *xrdpvr_init(void);
+int xrdpvr_deinit(void *decoder);
+int xrdpvr_init_context(void *dec);
+int xrdpvr_init_video_stream(void *dec, XrdpMediaInfo* vinfo);
+//int xrdpvr_init_audio_stream(XrdpMpegDecoder* mdecoder, XrdpMediaInfo* ainfo);
+int xrdpvr_init_stream(void *dec, XrdpMediaInfo* media_info);
+int xrdpvr_prepare(void *dec);
+int xrdpvr_set_format(void *dec, XrdpMediaInfo* media_info);
+
+int xrdpvr_decode_video(void* dec, uint32 data_size, const uint8* data, uint32 extensions);
+int xrdpvr_decode_audio(void* dec, uint32 data_size, const uint8* data, uint32 extensions);
+int xrdpvr_decode(void* dec, uint32 data_size, const uint8* data, uint32 extensions);
+//uint8* xrdpv_get_decoded_data(XrdpMpegDecoder* mdecoder, uint32* size);
+//uint32 xrdpvr_get_decoded_format(XrdpMpegDecoder* mdecoder);
+//int xrdpvr_get_decoded_dimension(XrdpMpegDecoder* mdecoder, uint32* width, uint32* height);
+//void xrdpvr_free(XrdpMpegDecoder* mdecoder);
+
+#endif
diff --git a/channels/xrdpvr/xrdpvr_ffmpeg.c b/channels/xrdpvr/xrdpvr_ffmpeg.c
new file mode 100644
index 0000000..32fe2bb
--- /dev/null
+++ b/channels/xrdpvr/xrdpvr_ffmpeg.c
@@ -0,0 +1,525 @@
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include "xrdpvr_common.h"
+#include "freerdp/types.h"
+#include "freerdp/utils/svc_plugin.h"
+#include "freerdp/utils/memory.h"
+
+/* MajorType */
+#define TSMF_MAJOR_TYPE_UNKNOWN 0
+#define TSMF_MAJOR_TYPE_VIDEO 1
+#define TSMF_MAJOR_TYPE_AUDIO 2
+
+/* SubType */
+#define TSMF_SUB_TYPE_UNKNOWN 0
+#define TSMF_SUB_TYPE_WVC1 1
+#define TSMF_SUB_TYPE_WMA2 2
+#define TSMF_SUB_TYPE_WMA9 3
+#define TSMF_SUB_TYPE_MP3 4
+#define TSMF_SUB_TYPE_MP2A 5
+#define TSMF_SUB_TYPE_MP2V 6
+#define TSMF_SUB_TYPE_WMV3 7
+#define TSMF_SUB_TYPE_AAC 8
+#define TSMF_SUB_TYPE_H264 9
+#define TSMF_SUB_TYPE_AVC1 10
+#define TSMF_SUB_TYPE_AC3 11
+#define TSMF_SUB_TYPE_WMV2 12
+#define TSMF_SUB_TYPE_WMV1 13
+#define TSMF_SUB_TYPE_MP1V 14
+#define TSMF_SUB_TYPE_MP1A 15
+#define TSMF_SUB_TYPE_YUY2 16
+#define TSMF_SUB_TYPE_MP43 17
+#define TSMF_SUB_TYPE_MP4S 18
+#define TSMF_SUB_TYPE_MP42 19
+
+/* FormatType */
+#define TSMF_FORMAT_TYPE_UNKNOWN 0
+#define TSMF_FORMAT_TYPE_MFVIDEOFORMAT 1
+#define TSMF_FORMAT_TYPE_WAVEFORMATEX 2
+#define TSMF_FORMAT_TYPE_MPEG2VIDEOINFO 3
+#define TSMF_FORMAT_TYPE_VIDEOINFO2 4
+#define TSMF_FORMAT_TYPE_MPEG1VIDEOINFO 5
+
+/* TS_MM_DATA_SAMPLE.SampleExtensions */
+#define TSMM_SAMPLE_EXT_CLEANPOINT 0x00000001
+#define TSMM_SAMPLE_EXT_DISCONTINUITY 0x00000002
+#define TSMM_SAMPLE_EXT_INTERLACED 0x00000004
+#define TSMM_SAMPLE_EXT_BOTTOMFIELDFIRST 0x00000008
+#define TSMM_SAMPLE_EXT_REPEATFIELDFIRST 0x00000010
+#define TSMM_SAMPLE_EXT_SINGLEFIELD 0x00000020
+#define TSMM_SAMPLE_EXT_DERIVEDFROMTOPFIELD 0x00000040
+#define TSMM_SAMPLE_EXT_HAS_NO_TIMESTAMPS 0x00000080
+#define TSMM_SAMPLE_EXT_RELATIVE_TIMESTAMPS 0x00000100
+#define TSMM_SAMPLE_EXT_ABSOLUTE_TIMESTAMPS 0x00000200
+
+/* RDP_VIDEO_FRAME_EVENT.frame_pixfmt */
+/* http://www.fourcc.org/yuv.php */
+#define RDP_PIXFMT_I420 0x30323449
+#define RDP_PIXFMT_YV12 0x32315659
+
+typedef struct _XrdpMpegDecoder
+{
+ int media_type;
+ enum CodecID codec_id;
+ AVCodecContext* codec_context;
+ AVCodec* codec;
+ AVFrame* frame;
+ int prepared;
+
+ uint8* decoded_data;
+ uint32 decoded_size;
+ uint32 decoded_size_max;
+} XrdpMpegDecoder;
+
+/* @return opaque pointer on success, NULL on failure
+ ******************************************************************************/
+void *xrdpvr_init(void)
+{
+ XrdpMpegDecoder *decoder;
+
+ decoder = (XrdpMpegDecoder *) calloc(1, sizeof(XrdpMpegDecoder));
+ if (!decoder)
+ return NULL;
+
+ av_register_all();
+ return decoder;
+}
+
+/* @return 0 on success, -1 on failure
+ ******************************************************************************/
+int xrdpvr_deinit(void *decoder)
+{
+ if (decoder)
+ free(decoder);
+
+ return 0;
+}
+
+/* @return 0 on success, -1 on failure
+ ******************************************************************************/
+int xrdpvr_init_context(void *dec)
+{
+ XrdpMpegDecoder* mdecoder = (XrdpMpegDecoder *) dec;
+
+ mdecoder->codec_context = avcodec_alloc_context3(NULL);
+ if (!mdecoder->codec_context)
+ {
+ DEBUG_WARN("avcodec_alloc_context failed.");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* @return 0 on success, -1 on failure
+ ******************************************************************************/
+int xrdpvr_init_video_stream(void *dec, XrdpMediaInfo* vinfo)
+{
+ XrdpMpegDecoder* mdecoder = (XrdpMpegDecoder *) dec;
+
+ mdecoder->codec_context->width = vinfo->width;
+ mdecoder->codec_context->height = vinfo->height;
+ mdecoder->codec_context->bit_rate = vinfo->bit_rate;
+ mdecoder->codec_context->time_base.den = vinfo->samples_per_sec_num;
+ mdecoder->codec_context->time_base.num = vinfo->samples_per_sec_den;
+
+ mdecoder->frame = avcodec_alloc_frame();
+
+ return 0;
+}
+
+/*
+ ******************************************************************************/
+int xrdpvr_init_audio_stream(XrdpMpegDecoder* mdecoder, XrdpMediaInfo* ainfo)
+{
+ printf("### LK_TODO: not yet implemented\n");
+ return 0;
+}
+
+/* @return 0 on success, -1 on failure
+ ******************************************************************************/
+int xrdpvr_init_stream(void *dec, XrdpMediaInfo* media_info)
+{
+ uint32 size;
+ uint8* s;
+ uint8* p;
+
+ XrdpMpegDecoder* mdecoder = (XrdpMpegDecoder *) dec;
+
+ mdecoder->codec = avcodec_find_decoder(mdecoder->codec_id);
+ if (!mdecoder->codec)
+ {
+ DEBUG_WARN("avcodec_find_decoder() failed.");
+ return -1;
+ }
+
+ mdecoder->codec_context->codec_id = mdecoder->codec_id;
+ mdecoder->codec_context->codec_type = mdecoder->media_type;
+
+ if (mdecoder->media_type == AVMEDIA_TYPE_VIDEO)
+ {
+ if (xrdpvr_init_video_stream((void *) mdecoder, media_info))
+ {
+ return -1;
+ }
+ }
+ else if (mdecoder->media_type == AVMEDIA_TYPE_AUDIO)
+ {
+ if (!xrdpvr_init_audio_stream(mdecoder, media_info))
+ {
+ return -1;
+ }
+ }
+
+ if (media_info->ExtraData)
+ {
+ if (media_info->SubType == TSMF_SUB_TYPE_AVC1 &&
+ media_info->FormatType == TSMF_FORMAT_TYPE_MPEG2VIDEOINFO)
+ {
+ /* The extradata format that FFmpeg uses is following CodecPrivate in Matroska.
+ See http://haali.su/mkv/codecs.pdf */
+ mdecoder->codec_context->extradata_size = media_info->ExtraDataSize + 8;
+ mdecoder->codec_context->extradata = xzalloc(mdecoder->codec_context->extradata_size);
+ p = mdecoder->codec_context->extradata;
+ *p++ = 1; /* Reserved? */
+ *p++ = media_info->ExtraData[8]; /* Profile */
+ *p++ = 0; /* Profile */
+ *p++ = media_info->ExtraData[12]; /* Level */
+ *p++ = 0xff; /* Flag? */
+ *p++ = 0xe0 | 0x01; /* Reserved | #sps */
+ s = media_info->ExtraData + 20;
+ size = ((uint32)(*s)) * 256 + ((uint32)(*(s + 1)));
+ memcpy(p, s, size + 2);
+ s += size + 2;
+ p += size + 2;
+ *p++ = 1; /* #pps */
+ size = ((uint32)(*s)) * 256 + ((uint32)(*(s + 1)));
+ memcpy(p, s, size + 2);
+ }
+ else
+ {
+ /* Add a padding to avoid invalid memory read in some codec */
+ mdecoder->codec_context->extradata_size = media_info->ExtraDataSize + 8;
+ mdecoder->codec_context->extradata = xzalloc(mdecoder->codec_context->extradata_size);
+ memcpy(mdecoder->codec_context->extradata, media_info->ExtraData, media_info->ExtraDataSize);
+ memset(mdecoder->codec_context->extradata + media_info->ExtraDataSize, 0, 8);
+ }
+ }
+
+ if (mdecoder->codec->capabilities & CODEC_CAP_TRUNCATED)
+ mdecoder->codec_context->flags |= CODEC_FLAG_TRUNCATED;
+
+ return 0;
+}
+
+/* @return 0 on success, -1 on failure
+ ******************************************************************************/
+int xrdpvr_prepare(void *dec)
+{
+ XrdpMpegDecoder* mdecoder = (XrdpMpegDecoder *) dec;
+
+ if (avcodec_open2(mdecoder->codec_context, mdecoder->codec, NULL) < 0)
+ {
+ DEBUG_WARN("avcodec_open2 failed.");
+ return -1;
+ }
+
+ mdecoder->prepared = 1;
+
+ return 0;
+}
+
+/* @return 0 on success, -1 on error
+ ******************************************************************************/
+int xrdpvr_set_format(void *dec, XrdpMediaInfo* media_info)
+{
+ XrdpMpegDecoder* mdecoder = (XrdpMpegDecoder *) dec;
+
+ switch (media_info->MajorType)
+ {
+ case TSMF_MAJOR_TYPE_VIDEO:
+ mdecoder->media_type = AVMEDIA_TYPE_VIDEO;
+ break;
+
+ case TSMF_MAJOR_TYPE_AUDIO:
+ mdecoder->media_type = AVMEDIA_TYPE_AUDIO;
+ break;
+
+ default:
+ printf("### xrdpvr_set_format() failed; wrong MajorType\n");
+ return -1;
+ }
+
+ switch (media_info->SubType)
+ {
+ case TSMF_SUB_TYPE_WVC1:
+ mdecoder->codec_id = CODEC_ID_VC1;
+ break;
+
+ case TSMF_SUB_TYPE_WMA2:
+ mdecoder->codec_id = CODEC_ID_WMAV2;
+ break;
+
+ case TSMF_SUB_TYPE_WMA9:
+ mdecoder->codec_id = CODEC_ID_WMAPRO;
+ break;
+
+ case TSMF_SUB_TYPE_MP3:
+ mdecoder->codec_id = CODEC_ID_MP3;
+ break;
+
+ case TSMF_SUB_TYPE_MP2A:
+ mdecoder->codec_id = CODEC_ID_MP2;
+ break;
+
+ case TSMF_SUB_TYPE_MP2V:
+ mdecoder->codec_id = CODEC_ID_MPEG2VIDEO;
+ break;
+
+ case TSMF_SUB_TYPE_WMV3:
+ mdecoder->codec_id = CODEC_ID_WMV3;
+ break;
+
+ case TSMF_SUB_TYPE_AAC:
+ mdecoder->codec_id = CODEC_ID_AAC;
+ /* For AAC the pFormat is a HEAACWAVEINFO struct, and the codec data
+ is at the end of it. See
+ http://msdn.microsoft.com/en-us/library/dd757806.aspx */
+ if (media_info->ExtraData)
+ {
+ media_info->ExtraData += 12;
+ media_info->ExtraDataSize -= 12;
+ }
+ break;
+
+ case TSMF_SUB_TYPE_H264:
+ case TSMF_SUB_TYPE_AVC1:
+ mdecoder->codec_id = CODEC_ID_H264;
+ break;
+
+ case TSMF_SUB_TYPE_AC3:
+ mdecoder->codec_id = CODEC_ID_AC3;
+ break;
+
+ default:
+ printf("### xrdpvr_set_format() failed; wrong SubType\n");
+ return -1;
+ }
+
+ if (xrdpvr_init_context((void *) mdecoder))
+ {
+ return -1;
+ }
+
+ if (xrdpvr_init_stream((void *) mdecoder, media_info))
+ {
+ return -1;
+ }
+
+ if (xrdpvr_prepare((void *) mdecoder))
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+/* @return 0 on success, -1 on failure
+ ******************************************************************************/
+int xrdpvr_decode_video(void *dec, uint32 data_size, const uint8* data,
+ uint32 extensions)
+{
+ XrdpMpegDecoder* mdecoder = (XrdpMpegDecoder *) dec;
+
+ int decoded;
+ int len;
+ AVFrame* frame;
+ int ret = 0;
+
+#if LIBAVCODEC_VERSION_MAJOR < 52 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR <= 20)
+ len = avcodec_decode_video(mdecoder->codec_context, mdecoder->frame, &decoded, data, data_size);
+#else
+ {
+ AVPacket pkt;
+ av_init_packet(&pkt);
+ pkt.data = (uint8*) data;
+ pkt.size = data_size;
+
+#if 0
+ if (extensions & TSMM_SAMPLE_EXT_CLEANPOINT)
+ pkt.flags |= AV_PKT_FLAG_KEY;
+#endif
+
+ len = avcodec_decode_video2(mdecoder->codec_context, mdecoder->frame, &decoded, &pkt);
+ }
+#endif
+
+ if (len < 0)
+ {
+ DEBUG_WARN("data_size %d, avcodec_decode_video failed (%d)", data_size, len);
+ ret = -1;
+ }
+ else if (!decoded)
+ {
+ DEBUG_WARN("data_size %d, no frame is decoded.", data_size);
+ ret = -1;
+ }
+ else
+ {
+ DEBUG_SVC("linesize[0] %d linesize[1] %d linesize[2] %d linesize[3] %d "
+ "pix_fmt %d width %d height %d",
+ mdecoder->frame->linesize[0], mdecoder->frame->linesize[1],
+ mdecoder->frame->linesize[2], mdecoder->frame->linesize[3],
+ mdecoder->codec_context->pix_fmt,
+ mdecoder->codec_context->width, mdecoder->codec_context->height);
+
+ mdecoder->decoded_size = avpicture_get_size(mdecoder->codec_context->pix_fmt,
+ mdecoder->codec_context->width, mdecoder->codec_context->height);
+ mdecoder->decoded_data = xzalloc(mdecoder->decoded_size);
+ frame = avcodec_alloc_frame();
+ avpicture_fill((AVPicture *) frame, mdecoder->decoded_data,
+ mdecoder->codec_context->pix_fmt,
+ mdecoder->codec_context->width, mdecoder->codec_context->height);
+
+ av_picture_copy((AVPicture *) frame, (AVPicture *) mdecoder->frame,
+ mdecoder->codec_context->pix_fmt,
+ mdecoder->codec_context->width, mdecoder->codec_context->height);
+
+ av_free(frame);
+ }
+
+ return ret;
+}
+
+/* @return 0 on success, -1 on failure
+ ******************************************************************************/
+int xrdpvr_decode_audio(void *dec, uint32 data_size, const uint8* data,
+ uint32 extensions)
+{
+ /* XrdpMpegDecoder* mdecoder = (XrdpMpegDecoder *) dec; */
+
+ printf("### not yet implemented\n");
+ return 0;
+}
+
+/* @return 0 on success, -1 on failure
+ ******************************************************************************/
+int xrdpvr_decode(void* dec, const uint32 data_size, const uint8* data,
+ uint32 extensions)
+{
+ XrdpMpegDecoder* mdecoder = (XrdpMpegDecoder *) dec;
+
+ if (mdecoder->decoded_data)
+ {
+ free(mdecoder->decoded_data);
+ mdecoder->decoded_data = NULL;
+ }
+ mdecoder->decoded_size = 0;
+
+ switch (mdecoder->media_type)
+ {
+ case AVMEDIA_TYPE_VIDEO:
+ return xrdpvr_decode_video(mdecoder, data_size, data, extensions);
+
+ case AVMEDIA_TYPE_AUDIO:
+ return xrdpvr_decode_audio(mdecoder, data_size, data, extensions);
+
+ default:
+ DEBUG_WARN("unknown media type.");
+ return -1;
+ }
+}
+
+/*
+ ******************************************************************************/
+uint8* xrdpv_get_decoded_data(XrdpMpegDecoder* mdecoder, uint32* size)
+{
+ uint8* buf;
+
+ *size = mdecoder->decoded_size;
+ buf = mdecoder->decoded_data;
+ mdecoder->decoded_data = NULL;
+ mdecoder->decoded_size = 0;
+ return buf;
+}
+
+/*
+ ******************************************************************************/
+uint32 xrdpvr_get_decoded_format(XrdpMpegDecoder* mdecoder)
+{
+ switch (mdecoder->codec_context->pix_fmt)
+ {
+ case PIX_FMT_YUV420P:
+ return RDP_PIXFMT_I420;
+
+ default:
+ DEBUG_WARN("unsupported pixel format %u",
+ mdecoder->codec_context->pix_fmt);
+ return (uint32) -1;
+ }
+}
+
+/* @return 0 on success, -1 on failure
+ ******************************************************************************/
+int xrdpvr_get_decoded_dimension(XrdpMpegDecoder* mdecoder, uint32* width,
+ uint32* height)
+{
+ if (mdecoder->codec_context->width > 0 && mdecoder->codec_context->height > 0)
+ {
+ *width = mdecoder->codec_context->width;
+ *height = mdecoder->codec_context->height;
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+/*
+ ******************************************************************************/
+void xrdpvr_free(XrdpMpegDecoder* mdecoder)
+{
+ if (mdecoder->frame)
+ av_free(mdecoder->frame);
+
+ if (mdecoder->decoded_data)
+ free(mdecoder->decoded_data);
+
+ if (mdecoder->codec_context)
+ {
+ if (mdecoder->prepared)
+ avcodec_close(mdecoder->codec_context);
+
+ if (mdecoder->codec_context->extradata)
+ free(mdecoder->codec_context->extradata);
+
+ av_free(mdecoder->codec_context);
+ }
+ free(mdecoder);
+}
+
+#if 0
+ITSMFDecoder*
+TSMFDecoderEntry(void)
+{
+ TSMFFFmpegDecoder * decoder;
+
+ if (!initialized)
+ {
+ avcodec_register_all();
+ initialized = TRUE;
+ }
+
+ decoder = xnew(TSMFFFmpegDecoder);
+
+ decoder->iface.SetFormat = tsmf_ffmpeg_set_format;
+ decoder->iface.Decode = tsmf_ffmpeg_decode;
+ decoder->iface.GetDecodedData = tsmf_ffmpeg_get_decoded_data;
+ decoder->iface.GetDecodedFormat = tsmf_ffmpeg_get_decoded_format;
+ decoder->iface.GetDecodedDimension = tsmf_ffmpeg_get_decoded_dimension;
+ decoder->iface.Free = tsmf_ffmpeg_free;
+
+ return (ITSMFDecoder*) decoder;
+}
+#endif
diff --git a/channels/xrdpvr/xrdpvr_main.c b/channels/xrdpvr/xrdpvr_main.c
new file mode 100644
index 0000000..6450a09
--- /dev/null
+++ b/channels/xrdpvr/xrdpvr_main.c
@@ -0,0 +1,305 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Xrdp video redirection channel
+ *
+ * Copyright 2012 Laxmikant Rashinkar <LK.Rashinkar@gmail.com>
+ * Copyright 2012 Vic Lee
+ *
+ * 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
+
+#ifndef _WIN32
+#include <sys/time.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <freerdp/constants.h>
+#include <freerdp/types.h>
+#include <freerdp/utils/memory.h>
+#include <freerdp/utils/stream.h>
+#include <freerdp/utils/list.h>
+#include <freerdp/utils/load_plugin.h>
+#include <freerdp/utils/svc_plugin.h>
+
+#include "xrdpvr_common.h"
+#include "xrdpvr_main.h"
+#include "freerdp/utils/svc_plugin.h"
+#include "freerdp/utils/memory.h"
+#include "freerdp/utils/stream.h"
+
+struct xrdpvr_plugin
+{
+ rdpSvcPlugin plugin;
+ void *decoder; /* reference to XrdpMpegDecoder */
+ STREAM* s;
+ int got_partial_data;
+ int bytes_needed;
+};
+
+/*
+ ******************************************************************************/
+static void xrdpvr_process_interval(rdpSvcPlugin* plugin)
+{
+ printf("xrdpvr: xrdpvr_process_interval:\n");
+}
+
+/*
+ ******************************************************************************/
+static void xrdpvr_process_receive(rdpSvcPlugin* plugin, STREAM* data_in)
+{
+ xrdpvrPlugin* xrdpvr = (xrdpvrPlugin*) plugin;
+ STREAM* s;
+ int rv;
+ int bytes_to_process;
+ int i;
+ uint32 cmd;
+ uint32 data_len;
+ uint32 tmp;
+ XrdpMediaInfo media_info;
+
+ if (xrdpvr == NULL)
+ {
+ stream_free(data_in);
+ return;
+ }
+
+ if (stream_get_size(data_in) <= 0)
+ {
+ stream_free(data_in);
+ return;
+ }
+
+start:
+
+ if (xrdpvr->got_partial_data)
+ {
+ /* previous pkt was fragmented and could not be processed; if we have */
+ /* enough data, process it now, else defer processing till next pkt */
+
+ /* how much additional data did we get? */
+ int data_in_len = data_in->size;
+
+ /* append new data to old */
+ memcpy(xrdpvr->s->p, data_in->p, data_in_len);
+ xrdpvr->s->p += data_in_len;
+
+ if (data_in_len < xrdpvr->bytes_needed)
+ {
+ /* we still don't have enough data */
+ xrdpvr->bytes_needed -= data_in_len;
+ stream_free(data_in);
+ return;
+ }
+
+ /* we have enough data */
+ xrdpvr->bytes_needed = 0;
+ xrdpvr->got_partial_data = 0;
+ bytes_to_process = stream_get_length(xrdpvr->s);
+ stream_set_pos(xrdpvr->s, 4); /* point to cmd */
+ s = xrdpvr->s;
+ }
+ else
+ {
+ stream_read_uint32(data_in, data_len);
+ if ((data_in->size - 4) < data_len)
+ {
+ /* got a fragmented pkt - save it for later processing */
+ xrdpvr->s->p = xrdpvr->s->data;
+ memcpy(xrdpvr->s->p, data_in->data, data_in->size);
+ xrdpvr->s->p += data_in->size;
+ xrdpvr->got_partial_data = 1;
+ xrdpvr->bytes_needed = data_len - (data_in->size - 4);
+ stream_free(data_in);
+ return;
+ }
+
+ /* got complete pkt */
+ xrdpvr->got_partial_data = 0;
+ xrdpvr->bytes_needed = 0;
+ s = data_in;
+ }
+
+ stream_read_uint32(s, cmd);
+ switch (cmd)
+ {
+ case CMD_SEND_VIDEO_DATA:
+ stream_read_uint32(s, tmp); /* stream id LK_TODO use this */
+ stream_read_uint32(s, data_len);
+
+ /* LK_TODO : s->p must be FF_INPUT_BUFFER_PADDING_SIZE padded */
+#if 0
+ rv = xrdpvr_decode((void *) xrdpvr->decoder, data_len, s->p, 0);
+#else
+ rv = xrdpvr_decode((void *) xrdpvr->decoder, data_len, s->p, 1);
+
+#endif
+ s->p += data_len;
+ if (rv != 0)
+ {
+ /* LK_TODO need to handle error */
+ goto end;
+ }
+ break;
+
+ case CMD_SET_VIDEO_FORMAT:
+ stream_read_uint32(s, media_info.MajorType);
+ stream_read_uint32(s, media_info.stream_id);
+ stream_read_uint32(s, media_info.SubType);
+ stream_read_uint32(s, media_info.FormatType);
+ stream_read_uint32(s, media_info.width);
+ stream_read_uint32(s, media_info.height);
+ stream_read_uint32(s, media_info.bit_rate);
+ stream_read_uint32(s, media_info.samples_per_sec_num);
+ stream_read_uint32(s, media_info.samples_per_sec_den);
+ stream_read_uint32(s, media_info.ExtraDataSize);
+ if (media_info.ExtraDataSize)
+ {
+ /* LK_TODO where is this getting freed? */
+ media_info.ExtraData = malloc(media_info.ExtraDataSize);
+ stream_read(s, media_info.ExtraData, media_info.ExtraDataSize);
+ }
+ else
+ {
+ media_info.ExtraData = NULL;
+ }
+
+ printf("### got CMD_SET_VIDEO_FORMAT\n");
+ printf("### MajorType=%d stream_id=%d SubType=0x%x FormatType=0x%x width=%d height=%d bit_rate=%d "
+ "samples_per_sec_num=%d samples_per_sec_den=%d ExtraDataSize=%d\n",
+ media_info.MajorType, media_info.stream_id, media_info.SubType, media_info.FormatType,
+ media_info.width, media_info.height, media_info.bit_rate, media_info.samples_per_sec_num,
+ media_info.samples_per_sec_den, media_info.ExtraDataSize);
+
+ if (xrdpvr_set_format(xrdpvr->decoder, &media_info) != 0)
+ {
+ /* LK_TODO need to handle error */
+ printf("### xrdpvr_set_format() failed\n");
+ goto end;
+ }
+ printf("### xrdpvr_set_format() passed\n");
+ printf("\n\n................................................................\n\n");
+ break;
+
+ case CMD_SET_AUDIO_FORMAT:
+ printf("### LK_TODO: got CMD_SET_AUDIO_FORMAT\n");
+ break;
+
+ default:
+ printf("### got unknown command 0x%x %d(.)\n", cmd, cmd);
+ break;
+ }
+
+end:
+
+ if (s == xrdpvr->s)
+ {
+ /* we just finished processing a fragmented pkt; */
+ /* did we get part of the next command as well? */
+
+ i = stream_get_length(xrdpvr->s);
+ if (bytes_to_process > i)
+ {
+ /* yes we did - copy this to data_in and start all over */
+ printf("### xrdpvr_process_receive: got part of next command\n");
+ memcpy(data_in->data, s->p, bytes_to_process - i);
+ data_in->p = data_in->data;
+ xrdpvr->got_partial_data = 0;
+ xrdpvr->bytes_needed = 0;
+ bytes_to_process = 0;
+ goto start;
+ }
+ }
+
+ stream_free(data_in);
+
+// LK_TODO
+#if 0
+ if (bytes > 0)
+ {
+ data_out = stream_new(bytes);
+ stream_copy(data_out, data_in, bytes);
+
+ /*
+ * svc_plugin_send takes ownership of data_out,
+ * that is why we do not free it
+ */
+
+ bytes = stream_get_length(data_in);
+ printf("xrdpvr: xrdpvr_process_receive: sending bytes %d\n", bytes);
+
+ svc_plugin_send(plugin, data_out);
+ }
+#endif
+}
+
+/*
+ ******************************************************************************/
+static void xrdpvr_process_connect(rdpSvcPlugin* plugin_p)
+{
+ xrdpvrPlugin* plugin = (xrdpvrPlugin*) plugin_p;
+
+ if (plugin == NULL)
+ return;
+
+ /* if you want a call from channel thread once is a while do this */
+// LK_TODO
+#if 0
+ plugin_p->interval_ms = 10000000; // LK_TODO
+ plugin_p->interval_callback = xrdpvr_process_interval;
+#endif
+
+ /* setup stream */
+ plugin->s = stream_new(1024 * 1024);
+ plugin->got_partial_data = 0;
+ plugin->bytes_needed = 0;
+
+ /* setup ffmpeg */
+ plugin->decoder = xrdpvr_init();
+}
+
+/*
+ ******************************************************************************/
+static void xrdpvr_process_event(rdpSvcPlugin* plugin, RDP_EVENT* event)
+{
+ printf("xrdpvr: xrdpvr_process_event:\n");
+
+ /* events comming from main freerdp window to plugin */
+ /* send them back with svc_plugin_send_event */
+
+ freerdp_event_free(event);
+}
+
+/*
+ ******************************************************************************/
+static void xrdpvr_process_terminate(rdpSvcPlugin* plugin)
+{
+ xrdpvrPlugin* xrdpvr = (xrdpvrPlugin*) plugin;
+
+ printf("xrdpvr: xrdpvr_process_terminate:\n");
+
+ if (xrdpvr == NULL)
+ return;
+
+ stream_free(xrdpvr->s);
+ xfree(plugin);
+}
+
+DEFINE_SVC_PLUGIN(xrdpvr, "xrdpvr",
+ CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP)
diff --git a/channels/xrdpvr/xrdpvr_main.h b/channels/xrdpvr/xrdpvr_main.h
new file mode 100644
index 0000000..2b3806c
--- /dev/null
+++ b/channels/xrdpvr/xrdpvr_main.h
@@ -0,0 +1,29 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Xrdp video redirection channel
+ *
+ * Copyright 2012 Laxmikant Rashinkar <LK.Rashinkar@gmail.com>
+ *
+ * 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 __XRDPVR_MAIN_H
+#define __XRDPVR_MAIN_H
+
+typedef struct xrdpvr_plugin xrdpvrPlugin;
+
+#define CMD_SET_VIDEO_FORMAT 1
+#define CMD_SET_AUDIO_FORMAT 2
+#define CMD_SEND_VIDEO_DATA 3
+
+#endif /* __XRDPVR_MAIN_H */