diff options
author | Laxmikant Rashinkar <LK.Rashinkar@gmail.com> | 2012-10-22 03:52:28 +0400 |
---|---|---|
committer | Laxmikant Rashinkar <LK.Rashinkar@gmail.com> | 2012-10-22 03:52:28 +0400 |
commit | 211c036b1f218cad5190c507457677f0bb0e91e9 (patch) | |
tree | fd08d6ee96dd1b8373491ee207cc8f4a39785cd8 /channels | |
parent | 2ef1293fc4671b2407b301da7525bc0aa2ddacb9 (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.txt | 26 | ||||
-rw-r--r-- | channels/xrdpvr/xrdpvr_common.h | 38 | ||||
-rw-r--r-- | channels/xrdpvr/xrdpvr_ffmpeg.c | 525 | ||||
-rw-r--r-- | channels/xrdpvr/xrdpvr_main.c | 305 | ||||
-rw-r--r-- | channels/xrdpvr/xrdpvr_main.h | 29 |
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 */ |