mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-15 00:44:19 +09:00
Merge pull request #2198 from awakecoding/master
Shadow Pointers, X11 XAllocColor Fix, TSMF Cleanup, Cliprdr Update
This commit is contained in:
@@ -28,7 +28,6 @@
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include <freerdp/channels/log.h>
|
||||
#include <freerdp/utils/event.h>
|
||||
#include <freerdp/client/tsmf.h>
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
@@ -83,11 +82,11 @@ typedef struct _TSMFFFmpegDecoder
|
||||
UINT32 decoded_size_max;
|
||||
} TSMFFFmpegDecoder;
|
||||
|
||||
static BOOL tsmf_ffmpeg_init_context(ITSMFDecoder *decoder)
|
||||
static BOOL tsmf_ffmpeg_init_context(ITSMFDecoder* decoder)
|
||||
{
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
mdecoder->codec_context = avcodec_alloc_context3(NULL);
|
||||
if(!mdecoder->codec_context)
|
||||
if (!mdecoder->codec_context)
|
||||
{
|
||||
WLog_ERR(TAG, "avcodec_alloc_context failed.");
|
||||
return FALSE;
|
||||
@@ -95,9 +94,9 @@ static BOOL tsmf_ffmpeg_init_context(ITSMFDecoder *decoder)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_init_video_stream(ITSMFDecoder *decoder, const TS_AM_MEDIA_TYPE *media_type)
|
||||
static BOOL tsmf_ffmpeg_init_video_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE *media_type)
|
||||
{
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
mdecoder->codec_context->width = media_type->Width;
|
||||
mdecoder->codec_context->height = media_type->Height;
|
||||
mdecoder->codec_context->bit_rate = media_type->BitRate;
|
||||
@@ -107,9 +106,9 @@ static BOOL tsmf_ffmpeg_init_video_stream(ITSMFDecoder *decoder, const TS_AM_MED
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_init_audio_stream(ITSMFDecoder *decoder, const TS_AM_MEDIA_TYPE *media_type)
|
||||
static BOOL tsmf_ffmpeg_init_audio_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE *media_type)
|
||||
{
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
mdecoder->codec_context->sample_rate = media_type->SamplesPerSecond.Numerator;
|
||||
mdecoder->codec_context->bit_rate = media_type->BitRate;
|
||||
mdecoder->codec_context->channels = media_type->Channels;
|
||||
@@ -134,34 +133,34 @@ static BOOL tsmf_ffmpeg_init_audio_stream(ITSMFDecoder *decoder, const TS_AM_MED
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder *decoder, const TS_AM_MEDIA_TYPE *media_type)
|
||||
static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE *media_type)
|
||||
{
|
||||
BYTE *p;
|
||||
UINT32 size;
|
||||
const BYTE *s;
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
mdecoder->codec = avcodec_find_decoder(mdecoder->codec_id);
|
||||
if(!mdecoder->codec)
|
||||
if (!mdecoder->codec)
|
||||
{
|
||||
WLog_ERR(TAG, "avcodec_find_decoder failed.");
|
||||
return FALSE;
|
||||
}
|
||||
mdecoder->codec_context->codec_id = mdecoder->codec_id;
|
||||
mdecoder->codec_context->codec_type = mdecoder->media_type;
|
||||
if(mdecoder->media_type == AVMEDIA_TYPE_VIDEO)
|
||||
if (mdecoder->media_type == AVMEDIA_TYPE_VIDEO)
|
||||
{
|
||||
if(!tsmf_ffmpeg_init_video_stream(decoder, media_type))
|
||||
if (!tsmf_ffmpeg_init_video_stream(decoder, media_type))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
if(mdecoder->media_type == AVMEDIA_TYPE_AUDIO)
|
||||
if (mdecoder->media_type == AVMEDIA_TYPE_AUDIO)
|
||||
{
|
||||
if(!tsmf_ffmpeg_init_audio_stream(decoder, media_type))
|
||||
if (!tsmf_ffmpeg_init_audio_stream(decoder, media_type))
|
||||
return FALSE;
|
||||
}
|
||||
if(media_type->ExtraData)
|
||||
if (media_type->ExtraData)
|
||||
{
|
||||
if(media_type->SubType == TSMF_SUB_TYPE_AVC1 &&
|
||||
if (media_type->SubType == TSMF_SUB_TYPE_AVC1 &&
|
||||
media_type->FormatType == TSMF_FORMAT_TYPE_MPEG2VIDEOINFO)
|
||||
{
|
||||
/* The extradata format that FFmpeg uses is following CodecPrivate in Matroska.
|
||||
@@ -195,15 +194,15 @@ static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder *decoder, const TS_AM_MEDIA_TYP
|
||||
memset(mdecoder->codec_context->extradata + media_type->ExtraDataSize, 0, 8);
|
||||
}
|
||||
}
|
||||
if(mdecoder->codec->capabilities & CODEC_CAP_TRUNCATED)
|
||||
if (mdecoder->codec->capabilities & CODEC_CAP_TRUNCATED)
|
||||
mdecoder->codec_context->flags |= CODEC_FLAG_TRUNCATED;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_prepare(ITSMFDecoder *decoder)
|
||||
static BOOL tsmf_ffmpeg_prepare(ITSMFDecoder* decoder)
|
||||
{
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
if(avcodec_open2(mdecoder->codec_context, mdecoder->codec, NULL) < 0)
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
if (avcodec_open2(mdecoder->codec_context, mdecoder->codec, NULL) < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "avcodec_open2 failed.");
|
||||
return FALSE;
|
||||
@@ -212,9 +211,9 @@ static BOOL tsmf_ffmpeg_prepare(ITSMFDecoder *decoder)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *media_type)
|
||||
static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE *media_type)
|
||||
{
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
switch(media_type->MajorType)
|
||||
{
|
||||
case TSMF_MAJOR_TYPE_VIDEO:
|
||||
@@ -254,7 +253,7 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *medi
|
||||
/* 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_type->ExtraData)
|
||||
if (media_type->ExtraData)
|
||||
{
|
||||
media_type->ExtraData += 12;
|
||||
media_type->ExtraDataSize -= 12;
|
||||
@@ -270,18 +269,18 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *medi
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
if(!tsmf_ffmpeg_init_context(decoder))
|
||||
if (!tsmf_ffmpeg_init_context(decoder))
|
||||
return FALSE;
|
||||
if(!tsmf_ffmpeg_init_stream(decoder, media_type))
|
||||
if (!tsmf_ffmpeg_init_stream(decoder, media_type))
|
||||
return FALSE;
|
||||
if(!tsmf_ffmpeg_prepare(decoder))
|
||||
if (!tsmf_ffmpeg_prepare(decoder))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions)
|
||||
static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder* decoder, const BYTE *data, UINT32 data_size, UINT32 extensions)
|
||||
{
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
int decoded;
|
||||
int len;
|
||||
AVFrame *frame;
|
||||
@@ -294,12 +293,12 @@ static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder *decoder, const BYTE *data, UI
|
||||
av_init_packet(&pkt);
|
||||
pkt.data = (BYTE *) data;
|
||||
pkt.size = data_size;
|
||||
if(extensions & TSMM_SAMPLE_EXT_CLEANPOINT)
|
||||
if (extensions & TSMM_SAMPLE_EXT_CLEANPOINT)
|
||||
pkt.flags |= AV_PKT_FLAG_KEY;
|
||||
len = avcodec_decode_video2(mdecoder->codec_context, mdecoder->frame, &decoded, &pkt);
|
||||
}
|
||||
#endif
|
||||
if(len < 0)
|
||||
if (len < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "data_size %d, avcodec_decode_video failed (%d)", data_size, len);
|
||||
ret = FALSE;
|
||||
@@ -334,9 +333,9 @@ static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder *decoder, const BYTE *data, UI
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions)
|
||||
static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder* decoder, const BYTE *data, UINT32 data_size, UINT32 extensions)
|
||||
{
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
int len;
|
||||
int frame_size;
|
||||
UINT32 src_size;
|
||||
@@ -349,11 +348,11 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder *decoder, const BYTE *data, UI
|
||||
for(i = 0; i < data_size; i++)
|
||||
{
|
||||
WLog_DBG(TAG, ("%02X ", data[i]));
|
||||
if(i % 16 == 15)
|
||||
if (i % 16 == 15)
|
||||
WLog_DBG(TAG, ("\n"));
|
||||
}
|
||||
#endif
|
||||
if(mdecoder->decoded_size_max == 0)
|
||||
if (mdecoder->decoded_size_max == 0)
|
||||
mdecoder->decoded_size_max = MAX_AUDIO_FRAME_SIZE + 16;
|
||||
mdecoder->decoded_data = malloc(mdecoder->decoded_size_max);
|
||||
ZeroMemory(mdecoder->decoded_data, mdecoder->decoded_size_max);
|
||||
@@ -365,12 +364,12 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder *decoder, const BYTE *data, UI
|
||||
while(src_size > 0)
|
||||
{
|
||||
/* Ensure enough space for decoding */
|
||||
if(mdecoder->decoded_size_max - mdecoder->decoded_size < MAX_AUDIO_FRAME_SIZE)
|
||||
if (mdecoder->decoded_size_max - mdecoder->decoded_size < MAX_AUDIO_FRAME_SIZE)
|
||||
{
|
||||
mdecoder->decoded_size_max = mdecoder->decoded_size_max * 2 + 16;
|
||||
mdecoder->decoded_data = realloc(mdecoder->decoded_data, mdecoder->decoded_size_max);
|
||||
dst = (BYTE *)(((uintptr_t)mdecoder->decoded_data + 15) & ~ 0x0F);
|
||||
if(dst - mdecoder->decoded_data != dst_offset)
|
||||
if (dst - mdecoder->decoded_data != dst_offset)
|
||||
{
|
||||
/* re-align the memory if the alignment has changed after realloc */
|
||||
memmove(dst, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size);
|
||||
@@ -391,7 +390,7 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder *decoder, const BYTE *data, UI
|
||||
pkt.data = (BYTE *) src;
|
||||
pkt.size = src_size;
|
||||
len = avcodec_decode_audio4(mdecoder->codec_context, decoded_frame, &got_frame, &pkt);
|
||||
if(len >= 0 && got_frame)
|
||||
if (len >= 0 && got_frame)
|
||||
{
|
||||
frame_size = av_samples_get_buffer_size(NULL, mdecoder->codec_context->channels,
|
||||
decoded_frame->nb_samples, mdecoder->codec_context->sample_fmt, 1);
|
||||
@@ -400,7 +399,7 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder *decoder, const BYTE *data, UI
|
||||
av_free(decoded_frame);
|
||||
}
|
||||
#endif
|
||||
if(len <= 0 || frame_size <= 0)
|
||||
if (len <= 0 || frame_size <= 0)
|
||||
{
|
||||
WLog_ERR(TAG, "error decoding");
|
||||
break;
|
||||
@@ -410,13 +409,13 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder *decoder, const BYTE *data, UI
|
||||
mdecoder->decoded_size += frame_size;
|
||||
dst += frame_size;
|
||||
}
|
||||
if(mdecoder->decoded_size == 0)
|
||||
if (mdecoder->decoded_size == 0)
|
||||
{
|
||||
free(mdecoder->decoded_data);
|
||||
mdecoder->decoded_data = NULL;
|
||||
}
|
||||
else
|
||||
if(dst_offset)
|
||||
if (dst_offset)
|
||||
{
|
||||
/* move the aligned decoded data to original place */
|
||||
memmove(mdecoder->decoded_data, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size);
|
||||
@@ -426,10 +425,10 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder *decoder, const BYTE *data, UI
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_decode(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions)
|
||||
static BOOL tsmf_ffmpeg_decode(ITSMFDecoder* decoder, const BYTE *data, UINT32 data_size, UINT32 extensions)
|
||||
{
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
if(mdecoder->decoded_data)
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
if (mdecoder->decoded_data)
|
||||
{
|
||||
free(mdecoder->decoded_data);
|
||||
mdecoder->decoded_data = NULL;
|
||||
@@ -447,10 +446,10 @@ static BOOL tsmf_ffmpeg_decode(ITSMFDecoder *decoder, const BYTE *data, UINT32 d
|
||||
}
|
||||
}
|
||||
|
||||
static BYTE *tsmf_ffmpeg_get_decoded_data(ITSMFDecoder *decoder, UINT32 *size)
|
||||
static BYTE *tsmf_ffmpeg_get_decoded_data(ITSMFDecoder* decoder, UINT32 *size)
|
||||
{
|
||||
BYTE *buf;
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
*size = mdecoder->decoded_size;
|
||||
buf = mdecoder->decoded_data;
|
||||
mdecoder->decoded_data = NULL;
|
||||
@@ -458,10 +457,11 @@ static BYTE *tsmf_ffmpeg_get_decoded_data(ITSMFDecoder *decoder, UINT32 *size)
|
||||
return buf;
|
||||
}
|
||||
|
||||
static UINT32 tsmf_ffmpeg_get_decoded_format(ITSMFDecoder *decoder)
|
||||
static UINT32 tsmf_ffmpeg_get_decoded_format(ITSMFDecoder* decoder)
|
||||
{
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
switch(mdecoder->codec_context->pix_fmt)
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
switch (mdecoder->codec_context->pix_fmt)
|
||||
{
|
||||
case PIX_FMT_YUV420P:
|
||||
return RDP_PIXFMT_I420;
|
||||
@@ -472,10 +472,11 @@ static UINT32 tsmf_ffmpeg_get_decoded_format(ITSMFDecoder *decoder)
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_get_decoded_dimension(ITSMFDecoder *decoder, UINT32 *width, UINT32 *height)
|
||||
static BOOL tsmf_ffmpeg_get_decoded_dimension(ITSMFDecoder* decoder, UINT32 *width, UINT32 *height)
|
||||
{
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
if(mdecoder->codec_context->width > 0 && mdecoder->codec_context->height > 0)
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
if (mdecoder->codec_context->width > 0 && mdecoder->codec_context->height > 0)
|
||||
{
|
||||
*width = mdecoder->codec_context->width;
|
||||
*height = mdecoder->codec_context->height;
|
||||
@@ -487,18 +488,18 @@ static BOOL tsmf_ffmpeg_get_decoded_dimension(ITSMFDecoder *decoder, UINT32 *wid
|
||||
}
|
||||
}
|
||||
|
||||
static void tsmf_ffmpeg_free(ITSMFDecoder *decoder)
|
||||
static void tsmf_ffmpeg_free(ITSMFDecoder* decoder)
|
||||
{
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
if(mdecoder->frame)
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
if (mdecoder->frame)
|
||||
av_free(mdecoder->frame);
|
||||
if(mdecoder->decoded_data)
|
||||
if (mdecoder->decoded_data)
|
||||
free(mdecoder->decoded_data);
|
||||
if(mdecoder->codec_context)
|
||||
if (mdecoder->codec_context)
|
||||
{
|
||||
if(mdecoder->prepared)
|
||||
if (mdecoder->prepared)
|
||||
avcodec_close(mdecoder->codec_context);
|
||||
if(mdecoder->codec_context->extradata)
|
||||
if (mdecoder->codec_context->extradata)
|
||||
free(mdecoder->codec_context->extradata);
|
||||
av_free(mdecoder->codec_context);
|
||||
}
|
||||
@@ -511,23 +512,29 @@ static BOOL initialized = FALSE;
|
||||
#define freerdp_tsmf_client_subsystem_entry ffmpeg_freerdp_tsmf_client_decoder_subsystem_entry
|
||||
#endif
|
||||
|
||||
ITSMFDecoder *freerdp_tsmf_client_subsystem_entry(void)
|
||||
ITSMFDecoder* freerdp_tsmf_client_subsystem_entry(void)
|
||||
{
|
||||
TSMFFFmpegDecoder *decoder;
|
||||
if(!initialized)
|
||||
TSMFFFmpegDecoder* decoder;
|
||||
|
||||
if (!initialized)
|
||||
{
|
||||
avcodec_register_all();
|
||||
initialized = TRUE;
|
||||
}
|
||||
|
||||
WLog_DBG(TAG, "TSMFDecoderEntry FFMPEG");
|
||||
decoder = (TSMFFFmpegDecoder*) malloc(sizeof(TSMFFFmpegDecoder));
|
||||
ZeroMemory(decoder, sizeof(TSMFFFmpegDecoder));
|
||||
|
||||
decoder = (TSMFFFmpegDecoder*) calloc(1, sizeof(TSMFFFmpegDecoder));
|
||||
|
||||
if (!decoder)
|
||||
return NULL;
|
||||
|
||||
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;
|
||||
|
||||
return (ITSMFDecoder*) decoder;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -61,29 +59,34 @@ struct X11Handle
|
||||
Window subwin;
|
||||
};
|
||||
|
||||
static const char *get_shm_id()
|
||||
static const char* get_shm_id()
|
||||
{
|
||||
static char shm_id[64];
|
||||
snprintf(shm_id, sizeof(shm_id), "com.freerdp.xfreerpd.tsmf_%016X", GetCurrentProcessId());
|
||||
return shm_id;
|
||||
}
|
||||
|
||||
const char *tsmf_platform_get_video_sink(void)
|
||||
const char* tsmf_platform_get_video_sink(void)
|
||||
{
|
||||
return "xvimagesink";
|
||||
}
|
||||
|
||||
const char *tsmf_platform_get_audio_sink(void)
|
||||
const char* tsmf_platform_get_audio_sink(void)
|
||||
{
|
||||
return "autoaudiosink";
|
||||
}
|
||||
|
||||
int tsmf_platform_create(TSMFGstreamerDecoder *decoder)
|
||||
int tsmf_platform_create(TSMFGstreamerDecoder* decoder)
|
||||
{
|
||||
struct X11Handle *hdl;
|
||||
assert(decoder);
|
||||
assert(!decoder->platform);
|
||||
hdl = malloc(sizeof(struct X11Handle));
|
||||
struct X11Handle* hdl;
|
||||
|
||||
if (!decoder)
|
||||
return -1;
|
||||
|
||||
if (decoder->platform)
|
||||
return -1;
|
||||
|
||||
hdl = calloc(1, sizeof(struct X11Handle));
|
||||
|
||||
if (!hdl)
|
||||
{
|
||||
@@ -91,7 +94,6 @@ int tsmf_platform_create(TSMFGstreamerDecoder *decoder)
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(hdl, 0, sizeof(struct X11Handle));
|
||||
decoder->platform = hdl;
|
||||
hdl->shmid = shm_open(get_shm_id(), O_RDWR, PROT_READ | PROT_WRITE);;
|
||||
|
||||
@@ -101,9 +103,11 @@ int tsmf_platform_create(TSMFGstreamerDecoder *decoder)
|
||||
return -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
hdl->xfwin = mmap(0, sizeof(void *), PROT_READ | PROT_WRITE, MAP_SHARED, hdl->shmid, 0);
|
||||
}
|
||||
|
||||
if (hdl->xfwin == (int *)-1)
|
||||
if (hdl->xfwin == (int*)-1)
|
||||
{
|
||||
WLog_ERR(TAG, "shmat failed!");
|
||||
return -3;
|
||||
@@ -120,22 +124,30 @@ int tsmf_platform_create(TSMFGstreamerDecoder *decoder)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_platform_set_format(TSMFGstreamerDecoder *decoder)
|
||||
int tsmf_platform_set_format(TSMFGstreamerDecoder* decoder)
|
||||
{
|
||||
assert(decoder);
|
||||
if (!decoder)
|
||||
return -1;
|
||||
|
||||
if (decoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_platform_register_handler(TSMFGstreamerDecoder *decoder)
|
||||
int tsmf_platform_register_handler(TSMFGstreamerDecoder* decoder)
|
||||
{
|
||||
assert(decoder);
|
||||
assert(decoder->pipe);
|
||||
GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(decoder->pipe));
|
||||
GstBus* bus;
|
||||
|
||||
if (!decoder)
|
||||
return -1;
|
||||
|
||||
if (!decoder->pipe)
|
||||
return -1;
|
||||
|
||||
bus = gst_pipeline_get_bus(GST_PIPELINE(decoder->pipe));
|
||||
|
||||
if (!bus)
|
||||
{
|
||||
@@ -146,9 +158,9 @@ int tsmf_platform_register_handler(TSMFGstreamerDecoder *decoder)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_platform_free(TSMFGstreamerDecoder *decoder)
|
||||
int tsmf_platform_free(TSMFGstreamerDecoder* decoder)
|
||||
{
|
||||
struct X11Handle *hdl = decoder->platform;
|
||||
struct X11Handle* hdl = decoder->platform;
|
||||
|
||||
if (!hdl)
|
||||
return -1;
|
||||
@@ -157,18 +169,21 @@ int tsmf_platform_free(TSMFGstreamerDecoder *decoder)
|
||||
XCloseDisplay(hdl->disp);
|
||||
|
||||
if (hdl->xfwin)
|
||||
munmap(0, sizeof(void *));
|
||||
munmap(0, sizeof(void*));
|
||||
|
||||
if (hdl->shmid >= 0)
|
||||
close(hdl->shmid);
|
||||
|
||||
free(hdl);
|
||||
decoder->platform = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_window_create(TSMFGstreamerDecoder *decoder)
|
||||
int tsmf_window_create(TSMFGstreamerDecoder* decoder)
|
||||
{
|
||||
struct X11Handle* hdl;
|
||||
|
||||
if (decoder->media_type != TSMF_MAJOR_TYPE_VIDEO)
|
||||
{
|
||||
decoder->ready = TRUE;
|
||||
@@ -181,9 +196,14 @@ int tsmf_window_create(TSMFGstreamerDecoder *decoder)
|
||||
#else
|
||||
GstXOverlay *overlay = GST_X_OVERLAY(decoder->outsink);
|
||||
#endif
|
||||
struct X11Handle *hdl = (struct X11Handle *)decoder->platform;
|
||||
assert(decoder);
|
||||
assert(hdl);
|
||||
|
||||
if (!decoder)
|
||||
return -1;
|
||||
|
||||
if (!decoder->platform)
|
||||
return -1;
|
||||
|
||||
hdl = (struct X11Handle*) decoder->platform;
|
||||
|
||||
if (!hdl->subwin)
|
||||
{
|
||||
@@ -217,11 +237,15 @@ int tsmf_window_create(TSMFGstreamerDecoder *decoder)
|
||||
}
|
||||
}
|
||||
|
||||
int tsmf_window_resize(TSMFGstreamerDecoder *decoder, int x, int y, int width,
|
||||
int tsmf_window_resize(TSMFGstreamerDecoder* decoder, int x, int y, int width,
|
||||
int height, int nr_rects, RDP_RECT *rects)
|
||||
{
|
||||
struct X11Handle* hdl;
|
||||
|
||||
if (decoder->media_type != TSMF_MAJOR_TYPE_VIDEO)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if GST_VERSION_MAJOR > 0
|
||||
@@ -229,10 +253,15 @@ int tsmf_window_resize(TSMFGstreamerDecoder *decoder, int x, int y, int width,
|
||||
#else
|
||||
GstXOverlay *overlay = GST_X_OVERLAY(decoder->outsink);
|
||||
#endif
|
||||
struct X11Handle *hdl = (struct X11Handle *)decoder->platform;
|
||||
if (!decoder)
|
||||
return -1;
|
||||
|
||||
if (!decoder->platform)
|
||||
return -1;
|
||||
|
||||
hdl = (struct X11Handle*) decoder->platform;
|
||||
DEBUG_TSMF("resize: x=%d, y=%d, w=%d, h=%d", x, y, width, height);
|
||||
assert(decoder);
|
||||
assert(hdl);
|
||||
|
||||
#if GST_VERSION_MAJOR > 0
|
||||
|
||||
if (!gst_video_overlay_set_render_rectangle(overlay, 0, 0, width, height))
|
||||
@@ -280,28 +309,37 @@ int tsmf_window_resize(TSMFGstreamerDecoder *decoder, int x, int y, int width,
|
||||
}
|
||||
}
|
||||
|
||||
int tsmf_window_pause(TSMFGstreamerDecoder *decoder)
|
||||
int tsmf_window_pause(TSMFGstreamerDecoder* decoder)
|
||||
{
|
||||
assert(decoder);
|
||||
if (!decoder)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_window_resume(TSMFGstreamerDecoder *decoder)
|
||||
int tsmf_window_resume(TSMFGstreamerDecoder* decoder)
|
||||
{
|
||||
assert(decoder);
|
||||
if (!decoder)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_window_destroy(TSMFGstreamerDecoder *decoder)
|
||||
int tsmf_window_destroy(TSMFGstreamerDecoder* decoder)
|
||||
{
|
||||
struct X11Handle *hdl = (struct X11Handle *)decoder->platform;
|
||||
struct X11Handle* hdl;
|
||||
decoder->ready = FALSE;
|
||||
|
||||
if (decoder->media_type != TSMF_MAJOR_TYPE_VIDEO)
|
||||
return -3;
|
||||
|
||||
assert(decoder);
|
||||
assert(hdl);
|
||||
if (!decoder)
|
||||
return -1;
|
||||
|
||||
if (!decoder->platform)
|
||||
return -1;
|
||||
|
||||
hdl = (struct X11Handle*) decoder->platform;
|
||||
|
||||
if (hdl->subwin)
|
||||
{
|
||||
|
||||
@@ -43,14 +43,15 @@
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
static BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder);
|
||||
static void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder *mdecoder);
|
||||
static int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder,
|
||||
static BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder);
|
||||
static void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder* mdecoder);
|
||||
static int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder* mdecoder,
|
||||
GstState desired_state);
|
||||
|
||||
const char *get_type(TSMFGstreamerDecoder *mdecoder)
|
||||
const char* get_type(TSMFGstreamerDecoder* mdecoder)
|
||||
{
|
||||
assert(mdecoder);
|
||||
if (!mdecoder)
|
||||
return NULL;
|
||||
|
||||
if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
|
||||
return "VIDEO";
|
||||
@@ -60,28 +61,28 @@ const char *get_type(TSMFGstreamerDecoder *mdecoder)
|
||||
|
||||
static void tsmf_gstreamer_enough_data(GstAppSrc *src, gpointer user_data)
|
||||
{
|
||||
TSMFGstreamerDecoder *mdecoder = user_data;
|
||||
(void)mdecoder;
|
||||
TSMFGstreamerDecoder* mdecoder = user_data;
|
||||
(void) mdecoder;
|
||||
DEBUG_TSMF("%s", get_type(mdecoder));
|
||||
}
|
||||
|
||||
static void tsmf_gstreamer_need_data(GstAppSrc *src, guint length, gpointer user_data)
|
||||
{
|
||||
TSMFGstreamerDecoder *mdecoder = user_data;
|
||||
(void)mdecoder;
|
||||
TSMFGstreamerDecoder* mdecoder = user_data;
|
||||
(void) mdecoder;
|
||||
DEBUG_TSMF("%s length=%lu", get_type(mdecoder), length);
|
||||
}
|
||||
|
||||
static gboolean tsmf_gstreamer_seek_data(GstAppSrc *src, guint64 offset, gpointer user_data)
|
||||
{
|
||||
TSMFGstreamerDecoder *mdecoder = user_data;
|
||||
(void)mdecoder;
|
||||
TSMFGstreamerDecoder* mdecoder = user_data;
|
||||
(void) mdecoder;
|
||||
DEBUG_TSMF("%s offset=%llu", get_type(mdecoder), offset);
|
||||
|
||||
if (!mdecoder->paused)
|
||||
tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PAUSED);
|
||||
|
||||
gst_app_src_end_of_stream((GstAppSrc *)mdecoder->src);
|
||||
gst_app_src_end_of_stream((GstAppSrc*) mdecoder->src);
|
||||
|
||||
if (!mdecoder->paused)
|
||||
tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING);
|
||||
@@ -100,11 +101,11 @@ static inline const GstClockTime tsmf_gstreamer_timestamp_ms_to_gst(UINT64 ms_ti
|
||||
return (GstClockTime)(ms_timestamp * 100);
|
||||
}
|
||||
|
||||
int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, GstState desired_state)
|
||||
int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder* mdecoder, GstState desired_state)
|
||||
{
|
||||
GstStateChangeReturn state_change;
|
||||
const char *name;
|
||||
const char *sname = get_type(mdecoder);
|
||||
const char* name;
|
||||
const char* sname = get_type(mdecoder);
|
||||
|
||||
if (!mdecoder)
|
||||
return 0;
|
||||
@@ -120,24 +121,33 @@ int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, GstState d
|
||||
state_change = gst_element_set_state(mdecoder->pipe, desired_state);
|
||||
|
||||
if (state_change == GST_STATE_CHANGE_FAILURE)
|
||||
{
|
||||
WLog_ERR(TAG, "%s: (%s) GST_STATE_CHANGE_FAILURE.", sname, name);
|
||||
}
|
||||
else if (state_change == GST_STATE_CHANGE_ASYNC)
|
||||
{
|
||||
WLog_ERR(TAG, "%s: (%s) GST_STATE_CHANGE_ASYNC.", sname, name);
|
||||
mdecoder->state = desired_state;
|
||||
}
|
||||
else
|
||||
{
|
||||
mdecoder->state = desired_state;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static GstBuffer *tsmf_get_buffer_from_data(const void *raw_data, gsize size)
|
||||
static GstBuffer* tsmf_get_buffer_from_data(const void* raw_data, gsize size)
|
||||
{
|
||||
GstBuffer *buffer;
|
||||
GstBuffer* buffer;
|
||||
gpointer data;
|
||||
assert(raw_data);
|
||||
assert(size > 0);
|
||||
|
||||
if (!raw_data)
|
||||
return NULL;
|
||||
|
||||
if (size < 1)
|
||||
return NULL;
|
||||
|
||||
data = g_malloc(size);
|
||||
|
||||
if (!data)
|
||||
@@ -146,7 +156,8 @@ static GstBuffer *tsmf_get_buffer_from_data(const void *raw_data, gsize size)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(data, raw_data, size);
|
||||
CopyMemory(data, raw_data, size);
|
||||
|
||||
#if GST_VERSION_MAJOR > 0
|
||||
buffer = gst_buffer_new_wrapped(data, size);
|
||||
#else
|
||||
@@ -163,12 +174,13 @@ static GstBuffer *tsmf_get_buffer_from_data(const void *raw_data, gsize size)
|
||||
GST_BUFFER_SIZE(buffer) = size;
|
||||
GST_BUFFER_DATA(buffer) = GST_BUFFER_MALLOCDATA(buffer);
|
||||
#endif
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *media_type)
|
||||
static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* media_type)
|
||||
{
|
||||
TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*) decoder;
|
||||
|
||||
if (!mdecoder)
|
||||
return FALSE;
|
||||
@@ -377,7 +389,6 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m
|
||||
|
||||
void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder* mdecoder)
|
||||
{
|
||||
//Cleaning up elements
|
||||
if (!mdecoder || !mdecoder->pipe)
|
||||
return;
|
||||
|
||||
@@ -393,11 +404,11 @@ void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder* mdecoder)
|
||||
mdecoder->src = NULL;
|
||||
}
|
||||
|
||||
BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder)
|
||||
BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder)
|
||||
{
|
||||
const char *appsrc = "appsrc name=source ! decodebin name=decoder !";
|
||||
const char *video = "autovideoconvert ! videoscale !";
|
||||
const char *audio = "audioconvert ! audiorate ! audioresample ! volume name=audiovolume !";
|
||||
const char* appsrc = "appsrc name=source ! decodebin name=decoder !";
|
||||
const char* video = "autovideoconvert ! videoscale !";
|
||||
const char* audio = "audioconvert ! audiorate ! audioresample ! volume name=audiovolume !";
|
||||
char pipeline[1024];
|
||||
|
||||
if (!mdecoder)
|
||||
@@ -467,16 +478,16 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder)
|
||||
mdecoder->pipeline_start_time_valid = 0;
|
||||
mdecoder->shutdown = 0;
|
||||
|
||||
GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(mdecoder->pipe), GST_DEBUG_GRAPH_SHOW_ALL, get_type(mdecoder));
|
||||
GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(mdecoder->pipe), GST_DEBUG_GRAPH_SHOW_ALL, get_type(mdecoder));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions,
|
||||
static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder, const BYTE *data, UINT32 data_size, UINT32 extensions,
|
||||
UINT64 start_time, UINT64 end_time, UINT64 duration)
|
||||
{
|
||||
GstBuffer *gst_buf;
|
||||
TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
UINT64 sample_time = tsmf_gstreamer_timestamp_ms_to_gst(start_time);
|
||||
UINT64 sample_duration = tsmf_gstreamer_timestamp_ms_to_gst(duration);
|
||||
|
||||
@@ -570,9 +581,9 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder *decoder, const BYTE *data, UIN
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void tsmf_gstreamer_change_volume(ITSMFDecoder *decoder, UINT32 newVolume, UINT32 muted)
|
||||
static void tsmf_gstreamer_change_volume(ITSMFDecoder* decoder, UINT32 newVolume, UINT32 muted)
|
||||
{
|
||||
TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
|
||||
if (!mdecoder || !mdecoder->pipe)
|
||||
return;
|
||||
@@ -595,9 +606,9 @@ static void tsmf_gstreamer_change_volume(ITSMFDecoder *decoder, UINT32 newVolume
|
||||
g_object_set(mdecoder->volume, "volume", mdecoder->gstVolume, NULL);
|
||||
}
|
||||
|
||||
static void tsmf_gstreamer_control(ITSMFDecoder *decoder, ITSMFControlMsg control_msg, UINT32 *arg)
|
||||
static void tsmf_gstreamer_control(ITSMFDecoder* decoder, ITSMFControlMsg control_msg, UINT32 *arg)
|
||||
{
|
||||
TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
|
||||
if (!mdecoder)
|
||||
return;
|
||||
@@ -659,9 +670,9 @@ static void tsmf_gstreamer_control(ITSMFDecoder *decoder, ITSMFControlMsg contro
|
||||
WLog_ERR(TAG, "Unknown control message %08x", control_msg);
|
||||
}
|
||||
|
||||
static BOOL tsmf_gstreamer_buffer_filled(ITSMFDecoder *decoder)
|
||||
static BOOL tsmf_gstreamer_buffer_filled(ITSMFDecoder* decoder)
|
||||
{
|
||||
TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
DEBUG_TSMF("");
|
||||
|
||||
if (!mdecoder)
|
||||
@@ -673,9 +684,9 @@ static BOOL tsmf_gstreamer_buffer_filled(ITSMFDecoder *decoder)
|
||||
return clbuff >= buff_max ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static void tsmf_gstreamer_free(ITSMFDecoder *decoder)
|
||||
static void tsmf_gstreamer_free(ITSMFDecoder* decoder)
|
||||
{
|
||||
TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
DEBUG_TSMF("%s", get_type(mdecoder));
|
||||
|
||||
if (mdecoder)
|
||||
@@ -687,15 +698,15 @@ static void tsmf_gstreamer_free(ITSMFDecoder *decoder)
|
||||
gst_caps_unref(mdecoder->gst_caps);
|
||||
|
||||
tsmf_platform_free(mdecoder);
|
||||
memset(mdecoder, 0, sizeof(TSMFGstreamerDecoder));
|
||||
ZeroMemory(mdecoder, sizeof(TSMFGstreamerDecoder));
|
||||
free(mdecoder);
|
||||
mdecoder = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static UINT64 tsmf_gstreamer_get_running_time(ITSMFDecoder *decoder)
|
||||
static UINT64 tsmf_gstreamer_get_running_time(ITSMFDecoder* decoder)
|
||||
{
|
||||
TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
|
||||
if (!mdecoder)
|
||||
return 0;
|
||||
@@ -716,31 +727,33 @@ static UINT64 tsmf_gstreamer_get_running_time(ITSMFDecoder *decoder)
|
||||
return pos/100;
|
||||
}
|
||||
|
||||
static void tsmf_gstreamer_update_rendering_area(ITSMFDecoder *decoder,
|
||||
static void tsmf_gstreamer_update_rendering_area(ITSMFDecoder* decoder,
|
||||
int newX, int newY, int newWidth, int newHeight, int numRectangles,
|
||||
RDP_RECT *rectangles)
|
||||
{
|
||||
TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
DEBUG_TSMF("x=%d, y=%d, w=%d, h=%d, rect=%d", newX, newY, newWidth,
|
||||
newHeight, numRectangles);
|
||||
|
||||
if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
|
||||
{
|
||||
tsmf_window_resize(mdecoder, newX, newY, newWidth, newHeight,
|
||||
numRectangles, rectangles);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL tsmf_gstreamer_ack(ITSMFDecoder *decoder, BOOL (*cb)(void *, BOOL), void *stream)
|
||||
BOOL tsmf_gstreamer_ack(ITSMFDecoder* decoder, BOOL (*cb)(void *, BOOL), void *stream)
|
||||
{
|
||||
TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
DEBUG_TSMF("");
|
||||
mdecoder->ack_cb = cb;
|
||||
mdecoder->stream = stream;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL tsmf_gstreamer_sync(ITSMFDecoder *decoder, void (*cb)(void *), void *stream)
|
||||
BOOL tsmf_gstreamer_sync(ITSMFDecoder* decoder, void (*cb)(void *), void *stream)
|
||||
{
|
||||
TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder;
|
||||
DEBUG_TSMF("");
|
||||
mdecoder->sync_cb = NULL;
|
||||
mdecoder->stream = stream;
|
||||
@@ -751,7 +764,7 @@ BOOL tsmf_gstreamer_sync(ITSMFDecoder *decoder, void (*cb)(void *), void *stream
|
||||
#define freerdp_tsmf_client_subsystem_entry gstreamer_freerdp_tsmf_client_decoder_subsystem_entry
|
||||
#endif
|
||||
|
||||
ITSMFDecoder *freerdp_tsmf_client_subsystem_entry(void)
|
||||
ITSMFDecoder* freerdp_tsmf_client_subsystem_entry(void)
|
||||
{
|
||||
TSMFGstreamerDecoder *decoder;
|
||||
|
||||
@@ -760,8 +773,11 @@ ITSMFDecoder *freerdp_tsmf_client_subsystem_entry(void)
|
||||
gst_init(NULL, NULL);
|
||||
}
|
||||
|
||||
decoder = malloc(sizeof(TSMFGstreamerDecoder));
|
||||
memset(decoder, 0, sizeof(TSMFGstreamerDecoder));
|
||||
decoder = calloc(1, sizeof(TSMFGstreamerDecoder));
|
||||
|
||||
if (!decoder)
|
||||
return NULL;
|
||||
|
||||
decoder->iface.SetFormat = tsmf_gstreamer_set_format;
|
||||
decoder->iface.Decode = NULL;
|
||||
decoder->iface.GetDecodedData = NULL;
|
||||
@@ -780,6 +796,8 @@ ITSMFDecoder *freerdp_tsmf_client_subsystem_entry(void)
|
||||
decoder->gstVolume = 0.5;
|
||||
decoder->gstMuted = FALSE;
|
||||
decoder->state = GST_STATE_VOID_PENDING; /* No real state yet */
|
||||
|
||||
tsmf_platform_create(decoder);
|
||||
return (ITSMFDecoder *) decoder;
|
||||
|
||||
return (ITSMFDecoder*) decoder;
|
||||
}
|
||||
|
||||
@@ -59,25 +59,25 @@ typedef struct _TSMFGstreamerDecoder
|
||||
|
||||
} TSMFGstreamerDecoder;
|
||||
|
||||
const char *get_type(TSMFGstreamerDecoder *mdecoder);
|
||||
const char* get_type(TSMFGstreamerDecoder* mdecoder);
|
||||
|
||||
const char *tsmf_platform_get_video_sink(void);
|
||||
const char *tsmf_platform_get_audio_sink(void);
|
||||
const char* tsmf_platform_get_video_sink(void);
|
||||
const char* tsmf_platform_get_audio_sink(void);
|
||||
|
||||
int tsmf_platform_create(TSMFGstreamerDecoder *decoder);
|
||||
int tsmf_platform_set_format(TSMFGstreamerDecoder *decoder);
|
||||
int tsmf_platform_register_handler(TSMFGstreamerDecoder *decoder);
|
||||
int tsmf_platform_free(TSMFGstreamerDecoder *decoder);
|
||||
int tsmf_platform_create(TSMFGstreamerDecoder* decoder);
|
||||
int tsmf_platform_set_format(TSMFGstreamerDecoder* decoder);
|
||||
int tsmf_platform_register_handler(TSMFGstreamerDecoder* decoder);
|
||||
int tsmf_platform_free(TSMFGstreamerDecoder* decoder);
|
||||
|
||||
int tsmf_window_create(TSMFGstreamerDecoder *decoder);
|
||||
int tsmf_window_resize(TSMFGstreamerDecoder *decoder, int x, int y,
|
||||
int tsmf_window_create(TSMFGstreamerDecoder* decoder);
|
||||
int tsmf_window_resize(TSMFGstreamerDecoder* decoder, int x, int y,
|
||||
int width, int height, int nr_rect, RDP_RECT *visible);
|
||||
int tsmf_window_destroy(TSMFGstreamerDecoder *decoder);
|
||||
int tsmf_window_destroy(TSMFGstreamerDecoder* decoder);
|
||||
|
||||
int tsmf_window_pause(TSMFGstreamerDecoder *decoder);
|
||||
int tsmf_window_resume(TSMFGstreamerDecoder *decoder);
|
||||
int tsmf_window_pause(TSMFGstreamerDecoder* decoder);
|
||||
int tsmf_window_resume(TSMFGstreamerDecoder* decoder);
|
||||
|
||||
BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder *mdecoder);
|
||||
void tsmf_gstreamer_remove_pad(TSMFGstreamerDecoder *mdecoder);
|
||||
BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder* mdecoder);
|
||||
void tsmf_gstreamer_remove_pad(TSMFGstreamerDecoder* mdecoder);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -34,12 +34,12 @@ static ITSMFAudioDevice* tsmf_load_audio_device_by_name(const char* name, const
|
||||
|
||||
entry = (TSMF_AUDIO_DEVICE_ENTRY) freerdp_load_channel_addin_entry("tsmf", (LPSTR) name, "audio", 0);
|
||||
|
||||
if (entry == NULL)
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
audio = entry();
|
||||
|
||||
if (audio == NULL)
|
||||
if (!audio)
|
||||
{
|
||||
WLog_ERR(TAG, "failed to call export function in %s", name);
|
||||
return NULL;
|
||||
|
||||
@@ -22,13 +22,11 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/print.h>
|
||||
|
||||
#include "tsmf_decoder.h"
|
||||
#include "tsmf_constants.h"
|
||||
#include "tsmf_types.h"
|
||||
|
||||
@@ -176,40 +174,64 @@ static const TSMFMediaTypeMap tsmf_sub_type_map[] =
|
||||
},
|
||||
|
||||
/* E436EB81-524F-11CE-9F53-0020AF0BA770 */
|
||||
/*
|
||||
{
|
||||
{ 0x81, 0xEB, 0x36, 0xE4, 0x4F, 0x52, 0xCE, 0x11, 0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70 },
|
||||
"MEDIASUBTYPE_MP1V",
|
||||
TSMF_SUB_TYPE_MP1V
|
||||
},
|
||||
*/
|
||||
|
||||
/* 00000050-0000-0010-8000-00AA00389B71 */
|
||||
/*
|
||||
{
|
||||
{ 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
|
||||
"MEDIASUBTYPE_MP1A",
|
||||
TSMF_SUB_TYPE_MP1A
|
||||
},
|
||||
*/
|
||||
|
||||
/* E06D802C-DB46-11CF-B4D1-00805F6CBBEA */
|
||||
/*
|
||||
{
|
||||
{ 0x2C, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA },
|
||||
"MEDIASUBTYPE_DOLBY_AC3",
|
||||
TSMF_SUB_TYPE_AC3
|
||||
},
|
||||
*/
|
||||
|
||||
/* 32595559-0000-0010-8000-00AA00389B71 */
|
||||
/*
|
||||
{
|
||||
{ 0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
|
||||
"MEDIASUBTYPE_YUY2",
|
||||
TSMF_SUB_TYPE_YUY2
|
||||
},
|
||||
*/
|
||||
|
||||
/* Opencodec IDS */
|
||||
{
|
||||
{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71},
|
||||
"MEDIASUBTYPE_FLAC",
|
||||
TSMF_SUB_TYPE_FLAC
|
||||
},
|
||||
|
||||
{
|
||||
{0x61, 0x34, 0x70, 0x6D, 0x7A, 0x76, 0x4D, 0x49, 0xB4, 0x78, 0xF2, 0x9D, 0x25, 0xDC, 0x90, 0x37},
|
||||
"MEDIASUBTYPE_OGG",
|
||||
TSMF_SUB_TYPE_OGG
|
||||
},
|
||||
|
||||
{
|
||||
{0x4D, 0x34, 0x53, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71},
|
||||
"MEDIASUBTYPE_H263",
|
||||
TSMF_SUB_TYPE_H263
|
||||
},
|
||||
|
||||
/* WebMMF codec IDS */
|
||||
{
|
||||
{0x56, 0x50, 0x38, 0x30, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71},
|
||||
"MEDIASUBTYPE_VP8",
|
||||
TSMF_SUB_TYPE_VP8
|
||||
},
|
||||
|
||||
{
|
||||
{0x0B, 0xD1, 0x2F, 0x8D, 0x41, 0x58, 0x6B, 0x4A, 0x89, 0x05, 0x58, 0x8F, 0xEC, 0x1A, 0xDE, 0xD9},
|
||||
"MEDIASUBTYPE_OGG",
|
||||
TSMF_SUB_TYPE_OGG
|
||||
},
|
||||
|
||||
{
|
||||
{ 0 },
|
||||
@@ -525,13 +547,30 @@ BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s)
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL tsmf_codec_check_media_type(wStream* s)
|
||||
BOOL tsmf_codec_check_media_type(const char* decoder_name, wStream* s)
|
||||
{
|
||||
BYTE* m;
|
||||
BOOL ret;
|
||||
TS_AM_MEDIA_TYPE mediatype;
|
||||
|
||||
Stream_GetPointer(s, m);
|
||||
ret = tsmf_codec_parse_media_type(&mediatype, s);
|
||||
Stream_SetPointer(s, m);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
ITSMFDecoder* decoder = tsmf_load_decoder(decoder_name, &mediatype);
|
||||
|
||||
if (!decoder)
|
||||
{
|
||||
WLog_WARN(TAG, "Format not supported by decoder %s", decoder_name);
|
||||
ret = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
decoder->Free(decoder);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "tsmf_types.h"
|
||||
|
||||
BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s);
|
||||
BOOL tsmf_codec_check_media_type(wStream* s);
|
||||
BOOL tsmf_codec_check_media_type(const char* decoder_name, wStream* s);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -118,6 +118,13 @@
|
||||
#define TSMF_SUB_TYPE_MP43 17
|
||||
#define TSMF_SUB_TYPE_MP4S 18
|
||||
#define TSMF_SUB_TYPE_MP42 19
|
||||
#define TSMF_SUB_TYPE_OGG 20
|
||||
#define TSMF_SUB_TYPE_SPEEX 21
|
||||
#define TSMF_SUB_TYPE_THEORA 22
|
||||
#define TSMF_SUB_TYPE_FLAC 23
|
||||
#define TSMF_SUB_TYPE_VP8 24
|
||||
#define TSMF_SUB_TYPE_VP9 25
|
||||
#define TSMF_SUB_TYPE_H263 26
|
||||
|
||||
/* FormatType */
|
||||
#define TSMF_FORMAT_TYPE_UNKNOWN 0
|
||||
|
||||
@@ -32,41 +32,51 @@
|
||||
#include "tsmf_constants.h"
|
||||
#include "tsmf_decoder.h"
|
||||
|
||||
static ITSMFDecoder *tsmf_load_decoder_by_name(const char *name, TS_AM_MEDIA_TYPE *media_type)
|
||||
static ITSMFDecoder* tsmf_load_decoder_by_name(const char *name, TS_AM_MEDIA_TYPE *media_type)
|
||||
{
|
||||
ITSMFDecoder *decoder;
|
||||
ITSMFDecoder* decoder;
|
||||
TSMF_DECODER_ENTRY entry;
|
||||
|
||||
entry = (TSMF_DECODER_ENTRY) freerdp_load_channel_addin_entry("tsmf", (LPSTR) name, "decoder", 0);
|
||||
if(entry == NULL)
|
||||
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
decoder = entry();
|
||||
if(decoder == NULL)
|
||||
|
||||
if (!decoder)
|
||||
{
|
||||
WLog_ERR(TAG, "failed to call export function in %s", name);
|
||||
return NULL;
|
||||
}
|
||||
if(!decoder->SetFormat(decoder, media_type))
|
||||
|
||||
if (!decoder->SetFormat(decoder, media_type))
|
||||
{
|
||||
decoder->Free(decoder);
|
||||
decoder = NULL;
|
||||
}
|
||||
|
||||
return decoder;
|
||||
}
|
||||
|
||||
ITSMFDecoder *tsmf_load_decoder(const char *name, TS_AM_MEDIA_TYPE *media_type)
|
||||
ITSMFDecoder* tsmf_load_decoder(const char* name, TS_AM_MEDIA_TYPE* media_type)
|
||||
{
|
||||
ITSMFDecoder *decoder = NULL;
|
||||
if(name)
|
||||
ITSMFDecoder* decoder = NULL;
|
||||
|
||||
if (name)
|
||||
{
|
||||
decoder = tsmf_load_decoder_by_name(name, media_type);
|
||||
}
|
||||
|
||||
#if defined(WITH_GSTREAMER_1_0) || defined(WITH_GSTREAMER_0_10)
|
||||
if(!decoder)
|
||||
if (!decoder)
|
||||
decoder = tsmf_load_decoder_by_name("gstreamer", media_type);
|
||||
#endif
|
||||
|
||||
#if defined(WITH_FFMPEG)
|
||||
if(!decoder)
|
||||
if (!decoder)
|
||||
decoder = tsmf_load_decoder_by_name("ffmpeg", media_type);
|
||||
#endif
|
||||
|
||||
return decoder;
|
||||
}
|
||||
|
||||
@@ -37,18 +37,22 @@
|
||||
|
||||
#include "tsmf_ifman.h"
|
||||
|
||||
int tsmf_ifman_rim_exchange_capability_request(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_rim_exchange_capability_request(TSMF_IFMAN* ifman)
|
||||
{
|
||||
UINT32 CapabilityValue;
|
||||
|
||||
Stream_Read_UINT32(ifman->input, CapabilityValue);
|
||||
|
||||
DEBUG_TSMF("server CapabilityValue %d", CapabilityValue);
|
||||
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 8);
|
||||
Stream_Write_UINT32(ifman->output, 1); /* CapabilityValue */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* Result */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_exchange_capability_request(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman)
|
||||
{
|
||||
UINT32 i;
|
||||
UINT32 v;
|
||||
@@ -56,17 +60,20 @@ int tsmf_ifman_exchange_capability_request(TSMF_IFMAN *ifman)
|
||||
UINT32 CapabilityType;
|
||||
UINT32 cbCapabilityLength;
|
||||
UINT32 numHostCapabilities;
|
||||
|
||||
pos = Stream_GetPosition(ifman->output);
|
||||
Stream_EnsureRemainingCapacity(ifman->output, ifman->input_size + 4);
|
||||
Stream_Copy(ifman->output, ifman->input, ifman->input_size);
|
||||
Stream_SetPosition(ifman->output, pos);
|
||||
Stream_Read_UINT32(ifman->output, numHostCapabilities);
|
||||
for(i = 0; i < numHostCapabilities; i++)
|
||||
|
||||
for (i = 0; i < numHostCapabilities; i++)
|
||||
{
|
||||
Stream_Read_UINT32(ifman->output, CapabilityType);
|
||||
Stream_Read_UINT32(ifman->output, cbCapabilityLength);
|
||||
pos = Stream_GetPosition(ifman->output);
|
||||
switch(CapabilityType)
|
||||
|
||||
switch (CapabilityType)
|
||||
{
|
||||
case 1: /* Protocol version request */
|
||||
Stream_Read_UINT32(ifman->output, v);
|
||||
@@ -76,8 +83,7 @@ int tsmf_ifman_exchange_capability_request(TSMF_IFMAN *ifman)
|
||||
Stream_Peek_UINT32(ifman->output, v);
|
||||
DEBUG_TSMF("server supported platform %d", v);
|
||||
/* Claim that we support both MF and DShow platforms. */
|
||||
Stream_Write_UINT32(ifman->output,
|
||||
MMREDIR_CAPABILITY_PLATFORM_MF | MMREDIR_CAPABILITY_PLATFORM_DSHOW);
|
||||
Stream_Write_UINT32(ifman->output, MMREDIR_CAPABILITY_PLATFORM_MF | MMREDIR_CAPABILITY_PLATFORM_DSHOW);
|
||||
break;
|
||||
default:
|
||||
WLog_ERR(TAG, "unknown capability type %d", CapabilityType);
|
||||
@@ -85,63 +91,81 @@ int tsmf_ifman_exchange_capability_request(TSMF_IFMAN *ifman)
|
||||
}
|
||||
Stream_SetPosition(ifman->output, pos + cbCapabilityLength);
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(ifman->output, 0); /* Result */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_check_format_support_request(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_check_format_support_request(TSMF_IFMAN* ifman)
|
||||
{
|
||||
UINT32 numMediaType;
|
||||
UINT32 PlatformCookie;
|
||||
UINT32 FormatSupported = 1;
|
||||
|
||||
Stream_Read_UINT32(ifman->input, PlatformCookie);
|
||||
Stream_Seek_UINT32(ifman->input); /* NoRolloverFlags (4 bytes) */
|
||||
Stream_Read_UINT32(ifman->input, numMediaType);
|
||||
|
||||
DEBUG_TSMF("PlatformCookie %d numMediaType %d", PlatformCookie, numMediaType);
|
||||
if(!tsmf_codec_check_media_type(ifman->input))
|
||||
|
||||
if (!tsmf_codec_check_media_type(ifman->decoder_name, ifman->input))
|
||||
FormatSupported = 0;
|
||||
if(FormatSupported)
|
||||
|
||||
if (FormatSupported)
|
||||
DEBUG_TSMF("format ok.");
|
||||
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 12);
|
||||
Stream_Write_UINT32(ifman->output, FormatSupported);
|
||||
Stream_Write_UINT32(ifman->output, PlatformCookie);
|
||||
Stream_Write_UINT32(ifman->output, 0); /* Result */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_new_presentation(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_on_new_presentation(TSMF_IFMAN* ifman)
|
||||
{
|
||||
int status = 0;
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_TSMF("");
|
||||
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
if(presentation)
|
||||
|
||||
if (presentation)
|
||||
{
|
||||
DEBUG_TSMF("Presentation already exists");
|
||||
ifman->output_pending = FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
presentation = tsmf_presentation_new(Stream_Pointer(ifman->input), ifman->channel_callback);
|
||||
if(presentation == NULL)
|
||||
|
||||
if (!presentation)
|
||||
status = 1;
|
||||
else
|
||||
tsmf_presentation_set_audio_device(presentation, ifman->audio_name, ifman->audio_device);
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int tsmf_ifman_add_stream(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_add_stream(TSMF_IFMAN* ifman)
|
||||
{
|
||||
UINT32 StreamId;
|
||||
int status = 0;
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_STREAM* stream;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_TSMF("");
|
||||
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
Stream_Seek(ifman->input, 16);
|
||||
if(presentation == NULL)
|
||||
|
||||
if (!presentation)
|
||||
{
|
||||
status = 1;
|
||||
}
|
||||
@@ -150,14 +174,14 @@ int tsmf_ifman_add_stream(TSMF_IFMAN *ifman)
|
||||
Stream_Read_UINT32(ifman->input, StreamId);
|
||||
Stream_Seek_UINT32(ifman->input); /* numMediaType */
|
||||
stream = tsmf_stream_new(presentation, StreamId);
|
||||
if(stream)
|
||||
if (stream)
|
||||
tsmf_stream_set_format(stream, ifman->decoder_name, ifman->input);
|
||||
}
|
||||
ifman->output_pending = TRUE;
|
||||
return status;
|
||||
}
|
||||
|
||||
int tsmf_ifman_set_topology_request(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_set_topology_request(TSMF_IFMAN* ifman)
|
||||
{
|
||||
DEBUG_TSMF("");
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 8);
|
||||
@@ -167,16 +191,20 @@ int tsmf_ifman_set_topology_request(TSMF_IFMAN *ifman)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_remove_stream(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_remove_stream(TSMF_IFMAN* ifman)
|
||||
{
|
||||
int status = 0;
|
||||
UINT32 StreamId;
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_STREAM* stream;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_TSMF("");
|
||||
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
|
||||
Stream_Seek(ifman->input, 16);
|
||||
if(presentation == NULL)
|
||||
|
||||
if (!presentation)
|
||||
{
|
||||
status = 1;
|
||||
}
|
||||
@@ -184,12 +212,15 @@ int tsmf_ifman_remove_stream(TSMF_IFMAN *ifman)
|
||||
{
|
||||
Stream_Read_UINT32(ifman->input, StreamId);
|
||||
stream = tsmf_stream_find_by_id(presentation, StreamId);
|
||||
if(stream)
|
||||
|
||||
if (stream)
|
||||
tsmf_stream_free(stream);
|
||||
else
|
||||
status = 1;
|
||||
}
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -202,16 +233,20 @@ float tsmf_stream_read_float(wStream *s)
|
||||
return fValue;
|
||||
}
|
||||
|
||||
int tsmf_ifman_set_source_video_rect(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_set_source_video_rect(TSMF_IFMAN* ifman)
|
||||
{
|
||||
int status = 0;
|
||||
float Left, Top;
|
||||
float Right, Bottom;
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_TSMF("");
|
||||
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
|
||||
Stream_Seek(ifman->input, 16);
|
||||
if(!presentation)
|
||||
|
||||
if (!presentation)
|
||||
{
|
||||
status = 1;
|
||||
}
|
||||
@@ -224,31 +259,39 @@ int tsmf_ifman_set_source_video_rect(TSMF_IFMAN *ifman)
|
||||
DEBUG_TSMF("SetSourceVideoRect: Left: %f Top: %f Right: %f Bottom: %f",
|
||||
Left, Top, Right, Bottom);
|
||||
}
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int tsmf_ifman_shutdown_presentation(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_shutdown_presentation(TSMF_IFMAN* ifman)
|
||||
{
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_TSMF("");
|
||||
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
if(presentation)
|
||||
|
||||
if (presentation)
|
||||
tsmf_presentation_free(presentation);
|
||||
else
|
||||
WLog_ERR(TAG, "unknown presentation id");
|
||||
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 4);
|
||||
Stream_Write_UINT32(ifman->output, 0); /* Result */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_stream_volume(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_on_stream_volume(TSMF_IFMAN* ifman)
|
||||
{
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
DEBUG_TSMF("on stream volume");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
if(presentation)
|
||||
|
||||
if (presentation)
|
||||
{
|
||||
UINT32 newVolume;
|
||||
UINT32 muted;
|
||||
@@ -263,16 +306,21 @@ int tsmf_ifman_on_stream_volume(TSMF_IFMAN *ifman)
|
||||
{
|
||||
WLog_ERR(TAG, "unknown presentation id");
|
||||
}
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_channel_volume(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_on_channel_volume(TSMF_IFMAN* ifman)
|
||||
{
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_TSMF("on channel volume");
|
||||
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
if(presentation)
|
||||
|
||||
if (presentation)
|
||||
{
|
||||
UINT32 channelVolume;
|
||||
UINT32 changedChannel;
|
||||
@@ -282,20 +330,22 @@ int tsmf_ifman_on_channel_volume(TSMF_IFMAN *ifman)
|
||||
Stream_Read_UINT32(ifman->input, changedChannel);
|
||||
DEBUG_TSMF("on stream volume: changed channel=[%d]", changedChannel);
|
||||
}
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_set_video_window(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_set_video_window(TSMF_IFMAN* ifman)
|
||||
{
|
||||
DEBUG_TSMF("");
|
||||
ifman->output_pending = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_update_geometry_info(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman)
|
||||
{
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
UINT32 numGeometryInfo;
|
||||
UINT32 Left;
|
||||
UINT32 Top;
|
||||
@@ -321,17 +371,17 @@ int tsmf_ifman_update_geometry_info(TSMF_IFMAN *ifman)
|
||||
num_rects = cbVisibleRect / 16;
|
||||
DEBUG_TSMF("numGeometryInfo %d Width %d Height %d Left %d Top %d cbVisibleRect %d num_rects %d",
|
||||
numGeometryInfo, Width, Height, Left, Top, cbVisibleRect, num_rects);
|
||||
if(presentation == NULL)
|
||||
if (presentation == NULL)
|
||||
{
|
||||
error = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(num_rects > 0)
|
||||
if (num_rects > 0)
|
||||
{
|
||||
rects = (RDP_RECT *) malloc(sizeof(RDP_RECT) * num_rects);
|
||||
ZeroMemory(rects, sizeof(RDP_RECT) * num_rects);
|
||||
for(i = 0; i < num_rects; i++)
|
||||
rects = (RDP_RECT*) calloc(num_rects, sizeof(RDP_RECT));
|
||||
|
||||
for (i = 0; i < num_rects; i++)
|
||||
{
|
||||
Stream_Read_UINT16(ifman->input, rects[i].y); /* Top */
|
||||
Stream_Seek_UINT16(ifman->input);
|
||||
@@ -347,36 +397,40 @@ int tsmf_ifman_update_geometry_info(TSMF_IFMAN *ifman)
|
||||
rects[i].x, rects[i].y, rects[i].width, rects[i].height);
|
||||
}
|
||||
}
|
||||
|
||||
tsmf_presentation_set_geometry_info(presentation, Left, Top, Width, Height, num_rects, rects);
|
||||
}
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int tsmf_ifman_set_allocator(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_set_allocator(TSMF_IFMAN* ifman)
|
||||
{
|
||||
DEBUG_TSMF("");
|
||||
ifman->output_pending = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_notify_preroll(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_notify_preroll(TSMF_IFMAN* ifman)
|
||||
{
|
||||
DEBUG_TSMF("");
|
||||
ifman->output_pending = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_sample(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_on_sample(TSMF_IFMAN* ifman)
|
||||
{
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
TSMF_STREAM* stream;
|
||||
UINT32 StreamId;
|
||||
UINT64 SampleStartTime;
|
||||
UINT64 SampleEndTime;
|
||||
UINT64 ThrottleDuration;
|
||||
UINT32 SampleExtensions;
|
||||
UINT32 cbData;
|
||||
|
||||
Stream_Seek(ifman->input, 16);
|
||||
Stream_Read_UINT32(ifman->input, StreamId);
|
||||
Stream_Seek_UINT32(ifman->input); /* numSample */
|
||||
@@ -386,62 +440,81 @@ int tsmf_ifman_on_sample(TSMF_IFMAN *ifman)
|
||||
Stream_Seek_UINT32(ifman->input); /* SampleFlags */
|
||||
Stream_Read_UINT32(ifman->input, SampleExtensions);
|
||||
Stream_Read_UINT32(ifman->input, cbData);
|
||||
|
||||
DEBUG_TSMF("MessageId %d StreamId %d SampleStartTime %d SampleEndTime %d "
|
||||
"ThrottleDuration %d SampleExtensions %d cbData %d",
|
||||
ifman->message_id, StreamId, (int)SampleStartTime, (int)SampleEndTime,
|
||||
(int)ThrottleDuration, SampleExtensions, cbData);
|
||||
|
||||
presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
|
||||
if(presentation == NULL)
|
||||
|
||||
if (!presentation)
|
||||
{
|
||||
WLog_ERR(TAG, "unknown presentation id");
|
||||
return 1;
|
||||
}
|
||||
|
||||
stream = tsmf_stream_find_by_id(presentation, StreamId);
|
||||
if(stream == NULL)
|
||||
|
||||
if (!stream)
|
||||
{
|
||||
WLog_ERR(TAG, "unknown stream id");
|
||||
return 1;
|
||||
}
|
||||
|
||||
tsmf_stream_push_sample(stream, ifman->channel_callback,
|
||||
ifman->message_id, SampleStartTime, SampleEndTime, ThrottleDuration, SampleExtensions,
|
||||
cbData, Stream_Pointer(ifman->input));
|
||||
ifman->message_id, SampleStartTime, SampleEndTime,
|
||||
ThrottleDuration, SampleExtensions, cbData, Stream_Pointer(ifman->input));
|
||||
|
||||
tsmf_presentation_sync(presentation);
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_flush(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_on_flush(TSMF_IFMAN* ifman)
|
||||
{
|
||||
UINT32 StreamId;
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
Stream_Seek(ifman->input, 16);
|
||||
Stream_Read_UINT32(ifman->input, StreamId);
|
||||
|
||||
DEBUG_TSMF("StreamId %d", StreamId);
|
||||
|
||||
presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
|
||||
if(presentation == NULL)
|
||||
|
||||
if (!presentation)
|
||||
{
|
||||
WLog_ERR(TAG, "unknown presentation id");
|
||||
return 1;
|
||||
}
|
||||
|
||||
tsmf_presentation_flush(presentation);
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_end_of_stream(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_on_end_of_stream(TSMF_IFMAN* ifman)
|
||||
{
|
||||
UINT32 StreamId;
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_STREAM* stream;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
|
||||
Stream_Seek(ifman->input, 16);
|
||||
Stream_Read_UINT32(ifman->input, StreamId);
|
||||
if(presentation)
|
||||
|
||||
if (presentation)
|
||||
{
|
||||
stream = tsmf_stream_find_by_id(presentation, StreamId);
|
||||
if(stream)
|
||||
|
||||
if (stream)
|
||||
tsmf_stream_end(stream);
|
||||
}
|
||||
|
||||
DEBUG_TSMF("StreamId %d", StreamId);
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 16);
|
||||
Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
|
||||
@@ -449,74 +522,93 @@ int tsmf_ifman_on_end_of_stream(TSMF_IFMAN *ifman)
|
||||
Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_ENDOFSTREAM); /* EventId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* cbData */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_playback_started(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_on_playback_started(TSMF_IFMAN* ifman)
|
||||
{
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_TSMF("");
|
||||
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
if(presentation)
|
||||
|
||||
if (presentation)
|
||||
tsmf_presentation_start(presentation);
|
||||
else
|
||||
WLog_ERR(TAG, "unknown presentation id");
|
||||
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 16);
|
||||
Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* StreamId */
|
||||
Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_START_COMPLETED); /* EventId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* cbData */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_playback_paused(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_on_playback_paused(TSMF_IFMAN* ifman)
|
||||
{
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_TSMF("");
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
/* Added pause control so gstreamer pipeline can be paused accordingly */
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
if(presentation)
|
||||
|
||||
if (presentation)
|
||||
tsmf_presentation_paused(presentation);
|
||||
else
|
||||
WLog_ERR(TAG, "unknown presentation id");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_playback_restarted(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_on_playback_restarted(TSMF_IFMAN* ifman)
|
||||
{
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_TSMF("");
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
/* Added restart control so gstreamer pipeline can be resumed accordingly */
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
if(presentation)
|
||||
|
||||
if (presentation)
|
||||
tsmf_presentation_restarted(presentation);
|
||||
else
|
||||
WLog_ERR(TAG, "unknown presentation id");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_playback_stopped(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_on_playback_stopped(TSMF_IFMAN* ifman)
|
||||
{
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_TSMF("");
|
||||
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
if(presentation)
|
||||
|
||||
if (presentation)
|
||||
tsmf_presentation_stop(presentation);
|
||||
else
|
||||
WLog_ERR(TAG, "unknown presentation id");
|
||||
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 16);
|
||||
Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* StreamId */
|
||||
Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_STOP_COMPLETED); /* EventId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* cbData */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN *ifman)
|
||||
int tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN* ifman)
|
||||
{
|
||||
DEBUG_TSMF("");
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 16);
|
||||
|
||||
@@ -21,14 +21,11 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/cmdline.h>
|
||||
|
||||
#include <winpr/stream.h>
|
||||
#include <freerdp/client/tsmf.h>
|
||||
|
||||
#include "tsmf_types.h"
|
||||
#include "tsmf_constants.h"
|
||||
@@ -37,81 +34,41 @@
|
||||
|
||||
#include "tsmf_main.h"
|
||||
|
||||
typedef struct _TSMF_LISTENER_CALLBACK TSMF_LISTENER_CALLBACK;
|
||||
|
||||
typedef struct _TSMF_CHANNEL_CALLBACK TSMF_CHANNEL_CALLBACK;
|
||||
|
||||
typedef struct _TSMF_PLUGIN TSMF_PLUGIN;
|
||||
|
||||
struct _TSMF_LISTENER_CALLBACK
|
||||
{
|
||||
IWTSListenerCallback iface;
|
||||
|
||||
IWTSPlugin *plugin;
|
||||
IWTSVirtualChannelManager *channel_mgr;
|
||||
};
|
||||
|
||||
struct _TSMF_CHANNEL_CALLBACK
|
||||
{
|
||||
IWTSVirtualChannelCallback iface;
|
||||
|
||||
IWTSPlugin *plugin;
|
||||
IWTSVirtualChannelManager *channel_mgr;
|
||||
IWTSVirtualChannel *channel;
|
||||
|
||||
BYTE presentation_id[GUID_SIZE];
|
||||
UINT32 stream_id;
|
||||
};
|
||||
|
||||
struct _TSMF_PLUGIN
|
||||
{
|
||||
IWTSPlugin iface;
|
||||
|
||||
TSMF_LISTENER_CALLBACK *listener_callback;
|
||||
|
||||
const char *decoder_name;
|
||||
const char *audio_name;
|
||||
const char *audio_device;
|
||||
};
|
||||
|
||||
void tsmf_playback_ack(IWTSVirtualChannelCallback *pChannelCallback,
|
||||
UINT32 message_id, UINT64 duration, UINT32 data_size)
|
||||
UINT32 message_id, UINT64 duration, UINT32 data_size)
|
||||
{
|
||||
wStream *s;
|
||||
int status = -1;
|
||||
TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback;
|
||||
|
||||
s = Stream_New(NULL, 32);
|
||||
|
||||
Stream_Write_UINT32(s, TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY);
|
||||
Stream_Write_UINT32(s, message_id);
|
||||
Stream_Write_UINT32(s, PLAYBACK_ACK); /* FunctionId */
|
||||
Stream_Write_UINT32(s, callback->stream_id); /* StreamId */
|
||||
Stream_Write_UINT64(s, duration); /* DataDuration */
|
||||
Stream_Write_UINT64(s, data_size); /* cbData */
|
||||
|
||||
DEBUG_TSMF("response size %d", (int) Stream_GetPosition(s));
|
||||
if(!callback || !callback->channel || !callback->channel->Write)
|
||||
|
||||
if (!callback || !callback->channel || !callback->channel->Write)
|
||||
{
|
||||
WLog_ERR(TAG, "callback=%p, channel=%p, write=%p", callback,
|
||||
callback->channel, callback->channel->Write);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = callback->channel->Write(callback->channel,
|
||||
Stream_GetPosition(s), Stream_Buffer(s), NULL);
|
||||
if(status)
|
||||
{
|
||||
WLog_ERR(TAG, "response error %d", status);
|
||||
Stream_GetPosition(s), Stream_Buffer(s), NULL);
|
||||
}
|
||||
Stream_Free(s, TRUE);
|
||||
}
|
||||
|
||||
BOOL tsmf_push_event(IWTSVirtualChannelCallback *pChannelCallback, wMessage *event)
|
||||
{
|
||||
int status;
|
||||
TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback;
|
||||
status = callback->channel_mgr->PushEvent(callback->channel_mgr, event);
|
||||
if(status)
|
||||
if (status)
|
||||
{
|
||||
WLog_ERR(TAG, "response error %d", status);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
}
|
||||
|
||||
static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
|
||||
@@ -128,7 +85,7 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, w
|
||||
UINT32 cbSize = Stream_GetRemainingLength(data);
|
||||
|
||||
/* 2.2.1 Shared Message Header (SHARED_MSG_HEADER) */
|
||||
if(cbSize < 12)
|
||||
if (cbSize < 12)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid size. cbSize=%d", cbSize);
|
||||
return 1;
|
||||
@@ -137,17 +94,19 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, w
|
||||
input = data;
|
||||
output = Stream_New(NULL, 256);
|
||||
Stream_Seek(output, 8);
|
||||
Stream_Read_UINT32(input, InterfaceId);
|
||||
Stream_Read_UINT32(input, MessageId);
|
||||
Stream_Read_UINT32(input, FunctionId);
|
||||
Stream_Read_UINT32(input, InterfaceId); /* InterfaceId (4 bytes) */
|
||||
Stream_Read_UINT32(input, MessageId); /* MessageId (4 bytes) */
|
||||
Stream_Read_UINT32(input, FunctionId); /* FunctionId (4 bytes) */
|
||||
|
||||
DEBUG_TSMF("cbSize=%d InterfaceId=0x%X MessageId=0x%X FunctionId=0x%X",
|
||||
cbSize, InterfaceId, MessageId, FunctionId);
|
||||
memset(&ifman, 0, sizeof(TSMF_IFMAN));
|
||||
|
||||
ZeroMemory(&ifman, sizeof(TSMF_IFMAN));
|
||||
ifman.channel_callback = pChannelCallback;
|
||||
ifman.decoder_name = ((TSMF_PLUGIN *) callback->plugin)->decoder_name;
|
||||
ifman.audio_name = ((TSMF_PLUGIN *) callback->plugin)->audio_name;
|
||||
ifman.audio_device = ((TSMF_PLUGIN *) callback->plugin)->audio_device;
|
||||
memcpy(ifman.presentation_id, callback->presentation_id, GUID_SIZE);
|
||||
ifman.decoder_name = ((TSMF_PLUGIN*) callback->plugin)->decoder_name;
|
||||
ifman.audio_name = ((TSMF_PLUGIN*) callback->plugin)->audio_name;
|
||||
ifman.audio_device = ((TSMF_PLUGIN*) callback->plugin)->audio_device;
|
||||
CopyMemory(ifman.presentation_id, callback->presentation_id, GUID_SIZE);
|
||||
ifman.stream_id = callback->stream_id;
|
||||
ifman.message_id = MessageId;
|
||||
ifman.input = input;
|
||||
@@ -155,23 +114,30 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, w
|
||||
ifman.output = output;
|
||||
ifman.output_pending = FALSE;
|
||||
ifman.output_interface_id = InterfaceId;
|
||||
switch(InterfaceId)
|
||||
|
||||
//fprintf(stderr, "InterfaceId: 0x%04X MessageId: 0x%04X FunctionId: 0x%04X\n", InterfaceId, MessageId, FunctionId);
|
||||
|
||||
switch (InterfaceId)
|
||||
{
|
||||
case TSMF_INTERFACE_CAPABILITIES | STREAM_ID_NONE:
|
||||
switch(FunctionId)
|
||||
switch (FunctionId)
|
||||
{
|
||||
case RIM_EXCHANGE_CAPABILITY_REQUEST:
|
||||
status = tsmf_ifman_rim_exchange_capability_request(&ifman);
|
||||
break;
|
||||
case RIMCALL_RELEASE:
|
||||
case RIMCALL_QUERYINTERFACE:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case TSMF_INTERFACE_DEFAULT | STREAM_ID_PROXY:
|
||||
switch(FunctionId)
|
||||
switch (FunctionId)
|
||||
{
|
||||
case SET_CHANNEL_PARAMS:
|
||||
memcpy(callback->presentation_id, Stream_Pointer(input), GUID_SIZE);
|
||||
CopyMemory(callback->presentation_id, Stream_Pointer(input), GUID_SIZE);
|
||||
Stream_Seek(input, GUID_SIZE);
|
||||
Stream_Read_UINT32(input, callback->stream_id);
|
||||
DEBUG_TSMF("SET_CHANNEL_PARAMS StreamId=%d", callback->stream_id);
|
||||
@@ -244,19 +210,24 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, w
|
||||
case ON_PLAYBACK_RATE_CHANGED:
|
||||
status = tsmf_ifman_on_playback_rate_changed(&ifman);
|
||||
break;
|
||||
case RIMCALL_RELEASE:
|
||||
case RIMCALL_QUERYINTERFACE:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
input = NULL;
|
||||
ifman.input = NULL;
|
||||
if(status == -1)
|
||||
|
||||
if (status == -1)
|
||||
{
|
||||
switch(FunctionId)
|
||||
switch (FunctionId)
|
||||
{
|
||||
case RIMCALL_RELEASE:
|
||||
/* [MS-RDPEXPS] 2.2.2.2 Interface Release (IFACE_RELEASE)
|
||||
@@ -270,15 +241,17 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, w
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
if(status == -1)
|
||||
|
||||
if (status == -1)
|
||||
{
|
||||
WLog_ERR(TAG, "InterfaceId 0x%X FunctionId 0x%X not processed.",
|
||||
InterfaceId, FunctionId);
|
||||
WLog_ERR(TAG, "Unknown InterfaceId: 0x%04X MessageId: 0x%04X FunctionId: 0x%04X\n", InterfaceId, MessageId, FunctionId);
|
||||
/* When a request is not implemented we return empty response indicating error */
|
||||
}
|
||||
|
||||
status = 0;
|
||||
}
|
||||
if(status == 0 && !ifman.output_pending)
|
||||
|
||||
if (status == 0 && !ifman.output_pending)
|
||||
{
|
||||
/* Response packet does not have FunctionId */
|
||||
length = Stream_GetPosition(output);
|
||||
@@ -287,31 +260,37 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, w
|
||||
Stream_Write_UINT32(output, MessageId);
|
||||
DEBUG_TSMF("response size %d", length);
|
||||
status = callback->channel->Write(callback->channel, length, Stream_Buffer(output), NULL);
|
||||
if(status)
|
||||
|
||||
if (status)
|
||||
{
|
||||
WLog_ERR(TAG, "response error %d", status);
|
||||
}
|
||||
}
|
||||
|
||||
Stream_Free(output, TRUE);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int tsmf_on_close(IWTSVirtualChannelCallback *pChannelCallback)
|
||||
{
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback;
|
||||
TSMF_STREAM* stream;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
|
||||
DEBUG_TSMF("");
|
||||
if(callback->stream_id)
|
||||
|
||||
if (callback->stream_id)
|
||||
{
|
||||
presentation = tsmf_presentation_find_by_id(callback->presentation_id);
|
||||
if(presentation)
|
||||
|
||||
if (presentation)
|
||||
{
|
||||
stream = tsmf_stream_find_by_id(presentation, callback->stream_id);
|
||||
if(stream)
|
||||
if (stream)
|
||||
tsmf_stream_free(stream);
|
||||
}
|
||||
}
|
||||
|
||||
free(pChannelCallback);
|
||||
return 0;
|
||||
}
|
||||
@@ -322,41 +301,63 @@ static int tsmf_on_new_channel_connection(IWTSListenerCallback *pListenerCallbac
|
||||
int *pbAccept,
|
||||
IWTSVirtualChannelCallback **ppCallback)
|
||||
{
|
||||
TSMF_CHANNEL_CALLBACK *callback;
|
||||
TSMF_LISTENER_CALLBACK *listener_callback = (TSMF_LISTENER_CALLBACK *) pListenerCallback;
|
||||
TSMF_CHANNEL_CALLBACK* callback;
|
||||
TSMF_LISTENER_CALLBACK* listener_callback = (TSMF_LISTENER_CALLBACK*) pListenerCallback;
|
||||
|
||||
DEBUG_TSMF("");
|
||||
callback = (TSMF_CHANNEL_CALLBACK *) malloc(sizeof(TSMF_CHANNEL_CALLBACK));
|
||||
ZeroMemory(callback, sizeof(TSMF_CHANNEL_CALLBACK));
|
||||
|
||||
callback = (TSMF_CHANNEL_CALLBACK*) calloc(1, sizeof(TSMF_CHANNEL_CALLBACK));
|
||||
|
||||
if (!callback)
|
||||
return -1;
|
||||
|
||||
callback->iface.OnDataReceived = tsmf_on_data_received;
|
||||
callback->iface.OnClose = tsmf_on_close;
|
||||
callback->iface.OnOpen = NULL;
|
||||
callback->plugin = listener_callback->plugin;
|
||||
callback->channel_mgr = listener_callback->channel_mgr;
|
||||
callback->channel = pChannel;
|
||||
*ppCallback = (IWTSVirtualChannelCallback *) callback;
|
||||
|
||||
*ppCallback = (IWTSVirtualChannelCallback*) callback;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tsmf_plugin_initialize(IWTSPlugin *pPlugin, IWTSVirtualChannelManager *pChannelMgr)
|
||||
static int tsmf_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
|
||||
{
|
||||
TSMF_PLUGIN *tsmf = (TSMF_PLUGIN *) pPlugin;
|
||||
int status;
|
||||
TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin;
|
||||
|
||||
DEBUG_TSMF("");
|
||||
tsmf->listener_callback = (TSMF_LISTENER_CALLBACK *) malloc(sizeof(TSMF_LISTENER_CALLBACK));
|
||||
ZeroMemory(tsmf->listener_callback, sizeof(TSMF_LISTENER_CALLBACK));
|
||||
|
||||
tsmf->listener_callback = (TSMF_LISTENER_CALLBACK*) calloc(1, sizeof(TSMF_LISTENER_CALLBACK));
|
||||
|
||||
if (!tsmf->listener_callback)
|
||||
return -1;
|
||||
|
||||
tsmf->listener_callback->iface.OnNewChannelConnection = tsmf_on_new_channel_connection;
|
||||
tsmf->listener_callback->plugin = pPlugin;
|
||||
tsmf->listener_callback->channel_mgr = pChannelMgr;
|
||||
return pChannelMgr->CreateListener(pChannelMgr, "TSMF", 0,
|
||||
(IWTSListenerCallback *) tsmf->listener_callback, NULL);
|
||||
|
||||
status = pChannelMgr->CreateListener(pChannelMgr, "TSMF", 0,
|
||||
(IWTSListenerCallback*) tsmf->listener_callback, &(tsmf->listener));
|
||||
|
||||
tsmf->listener->pInterface = tsmf->iface.pInterface;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int tsmf_plugin_terminated(IWTSPlugin *pPlugin)
|
||||
static int tsmf_plugin_terminated(IWTSPlugin* pPlugin)
|
||||
{
|
||||
TSMF_PLUGIN *tsmf = (TSMF_PLUGIN *) pPlugin;
|
||||
TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin;
|
||||
|
||||
DEBUG_TSMF("");
|
||||
if(tsmf->listener_callback)
|
||||
|
||||
if (tsmf->listener_callback)
|
||||
free(tsmf->listener_callback);
|
||||
|
||||
free(tsmf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -372,15 +373,18 @@ static void tsmf_process_addin_args(IWTSPlugin *pPlugin, ADDIN_ARGV *args)
|
||||
{
|
||||
int status;
|
||||
DWORD flags;
|
||||
COMMAND_LINE_ARGUMENT_A *arg;
|
||||
TSMF_PLUGIN *tsmf = (TSMF_PLUGIN *) pPlugin;
|
||||
COMMAND_LINE_ARGUMENT_A* arg;
|
||||
TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin;
|
||||
|
||||
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON;
|
||||
status = CommandLineParseArgumentsA(args->argc, (const char **) args->argv,
|
||||
tsmf_args, flags, tsmf, NULL, NULL);
|
||||
|
||||
status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv,
|
||||
tsmf_args, flags, tsmf, NULL, NULL);
|
||||
arg = tsmf_args;
|
||||
|
||||
do
|
||||
{
|
||||
if(!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
|
||||
if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
|
||||
continue;
|
||||
CommandLineSwitchStart(arg)
|
||||
CommandLineSwitchCase(arg, "audio")
|
||||
@@ -400,32 +404,50 @@ static void tsmf_process_addin_args(IWTSPlugin *pPlugin, ADDIN_ARGV *args)
|
||||
}
|
||||
CommandLineSwitchEnd(arg)
|
||||
}
|
||||
while((arg = CommandLineFindNextArgumentA(arg)) != NULL);
|
||||
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
|
||||
}
|
||||
|
||||
#ifdef STATIC_CHANNELS
|
||||
#define DVCPluginEntry tsmf_DVCPluginEntry
|
||||
#endif
|
||||
|
||||
int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS *pEntryPoints)
|
||||
int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
{
|
||||
int status = 0;
|
||||
TSMF_PLUGIN *tsmf;
|
||||
tsmf = (TSMF_PLUGIN *) pEntryPoints->GetPlugin(pEntryPoints, "tsmf");
|
||||
if(tsmf == NULL)
|
||||
TSMF_PLUGIN* tsmf;
|
||||
TsmfClientContext* context;
|
||||
|
||||
tsmf = (TSMF_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "tsmf");
|
||||
|
||||
if (!tsmf)
|
||||
{
|
||||
tsmf = (TSMF_PLUGIN *) malloc(sizeof(TSMF_PLUGIN));
|
||||
ZeroMemory(tsmf, sizeof(TSMF_PLUGIN));
|
||||
tsmf = (TSMF_PLUGIN*) calloc(1, sizeof(TSMF_PLUGIN));
|
||||
|
||||
if (!tsmf)
|
||||
return -1;
|
||||
|
||||
tsmf->iface.Initialize = tsmf_plugin_initialize;
|
||||
tsmf->iface.Connected = NULL;
|
||||
tsmf->iface.Disconnected = NULL;
|
||||
tsmf->iface.Terminated = tsmf_plugin_terminated;
|
||||
status = pEntryPoints->RegisterPlugin(pEntryPoints, "tsmf", (IWTSPlugin *) tsmf);
|
||||
|
||||
context = (TsmfClientContext*) calloc(1, sizeof(TsmfClientContext));
|
||||
|
||||
if (!context)
|
||||
return -1;
|
||||
|
||||
context->handle = (void*) tsmf;
|
||||
tsmf->iface.pInterface = (void*) context;
|
||||
|
||||
tsmf_media_init();
|
||||
|
||||
status = pEntryPoints->RegisterPlugin(pEntryPoints, "tsmf", (IWTSPlugin*) tsmf);
|
||||
}
|
||||
if(status == 0)
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
tsmf_process_addin_args((IWTSPlugin *) tsmf, pEntryPoints->GetPluginData(pEntryPoints));
|
||||
tsmf_process_addin_args((IWTSPlugin*) tsmf, pEntryPoints->GetPluginData(pEntryPoints));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -20,10 +20,46 @@
|
||||
#ifndef __TSMF_MAIN_H
|
||||
#define __TSMF_MAIN_H
|
||||
|
||||
typedef struct _TSMF_LISTENER_CALLBACK TSMF_LISTENER_CALLBACK;
|
||||
|
||||
typedef struct _TSMF_CHANNEL_CALLBACK TSMF_CHANNEL_CALLBACK;
|
||||
|
||||
typedef struct _TSMF_PLUGIN TSMF_PLUGIN;
|
||||
|
||||
struct _TSMF_LISTENER_CALLBACK
|
||||
{
|
||||
IWTSListenerCallback iface;
|
||||
|
||||
IWTSPlugin* plugin;
|
||||
IWTSVirtualChannelManager* channel_mgr;
|
||||
};
|
||||
|
||||
struct _TSMF_CHANNEL_CALLBACK
|
||||
{
|
||||
IWTSVirtualChannelCallback iface;
|
||||
|
||||
IWTSPlugin* plugin;
|
||||
IWTSVirtualChannelManager* channel_mgr;
|
||||
IWTSVirtualChannel* channel;
|
||||
|
||||
BYTE presentation_id[GUID_SIZE];
|
||||
UINT32 stream_id;
|
||||
};
|
||||
|
||||
struct _TSMF_PLUGIN
|
||||
{
|
||||
IWTSPlugin iface;
|
||||
|
||||
IWTSListener* listener;
|
||||
TSMF_LISTENER_CALLBACK* listener_callback;
|
||||
|
||||
const char* decoder_name;
|
||||
const char* audio_name;
|
||||
const char* audio_device;
|
||||
};
|
||||
|
||||
void tsmf_playback_ack(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
UINT32 message_id, UINT64 duration, UINT32 data_size);
|
||||
BOOL tsmf_push_event(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
wMessage* event);
|
||||
UINT32 message_id, UINT64 duration, UINT32 data_size);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -43,7 +41,6 @@
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
#include <freerdp/utils/event.h>
|
||||
#include <freerdp/client/tsmf.h>
|
||||
|
||||
#include "tsmf_constants.h"
|
||||
@@ -87,7 +84,7 @@ struct _TSMF_STREAM
|
||||
{
|
||||
UINT32 stream_id;
|
||||
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
ITSMFDecoder *decoder;
|
||||
|
||||
@@ -127,7 +124,7 @@ struct _TSMF_SAMPLE
|
||||
UINT32 decoded_size;
|
||||
UINT32 pixfmt;
|
||||
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_STREAM* stream;
|
||||
IWTSVirtualChannelCallback *channel_callback;
|
||||
UINT64 ack_time;
|
||||
};
|
||||
@@ -135,8 +132,8 @@ struct _TSMF_SAMPLE
|
||||
static wArrayList *presentation_list = NULL;
|
||||
static int TERMINATING = 0;
|
||||
|
||||
static void _tsmf_presentation_free(TSMF_PRESENTATION *presentation);
|
||||
static void _tsmf_stream_free(TSMF_STREAM *stream);
|
||||
static void _tsmf_presentation_free(TSMF_PRESENTATION* presentation);
|
||||
static void _tsmf_stream_free(TSMF_STREAM* stream);
|
||||
|
||||
static UINT64 get_current_time(void)
|
||||
{
|
||||
@@ -145,15 +142,17 @@ static UINT64 get_current_time(void)
|
||||
return ((UINT64)tp.tv_sec) * 10000000LL + ((UINT64)tp.tv_usec) * 10LL;
|
||||
}
|
||||
|
||||
static TSMF_SAMPLE *tsmf_stream_pop_sample(TSMF_STREAM *stream, int sync)
|
||||
static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync)
|
||||
{
|
||||
UINT32 index;
|
||||
UINT32 count;
|
||||
TSMF_STREAM *s;
|
||||
TSMF_SAMPLE *sample;
|
||||
TSMF_SAMPLE* sample;
|
||||
BOOL pending = FALSE;
|
||||
TSMF_PRESENTATION *presentation = stream->presentation;
|
||||
assert(stream);
|
||||
TSMF_PRESENTATION* presentation = stream->presentation;
|
||||
|
||||
if (!stream)
|
||||
return NULL;
|
||||
|
||||
if (Queue_Count(stream->sample_list) < 1)
|
||||
return NULL;
|
||||
@@ -211,8 +210,10 @@ static TSMF_SAMPLE *tsmf_stream_pop_sample(TSMF_STREAM *stream, int sync)
|
||||
|
||||
static void tsmf_sample_free(void *arg)
|
||||
{
|
||||
TSMF_SAMPLE *sample = arg;
|
||||
assert(sample);
|
||||
TSMF_SAMPLE* sample = arg;
|
||||
|
||||
if (!sample)
|
||||
return;
|
||||
|
||||
if (sample->data)
|
||||
free(sample->data);
|
||||
@@ -220,28 +221,37 @@ static void tsmf_sample_free(void *arg)
|
||||
free(sample);
|
||||
}
|
||||
|
||||
static void tsmf_sample_ack(TSMF_SAMPLE *sample)
|
||||
static void tsmf_sample_ack(TSMF_SAMPLE* sample)
|
||||
{
|
||||
assert(sample);
|
||||
if (!sample)
|
||||
return;
|
||||
|
||||
tsmf_playback_ack(sample->channel_callback, sample->sample_id, sample->duration, sample->data_size);
|
||||
}
|
||||
|
||||
static void tsmf_sample_queue_ack(TSMF_SAMPLE *sample)
|
||||
static void tsmf_sample_queue_ack(TSMF_SAMPLE* sample)
|
||||
{
|
||||
assert(sample);
|
||||
assert(sample->stream);
|
||||
if (!sample)
|
||||
return;
|
||||
|
||||
if (!sample->stream)
|
||||
return;
|
||||
|
||||
Queue_Enqueue(sample->stream->sample_ack_list, sample);
|
||||
}
|
||||
|
||||
static BOOL tsmf_stream_process_ack(void *arg, BOOL force)
|
||||
static BOOL tsmf_stream_process_ack(void* arg, BOOL force)
|
||||
{
|
||||
TSMF_STREAM *stream = arg;
|
||||
TSMF_SAMPLE *sample;
|
||||
TSMF_STREAM* stream = arg;
|
||||
TSMF_SAMPLE* sample;
|
||||
UINT64 ack_time;
|
||||
BOOL rc = FALSE;
|
||||
assert(stream);
|
||||
|
||||
if (!stream)
|
||||
return FALSE;
|
||||
|
||||
Queue_Lock(stream->sample_ack_list);
|
||||
sample = (TSMF_SAMPLE *) Queue_Peek(stream->sample_ack_list);
|
||||
sample = (TSMF_SAMPLE*) Queue_Peek(stream->sample_ack_list);
|
||||
|
||||
if (!sample)
|
||||
goto finally;
|
||||
@@ -257,17 +267,20 @@ static BOOL tsmf_stream_process_ack(void *arg, BOOL force)
|
||||
sample = Queue_Dequeue(stream->sample_ack_list);
|
||||
tsmf_sample_ack(sample);
|
||||
tsmf_sample_free(sample);
|
||||
|
||||
finally:
|
||||
Queue_Unlock(stream->sample_ack_list);
|
||||
return rc;
|
||||
}
|
||||
|
||||
TSMF_PRESENTATION *tsmf_presentation_new(const BYTE *guid, IWTSVirtualChannelCallback *pChannelCallback)
|
||||
TSMF_PRESENTATION* tsmf_presentation_new(const BYTE* guid, IWTSVirtualChannelCallback* pChannelCallback)
|
||||
{
|
||||
TSMF_PRESENTATION *presentation;
|
||||
assert(guid);
|
||||
assert(pChannelCallback);
|
||||
presentation = (TSMF_PRESENTATION *) calloc(1, sizeof(TSMF_PRESENTATION));
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
if (!guid || !pChannelCallback)
|
||||
return NULL;
|
||||
|
||||
presentation = (TSMF_PRESENTATION*) calloc(1, sizeof(TSMF_PRESENTATION));
|
||||
|
||||
if (!presentation)
|
||||
{
|
||||
@@ -280,15 +293,18 @@ TSMF_PRESENTATION *tsmf_presentation_new(const BYTE *guid, IWTSVirtualChannelCal
|
||||
presentation->volume = 5000; /* 50% */
|
||||
presentation->stream_list = ArrayList_New(TRUE);
|
||||
ArrayList_Object(presentation->stream_list)->fnObjectFree = (OBJECT_FREE_FN) _tsmf_stream_free;
|
||||
|
||||
ArrayList_Add(presentation_list, presentation);
|
||||
|
||||
return presentation;
|
||||
}
|
||||
|
||||
static char *guid_to_string(const BYTE *guid, char *str, size_t len)
|
||||
static char* guid_to_string(const BYTE* guid, char* str, size_t len)
|
||||
{
|
||||
int i;
|
||||
assert(guid);
|
||||
assert(str);
|
||||
|
||||
if (!guid || !str)
|
||||
return NULL;
|
||||
|
||||
for (i=0; i<GUID_SIZE && len > 2*i; i++)
|
||||
snprintf(str + (2*i), len - 2*i, "%02X", guid[i]);
|
||||
@@ -296,19 +312,20 @@ static char *guid_to_string(const BYTE *guid, char *str, size_t len)
|
||||
return str;
|
||||
}
|
||||
|
||||
TSMF_PRESENTATION *tsmf_presentation_find_by_id(const BYTE *guid)
|
||||
TSMF_PRESENTATION* tsmf_presentation_find_by_id(const BYTE *guid)
|
||||
{
|
||||
char guid_str[GUID_SIZE * 2 + 1];
|
||||
UINT32 index;
|
||||
UINT32 count;
|
||||
BOOL found = FALSE;
|
||||
TSMF_PRESENTATION *presentation;
|
||||
char guid_str[GUID_SIZE * 2 + 1];
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
ArrayList_Lock(presentation_list);
|
||||
count = ArrayList_Count(presentation_list);
|
||||
|
||||
for (index = 0; index < count; index++)
|
||||
{
|
||||
presentation = (TSMF_PRESENTATION *) ArrayList_GetItem(presentation_list, index);
|
||||
presentation = (TSMF_PRESENTATION*) ArrayList_GetItem(presentation_list, index);
|
||||
|
||||
if (memcmp(presentation->presentation_id, guid, GUID_SIZE) == 0)
|
||||
{
|
||||
@@ -325,14 +342,17 @@ TSMF_PRESENTATION *tsmf_presentation_find_by_id(const BYTE *guid)
|
||||
return (found) ? presentation : NULL;
|
||||
}
|
||||
|
||||
static void tsmf_sample_playback_video(TSMF_SAMPLE *sample)
|
||||
static void tsmf_sample_playback_video(TSMF_SAMPLE* sample)
|
||||
{
|
||||
UINT64 t;
|
||||
RDP_VIDEO_FRAME_EVENT *vevent;
|
||||
TSMF_STREAM *stream = sample->stream;
|
||||
TSMF_PRESENTATION *presentation = stream->presentation;
|
||||
TSMF_VIDEO_FRAME_EVENT event;
|
||||
TSMF_STREAM* stream = sample->stream;
|
||||
TSMF_PRESENTATION* presentation = stream->presentation;
|
||||
TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) sample->channel_callback;
|
||||
TsmfClientContext* tsmf = (TsmfClientContext*) callback->plugin->pInterface;
|
||||
|
||||
DEBUG_TSMF("MessageId %d EndTime %d data_size %d consumed.",
|
||||
sample->sample_id, (int)sample->end_time, sample->data_size);
|
||||
sample->sample_id, (int) sample->end_time, sample->data_size);
|
||||
|
||||
if (sample->data)
|
||||
{
|
||||
@@ -346,21 +366,21 @@ static void tsmf_sample_playback_video(TSMF_SAMPLE *sample)
|
||||
}
|
||||
|
||||
stream->next_start_time = t + sample->duration - 50000;
|
||||
vevent = (RDP_VIDEO_FRAME_EVENT *) freerdp_event_new(TsmfChannel_Class, TsmfChannel_VideoFrame,
|
||||
NULL, NULL);
|
||||
vevent->frame_data = sample->data;
|
||||
vevent->frame_size = sample->decoded_size;
|
||||
vevent->frame_pixfmt = sample->pixfmt;
|
||||
vevent->frame_width = sample->stream->width;
|
||||
vevent->frame_height = sample->stream->height;
|
||||
|
||||
ZeroMemory(&event, sizeof(TSMF_VIDEO_FRAME_EVENT));
|
||||
|
||||
event.frameData = sample->data;
|
||||
event.frameSize = sample->decoded_size;
|
||||
event.framePixFmt = sample->pixfmt;
|
||||
event.frameWidth = sample->stream->width;
|
||||
event.frameHeight = sample->stream->height;
|
||||
|
||||
/* The frame data ownership is passed to the event object, and is freed after the event is processed. */
|
||||
sample->data = NULL;
|
||||
sample->decoded_size = 0;
|
||||
|
||||
if (!tsmf_push_event(sample->channel_callback, (wMessage *) vevent))
|
||||
{
|
||||
freerdp_event_free((wMessage *) vevent);
|
||||
}
|
||||
if (tsmf->FrameEvent)
|
||||
tsmf->FrameEvent(tsmf, &event);
|
||||
|
||||
#if 0
|
||||
/* Dump a .ppm image for every 30 frames. Assuming the frame is in YUV format, we
|
||||
@@ -387,17 +407,17 @@ static void tsmf_sample_playback_video(TSMF_SAMPLE *sample)
|
||||
}
|
||||
}
|
||||
|
||||
static void tsmf_sample_playback_audio(TSMF_SAMPLE *sample)
|
||||
static void tsmf_sample_playback_audio(TSMF_SAMPLE* sample)
|
||||
{
|
||||
UINT64 latency = 0;
|
||||
TSMF_STREAM *stream = sample->stream;
|
||||
TSMF_STREAM* stream = sample->stream;
|
||||
|
||||
DEBUG_TSMF("MessageId %d EndTime %d consumed.",
|
||||
sample->sample_id, (int)sample->end_time);
|
||||
|
||||
if (sample->stream->audio && sample->data)
|
||||
{
|
||||
sample->stream->audio->Play(sample->stream->audio,
|
||||
sample->data, sample->decoded_size);
|
||||
sample->stream->audio->Play(sample->stream->audio, sample->data, sample->decoded_size);
|
||||
sample->data = NULL;
|
||||
sample->decoded_size = 0;
|
||||
|
||||
@@ -415,21 +435,25 @@ static void tsmf_sample_playback_audio(TSMF_SAMPLE *sample)
|
||||
stream->presentation->audio_end_time = sample->end_time + latency;
|
||||
}
|
||||
|
||||
static void tsmf_sample_playback(TSMF_SAMPLE *sample)
|
||||
static void tsmf_sample_playback(TSMF_SAMPLE* sample)
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
UINT32 width;
|
||||
UINT32 height;
|
||||
UINT32 pixfmt = 0;
|
||||
TSMF_STREAM *stream = sample->stream;
|
||||
TSMF_STREAM* stream = sample->stream;
|
||||
|
||||
if (stream->decoder)
|
||||
{
|
||||
if (stream->decoder->DecodeEx)
|
||||
{
|
||||
ret = stream->decoder->DecodeEx(stream->decoder, sample->data, sample->data_size, sample->extensions,
|
||||
sample->start_time, sample->end_time, sample->duration);
|
||||
sample->start_time, sample->end_time, sample->duration);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = stream->decoder->Decode(stream->decoder, sample->data, sample->data_size, sample->extensions);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
@@ -456,7 +480,7 @@ static void tsmf_sample_playback(TSMF_SAMPLE *sample)
|
||||
sample->pixfmt = pixfmt;
|
||||
}
|
||||
|
||||
ret = FALSE ;
|
||||
ret = FALSE;
|
||||
|
||||
if (stream->decoder->GetDecodedDimension)
|
||||
{
|
||||
@@ -490,7 +514,7 @@ static void tsmf_sample_playback(TSMF_SAMPLE *sample)
|
||||
}
|
||||
else
|
||||
{
|
||||
TSMF_STREAM *stream = sample->stream;
|
||||
TSMF_STREAM* stream = sample->stream;
|
||||
UINT64 ack_anticipation_time = get_current_time();
|
||||
UINT64 currentRunningTime = sample->start_time;
|
||||
BOOL buffer_filled = TRUE;
|
||||
@@ -521,7 +545,9 @@ static void tsmf_sample_playback(TSMF_SAMPLE *sample)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ack_anticipation_time += sample->duration / 2;
|
||||
}
|
||||
|
||||
switch (sample->stream->major_type)
|
||||
{
|
||||
@@ -541,11 +567,12 @@ static void tsmf_sample_playback(TSMF_SAMPLE *sample)
|
||||
}
|
||||
}
|
||||
|
||||
static void *tsmf_stream_ack_func(void *arg)
|
||||
static void* tsmf_stream_ack_func(void *arg)
|
||||
{
|
||||
TSMF_STREAM *stream = (TSMF_STREAM *) arg;
|
||||
HANDLE hdl[2];
|
||||
TSMF_STREAM* stream = (TSMF_STREAM*) arg;
|
||||
DEBUG_TSMF("in %d", stream->stream_id);
|
||||
|
||||
hdl[0] = stream->stopEvent;
|
||||
hdl[1] = Queue_Event(stream->sample_ack_list);
|
||||
|
||||
@@ -571,12 +598,13 @@ static void *tsmf_stream_ack_func(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *tsmf_stream_playback_func(void *arg)
|
||||
static void* tsmf_stream_playback_func(void *arg)
|
||||
{
|
||||
HANDLE hdl[2];
|
||||
TSMF_SAMPLE *sample;
|
||||
TSMF_STREAM *stream = (TSMF_STREAM *) arg;
|
||||
TSMF_PRESENTATION *presentation = stream->presentation;
|
||||
TSMF_SAMPLE* sample;
|
||||
TSMF_STREAM* stream = (TSMF_STREAM *) arg;
|
||||
TSMF_PRESENTATION* presentation = stream->presentation;
|
||||
|
||||
DEBUG_TSMF("in %d", stream->stream_id);
|
||||
|
||||
if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO &&
|
||||
@@ -587,13 +615,12 @@ static void *tsmf_stream_playback_func(void *arg)
|
||||
if (stream->decoder->GetDecodedData)
|
||||
{
|
||||
stream->audio = tsmf_load_audio_device(
|
||||
presentation->audio_name && presentation->audio_name[0] ? presentation->audio_name : NULL,
|
||||
presentation->audio_device && presentation->audio_device[0] ? presentation->audio_device : NULL);
|
||||
presentation->audio_name && presentation->audio_name[0] ? presentation->audio_name : NULL,
|
||||
presentation->audio_device && presentation->audio_device[0] ? presentation->audio_device : NULL);
|
||||
|
||||
if (stream->audio)
|
||||
{
|
||||
stream->audio->SetFormat(stream->audio,
|
||||
stream->sample_rate, stream->channels, stream->bits_per_sample);
|
||||
stream->audio->SetFormat(stream->audio, stream->sample_rate, stream->channels, stream->bits_per_sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -621,7 +648,7 @@ static void *tsmf_stream_playback_func(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void tsmf_stream_start(TSMF_STREAM *stream)
|
||||
static void tsmf_stream_start(TSMF_STREAM* stream)
|
||||
{
|
||||
if (!stream || !stream->presentation || !stream->decoder)
|
||||
return;
|
||||
@@ -632,7 +659,7 @@ static void tsmf_stream_start(TSMF_STREAM *stream)
|
||||
}
|
||||
}
|
||||
|
||||
static void tsmf_stream_stop(TSMF_STREAM *stream)
|
||||
static void tsmf_stream_stop(TSMF_STREAM* stream)
|
||||
{
|
||||
if (!stream || !stream->decoder)
|
||||
return;
|
||||
@@ -643,7 +670,7 @@ static void tsmf_stream_stop(TSMF_STREAM *stream)
|
||||
}
|
||||
}
|
||||
|
||||
static void tsmf_stream_pause(TSMF_STREAM *stream)
|
||||
static void tsmf_stream_pause(TSMF_STREAM* stream)
|
||||
{
|
||||
if (!stream || !stream->decoder)
|
||||
return;
|
||||
@@ -654,7 +681,7 @@ static void tsmf_stream_pause(TSMF_STREAM *stream)
|
||||
}
|
||||
}
|
||||
|
||||
static void tsmf_stream_restart(TSMF_STREAM *stream)
|
||||
static void tsmf_stream_restart(TSMF_STREAM* stream)
|
||||
{
|
||||
if (!stream || !stream->decoder)
|
||||
return;
|
||||
@@ -665,7 +692,7 @@ static void tsmf_stream_restart(TSMF_STREAM *stream)
|
||||
}
|
||||
}
|
||||
|
||||
static void tsmf_stream_change_volume(TSMF_STREAM *stream, UINT32 newVolume, UINT32 muted)
|
||||
static void tsmf_stream_change_volume(TSMF_STREAM* stream, UINT32 newVolume, UINT32 muted)
|
||||
{
|
||||
if (!stream || !stream->decoder)
|
||||
return;
|
||||
@@ -680,11 +707,11 @@ static void tsmf_stream_change_volume(TSMF_STREAM *stream, UINT32 newVolume, UIN
|
||||
}
|
||||
}
|
||||
|
||||
void tsmf_presentation_volume_changed(TSMF_PRESENTATION *presentation, UINT32 newVolume, UINT32 muted)
|
||||
void tsmf_presentation_volume_changed(TSMF_PRESENTATION* presentation, UINT32 newVolume, UINT32 muted)
|
||||
{
|
||||
UINT32 index;
|
||||
UINT32 count;
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_STREAM* stream;
|
||||
presentation->volume = newVolume;
|
||||
presentation->muted = muted;
|
||||
ArrayList_Lock(presentation->stream_list);
|
||||
@@ -699,11 +726,11 @@ void tsmf_presentation_volume_changed(TSMF_PRESENTATION *presentation, UINT32 ne
|
||||
ArrayList_Unlock(presentation->stream_list);
|
||||
}
|
||||
|
||||
void tsmf_presentation_paused(TSMF_PRESENTATION *presentation)
|
||||
void tsmf_presentation_paused(TSMF_PRESENTATION* presentation)
|
||||
{
|
||||
UINT32 index;
|
||||
UINT32 count;
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_STREAM* stream;
|
||||
ArrayList_Lock(presentation->stream_list);
|
||||
count = ArrayList_Count(presentation->stream_list);
|
||||
|
||||
@@ -716,11 +743,11 @@ void tsmf_presentation_paused(TSMF_PRESENTATION *presentation)
|
||||
ArrayList_Unlock(presentation->stream_list);
|
||||
}
|
||||
|
||||
void tsmf_presentation_restarted(TSMF_PRESENTATION *presentation)
|
||||
void tsmf_presentation_restarted(TSMF_PRESENTATION* presentation)
|
||||
{
|
||||
UINT32 index;
|
||||
UINT32 count;
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_STREAM* stream;
|
||||
ArrayList_Lock(presentation->stream_list);
|
||||
count = ArrayList_Count(presentation->stream_list);
|
||||
|
||||
@@ -733,11 +760,11 @@ void tsmf_presentation_restarted(TSMF_PRESENTATION *presentation)
|
||||
ArrayList_Unlock(presentation->stream_list);
|
||||
}
|
||||
|
||||
void tsmf_presentation_start(TSMF_PRESENTATION *presentation)
|
||||
void tsmf_presentation_start(TSMF_PRESENTATION* presentation)
|
||||
{
|
||||
UINT32 index;
|
||||
UINT32 count;
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_STREAM* stream;
|
||||
ArrayList_Lock(presentation->stream_list);
|
||||
count = ArrayList_Count(presentation->stream_list);
|
||||
|
||||
@@ -750,7 +777,7 @@ void tsmf_presentation_start(TSMF_PRESENTATION *presentation)
|
||||
ArrayList_Unlock(presentation->stream_list);
|
||||
}
|
||||
|
||||
void tsmf_presentation_sync(TSMF_PRESENTATION *presentation)
|
||||
void tsmf_presentation_sync(TSMF_PRESENTATION* presentation)
|
||||
{
|
||||
UINT32 index;
|
||||
UINT32 count;
|
||||
@@ -759,18 +786,18 @@ void tsmf_presentation_sync(TSMF_PRESENTATION *presentation)
|
||||
|
||||
for (index = 0; index < count; index++)
|
||||
{
|
||||
TSMF_STREAM *stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index);
|
||||
TSMF_STREAM* stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index);
|
||||
WaitForSingleObject(stream->ready, 500);
|
||||
}
|
||||
|
||||
ArrayList_Unlock(presentation->stream_list);
|
||||
}
|
||||
|
||||
void tsmf_presentation_stop(TSMF_PRESENTATION *presentation)
|
||||
void tsmf_presentation_stop(TSMF_PRESENTATION* presentation)
|
||||
{
|
||||
UINT32 index;
|
||||
UINT32 count;
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_STREAM* stream;
|
||||
tsmf_presentation_flush(presentation);
|
||||
ArrayList_Lock(presentation->stream_list);
|
||||
count = ArrayList_Count(presentation->stream_list);
|
||||
@@ -784,12 +811,12 @@ void tsmf_presentation_stop(TSMF_PRESENTATION *presentation)
|
||||
ArrayList_Unlock(presentation->stream_list);
|
||||
}
|
||||
|
||||
void tsmf_presentation_set_geometry_info(TSMF_PRESENTATION *presentation,
|
||||
void tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation,
|
||||
UINT32 x, UINT32 y, UINT32 width, UINT32 height, int num_rects, RDP_RECT *rects)
|
||||
{
|
||||
UINT32 index;
|
||||
UINT32 count;
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_STREAM* stream;
|
||||
|
||||
/* The server may send messages with invalid width / height.
|
||||
* Ignore those messages. */
|
||||
@@ -812,7 +839,7 @@ void tsmf_presentation_set_geometry_info(TSMF_PRESENTATION *presentation,
|
||||
presentation->rects = realloc(presentation->rects, sizeof(RDP_RECT) * num_rects);
|
||||
|
||||
if (presentation->rects)
|
||||
memcpy(presentation->rects, rects, sizeof(RDP_RECT) * num_rects);
|
||||
CopyMemory(presentation->rects, rects, sizeof(RDP_RECT) * num_rects);
|
||||
|
||||
ArrayList_Lock(presentation->stream_list);
|
||||
count = ArrayList_Count(presentation->stream_list);
|
||||
@@ -833,13 +860,13 @@ void tsmf_presentation_set_geometry_info(TSMF_PRESENTATION *presentation,
|
||||
ArrayList_Unlock(presentation->stream_list);
|
||||
}
|
||||
|
||||
void tsmf_presentation_set_audio_device(TSMF_PRESENTATION *presentation, const char *name, const char *device)
|
||||
void tsmf_presentation_set_audio_device(TSMF_PRESENTATION* presentation, const char *name, const char *device)
|
||||
{
|
||||
presentation->audio_name = name;
|
||||
presentation->audio_device = device;
|
||||
}
|
||||
|
||||
static void tsmf_stream_flush(TSMF_STREAM *stream)
|
||||
static void tsmf_stream_flush(TSMF_STREAM* stream)
|
||||
{
|
||||
//TSMF_SAMPLE* sample;
|
||||
/* TODO: free lists */
|
||||
@@ -857,17 +884,17 @@ static void tsmf_stream_flush(TSMF_STREAM *stream)
|
||||
}
|
||||
}
|
||||
|
||||
void tsmf_presentation_flush(TSMF_PRESENTATION *presentation)
|
||||
void tsmf_presentation_flush(TSMF_PRESENTATION* presentation)
|
||||
{
|
||||
UINT32 index;
|
||||
UINT32 count;
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_STREAM* stream;
|
||||
ArrayList_Lock(presentation->stream_list);
|
||||
count = ArrayList_Count(presentation->stream_list);
|
||||
|
||||
for (index = 0; index < count; index++)
|
||||
{
|
||||
stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index);
|
||||
stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index);
|
||||
tsmf_stream_flush(stream);
|
||||
}
|
||||
|
||||
@@ -877,7 +904,7 @@ void tsmf_presentation_flush(TSMF_PRESENTATION *presentation)
|
||||
presentation->audio_end_time = 0;
|
||||
}
|
||||
|
||||
void _tsmf_presentation_free(TSMF_PRESENTATION *presentation)
|
||||
void _tsmf_presentation_free(TSMF_PRESENTATION* presentation)
|
||||
{
|
||||
tsmf_presentation_stop(presentation);
|
||||
ArrayList_Clear(presentation->stream_list);
|
||||
@@ -886,18 +913,18 @@ void _tsmf_presentation_free(TSMF_PRESENTATION *presentation)
|
||||
if (presentation->rects)
|
||||
free(presentation->rects);
|
||||
|
||||
memset(presentation, 0, sizeof(TSMF_PRESENTATION));
|
||||
ZeroMemory(presentation, sizeof(TSMF_PRESENTATION));
|
||||
free(presentation);
|
||||
}
|
||||
|
||||
void tsmf_presentation_free(TSMF_PRESENTATION *presentation)
|
||||
void tsmf_presentation_free(TSMF_PRESENTATION* presentation)
|
||||
{
|
||||
ArrayList_Remove(presentation_list, presentation);
|
||||
}
|
||||
|
||||
TSMF_STREAM *tsmf_stream_new(TSMF_PRESENTATION *presentation, UINT32 stream_id)
|
||||
TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, UINT32 stream_id)
|
||||
{
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_STREAM* stream;
|
||||
stream = tsmf_stream_find_by_id(presentation, stream_id);
|
||||
|
||||
if (stream)
|
||||
@@ -906,7 +933,7 @@ TSMF_STREAM *tsmf_stream_new(TSMF_PRESENTATION *presentation, UINT32 stream_id)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stream = (TSMF_STREAM *) calloc(1, sizeof(TSMF_STREAM));
|
||||
stream = (TSMF_STREAM*) calloc(1, sizeof(TSMF_STREAM));
|
||||
|
||||
if (!stream)
|
||||
{
|
||||
@@ -922,26 +949,27 @@ TSMF_STREAM *tsmf_stream_new(TSMF_PRESENTATION *presentation, UINT32 stream_id)
|
||||
stream->sample_list->object.fnObjectFree = tsmf_sample_free;
|
||||
stream->sample_ack_list = Queue_New(TRUE, -1, -1);
|
||||
stream->sample_ack_list->object.fnObjectFree = tsmf_sample_free;
|
||||
stream->play_thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE)tsmf_stream_playback_func, stream, 0, NULL);
|
||||
stream->ack_thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE)tsmf_stream_ack_func, stream, 0, NULL);
|
||||
stream->play_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) tsmf_stream_playback_func, stream, 0, NULL);
|
||||
stream->ack_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)tsmf_stream_ack_func, stream, 0, NULL);
|
||||
|
||||
ArrayList_Add(presentation->stream_list, stream);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
TSMF_STREAM *tsmf_stream_find_by_id(TSMF_PRESENTATION *presentation, UINT32 stream_id)
|
||||
TSMF_STREAM *tsmf_stream_find_by_id(TSMF_PRESENTATION* presentation, UINT32 stream_id)
|
||||
{
|
||||
UINT32 index;
|
||||
UINT32 count;
|
||||
BOOL found = FALSE;
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_STREAM* stream;
|
||||
|
||||
ArrayList_Lock(presentation->stream_list);
|
||||
count = ArrayList_Count(presentation->stream_list);
|
||||
|
||||
for (index = 0; index < count; index++)
|
||||
{
|
||||
stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index);
|
||||
stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index);
|
||||
|
||||
if (stream->stream_id == stream_id)
|
||||
{
|
||||
@@ -956,11 +984,11 @@ TSMF_STREAM *tsmf_stream_find_by_id(TSMF_PRESENTATION *presentation, UINT32 stre
|
||||
|
||||
static void tsmf_stream_resync(void *arg)
|
||||
{
|
||||
TSMF_STREAM *stream = arg;
|
||||
TSMF_STREAM* stream = arg;
|
||||
ResetEvent(stream->ready);
|
||||
}
|
||||
|
||||
void tsmf_stream_set_format(TSMF_STREAM *stream, const char *name, wStream *s)
|
||||
void tsmf_stream_set_format(TSMF_STREAM* stream, const char *name, wStream *s)
|
||||
{
|
||||
TS_AM_MEDIA_TYPE mediatype;
|
||||
|
||||
@@ -1008,16 +1036,20 @@ void tsmf_stream_set_format(TSMF_STREAM *stream, const char *name, wStream *s)
|
||||
stream->decoder->SetSyncFunc(stream->decoder, tsmf_stream_resync, stream);
|
||||
}
|
||||
|
||||
void tsmf_stream_end(TSMF_STREAM *stream)
|
||||
void tsmf_stream_end(TSMF_STREAM* stream)
|
||||
{
|
||||
assert(stream);
|
||||
if (!stream)
|
||||
return;
|
||||
|
||||
stream->eos = 1;
|
||||
stream->presentation->eos = 1;
|
||||
}
|
||||
|
||||
void _tsmf_stream_free(TSMF_STREAM *stream)
|
||||
void _tsmf_stream_free(TSMF_STREAM* stream)
|
||||
{
|
||||
assert(stream);
|
||||
if (!stream)
|
||||
return;
|
||||
|
||||
tsmf_stream_stop(stream);
|
||||
tsmf_stream_flush(stream);
|
||||
SetEvent(stream->stopEvent);
|
||||
@@ -1047,27 +1079,27 @@ void _tsmf_stream_free(TSMF_STREAM *stream)
|
||||
|
||||
CloseHandle(stream->stopEvent);
|
||||
CloseHandle(stream->ready);
|
||||
memset(stream, 0, sizeof(TSMF_STREAM));
|
||||
ZeroMemory(stream, sizeof(TSMF_STREAM));
|
||||
free(stream);
|
||||
}
|
||||
|
||||
void tsmf_stream_free(TSMF_STREAM *stream)
|
||||
void tsmf_stream_free(TSMF_STREAM* stream)
|
||||
{
|
||||
TSMF_PRESENTATION *presentation = stream->presentation;
|
||||
TSMF_PRESENTATION* presentation = stream->presentation;
|
||||
ArrayList_Remove(presentation->stream_list, stream);
|
||||
}
|
||||
|
||||
void tsmf_stream_push_sample(TSMF_STREAM *stream, IWTSVirtualChannelCallback *pChannelCallback,
|
||||
UINT32 sample_id, UINT64 start_time, UINT64 end_time, UINT64 duration, UINT32 extensions,
|
||||
UINT32 data_size, BYTE *data)
|
||||
void tsmf_stream_push_sample(TSMF_STREAM* stream, IWTSVirtualChannelCallback *pChannelCallback,
|
||||
UINT32 sample_id, UINT64 start_time, UINT64 end_time, UINT64 duration, UINT32 extensions,
|
||||
UINT32 data_size, BYTE *data)
|
||||
{
|
||||
TSMF_SAMPLE *sample;
|
||||
TSMF_SAMPLE* sample;
|
||||
SetEvent(stream->ready);
|
||||
|
||||
if (TERMINATING)
|
||||
return;
|
||||
|
||||
sample = (TSMF_SAMPLE *) calloc(1, sizeof(TSMF_SAMPLE));
|
||||
sample = (TSMF_SAMPLE*) calloc(1, sizeof(TSMF_SAMPLE));
|
||||
|
||||
if (!sample)
|
||||
{
|
||||
|
||||
@@ -32,6 +32,7 @@ set(${MODULE_PREFIX}_OBJECTIVE_SOURCES
|
||||
MRDPCursor.m
|
||||
MRDPView.m
|
||||
Keyboard.m
|
||||
Clipboard.m
|
||||
PasswordDialog.m)
|
||||
|
||||
list(APPEND ${MODULE_PREFIX}_SOURCES ${${MODULE_PREFIX}_OBJECTIVE_SOURCES})
|
||||
@@ -42,6 +43,7 @@ set(${MODULE_PREFIX}_HEADERS
|
||||
MRDPCursor.h
|
||||
MRDPView.h
|
||||
Keyboard.h
|
||||
Clipboard.h
|
||||
PasswordDialog.h)
|
||||
|
||||
set(${MODULE_PREFIX}_RESOURCES "en.lproj/InfoPlist.strings")
|
||||
|
||||
29
client/Mac/Clipboard.h
Normal file
29
client/Mac/Clipboard.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@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.
|
||||
*/
|
||||
|
||||
#import "mfreerdp.h"
|
||||
#import "mf_client.h"
|
||||
|
||||
#import "freerdp/freerdp.h"
|
||||
#import "freerdp/channels/channels.h"
|
||||
#import "freerdp/client/cliprdr.h"
|
||||
|
||||
int mac_cliprdr_send_client_format_list(CliprdrClientContext* cliprdr);
|
||||
|
||||
void mac_cliprdr_init(mfContext* mfc, CliprdrClientContext* cliprdr);
|
||||
void mac_cliprdr_uninit(mfContext* mfc, CliprdrClientContext* cliprdr);
|
||||
328
client/Mac/Clipboard.m
Normal file
328
client/Mac/Clipboard.m
Normal file
@@ -0,0 +1,328 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@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.
|
||||
*/
|
||||
|
||||
#import "Clipboard.h"
|
||||
|
||||
int mac_cliprdr_send_client_format_list(CliprdrClientContext* cliprdr)
|
||||
{
|
||||
UINT32 index;
|
||||
UINT32 formatId;
|
||||
UINT32 numFormats;
|
||||
UINT32* pFormatIds;
|
||||
const char* formatName;
|
||||
CLIPRDR_FORMAT* formats;
|
||||
CLIPRDR_FORMAT_LIST formatList;
|
||||
mfContext* mfc = (mfContext*) cliprdr->custom;
|
||||
|
||||
ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST));
|
||||
|
||||
pFormatIds = NULL;
|
||||
numFormats = ClipboardGetFormatIds(mfc->clipboard, &pFormatIds);
|
||||
|
||||
formats = (CLIPRDR_FORMAT*) calloc(numFormats, sizeof(CLIPRDR_FORMAT));
|
||||
|
||||
if (!formats)
|
||||
return -1;
|
||||
|
||||
for (index = 0; index < numFormats; index++)
|
||||
{
|
||||
formatId = pFormatIds[index];
|
||||
formatName = ClipboardGetFormatName(mfc->clipboard, formatId);
|
||||
|
||||
formats[index].formatId = formatId;
|
||||
formats[index].formatName = NULL;
|
||||
|
||||
if ((formatId > CF_MAX) && formatName)
|
||||
formats[index].formatName = _strdup(formatName);
|
||||
}
|
||||
|
||||
formatList.msgFlags = CB_RESPONSE_OK;
|
||||
formatList.numFormats = numFormats;
|
||||
formatList.formats = formats;
|
||||
|
||||
mfc->cliprdr->ClientFormatList(mfc->cliprdr, &formatList);
|
||||
|
||||
free(pFormatIds);
|
||||
free(formats);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mac_cliprdr_send_client_format_data_request(CliprdrClientContext* cliprdr, UINT32 formatId)
|
||||
{
|
||||
CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest;
|
||||
mfContext* mfc = (mfContext*) cliprdr->custom;
|
||||
|
||||
ZeroMemory(&formatDataRequest, sizeof(CLIPRDR_FORMAT_DATA_REQUEST));
|
||||
|
||||
formatDataRequest.msgType = CB_FORMAT_DATA_REQUEST;
|
||||
formatDataRequest.msgFlags = 0;
|
||||
|
||||
formatDataRequest.requestedFormatId = formatId;
|
||||
mfc->requestedFormatId = formatId;
|
||||
ResetEvent(mfc->clipboardRequestEvent);
|
||||
|
||||
cliprdr->ClientFormatDataRequest(cliprdr, &formatDataRequest);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mac_cliprdr_send_client_capabilities(CliprdrClientContext* cliprdr)
|
||||
{
|
||||
CLIPRDR_CAPABILITIES capabilities;
|
||||
CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet;
|
||||
|
||||
capabilities.cCapabilitiesSets = 1;
|
||||
capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) &(generalCapabilitySet);
|
||||
|
||||
generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL;
|
||||
generalCapabilitySet.capabilitySetLength = 12;
|
||||
|
||||
generalCapabilitySet.version = CB_CAPS_VERSION_2;
|
||||
generalCapabilitySet.generalFlags = CB_USE_LONG_FORMAT_NAMES;
|
||||
|
||||
cliprdr->ClientCapabilities(cliprdr, &capabilities);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mac_cliprdr_monitor_ready(CliprdrClientContext* cliprdr, CLIPRDR_MONITOR_READY* monitorReady)
|
||||
{
|
||||
mfContext* mfc = (mfContext*) cliprdr->custom;
|
||||
|
||||
mfc->clipboardSync = TRUE;
|
||||
mac_cliprdr_send_client_capabilities(cliprdr);
|
||||
mac_cliprdr_send_client_format_list(cliprdr);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mac_cliprdr_server_capabilities(CliprdrClientContext* cliprdr, CLIPRDR_CAPABILITIES* capabilities)
|
||||
{
|
||||
UINT32 index;
|
||||
CLIPRDR_CAPABILITY_SET* capabilitySet;
|
||||
mfContext* mfc = (mfContext*) cliprdr->custom;
|
||||
|
||||
for (index = 0; index < capabilities->cCapabilitiesSets; index++)
|
||||
{
|
||||
capabilitySet = &(capabilities->capabilitySets[index]);
|
||||
|
||||
if ((capabilitySet->capabilitySetType == CB_CAPSTYPE_GENERAL) &&
|
||||
(capabilitySet->capabilitySetLength >= CB_CAPSTYPE_GENERAL_LEN))
|
||||
{
|
||||
CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet
|
||||
= (CLIPRDR_GENERAL_CAPABILITY_SET*) capabilitySet;
|
||||
|
||||
mfc->clipboardCapabilities = generalCapabilitySet->generalFlags;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mac_cliprdr_server_format_list(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_LIST* formatList)
|
||||
{
|
||||
UINT32 index;
|
||||
CLIPRDR_FORMAT* format;
|
||||
mfContext* mfc = (mfContext*) cliprdr->custom;
|
||||
|
||||
if (mfc->serverFormats)
|
||||
{
|
||||
for (index = 0; index < mfc->numServerFormats; index++)
|
||||
{
|
||||
free(mfc->serverFormats[index].formatName);
|
||||
}
|
||||
|
||||
free(mfc->serverFormats);
|
||||
mfc->serverFormats = NULL;
|
||||
mfc->numServerFormats = 0;
|
||||
}
|
||||
|
||||
if (formatList->numFormats < 1)
|
||||
return 1;
|
||||
|
||||
mfc->numServerFormats = formatList->numFormats;
|
||||
mfc->serverFormats = (CLIPRDR_FORMAT*) calloc(mfc->numServerFormats, sizeof(CLIPRDR_FORMAT));
|
||||
|
||||
if (!mfc->serverFormats)
|
||||
return -1;
|
||||
|
||||
for (index = 0; index < mfc->numServerFormats; index++)
|
||||
{
|
||||
mfc->serverFormats[index].formatId = formatList->formats[index].formatId;
|
||||
mfc->serverFormats[index].formatName = NULL;
|
||||
|
||||
if (formatList->formats[index].formatName)
|
||||
mfc->serverFormats[index].formatName = _strdup(formatList->formats[index].formatName);
|
||||
}
|
||||
|
||||
for (index = 0; index < mfc->numServerFormats; index++)
|
||||
{
|
||||
format = &(mfc->serverFormats[index]);
|
||||
|
||||
if (format->formatId == CF_UNICODETEXT)
|
||||
{
|
||||
mac_cliprdr_send_client_format_data_request(cliprdr, CF_UNICODETEXT);
|
||||
break;
|
||||
}
|
||||
else if (format->formatId == CF_TEXT)
|
||||
{
|
||||
mac_cliprdr_send_client_format_data_request(cliprdr, CF_TEXT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mac_cliprdr_server_format_list_response(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mac_cliprdr_server_lock_clipboard_data(CliprdrClientContext* cliprdr, CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mac_cliprdr_server_unlock_clipboard_data(CliprdrClientContext* cliprdr, CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mac_cliprdr_server_format_data_request(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
|
||||
{
|
||||
BYTE* data;
|
||||
UINT32 size;
|
||||
UINT32 formatId;
|
||||
CLIPRDR_FORMAT_DATA_RESPONSE response;
|
||||
mfContext* mfc = (mfContext*) cliprdr->custom;
|
||||
|
||||
ZeroMemory(&response, sizeof(CLIPRDR_FORMAT_DATA_RESPONSE));
|
||||
|
||||
formatId = formatDataRequest->requestedFormatId;
|
||||
data = (BYTE*) ClipboardGetData(mfc->clipboard, formatId, &size);
|
||||
|
||||
response.msgFlags = CB_RESPONSE_OK;
|
||||
response.dataLen = size;
|
||||
response.requestedFormatData = data;
|
||||
|
||||
if (!data)
|
||||
{
|
||||
response.msgFlags = CB_RESPONSE_FAIL;
|
||||
response.dataLen = 0;
|
||||
response.requestedFormatData = NULL;
|
||||
}
|
||||
|
||||
cliprdr->ClientFormatDataResponse(cliprdr, &response);
|
||||
|
||||
free(data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mac_cliprdr_server_format_data_response(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
|
||||
{
|
||||
BYTE* data;
|
||||
UINT32 size;
|
||||
UINT32 index;
|
||||
UINT32 formatId;
|
||||
CLIPRDR_FORMAT* format = NULL;
|
||||
mfContext* mfc = (mfContext*) cliprdr->custom;
|
||||
MRDPView* view = (MRDPView*) mfc->view;
|
||||
|
||||
for (index = 0; index < mfc->numServerFormats; index++)
|
||||
{
|
||||
if (mfc->requestedFormatId == mfc->serverFormats[index].formatId)
|
||||
format = &(mfc->serverFormats[index]);
|
||||
}
|
||||
|
||||
if (!format)
|
||||
{
|
||||
SetEvent(mfc->clipboardRequestEvent);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (format->formatName)
|
||||
formatId = ClipboardRegisterFormat(mfc->clipboard, format->formatName);
|
||||
else
|
||||
formatId = format->formatId;
|
||||
|
||||
size = formatDataResponse->dataLen;
|
||||
data = (BYTE*) malloc(size);
|
||||
CopyMemory(data, formatDataResponse->requestedFormatData, size);
|
||||
|
||||
ClipboardSetData(mfc->clipboard, formatId, data, size);
|
||||
|
||||
SetEvent(mfc->clipboardRequestEvent);
|
||||
|
||||
if ((formatId == CF_TEXT) || (formatId == CF_UNICODETEXT))
|
||||
{
|
||||
formatId = ClipboardRegisterFormat(mfc->clipboard, "UTF8_STRING");
|
||||
|
||||
data = (void*) ClipboardGetData(mfc->clipboard, formatId, &size);
|
||||
NSString* str = [[NSString alloc] initWithBytes: (void*) data length:size encoding:NSUTF8StringEncoding];
|
||||
free(data);
|
||||
|
||||
NSArray* types = [[NSArray alloc] initWithObjects:NSStringPboardType, nil];
|
||||
[view->pasteboard_wr declareTypes:types owner:view];
|
||||
[view->pasteboard_wr setString:str forType:NSStringPboardType];
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mac_cliprdr_server_file_contents_request(CliprdrClientContext* cliprdr, CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mac_cliprdr_server_file_contents_response(CliprdrClientContext* cliprdr, CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void mac_cliprdr_init(mfContext* mfc, CliprdrClientContext* cliprdr)
|
||||
{
|
||||
cliprdr->custom = (void*) mfc;
|
||||
mfc->cliprdr = cliprdr;
|
||||
|
||||
mfc->clipboard = ClipboardCreate();
|
||||
mfc->clipboardRequestEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
cliprdr->MonitorReady = mac_cliprdr_monitor_ready;
|
||||
cliprdr->ServerCapabilities = mac_cliprdr_server_capabilities;
|
||||
cliprdr->ServerFormatList = mac_cliprdr_server_format_list;
|
||||
cliprdr->ServerFormatListResponse = mac_cliprdr_server_format_list_response;
|
||||
cliprdr->ServerLockClipboardData = mac_cliprdr_server_lock_clipboard_data;
|
||||
cliprdr->ServerUnlockClipboardData = mac_cliprdr_server_unlock_clipboard_data;
|
||||
cliprdr->ServerFormatDataRequest = mac_cliprdr_server_format_data_request;
|
||||
cliprdr->ServerFormatDataResponse = mac_cliprdr_server_format_data_response;
|
||||
cliprdr->ServerFileContentsRequest = mac_cliprdr_server_file_contents_request;
|
||||
cliprdr->ServerFileContentsResponse = mac_cliprdr_server_file_contents_response;
|
||||
}
|
||||
|
||||
void mac_cliprdr_uninit(mfContext* mfc, CliprdrClientContext* cliprdr)
|
||||
{
|
||||
cliprdr->custom = NULL;
|
||||
mfc->cliprdr = NULL;
|
||||
|
||||
ClipboardDestroy(mfc->clipboard);
|
||||
CloseHandle(mfc->clipboardRequestEvent);
|
||||
}
|
||||
@@ -51,8 +51,8 @@
|
||||
BOOL skipMoveWindowOnce;
|
||||
|
||||
@public
|
||||
NSPasteboard* pasteboard_rd; /* for reading from clipboard */
|
||||
NSPasteboard* pasteboard_wr; /* for writing to clipboard */
|
||||
NSPasteboard* pasteboard_rd;
|
||||
NSPasteboard* pasteboard_wr;
|
||||
int pasteboard_changecount;
|
||||
int pasteboard_format;
|
||||
int is_connected;
|
||||
@@ -63,6 +63,8 @@
|
||||
- (void) setScrollOffset:(int)xOffset y:(int)yOffset w:(int)width h:(int)height;
|
||||
|
||||
- (void) onPasteboardTimerFired :(NSTimer *) timer;
|
||||
- (void) pause;
|
||||
- (void) resume;
|
||||
- (void) releaseResources;
|
||||
|
||||
@property (assign) int is_connected;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#import "mfreerdp.h"
|
||||
#import "MRDPView.h"
|
||||
#import "MRDPCursor.h"
|
||||
#import "Clipboard.h"
|
||||
#import "PasswordDialog.h"
|
||||
|
||||
#include <winpr/crt.h>
|
||||
@@ -39,8 +40,6 @@
|
||||
#import "freerdp/gdi/dc.h"
|
||||
#import "freerdp/gdi/region.h"
|
||||
#import "freerdp/graphics.h"
|
||||
#import "freerdp/utils/event.h"
|
||||
#import "freerdp/client/cliprdr.h"
|
||||
#import "freerdp/client/file.h"
|
||||
#import "freerdp/client/cmdline.h"
|
||||
#import "freerdp/log.h"
|
||||
@@ -59,39 +58,9 @@ void mac_desktop_resize(rdpContext* context);
|
||||
|
||||
static void update_activity_cb(freerdp* instance);
|
||||
static void input_activity_cb(freerdp* instance);
|
||||
static void channel_activity_cb(freerdp* instance);
|
||||
|
||||
int process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data);
|
||||
int receive_channel_data(freerdp* instance, int chan_id, BYTE* data, int size, int flags, int total_size);
|
||||
|
||||
void process_cliprdr_event(freerdp* instance, wMessage* event);
|
||||
void cliprdr_process_cb_format_list_event(freerdp* instance, RDP_CB_FORMAT_LIST_EVENT* event);
|
||||
void cliprdr_send_data_request(freerdp* instance, UINT32 format);
|
||||
void cliprdr_process_cb_monitor_ready_event(freerdp* inst);
|
||||
void cliprdr_process_cb_data_response_event(freerdp* instance, RDP_CB_DATA_RESPONSE_EVENT* event);
|
||||
void cliprdr_process_text(freerdp* instance, BYTE* data, int len);
|
||||
void cliprdr_send_supported_format_list(freerdp* instance);
|
||||
int register_channel_fds(int* fds, int count, freerdp* instance);
|
||||
|
||||
DWORD mac_client_thread(void* param);
|
||||
|
||||
struct cursor
|
||||
{
|
||||
rdpPointer* pointer;
|
||||
BYTE* cursor_data;
|
||||
void* bmiRep; /* NSBitmapImageRep */
|
||||
void* nsCursor; /* NSCursor */
|
||||
void* nsImage; /* NSImage */
|
||||
};
|
||||
|
||||
struct rgba_data
|
||||
{
|
||||
char red;
|
||||
char green;
|
||||
char blue;
|
||||
char alpha;
|
||||
};
|
||||
|
||||
@implementation MRDPView
|
||||
|
||||
@synthesize is_connected;
|
||||
@@ -183,43 +152,6 @@ DWORD mac_client_input_thread(void* param)
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD mac_client_channels_thread(void* param)
|
||||
{
|
||||
int status;
|
||||
wMessage* event;
|
||||
HANDLE channelsEvent;
|
||||
rdpChannels* channels;
|
||||
rdpContext* context = (rdpContext*) param;
|
||||
|
||||
channels = context->channels;
|
||||
channelsEvent = freerdp_channels_get_event_handle(context->instance);
|
||||
|
||||
while (WaitForSingleObject(channelsEvent, INFINITE) == WAIT_OBJECT_0)
|
||||
{
|
||||
status = freerdp_channels_process_pending_messages(context->instance);
|
||||
|
||||
if (!status)
|
||||
break;
|
||||
|
||||
event = freerdp_channels_pop_event(context->channels);
|
||||
|
||||
if (event)
|
||||
{
|
||||
switch (GetMessageClass(event->id))
|
||||
{
|
||||
case CliprdrChannel_Class:
|
||||
process_cliprdr_event(context->instance, event);
|
||||
break;
|
||||
}
|
||||
|
||||
freerdp_event_free(event);
|
||||
}
|
||||
}
|
||||
|
||||
ExitThread(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD mac_client_thread(void* param)
|
||||
{
|
||||
@autoreleasepool
|
||||
@@ -231,7 +163,6 @@ DWORD mac_client_thread(void* param)
|
||||
HANDLE updateEvent;
|
||||
HANDLE updateThread;
|
||||
HANDLE channelsEvent;
|
||||
HANDLE channelsThread;
|
||||
|
||||
DWORD nCount;
|
||||
rdpContext* context = (rdpContext*) param;
|
||||
@@ -272,14 +203,7 @@ DWORD mac_client_thread(void* param)
|
||||
events[nCount++] = inputEvent = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE);
|
||||
}
|
||||
|
||||
if (settings->AsyncChannels)
|
||||
{
|
||||
channelsThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) mac_client_channels_thread, context, 0, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
events[nCount++] = channelsEvent = freerdp_channels_get_event_handle(instance);
|
||||
}
|
||||
events[nCount++] = channelsEvent = freerdp_channels_get_event_handle(instance);
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -307,12 +231,9 @@ DWORD mac_client_thread(void* param)
|
||||
}
|
||||
}
|
||||
|
||||
if (!settings->AsyncChannels)
|
||||
if (WaitForSingleObject(channelsEvent, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
if (WaitForSingleObject(channelsEvent, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
channel_activity_cb(instance);
|
||||
}
|
||||
freerdp_channels_process_pending_messages(instance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,12 +253,6 @@ DWORD mac_client_thread(void* param)
|
||||
CloseHandle(inputThread);
|
||||
}
|
||||
|
||||
if (settings->AsyncChannels)
|
||||
{
|
||||
WaitForSingleObject(channelsThread, INFINITE);
|
||||
CloseHandle(channelsThread);
|
||||
}
|
||||
|
||||
ExitThread(0);
|
||||
return 0;
|
||||
}
|
||||
@@ -798,21 +713,87 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type)
|
||||
|
||||
- (void) onPasteboardTimerFired :(NSTimer*) timer
|
||||
{
|
||||
int i;
|
||||
NSArray* types;
|
||||
BYTE* data;
|
||||
UINT32 size;
|
||||
UINT32 formatId;
|
||||
BOOL formatMatch;
|
||||
int changeCount;
|
||||
NSData* formatData;
|
||||
const char* formatType;
|
||||
NSPasteboardItem* item;
|
||||
|
||||
i = (int) [pasteboard_rd changeCount];
|
||||
changeCount = (int) [pasteboard_rd changeCount];
|
||||
|
||||
if (i != pasteboard_changecount)
|
||||
if (changeCount == pasteboard_changecount)
|
||||
return;
|
||||
|
||||
pasteboard_changecount = changeCount;
|
||||
|
||||
NSArray* items = [pasteboard_rd pasteboardItems];
|
||||
|
||||
if ([items count] < 1)
|
||||
return;
|
||||
|
||||
item = [items objectAtIndex:0];
|
||||
|
||||
/**
|
||||
* System-Declared Uniform Type Identifiers:
|
||||
* https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html
|
||||
*/
|
||||
|
||||
formatMatch = FALSE;
|
||||
|
||||
for (NSString* type in [item types])
|
||||
{
|
||||
pasteboard_changecount = i;
|
||||
types = [NSArray arrayWithObject:NSStringPboardType];
|
||||
NSString *str = [pasteboard_rd availableTypeFromArray:types];
|
||||
if (str != nil)
|
||||
formatType = [type UTF8String];
|
||||
|
||||
if (strcmp(formatType, "public.utf8-plain-text") == 0)
|
||||
{
|
||||
cliprdr_send_supported_format_list(instance);
|
||||
formatData = [item dataForType:type];
|
||||
formatId = ClipboardRegisterFormat(mfc->clipboard, "UTF8_STRING");
|
||||
|
||||
size = (UINT32) [formatData length];
|
||||
|
||||
data = (BYTE*) malloc(size);
|
||||
[formatData getBytes:data length:size];
|
||||
|
||||
ClipboardSetData(mfc->clipboard, formatId, (void*) data, size);
|
||||
formatMatch = TRUE;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!formatMatch)
|
||||
ClipboardEmpty(mfc->clipboard);
|
||||
|
||||
if (mfc->clipboardSync)
|
||||
mac_cliprdr_send_client_format_list(mfc->cliprdr);
|
||||
}
|
||||
|
||||
- (void) pause
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self->pasteboard_timer invalidate];
|
||||
});
|
||||
|
||||
NSArray* trackingAreas = self.trackingAreas;
|
||||
|
||||
for (NSTrackingArea* ta in trackingAreas)
|
||||
{
|
||||
[self removeTrackingArea:ta];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)resume
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self->pasteboard_timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(onPasteboardTimerFired:) userInfo:nil repeats:YES];
|
||||
});
|
||||
|
||||
NSTrackingArea * trackingArea = [[NSTrackingArea alloc] initWithRect:[self visibleRect] options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag | NSTrackingActiveWhenFirstResponder owner:self userInfo:nil];
|
||||
[self addTrackingArea:trackingArea];
|
||||
[trackingArea release];
|
||||
}
|
||||
|
||||
- (void) setScrollOffset:(int)xOffset y:(int)yOffset w:(int)width h:(int)height
|
||||
@@ -826,6 +807,7 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type)
|
||||
void mac_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEventArgs* e)
|
||||
{
|
||||
rdpSettings* settings = context->settings;
|
||||
mfContext* mfc = (mfContext*) context;
|
||||
|
||||
if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
@@ -836,6 +818,10 @@ void mac_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEve
|
||||
if (settings->SoftwareGdi)
|
||||
gdi_graphics_pipeline_init(context->gdi, (RdpgfxClientContext*) e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
mac_cliprdr_init(mfc, (CliprdrClientContext*) e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
|
||||
@@ -845,6 +831,7 @@ void mac_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEve
|
||||
void mac_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnectedEventArgs* e)
|
||||
{
|
||||
rdpSettings* settings = context->settings;
|
||||
mfContext* mfc = (mfContext*) context;
|
||||
|
||||
if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
@@ -855,6 +842,10 @@ void mac_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnec
|
||||
if (settings->SoftwareGdi)
|
||||
gdi_graphics_pipeline_uninit(context->gdi, (RdpgfxClientContext*) e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
mac_cliprdr_uninit(mfc, (CliprdrClientContext*) e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
|
||||
@@ -963,9 +954,12 @@ BOOL mac_post_connect(freerdp* instance)
|
||||
view->pasteboard_wr = [NSPasteboard generalPasteboard];
|
||||
|
||||
/* setup pasteboard for read operations */
|
||||
view->pasteboard_rd = [NSPasteboard generalPasteboard];
|
||||
view->pasteboard_changecount = (int) [view->pasteboard_rd changeCount];
|
||||
view->pasteboard_timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:mfc->view selector:@selector(onPasteboardTimerFired:) userInfo:nil repeats:YES];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
view->pasteboard_rd = [NSPasteboard generalPasteboard];
|
||||
view->pasteboard_changecount = -1;
|
||||
});
|
||||
|
||||
[view resume];
|
||||
|
||||
mfc->appleKeyboardType = mac_detect_keyboard_type();
|
||||
|
||||
@@ -1272,212 +1266,6 @@ static void input_activity_cb(freerdp* instance)
|
||||
}
|
||||
}
|
||||
|
||||
static void channel_activity_cb(freerdp* instance)
|
||||
{
|
||||
wMessage* event;
|
||||
|
||||
freerdp_channels_process_pending_messages(instance);
|
||||
event = freerdp_channels_pop_event(instance->context->channels);
|
||||
|
||||
if (event)
|
||||
{
|
||||
WLog_DBG(TAG, "channel_activity_cb: message %d", event->id);
|
||||
|
||||
switch (GetMessageClass(event->id))
|
||||
{
|
||||
case CliprdrChannel_Class:
|
||||
process_cliprdr_event(instance, event);
|
||||
break;
|
||||
}
|
||||
|
||||
freerdp_event_free(event);
|
||||
}
|
||||
}
|
||||
|
||||
int process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data)
|
||||
{
|
||||
rdpChannels* channels = (rdpChannels*) user_data;
|
||||
|
||||
freerdp_channels_load_plugin(channels, settings, name, plugin_data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* stuff related to clipboard redirection
|
||||
*/
|
||||
|
||||
void cliprdr_process_cb_data_request_event(freerdp* instance)
|
||||
{
|
||||
int len;
|
||||
NSArray* types;
|
||||
RDP_CB_DATA_RESPONSE_EVENT* event;
|
||||
mfContext* mfc = (mfContext*) instance->context;
|
||||
MRDPView* view = (MRDPView*) mfc->view;
|
||||
|
||||
event = (RDP_CB_DATA_RESPONSE_EVENT*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_DataResponse, NULL, NULL);
|
||||
|
||||
types = [NSArray arrayWithObject:NSStringPboardType];
|
||||
NSString* str = [view->pasteboard_rd availableTypeFromArray:types];
|
||||
|
||||
if (str == nil)
|
||||
{
|
||||
event->data = NULL;
|
||||
event->size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSString* data = [view->pasteboard_rd stringForType:NSStringPboardType];
|
||||
len = (int) ([data length] * 2 + 2);
|
||||
event->data = malloc(len);
|
||||
[data getCString:(char *) event->data maxLength:len encoding:NSUnicodeStringEncoding];
|
||||
event->size = len;
|
||||
}
|
||||
|
||||
freerdp_channels_send_event(instance->context->channels, (wMessage*) event);
|
||||
}
|
||||
|
||||
void cliprdr_send_data_request(freerdp* instance, UINT32 format)
|
||||
{
|
||||
RDP_CB_DATA_REQUEST_EVENT* event;
|
||||
|
||||
event = (RDP_CB_DATA_REQUEST_EVENT*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_DataRequest, NULL, NULL);
|
||||
|
||||
event->format = format;
|
||||
freerdp_channels_send_event(instance->context->channels, (wMessage*) event);
|
||||
}
|
||||
|
||||
/**
|
||||
* at the moment, only the following formats are supported
|
||||
* CF_TEXT
|
||||
* CF_UNICODETEXT
|
||||
*/
|
||||
|
||||
void cliprdr_process_cb_data_response_event(freerdp* instance, RDP_CB_DATA_RESPONSE_EVENT* event)
|
||||
{
|
||||
NSString* str;
|
||||
NSArray* types;
|
||||
mfContext* mfc = (mfContext*) instance->context;
|
||||
MRDPView* view = (MRDPView*) mfc->view;
|
||||
|
||||
if (event->size == 0)
|
||||
return;
|
||||
|
||||
if (view->pasteboard_format == CF_TEXT || view->pasteboard_format == CF_UNICODETEXT)
|
||||
{
|
||||
str = [[NSString alloc] initWithCharacters:(unichar *) event->data length:event->size / 2];
|
||||
types = [[NSArray alloc] initWithObjects:NSStringPboardType, nil];
|
||||
[view->pasteboard_wr declareTypes:types owner:mfc->view];
|
||||
[view->pasteboard_wr setString:str forType:NSStringPboardType];
|
||||
}
|
||||
}
|
||||
|
||||
void cliprdr_process_cb_monitor_ready_event(freerdp* instance)
|
||||
{
|
||||
wMessage* event;
|
||||
RDP_CB_FORMAT_LIST_EVENT* format_list_event;
|
||||
|
||||
event = freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_FormatList, NULL, NULL);
|
||||
|
||||
format_list_event = (RDP_CB_FORMAT_LIST_EVENT*) event;
|
||||
format_list_event->num_formats = 0;
|
||||
|
||||
freerdp_channels_send_event(instance->context->channels, event);
|
||||
}
|
||||
|
||||
/**
|
||||
* list of supported clipboard formats; currently only the following are supported
|
||||
* CF_TEXT
|
||||
* CF_UNICODETEXT
|
||||
*/
|
||||
|
||||
void cliprdr_process_cb_format_list_event(freerdp* instance, RDP_CB_FORMAT_LIST_EVENT* event)
|
||||
{
|
||||
int i;
|
||||
mfContext* mfc = (mfContext*) instance->context;
|
||||
MRDPView* view = (MRDPView*) mfc->view;
|
||||
|
||||
if (event->num_formats == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < event->num_formats; i++)
|
||||
{
|
||||
switch (event->formats[i])
|
||||
{
|
||||
case CF_TEXT:
|
||||
case CF_UNICODETEXT:
|
||||
view->pasteboard_format = CF_UNICODETEXT;
|
||||
cliprdr_send_data_request(instance, CF_UNICODETEXT);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void process_cliprdr_event(freerdp* instance, wMessage* event)
|
||||
{
|
||||
if (event)
|
||||
{
|
||||
switch (GetMessageType(event->id))
|
||||
{
|
||||
/*
|
||||
* Monitor Ready PDU is sent by server to indicate that it has been
|
||||
* initialized and is ready. This PDU is transmitted by the server after it has sent
|
||||
* Clipboard Capabilities PDU
|
||||
*/
|
||||
case CliprdrChannel_MonitorReady:
|
||||
cliprdr_process_cb_monitor_ready_event(instance);
|
||||
break;
|
||||
|
||||
/*
|
||||
* The Format List PDU is sent either by the client or the server when its
|
||||
* local system clipboard is updated with new clipboard data. This PDU
|
||||
* contains the Clipboard Format ID and name pairs of the new Clipboard
|
||||
* Formats on the clipboard
|
||||
*/
|
||||
case CliprdrChannel_FormatList:
|
||||
cliprdr_process_cb_format_list_event(instance, (RDP_CB_FORMAT_LIST_EVENT*) event);
|
||||
break;
|
||||
|
||||
/*
|
||||
* The Format Data Request PDU is sent by the receipient of the Format List PDU.
|
||||
* It is used to request the data for one of the formats that was listed in the
|
||||
* Format List PDU
|
||||
*/
|
||||
case CliprdrChannel_DataRequest:
|
||||
cliprdr_process_cb_data_request_event(instance);
|
||||
break;
|
||||
|
||||
/*
|
||||
* The Format Data Response PDU is sent as a reply to the Format Data Request PDU.
|
||||
* It is used to indicate whether processing of the Format Data Request PDU
|
||||
* was successful. If the processing was successful, the Format Data Response PDU
|
||||
* includes the contents of the requested clipboard data
|
||||
*/
|
||||
case CliprdrChannel_DataResponse:
|
||||
cliprdr_process_cb_data_response_event(instance, (RDP_CB_DATA_RESPONSE_EVENT*) event);
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "process_cliprdr_event: unknown event type %d", GetMessageType(event->id));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cliprdr_send_supported_format_list(freerdp* instance)
|
||||
{
|
||||
RDP_CB_FORMAT_LIST_EVENT* event;
|
||||
|
||||
event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_FormatList, NULL, NULL);
|
||||
|
||||
event->formats = (UINT32*) malloc(sizeof(UINT32) * 1);
|
||||
event->num_formats = 1;
|
||||
event->formats[0] = CF_UNICODETEXT;
|
||||
|
||||
freerdp_channels_send_event(instance->context->channels, (wMessage*) event);
|
||||
}
|
||||
|
||||
/**
|
||||
* given a rect with 0,0 at the top left (windows cords)
|
||||
* convert it to a rect with 0,0 at the bottom left (apple cords)
|
||||
|
||||
@@ -99,10 +99,8 @@ int mfreerdp_client_new(freerdp* instance, rdpContext* context)
|
||||
settings = instance->settings;
|
||||
|
||||
settings->AsyncTransport = TRUE;
|
||||
|
||||
settings->AsyncUpdate = TRUE;
|
||||
settings->AsyncInput = TRUE;
|
||||
settings->AsyncChannels = TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -19,11 +19,13 @@ typedef struct mf_context mfContext;
|
||||
#include <freerdp/client/channels.h>
|
||||
#include <freerdp/client/rdpei.h>
|
||||
#include <freerdp/client/rdpgfx.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
#include <freerdp/client/encomsp.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/clipboard.h>
|
||||
|
||||
#include "MRDPView.h"
|
||||
#include "Keyboard.h"
|
||||
@@ -63,6 +65,15 @@ struct mf_context
|
||||
DWORD keyboardThreadId;
|
||||
BOOL disconnect;
|
||||
BOOL sw_gdi;
|
||||
|
||||
BOOL clipboardSync;
|
||||
wClipboard* clipboard;
|
||||
UINT32 numServerFormats;
|
||||
UINT32 requestedFormatId;
|
||||
HANDLE clipboardRequestEvent;
|
||||
CLIPRDR_FORMAT* serverFormats;
|
||||
CliprdrClientContext* cliprdr;
|
||||
UINT32 clipboardCapabilities;
|
||||
|
||||
rdpFile* connectionRdpFile;
|
||||
|
||||
|
||||
@@ -50,28 +50,12 @@
|
||||
|
||||
#define TAG CLIENT_TAG("sample")
|
||||
|
||||
struct tf_info
|
||||
{
|
||||
void* data;
|
||||
};
|
||||
typedef struct tf_info tfInfo;
|
||||
|
||||
struct tf_context
|
||||
{
|
||||
rdpContext _p;
|
||||
|
||||
tfInfo* tfi;
|
||||
};
|
||||
typedef struct tf_context tfContext;
|
||||
|
||||
HANDLE g_sem;
|
||||
static int g_thread_count = 0;
|
||||
|
||||
struct thread_data
|
||||
{
|
||||
freerdp* instance;
|
||||
};
|
||||
|
||||
int tf_context_new(freerdp* instance, rdpContext* context)
|
||||
{
|
||||
context->channels = freerdp_channels_new();
|
||||
@@ -97,59 +81,12 @@ void tf_end_paint(rdpContext* context)
|
||||
return;
|
||||
}
|
||||
|
||||
int tf_receive_channel_data(freerdp* instance, UINT16 channelId, BYTE* data, int size, int flags, int total_size)
|
||||
{
|
||||
return freerdp_channels_data(instance, channelId, data, size, flags, total_size);
|
||||
}
|
||||
|
||||
void tf_process_cb_monitor_ready_event(rdpChannels* channels, freerdp* instance)
|
||||
{
|
||||
wMessage* event;
|
||||
RDP_CB_FORMAT_LIST_EVENT* format_list_event;
|
||||
|
||||
event = freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_FormatList, NULL, NULL);
|
||||
|
||||
format_list_event = (RDP_CB_FORMAT_LIST_EVENT*) event;
|
||||
format_list_event->num_formats = 0;
|
||||
|
||||
freerdp_channels_send_event(channels, event);
|
||||
}
|
||||
|
||||
void tf_process_channel_event(rdpChannels* channels, freerdp* instance)
|
||||
{
|
||||
wMessage* event;
|
||||
|
||||
event = freerdp_channels_pop_event(channels);
|
||||
|
||||
if (event)
|
||||
{
|
||||
switch (GetMessageType(event->id))
|
||||
{
|
||||
case CliprdrChannel_MonitorReady:
|
||||
tf_process_cb_monitor_ready_event(channels, instance);
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "unknown event type %d", GetMessageType(event->id));
|
||||
break;
|
||||
}
|
||||
|
||||
freerdp_event_free(event);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL tf_pre_connect(freerdp* instance)
|
||||
{
|
||||
tfInfo* tfi;
|
||||
tfContext* context;
|
||||
tfContext* tfc;
|
||||
rdpSettings* settings;
|
||||
|
||||
context = (tfContext*) instance->context;
|
||||
|
||||
tfi = (tfInfo*) malloc(sizeof(tfInfo));
|
||||
ZeroMemory(tfi, sizeof(tfInfo));
|
||||
|
||||
context->tfi = tfi;
|
||||
tfc = (tfContext*) instance->context;
|
||||
|
||||
settings = instance->settings;
|
||||
|
||||
@@ -220,12 +157,14 @@ int tfreerdp_run(freerdp* instance)
|
||||
|
||||
ZeroMemory(rfds, sizeof(rfds));
|
||||
ZeroMemory(wfds, sizeof(wfds));
|
||||
if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE)
|
||||
|
||||
if (!freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get FreeRDP file descriptor");
|
||||
break;
|
||||
}
|
||||
if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != TRUE)
|
||||
|
||||
if (!freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get channel manager file descriptor");
|
||||
break;
|
||||
@@ -261,17 +200,17 @@ int tfreerdp_run(freerdp* instance)
|
||||
}
|
||||
}
|
||||
|
||||
if (freerdp_check_fds(instance) != TRUE)
|
||||
if (!freerdp_check_fds(instance))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
|
||||
break;
|
||||
}
|
||||
if (freerdp_channels_check_fds(channels, instance) != TRUE)
|
||||
|
||||
if (!freerdp_channels_check_fds(channels, instance))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to check channel manager file descriptor");
|
||||
break;
|
||||
}
|
||||
tf_process_channel_event(channels, instance);
|
||||
}
|
||||
|
||||
freerdp_channels_close(channels, instance);
|
||||
@@ -281,21 +220,89 @@ int tfreerdp_run(freerdp* instance)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* thread_func(void* param)
|
||||
void* tf_client_thread_proc(freerdp* instance)
|
||||
{
|
||||
struct thread_data* data;
|
||||
data = (struct thread_data*) param;
|
||||
int i;
|
||||
int fds;
|
||||
int max_fds;
|
||||
int rcount;
|
||||
int wcount;
|
||||
void* rfds[32];
|
||||
void* wfds[32];
|
||||
fd_set rfds_set;
|
||||
fd_set wfds_set;
|
||||
rdpChannels* channels;
|
||||
|
||||
tfreerdp_run(data->instance);
|
||||
channels = instance->context->channels;
|
||||
|
||||
free(data);
|
||||
freerdp_connect(instance);
|
||||
|
||||
pthread_detach(pthread_self());
|
||||
while (1)
|
||||
{
|
||||
rcount = 0;
|
||||
wcount = 0;
|
||||
|
||||
g_thread_count--;
|
||||
ZeroMemory(rfds, sizeof(rfds));
|
||||
ZeroMemory(wfds, sizeof(wfds));
|
||||
|
||||
if (g_thread_count < 1)
|
||||
ReleaseSemaphore(g_sem, 1, NULL);
|
||||
if (!freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get FreeRDP file descriptor");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get channel manager file descriptor");
|
||||
break;
|
||||
}
|
||||
|
||||
max_fds = 0;
|
||||
FD_ZERO(&rfds_set);
|
||||
FD_ZERO(&wfds_set);
|
||||
|
||||
for (i = 0; i < rcount; i++)
|
||||
{
|
||||
fds = (int)(long)(rfds[i]);
|
||||
|
||||
if (fds > max_fds)
|
||||
max_fds = fds;
|
||||
|
||||
FD_SET(fds, &rfds_set);
|
||||
}
|
||||
|
||||
if (max_fds == 0)
|
||||
break;
|
||||
|
||||
if (select(max_fds + 1, &rfds_set, &wfds_set, NULL, NULL) == -1)
|
||||
{
|
||||
/* these are not really errors */
|
||||
if (!((errno == EAGAIN) ||
|
||||
(errno == EWOULDBLOCK) ||
|
||||
(errno == EINPROGRESS) ||
|
||||
(errno == EINTR))) /* signal occurred */
|
||||
{
|
||||
WLog_ERR(TAG, "tfreerdp_run: select failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!freerdp_check_fds(instance))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!freerdp_channels_check_fds(channels, instance))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to check channel manager file descriptor");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
freerdp_channels_close(channels, instance);
|
||||
freerdp_channels_free(channels);
|
||||
freerdp_free(instance);
|
||||
|
||||
ExitThread(0);
|
||||
return NULL;
|
||||
@@ -304,17 +311,13 @@ void* thread_func(void* param)
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int status;
|
||||
pthread_t thread;
|
||||
HANDLE thread;
|
||||
freerdp* instance;
|
||||
rdpChannels* channels;
|
||||
struct thread_data* data;
|
||||
|
||||
g_sem = CreateSemaphore(NULL, 0, 1, NULL);
|
||||
|
||||
instance = freerdp_new();
|
||||
instance->PreConnect = tf_pre_connect;
|
||||
instance->PostConnect = tf_post_connect;
|
||||
instance->ReceiveChannelData = tf_receive_channel_data;
|
||||
|
||||
instance->ContextSize = sizeof(tfContext);
|
||||
instance->ContextNew = tf_context_new;
|
||||
@@ -326,22 +329,16 @@ int main(int argc, char* argv[])
|
||||
status = freerdp_client_settings_parse_command_line(instance->settings, argc, argv);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
|
||||
freerdp_client_load_addins(instance->context->channels, instance->settings);
|
||||
|
||||
data = (struct thread_data*) malloc(sizeof(struct thread_data));
|
||||
ZeroMemory(data, sizeof(sizeof(struct thread_data)));
|
||||
thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)
|
||||
tf_client_thread_proc, instance, 0, NULL);
|
||||
|
||||
data->instance = instance;
|
||||
|
||||
g_thread_count++;
|
||||
pthread_create(&thread, 0, thread_func, data);
|
||||
|
||||
while (g_thread_count > 0)
|
||||
{
|
||||
WaitForSingleObject(g_sem, INFINITE);
|
||||
}
|
||||
WaitForSingleObject(thread, INFINITE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "xfreerdp.h"
|
||||
|
||||
#include "xf_gfx.h"
|
||||
#include "xf_tsmf.h"
|
||||
#include "xf_cliprdr.h"
|
||||
|
||||
void xf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEventArgs* e)
|
||||
@@ -38,6 +39,10 @@ void xf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEven
|
||||
{
|
||||
xfc->rdpei = (RdpeiClientContext*) e->pInterface;
|
||||
}
|
||||
else if (strcmp(e->name, TSMF_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
xf_tsmf_init(xfc, (TsmfClientContext*) e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
if (settings->SoftwareGdi)
|
||||
@@ -64,6 +69,10 @@ void xf_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnect
|
||||
{
|
||||
xfc->rdpei = NULL;
|
||||
}
|
||||
else if (strcmp(e->name, TSMF_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
xf_tsmf_uninit(xfc, (TsmfClientContext*) e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
if (settings->SoftwareGdi)
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/client/channels.h>
|
||||
#include <freerdp/client/rdpei.h>
|
||||
#include <freerdp/client/tsmf.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
#include <freerdp/client/rdpgfx.h>
|
||||
#include <freerdp/client/encomsp.h>
|
||||
|
||||
@@ -104,7 +104,6 @@
|
||||
#include <freerdp/log.h>
|
||||
#define TAG CLIENT_TAG("x11")
|
||||
|
||||
static long xv_port = 0;
|
||||
static const size_t password_size = 512;
|
||||
|
||||
void xf_transform_window(xfContext *xfc)
|
||||
@@ -1020,7 +1019,6 @@ BOOL xf_post_connect(freerdp *instance)
|
||||
|
||||
xfc->clipboard = xf_clipboard_new(xfc);
|
||||
freerdp_channels_post_connect(channels, instance);
|
||||
xf_tsmf_init(xfc, xv_port);
|
||||
|
||||
EventArgsInit(&e, "xfreerdp");
|
||||
e.width = settings->DesktopWidth;
|
||||
@@ -1121,10 +1119,6 @@ void xf_process_channel_event(rdpChannels* channels, freerdp* instance)
|
||||
xf_process_rail_event(xfc, channels, event);
|
||||
break;
|
||||
|
||||
case TsmfChannel_Class:
|
||||
xf_process_tsmf_event(xfc, event);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1195,7 +1189,7 @@ void xf_window_free(xfContext *xfc)
|
||||
|
||||
if (xfc->xv_context)
|
||||
{
|
||||
xf_tsmf_uninit(xfc);
|
||||
xf_tsmf_uninit(xfc, NULL);
|
||||
xfc->xv_context = NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -217,28 +217,6 @@ BOOL xf_set_rop3(xfContext* xfc, int rop3)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
unsigned long xf_gdi_get_color(xfContext* xfc, GDI_COLOR color)
|
||||
{
|
||||
XColor x11_color;
|
||||
|
||||
x11_color.flags = DoRed | DoGreen | DoBlue;
|
||||
GetRGB32(x11_color.red, x11_color.green, x11_color.blue, color);
|
||||
x11_color.red = x11_color.red << 8;
|
||||
x11_color.green = x11_color.green << 8;
|
||||
x11_color.blue = x11_color.blue << 8;
|
||||
|
||||
if (XAllocColor(xfc->display, xfc->colormap, &x11_color) != 0)
|
||||
{
|
||||
XFreeColors(xfc->display, xfc->colormap, &x11_color.pixel, 1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
x11_color.pixel = BlackPixel(xfc->display, xfc->screen_number);
|
||||
}
|
||||
|
||||
return x11_color.pixel;
|
||||
}
|
||||
|
||||
Pixmap xf_brush_new(xfContext* xfc, int width, int height, int bpp, BYTE* data)
|
||||
{
|
||||
GC gc;
|
||||
@@ -488,9 +466,7 @@ void xf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
|
||||
xf_set_rop3(xfc, gdi_rop3_code(patblt->bRop));
|
||||
|
||||
foreColor = freerdp_convert_gdi_order_color(patblt->foreColor, context->settings->ColorDepth, xfc->format, xfc->palette);
|
||||
foreColor = xf_gdi_get_color(xfc, foreColor);
|
||||
backColor = freerdp_convert_gdi_order_color(patblt->backColor, context->settings->ColorDepth, xfc->format, xfc->palette);
|
||||
backColor = xf_gdi_get_color(xfc, backColor);
|
||||
|
||||
if (brush->style == GDI_BS_SOLID)
|
||||
{
|
||||
@@ -610,7 +586,6 @@ void xf_gdi_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect)
|
||||
xf_lock_x11(xfc, FALSE);
|
||||
|
||||
color = freerdp_convert_gdi_order_color(opaque_rect->color, context->settings->ColorDepth, xfc->format, xfc->palette);
|
||||
color = xf_gdi_get_color(xfc, color);
|
||||
|
||||
XSetFunction(xfc->display, xfc->gc, GXcopy);
|
||||
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
|
||||
@@ -646,7 +621,6 @@ void xf_gdi_multi_opaque_rect(rdpContext* context, MULTI_OPAQUE_RECT_ORDER* mult
|
||||
xf_lock_x11(xfc, FALSE);
|
||||
|
||||
color = freerdp_convert_gdi_order_color(multi_opaque_rect->color, context->settings->ColorDepth, xfc->format, xfc->palette);
|
||||
color = xf_gdi_get_color(xfc, color);
|
||||
|
||||
XSetFunction(xfc->display, xfc->gc, GXcopy);
|
||||
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
|
||||
@@ -689,7 +663,6 @@ void xf_gdi_line_to(rdpContext* context, LINE_TO_ORDER* line_to)
|
||||
|
||||
xf_set_rop2(xfc, line_to->bRop2);
|
||||
color = freerdp_convert_gdi_order_color(line_to->penColor, context->settings->ColorDepth, xfc->format, xfc->palette);
|
||||
color = xf_gdi_get_color(xfc, color);
|
||||
|
||||
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
|
||||
XSetForeground(xfc->display, xfc->gc, color);
|
||||
@@ -741,7 +714,6 @@ void xf_gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline)
|
||||
|
||||
xf_set_rop2(xfc, polyline->bRop2);
|
||||
color = freerdp_convert_gdi_order_color(polyline->penColor, context->settings->ColorDepth, xfc->format, xfc->palette);
|
||||
color = xf_gdi_get_color(xfc, color);
|
||||
|
||||
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
|
||||
XSetForeground(xfc->display, xfc->gc, color);
|
||||
@@ -841,9 +813,7 @@ void xf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
|
||||
bitmap = (xfBitmap*) mem3blt->bitmap;
|
||||
xf_set_rop3(xfc, gdi_rop3_code(mem3blt->bRop));
|
||||
foreColor = freerdp_convert_gdi_order_color(mem3blt->foreColor, context->settings->ColorDepth, xfc->format, xfc->palette);
|
||||
foreColor = xf_gdi_get_color(xfc, foreColor);
|
||||
backColor = freerdp_convert_gdi_order_color(mem3blt->backColor, context->settings->ColorDepth, xfc->format, xfc->palette);
|
||||
backColor = xf_gdi_get_color(xfc, backColor);
|
||||
|
||||
if (brush->style == GDI_BS_PATTERN)
|
||||
{
|
||||
@@ -916,7 +886,6 @@ void xf_gdi_polygon_sc(rdpContext* context, POLYGON_SC_ORDER* polygon_sc)
|
||||
|
||||
xf_set_rop2(xfc, polygon_sc->bRop2);
|
||||
brush_color = freerdp_convert_gdi_order_color(polygon_sc->brushColor, context->settings->ColorDepth, xfc->format, xfc->palette);
|
||||
brush_color = xf_gdi_get_color(xfc, brush_color);
|
||||
|
||||
npoints = polygon_sc->numPoints + 1;
|
||||
points = malloc(sizeof(XPoint) * npoints);
|
||||
@@ -978,9 +947,7 @@ void xf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb)
|
||||
brush = &(polygon_cb->brush);
|
||||
xf_set_rop2(xfc, polygon_cb->bRop2);
|
||||
foreColor = freerdp_convert_gdi_order_color(polygon_cb->foreColor, context->settings->ColorDepth, xfc->format, xfc->palette);
|
||||
foreColor = xf_gdi_get_color(xfc, foreColor);
|
||||
backColor = freerdp_convert_gdi_order_color(polygon_cb->backColor, context->settings->ColorDepth, xfc->format, xfc->palette);
|
||||
backColor = xf_gdi_get_color(xfc, backColor);
|
||||
|
||||
npoints = polygon_cb->numPoints + 1;
|
||||
points = malloc(sizeof(XPoint) * npoints);
|
||||
@@ -1005,7 +972,7 @@ void xf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb)
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "PolygonCB unknown fillMode: %d", polygon_cb->fillMode);
|
||||
WLog_ERR(TAG, "PolygonCB unknown fillMode: %d", polygon_cb->fillMode);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -386,9 +386,6 @@ void xf_Glyph_BeginDraw(rdpContext* context, int x, int y, int width, int height
|
||||
|
||||
xf_lock_x11(xfc, FALSE);
|
||||
|
||||
fgcolor = xf_gdi_get_color(xfc, fgcolor);
|
||||
bgcolor = xf_gdi_get_color(xfc, bgcolor);
|
||||
|
||||
XSetFunction(xfc->display, xfc->gc, GXcopy);
|
||||
|
||||
if (width && height)
|
||||
|
||||
@@ -21,9 +21,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
@@ -33,8 +31,6 @@
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/extensions/XShm.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include <freerdp/utils/event.h>
|
||||
#include <freerdp/log.h>
|
||||
#include <freerdp/client/tsmf.h>
|
||||
@@ -46,7 +42,7 @@
|
||||
#include <X11/extensions/Xv.h>
|
||||
#include <X11/extensions/Xvlib.h>
|
||||
|
||||
typedef struct xf_xv_context xfXvContext;
|
||||
static long xv_port = 0;
|
||||
|
||||
struct xf_xv_context
|
||||
{
|
||||
@@ -57,15 +53,256 @@ struct xf_xv_context
|
||||
char* xv_shmaddr;
|
||||
UINT32* xv_pixfmts;
|
||||
};
|
||||
typedef struct xf_xv_context xfXvContext;
|
||||
|
||||
#define TAG CLIENT_TAG("x11")
|
||||
#ifdef WITH_DEBUG_XV
|
||||
#define DEBUG_XV(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_XV(fmt, ...) do { } while (0)
|
||||
#endif
|
||||
|
||||
void xf_tsmf_init(xfContext* xfc, long xv_port)
|
||||
static BOOL xf_tsmf_is_format_supported(xfXvContext* xv, UINT32 pixfmt)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!xv->xv_pixfmts)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; xv->xv_pixfmts[i]; i++)
|
||||
{
|
||||
if (xv->xv_pixfmts[i] == pixfmt)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int xf_tsmf_xv_video_frame_event(TsmfClientContext* tsmf, TSMF_VIDEO_FRAME_EVENT* event)
|
||||
{
|
||||
int i;
|
||||
int x, y;
|
||||
UINT32 width;
|
||||
UINT32 height;
|
||||
BYTE* data1;
|
||||
BYTE* data2;
|
||||
UINT32 pixfmt;
|
||||
UINT32 xvpixfmt;
|
||||
XvImage* image;
|
||||
int colorkey = 0;
|
||||
int numRects = 0;
|
||||
xfContext* xfc;
|
||||
xfXvContext* xv;
|
||||
XRectangle* xrects;
|
||||
XShmSegmentInfo shminfo;
|
||||
BOOL converti420yv12 = FALSE;
|
||||
|
||||
if (!tsmf)
|
||||
return -1;
|
||||
|
||||
xfc = (xfContext*) tsmf->custom;
|
||||
|
||||
if (!xfc)
|
||||
return -1;
|
||||
|
||||
xv = (xfXvContext*) xfc->xv_context;
|
||||
|
||||
if (!xv)
|
||||
return -1;
|
||||
|
||||
if (xv->xv_port == 0)
|
||||
return -1001;
|
||||
|
||||
/* In case the player is minimized */
|
||||
if (event->x < -2048 || event->y < -2048 || event->numVisibleRects < 0)
|
||||
{
|
||||
return -1002;
|
||||
}
|
||||
|
||||
xrects = NULL;
|
||||
numRects = event->numVisibleRects;
|
||||
|
||||
if (numRects > 0)
|
||||
{
|
||||
xrects = (XRectangle*) calloc(numRects, sizeof(XRectangle));
|
||||
|
||||
if (!xrects)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < numRects; i++)
|
||||
{
|
||||
x = event->x + event->visibleRects[i].left;
|
||||
y = event->y + event->visibleRects[i].top;
|
||||
width = event->visibleRects[i].right - event->visibleRects[i].left;
|
||||
height = event->visibleRects[i].bottom - event->visibleRects[i].top;
|
||||
|
||||
xrects[i].x = x;
|
||||
xrects[i].y = y;
|
||||
xrects[i].width = width;
|
||||
xrects[i].height = height;
|
||||
}
|
||||
}
|
||||
|
||||
if (xv->xv_colorkey_atom != None)
|
||||
{
|
||||
XvGetPortAttribute(xfc->display, xv->xv_port, xv->xv_colorkey_atom, &colorkey);
|
||||
XSetFunction(xfc->display, xfc->gc, GXcopy);
|
||||
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
|
||||
XSetForeground(xfc->display, xfc->gc, colorkey);
|
||||
|
||||
if (event->numVisibleRects < 1)
|
||||
{
|
||||
XSetClipMask(xfc->display, xfc->gc, None);
|
||||
}
|
||||
else
|
||||
{
|
||||
XFillRectangles(xfc->display, xfc->window->handle, xfc->gc, xrects, numRects);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
XSetFunction(xfc->display, xfc->gc, GXcopy);
|
||||
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
|
||||
|
||||
if (event->numVisibleRects < 1)
|
||||
{
|
||||
XSetClipMask(xfc->display, xfc->gc, None);
|
||||
}
|
||||
else
|
||||
{
|
||||
XSetClipRectangles(xfc->display, xfc->gc, 0, 0, xrects, numRects, YXBanded);
|
||||
}
|
||||
}
|
||||
|
||||
pixfmt = event->framePixFmt;
|
||||
|
||||
if (xf_tsmf_is_format_supported(xv, pixfmt))
|
||||
{
|
||||
xvpixfmt = pixfmt;
|
||||
}
|
||||
else if (pixfmt == RDP_PIXFMT_I420 && xf_tsmf_is_format_supported(xv, RDP_PIXFMT_YV12))
|
||||
{
|
||||
xvpixfmt = RDP_PIXFMT_YV12;
|
||||
converti420yv12 = TRUE;
|
||||
}
|
||||
else if (pixfmt == RDP_PIXFMT_YV12 && xf_tsmf_is_format_supported(xv, RDP_PIXFMT_I420))
|
||||
{
|
||||
xvpixfmt = RDP_PIXFMT_I420;
|
||||
converti420yv12 = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_DBG(TAG, "pixel format 0x%X not supported by hardware.", pixfmt);
|
||||
return -1003;
|
||||
}
|
||||
|
||||
image = XvShmCreateImage(xfc->display, xv->xv_port,
|
||||
xvpixfmt, 0, event->frameWidth, event->frameHeight, &shminfo);
|
||||
|
||||
if (xv->xv_image_size != image->data_size)
|
||||
{
|
||||
if (xv->xv_image_size > 0)
|
||||
{
|
||||
shmdt(xv->xv_shmaddr);
|
||||
shmctl(xv->xv_shmid, IPC_RMID, NULL);
|
||||
}
|
||||
|
||||
xv->xv_image_size = image->data_size;
|
||||
xv->xv_shmid = shmget(IPC_PRIVATE, image->data_size, IPC_CREAT | 0777);
|
||||
xv->xv_shmaddr = shmat(xv->xv_shmid, 0, 0);
|
||||
}
|
||||
|
||||
shminfo.shmid = xv->xv_shmid;
|
||||
shminfo.shmaddr = image->data = xv->xv_shmaddr;
|
||||
shminfo.readOnly = FALSE;
|
||||
|
||||
if (!XShmAttach(xfc->display, &shminfo))
|
||||
{
|
||||
XFree(image);
|
||||
WLog_DBG(TAG, "XShmAttach failed.");
|
||||
return -1004;
|
||||
}
|
||||
|
||||
/* The video driver may align each line to a different size
|
||||
and we need to convert our original image data. */
|
||||
switch (pixfmt)
|
||||
{
|
||||
case RDP_PIXFMT_I420:
|
||||
case RDP_PIXFMT_YV12:
|
||||
/* Y */
|
||||
if (image->pitches[0] == event->frameWidth)
|
||||
{
|
||||
CopyMemory(image->data + image->offsets[0],
|
||||
event->frameData,
|
||||
event->frameWidth * event->frameHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < event->frameHeight; i++)
|
||||
{
|
||||
CopyMemory(image->data + image->offsets[0] + i * image->pitches[0],
|
||||
event->frameData + i * event->frameWidth,
|
||||
event->frameWidth);
|
||||
}
|
||||
}
|
||||
/* UV */
|
||||
/* Conversion between I420 and YV12 is to simply swap U and V */
|
||||
if (!converti420yv12)
|
||||
{
|
||||
data1 = event->frameData + event->frameWidth * event->frameHeight;
|
||||
data2 = event->frameData + event->frameWidth * event->frameHeight +
|
||||
event->frameWidth * event->frameHeight / 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
data2 = event->frameData + event->frameWidth * event->frameHeight;
|
||||
data1 = event->frameData + event->frameWidth * event->frameHeight +
|
||||
event->frameWidth * event->frameHeight / 4;
|
||||
image->id = pixfmt == RDP_PIXFMT_I420 ? RDP_PIXFMT_YV12 : RDP_PIXFMT_I420;
|
||||
}
|
||||
|
||||
if (image->pitches[1] * 2 == event->frameWidth)
|
||||
{
|
||||
CopyMemory(image->data + image->offsets[1],
|
||||
data1,
|
||||
event->frameWidth * event->frameHeight / 4);
|
||||
CopyMemory(image->data + image->offsets[2],
|
||||
data2,
|
||||
event->frameWidth * event->frameHeight / 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < event->frameHeight / 2; i++)
|
||||
{
|
||||
CopyMemory(image->data + image->offsets[1] + i * image->pitches[1],
|
||||
data1 + i * event->frameWidth / 2,
|
||||
event->frameWidth / 2);
|
||||
CopyMemory(image->data + image->offsets[2] + i * image->pitches[2],
|
||||
data2 + i * event->frameWidth / 2,
|
||||
event->frameWidth / 2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
CopyMemory(image->data, event->frameData, image->data_size <= event->frameSize ?
|
||||
image->data_size : event->frameSize);
|
||||
break;
|
||||
}
|
||||
|
||||
XvShmPutImage(xfc->display, xv->xv_port, xfc->window->handle, xfc->gc,
|
||||
image, 0, 0, image->width, image->height,
|
||||
event->x, event->y, event->width, event->height, FALSE);
|
||||
|
||||
if (xv->xv_colorkey_atom == None)
|
||||
XSetClipMask(xfc->display, xfc->gc, None);
|
||||
|
||||
XSync(xfc->display, FALSE);
|
||||
|
||||
XShmDetach(xfc->display, &shminfo);
|
||||
XFree(image);
|
||||
|
||||
free(xrects);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_tsmf_xv_init(xfContext* xfc, TsmfClientContext* tsmf)
|
||||
{
|
||||
int ret;
|
||||
unsigned int i;
|
||||
@@ -80,8 +317,13 @@ void xf_tsmf_init(xfContext* xfc, long xv_port)
|
||||
XvAttribute* attr;
|
||||
XvImageFormatValues* fo;
|
||||
|
||||
xv = (xfXvContext*) malloc(sizeof(xfXvContext));
|
||||
ZeroMemory(xv, sizeof(xfXvContext));
|
||||
if (xfc->xv_context)
|
||||
return 1; /* context already created */
|
||||
|
||||
xv = (xfXvContext*) calloc(1, sizeof(xfXvContext));
|
||||
|
||||
if (!xv)
|
||||
return -1;
|
||||
|
||||
xfc->xv_context = xv;
|
||||
|
||||
@@ -91,30 +333,34 @@ void xf_tsmf_init(xfContext* xfc, long xv_port)
|
||||
|
||||
if (!XShmQueryExtension(xfc->display))
|
||||
{
|
||||
DEBUG_XV("no shmem available.");
|
||||
return;
|
||||
WLog_DBG(TAG, "no xshm available.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = XvQueryExtension(xfc->display, &version, &release, &request_base, &event_base, &error_base);
|
||||
|
||||
if (ret != Success)
|
||||
{
|
||||
DEBUG_XV("XvQueryExtension failed %d.", ret);
|
||||
return;
|
||||
WLog_DBG(TAG, "XvQueryExtension failed %d.", ret);
|
||||
return -1;
|
||||
}
|
||||
DEBUG_XV("version %u release %u", version, release);
|
||||
|
||||
WLog_DBG(TAG, "version %u release %u", version, release);
|
||||
|
||||
ret = XvQueryAdaptors(xfc->display, DefaultRootWindow(xfc->display),
|
||||
&num_adaptors, &ai);
|
||||
|
||||
if (ret != Success)
|
||||
{
|
||||
DEBUG_XV("XvQueryAdaptors failed %d.", ret);
|
||||
return;
|
||||
WLog_DBG(TAG, "XvQueryAdaptors failed %d.", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_adaptors; i++)
|
||||
{
|
||||
DEBUG_XV("adapter port %ld-%ld (%s)", ai[i].base_id,
|
||||
WLog_DBG(TAG, "adapter port %ld-%ld (%s)", ai[i].base_id,
|
||||
ai[i].base_id + ai[i].num_ports - 1, ai[i].name);
|
||||
|
||||
if (xv->xv_port == 0 && i == num_adaptors - 1)
|
||||
xv->xv_port = ai[i].base_id;
|
||||
}
|
||||
@@ -124,12 +370,13 @@ void xf_tsmf_init(xfContext* xfc, long xv_port)
|
||||
|
||||
if (xv->xv_port == 0)
|
||||
{
|
||||
DEBUG_XV("no adapter selected, video frames will not be processed.");
|
||||
return;
|
||||
WLog_DBG(TAG, "no adapter selected, video frames will not be processed.");
|
||||
return -1;
|
||||
}
|
||||
DEBUG_XV("selected %ld", xv->xv_port);
|
||||
WLog_DBG(TAG, "selected %ld", xv->xv_port);
|
||||
|
||||
attr = XvQueryPortAttributes(xfc->display, xv->xv_port, &ret);
|
||||
|
||||
for (i = 0; i < (unsigned int)ret; i++)
|
||||
{
|
||||
if (strcmp(attr[i].name, "XV_COLORKEY") == 0)
|
||||
@@ -141,29 +388,36 @@ void xf_tsmf_init(xfContext* xfc, long xv_port)
|
||||
}
|
||||
XFree(attr);
|
||||
|
||||
#ifdef WITH_DEBUG_XV
|
||||
WLog_DBG(TAG, "xf_tsmf_init: pixel format ");
|
||||
#endif
|
||||
|
||||
fo = XvListImageFormats(xfc->display, xv->xv_port, &ret);
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
xv->xv_pixfmts = (UINT32*) malloc((ret + 1) * sizeof(UINT32));
|
||||
ZeroMemory(xv->xv_pixfmts, (ret + 1) * sizeof(UINT32));
|
||||
xv->xv_pixfmts = (UINT32*) calloc((ret + 1), sizeof(UINT32));
|
||||
|
||||
for (i = 0; i < ret; i++)
|
||||
{
|
||||
xv->xv_pixfmts[i] = fo[i].id;
|
||||
#ifdef WITH_DEBUG_XV
|
||||
WLog_DBG(TAG, "%c%c%c%c ", ((char*)(xv->xv_pixfmts + i))[0], ((char*)(xv->xv_pixfmts + i))[1],
|
||||
((char*)(xv->xv_pixfmts + i))[2], ((char*)(xv->xv_pixfmts + i))[3]);
|
||||
#endif
|
||||
}
|
||||
xv->xv_pixfmts[i] = 0;
|
||||
}
|
||||
XFree(fo);
|
||||
|
||||
if (tsmf)
|
||||
{
|
||||
xfc->tsmf = tsmf;
|
||||
tsmf->custom = (void*) xfc;
|
||||
|
||||
tsmf->FrameEvent = xf_tsmf_xv_video_frame_event;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void xf_tsmf_uninit(xfContext* xfc)
|
||||
int xf_tsmf_xv_uninit(xfContext* xfc, TsmfClientContext* tsmf)
|
||||
{
|
||||
xfXvContext* xv = (xfXvContext*) xfc->xv_context;
|
||||
|
||||
@@ -182,226 +436,33 @@ void xf_tsmf_uninit(xfContext* xfc)
|
||||
free(xv);
|
||||
xfc->xv_context = NULL;
|
||||
}
|
||||
|
||||
if (xfc->tsmf)
|
||||
{
|
||||
xfc->tsmf->custom = NULL;
|
||||
xfc->tsmf = NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
xf_tsmf_is_format_supported(xfXvContext* xv, UINT32 pixfmt)
|
||||
#endif
|
||||
|
||||
int xf_tsmf_init(xfContext* xfc, TsmfClientContext* tsmf)
|
||||
{
|
||||
int i;
|
||||
#ifdef WITH_XV
|
||||
return xf_tsmf_xv_init(xfc, tsmf);
|
||||
#endif
|
||||
|
||||
if (!xv->xv_pixfmts)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; xv->xv_pixfmts[i]; i++)
|
||||
{
|
||||
if (xv->xv_pixfmts[i] == pixfmt)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void xf_process_tsmf_video_frame_event(xfContext* xfc, RDP_VIDEO_FRAME_EVENT* vevent)
|
||||
int xf_tsmf_uninit(xfContext* xfc, TsmfClientContext* tsmf)
|
||||
{
|
||||
int i;
|
||||
BYTE* data1;
|
||||
BYTE* data2;
|
||||
UINT32 pixfmt;
|
||||
UINT32 xvpixfmt;
|
||||
BOOL converti420yv12 = FALSE;
|
||||
XvImage * image;
|
||||
int colorkey = 0;
|
||||
XShmSegmentInfo shminfo;
|
||||
xfXvContext* xv = (xfXvContext*) xfc->xv_context;
|
||||
#ifdef WITH_XV
|
||||
return xf_tsmf_xv_uninit(xfc, tsmf);
|
||||
#endif
|
||||
|
||||
if (xv->xv_port == 0)
|
||||
return;
|
||||
|
||||
/* In case the player is minimized */
|
||||
if (vevent->x < -2048 || vevent->y < -2048 || vevent->num_visible_rects <= 0)
|
||||
return;
|
||||
|
||||
if (xv->xv_colorkey_atom != None)
|
||||
{
|
||||
XvGetPortAttribute(xfc->display, xv->xv_port, xv->xv_colorkey_atom, &colorkey);
|
||||
XSetFunction(xfc->display, xfc->gc, GXcopy);
|
||||
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
|
||||
XSetForeground(xfc->display, xfc->gc, colorkey);
|
||||
|
||||
for (i = 0; i < vevent->num_visible_rects; i++)
|
||||
{
|
||||
XFillRectangle(xfc->display, xfc->window->handle, xfc->gc,
|
||||
vevent->x + vevent->visible_rects[i].x,
|
||||
vevent->y + vevent->visible_rects[i].y,
|
||||
vevent->visible_rects[i].width,
|
||||
vevent->visible_rects[i].height);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
XSetClipRectangles(xfc->display, xfc->gc, vevent->x, vevent->y,
|
||||
(XRectangle*) vevent->visible_rects, vevent->num_visible_rects, YXBanded);
|
||||
}
|
||||
|
||||
pixfmt = vevent->frame_pixfmt;
|
||||
|
||||
if (xf_tsmf_is_format_supported(xv, pixfmt))
|
||||
{
|
||||
xvpixfmt = pixfmt;
|
||||
}
|
||||
else if (pixfmt == RDP_PIXFMT_I420 && xf_tsmf_is_format_supported(xv, RDP_PIXFMT_YV12))
|
||||
{
|
||||
xvpixfmt = RDP_PIXFMT_YV12;
|
||||
converti420yv12 = TRUE;
|
||||
}
|
||||
else if (pixfmt == RDP_PIXFMT_YV12 && xf_tsmf_is_format_supported(xv, RDP_PIXFMT_I420))
|
||||
{
|
||||
xvpixfmt = RDP_PIXFMT_I420;
|
||||
converti420yv12 = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_XV("pixel format 0x%X not supported by hardware.", pixfmt);
|
||||
return;
|
||||
}
|
||||
|
||||
image = XvShmCreateImage(xfc->display, xv->xv_port,
|
||||
xvpixfmt, 0, vevent->frame_width, vevent->frame_height, &shminfo);
|
||||
|
||||
if (xv->xv_image_size != image->data_size)
|
||||
{
|
||||
if (xv->xv_image_size > 0)
|
||||
{
|
||||
shmdt(xv->xv_shmaddr);
|
||||
shmctl(xv->xv_shmid, IPC_RMID, NULL);
|
||||
}
|
||||
xv->xv_image_size = image->data_size;
|
||||
xv->xv_shmid = shmget(IPC_PRIVATE, image->data_size, IPC_CREAT | 0777);
|
||||
xv->xv_shmaddr = shmat(xv->xv_shmid, 0, 0);
|
||||
}
|
||||
shminfo.shmid = xv->xv_shmid;
|
||||
shminfo.shmaddr = image->data = xv->xv_shmaddr;
|
||||
shminfo.readOnly = FALSE;
|
||||
|
||||
if (!XShmAttach(xfc->display, &shminfo))
|
||||
{
|
||||
XFree(image);
|
||||
DEBUG_XV("XShmAttach failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* The video driver may align each line to a different size
|
||||
and we need to convert our original image data. */
|
||||
switch (pixfmt)
|
||||
{
|
||||
case RDP_PIXFMT_I420:
|
||||
case RDP_PIXFMT_YV12:
|
||||
/* Y */
|
||||
if (image->pitches[0] == vevent->frame_width)
|
||||
{
|
||||
memcpy(image->data + image->offsets[0],
|
||||
vevent->frame_data,
|
||||
vevent->frame_width * vevent->frame_height);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < vevent->frame_height; i++)
|
||||
{
|
||||
memcpy(image->data + image->offsets[0] + i * image->pitches[0],
|
||||
vevent->frame_data + i * vevent->frame_width,
|
||||
vevent->frame_width);
|
||||
}
|
||||
}
|
||||
/* UV */
|
||||
/* Conversion between I420 and YV12 is to simply swap U and V */
|
||||
if (converti420yv12 == FALSE)
|
||||
{
|
||||
data1 = vevent->frame_data + vevent->frame_width * vevent->frame_height;
|
||||
data2 = vevent->frame_data + vevent->frame_width * vevent->frame_height +
|
||||
vevent->frame_width * vevent->frame_height / 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
data2 = vevent->frame_data + vevent->frame_width * vevent->frame_height;
|
||||
data1 = vevent->frame_data + vevent->frame_width * vevent->frame_height +
|
||||
vevent->frame_width * vevent->frame_height / 4;
|
||||
image->id = pixfmt == RDP_PIXFMT_I420 ? RDP_PIXFMT_YV12 : RDP_PIXFMT_I420;
|
||||
}
|
||||
if (image->pitches[1] * 2 == vevent->frame_width)
|
||||
{
|
||||
memcpy(image->data + image->offsets[1],
|
||||
data1,
|
||||
vevent->frame_width * vevent->frame_height / 4);
|
||||
memcpy(image->data + image->offsets[2],
|
||||
data2,
|
||||
vevent->frame_width * vevent->frame_height / 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < vevent->frame_height / 2; i++)
|
||||
{
|
||||
memcpy(image->data + image->offsets[1] + i * image->pitches[1],
|
||||
data1 + i * vevent->frame_width / 2,
|
||||
vevent->frame_width / 2);
|
||||
memcpy(image->data + image->offsets[2] + i * image->pitches[2],
|
||||
data2 + i * vevent->frame_width / 2,
|
||||
vevent->frame_width / 2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
memcpy(image->data, vevent->frame_data, image->data_size <= vevent->frame_size ?
|
||||
image->data_size : vevent->frame_size);
|
||||
break;
|
||||
}
|
||||
|
||||
XvShmPutImage(xfc->display, xv->xv_port, xfc->window->handle, xfc->gc, image,
|
||||
0, 0, image->width, image->height,
|
||||
vevent->x, vevent->y, vevent->width, vevent->height, FALSE);
|
||||
if (xv->xv_colorkey_atom == None)
|
||||
XSetClipMask(xfc->display, xfc->gc, None);
|
||||
XSync(xfc->display, FALSE);
|
||||
|
||||
XShmDetach(xfc->display, &shminfo);
|
||||
XFree(image);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void xf_process_tsmf_redraw_event(xfContext* xfc, RDP_REDRAW_EVENT* revent)
|
||||
{
|
||||
XSetFunction(xfc->display, xfc->gc, GXcopy);
|
||||
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
|
||||
XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc,
|
||||
revent->x, revent->y, revent->width, revent->height, revent->x, revent->y);
|
||||
}
|
||||
|
||||
void xf_process_tsmf_event(xfContext* xfc, wMessage* event)
|
||||
{
|
||||
switch (GetMessageType(event->id))
|
||||
{
|
||||
case TsmfChannel_VideoFrame:
|
||||
xf_process_tsmf_video_frame_event(xfc, (RDP_VIDEO_FRAME_EVENT*) event);
|
||||
break;
|
||||
|
||||
case TsmfChannel_Redraw:
|
||||
xf_process_tsmf_redraw_event(xfc, (RDP_REDRAW_EVENT*) event);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#else /* WITH_XV */
|
||||
|
||||
void xf_tsmf_init(xfContext* xfc, long xv_port)
|
||||
{
|
||||
}
|
||||
|
||||
void xf_tsmf_uninit(xfContext* xfc)
|
||||
{
|
||||
}
|
||||
|
||||
void xf_process_tsmf_event(xfContext* xfc, wMessage* event)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* WITH_XV */
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
#include "xf_client.h"
|
||||
#include "xfreerdp.h"
|
||||
|
||||
void xf_tsmf_init(xfContext* xfc, long xv_port);
|
||||
void xf_tsmf_uninit(xfContext* xfc);
|
||||
void xf_process_tsmf_event(xfContext* xfc, wMessage* event);
|
||||
int xf_tsmf_init(xfContext* xfc, TsmfClientContext* tsmf);
|
||||
int xf_tsmf_uninit(xfContext* xfc, TsmfClientContext* tsmf);
|
||||
|
||||
#endif /* __XF_TSMF_H */
|
||||
|
||||
@@ -158,6 +158,7 @@ struct xf_context
|
||||
BOOL complex_regions;
|
||||
VIRTUAL_SCREEN vscreen;
|
||||
void* xv_context;
|
||||
TsmfClientContext* tsmf;
|
||||
xfClipboard* clipboard;
|
||||
CliprdrClientContext* cliprdr;
|
||||
|
||||
@@ -248,8 +249,6 @@ void xf_unlock_x11(xfContext* xfc, BOOL display);
|
||||
void xf_draw_screen_scaled(xfContext* xfc, int x, int y, int w, int h, BOOL scale);
|
||||
void xf_transform_window(xfContext* xfc);
|
||||
|
||||
unsigned long xf_gdi_get_color(xfContext* xfc, GDI_COLOR color);
|
||||
|
||||
FREERDP_API DWORD xf_exit_code_from_disconnect_reason(DWORD reason);
|
||||
|
||||
#endif /* __XFREERDP_H */
|
||||
|
||||
@@ -18,46 +18,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _TSMF_H_
|
||||
#define _TSMF_H_
|
||||
#ifndef FREERDP_CHANNEL_TSMF_H
|
||||
#define FREERDP_CHANNEL_TSMF_H
|
||||
|
||||
#include <freerdp/types.h>
|
||||
|
||||
/* Callback function setup order:
|
||||
*
|
||||
* When the channel is loaded, it calls TSMF_REGISTER to register the
|
||||
* decoder handle with the client.
|
||||
* The client then stores the handle and calls TSMF_REGISTER_INSTANCE
|
||||
* to give the channel the current handle to the session necessary
|
||||
* to call other functions.
|
||||
* After this initial setup the other functions can be used.
|
||||
*/
|
||||
/* Functions called from client -> registered by channel */
|
||||
#define TSMF_GET_INSTANCE "tsmf_get_instance"
|
||||
typedef void (*tsmf_get_instance)(void *instance, void *decoder);
|
||||
|
||||
#define TSMF_ADD_WINDOW_HANDLE "tsmf_add_window_handle"
|
||||
typedef void (*tsmf_add_window_handle)(void *instance, void *decoder, void *window);
|
||||
|
||||
#define TSMF_DEL_WINDOW_HANDLE "tsmf_del_window_handle"
|
||||
typedef void (*tsmf_del_window_handle)(void *instance, void *decoder);
|
||||
|
||||
/* Functions called from channel -> registered by client */
|
||||
#define TSMF_REGISTER "tsmf_register"
|
||||
typedef void (*tsmf_register)(void *instance, void *decoder);
|
||||
|
||||
#define TSMF_DESTROY "tsmf_destroy"
|
||||
typedef void (*tsmf_destroy)(void *instance, void *decoder);
|
||||
|
||||
#define TSMF_PLAY "tsmf_play"
|
||||
typedef void (*tsmf_play)(void *instance, void *decoder);
|
||||
|
||||
#define TSMF_PAUSE "tsmf_pause"
|
||||
typedef void (*tsmf_pause)(void *instance, void *decoder);
|
||||
|
||||
#define TSMF_RESIZE_WINDOW "tsmf_resize_window"
|
||||
typedef void (*tsmf_resize_window)(void *instance, void *decoder, int x, int y, int width,
|
||||
int height, int nr_rect, RDP_RECT *visible);
|
||||
|
||||
#endif
|
||||
#define TSMF_DVC_CHANNEL_NAME "TSMF"
|
||||
|
||||
#endif /* FREERDP_CHANNEL_TSMF_H */
|
||||
|
||||
@@ -20,36 +20,45 @@
|
||||
#ifndef FREERDP_CHANNEL_CLIENT_TSMF_H
|
||||
#define FREERDP_CHANNEL_CLIENT_TSMF_H
|
||||
|
||||
struct _RDP_VIDEO_FRAME_EVENT
|
||||
{
|
||||
wMessage event;
|
||||
BYTE* frame_data;
|
||||
UINT32 frame_size;
|
||||
UINT32 frame_pixfmt;
|
||||
INT16 frame_width;
|
||||
INT16 frame_height;
|
||||
INT16 x;
|
||||
INT16 y;
|
||||
INT16 width;
|
||||
INT16 height;
|
||||
UINT16 num_visible_rects;
|
||||
RDP_RECT* visible_rects;
|
||||
};
|
||||
typedef struct _RDP_VIDEO_FRAME_EVENT RDP_VIDEO_FRAME_EVENT;
|
||||
#include <freerdp/codec/region.h>
|
||||
|
||||
struct _RDP_REDRAW_EVENT
|
||||
{
|
||||
wMessage event;
|
||||
INT16 x;
|
||||
INT16 y;
|
||||
INT16 width;
|
||||
INT16 height;
|
||||
};
|
||||
typedef struct _RDP_REDRAW_EVENT RDP_REDRAW_EVENT;
|
||||
#include <freerdp/channels/tsmf.h>
|
||||
|
||||
/* RDP_VIDEO_FRAME_EVENT.frame_pixfmt */
|
||||
/* http://www.fourcc.org/yuv.php */
|
||||
#define RDP_PIXFMT_I420 0x30323449
|
||||
#define RDP_PIXFMT_YV12 0x32315659
|
||||
|
||||
struct _TSMF_VIDEO_FRAME_EVENT
|
||||
{
|
||||
BYTE* frameData;
|
||||
UINT32 frameSize;
|
||||
UINT32 framePixFmt;
|
||||
INT16 frameWidth;
|
||||
INT16 frameHeight;
|
||||
INT16 x;
|
||||
INT16 y;
|
||||
INT16 width;
|
||||
INT16 height;
|
||||
UINT16 numVisibleRects;
|
||||
RECTANGLE_16* visibleRects;
|
||||
};
|
||||
typedef struct _TSMF_VIDEO_FRAME_EVENT TSMF_VIDEO_FRAME_EVENT;
|
||||
|
||||
/**
|
||||
* Client Interface
|
||||
*/
|
||||
|
||||
typedef struct _tsmf_client_context TsmfClientContext;
|
||||
|
||||
typedef int (*pcTsmfFrameEvent)(TsmfClientContext* context, TSMF_VIDEO_FRAME_EVENT* event);
|
||||
|
||||
struct _tsmf_client_context
|
||||
{
|
||||
void* handle;
|
||||
void* custom;
|
||||
|
||||
pcTsmfFrameEvent FrameEvent;
|
||||
};
|
||||
|
||||
#endif /* FREERDP_CHANNEL_CLIENT_TSMF_H */
|
||||
|
||||
@@ -87,6 +87,9 @@ struct rdp_shadow_client
|
||||
rdpShadowEncoder* encoder;
|
||||
rdpShadowSubsystem* subsystem;
|
||||
|
||||
UINT32 pointerX;
|
||||
UINT32 pointerY;
|
||||
|
||||
HANDLE vcm;
|
||||
EncomspServerContext* encomsp;
|
||||
RemdeskServerContext* remdesk;
|
||||
@@ -145,6 +148,8 @@ struct _RDP_SHADOW_ENTRY_POINTS
|
||||
REGION16 invalidRegion; \
|
||||
wMessagePipe* MsgPipe; \
|
||||
SYNCHRONIZATION_BARRIER barrier; \
|
||||
UINT32 pointerX; \
|
||||
UINT32 pointerY; \
|
||||
\
|
||||
pfnShadowSynchronizeEvent SynchronizeEvent; \
|
||||
pfnShadowKeyboardEvent KeyboardEvent; \
|
||||
|
||||
@@ -105,7 +105,7 @@ static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_a
|
||||
if (status != 0)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WLog_ERR(_T("getaddrinfo error: %s"), gai_strerror(status));
|
||||
WLog_ERR("getaddrinfo error: %s", gai_strerrorA(status));
|
||||
#else
|
||||
WLog_ERR(TAG, "getaddrinfo");
|
||||
#endif
|
||||
|
||||
@@ -1506,9 +1506,25 @@ static void update_send_pointer_system(rdpContext* context, POINTER_SYSTEM_UPDAT
|
||||
Stream_Release(s);
|
||||
}
|
||||
|
||||
static void update_send_pointer_position(rdpContext* context, POINTER_POSITION_UPDATE* pointerPosition)
|
||||
{
|
||||
wStream* s;
|
||||
rdpRdp* rdp = context->rdp;
|
||||
|
||||
s = fastpath_update_pdu_init(rdp->fastpath);
|
||||
|
||||
Stream_EnsureRemainingCapacity(s, 16);
|
||||
|
||||
Stream_Write_UINT16(s, pointerPosition->xPos); /* xPos (2 bytes) */
|
||||
Stream_Write_UINT16(s, pointerPosition->yPos); /* yPos (2 bytes) */
|
||||
|
||||
fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_PTR_POSITION, s, FALSE);
|
||||
Stream_Release(s);
|
||||
}
|
||||
|
||||
static void update_write_pointer_color(wStream* s, POINTER_COLOR_UPDATE* pointer_color)
|
||||
{
|
||||
Stream_EnsureRemainingCapacity(s, 15 + (int) pointer_color->lengthAndMask + (int) pointer_color->lengthXorMask);
|
||||
Stream_EnsureRemainingCapacity(s, 32 + (int) pointer_color->lengthAndMask + (int) pointer_color->lengthXorMask);
|
||||
|
||||
Stream_Write_UINT16(s, pointer_color->cacheIndex);
|
||||
Stream_Write_UINT16(s, pointer_color->xPos);
|
||||
@@ -1544,9 +1560,14 @@ static void update_send_pointer_new(rdpContext* context, POINTER_NEW_UPDATE* poi
|
||||
rdpRdp* rdp = context->rdp;
|
||||
|
||||
s = fastpath_update_pdu_init(rdp->fastpath);
|
||||
|
||||
Stream_EnsureRemainingCapacity(s, 16);
|
||||
|
||||
Stream_Write_UINT16(s, pointer_new->xorBpp); /* xorBpp (2 bytes) */
|
||||
update_write_pointer_color(s, &pointer_new->colorPtrAttr);
|
||||
|
||||
fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_POINTER, s, FALSE);
|
||||
|
||||
Stream_Release(s);
|
||||
}
|
||||
|
||||
@@ -1614,14 +1635,14 @@ BOOL update_read_suppress_output(rdpUpdate* update, wStream* s)
|
||||
|
||||
static void update_send_set_keyboard_indicators(rdpContext* context, UINT16 led_flags)
|
||||
{
|
||||
wStream* s;
|
||||
rdpRdp* rdp = context->rdp;
|
||||
wStream* s;
|
||||
rdpRdp* rdp = context->rdp;
|
||||
|
||||
s = rdp_data_pdu_init(rdp);
|
||||
Stream_Write_UINT16(s, 0); /* unitId should be 0 according to MS-RDPBCGR 2.2.8.2.1.1 */
|
||||
Stream_Write_UINT16(s, led_flags); /* ledFlags (2 bytes) */
|
||||
rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS, rdp->mcs->userId);
|
||||
Stream_Release(s);
|
||||
s = rdp_data_pdu_init(rdp);
|
||||
Stream_Write_UINT16(s, 0); /* unitId should be 0 according to MS-RDPBCGR 2.2.8.2.1.1 */
|
||||
Stream_Write_UINT16(s, led_flags); /* ledFlags (2 bytes) */
|
||||
rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS, rdp->mcs->userId);
|
||||
Stream_Release(s);
|
||||
}
|
||||
|
||||
void update_register_server_callbacks(rdpUpdate* update)
|
||||
@@ -1655,6 +1676,7 @@ void update_register_server_callbacks(rdpUpdate* update)
|
||||
update->altsec->CreateOffscreenBitmap = update_send_create_offscreen_bitmap_order;
|
||||
update->altsec->SwitchSurface = update_send_switch_surface_order;
|
||||
update->pointer->PointerSystem = update_send_pointer_system;
|
||||
update->pointer->PointerPosition = update_send_pointer_position;
|
||||
update->pointer->PointerColor = update_send_pointer_color;
|
||||
update->pointer->PointerNew = update_send_pointer_new;
|
||||
update->pointer->PointerCached = update_send_pointer_cached;
|
||||
|
||||
@@ -528,7 +528,7 @@ static void gdi_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmapUpdate)
|
||||
pSrcData = gdi->bitmap_buffer;
|
||||
}
|
||||
|
||||
nSrcStep = nWidth * 4;
|
||||
nSrcStep = nWidth * gdi->bytesPerPixel;
|
||||
|
||||
pDstData = gdi->primary_buffer;
|
||||
nDstStep = gdi->width * gdi->bytesPerPixel;
|
||||
|
||||
@@ -21,16 +21,11 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include <freerdp/message.h>
|
||||
#include <freerdp/utils/event.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
#include <freerdp/client/tsmf.h>
|
||||
#include <freerdp/rail.h>
|
||||
|
||||
static wMessage* freerdp_cliprdr_event_new(UINT16 event_type)
|
||||
@@ -109,33 +104,6 @@ static wMessage* freerdp_cliprdr_event_new(UINT16 event_type)
|
||||
return event.m;
|
||||
}
|
||||
|
||||
static wMessage* freerdp_tsmf_event_new(UINT16 event_type)
|
||||
{
|
||||
union
|
||||
{
|
||||
void *v;
|
||||
wMessage* m;
|
||||
} event;
|
||||
|
||||
event.m = NULL;
|
||||
switch (event_type)
|
||||
{
|
||||
case TsmfChannel_VideoFrame:
|
||||
event.v = malloc(sizeof(RDP_VIDEO_FRAME_EVENT));
|
||||
ZeroMemory(event.v, sizeof(RDP_VIDEO_FRAME_EVENT));
|
||||
event.m->id = MakeMessageId(TsmfChannel, VideoFrame);
|
||||
break;
|
||||
|
||||
case TsmfChannel_Redraw:
|
||||
event.v = malloc(sizeof(RDP_REDRAW_EVENT));
|
||||
ZeroMemory(event.v, sizeof(RDP_REDRAW_EVENT));
|
||||
event.m->id = MakeMessageId(TsmfChannel, Redraw);
|
||||
break;
|
||||
}
|
||||
|
||||
return event.v;
|
||||
}
|
||||
|
||||
static wMessage* freerdp_rail_event_new(UINT16 event_type)
|
||||
{
|
||||
wMessage* event = NULL;
|
||||
@@ -153,19 +121,10 @@ wMessage* freerdp_event_new(UINT16 event_class, UINT16 event_type,
|
||||
|
||||
switch (event_class)
|
||||
{
|
||||
case DebugChannel_Class:
|
||||
event = (wMessage*) malloc(sizeof(wMessage));
|
||||
ZeroMemory(event, sizeof(wMessage));
|
||||
break;
|
||||
|
||||
case CliprdrChannel_Class:
|
||||
event = freerdp_cliprdr_event_new(event_type);
|
||||
break;
|
||||
|
||||
case TsmfChannel_Class:
|
||||
event = freerdp_tsmf_event_new(event_type);
|
||||
break;
|
||||
|
||||
case RailChannel_Class:
|
||||
event = freerdp_rail_event_new(event_type);
|
||||
break;
|
||||
@@ -202,20 +161,6 @@ static void freerdp_cliprdr_event_free(wMessage* event)
|
||||
}
|
||||
}
|
||||
|
||||
static void freerdp_tsmf_event_free(wMessage* event)
|
||||
{
|
||||
switch (GetMessageType(event->id))
|
||||
{
|
||||
case TsmfChannel_VideoFrame:
|
||||
{
|
||||
RDP_VIDEO_FRAME_EVENT* vevent = (RDP_VIDEO_FRAME_EVENT*)event;
|
||||
free(vevent->frame_data);
|
||||
free(vevent->visible_rects);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void freerdp_rail_event_free(wMessage* event)
|
||||
{
|
||||
|
||||
@@ -234,10 +179,6 @@ void freerdp_event_free(wMessage* event)
|
||||
freerdp_cliprdr_event_free(event);
|
||||
break;
|
||||
|
||||
case TsmfChannel_Class:
|
||||
freerdp_tsmf_event_free(event);
|
||||
break;
|
||||
|
||||
case RailChannel_Class:
|
||||
freerdp_rail_event_free(event);
|
||||
break;
|
||||
|
||||
@@ -231,11 +231,13 @@ void x11_shadow_input_keyboard_event(x11ShadowSubsystem* subsystem, UINT16 flags
|
||||
XTestGrabControl(subsystem->display, True);
|
||||
|
||||
if (flags & KBD_FLAGS_DOWN)
|
||||
XTestFakeKeyEvent(subsystem->display, keycode, True, 0);
|
||||
XTestFakeKeyEvent(subsystem->display, keycode, True, CurrentTime);
|
||||
else if (flags & KBD_FLAGS_RELEASE)
|
||||
XTestFakeKeyEvent(subsystem->display, keycode, False, 0);
|
||||
XTestFakeKeyEvent(subsystem->display, keycode, False, CurrentTime);
|
||||
|
||||
XTestGrabControl(subsystem->display, False);
|
||||
|
||||
XFlush(subsystem->display);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -276,13 +278,13 @@ void x11_shadow_input_mouse_event(x11ShadowSubsystem* subsystem, UINT16 flags, U
|
||||
|
||||
button = (negative) ? 5 : 4;
|
||||
|
||||
XTestFakeButtonEvent(subsystem->display, button, True, 0);
|
||||
XTestFakeButtonEvent(subsystem->display, button, False, 0);
|
||||
XTestFakeButtonEvent(subsystem->display, button, True, CurrentTime);
|
||||
XTestFakeButtonEvent(subsystem->display, button, False, CurrentTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flags & PTR_FLAGS_MOVE)
|
||||
XTestFakeMotionEvent(subsystem->display, 0, x, y, 0);
|
||||
XTestFakeMotionEvent(subsystem->display, 0, x, y, CurrentTime);
|
||||
|
||||
if (flags & PTR_FLAGS_BUTTON1)
|
||||
button = 1;
|
||||
@@ -295,10 +297,12 @@ void x11_shadow_input_mouse_event(x11ShadowSubsystem* subsystem, UINT16 flags, U
|
||||
down = TRUE;
|
||||
|
||||
if (button)
|
||||
XTestFakeButtonEvent(subsystem->display, button, down, 0);
|
||||
XTestFakeButtonEvent(subsystem->display, button, down, CurrentTime);
|
||||
}
|
||||
|
||||
XTestGrabControl(subsystem->display, False);
|
||||
|
||||
XFlush(subsystem->display);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -335,12 +339,63 @@ void x11_shadow_input_extended_mouse_event(x11ShadowSubsystem* subsystem, UINT16
|
||||
down = TRUE;
|
||||
|
||||
if (button)
|
||||
XTestFakeButtonEvent(subsystem->display, button, down, 0);
|
||||
XTestFakeButtonEvent(subsystem->display, button, down, CurrentTime);
|
||||
|
||||
XTestGrabControl(subsystem->display, False);
|
||||
|
||||
XFlush(subsystem->display);
|
||||
#endif
|
||||
}
|
||||
|
||||
int x11_shadow_pointer_position_update(x11ShadowSubsystem* subsystem)
|
||||
{
|
||||
SHADOW_MSG_OUT_POINTER_POSITION_UPDATE* msg;
|
||||
UINT32 msgId = SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID;
|
||||
wMessagePipe* MsgPipe = subsystem->MsgPipe;
|
||||
|
||||
msg = (SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*) calloc(1, sizeof(SHADOW_MSG_OUT_POINTER_POSITION_UPDATE));
|
||||
|
||||
if (!msg)
|
||||
return -1;
|
||||
|
||||
msg->xPos = subsystem->pointerX;
|
||||
msg->yPos = subsystem->pointerY;
|
||||
|
||||
MessageQueue_Post(MsgPipe->Out, NULL, msgId, (void*) msg, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int x11_shadow_pointer_alpha_update(x11ShadowSubsystem* subsystem)
|
||||
{
|
||||
SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* msg;
|
||||
UINT32 msgId = SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID;
|
||||
wMessagePipe* MsgPipe = subsystem->MsgPipe;
|
||||
|
||||
msg = (SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*) calloc(1, sizeof(SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE));
|
||||
|
||||
if (!msg)
|
||||
return -1;
|
||||
|
||||
msg->xHot = subsystem->cursorHotX;
|
||||
msg->yHot = subsystem->cursorHotY;
|
||||
msg->width = subsystem->cursorWidth;
|
||||
msg->height = subsystem->cursorHeight;
|
||||
msg->scanline = msg->width * 4;
|
||||
|
||||
msg->pixels = (BYTE*) malloc(msg->scanline * msg->height);
|
||||
|
||||
if (!msg->pixels)
|
||||
return -1;
|
||||
|
||||
CopyMemory(msg->pixels, subsystem->cursorPixels, msg->scanline * msg->height);
|
||||
msg->premultiplied = TRUE;
|
||||
|
||||
MessageQueue_Post(MsgPipe->Out, NULL, msgId, (void*) msg, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage)
|
||||
{
|
||||
int x, y, n, k;
|
||||
@@ -358,6 +413,9 @@ int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage)
|
||||
|
||||
ci = XFixesGetCursorImage(subsystem->display);
|
||||
|
||||
if (!ci)
|
||||
return -1;
|
||||
|
||||
x = ci->x;
|
||||
y = ci->y;
|
||||
|
||||
@@ -385,6 +443,8 @@ int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage)
|
||||
}
|
||||
|
||||
XFree(ci);
|
||||
|
||||
x11_shadow_pointer_alpha_update(subsystem);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@@ -404,8 +464,13 @@ int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage)
|
||||
y = root_y;
|
||||
}
|
||||
|
||||
subsystem->cursorX = x;
|
||||
subsystem->cursorY = y;
|
||||
if ((x != subsystem->pointerX) || (y != subsystem->pointerY))
|
||||
{
|
||||
subsystem->pointerX = x;
|
||||
subsystem->pointerY = y;
|
||||
|
||||
x11_shadow_pointer_position_update(subsystem);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -416,13 +481,16 @@ int x11_shadow_handle_xevent(x11ShadowSubsystem* subsystem, XEvent* xevent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#ifdef WITH_XFIXES
|
||||
if (xevent->type == subsystem->xfixes_cursor_notify_event)
|
||||
else if (xevent->type == subsystem->xfixes_cursor_notify_event)
|
||||
{
|
||||
x11_shadow_query_cursor(subsystem, TRUE);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -473,8 +541,8 @@ int x11_shadow_blend_cursor(x11ShadowSubsystem* subsystem)
|
||||
nWidth = subsystem->cursorWidth;
|
||||
nHeight = subsystem->cursorHeight;
|
||||
|
||||
nXDst = subsystem->cursorX - surface->x - subsystem->cursorHotX;
|
||||
nYDst = subsystem->cursorY - surface->y - subsystem->cursorHotY;
|
||||
nXDst = subsystem->pointerX - surface->x - subsystem->cursorHotX;
|
||||
nYDst = subsystem->pointerY - surface->y - subsystem->cursorHotY;
|
||||
|
||||
if (nXDst >= surface->width)
|
||||
return 1;
|
||||
@@ -633,7 +701,7 @@ int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
|
||||
(BYTE*) image->data, PIXEL_FORMAT_XRGB32,
|
||||
image->bytes_per_line, x, y, NULL);
|
||||
|
||||
x11_shadow_blend_cursor(subsystem);
|
||||
//x11_shadow_blend_cursor(subsystem);
|
||||
|
||||
count = ArrayList_Count(server->clients);
|
||||
|
||||
@@ -767,8 +835,8 @@ void* x11_shadow_subsystem_thread(x11ShadowSubsystem* subsystem)
|
||||
|
||||
if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime))
|
||||
{
|
||||
x11_shadow_query_cursor(subsystem, FALSE);
|
||||
x11_shadow_screen_grab(subsystem);
|
||||
x11_shadow_query_cursor(subsystem, FALSE);
|
||||
|
||||
dwInterval = 1000 / subsystem->captureFrameRate;
|
||||
frameTime += dwInterval;
|
||||
@@ -804,7 +872,7 @@ int x11_shadow_subsystem_base_init(x11ShadowSubsystem* subsystem)
|
||||
subsystem->depth = DefaultDepthOfScreen(subsystem->screen);
|
||||
subsystem->width = WidthOfScreen(subsystem->screen);
|
||||
subsystem->height = HeightOfScreen(subsystem->screen);
|
||||
subsystem->root_window = DefaultRootWindow(subsystem->display);
|
||||
subsystem->root_window = RootWindow(subsystem->display, subsystem->number);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -824,7 +892,8 @@ int x11_shadow_xfixes_init(x11ShadowSubsystem* subsystem)
|
||||
|
||||
subsystem->xfixes_cursor_notify_event = xfixes_event + XFixesCursorNotify;
|
||||
|
||||
XFixesSelectCursorInput(subsystem->display, DefaultRootWindow(subsystem->display), XFixesDisplayCursorNotifyMask);
|
||||
XFixesSelectCursorInput(subsystem->display, subsystem->root_window,
|
||||
XFixesDisplayCursorNotifyMask);
|
||||
|
||||
return 1;
|
||||
#else
|
||||
|
||||
@@ -80,8 +80,6 @@ struct x11_shadow_subsystem
|
||||
Window root_window;
|
||||
XShmSegmentInfo fb_shm_info;
|
||||
|
||||
int cursorX;
|
||||
int cursorY;
|
||||
int cursorHotX;
|
||||
int cursorHotY;
|
||||
int cursorWidth;
|
||||
|
||||
@@ -94,10 +94,10 @@ int shadow_capture_compare(BYTE* pData1, int nStep1, int nWidth, int nHeight, BY
|
||||
BOOL grid[1024][1024];
|
||||
|
||||
allEqual = TRUE;
|
||||
ZeroMemory(rect, sizeof(RECTANGLE_16));
|
||||
FillMemory(rows, sizeof(rows), 0xFF);
|
||||
FillMemory(cols, sizeof(cols), 0xFF);
|
||||
FillMemory(grid, sizeof(grid), 0xFF);
|
||||
ZeroMemory(rect, sizeof(RECTANGLE_16));
|
||||
|
||||
nrow = (nHeight + 15) / 16;
|
||||
ncol = (nWidth + 15) / 16;
|
||||
|
||||
@@ -56,6 +56,8 @@ void shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client)
|
||||
settings->DrawAllowColorSubsampling = TRUE;
|
||||
settings->DrawAllowDynamicColorFidelity = TRUE;
|
||||
|
||||
settings->CompressionLevel = PACKET_COMPR_TYPE_RDP6;
|
||||
|
||||
settings->RdpSecurity = TRUE;
|
||||
settings->TlsSecurity = TRUE;
|
||||
settings->NlaSecurity = FALSE;
|
||||
@@ -162,6 +164,9 @@ BOOL shadow_client_post_connect(freerdp_peer* peer)
|
||||
if (settings->ColorDepth == 24)
|
||||
settings->ColorDepth = 16; /* disable 24bpp */
|
||||
|
||||
if (settings->MultifragMaxRequestSize < 0x3F0000)
|
||||
settings->NSCodec = FALSE; /* NSCodec compressor does not support fragmentation yet */
|
||||
|
||||
WLog_ERR(TAG, "Client from %s is activated (%dx%d@%d)",
|
||||
peer->hostname, settings->DesktopWidth, settings->DesktopHeight, settings->ColorDepth);
|
||||
|
||||
@@ -266,7 +271,7 @@ BOOL shadow_client_activate(freerdp_peer* peer)
|
||||
rdpSettings* settings = peer->settings;
|
||||
rdpShadowClient* client = (rdpShadowClient*) peer->context;
|
||||
|
||||
if (strcmp(settings->ClientDir, "librdp") == 0)
|
||||
if (settings->ClientDir && (strcmp(settings->ClientDir, "librdp") == 0))
|
||||
{
|
||||
/* Hack for Mac/iOS/Android Microsoft RDP clients */
|
||||
|
||||
@@ -595,10 +600,47 @@ int shadow_client_send_bitmap_update(rdpShadowClient* client, rdpShadowSurface*
|
||||
|
||||
if (updateSizeEstimate > maxUpdateSize)
|
||||
{
|
||||
fprintf(stderr, "update size estimate larger than maximum update size\n");
|
||||
}
|
||||
UINT32 i, j;
|
||||
UINT32 updateSize;
|
||||
UINT32 newUpdateSize;
|
||||
BITMAP_DATA* fragBitmapData;
|
||||
|
||||
IFCALL(update->BitmapUpdate, context, &bitmapUpdate);
|
||||
fragBitmapData = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * k);
|
||||
bitmapUpdate.rectangles = fragBitmapData;
|
||||
|
||||
i = j = 0;
|
||||
updateSize = 1024;
|
||||
|
||||
while (i < k)
|
||||
{
|
||||
newUpdateSize = updateSize + (bitmapData[i].bitmapLength + 16);
|
||||
|
||||
if ((newUpdateSize < maxUpdateSize) && ((i + 1) < k))
|
||||
{
|
||||
CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA));
|
||||
updateSize = newUpdateSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((i + 1) >= k)
|
||||
{
|
||||
CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA));
|
||||
updateSize = newUpdateSize;
|
||||
}
|
||||
|
||||
bitmapUpdate.count = bitmapUpdate.number = j;
|
||||
IFCALL(update->BitmapUpdate, context, &bitmapUpdate);
|
||||
updateSize = 1024;
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
|
||||
free(fragBitmapData);
|
||||
}
|
||||
else
|
||||
{
|
||||
IFCALL(update->BitmapUpdate, context, &bitmapUpdate);
|
||||
}
|
||||
|
||||
free(bitmapData);
|
||||
|
||||
@@ -696,10 +738,151 @@ int shadow_client_surface_update(rdpShadowClient* client, REGION16* region)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int shadow_client_convert_alpha_pointer_data(BYTE* pixels, BOOL premultiplied,
|
||||
UINT32 width, UINT32 height, POINTER_COLOR_UPDATE* pointerColor)
|
||||
{
|
||||
UINT32 x, y;
|
||||
BYTE* pSrc8;
|
||||
BYTE* pDst8;
|
||||
int xorStep;
|
||||
int andStep;
|
||||
UINT32 andBit;
|
||||
BYTE* andBits;
|
||||
UINT32 andPixel;
|
||||
BYTE A, R, G, B;
|
||||
|
||||
xorStep = (width * 3);
|
||||
xorStep += (xorStep % 2);
|
||||
|
||||
andStep = ((width + 7) / 8);
|
||||
andStep += (andStep % 2);
|
||||
|
||||
pointerColor->lengthXorMask = height * xorStep;
|
||||
pointerColor->xorMaskData = (BYTE*) calloc(1, pointerColor->lengthXorMask);
|
||||
|
||||
if (!pointerColor->xorMaskData)
|
||||
return -1;
|
||||
|
||||
pointerColor->lengthAndMask = height * andStep;
|
||||
pointerColor->andMaskData = (BYTE*) calloc(1, pointerColor->lengthAndMask);
|
||||
|
||||
if (!pointerColor->andMaskData)
|
||||
return -1;
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
pSrc8 = &pixels[(width * 4) * (height - 1 - y)];
|
||||
pDst8 = &(pointerColor->xorMaskData[y * xorStep]);
|
||||
|
||||
andBit = 0x80;
|
||||
andBits = &(pointerColor->andMaskData[andStep * y]);
|
||||
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
B = *pSrc8++;
|
||||
G = *pSrc8++;
|
||||
R = *pSrc8++;
|
||||
A = *pSrc8++;
|
||||
|
||||
andPixel = 0;
|
||||
|
||||
if (A < 64)
|
||||
A = 0; /* pixel cannot be partially transparent */
|
||||
|
||||
if (!A)
|
||||
{
|
||||
/* transparent pixel: XOR = black, AND = 1 */
|
||||
andPixel = 1;
|
||||
B = G = R = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (premultiplied)
|
||||
{
|
||||
B = (B * 0xFF ) / A;
|
||||
G = (G * 0xFF ) / A;
|
||||
R = (R * 0xFF ) / A;
|
||||
}
|
||||
}
|
||||
|
||||
*pDst8++ = B;
|
||||
*pDst8++ = G;
|
||||
*pDst8++ = R;
|
||||
|
||||
if (andPixel) *andBits |= andBit;
|
||||
if (!(andBit >>= 1)) { andBits++; andBit = 0x80; }
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* message)
|
||||
{
|
||||
rdpContext* context = (rdpContext*) client;
|
||||
rdpUpdate* update = context->update;
|
||||
|
||||
/* FIXME: the pointer updates appear to be broken when used with bulk compression and mstsc */
|
||||
|
||||
if (message->id == SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID)
|
||||
{
|
||||
POINTER_POSITION_UPDATE pointerPosition;
|
||||
SHADOW_MSG_OUT_POINTER_POSITION_UPDATE* msg = (SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*) message->wParam;
|
||||
|
||||
pointerPosition.xPos = msg->xPos;
|
||||
pointerPosition.yPos = msg->yPos;
|
||||
|
||||
if ((msg->xPos != client->pointerX) || (msg->yPos != client->pointerY))
|
||||
{
|
||||
IFCALL(update->pointer->PointerPosition, context, &pointerPosition);
|
||||
|
||||
client->pointerX = msg->xPos;
|
||||
client->pointerY = msg->yPos;
|
||||
}
|
||||
|
||||
free(msg);
|
||||
}
|
||||
else if (message->id == SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID)
|
||||
{
|
||||
POINTER_NEW_UPDATE pointerNew;
|
||||
POINTER_COLOR_UPDATE* pointerColor;
|
||||
POINTER_CACHED_UPDATE pointerCached;
|
||||
SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* msg = (SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*) message->wParam;
|
||||
|
||||
ZeroMemory(&pointerNew, sizeof(POINTER_NEW_UPDATE));
|
||||
|
||||
pointerNew.xorBpp = 24;
|
||||
pointerColor = &(pointerNew.colorPtrAttr);
|
||||
|
||||
pointerColor->cacheIndex = 0;
|
||||
pointerColor->xPos = msg->xHot;
|
||||
pointerColor->yPos = msg->yHot;
|
||||
pointerColor->width = msg->width;
|
||||
pointerColor->height = msg->height;
|
||||
|
||||
pointerCached.cacheIndex = pointerColor->cacheIndex;
|
||||
|
||||
shadow_client_convert_alpha_pointer_data(msg->pixels, msg->premultiplied,
|
||||
msg->width, msg->height, pointerColor);
|
||||
|
||||
IFCALL(update->pointer->PointerNew, context, &pointerNew);
|
||||
IFCALL(update->pointer->PointerCached, context, &pointerCached);
|
||||
|
||||
free(pointerColor->xorMaskData);
|
||||
free(pointerColor->andMaskData);
|
||||
|
||||
free(msg->pixels);
|
||||
free(msg);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void* shadow_client_thread(rdpShadowClient* client)
|
||||
{
|
||||
DWORD status;
|
||||
DWORD nCount;
|
||||
wMessage message;
|
||||
HANDLE events[32];
|
||||
HANDLE StopEvent;
|
||||
HANDLE ClientEvent;
|
||||
@@ -712,6 +895,7 @@ void* shadow_client_thread(rdpShadowClient* client)
|
||||
rdpShadowScreen* screen;
|
||||
rdpShadowEncoder* encoder;
|
||||
rdpShadowSubsystem* subsystem;
|
||||
wMessagePipe* MsgPipe = client->subsystem->MsgPipe;
|
||||
|
||||
server = client->server;
|
||||
screen = server->screen;
|
||||
@@ -746,6 +930,7 @@ void* shadow_client_thread(rdpShadowClient* client)
|
||||
events[nCount++] = UpdateEvent;
|
||||
events[nCount++] = ClientEvent;
|
||||
events[nCount++] = ChannelEvent;
|
||||
events[nCount++] = MessageQueue_Event(MsgPipe->Out);
|
||||
|
||||
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
|
||||
|
||||
@@ -793,12 +978,23 @@ void* shadow_client_thread(rdpShadowClient* client)
|
||||
|
||||
if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
if (WTSVirtualChannelManagerCheckFileDescriptor(client->vcm) != TRUE)
|
||||
if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm))
|
||||
{
|
||||
WLog_ERR(TAG, "WTSVirtualChannelManagerCheckFileDescriptor failure");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (WaitForSingleObject(MessageQueue_Event(MsgPipe->Out), 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
if (MessageQueue_Peek(MsgPipe->Out, &message, TRUE))
|
||||
{
|
||||
if (message.id == WMQ_QUIT)
|
||||
break;
|
||||
|
||||
shadow_client_subsystem_process_message(client, &message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peer->Disconnect(peer);
|
||||
|
||||
@@ -69,6 +69,21 @@ void shadow_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
|
||||
rdpShadowClient* client = (rdpShadowClient*) input->context;
|
||||
rdpShadowSubsystem* subsystem = client->server->subsystem;
|
||||
|
||||
if (!(flags & PTR_FLAGS_WHEEL))
|
||||
{
|
||||
client->pointerX = x;
|
||||
client->pointerY = y;
|
||||
|
||||
if ((client->pointerX == subsystem->pointerX) &&
|
||||
(client->pointerY == subsystem->pointerY))
|
||||
{
|
||||
flags &= ~PTR_FLAGS_MOVE;
|
||||
|
||||
if (!(flags & (PTR_FLAGS_BUTTON1 | PTR_FLAGS_BUTTON2 | PTR_FLAGS_BUTTON3)))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!client->mayInteract)
|
||||
return;
|
||||
|
||||
@@ -83,6 +98,9 @@ void shadow_input_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x,
|
||||
rdpShadowClient* client = (rdpShadowClient*) input->context;
|
||||
rdpShadowSubsystem* subsystem = client->server->subsystem;
|
||||
|
||||
client->pointerX = x;
|
||||
client->pointerY = y;
|
||||
|
||||
if (!client->mayInteract)
|
||||
return;
|
||||
|
||||
|
||||
@@ -41,6 +41,28 @@ struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT
|
||||
};
|
||||
typedef struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT SHADOW_MSG_IN_SUPPRESS_OUTPUT;
|
||||
|
||||
#define SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID 2001
|
||||
#define SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID 2002
|
||||
|
||||
struct _SHADOW_MSG_OUT_POINTER_POSITION_UPDATE
|
||||
{
|
||||
UINT32 xPos;
|
||||
UINT32 yPos;
|
||||
};
|
||||
typedef struct _SHADOW_MSG_OUT_POINTER_POSITION_UPDATE SHADOW_MSG_OUT_POINTER_POSITION_UPDATE;
|
||||
|
||||
struct _SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE
|
||||
{
|
||||
UINT32 xHot;
|
||||
UINT32 yHot;
|
||||
UINT32 width;
|
||||
UINT32 height;
|
||||
BYTE* pixels;
|
||||
int scanline;
|
||||
BOOL premultiplied;
|
||||
};
|
||||
typedef struct _SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@@ -23,9 +23,11 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <winpr/environment.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/error.h>
|
||||
|
||||
#include <winpr/environment.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#define stricmp strcasecmp
|
||||
@@ -326,7 +328,7 @@ LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge)
|
||||
if (mergeStringLength == mergeArraySize)
|
||||
{
|
||||
mergeArraySize += 128;
|
||||
mergeStrings = (LPCSTR*) realloc(mergeStrings, mergeArraySize * sizeof(char*));
|
||||
mergeStrings = (const char**) realloc((void*) mergeStrings, mergeArraySize * sizeof(char*));
|
||||
|
||||
if (!mergeStrings)
|
||||
return NULL;
|
||||
@@ -441,7 +443,7 @@ LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge)
|
||||
|
||||
lpszEnvironmentBlock[offset] = '\0';
|
||||
|
||||
free(mergeStrings);
|
||||
free((void*) mergeStrings);
|
||||
|
||||
return lpszEnvironmentBlock;
|
||||
}
|
||||
|
||||
@@ -181,9 +181,6 @@ VOID CloseThreadpool(PTP_POOL ptpp)
|
||||
if (pCloseThreadpool)
|
||||
pCloseThreadpool(ptpp);
|
||||
#else
|
||||
int index;
|
||||
HANDLE thread;
|
||||
|
||||
SetEvent(ptpp->TerminateEvent);
|
||||
|
||||
ArrayList_Free(ptpp->Threads);
|
||||
|
||||
@@ -1382,6 +1382,8 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetStatusChange_Internal(SCARDCONTEXT hContext
|
||||
{
|
||||
int i, j;
|
||||
int* map;
|
||||
DWORD dwEventState;
|
||||
BOOL stateChanged = FALSE;
|
||||
PCSC_DWORD cMappedReaders;
|
||||
PCSC_SCARD_READERSTATE* states;
|
||||
LONG status = SCARD_S_SUCCESS;
|
||||
@@ -1469,11 +1471,7 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetStatusChange_Internal(SCARDCONTEXT hContext
|
||||
rgReaderStates[i].dwCurrentState = states[j].dwCurrentState;
|
||||
rgReaderStates[i].cbAtr = states[j].cbAtr;
|
||||
CopyMemory(&(rgReaderStates[i].rgbAtr), &(states[j].rgbAtr), PCSC_MAX_ATR_SIZE);
|
||||
/**
|
||||
* Why we should interpret and modify the results of pcsc-lite ScardGetStatusChange ?
|
||||
* Should not we just act as a pass-through between the client and the remote smartcard subsystem ?
|
||||
*/
|
||||
#if 0
|
||||
|
||||
/* pcsc-lite puts an event count in the higher bits of dwEventState */
|
||||
states[j].dwEventState &= 0xFFFF;
|
||||
dwEventState = states[j].dwEventState & ~SCARD_STATE_CHANGED;
|
||||
@@ -1497,19 +1495,14 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetStatusChange_Internal(SCARDCONTEXT hContext
|
||||
|
||||
if (rgReaderStates[i].dwCurrentState & SCARD_STATE_IGNORE)
|
||||
rgReaderStates[i].dwEventState = SCARD_STATE_IGNORE;
|
||||
#endif
|
||||
|
||||
rgReaderStates[i].dwEventState = states[j].dwEventState;
|
||||
}
|
||||
/**
|
||||
* Why we should interpret and modify the results of pcsc-lite ScardGetStatusChange ?
|
||||
* Should not we just act as a pass-through between the client and the remote smartcard subsystem ?
|
||||
*/
|
||||
#if 0
|
||||
|
||||
if ((status == SCARD_S_SUCCESS) && !stateChanged)
|
||||
status = SCARD_E_TIMEOUT;
|
||||
else if ((status == SCARD_E_TIMEOUT) && stateChanged)
|
||||
return SCARD_S_SUCCESS;
|
||||
#endif
|
||||
|
||||
free(states);
|
||||
free(map);
|
||||
|
||||
@@ -267,7 +267,7 @@ exit:
|
||||
if (thread->detached || !thread->started)
|
||||
cleanup_handle(thread);
|
||||
|
||||
pthread_exit(thread->dwExitCode);
|
||||
pthread_exit((void*) (size_t) thread->dwExitCode);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -426,12 +426,13 @@ VOID ExitThread(DWORD dwExitCode)
|
||||
{
|
||||
pthread_t tid = pthread_self();
|
||||
|
||||
if (NULL == thread_list)
|
||||
if (!thread_list)
|
||||
{
|
||||
WLog_ERR(TAG, "function called without existing thread list!");
|
||||
#if defined(WITH_DEBUG_THREADS)
|
||||
DumpThreadHandles();
|
||||
#endif
|
||||
pthread_exit(0);
|
||||
}
|
||||
else if (!ListDictionary_Contains(thread_list, &tid))
|
||||
{
|
||||
@@ -439,12 +440,15 @@ VOID ExitThread(DWORD dwExitCode)
|
||||
#if defined(WITH_DEBUG_THREADS)
|
||||
DumpThreadHandles();
|
||||
#endif
|
||||
pthread_exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
WINPR_THREAD *thread;
|
||||
WINPR_THREAD* thread;
|
||||
|
||||
ListDictionary_Lock(thread_list);
|
||||
thread = ListDictionary_GetItemValue(thread_list, &tid);
|
||||
|
||||
assert(thread);
|
||||
thread->exited = TRUE;
|
||||
thread->dwExitCode = dwExitCode;
|
||||
@@ -457,7 +461,7 @@ VOID ExitThread(DWORD dwExitCode)
|
||||
if (thread->detached || !thread->started)
|
||||
cleanup_handle(thread);
|
||||
|
||||
pthread_exit(thread->dwExitCode);
|
||||
pthread_exit((void*) (size_t) thread->dwExitCode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -689,7 +689,6 @@ BOOL WINAPI Win32_WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLAS
|
||||
VOID WINAPI Win32_WTSFreeMemory(PVOID pMemory)
|
||||
{
|
||||
LocalFree(pMemory);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WINAPI Win32_WTSFreeMemoryExW(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory, ULONG NumberOfEntries)
|
||||
|
||||
Reference in New Issue
Block a user