diff --git a/CMakeLists.txt b/CMakeLists.txt index a8cb7701be47..34efa35f8be3 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -417,9 +417,13 @@ set(FFMPEG_FEATURE_TYPE "RECOMMENDED") set(FFMPEG_FEATURE_PURPOSE "multimedia") set(FFMPEG_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback") -set(GSTREAMER_FEATURE_TYPE "RECOMMENDED") -set(GSTREAMER_FEATURE_PURPOSE "multimedia") -set(GSTREAMER_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback") +set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL") +set(GSTREAMER_0_10_FEATURE_PURPOSE "multimedia") +set(GSTREAMER_0_10_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback, gstreamer 0.10 version") + +set(GSTREAMER_1_0_FEATURE_TYPE "RECOMMENDED") +set(GSTREAMER_1_0_FEATURE_PURPOSE "multimedia") +set(GSTREAMER_1_0_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback") set(IPP_FEATURE_TYPE "OPTIONAL") set(IPP_FEATURE_PURPOSE "performance") @@ -442,14 +446,15 @@ if(WIN32) set(CUPS_FEATURE_TYPE "DISABLED") set(PCSC_FEATURE_TYPE "DISABLED") set(FFMPEG_FEATURE_TYPE "DISABLED") - set(GSTREAMER_FEATURE_TYPE "DISABLED") + set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED") + set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL") set(OPENSLES_FEATURE_TYPE "DISABLED") endif() if(APPLE) set(DIRECTFB_FEATURE_TYPE "DISABLED") set(FFMPEG_FEATURE_TYPE "OPTIONAL") - set(GSTREAMER_FEATURE_TYPE "OPTIONAL") + set(GSTREAMER_1_0_FEATURE_TYPE "OPTIONAL") set(X11_FEATURE_TYPE "OPTIONAL") if(IOS) set(X11_FEATURE_TYPE "DISABLED") @@ -457,7 +462,8 @@ if(APPLE) set(PULSE_FEATURE_TYPE "DISABLED") set(CUPS_FEATURE_TYPE "DISABLED") set(PCSC_FEATURE_TYPE "DISABLED") - set(GSTREAMER_FEATURE_TYPE "DISABLED") + set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED") + set(GSTREAMER_0_10_FEATURE_TYPE "DISABLED") endif() set(OPENSLES_FEATURE_TYPE "DISABLED") endif() @@ -470,7 +476,8 @@ if(ANDROID) set(CUPS_FEATURE_TYPE "DISABLED") set(PCSC_FEATURE_TYPE "DISABLED") set(FFMPEG_FEATURE_TYPE "DISABLED") - set(GSTREAMER_FEATURE_TYPE "DISABLED") + set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED") + set(GSTREAMER_0_10_FEATURE_TYPE "DISABLED") set(OPENSLES_FEATURE_TYPE "REQUIRED") endif() @@ -492,7 +499,9 @@ find_feature(Cups ${CUPS_FEATURE_TYPE} ${CUPS_FEATURE_PURPOSE} ${CUPS_FEATURE_DE find_feature(PCSC ${PCSC_FEATURE_TYPE} ${PCSC_FEATURE_PURPOSE} ${PCSC_FEATURE_DESCRIPTION}) find_feature(FFmpeg ${FFMPEG_FEATURE_TYPE} ${FFMPEG_FEATURE_PURPOSE} ${FFMPEG_FEATURE_DESCRIPTION}) -find_feature(Gstreamer ${GSTREAMER_FEATURE_TYPE} ${GSTREAMER_FEATURE_PURPOSE} ${GSTREAMER_FEATURE_DESCRIPTION}) + +find_feature(GStreamer_0_10 ${GSTREAMER_0_10_FEATURE_TYPE} ${GSTREAMER_0_10_FEATURE_PURPOSE} ${GSTREAMER_0_10_FEATURE_DESCRIPTION}) +find_feature(GStreamer_1_0 ${GSTREAMER_1_0_FEATURE_TYPE} ${GSTREAMER_1_0_FEATURE_PURPOSE} ${GSTREAMER_1_0_FEATURE_DESCRIPTION}) find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION}) find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRIPTION}) diff --git a/channels/drdynvc/client/dvcman.c b/channels/drdynvc/client/dvcman.c index da170160dc95..670d84ecc4a7 100644 --- a/channels/drdynvc/client/dvcman.c +++ b/channels/drdynvc/client/dvcman.c @@ -3,6 +3,8 @@ * Dynamic Virtual Channel Manager * * Copyright 2010-2011 Vic Lee + * Copyright 2014 Thincast Technologies GmbH + * Copyright 2014 Armin Novak * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +23,9 @@ #include "config.h" #endif +#include +#include + #include #include #include @@ -28,45 +33,61 @@ #include #include #include +#include #include #include "drdynvc_types.h" #include "dvcman.h" +static wListDictionary *cb_dict = NULL; +struct cb_value +{ + void *fkt; + void *context; +}; -static int dvcman_get_configuration(IWTSListener* pListener, void** ppPropertyBag) +static int dvcman_get_configuration(IWTSListener *pListener, void **ppPropertyBag) { + if (!ppPropertyBag) + { + DEBUG_WARN("ppPropertyBag=%p", ppPropertyBag); + return 0; + } + *ppPropertyBag = NULL; return 1; } -static int dvcman_create_listener(IWTSVirtualChannelManager* pChannelMgr, - const char* pszChannelName, UINT32 ulFlags, - IWTSListenerCallback* pListenerCallback, IWTSListener** ppListener) +static int dvcman_create_listener(IWTSVirtualChannelManager *pChannelMgr, + const char *pszChannelName, UINT32 ulFlags, + IWTSListenerCallback *pListenerCallback, IWTSListener **ppListener) { - DVCMAN* dvcman = (DVCMAN*) pChannelMgr; - DVCMAN_LISTENER* listener; + DVCMAN *dvcman = (DVCMAN *) pChannelMgr; + DVCMAN_LISTENER *listener; + assert(dvcman); if (dvcman->num_listeners < MAX_PLUGINS) { DEBUG_DVC("%d.%s.", dvcman->num_listeners, pszChannelName); + listener = (DVCMAN_LISTENER *) calloc(1, sizeof(DVCMAN_LISTENER)); - listener = (DVCMAN_LISTENER*) malloc(sizeof(DVCMAN_LISTENER)); - ZeroMemory(listener, sizeof(DVCMAN_LISTENER)); + if (!listener) + { + DEBUG_WARN("calloc failed %s (%d)!", strerror(errno), errno); + return 2; + } listener->iface.GetConfiguration = dvcman_get_configuration; listener->iface.pInterface = NULL; - listener->dvcman = dvcman; listener->channel_name = _strdup(pszChannelName); listener->flags = ulFlags; listener->listener_callback = pListenerCallback; if (ppListener) - *ppListener = (IWTSListener*) listener; + *ppListener = (IWTSListener *) listener; - dvcman->listeners[dvcman->num_listeners++] = (IWTSListener*) listener; - + dvcman->listeners[dvcman->num_listeners++] = (IWTSListener *) listener; return 0; } else @@ -76,11 +97,11 @@ static int dvcman_create_listener(IWTSVirtualChannelManager* pChannelMgr, } } -static int dvcman_push_event(IWTSVirtualChannelManager* pChannelMgr, wMessage* pEvent) +static int dvcman_push_event(IWTSVirtualChannelManager *pChannelMgr, wMessage *pEvent) { int status; - DVCMAN* dvcman = (DVCMAN*) pChannelMgr; - + DVCMAN *dvcman = (DVCMAN *) pChannelMgr; + assert(dvcman); status = drdynvc_push_event(dvcman->drdynvc, pEvent); if (status == 0) @@ -95,9 +116,11 @@ static int dvcman_push_event(IWTSVirtualChannelManager* pChannelMgr, wMessage* p return status; } -static int dvcman_register_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* name, IWTSPlugin* pPlugin) +static int dvcman_register_plugin(IDRDYNVC_ENTRY_POINTS *pEntryPoints, const char *name, IWTSPlugin *pPlugin) { - DVCMAN* dvcman = ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->dvcman; + DVCMAN *dvcman = ((DVCMAN_ENTRY_POINTS *) pEntryPoints)->dvcman; + assert(pEntryPoints); + assert(dvcman); if (dvcman->num_plugins < MAX_PLUGINS) { @@ -113,15 +136,17 @@ static int dvcman_register_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const cha } } -IWTSPlugin* dvcman_get_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* name) +IWTSPlugin *dvcman_get_plugin(IDRDYNVC_ENTRY_POINTS *pEntryPoints, const char *name) { int i; - DVCMAN* dvcman = ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->dvcman; + DVCMAN *dvcman = ((DVCMAN_ENTRY_POINTS *) pEntryPoints)->dvcman; + assert(pEntryPoints); + assert(dvcman); for (i = 0; i < dvcman->num_plugins; i++) { if (dvcman->plugin_names[i] == name || - strcmp(dvcman->plugin_names[i], name) == 0) + strcmp(dvcman->plugin_names[i], name) == 0) { return dvcman->plugins[i]; } @@ -130,27 +155,28 @@ IWTSPlugin* dvcman_get_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* n return NULL; } -ADDIN_ARGV* dvcman_get_plugin_data(IDRDYNVC_ENTRY_POINTS* pEntryPoints) +ADDIN_ARGV *dvcman_get_plugin_data(IDRDYNVC_ENTRY_POINTS *pEntryPoints) { - return ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->args; + assert(pEntryPoints); + return ((DVCMAN_ENTRY_POINTS *) pEntryPoints)->args; } -UINT32 dvcman_get_channel_id(IWTSVirtualChannel * channel) +UINT32 dvcman_get_channel_id(IWTSVirtualChannel *channel) { - return ((DVCMAN_CHANNEL*) channel)->channel_id; + assert(channel); + return ((DVCMAN_CHANNEL *) channel)->channel_id; } -IWTSVirtualChannel* dvcman_find_channel_by_id(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId) +IWTSVirtualChannel *dvcman_find_channel_by_id(IWTSVirtualChannelManager *pChannelMgr, UINT32 ChannelId) { int index; BOOL found = FALSE; - DVCMAN_CHANNEL* channel; - DVCMAN* dvcman = (DVCMAN*) pChannelMgr; - + DVCMAN_CHANNEL *channel; + DVCMAN *dvcman = (DVCMAN *) pChannelMgr; + assert(dvcman); ArrayList_Lock(dvcman->channels); - index = 0; - channel = (DVCMAN_CHANNEL*) ArrayList_GetItem(dvcman->channels, index++); + channel = (DVCMAN_CHANNEL *) ArrayList_GetItem(dvcman->channels, index++); while (channel) { @@ -160,25 +186,26 @@ IWTSVirtualChannel* dvcman_find_channel_by_id(IWTSVirtualChannelManager* pChanne break; } - channel = (DVCMAN_CHANNEL*) ArrayList_GetItem(dvcman->channels, index++); + channel = (DVCMAN_CHANNEL *) ArrayList_GetItem(dvcman->channels, index++); } ArrayList_Unlock(dvcman->channels); - - return (found) ? ((IWTSVirtualChannel*) channel) : NULL; + return (found) ? ((IWTSVirtualChannel *) channel) : NULL; } -void* dvcman_get_channel_interface_by_name(IWTSVirtualChannelManager* pChannelMgr, const char* ChannelName) +void *dvcman_get_channel_interface_by_name(IWTSVirtualChannelManager *pChannelMgr, const char *ChannelName) { int i; BOOL found = FALSE; - void* pInterface = NULL; - DVCMAN_LISTENER* listener; - DVCMAN* dvcman = (DVCMAN*) pChannelMgr; + void *pInterface = NULL; + DVCMAN_LISTENER *listener; + DVCMAN *dvcman = (DVCMAN *) pChannelMgr; + assert(dvcman); for (i = 0; i < dvcman->num_listeners; i++) { - listener = (DVCMAN_LISTENER*) dvcman->listeners[i]; + listener = (DVCMAN_LISTENER *) dvcman->listeners[i]; + assert(listener); if (strcmp(listener->channel_name, ChannelName) == 0) { @@ -191,12 +218,16 @@ void* dvcman_get_channel_interface_by_name(IWTSVirtualChannelManager* pChannelMg return (found) ? pInterface : NULL; } -IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin) +IWTSVirtualChannelManager *dvcman_new(drdynvcPlugin *plugin) { - DVCMAN* dvcman; + DVCMAN *dvcman; + dvcman = (DVCMAN *) calloc(1,sizeof(DVCMAN)); - dvcman = (DVCMAN*) malloc(sizeof(DVCMAN)); - ZeroMemory(dvcman, sizeof(DVCMAN)); + if (!dvcman) + { + DEBUG_WARN("calloc failed %s (%d)!", strerror(errno), errno); + return NULL; + } dvcman->iface.CreateListener = dvcman_create_listener; dvcman->iface.PushEvent = dvcman_push_event; @@ -204,68 +235,68 @@ IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin) dvcman->iface.GetChannelId = dvcman_get_channel_id; dvcman->drdynvc = plugin; dvcman->channels = ArrayList_New(TRUE); - - return (IWTSVirtualChannelManager*) dvcman; + return (IWTSVirtualChannelManager *) dvcman; } -int dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args) +int dvcman_load_addin(IWTSVirtualChannelManager *pChannelMgr, ADDIN_ARGV *args) { DVCMAN_ENTRY_POINTS entryPoints; PDVC_PLUGIN_ENTRY pDVCPluginEntry = NULL; - + assert(args); fprintf(stderr, "Loading Dynamic Virtual Channel %s\n", args->argv[0]); - pDVCPluginEntry = (PDVC_PLUGIN_ENTRY) freerdp_load_channel_addin_entry(args->argv[0], - NULL, NULL, FREERDP_ADDIN_CHANNEL_DYNAMIC); + NULL, NULL, FREERDP_ADDIN_CHANNEL_DYNAMIC); if (pDVCPluginEntry) { entryPoints.iface.RegisterPlugin = dvcman_register_plugin; entryPoints.iface.GetPlugin = dvcman_get_plugin; entryPoints.iface.GetPluginData = dvcman_get_plugin_data; - entryPoints.dvcman = (DVCMAN*) pChannelMgr; + entryPoints.dvcman = (DVCMAN *) pChannelMgr; entryPoints.args = args; - - pDVCPluginEntry((IDRDYNVC_ENTRY_POINTS*) &entryPoints); + pDVCPluginEntry((IDRDYNVC_ENTRY_POINTS *) &entryPoints); } return 0; } -static void dvcman_channel_free(DVCMAN_CHANNEL* channel) +static void dvcman_channel_free(DVCMAN_CHANNEL *channel) { + assert(channel); + if (channel->channel_callback) channel->channel_callback->OnClose(channel->channel_callback); + if (channel->channel_name) + free(channel->channel_name); + free(channel); } -void dvcman_free(IWTSVirtualChannelManager* pChannelMgr) +void dvcman_free(IWTSVirtualChannelManager *pChannelMgr) { int i; int count; - IWTSPlugin* pPlugin; - DVCMAN_LISTENER* listener; - DVCMAN_CHANNEL* channel; - DVCMAN* dvcman = (DVCMAN*) pChannelMgr; - + IWTSPlugin *pPlugin; + DVCMAN_LISTENER *listener; + DVCMAN_CHANNEL *channel; + DVCMAN *dvcman = (DVCMAN *) pChannelMgr; + assert(dvcman); ArrayList_Lock(dvcman->channels); - count = ArrayList_Count(dvcman->channels); for (i = 0; i < count; i++) { - channel = (DVCMAN_CHANNEL*) ArrayList_GetItem(dvcman->channels, i); + channel = (DVCMAN_CHANNEL *) ArrayList_GetItem(dvcman->channels, i); dvcman_channel_free(channel); } ArrayList_Unlock(dvcman->channels); - ArrayList_Free(dvcman->channels); for (i = 0; i < dvcman->num_listeners; i++) { - listener = (DVCMAN_LISTENER*) dvcman->listeners[i]; + listener = (DVCMAN_LISTENER *) dvcman->listeners[i]; free(listener->channel_name); free(listener); } @@ -281,11 +312,12 @@ void dvcman_free(IWTSVirtualChannelManager* pChannelMgr) free(dvcman); } -int dvcman_init(IWTSVirtualChannelManager* pChannelMgr) +int dvcman_init(IWTSVirtualChannelManager *pChannelMgr) { int i; - IWTSPlugin* pPlugin; - DVCMAN* dvcman = (DVCMAN*) pChannelMgr; + IWTSPlugin *pPlugin; + DVCMAN *dvcman = (DVCMAN *) pChannelMgr; + assert(dvcman); for (i = 0; i < dvcman->num_plugins; i++) { @@ -298,83 +330,83 @@ int dvcman_init(IWTSVirtualChannelManager* pChannelMgr) return 0; } -static int dvcman_write_channel(IWTSVirtualChannel* pChannel, UINT32 cbSize, BYTE* pBuffer, void* pReserved) +static int dvcman_write_channel(IWTSVirtualChannel *pChannel, UINT32 cbSize, BYTE *pBuffer, void *pReserved) { int status; - DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*) pChannel; - + DVCMAN_CHANNEL *channel = (DVCMAN_CHANNEL *) pChannel; + assert(channel); WaitForSingleObject(channel->dvc_chan_mutex, INFINITE); status = drdynvc_write_data(channel->dvcman->drdynvc, channel->channel_id, pBuffer, cbSize); ReleaseMutex(channel->dvc_chan_mutex); - return status; } -static int dvcman_close_channel_iface(IWTSVirtualChannel* pChannel) +static int dvcman_close_channel_iface(IWTSVirtualChannel *pChannel) { - DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*) pChannel; - DVCMAN* dvcman = channel->dvcman; - + DVCMAN_CHANNEL *channel = (DVCMAN_CHANNEL *) pChannel; + DVCMAN *dvcman = channel->dvcman; + assert(channel); + assert(dvcman); DEBUG_DVC("id=%d", channel->channel_id); - ArrayList_Remove(dvcman->channels, channel); - dvcman_channel_free(channel); - return 1; } -int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, const char* ChannelName) +int dvcman_create_channel(IWTSVirtualChannelManager *pChannelMgr, UINT32 ChannelId, const char *ChannelName) { int i; int bAccept; - DVCMAN_LISTENER* listener; - DVCMAN_CHANNEL* channel; - DrdynvcClientContext* context; - IWTSVirtualChannelCallback* pCallback; - DVCMAN* dvcman = (DVCMAN*) pChannelMgr; + DVCMAN_LISTENER *listener; + DVCMAN_CHANNEL *channel; + DrdynvcClientContext *context; + IWTSVirtualChannelCallback *pCallback; + DVCMAN *dvcman = (DVCMAN *) pChannelMgr; + channel = (DVCMAN_CHANNEL *) calloc(1, sizeof(DVCMAN_CHANNEL)); - channel = (DVCMAN_CHANNEL*) malloc(sizeof(DVCMAN_CHANNEL)); - ZeroMemory(channel, sizeof(DVCMAN_CHANNEL)); + if (!channel) + { + DEBUG_WARN("calloc failed %s (%d)!", strerror(errno), errno); + return -1; + } + ZeroMemory(channel, sizeof(DVCMAN_CHANNEL)); channel->dvcman = dvcman; channel->channel_id = ChannelId; channel->channel_name = _strdup(ChannelName); for (i = 0; i < dvcman->num_listeners; i++) { - listener = (DVCMAN_LISTENER*) dvcman->listeners[i]; + listener = (DVCMAN_LISTENER *) dvcman->listeners[i]; + assert(listener); if (strcmp(listener->channel_name, ChannelName) == 0) { channel->iface.Write = dvcman_write_channel; channel->iface.Close = dvcman_close_channel_iface; channel->dvc_chan_mutex = CreateMutex(NULL, FALSE, NULL); - bAccept = 1; pCallback = NULL; + assert(listener->listener_callback); + assert(listener->listener_callback->OnNewChannelConnection); if (listener->listener_callback->OnNewChannelConnection(listener->listener_callback, - (IWTSVirtualChannel*) channel, NULL, &bAccept, &pCallback) == 0 && bAccept == 1) + (IWTSVirtualChannel *) channel, NULL, &bAccept, &pCallback) == 0 && bAccept == 1) { DEBUG_DVC("listener %s created new channel %d", - listener->channel_name, channel->channel_id); - + listener->channel_name, channel->channel_id); channel->status = 0; channel->channel_callback = pCallback; channel->pInterface = listener->iface.pInterface; - + assert(dvcman->drdynvc); ArrayList_Add(dvcman->channels, channel); - context = dvcman->drdynvc->context; IFCALL(context->OnChannelConnected, context, ChannelName, listener->iface.pInterface); - return 0; } else { DEBUG_WARN("channel rejected by plugin"); - free(channel); return 1; } @@ -385,14 +417,14 @@ int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 Channel return 1; } -int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId) +int dvcman_close_channel(IWTSVirtualChannelManager *pChannelMgr, UINT32 ChannelId) { - DVCMAN_CHANNEL* channel; - IWTSVirtualChannel* ichannel; - DrdynvcClientContext* context; - DVCMAN* dvcman = (DVCMAN*) pChannelMgr; - - channel = (DVCMAN_CHANNEL*) dvcman_find_channel_by_id(pChannelMgr, ChannelId); + DVCMAN_CHANNEL *channel; + IWTSVirtualChannel *ichannel; + DrdynvcClientContext *context; + DVCMAN *dvcman = (DVCMAN *) pChannelMgr; + assert(dvcman); + channel = (DVCMAN_CHANNEL *) dvcman_find_channel_by_id(pChannelMgr, ChannelId); if (!channel) { @@ -408,25 +440,21 @@ int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelI if (channel->status == 0) { + assert(dvcman->drdynvc); context = dvcman->drdynvc->context; - IFCALL(context->OnChannelDisconnected, context, channel->channel_name, channel->pInterface); - - free(channel->channel_name); - DEBUG_DVC("dvcman_close_channel: channel %d closed", ChannelId); - ichannel = (IWTSVirtualChannel*) channel; + ichannel = (IWTSVirtualChannel *) channel; ichannel->Close(ichannel); } return 0; } -int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, UINT32 length) +int dvcman_receive_channel_data_first(IWTSVirtualChannelManager *pChannelMgr, UINT32 ChannelId, UINT32 length) { - DVCMAN_CHANNEL* channel; - - channel = (DVCMAN_CHANNEL*) dvcman_find_channel_by_id(pChannelMgr, ChannelId); + DVCMAN_CHANNEL *channel; + channel = (DVCMAN_CHANNEL *) dvcman_find_channel_by_id(pChannelMgr, ChannelId); if (!channel) { @@ -438,16 +466,14 @@ int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, UI Stream_Free(channel->dvc_data, TRUE); channel->dvc_data = Stream_New(NULL, length); - return 0; } -int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, BYTE* data, UINT32 data_size) +int dvcman_receive_channel_data(IWTSVirtualChannelManager *pChannelMgr, UINT32 ChannelId, BYTE *data, UINT32 data_size) { int error = 0; - DVCMAN_CHANNEL* channel; - - channel = (DVCMAN_CHANNEL*) dvcman_find_channel_by_id(pChannelMgr, ChannelId); + DVCMAN_CHANNEL *channel; + channel = (DVCMAN_CHANNEL *) dvcman_find_channel_by_id(pChannelMgr, ChannelId); if (!channel) { @@ -471,15 +497,122 @@ int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 C if (((size_t) Stream_GetPosition(channel->dvc_data)) >= Stream_Capacity(channel->dvc_data)) { error = channel->channel_callback->OnDataReceived(channel->channel_callback, - Stream_Capacity(channel->dvc_data), Stream_Buffer(channel->dvc_data)); + Stream_Capacity(channel->dvc_data), Stream_Buffer(channel->dvc_data)); Stream_Free(channel->dvc_data, TRUE); channel->dvc_data = NULL; } } else { + assert(channel->channel_callback); + assert(channel->channel_callback->OnDataReceived); error = channel->channel_callback->OnDataReceived(channel->channel_callback, data_size, data); } return error; } + +static void dump_callbacks(void) +{ + wListDictionaryItem *cur; + DEBUG_DVC("Dumping all currently registered callbacks"); + + if (!cb_dict) + { + DEBUG_DVC("cb_dict=NULL"); + return; + } + + cur = cb_dict->head; + + while (cur) + { + DEBUG_DVC("cb_dict %s:%p", cur->key, cur->value); + cur = cur->next; + } +} + +void *get_callback_by_name(const char *name, void **context) +{ + struct cb_value *rc; + + if (!cb_dict) + { + DEBUG_WARN("'%s' not found, function list does not exist.", + name); + return NULL; + } + + if (!ListDictionary_Contains(cb_dict, (void *)name)) + { + DEBUG_WARN("'%s' not found", name); + return NULL; + } + + rc = ListDictionary_GetItemValue(cb_dict, (void *)name); + DEBUG_DVC("'%s'=%p found", name, rc); + + if (context) + *context = rc->context; + + return rc->fkt; +} + +static BOOL callback_key_cmp(void *a, void *b) +{ + return strcmp(a, b) ? FALSE : TRUE; +} + +void add_callback_by_name(const char *name, void *fkt, void *context) +{ + struct cb_value *value = calloc(1, sizeof(struct cb_value)); + + if (!value) + { + DEBUG_WARN("calloc failed %s (%d)!", strerror(errno), errno); + assert(FALSE); + return; + } + + if (!cb_dict) + { + DEBUG_DVC("Function list is empty, allocating new."); + cb_dict = ListDictionary_New(TRUE); + ListDictionary_KeyObject(cb_dict)->fnObjectEquals = callback_key_cmp; + } + + value->fkt = fkt; + value->context = context; + DEBUG_DVC("Adding '%s'=%p to function list.", name, fkt); + ListDictionary_Add(cb_dict, (void *)name, value); + dump_callbacks(); +} + +void remove_callback_by_name(const char *name, void *context) +{ + if (!cb_dict) + { + DEBUG_WARN("trying to remove '%s', but function list does not exist.", + name); + return; + } + + if (!ListDictionary_Contains(cb_dict, (void *)name)) + { + DEBUG_WARN("trying to remove '%s', which is not in function list.", + name); + return; + } + + DEBUG_DVC("Removing '%s' from function list.", name); + ListDictionary_Remove(cb_dict, (void *)name); + + if (ListDictionary_Count(cb_dict) < 1) + { + DEBUG_DVC("Function list is empty, freeing resources."); + ListDictionary_Free(cb_dict); + cb_dict = NULL; + } + + dump_callbacks(); +} diff --git a/channels/tsmf/client/CMakeLists.txt b/channels/tsmf/client/CMakeLists.txt index 18f463d4f2f9..a92ceda1d71e 100644 --- a/channels/tsmf/client/CMakeLists.txt +++ b/channels/tsmf/client/CMakeLists.txt @@ -55,7 +55,7 @@ if(WITH_FFMPEG) add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "ffmpeg" "decoder") endif() -if(WITH_GSTREAMER) +if(WITH_GSTREAMER_0_10 OR WITH_GSTREAMER_1_0) set(XRANDR_FEATURE_TYPE "REQUIRED") set(XRANDR_FEATURE_PURPOSE "X11 randr") set(XRANDR_FEATURE_DESCRIPTION "X11 randr extension") diff --git a/channels/tsmf/client/alsa/tsmf_alsa.c b/channels/tsmf/client/alsa/tsmf_alsa.c index a6b67d71a232..d442dca8c574 100644 --- a/channels/tsmf/client/alsa/tsmf_alsa.c +++ b/channels/tsmf/client/alsa/tsmf_alsa.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -41,225 +40,194 @@ typedef struct _TSMFALSAAudioDevice ITSMFAudioDevice iface; char device[32]; - snd_pcm_t* out_handle; + snd_pcm_t *out_handle; UINT32 source_rate; UINT32 actual_rate; UINT32 source_channels; UINT32 actual_channels; UINT32 bytes_per_sample; - FREERDP_DSP_CONTEXT* dsp_context; + FREERDP_DSP_CONTEXT *dsp_context; } TSMFAlsaAudioDevice; -static BOOL tsmf_alsa_open_device(TSMFAlsaAudioDevice* alsa) +static BOOL tsmf_alsa_open_device(TSMFAlsaAudioDevice *alsa) { int error; - error = snd_pcm_open(&alsa->out_handle, alsa->device, SND_PCM_STREAM_PLAYBACK, 0); - - if (error < 0) + if(error < 0) { DEBUG_WARN("failed to open device %s", alsa->device); return FALSE; } - - DEBUG_DVC("open device %s", alsa->device); + DEBUG_TSMF("open device %s", alsa->device); return TRUE; } -static BOOL tsmf_alsa_open(ITSMFAudioDevice* audio, const char* device) +static BOOL tsmf_alsa_open(ITSMFAudioDevice *audio, const char *device) { - TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; - - if (!device) + TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio; + if(!device) { - if (!alsa->device[0]) + if(!alsa->device[0]) strncpy(alsa->device, "default", sizeof(alsa->device)); } else { strncpy(alsa->device, device, sizeof(alsa->device)); } - return tsmf_alsa_open_device(alsa); } -static BOOL tsmf_alsa_set_format(ITSMFAudioDevice* audio, - UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample) +static BOOL tsmf_alsa_set_format(ITSMFAudioDevice *audio, + UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample) { int error; snd_pcm_uframes_t frames; - snd_pcm_hw_params_t* hw_params; - snd_pcm_sw_params_t* sw_params; - TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; - - if (!alsa->out_handle) + snd_pcm_hw_params_t *hw_params; + snd_pcm_sw_params_t *sw_params; + TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio; + if(!alsa->out_handle) return FALSE; - snd_pcm_drop(alsa->out_handle); - alsa->actual_rate = alsa->source_rate = sample_rate; alsa->actual_channels = alsa->source_channels = channels; alsa->bytes_per_sample = bits_per_sample / 8; - error = snd_pcm_hw_params_malloc(&hw_params); - - if (error < 0) + if(error < 0) { DEBUG_WARN("snd_pcm_hw_params_malloc failed"); return FALSE; } - snd_pcm_hw_params_any(alsa->out_handle, hw_params); snd_pcm_hw_params_set_access(alsa->out_handle, hw_params, - SND_PCM_ACCESS_RW_INTERLEAVED); + SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(alsa->out_handle, hw_params, - SND_PCM_FORMAT_S16_LE); + SND_PCM_FORMAT_S16_LE); snd_pcm_hw_params_set_rate_near(alsa->out_handle, hw_params, - &alsa->actual_rate, NULL); + &alsa->actual_rate, NULL); snd_pcm_hw_params_set_channels_near(alsa->out_handle, hw_params, - &alsa->actual_channels); + &alsa->actual_channels); frames = sample_rate; snd_pcm_hw_params_set_buffer_size_near(alsa->out_handle, hw_params, - &frames); + &frames); snd_pcm_hw_params(alsa->out_handle, hw_params); snd_pcm_hw_params_free(hw_params); - error = snd_pcm_sw_params_malloc(&sw_params); - - if (error < 0) + if(error < 0) { DEBUG_WARN("snd_pcm_sw_params_malloc"); return FALSE; } - snd_pcm_sw_params_current(alsa->out_handle, sw_params); snd_pcm_sw_params_set_start_threshold(alsa->out_handle, sw_params, - frames / 2); + frames / 2); snd_pcm_sw_params(alsa->out_handle, sw_params); snd_pcm_sw_params_free(sw_params); - snd_pcm_prepare(alsa->out_handle); - - DEBUG_DVC("sample_rate %d channels %d bits_per_sample %d", - sample_rate, channels, bits_per_sample); - DEBUG_DVC("hardware buffer %d frames", (int)frames); - - if ((alsa->actual_rate != alsa->source_rate) || - (alsa->actual_channels != alsa->source_channels)) + DEBUG_TSMF("sample_rate %d channels %d bits_per_sample %d", + sample_rate, channels, bits_per_sample); + DEBUG_TSMF("hardware buffer %d frames", (int)frames); + if((alsa->actual_rate != alsa->source_rate) || + (alsa->actual_channels != alsa->source_channels)) { - DEBUG_DVC("actual rate %d / channel %d is different " - "from source rate %d / channel %d, resampling required.", - alsa->actual_rate, alsa->actual_channels, - alsa->source_rate, alsa->source_channels); + DEBUG_TSMF("actual rate %d / channel %d is different " + "from source rate %d / channel %d, resampling required.", + alsa->actual_rate, alsa->actual_channels, + alsa->source_rate, alsa->source_channels); } - return TRUE; } -static BOOL tsmf_alsa_play(ITSMFAudioDevice* audio, BYTE* data, UINT32 data_size) +static BOOL tsmf_alsa_play(ITSMFAudioDevice *audio, BYTE *data, UINT32 data_size) { int len; int error; int frames; - BYTE* end; - BYTE* src; - BYTE* pindex; + BYTE *end; + BYTE *src; + BYTE *pindex; int rbytes_per_frame; int sbytes_per_frame; - TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; - - DEBUG_DVC("data_size %d", data_size); - - if (alsa->out_handle) + TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio; + DEBUG_TSMF("data_size %d", data_size); + if(alsa->out_handle) { sbytes_per_frame = alsa->source_channels * alsa->bytes_per_sample; rbytes_per_frame = alsa->actual_channels * alsa->bytes_per_sample; - - if ((alsa->source_rate == alsa->actual_rate) && - (alsa->source_channels == alsa->actual_channels)) + if((alsa->source_rate == alsa->actual_rate) && + (alsa->source_channels == alsa->actual_channels)) { src = data; } else { alsa->dsp_context->resample(alsa->dsp_context, data, alsa->bytes_per_sample, - alsa->source_channels, alsa->source_rate, data_size / sbytes_per_frame, - alsa->actual_channels, alsa->actual_rate); + alsa->source_channels, alsa->source_rate, data_size / sbytes_per_frame, + alsa->actual_channels, alsa->actual_rate); frames = alsa->dsp_context->resampled_frames; - DEBUG_DVC("resampled %d frames at %d to %d frames at %d", - data_size / sbytes_per_frame, alsa->source_rate, frames, alsa->actual_rate); + DEBUG_TSMF("resampled %d frames at %d to %d frames at %d", + data_size / sbytes_per_frame, alsa->source_rate, frames, alsa->actual_rate); data_size = frames * rbytes_per_frame; src = alsa->dsp_context->resampled_buffer; } - pindex = src; end = pindex + data_size; - while (pindex < end) + while(pindex < end) { len = end - pindex; frames = len / rbytes_per_frame; error = snd_pcm_writei(alsa->out_handle, pindex, frames); - - if (error == -EPIPE) + if(error == -EPIPE) { snd_pcm_recover(alsa->out_handle, error, 0); error = 0; } - else if (error < 0) - { - DEBUG_DVC("error len %d", error); - snd_pcm_close(alsa->out_handle); - alsa->out_handle = 0; - tsmf_alsa_open_device(alsa); - break; - } - - DEBUG_DVC("%d frames played.", error); - - if (error == 0) + else + if(error < 0) + { + DEBUG_TSMF("error len %d", error); + snd_pcm_close(alsa->out_handle); + alsa->out_handle = 0; + tsmf_alsa_open_device(alsa); + break; + } + DEBUG_TSMF("%d frames played.", error); + if(error == 0) break; - pindex += error * rbytes_per_frame; } } free(data); - return TRUE; } -static UINT64 tsmf_alsa_get_latency(ITSMFAudioDevice* audio) +static UINT64 tsmf_alsa_get_latency(ITSMFAudioDevice *audio) { UINT64 latency = 0; snd_pcm_sframes_t frames = 0; - TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; - - if (alsa->out_handle && alsa->actual_rate > 0 && - snd_pcm_delay(alsa->out_handle, &frames) == 0 && - frames > 0) + TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio; + if(alsa->out_handle && alsa->actual_rate > 0 && + snd_pcm_delay(alsa->out_handle, &frames) == 0 && + frames > 0) { latency = ((UINT64)frames) * 10000000LL / (UINT64) alsa->actual_rate; } - return latency; } -static void tsmf_alsa_flush(ITSMFAudioDevice* audio) +static void tsmf_alsa_flush(ITSMFAudioDevice *audio) { } -static void tsmf_alsa_free(ITSMFAudioDevice* audio) +static void tsmf_alsa_free(ITSMFAudioDevice *audio) { - TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; - - DEBUG_DVC(""); - - if (alsa->out_handle) + TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio; + DEBUG_TSMF(""); + if(alsa->out_handle) { snd_pcm_drain(alsa->out_handle); snd_pcm_close(alsa->out_handle); } - freerdp_dsp_context_free(alsa->dsp_context); free(alsa); } @@ -268,21 +236,17 @@ static void tsmf_alsa_free(ITSMFAudioDevice* audio) #define freerdp_tsmf_client_audio_subsystem_entry alsa_freerdp_tsmf_client_audio_subsystem_entry #endif -ITSMFAudioDevice* freerdp_tsmf_client_audio_subsystem_entry(void) +ITSMFAudioDevice *freerdp_tsmf_client_audio_subsystem_entry(void) { - TSMFAlsaAudioDevice* alsa; - - alsa = (TSMFAlsaAudioDevice*) malloc(sizeof(TSMFAlsaAudioDevice)); + TSMFAlsaAudioDevice *alsa; + alsa = (TSMFAlsaAudioDevice *) malloc(sizeof(TSMFAlsaAudioDevice)); ZeroMemory(alsa, sizeof(TSMFAlsaAudioDevice)); - alsa->iface.Open = tsmf_alsa_open; alsa->iface.SetFormat = tsmf_alsa_set_format; alsa->iface.Play = tsmf_alsa_play; alsa->iface.GetLatency = tsmf_alsa_get_latency; alsa->iface.Flush = tsmf_alsa_flush; alsa->iface.Free = tsmf_alsa_free; - alsa->dsp_context = freerdp_dsp_context_new(); - - return (ITSMFAudioDevice*) alsa; + return (ITSMFAudioDevice *) alsa; } diff --git a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c index 09b4f685c559..e2c9da2c59b6 100644 --- a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c +++ b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c @@ -32,8 +32,6 @@ #include -#include - #include "tsmf_constants.h" #include "tsmf_decoder.h" @@ -59,55 +57,47 @@ typedef struct _TSMFFFmpegDecoder #else enum AVCodecID codec_id; #endif - AVCodecContext* codec_context; - AVCodec* codec; - AVFrame* frame; + AVCodecContext *codec_context; + AVCodec *codec; + AVFrame *frame; int prepared; - BYTE* decoded_data; + BYTE *decoded_data; UINT32 decoded_size; 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) { DEBUG_WARN("avcodec_alloc_context failed."); return FALSE; } - 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; mdecoder->codec_context->time_base.den = media_type->SamplesPerSecond.Numerator; mdecoder->codec_context->time_base.num = media_type->SamplesPerSecond.Denominator; - mdecoder->frame = avcodec_alloc_frame(); - 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; mdecoder->codec_context->block_align = media_type->BlockAlign; - #if LIBAVCODEC_VERSION_MAJOR < 55 #ifdef AV_CPU_FLAG_SSE2 mdecoder->codec_context->dsp_mask = AV_CPU_FLAG_SSE2 | AV_CPU_FLAG_MMX2; @@ -125,43 +115,38 @@ static BOOL tsmf_ffmpeg_init_audio_stream(ITSMFDecoder* decoder, const TS_AM_MED av_set_cpu_flags_mask(FF_MM_SSE2 | FF_MM_MMX2); #endif #endif /* LIBAVCODEC_VERSION_MAJOR < 55 */ - 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; + BYTE *p; UINT32 size; - const BYTE* s; - TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; - + const BYTE *s; + TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder; mdecoder->codec = avcodec_find_decoder(mdecoder->codec_id); - - if (!mdecoder->codec) + if(!mdecoder->codec) { DEBUG_WARN("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 (!tsmf_ffmpeg_init_audio_stream(decoder, media_type)) - return FALSE; - } - - if (media_type->ExtraData) + else + if(mdecoder->media_type == AVMEDIA_TYPE_AUDIO) + { + if(!tsmf_ffmpeg_init_audio_stream(decoder, media_type)) + return FALSE; + } + if(media_type->ExtraData) { - if (media_type->SubType == TSMF_SUB_TYPE_AVC1 && - media_type->FormatType == TSMF_FORMAT_TYPE_MPEG2VIDEOINFO) + 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. See http://haali.su/mkv/codecs.pdf */ @@ -194,33 +179,27 @@ 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) { DEBUG_WARN("avcodec_open2 failed."); return FALSE; } - mdecoder->prepared = 1; - 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; - - switch (media_type->MajorType) + TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder; + switch(media_type->MajorType) { case TSMF_MAJOR_TYPE_VIDEO: mdecoder->media_type = AVMEDIA_TYPE_VIDEO; @@ -231,7 +210,7 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* medi default: return FALSE; } - switch (media_type->SubType) + switch(media_type->SubType) { case TSMF_SUB_TYPE_WVC1: mdecoder->codec_id = CODEC_ID_VC1; @@ -259,7 +238,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; @@ -275,118 +254,108 @@ 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; + AVFrame *frame; BOOL ret = TRUE; - #if LIBAVCODEC_VERSION_MAJOR < 52 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR <= 20) len = avcodec_decode_video(mdecoder->codec_context, mdecoder->frame, &decoded, data, data_size); #else { AVPacket pkt; av_init_packet(&pkt); - pkt.data = (BYTE*) data; + 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) { DEBUG_WARN("data_size %d, avcodec_decode_video failed (%d)", data_size, len); ret = FALSE; } - else if (!decoded) - { - DEBUG_WARN("data_size %d, no frame is decoded.", data_size); - ret = FALSE; - } else - { - DEBUG_DVC("linesize[0] %d linesize[1] %d linesize[2] %d linesize[3] %d " - "pix_fmt %d width %d height %d", - mdecoder->frame->linesize[0], mdecoder->frame->linesize[1], - mdecoder->frame->linesize[2], mdecoder->frame->linesize[3], - mdecoder->codec_context->pix_fmt, - mdecoder->codec_context->width, mdecoder->codec_context->height); - - mdecoder->decoded_size = avpicture_get_size(mdecoder->codec_context->pix_fmt, - mdecoder->codec_context->width, mdecoder->codec_context->height); - mdecoder->decoded_data = malloc(mdecoder->decoded_size); - ZeroMemory(mdecoder->decoded_data, mdecoder->decoded_size); - frame = avcodec_alloc_frame(); - avpicture_fill((AVPicture*) frame, mdecoder->decoded_data, - mdecoder->codec_context->pix_fmt, - mdecoder->codec_context->width, mdecoder->codec_context->height); - - av_picture_copy((AVPicture*) frame, (AVPicture*) mdecoder->frame, - mdecoder->codec_context->pix_fmt, - mdecoder->codec_context->width, mdecoder->codec_context->height); - - av_free(frame); - } - + if(!decoded) + { + DEBUG_WARN("data_size %d, no frame is decoded.", data_size); + ret = FALSE; + } + else + { + DEBUG_TSMF("linesize[0] %d linesize[1] %d linesize[2] %d linesize[3] %d " + "pix_fmt %d width %d height %d", + mdecoder->frame->linesize[0], mdecoder->frame->linesize[1], + mdecoder->frame->linesize[2], mdecoder->frame->linesize[3], + mdecoder->codec_context->pix_fmt, + mdecoder->codec_context->width, mdecoder->codec_context->height); + mdecoder->decoded_size = avpicture_get_size(mdecoder->codec_context->pix_fmt, + mdecoder->codec_context->width, mdecoder->codec_context->height); + mdecoder->decoded_data = malloc(mdecoder->decoded_size); + ZeroMemory(mdecoder->decoded_data, mdecoder->decoded_size); + frame = avcodec_alloc_frame(); + avpicture_fill((AVPicture *) frame, mdecoder->decoded_data, + mdecoder->codec_context->pix_fmt, + mdecoder->codec_context->width, mdecoder->codec_context->height); + av_picture_copy((AVPicture *) frame, (AVPicture *) mdecoder->frame, + mdecoder->codec_context->pix_fmt, + mdecoder->codec_context->width, mdecoder->codec_context->height); + av_free(frame); + } return ret; } -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; - const BYTE* src; - BYTE* dst; + const BYTE *src; + BYTE *dst; int dst_offset; - #if 0 LLOGLN(0, ("tsmf_ffmpeg_decode_audio: data_size %d", data_size)); int i; - for (i = 0; i < data_size; i++) + for(i = 0; i < data_size; i++) { LLOG(0, ("%02X ", data[i])); - if (i % 16 == 15) + if(i % 16 == 15) LLOG(0, ("\n")); } LLOG(0, ("\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); /* align the memory for SSE2 needs */ - dst = (BYTE*) (((uintptr_t) mdecoder->decoded_data + 15) & ~ 0x0F); + dst = (BYTE *)(((uintptr_t) mdecoder->decoded_data + 15) & ~ 0x0F); dst_offset = dst - mdecoder->decoded_data; src = data; src_size = data_size; - - while (src_size > 0) + 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) + dst = (BYTE *)(((uintptr_t)mdecoder->decoded_data + 15) & ~ 0x0F); + 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); @@ -394,72 +363,64 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder* decoder, const BYTE* data, UI } dst += mdecoder->decoded_size; } - frame_size = mdecoder->decoded_size_max - mdecoder->decoded_size; #if LIBAVCODEC_VERSION_MAJOR < 52 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR <= 20) len = avcodec_decode_audio2(mdecoder->codec_context, - (int16_t*) dst, &frame_size, src, src_size); + (int16_t *) dst, &frame_size, src, src_size); #else { - AVFrame* decoded_frame = avcodec_alloc_frame(); + AVFrame *decoded_frame = avcodec_alloc_frame(); int got_frame = 0; AVPacket pkt; av_init_packet(&pkt); - pkt.data = (BYTE*) src; + 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); + decoded_frame->nb_samples, mdecoder->codec_context->sample_fmt, 1); memcpy(dst, decoded_frame->data[0], frame_size); } - av_free(decoded_frame); } #endif - if (len <= 0 || frame_size <= 0) + if(len <= 0 || frame_size <= 0) { DEBUG_WARN("error decoding"); break; } - src += len; src_size -= len; 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) - { - /* move the aligned decoded data to original place */ - memmove(mdecoder->decoded_data, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size); - } - - DEBUG_DVC("data_size %d decoded_size %d", - data_size, mdecoder->decoded_size); - + else + if(dst_offset) + { + /* move the aligned decoded data to original place */ + memmove(mdecoder->decoded_data, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size); + } + DEBUG_TSMF("data_size %d decoded_size %d", + data_size, mdecoder->decoded_size); 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; } mdecoder->decoded_size = 0; - - switch (mdecoder->media_type) + switch(mdecoder->media_type) { case AVMEDIA_TYPE_VIDEO: return tsmf_ffmpeg_decode_video(decoder, data, data_size, extensions); @@ -471,40 +432,35 @@ 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; - + BYTE *buf; + TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder; *size = mdecoder->decoded_size; buf = mdecoder->decoded_data; mdecoder->decoded_data = NULL; mdecoder->decoded_size = 0; - 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; - default: DEBUG_WARN("unsupported pixel format %u", - mdecoder->codec_context->pix_fmt); + mdecoder->codec_context->pix_fmt); return (UINT32) -1; } } -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; @@ -516,25 +472,21 @@ 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); } - free(decoder); } @@ -544,27 +496,22 @@ static BOOL initialized = FALSE; #define freerdp_tsmf_client_decoder_subsystem_entry ffmpeg_freerdp_tsmf_client_decoder_subsystem_entry #endif -ITSMFDecoder* freerdp_tsmf_client_decoder_subsystem_entry(void) +ITSMFDecoder *freerdp_tsmf_client_decoder_subsystem_entry(void) { - TSMFFFmpegDecoder* decoder; - - if (!initialized) + TSMFFFmpegDecoder *decoder; + if(!initialized) { avcodec_register_all(); initialized = TRUE; } - fprintf(stderr, "TSMFDecoderEntry FFMPEG\n"); - - decoder = (TSMFFFmpegDecoder*) malloc(sizeof(TSMFFFmpegDecoder)); + decoder = (TSMFFFmpegDecoder *) malloc(sizeof(TSMFFFmpegDecoder)); ZeroMemory(decoder, sizeof(TSMFFFmpegDecoder)); - decoder->iface.SetFormat = tsmf_ffmpeg_set_format; decoder->iface.Decode = tsmf_ffmpeg_decode; decoder->iface.GetDecodedData = tsmf_ffmpeg_get_decoded_data; decoder->iface.GetDecodedFormat = tsmf_ffmpeg_get_decoded_format; decoder->iface.GetDecodedDimension = tsmf_ffmpeg_get_decoded_dimension; decoder->iface.Free = tsmf_ffmpeg_free; - - return (ITSMFDecoder*) decoder; + return (ITSMFDecoder *) decoder; } diff --git a/channels/tsmf/client/gstreamer/CMakeLists.txt b/channels/tsmf/client/gstreamer/CMakeLists.txt index 5080358c8c1a..3415da717f65 100644 --- a/channels/tsmf/client/gstreamer/CMakeLists.txt +++ b/channels/tsmf/client/gstreamer/CMakeLists.txt @@ -7,7 +7,7 @@ # 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 +# 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, @@ -17,26 +17,60 @@ define_channel_client_subsystem("tsmf" "gstreamer" "decoder") -set(${MODULE_PREFIX}_SRCS - tsmf_gstreamer.c) +if(NOT GSTREAMER_0_10_FOUND AND NOT GSTREAMER_1_0_FOUND) + message(FATAL_ERROR "GStreamer library not found, but required for TSMF module.") +elseif (GSTREAMER_0_10_FOUND AND GSTREAMER_1_0_FOUND) + message(FATAL_ERROR "GStreamer 0.10 and GStreamer 1.0 support are mutually exclusive!") +endif() + +set(SRC "tsmf_gstreamer.c") + +if (GSTREAMER_1_0_FOUND) + set(LIBS ${GSTREAMER_1_0_LIBRARIES}) + include_directories(${GSTREAMER_1_0_INCLUDE_DIRS}) +elseif (GSTREAMER_0_10_FOUND) + set(LIBS ${GSTREAMER_0_10_LIBRARIES}) + include_directories(${GSTREAMER_0_10_INCLUDE_DIRS}) +endif() + +if(ANDROID) + set(SRC ${SRC} + tsmf_android.c) + set(LIBS ${LIBS}) +else() + set(XEXT_FEATURE_TYPE "RECOMMENDED") + set(XEXT_FEATURE_PURPOSE "X11 extension") + set(XEXT_FEATURE_DESCRIPTION "X11 core extensions") + + find_feature(Xext ${XEXT_FEATURE_TYPE} ${XEXT_FEATURE_PURPOSE} ${XEXT_FEATURE_DESCRIPTION}) + + set(SRC ${SRC} + tsmf_X11.c) + set(LIBS ${LIBS} ${X11_LIBRARIES} ${XEXT_LIBRARIES}) + + if(NOT XEXT_FOUND) + message(FATAL_ERROR "Xext library not found, but required for TSMF module.") + else() + add_definitions(-DWITH_XEXT=1) + endif() + +endif() + +set(${MODULE_PREFIX}_SRCS "${SRC}") include_directories(..) -include_directories(${GSTREAMER_INCLUDE_DIRS}) add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE freerdp + MODULES freerdp-utils) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} - ${GSTREAMER_LIBRARIES} - gstapp-0.10 - gstinterfaces-0.10 - Xrandr X11 Xext) + ${LIBS}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/tsmf/client/gstreamer/tsmf_X11.c b/channels/tsmf/client/gstreamer/tsmf_X11.c new file mode 100644 index 000000000000..6acc6eeb33b0 --- /dev/null +++ b/channels/tsmf/client/gstreamer/tsmf_X11.c @@ -0,0 +1,316 @@ +/* + * FreeRDP: A Remote Desktop Protocol Implementation + * Video Redirection Virtual Channel - GStreamer Decoder X11 specifics + * + * (C) Copyright 2014 Thincast Technologies GmbH + * (C) Copyright 2014 Armin Novak + * + * 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. +*/ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#if GST_VERSION_MAJOR > 0 +#include +#else +#include +#endif + +#include +#include +#include + +#include + +#include "tsmf_platform.h" +#include "tsmf_constants.h" +#include "tsmf_decoder.h" + +#if !defined(WITH_XEXT) +#warning "Building TSMF without shape extension support" +#endif + +struct X11Handle +{ + int shmid; + int *xfwin; +#if defined(WITH_XEXT) + BOOL has_shape; +#endif + Display *disp; + Window subwin; +}; + +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) +{ + return "xvimagesink"; +} + +const char *tsmf_platform_get_audio_sink(void) +{ + return "autoaudiosink"; +} + +int tsmf_platform_create(TSMFGstreamerDecoder *decoder) +{ + struct X11Handle *hdl; + assert(decoder); + assert(!decoder->platform); + hdl = malloc(sizeof(struct X11Handle)); + + if (!hdl) + { + DEBUG_WARN("%s: Could not allocate handle.", __func__); + return -1; + } + + memset(hdl, 0, sizeof(struct X11Handle)); + decoder->platform = hdl; + hdl->shmid = shm_open(get_shm_id(), O_RDWR, PROT_READ | PROT_WRITE);; + + if (hdl->shmid < 0) + { + DEBUG_WARN("%s: failed to get access to shared memory - shmget()", + __func__); + return -2; + } + else + hdl->xfwin = mmap(0, sizeof(void *), PROT_READ | PROT_WRITE, MAP_SHARED, hdl->shmid, 0); + + if (hdl->xfwin == (int *)-1) + { + DEBUG_WARN("%s: shmat failed!", __func__); + return -3; + } + + hdl->disp = XOpenDisplay(NULL); + + if (!hdl->disp) + { + DEBUG_WARN("Failed to open display"); + return -4; + } + + return 0; +} + +int tsmf_platform_set_format(TSMFGstreamerDecoder *decoder) +{ + assert(decoder); + + if (decoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + { + } + + return 0; +} + +int tsmf_platform_register_handler(TSMFGstreamerDecoder *decoder) +{ + assert(decoder); + assert(decoder->pipe); + GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(decoder->pipe)); + + if (!bus) + { + DEBUG_WARN("gst_pipeline_get_bus failed!"); + return 1; + } + + return 0; +} + +int tsmf_platform_free(TSMFGstreamerDecoder *decoder) +{ + struct X11Handle *hdl = decoder->platform; + + if (!hdl) + return -1; + + if (hdl->disp) + XCloseDisplay(hdl->disp); + + if (hdl->xfwin) + munmap(0, sizeof(void *)); + + if (hdl->shmid >= 0) + close(hdl->shmid); + + free(hdl); + decoder->platform = NULL; + return 0; +} + +int tsmf_window_create(TSMFGstreamerDecoder *decoder) +{ + if (decoder->media_type != TSMF_MAJOR_TYPE_VIDEO) + { + decoder->ready = TRUE; + return -3; + } + else + { +#if GST_VERSION_MAJOR > 0 + GstVideoOverlay *overlay = GST_VIDEO_OVERLAY(decoder->outsink); +#else + GstXOverlay *overlay = GST_X_OVERLAY(decoder->outsink); +#endif + struct X11Handle *hdl = (struct X11Handle *)decoder->platform; + assert(decoder); + assert(hdl); + + if (!hdl->subwin) + { + int event, error; + hdl->subwin = XCreateSimpleWindow(hdl->disp, *(int *)hdl->xfwin, 0, 0, 1, 1, 0, 0, 0); + + if (!hdl->subwin) + { + DEBUG_WARN("Could not create subwindow!"); + } + + XMapWindow(hdl->disp, hdl->subwin); + XSync(hdl->disp, FALSE); +#if GST_VERSION_MAJOR > 0 + gst_video_overlay_set_window_handle(overlay, hdl->subwin); +#else + gst_x_overlay_set_window_handle(overlay, hdl->subwin); +#endif + decoder->ready = TRUE; +#if defined(WITH_XEXT) + hdl->has_shape = XShapeQueryExtension(hdl->disp, &event, &error); +#endif + } + +#if GST_VERSION_MAJOR > 0 + gst_video_overlay_handle_events(overlay, TRUE); +#else + gst_x_overlay_handle_events(overlay, TRUE); +#endif + return 0; + } +} + +int tsmf_window_resize(TSMFGstreamerDecoder *decoder, int x, int y, int width, + int height, int nr_rects, RDP_RECT *rects) +{ + if (decoder->media_type != TSMF_MAJOR_TYPE_VIDEO) + return -3; + else + { +#if GST_VERSION_MAJOR > 0 + GstVideoOverlay *overlay = GST_VIDEO_OVERLAY(decoder->outsink); +#else + GstXOverlay *overlay = GST_X_OVERLAY(decoder->outsink); +#endif + struct X11Handle *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)) + { + DEBUG_WARN("Could not resize overlay!"); + } + + gst_video_overlay_expose(overlay); +#else + if (!gst_x_overlay_set_render_rectangle(overlay, 0, 0, width, height)) + { + DEBUG_WARN("Could not resize overlay!"); + } + + gst_x_overlay_expose(overlay); +#endif + + if (hdl->subwin) + { + XMoveResizeWindow(hdl->disp, hdl->subwin, x, y, width, height); +#if defined(WITH_XEXT) + + if (hdl->has_shape) + { + int i; + XRectangle *xrects = calloc(nr_rects, sizeof(XRectangle)); + + for (i=0; idisp, hdl->subwin, ShapeBounding, x, y, xrects, nr_rects, ShapeSet, 0); + free(xrects); + } + +#endif + XSync(hdl->disp, FALSE); + } + + return 0; + } +} + +int tsmf_window_pause(TSMFGstreamerDecoder *decoder) +{ + assert(decoder); + return 0; +} + +int tsmf_window_resume(TSMFGstreamerDecoder *decoder) +{ + assert(decoder); + return 0; +} + +int tsmf_window_destroy(TSMFGstreamerDecoder *decoder) +{ + struct X11Handle *hdl = (struct X11Handle *)decoder->platform; + decoder->ready = FALSE; + + if (decoder->media_type != TSMF_MAJOR_TYPE_VIDEO) + return -3; + + assert(decoder); + assert(hdl); + + if (hdl->subwin) + { + XDestroyWindow(hdl->disp, hdl->subwin); + XSync(hdl->disp, FALSE); + } + + hdl->subwin = 0; + return 0; +} + diff --git a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c index d3c477c92a50..33a609bef490 100644 --- a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c +++ b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c @@ -2,8 +2,10 @@ * FreeRDP: A Remote Desktop Protocol Implementation * Video Redirection Virtual Channel - GStreamer Decoder * - * (C) Copyright 2012 HP Development Company, LLC - * + * (C) Copyright 2012 HP Development Company, LLC + * (C) Copyright 2014 Thincast Technologies GmbH + * (C) Copyright 2014 Armin Novak + * * 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 @@ -21,329 +23,165 @@ #include "config.h" #endif -#include -#include -#include +#include #include #include #include #include #include -#include #include #include #include -#include - -#include -#include -#include -#include -#include #include "tsmf_constants.h" #include "tsmf_decoder.h" +#include "tsmf_platform.h" #ifdef HAVE_INTTYPES_H #include #endif -#define SHARED_MEM_KEY 7777 -#define TRY_DECODEBIN 0 +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); -typedef struct _TSMFGstreamerDecoder +const char *get_type(TSMFGstreamerDecoder *mdecoder) { - ITSMFDecoder iface; - - int media_type; /* TSMF_MAJOR_TYPE_AUDIO or TSMF_MAJOR_TYPE_VIDEO */ - - TS_AM_MEDIA_TYPE tsmf_media_type; /* TSMF description of the media type, (without ExtraData) */ + assert(mdecoder); - pthread_t eventloop_thread; + if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + return "VIDEO"; + else + return "AUDIO"; +} - GstCaps *gst_caps; /* Gstreamer description of the media type */ +static void tsmf_gstreamer_enough_data(GstAppSrc *src, gpointer user_data) +{ + TSMFGstreamerDecoder *mdecoder = user_data; + (void)mdecoder; + DEBUG_TSMF("%s", get_type(mdecoder)); +} - GstState state; +static void tsmf_gstreamer_need_data(GstAppSrc *src, guint length, gpointer user_data) +{ + TSMFGstreamerDecoder *mdecoder = user_data; + (void)mdecoder; + DEBUG_TSMF("%s length=%lu", get_type(mdecoder), length); +} - GstElement *pipe; - GstElement *src; - GstElement *queue; - GstElement *decbin; - GstElement *outbin; - GstElement *outconv; - GstElement *outsink; - GstElement *aVolume; +static gboolean tsmf_gstreamer_seek_data(GstAppSrc *src, guint64 offset, gpointer user_data) +{ + TSMFGstreamerDecoder *mdecoder = user_data; + (void)mdecoder; + DEBUG_TSMF("%s offset=%llu", get_type(mdecoder), offset); - BOOL paused; - UINT64 last_sample_end_time; + if (!mdecoder->paused) + tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PAUSED); - Display *disp; - int *xfwin; - Window subwin; - int xOffset; - int yOffset; - BOOL offsetObtained; - int linked; - double gstVolume; - BOOL gstMuted; + gst_app_src_end_of_stream((GstAppSrc *)mdecoder->src); - int pipeline_start_time_valid; /* We've set the start time and have not reset the pipeline */ - int shutdown; /* The decoder stream is shutting down */ - pthread_mutex_t gst_mutex; + if (!mdecoder->paused) + tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); -} TSMFGstreamerDecoder; + if (mdecoder->sync_cb) + mdecoder->sync_cb(mdecoder->stream); -const char *NAME_GST_STATE_PLAYING = "GST_STATE_PLAYING"; -const char *NAME_GST_STATE_PAUSED = "GST_STATE_PAUSED"; -const char *NAME_GST_STATE_READY = "GST_STATE_READY"; -const char *NAME_GST_STATE_NULL = "GST_STATE_NULL"; -const char *NAME_GST_STATE_VOID_PENDING = "GST_STATE_VOID_PENDING"; -const char *NAME_GST_STATE_OTHER = "GST_STATE_?"; + return TRUE; +} static inline const GstClockTime tsmf_gstreamer_timestamp_ms_to_gst(UINT64 ms_timestamp) { - /* + /* * Convert Microsoft 100ns timestamps to Gstreamer 1ns units. */ return (GstClockTime)(ms_timestamp * 100); } -static const char *tsmf_gstreamer_state_name(GstState state) +int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, GstState desired_state) { + GstStateChangeReturn state_change; const char *name; + const char *sname = get_type(mdecoder); - if (state == GST_STATE_PLAYING) name = NAME_GST_STATE_PLAYING; - else if (state == GST_STATE_PAUSED) name = NAME_GST_STATE_PAUSED; - else if (state == GST_STATE_READY) name = NAME_GST_STATE_READY; - else if (state == GST_STATE_NULL) name = NAME_GST_STATE_NULL; - else if (state == GST_STATE_VOID_PENDING) name = NAME_GST_STATE_VOID_PENDING; - else name = NAME_GST_STATE_OTHER; - - return name; -} - -#if 0 -static void *tsmf_gstreamer_eventloop_thread_func(void * arg) -{ - TSMFGstreamerDecoder * mdecoder = (TSMFGstreamerDecoder *) arg; - GstBus *bus; - GstMessage *message = NULL; - GstState old, new, pending; - int loop; - - DEBUG_DVC("tsmf_gstreamer_eventloop_thread_func: "); - - bus = gst_element_get_bus(mdecoder->pipe); - - loop = 1; - while (loop) - { - message = gst_bus_poll (bus, GST_MESSAGE_ANY, -1); - - if (mdecoder->shutdown) - { - loop =0; /* We are done with this stream */ - } - else - { - switch (message->type) - { - case GST_MESSAGE_EOS: - DEBUG_DVC("tsmf_gstreamer_eventloop_thread_func: GST_MESSAGE_EOS"); - gst_message_unref (message); - break; - - case GST_MESSAGE_WARNING: - case GST_MESSAGE_ERROR: - { - DEBUG_DVC("tsmf_gstreamer_eventloop_thread_func: GST_MESSAGE_ERROR"); - /*GError *err; - gchar *debug; - gst_message_parse_error(message, &err, &debug); - g_print("ERROR: %s\nDEBUG:%s\n", err->message, debug); - g_error_free(err); - g_free(debug); - gst_message_unref(message);*/ - break; - } - case GST_MESSAGE_STATE_CHANGED: - { - gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC(message)); - - gst_message_parse_state_changed (message, &old, &new, &pending); - - DEBUG_DVC("tsmf_gstreamer_eventloop_thread_func: GST_MESSAGE_STATE_CHANGED %s old %s new %s pending %s", - name, - gst_element_state_get_name(old), - gst_element_state_get_name(new), - gst_element_state_get_name(pending)); - - g_free (name); - gst_message_unref(message); - - break; - } - - case GST_MESSAGE_REQUEST_STATE: - { - GstState state; - gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC(message)); - - gst_message_parse_request_state(message, &state); - - DEBUG_DVC("GST_MESSAGE_REQUEST_STATE: Setting %s state to %s", name, gst_element_state_get_name(state)); - - gst_element_set_state (mdecoder->pipe, state); - - g_free (name); - - gst_message_unref(message); - break; - } - - default: - gst_message_unref(message); - break; - } - } - } - - mdecoder->eventloop_thread = 0; - - DEBUG_DVC("tsmf_gstreamer_eventloop_thread_func: EXITED"); - return 0; -} + if (!mdecoder) + return 0; -static int tsmf_gstreamer_start_eventloop_thread(TSMFGstreamerDecoder *mdecoder) -{ - pthread_create(&(mdecoder->eventloop_thread), 0, tsmf_gstreamer_eventloop_thread_func, mdecoder); - pthread_detach(mdecoder->eventloop_thread); + if (!mdecoder->pipe) + return 0; /* Just in case this is called during startup or shutdown when we don't expect it */ - return 0; -} -#endif + if (desired_state == mdecoder->state) + return 0; /* Redundant request - Nothing to do */ -static int tsmf_gstreamer_stop_eventloop_thread(TSMFGstreamerDecoder *mdecoder) -{ - DEBUG_DVC("tsmf_gstreamer_stop_eventloop_thread: "); - if (!mdecoder) - return 0; + name = gst_element_state_get_name(desired_state); /* For debug */ + DEBUG_TSMF("%s to %s", sname, name); + state_change = gst_element_set_state(mdecoder->pipe, desired_state); - if (mdecoder->eventloop_thread != 0) + if (state_change == GST_STATE_CHANGE_FAILURE) + DEBUG_WARN("%s: (%s) GST_STATE_CHANGE_FAILURE.", sname, name); + else if (state_change == GST_STATE_CHANGE_ASYNC) { - pthread_cancel(mdecoder->eventloop_thread); + DEBUG_WARN("%s: (%s) GST_STATE_CHANGE_ASYNC.", sname, name); + mdecoder->state = desired_state; } + else + mdecoder->state = desired_state; return 0; } -static int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder * mdecoder, GstState desired_state) +static GstBuffer *tsmf_get_buffer_from_data(const void *raw_data, gsize size) { - if (!mdecoder) - return 0; - GstStateChangeReturn state_change; - int keep_waiting; - int timeout; - GstState current_state; - GstState pending_state; - const char *name; - const char *current_name; - const char *pending_name; - - if (!mdecoder->pipe) - return 0; /* Just in case this is called during startup or shutdown when we don't expect it */ - - if (desired_state == mdecoder->state) - return 0; /* Redundant request - Nothing to do */ + GstBuffer *buffer; + gpointer data; + assert(raw_data); + assert(size > 0); + data = g_malloc(size); - name = tsmf_gstreamer_state_name(desired_state); /* For debug */ + if (!data) + { + DEBUG_WARN("Could not allocate %"G_GSIZE_FORMAT" bytes of data.", size); + return NULL; + } - keep_waiting = 1; - state_change = gst_element_set_state (mdecoder->pipe, desired_state); - timeout = 1000; - if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) - DEBUG_DVC("tsmf_gstreamer_pipeline_set_state_VIDEO:"); - else - DEBUG_DVC("tsmf_gstreamer_pipeline_set_state_AUDIO:"); + memcpy(data, raw_data, size); +#if GST_VERSION_MAJOR > 0 + buffer = gst_buffer_new_wrapped(data, size); +#else + buffer = gst_buffer_new(); - while (keep_waiting) + if (!buffer) { - if (state_change == GST_STATE_CHANGE_FAILURE) - { - DEBUG_WARN("tsmf_gstreamer_pipeline_set_state(%s) GST_STATE_CHANGE_FAILURE.", name); - keep_waiting = 0; - } - else if (state_change == GST_STATE_CHANGE_SUCCESS) - { - DEBUG_DVC("tsmf_gstreamer_pipeline_set_state(%s) GST_STATE_CHANGE_SUCCESS.", name); - mdecoder->state = desired_state; - keep_waiting = 0; - } - else if (state_change == GST_STATE_CHANGE_NO_PREROLL) - { - DEBUG_DVC("tsmf_gstreamer_pipeline_set_state(%s) GST_STATE_CHANGE_NO_PREROLL.", name); - keep_waiting = 0; - } - else if (state_change == GST_STATE_CHANGE_ASYNC) - { - DEBUG_DVC("tsmf_gstreamer_pipeline_set_state(%s) GST_STATE_CHANGE_ASYNC.", name); - - state_change = gst_element_get_state(mdecoder->pipe, ¤t_state, &pending_state, 10 * GST_MSECOND); - current_name = tsmf_gstreamer_state_name(current_state); - pending_name = tsmf_gstreamer_state_name(pending_state); - - if (current_state == desired_state) - { - DEBUG_DVC("tsmf_gstreamer_pipeline_set_state(%s) GST_STATE_CHANGE_SUCCESS.", name); - mdecoder->state = desired_state; - keep_waiting = 0; - } - else if (pending_state != desired_state) - { - DEBUG_DVC("tsmf_gstreamer_pipeline_set_state(%s) changing to %s instead.", name, pending_name); - keep_waiting = 0; - } - else - { - DEBUG_DVC("tsmf_gstreamer_pipeline_set_state(%s) Waiting - current %s pending %s.", name, current_name, pending_name); - } - } - /* - To avoid RDP session hang. set timeout for changing gstreamer state to 5 seconds. - */ - usleep(10000); - timeout--; - if (timeout <= 0) - { - DEBUG_WARN("tsmf_gstreamer_pipeline_set_state: TIMED OUT - failed to change state"); - keep_waiting = 0; - break; - } + DEBUG_WARN("Could not create GstBuffer"); + free(data); + return NULL; } - //sleep(1); - return 0; + + GST_BUFFER_MALLOCDATA(buffer) = data; + 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; - GstBuffer *gst_buf_cap_codec_data; /* Buffer to hold extra descriptive codec-specific caps data */ + return FALSE; - DEBUG_DVC("tsmf_gstreamer_set_format: "); + DEBUG_TSMF(""); switch (media_type->MajorType) { case TSMF_MAJOR_TYPE_VIDEO: mdecoder->media_type = TSMF_MAJOR_TYPE_VIDEO; - mdecoder->tsmf_media_type = *media_type; /* Structure copy */ break; case TSMF_MAJOR_TYPE_AUDIO: mdecoder->media_type = TSMF_MAJOR_TYPE_AUDIO; - mdecoder->tsmf_media_type = *media_type; /* Structure copy */ break; default: return FALSE; @@ -352,230 +190,104 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder * decoder, TS_AM_MEDIA_TYPE * switch (media_type->SubType) { case TSMF_SUB_TYPE_WVC1: - gst_buf_cap_codec_data = gst_buffer_try_new_and_alloc(media_type->ExtraDataSize); - if (gst_buf_cap_codec_data != NULL) - { - memcpy(GST_BUFFER_MALLOCDATA(gst_buf_cap_codec_data), - media_type->ExtraData, media_type->ExtraDataSize); - } - else - { - DEBUG_WARN("tsmf_gstreamer_set_format: gst_buffer_try_new_and_alloc(%d) failed.", - media_type->ExtraDataSize); - } - mdecoder->gst_caps = gst_caps_new_simple ("video/x-wmv", - "bitrate", G_TYPE_UINT, media_type->BitRate, - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - "wmvversion", G_TYPE_INT, 3, - "codec_data", GST_TYPE_BUFFER, gst_buf_cap_codec_data, - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'V', 'C', '1'), - //"framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, - NULL); + mdecoder->gst_caps = gst_caps_new_simple("video/x-wmv", + "bitrate", G_TYPE_UINT, media_type->BitRate, + "width", G_TYPE_INT, media_type->Width, + "height", G_TYPE_INT, media_type->Height, + "wmvversion", G_TYPE_INT, 3, + NULL); break; case TSMF_SUB_TYPE_MP4S: - if (media_type->ExtraDataSize > 0) - { - gst_buf_cap_codec_data = gst_buffer_try_new_and_alloc(media_type->ExtraDataSize); - if (gst_buf_cap_codec_data != NULL) - { - memcpy(GST_BUFFER_MALLOCDATA(gst_buf_cap_codec_data), media_type->ExtraData, media_type->ExtraDataSize); - } - else - { - DEBUG_WARN("tsmf_gstreamer_set_format: gst_buffer_try_new_and_alloc(%d) failed.", media_type->ExtraDataSize); - } - mdecoder->gst_caps = gst_caps_new_simple ("video/x-divx", - "divxversion", G_TYPE_INT, 5, - "bitrate", G_TYPE_UINT, media_type->BitRate, - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - "codec_data", GST_TYPE_BUFFER, gst_buf_cap_codec_data, - NULL); - } - else - { - mdecoder->gst_caps = gst_caps_new_simple ("video/x-divx", - "divxversion", G_TYPE_INT, 5, - "bitrate", G_TYPE_UINT, media_type->BitRate, - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - NULL); - } + mdecoder->gst_caps = gst_caps_new_simple("video/x-divx", + "divxversion", G_TYPE_INT, 5, + "bitrate", G_TYPE_UINT, media_type->BitRate, + "width", G_TYPE_INT, media_type->Width, + "height", G_TYPE_INT, media_type->Height, + NULL); break; case TSMF_SUB_TYPE_MP42: - mdecoder->gst_caps = gst_caps_new_simple ("video/x-msmpeg", - "msmpegversion", G_TYPE_INT, 42, - "bitrate", G_TYPE_UINT, media_type->BitRate, - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - NULL); + mdecoder->gst_caps = gst_caps_new_simple("video/x-msmpeg", + "msmpegversion", G_TYPE_INT, 42, + "bitrate", G_TYPE_UINT, media_type->BitRate, + "width", G_TYPE_INT, media_type->Width, + "height", G_TYPE_INT, media_type->Height, + NULL); break; case TSMF_SUB_TYPE_MP43: - mdecoder->gst_caps = gst_caps_new_simple ("video/x-msmpeg", - "bitrate", G_TYPE_UINT, media_type->BitRate, - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('M', 'P', '4', '3'), - NULL); + mdecoder->gst_caps = gst_caps_new_simple("video/x-msmpeg", + "bitrate", G_TYPE_UINT, media_type->BitRate, + "width", G_TYPE_INT, media_type->Width, + "height", G_TYPE_INT, media_type->Height, + NULL); break; case TSMF_SUB_TYPE_WMA9: - if (media_type->ExtraDataSize > 0) - { - gst_buf_cap_codec_data = gst_buffer_try_new_and_alloc(media_type->ExtraDataSize); - if (gst_buf_cap_codec_data != NULL) - { - memcpy(GST_BUFFER_MALLOCDATA(gst_buf_cap_codec_data), media_type->ExtraData, media_type->ExtraDataSize); - } - else - { - DEBUG_WARN("tsmf_gstreamer_set_format: gst_buffer_try_new_and_alloc(%d) failed.", media_type->ExtraDataSize); - } - mdecoder->gst_caps = gst_caps_new_simple ("audio/x-wma", - "wmaversion", G_TYPE_INT, 3, - "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, - "channels", G_TYPE_INT, media_type->Channels, - "bitrate", G_TYPE_INT, media_type->BitRate, - "depth", G_TYPE_INT, media_type->BitsPerSample, - "width", G_TYPE_INT, media_type->BitsPerSample, - "block_align", G_TYPE_INT, media_type->BlockAlign, - "codec_data", GST_TYPE_BUFFER, gst_buf_cap_codec_data, - NULL); - } - else - { - mdecoder->gst_caps = gst_caps_new_simple ("audio/x-wma", - "wmaversion", G_TYPE_INT, 3, - "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, - "channels", G_TYPE_INT, media_type->Channels, - "bitrate", G_TYPE_INT, media_type->BitRate, - "depth", G_TYPE_INT, media_type->BitsPerSample, - "width", G_TYPE_INT, media_type->BitsPerSample, - "block_align", G_TYPE_INT, media_type->BlockAlign, - NULL); - } + mdecoder->gst_caps = gst_caps_new_simple("audio/x-wma", + "wmaversion", G_TYPE_INT, 3, + "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, + "channels", G_TYPE_INT, media_type->Channels, + "bitrate", G_TYPE_INT, media_type->BitRate, + "depth", G_TYPE_INT, media_type->BitsPerSample, + "width", G_TYPE_INT, media_type->BitsPerSample, + "block_align", G_TYPE_INT, media_type->BlockAlign, + NULL); break; case TSMF_SUB_TYPE_WMA2: - gst_buf_cap_codec_data = gst_buffer_try_new_and_alloc(media_type->ExtraDataSize); - if (gst_buf_cap_codec_data != NULL) - { - memcpy(GST_BUFFER_MALLOCDATA(gst_buf_cap_codec_data), - media_type->ExtraData, media_type->ExtraDataSize); - } - else - { - DEBUG_WARN("tsmf_gstreamer_set_format: gst_buffer_try_new_and_alloc(%d) failed.", - media_type->ExtraDataSize); - } - - mdecoder->gst_caps = gst_caps_new_simple ("audio/x-wma", - "wmaversion", G_TYPE_INT, 2, - "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, - "channels", G_TYPE_INT, media_type->Channels, - "bitrate", G_TYPE_INT, media_type->BitRate, - "depth", G_TYPE_INT, media_type->BitsPerSample, - "width", G_TYPE_INT, media_type->BitsPerSample, - "block_align", G_TYPE_INT, media_type->BlockAlign, - "codec_data", GST_TYPE_BUFFER, gst_buf_cap_codec_data, - NULL); + mdecoder->gst_caps = gst_caps_new_simple("audio/x-wma", + "wmaversion", G_TYPE_INT, 2, + "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, + "channels", G_TYPE_INT, media_type->Channels, + "bitrate", G_TYPE_INT, media_type->BitRate, + "depth", G_TYPE_INT, media_type->BitsPerSample, + "width", G_TYPE_INT, media_type->BitsPerSample, + "block_align", G_TYPE_INT, media_type->BlockAlign, + NULL); break; case TSMF_SUB_TYPE_MP3: - mdecoder->gst_caps = gst_caps_new_simple ("audio/mpeg", - "mpegversion", G_TYPE_INT, 1, - "mpegaudioversion", G_TYPE_INT, 1, - "layer", G_TYPE_INT, 3, - "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, - "channels", G_TYPE_INT, media_type->Channels, - "parsed", G_TYPE_BOOLEAN, TRUE, - NULL); + mdecoder->gst_caps = gst_caps_new_simple("audio/mpeg", + "mpegversion", G_TYPE_INT, 1, + "layer", G_TYPE_INT, 3, + "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, + "channels", G_TYPE_INT, media_type->Channels, + NULL); break; case TSMF_SUB_TYPE_WMV1: - mdecoder->gst_caps = gst_caps_new_simple ("video/x-wmv", - "bitrate", G_TYPE_UINT, media_type->BitRate, - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - "wmvversion", G_TYPE_INT, 1, - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'M', 'V', '1'), - NULL); + mdecoder->gst_caps = gst_caps_new_simple("video/x-wmv", + "bitrate", G_TYPE_UINT, media_type->BitRate, + "width", G_TYPE_INT, media_type->Width, + "height", G_TYPE_INT, media_type->Height, + "wmvversion", G_TYPE_INT, 1, + NULL); break; case TSMF_SUB_TYPE_WMV2: - gst_buf_cap_codec_data = gst_buffer_try_new_and_alloc(media_type->ExtraDataSize); - if (gst_buf_cap_codec_data != NULL) - { - memcpy(GST_BUFFER_MALLOCDATA(gst_buf_cap_codec_data), - media_type->ExtraData, media_type->ExtraDataSize); - } - else - { - DEBUG_WARN("tsmf_gstreamer_set_format: gst_buffer_try_new_and_alloc(%d) failed.", - media_type->ExtraDataSize); - } - mdecoder->gst_caps = gst_caps_new_simple ("video/x-wmv", - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - "wmvversion", G_TYPE_INT, 2, - "codec_data", GST_TYPE_BUFFER, gst_buf_cap_codec_data, - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'M', 'V', '2'), - NULL); + mdecoder->gst_caps = gst_caps_new_simple("video/x-wmv", + "width", G_TYPE_INT, media_type->Width, + "height", G_TYPE_INT, media_type->Height, + "wmvversion", G_TYPE_INT, 2, + NULL); break; case TSMF_SUB_TYPE_WMV3: - gst_buf_cap_codec_data = gst_buffer_try_new_and_alloc(media_type->ExtraDataSize); - if (gst_buf_cap_codec_data != NULL) - { - memcpy(GST_BUFFER_MALLOCDATA(gst_buf_cap_codec_data), - media_type->ExtraData, media_type->ExtraDataSize); - } - else - { - DEBUG_WARN("tsmf_gstreamer_set_format: gst_buffer_try_new_and_alloc(%d) failed.", - media_type->ExtraDataSize); - } - mdecoder->gst_caps = gst_caps_new_simple ("video/x-wmv", - "bitrate", G_TYPE_UINT, media_type->BitRate, - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - "wmvversion", G_TYPE_INT, 3, - "codec_data", GST_TYPE_BUFFER, gst_buf_cap_codec_data, - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'M', 'V', '3'), - //"framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, - NULL); + mdecoder->gst_caps = gst_caps_new_simple("video/x-wmv", + "bitrate", G_TYPE_UINT, media_type->BitRate, + "width", G_TYPE_INT, media_type->Width, + "height", G_TYPE_INT, media_type->Height, + "wmvversion", G_TYPE_INT, 3, + NULL); break; case TSMF_SUB_TYPE_AVC1: case TSMF_SUB_TYPE_H264: - if (media_type->ExtraDataSize > 0) - { - gst_buf_cap_codec_data = gst_buffer_try_new_and_alloc(media_type->ExtraDataSize); - if (gst_buf_cap_codec_data != NULL) - { - memcpy(GST_BUFFER_MALLOCDATA(gst_buf_cap_codec_data), media_type->ExtraData, media_type->ExtraDataSize); - } - else - { - DEBUG_WARN("tsmf_gstreamer_set_format: gst_buffer_try_new_and_alloc(%d) failed.", media_type->ExtraDataSize); - } - mdecoder->gst_caps = gst_caps_new_simple ("video/x-h264", - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - "codec_data", GST_TYPE_BUFFER, gst_buf_cap_codec_data, - //"framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, - NULL); - } - else - { - mdecoder->gst_caps = gst_caps_new_simple ("video/x-h264", - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - //"framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, - NULL); - } + mdecoder->gst_caps = gst_caps_new_simple("video/x-h264", + "width", G_TYPE_INT, media_type->Width, + "height", G_TYPE_INT, media_type->Height, + NULL); break; case TSMF_SUB_TYPE_AC3: - mdecoder->gst_caps = gst_caps_new_simple ("audio/x-ac3", - "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, - "channels", G_TYPE_INT, media_type->Channels, - NULL); + mdecoder->gst_caps = gst_caps_new_simple("audio/x-ac3", + "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, + "channels", G_TYPE_INT, media_type->Channels, + NULL); break; case TSMF_SUB_TYPE_AAC: + /* For AAC the pFormat is a HEAACWAVEINFO struct, and the codec data is at the end of it. See http://msdn.microsoft.com/en-us/library/dd757806.aspx */ @@ -584,1010 +296,472 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder * decoder, TS_AM_MEDIA_TYPE * media_type->ExtraData += 12; media_type->ExtraDataSize -= 12; } - gst_buf_cap_codec_data = gst_buffer_try_new_and_alloc(media_type->ExtraDataSize); - if (gst_buf_cap_codec_data != NULL) - { - memcpy(GST_BUFFER_MALLOCDATA(gst_buf_cap_codec_data), - media_type->ExtraData, media_type->ExtraDataSize); - } - else - { - DEBUG_WARN("tsmf_gstreamer_set_format: gst_buffer_try_new_and_alloc(%d) failed.", - media_type->ExtraDataSize); - } - mdecoder->gst_caps = gst_caps_new_simple ("audio/mpeg", - "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, - "channels", G_TYPE_INT, media_type->Channels, - "mpegversion", G_TYPE_INT, 4, - "codec_data", GST_TYPE_BUFFER, gst_buf_cap_codec_data, - NULL); + + mdecoder->gst_caps = gst_caps_new_simple("audio/mpeg", + "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, + "channels", G_TYPE_INT, media_type->Channels, + "mpegversion", G_TYPE_INT, 4, + NULL); break; case TSMF_SUB_TYPE_MP1A: - if (media_type->ExtraDataSize > 0) - { - gst_buf_cap_codec_data = gst_buffer_try_new_and_alloc(media_type->ExtraDataSize); - if (gst_buf_cap_codec_data != NULL) - { - memcpy(GST_BUFFER_MALLOCDATA(gst_buf_cap_codec_data), media_type->ExtraData, media_type->ExtraDataSize); - } - else - { - DEBUG_WARN("tsmf_gstreamer_set_format: gst_buffer_try_new_and_alloc(%d) failed.", media_type->ExtraDataSize); - } - mdecoder->gst_caps = gst_caps_new_simple ("audio/mpeg", - "mpegversion", G_TYPE_INT, 1, - "channels", G_TYPE_INT, media_type->Channels, - "codec_data", GST_TYPE_BUFFER, gst_buf_cap_codec_data, - NULL); - } - else - { - mdecoder->gst_caps = gst_caps_new_simple ("audio/mpeg", - "mpegversion", G_TYPE_INT, 1, - "channels", G_TYPE_INT, media_type->Channels, - NULL); - } + mdecoder->gst_caps = gst_caps_new_simple("audio/mpeg", + "mpegversion", G_TYPE_INT, 1, + "channels", G_TYPE_INT, media_type->Channels, + NULL); break; case TSMF_SUB_TYPE_MP1V: - mdecoder->gst_caps = gst_caps_new_simple ("video/mpeg", - "mpegversion", G_TYPE_INT, 1, - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - "systemstream", G_TYPE_BOOLEAN, FALSE, - NULL); + mdecoder->gst_caps = gst_caps_new_simple("video/mpeg", + "mpegversion", G_TYPE_INT, 1, + "width", G_TYPE_INT, media_type->Width, + "height", G_TYPE_INT, media_type->Height, + "systemstream", G_TYPE_BOOLEAN, FALSE, + NULL); break; case TSMF_SUB_TYPE_YUY2: - mdecoder->gst_caps = gst_caps_new_simple ("video/x-raw-yuv", - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'), - //"bitrate", G_TYPE_UINT, media_type->BitRate, - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - NULL); +#if GST_VERSION_MAJOR > 0 + mdecoder->gst_caps = gst_caps_new_simple("video/x-raw", + "format", G_TYPE_STRING, "YUY2", + "width", G_TYPE_INT, media_type->Width, + "height", G_TYPE_INT, media_type->Height, + NULL); +#else + mdecoder->gst_caps = gst_caps_new_simple("video/x-raw-yuv", + "format", G_TYPE_STRING, "YUY2", + "width", G_TYPE_INT, media_type->Width, + "height", G_TYPE_INT, media_type->Height, + NULL); +#endif break; case TSMF_SUB_TYPE_MP2V: - mdecoder->gst_caps = gst_caps_new_simple ("video/mpeg", - //"bitrate", G_TYPE_UINT, media_type->BitRate, - //"width", G_TYPE_INT, media_type->Width, - //"height", G_TYPE_INT, media_type->Height, - "mpegversion", G_TYPE_INT, 2, - "systemstream", G_TYPE_BOOLEAN, FALSE, - NULL); + mdecoder->gst_caps = gst_caps_new_simple("video/mpeg", + "mpegversion", G_TYPE_INT, 2, + "systemstream", G_TYPE_BOOLEAN, FALSE, + NULL); break; case TSMF_SUB_TYPE_MP2A: - mdecoder->gst_caps = gst_caps_new_simple ("audio/mpeg", - "mpegversion", G_TYPE_INT, 2, - "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, - "channels", G_TYPE_INT, media_type->Channels, - NULL); - break; -#if 0 - case TSMF_SUB_TYPE_AC3: + mdecoder->gst_caps = gst_caps_new_simple("audio/mpeg", + "mpegversion", G_TYPE_INT, 2, + "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, + "channels", G_TYPE_INT, media_type->Channels, + NULL); break; -#endif default: - DEBUG_WARN("tsmf_gstreamer_set_format: unknown format:(%d).", media_type->SubType); + DEBUG_WARN("unknown format:(%d).", media_type->SubType); return FALSE; } - return TRUE; -} - -static void tsmf_gstreamer_pipeline_send_end_of_stream(TSMFGstreamerDecoder * mdecoder) -{ - DEBUG_DVC("tsmf_gstreamer_pipeline_send_end_of_stream: "); - - if (mdecoder && mdecoder->src) - { - gst_app_src_end_of_stream(GST_APP_SRC(mdecoder->src)); - } - - return; -} - -#ifdef __arm__ -/* code from TI to check whether OMX is being lock or not */ -static BOOL tsmf_gstreamer_pipeline_omx_available() -{ - BOOL ret = TRUE; - int shm_fd = 0; - struct shm_info + if (media_type->ExtraDataSize > 0) { - pid_t pid; - }shm_info; - struct shm_info *info = NULL; + GstBuffer *buffer; + DEBUG_TSMF("Extra data available (%d)", media_type->ExtraDataSize); + buffer = tsmf_get_buffer_from_data(media_type->ExtraData, media_type->ExtraDataSize); - shm_fd = shm_open ("gstomx", (O_CREAT | O_RDWR), (S_IREAD | S_IWRITE)); - if (shm_fd < 0) - { - DEBUG_DVC("ERROR: failed to open shm"); - goto exit; - } - - /* set file size */ - ftruncate(shm_fd, sizeof(struct shm_info)); - - if ((info = mmap(0, sizeof(struct shm_info), (PROT_READ | PROT_WRITE), MAP_SHARED, shm_fd, 0)) == MAP_FAILED) - { - DEBUG_DVC("ERROR: failed to map"); - goto exit; - } + if (!buffer) + { + DEBUG_WARN("could not allocate GstBuffer!"); + return FALSE; + } - if (info->pid) - { - DEBUG_DVC ("ERROR: omxcore is in use by '%d'", info->pid); - ret = FALSE; - } - else - { - DEBUG_DVC ("omxcore is available for use"); + gst_caps_set_simple(mdecoder->gst_caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); } + DEBUG_TSMF("%p format '%s'", mdecoder, gst_caps_to_string(mdecoder->gst_caps)); + tsmf_platform_set_format(mdecoder); - exit: - if (info) - munmap (info, sizeof(struct shm_info)); - - if (shm_fd) - close (shm_fd); + /* Create the pipeline... */ + if (!tsmf_gstreamer_pipeline_build(mdecoder)) + return FALSE; - return ret; + return TRUE; } -#endif -static void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder * mdecoder) +void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder *mdecoder) { //Cleaning up elements - if (!mdecoder) + if (!mdecoder || !mdecoder->pipe) return; - if (mdecoder->src) + if (mdecoder->pipe && GST_OBJECT_REFCOUNT_VALUE(mdecoder->pipe) > 0) { - gst_object_unref(mdecoder->src); - mdecoder->src = NULL; + tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_NULL); + gst_object_unref(mdecoder->pipe); } - if (mdecoder->queue) - { - gst_object_unref(mdecoder->queue); - mdecoder->queue = NULL; - } - if (mdecoder->decbin) - { - gst_object_unref(mdecoder->decbin); - mdecoder->decbin = NULL; - } - if(mdecoder->outbin) - { - gst_object_unref(mdecoder->outbin); - mdecoder->outbin = NULL; - } - if (mdecoder->outconv) - { - gst_object_unref(mdecoder->outconv); - mdecoder->outconv = NULL; - } - if (mdecoder->outsink) - { - gst_object_unref(mdecoder->outsink); - mdecoder->outsink = NULL; - } - if (mdecoder->aVolume) - { - gst_object_unref(mdecoder->aVolume); - mdecoder->aVolume = NULL; - } -} + tsmf_window_destroy(mdecoder); + mdecoder->ready = FALSE; + mdecoder->pipe = NULL; + mdecoder->src = NULL; +} -static 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 !"; + char pipeline[1024]; + if (!mdecoder) return FALSE; - GstPad *out_pad; - mdecoder->pipe = gst_pipeline_new (NULL); + /* TODO: Construction of the pipeline from a string allows easy overwrite with arguments. + * The only fixed elements necessary are appsrc and the volume element for audio streams. + * The rest could easily be provided in gstreamer pipeline notation from command line. */ + if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + snprintf(pipeline, sizeof(pipeline), "%s %s %s name=outsink", appsrc, video, tsmf_platform_get_video_sink()); + else + snprintf(pipeline, sizeof(pipeline), "%s %s %s name=outsink", appsrc, audio, tsmf_platform_get_audio_sink()); + + DEBUG_TSMF("pipeline=%s", pipeline); + mdecoder->pipe = gst_parse_launch(pipeline, NULL); + if (!mdecoder->pipe) { - DEBUG_WARN("tsmf_gstreamer_pipeline_build: Failed to create new pipe"); + DEBUG_WARN("Failed to create new pipe"); return FALSE; } - BOOL OMXavailable = FALSE; - -#ifdef __arm__ - OMXavailable = tsmf_gstreamer_pipeline_omx_available(); -#endif - - /* - * On Atlas without this printf, we'll see Illegal instruction only with optimization level set to -O2. - */ - const char *blank = ""; - printf("%s", blank); - - BOOL hwaccelflu = FALSE; - BOOL hwaccelomx = FALSE; + mdecoder->src = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "source"); - switch (mdecoder->tsmf_media_type.SubType) + if (!mdecoder->src) { - case TSMF_SUB_TYPE_WMA2: - mdecoder->decbin = gst_element_factory_make ("fluwmadec", NULL); - if (!mdecoder->decbin) - mdecoder->decbin = gst_element_factory_make ("ffdec_wmav2", NULL); - DEBUG_DVC("tsmf_gstreamer_pipeline_build: WMA2"); - break; - case TSMF_SUB_TYPE_WMA9: - mdecoder->decbin = gst_element_factory_make ("fluwmadec", NULL); - if (!mdecoder->decbin) - mdecoder->decbin = gst_element_factory_make ("ffdec_wmapro", NULL); - DEBUG_DVC("tsmf_gstreamer_pipeline_build: WMA9 - WMA PRO version 3"); - break; - case TSMF_SUB_TYPE_MP3: - mdecoder->decbin = gst_element_factory_make ("flump3dec", NULL); - DEBUG_DVC("tsmf_gstreamer_pipeline_build: MP3"); - break; - case TSMF_SUB_TYPE_MP4S: - if (OMXavailable) - { - mdecoder->decbin = gst_element_factory_make ("omx_mpeg4dec", NULL); - if (mdecoder->decbin) - { - hwaccelomx = TRUE; - } - } - else - mdecoder->decbin = NULL; - - if(!mdecoder->decbin) - mdecoder->decbin = gst_element_factory_make ("flumpeg4vdec", NULL); - if(!mdecoder->decbin) - mdecoder->decbin = gst_element_factory_make ("ffdec_mpeg4", NULL); - DEBUG_DVC("tsmf_gstreamer_pipeline_build: MP4S"); - break; - case TSMF_SUB_TYPE_MP42: - mdecoder->decbin = gst_element_factory_make ("ffdec_msmpeg4v2", NULL); - DEBUG_DVC("tsmf_gstreamer_pipeline_build: MP42"); - break; - case TSMF_SUB_TYPE_MP43: - mdecoder->decbin = gst_element_factory_make ("ffdec_msmpeg4", NULL); - DEBUG_DVC("tsmf_gstreamer_pipeline_build: MP43"); - break; - case TSMF_SUB_TYPE_MP2V: - if (OMXavailable) - { - mdecoder->decbin = gst_element_factory_make ("omx_mpeg2dec", NULL); - if (mdecoder->decbin) - { - hwaccelomx = TRUE; - } - } - else - mdecoder->decbin = NULL; - if (!mdecoder->decbin) - mdecoder->decbin = gst_element_factory_make ("ffdec_mpeg2video", NULL); - - DEBUG_DVC("tsmf_gstreamer_pipeline_build: MPEG2 Video"); - break; - case TSMF_SUB_TYPE_WMV1: - mdecoder->decbin = gst_element_factory_make ("ffdec_wmv1", NULL); - DEBUG_DVC("tsmf_gstreamer_pipeline_build: WMV1"); - break; - case TSMF_SUB_TYPE_WMV2: - mdecoder->decbin = gst_element_factory_make ("ffdec_wmv2", NULL); - DEBUG_DVC("tsmf_gstreamer_pipeline_build: WMV2"); - break; - case TSMF_SUB_TYPE_WVC1: - case TSMF_SUB_TYPE_WMV3: - mdecoder->decbin = gst_element_factory_make ("fluvadec", NULL); - if (mdecoder->decbin) - { - hwaccelflu = TRUE; - } - else - { - if (OMXavailable) - { - mdecoder->decbin = gst_element_factory_make ("omx_vc1dec", NULL); - if (mdecoder->decbin) - hwaccelomx = TRUE; - } - else - mdecoder->decbin = NULL; - } + DEBUG_WARN("Failed to get appsrc"); + return FALSE; + } - if (!mdecoder->decbin) - mdecoder->decbin = gst_element_factory_make ("fluwmvdec", NULL); - if (!mdecoder->decbin) - mdecoder->decbin = gst_element_factory_make ("ffdec_wmv3", NULL); - DEBUG_DVC("tsmf_gstreamer_pipeline_build: WMV3"); - break; - case TSMF_SUB_TYPE_AVC1: - case TSMF_SUB_TYPE_H264: - mdecoder->decbin = gst_element_factory_make ("fluvadec", NULL); - if (mdecoder->decbin) - { - hwaccelflu = TRUE; - } - else - { - if (OMXavailable) - { - mdecoder->decbin = gst_element_factory_make ("omx_h264dec", NULL); - if (mdecoder->decbin) - hwaccelomx = TRUE; - } - else - mdecoder->decbin = NULL; - } - if (!mdecoder->decbin) - mdecoder->decbin = gst_element_factory_make ("fluh264dec", NULL); + mdecoder->outsink = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "outsink"); - if (!mdecoder->decbin) - mdecoder->decbin = gst_element_factory_make ("ffdec_h264", NULL); - DEBUG_DVC("tsmf_gstreamer_pipeline_build: H264"); - break; - case TSMF_SUB_TYPE_AC3: - mdecoder->decbin = gst_element_factory_make ("ffdec_ac3", NULL); - //mdecoder->decbin = gst_element_factory_make ("ffdec_ac3", NULL);//no fluendo equivalent? - DEBUG_DVC("tsmf_gstreamer_pipeline_build: AC3"); - break; - case TSMF_SUB_TYPE_AAC: - mdecoder->decbin = gst_element_factory_make ("fluaacdec", NULL); - if (!mdecoder->decbin) - mdecoder->decbin = gst_element_factory_make ("faad", NULL); - if (!mdecoder->decbin) - mdecoder->decbin = gst_element_factory_make ("ffdec_aac", NULL); - DEBUG_DVC("tsmf_gstreamer_pipeline_build: AAC"); - break; - case TSMF_SUB_TYPE_MP2A: - mdecoder->decbin = gst_element_factory_make ("fluaacdec", NULL); - if (!mdecoder->decbin) - mdecoder->decbin = gst_element_factory_make ("faad", NULL); - DEBUG_DVC("tsmf_gstreamer_pipeline_build: MP2A"); - break; - case TSMF_SUB_TYPE_MP1A: - mdecoder->decbin = gst_element_factory_make ("flump3dec", NULL); - DEBUG_DVC("tsmf_gstreamer_pipeline_build: MP1A"); - break; - case TSMF_SUB_TYPE_MP1V: - mdecoder->decbin = gst_element_factory_make ("ffdec_mpegvideo", NULL); - DEBUG_DVC("tsmf_gstreamer_pipeline_build: MP1V"); - break; - default: - DEBUG_WARN("tsmf_gstreamer_pipeline_build: Unsupported media type %d", mdecoder->tsmf_media_type.SubType); - return FALSE; - } - if (!mdecoder->decbin) + if (!mdecoder->outsink) { - DEBUG_WARN("tsmf_gstreamer_pipeline_build: Failed to load decoder plugin"); + DEBUG_WARN("Failed to get sink"); return FALSE; } - switch (mdecoder->media_type) + if (mdecoder->media_type != TSMF_MAJOR_TYPE_VIDEO) { - case TSMF_MAJOR_TYPE_VIDEO: - { - mdecoder->outbin = gst_bin_new ("videobin"); - if (hwaccelflu) - { - mdecoder->outconv = gst_element_factory_make ("queue", "queuetosink"); - mdecoder->outsink = gst_element_factory_make ("fluvasink", "videosink"); - } - else if(hwaccelomx) - { - mdecoder->outconv = gst_element_factory_make ("queue", "queuetosink"); - mdecoder->outsink = gst_element_factory_make ("gemxvimagesink", "videosink"); - } - else - { - mdecoder->outconv = gst_element_factory_make ("ffmpegcolorspace", "vconv"); - mdecoder->outsink = gst_element_factory_make ("xvimagesink", "videosink"); - } - DEBUG_DVC("tsmf_gstreamer_pipeline_build: building Video Pipe"); + mdecoder->volume = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "audiovolume"); - if (mdecoder->xfwin == (int *) -1) - DEBUG_WARN("tsmf_gstreamer_entry: failed to assign pointer to the memory address - shmat()"); - else - { - if (!mdecoder->disp) - mdecoder->disp = XOpenDisplay(NULL); - - if (!mdecoder->subwin) - { - mdecoder->subwin = XCreateSimpleWindow(mdecoder->disp, *mdecoder->xfwin, 0, 0, 1, 1, 0, 0, 0); - XMapWindow(mdecoder->disp, mdecoder->subwin); - XSync(mdecoder->disp, FALSE); - } - } - mdecoder->aVolume = 0; - break; - } - case TSMF_MAJOR_TYPE_AUDIO: + if (!mdecoder->volume) { - mdecoder->outbin = gst_bin_new ("audiobin"); - mdecoder->outconv = gst_element_factory_make ("audioconvert", "aconv"); - mdecoder->outsink = gst_element_factory_make ("alsasink", NULL); - mdecoder->aVolume = gst_element_factory_make ("volume", "AudioVol"); - if (mdecoder->aVolume) - { - g_object_set(mdecoder->aVolume, "mute", mdecoder->gstMuted, NULL); - g_object_set(mdecoder->aVolume, "volume", mdecoder->gstVolume, NULL); - } - DEBUG_DVC("tsmf_gstreamer_pipeline_build: building Audio Pipe"); - break; + DEBUG_WARN("Failed to get volume"); + return FALSE; } - default: - break; - } - if (!mdecoder->outconv) - { - DEBUG_WARN("tsmf_gstreamer_pipeline_build: Failed to load media converter"); - tsmf_gstreamer_clean_up(mdecoder); - return FALSE; - } - if (!mdecoder->outsink) - { - DEBUG_WARN("tsmf_gstreamer_pipeline_build: Failed to load xvimagesink plugin"); - tsmf_gstreamer_clean_up(mdecoder); - return FALSE; } - mdecoder->src = gst_element_factory_make ("appsrc", NULL); - mdecoder->queue = gst_element_factory_make ("queue2", NULL); - g_object_set(mdecoder->queue, "use-buffering", FALSE, NULL); - g_object_set(mdecoder->queue, "use-rate-estimate", FALSE, NULL); - g_object_set(mdecoder->outsink, "async", FALSE, NULL); + tsmf_platform_register_handler(mdecoder); + /* AppSrc settings */ + GstAppSrcCallbacks callbacks = + { + tsmf_gstreamer_need_data, + tsmf_gstreamer_enough_data, + tsmf_gstreamer_seek_data + }; g_object_set(mdecoder->src, "format", GST_FORMAT_TIME, NULL); - gst_app_src_set_stream_type((GstAppSrc *) mdecoder->src, GST_APP_STREAM_TYPE_STREAM); - gst_app_src_set_max_bytes((GstAppSrc *) mdecoder->src, 4*1024*1024); /* 32 Mbits */ + g_object_set(mdecoder->src, "is-live", TRUE, NULL); + g_object_set(mdecoder->src, "block", TRUE, NULL); gst_app_src_set_caps((GstAppSrc *) mdecoder->src, mdecoder->gst_caps); + gst_app_src_set_callbacks((GstAppSrc *)mdecoder->src, &callbacks, mdecoder, NULL); + gst_app_src_set_stream_type((GstAppSrc *) mdecoder->src, GST_APP_STREAM_TYPE_SEEKABLE); + tsmf_window_create(mdecoder); + tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_READY); + tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); + mdecoder->pipeline_start_time_valid = 0; + mdecoder->shutdown = 0; - out_pad = gst_element_get_static_pad(mdecoder->outconv, "sink"); - - gboolean linkResult = FALSE; - gst_bin_add(GST_BIN(mdecoder->outbin), mdecoder->outconv); - gst_bin_add(GST_BIN(mdecoder->outbin), mdecoder->outsink); - if (mdecoder->aVolume) - { - gst_bin_add(GST_BIN(mdecoder->outbin), mdecoder->aVolume); - linkResult = gst_element_link_many(mdecoder->outconv, mdecoder->aVolume, mdecoder->outsink, NULL); - } - else - { - linkResult = gst_element_link(mdecoder->outconv, mdecoder->outsink); - } - if (!linkResult) - { - DEBUG_WARN("tsmf_gstreamer_pipeline_build: Failed to link these elements: converter->sink"); - tsmf_gstreamer_clean_up(mdecoder); - return FALSE; - } - - gst_element_add_pad(mdecoder->outbin, gst_ghost_pad_new ("sink", out_pad)); - gst_object_unref(out_pad); - - gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->src); - gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->queue); - gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->decbin); - gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->outbin); - - linkResult = gst_element_link_many(mdecoder->src, mdecoder->queue, mdecoder->decbin, NULL); - if (!linkResult) - { - DEBUG_WARN("tsmf_gstreamer_pipeline_build: Failed to link these elements: source->decoder"); - tsmf_gstreamer_clean_up(mdecoder); - return FALSE; - } + GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(mdecoder->pipe), GST_DEBUG_GRAPH_SHOW_ALL, get_type(mdecoder)); - mdecoder->linked = gst_element_link(mdecoder->decbin, mdecoder->outbin); - if (!mdecoder->linked) - { - DEBUG_WARN("tsmf_gstreamer_pipeline_build: Failed to link these elements: decoder->output_bin"); - tsmf_gstreamer_clean_up(mdecoder); - return FALSE; - } - - if (GST_IS_X_OVERLAY (mdecoder->outsink)) - { - //gst_x_overlay_set_window_handle (GST_X_OVERLAY (mdecoder->outsink), *mdecoder->xfwin); - if(mdecoder->subwin) - { - //gdk_threads_enter(); - gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (mdecoder->outsink), mdecoder->subwin); - //gdk_threads_leave(); - } - } - - g_object_set(mdecoder->outsink, "preroll-queue-len", 10, NULL); return TRUE; } -static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder * decoder, const BYTE * data, UINT32 data_size, UINT32 extensions, - UINT64 start_time, UINT64 end_time, UINT64 duration) +static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions, + UINT64 start_time, UINT64 end_time, UINT64 duration) { - TSMFGstreamerDecoder * mdecoder = (TSMFGstreamerDecoder*) decoder; + GstBuffer *gst_buf; + 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); if (!mdecoder) { + DEBUG_WARN("Decoder not initialized!"); return FALSE; } - int mutexret = pthread_mutex_lock(&mdecoder->gst_mutex); - - if (mutexret != 0) - return FALSE; + /* + * This function is always called from a stream-specific thread. + * It should be alright to block here if necessary. + * We don't expect to block here often, since the pipeline should + * have more than enough buffering. + */ + DEBUG_TSMF("%s. Start:(%llu) End:(%llu) Duration:(%llu) Last End:(%llu)", + get_type(mdecoder), start_time, end_time, duration, + mdecoder->last_sample_end_time); - if (mdecoder->shutdown) + if (mdecoder->gst_caps == NULL) { - pthread_mutex_unlock(&mdecoder->gst_mutex); + DEBUG_WARN("tsmf_gstreamer_set_format not called or invalid format."); return FALSE; } - GstBuffer *gst_buf; - - /* - * This function is always called from a stream-specific thread. - * It should be alright to block here if necessary. - * We don't expect to block here often, since the pipeline should - * have more than enough buffering. - */ - - if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) - { - DEBUG_DVC("tsmf_gstreamer_decodeEx_VIDEO. Start:(%"PRIu64") End:(%"PRIu64") Duration:(%"PRIu64") Last End:(%"PRIu64")", - start_time, end_time, duration, mdecoder->last_sample_end_time); - } - else + if (!mdecoder->src) { - DEBUG_DVC("tsmf_gstreamer_decodeEx_AUDIO. Start:(%"PRIu64") End:(%"PRIu64") Duration:(%"PRIu64") Last End:(%"PRIu64")", - start_time, end_time, duration, mdecoder->last_sample_end_time); + DEBUG_WARN("failed to construct pipeline correctly. Unable to push buffer to source element."); + return FALSE; } - if (mdecoder->gst_caps == NULL) + gst_buf = tsmf_get_buffer_from_data(data, data_size); + + if (gst_buf == NULL) { - DEBUG_WARN("tsmf_gstreamer_decodeEx: tsmf_gstreamer_set_format not called or invalid format."); - pthread_mutex_unlock(&mdecoder->gst_mutex); + DEBUG_WARN("tsmf_get_buffer_from_data(%p, %d) failed.", data, data_size); return FALSE; } - if (mdecoder->pipe == NULL) + if (mdecoder->pipeline_start_time_valid) { - if (!tsmf_gstreamer_pipeline_build(mdecoder)) - { - if (mdecoder->pipe) - { - tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_NULL); - gst_object_unref(mdecoder->pipe); - mdecoder->pipe = NULL; - } - pthread_mutex_unlock(&mdecoder->gst_mutex); - return FALSE; - } + long long diff = start_time; + diff -= mdecoder->last_sample_end_time; - //tsmf_gstreamer_start_eventloop_thread(mdecoder); + if (diff < 0) + diff *= -1; - tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_READY); - mdecoder->pipeline_start_time_valid = 0; - } - else - { - /* - * this is to fix gstreamer's seeking forward/backward issue with live stream. - * set the seeking tolerance to 1 second. - */ - if (start_time > (mdecoder->last_sample_end_time + 10000000) || (end_time + 10000000) < mdecoder->last_sample_end_time) + /* The pipe is initialized, but there is a discontinuity. + * Seek to the start position... */ + if (diff > 50) { - DEBUG_DVC("tsmf_gstreamer_decodeEx: start_time=[%"PRIu64"] > last_sample_end_time=[%"PRIu64"]", start_time, mdecoder->last_sample_end_time); - DEBUG_DVC("tsmf_gstreamer_decodeEx: Stream seek detected - flushing element."); - tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_NULL); - gst_object_unref(mdecoder->pipe); - mdecoder->pipe = NULL; - if (!tsmf_gstreamer_pipeline_build(mdecoder)) - { - if (mdecoder->pipe) - { - tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_NULL); - gst_object_unref(mdecoder->pipe); - mdecoder->pipe = NULL; - } - pthread_mutex_unlock(&mdecoder->gst_mutex); - return FALSE; - } - tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_READY); - mdecoder->pipeline_start_time_valid = 0; - /* - * This is to fix the discrepancy between audio/video start time during a seek - */ - FILE *fout = NULL; - if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) - fout = fopen("/tmp/tsmf_vseek.info", "wt"); - else - fout = fopen("/tmp/tsmf_aseek.info", "wt"); - - if (fout) - { - fprintf(fout, "%"PRIu64"\n", (long unsigned int) start_time); - fclose(fout); - } + DEBUG_TSMF("%s seeking to %lld", get_type(mdecoder), start_time); - } - } - - if (!mdecoder->src) - { - pthread_mutex_unlock(&mdecoder->gst_mutex); - DEBUG_WARN("tsmf_gstreamer_decodeEx: failed to construct pipeline correctly. Unable to push buffer to source element."); - return FALSE; - } - - if (GST_STATE(mdecoder->pipe) != GST_STATE_PAUSED && GST_STATE(mdecoder->pipe) != GST_STATE_PLAYING) - { - tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PAUSED); - if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) - { - FILE *fout = fopen("/tmp/tsmf_video.ready", "wt"); - if (fout) - fclose(fout); - FILE *fin = fopen("/tmp/tsmf_aseek.info", "rt"); - if (fin) - { - UINT64 AStartTime = 0; - fscanf(fin, "%"PRIu64, (long unsigned int*) &AStartTime); - fclose(fin); - if (start_time > AStartTime) - { - UINT64 streamDelay = (start_time - AStartTime) / 10; - usleep(streamDelay); - } - unlink("/tmp/tsmf_aseek.info"); - } - } - else if (mdecoder->media_type == TSMF_MAJOR_TYPE_AUDIO) - { - int timeout = 0; - FILE *fin = fopen("/tmp/tsmf_video.ready", "rt"); - while (fin == NULL) - { - timeout++; - usleep(1000); - //wait up to 1.5 second - if (timeout >= 1500) - break; - fin = fopen("/tmp/tsmf_video.ready", "rt"); - } - if (fin) + if (!gst_element_seek(mdecoder->pipe, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, + GST_SEEK_TYPE_SET, sample_time, + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) { - fclose(fin); - unlink("/tmp/tsmf_video.ready"); - fin = NULL; + DEBUG_WARN("seek failed"); } - fin = fopen("/tmp/tsmf_vseek.info", "rt"); - if (fin) - { - UINT64 VStartTime = 0; - fscanf(fin, "%"PRIu64, (long unsigned int*) &VStartTime); - fclose(fin); - if (start_time > VStartTime) - { - UINT64 streamDelay = (start_time - VStartTime) / 10; - usleep(streamDelay); - } - unlink("/tmp/tsmf_vseek.info"); - } + mdecoder->pipeline_start_time_valid = 0; } } - - gst_buf = gst_buffer_try_new_and_alloc(data_size); - if (gst_buf == NULL) + else { - pthread_mutex_unlock(&mdecoder->gst_mutex); - DEBUG_WARN("tsmf_gstreamer_decodeEx: gst_buffer_try_new_and_alloc(%d) failed.", data_size); - return FALSE; + DEBUG_TSMF("%s start time %llu", get_type(mdecoder), sample_time); + mdecoder->pipeline_start_time_valid = 1; } - gst_buffer_set_caps(gst_buf, mdecoder->gst_caps); - memcpy(GST_BUFFER_MALLOCDATA(gst_buf), data, data_size); - GST_BUFFER_TIMESTAMP(gst_buf) = tsmf_gstreamer_timestamp_ms_to_gst(start_time); - GST_BUFFER_DURATION(gst_buf) = tsmf_gstreamer_timestamp_ms_to_gst(duration); +#if GST_VERSION_MAJOR > 0 + GST_BUFFER_PTS(gst_buf) = sample_time; +#else + GST_BUFFER_TIMESTAMP(gst_buf) = sample_time; +#endif + GST_BUFFER_DURATION(gst_buf) = sample_duration; gst_app_src_push_buffer(GST_APP_SRC(mdecoder->src), gst_buf); + if (mdecoder->ack_cb) + mdecoder->ack_cb(mdecoder->stream, TRUE); + mdecoder->last_sample_end_time = end_time; - - if (!mdecoder->pipeline_start_time_valid) - { - gst_element_set_base_time(mdecoder->pipe, tsmf_gstreamer_timestamp_ms_to_gst(start_time)); - gst_element_set_start_time(mdecoder->pipe, tsmf_gstreamer_timestamp_ms_to_gst(start_time)); - mdecoder->pipeline_start_time_valid = 1; - } - if(GST_STATE(mdecoder->pipe) != GST_STATE_PLAYING) + if (GST_STATE(mdecoder->pipe) != GST_STATE_PLAYING) { - if (!mdecoder->paused) - { - if (mdecoder->subwin) - { - XMapWindow(mdecoder->disp, mdecoder->subwin); - XSync(mdecoder->disp, FALSE); - } + DEBUG_TSMF("%s: state=%s", get_type(mdecoder), gst_element_state_get_name(GST_STATE(mdecoder->pipe))); + + if (!mdecoder->paused && !mdecoder->shutdown && mdecoder->ready) tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); - } } - pthread_mutex_unlock(&mdecoder->gst_mutex); + 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; - if (!mdecoder) - return; + TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; - if (mdecoder->shutdown) + if (!mdecoder || !mdecoder->pipe) return; if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) return; mdecoder->gstMuted = (BOOL) muted; - DEBUG_DVC("tsmf_gstreamer_change_volume: mute=[%d]", mdecoder->gstMuted); + DEBUG_TSMF("mute=[%d]", mdecoder->gstMuted); mdecoder->gstVolume = (double) newVolume / (double) 10000; - DEBUG_DVC("tsmf_gstreamer_change_volume: gst_new_vol=[%f]", mdecoder->gstVolume); + DEBUG_TSMF("gst_new_vol=[%f]", mdecoder->gstVolume); - if (!mdecoder->aVolume) + if (!mdecoder->volume) return; - if (!G_IS_OBJECT(mdecoder->aVolume)) + if (!G_IS_OBJECT(mdecoder->volume)) return; - g_object_set(mdecoder->aVolume, "mute", mdecoder->gstMuted, NULL); - g_object_set(mdecoder->aVolume, "volume", mdecoder->gstVolume, NULL); + g_object_set(mdecoder->volume, "mute", mdecoder->gstMuted, NULL); + 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; - if (control_msg == Control_Pause) + if (control_msg == Control_Pause) { - DEBUG_DVC("tsmf_gstreamer_control: Control_Pause"); - tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PAUSED); - mdecoder->paused = TRUE; + DEBUG_TSMF("Control_Pause %s", get_type(mdecoder)); - if (mdecoder->subwin) + if (mdecoder->paused) { - XUnmapWindow(mdecoder->disp, mdecoder->subwin); - XSync(mdecoder->disp, FALSE); + DEBUG_WARN("%s: Ignoring control PAUSE, already received!", get_type(mdecoder)); + return; } + + tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PAUSED); + mdecoder->paused = TRUE; + + if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + tsmf_window_pause(mdecoder); } - else if (control_msg == Control_Restart) + else if (control_msg == Control_Resume) { - DEBUG_DVC("tsmf_gstreamer_control: Control_Restart"); - mdecoder->paused = FALSE; - if (mdecoder->subwin) + DEBUG_TSMF("Control_Resume %s", get_type(mdecoder)); + + if (!mdecoder->paused && !mdecoder->shutdown) { - XMapWindow(mdecoder->disp, mdecoder->subwin); - XSync(mdecoder->disp, FALSE); + DEBUG_WARN("%s: Ignoring control RESUME, already received!", get_type(mdecoder)); + return; } - if (mdecoder->pipeline_start_time_valid) - tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); + + mdecoder->paused = FALSE; + mdecoder->shutdown = FALSE; + + if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + tsmf_window_resume(mdecoder); + + tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); } - else if (control_msg == Control_Flush) + else if (control_msg == Control_Stop) { - DEBUG_DVC("tsmf_gstreamer_control: Control_Flush"); - /* Reset stamps, flush buffers, etc */ - if (mdecoder->pipe) - { - tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_NULL); - gst_object_unref(mdecoder->pipe); - mdecoder->pipe = NULL; - } - mdecoder->pipeline_start_time_valid = 0; - mdecoder->paused = FALSE; - - if (mdecoder->subwin) + DEBUG_TSMF("Control_Stop %s", get_type(mdecoder)); + + if (mdecoder->shutdown) { - XUnmapWindow(mdecoder->disp, mdecoder->subwin); - XSync(mdecoder->disp, FALSE); + DEBUG_WARN("%s: Ignoring control STOP, already received!", get_type(mdecoder)); + return; } + + mdecoder->shutdown = TRUE; + /* Reset stamps, flush buffers, etc */ + tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PAUSED); + + if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + tsmf_window_pause(mdecoder); + + gst_app_src_end_of_stream((GstAppSrc *)mdecoder->src); } - else if (control_msg == Control_EndOfStream) - { - mdecoder->paused = FALSE; - DEBUG_DVC("tsmf_gstreamer_control: Control_EndOfStream"); - /* - * The EOS may take some time to flow through the pipeline - * If the server sees the client "End of Stream Processed" - * notification too soon, it may shut down the stream - * and clip the end of files. - * If that's the case, then we'll need to change the TSMF layer - * to send the "End of Stream Processed" only after the stream - * is truly EOS. - * (It's unlikely we can simply "wait" here for it to happen - * since we don't want to hold up acks, etc.) - */ - tsmf_gstreamer_pipeline_send_end_of_stream(mdecoder); - } + else + DEBUG_WARN("Unknown control message %08x", control_msg); } -static guint tsmf_gstreamer_buffer_level(ITSMFDecoder * decoder) +static BOOL tsmf_gstreamer_buffer_filled(ITSMFDecoder *decoder) { - TSMFGstreamerDecoder * mdecoder = (TSMFGstreamerDecoder *) decoder; - DEBUG_DVC("tsmf_gstreamer_buffer_level\n"); + TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + DEBUG_TSMF(""); if (!mdecoder) - return 0; - - if (mdecoder->shutdown) - return 0; - - if (!G_IS_OBJECT(mdecoder->queue)) - return 0; + return FALSE; + guint buff_max = 0; guint clbuff = 0; - g_object_get(mdecoder->queue, "current-level-buffers", &clbuff, NULL); - return clbuff; + DEBUG_TSMF("%s buffer fill %u/%u", get_type(mdecoder), clbuff, buff_max); + return clbuff >= buff_max ? TRUE : FALSE; } -static void tsmf_gstreamer_free(ITSMFDecoder * decoder) +static void tsmf_gstreamer_free(ITSMFDecoder *decoder) { - TSMFGstreamerDecoder * mdecoder = (TSMFGstreamerDecoder *) decoder; - DEBUG_DVC("tsmf_gstreamer_free\n"); + TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + DEBUG_TSMF("%s", get_type(mdecoder)); if (mdecoder) { - pthread_mutex_lock(&mdecoder->gst_mutex); mdecoder->shutdown = 1; - if (mdecoder->pipe) - { - tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_NULL); - gst_object_unref(mdecoder->pipe); - mdecoder->pipe = NULL; - } - tsmf_gstreamer_stop_eventloop_thread(mdecoder); + tsmf_gstreamer_clean_up(mdecoder); + if (mdecoder->gst_caps) gst_caps_unref(mdecoder->gst_caps); - if (mdecoder->subwin) - { - DEBUG_DVC("destroy subwindow\n"); - XDestroyWindow(mdecoder->disp, mdecoder->subwin); - XSync(mdecoder->disp, FALSE); - } - - if (mdecoder->disp) - XCloseDisplay(mdecoder->disp); - - unlink("/tmp/tsmf_aseek.info"); - unlink("/tmp/tsmf_vseek.info"); - unlink("/tmp/tsmf_video.ready"); - - pthread_mutex_unlock(&mdecoder->gst_mutex); + tsmf_platform_free(mdecoder); + memset(mdecoder, 0, sizeof(TSMFGstreamerDecoder)); free(mdecoder); - mdecoder = 0; + mdecoder = NULL; } } -static UINT64 tsmf_gstreamer_get_running_time(ITSMFDecoder * decoder) +static UINT64 tsmf_gstreamer_get_running_time(ITSMFDecoder *decoder) { TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + if (!mdecoder) return 0; + if (!mdecoder->outsink) return mdecoder->last_sample_end_time; - if(GST_STATE(mdecoder->pipe) != GST_STATE_PLAYING) + if (GST_STATE(mdecoder->pipe) != GST_STATE_PLAYING) return 0; GstFormat fmt = GST_FORMAT_TIME; gint64 pos = 0; - gst_element_query_position (mdecoder->outsink, &fmt, &pos); - DEBUG_DVC("tsmf_gstreamer_current_pos=[%"PRIu64"]", pos); +#if GST_VERSION_MAJOR > 0 + gst_element_query_position(mdecoder->outsink, fmt, &pos); +#else + gst_element_query_position(mdecoder->outsink, &fmt, &pos); +#endif return pos/100; } -static void tsmf_gstreamer_update_rendering_area(ITSMFDecoder * decoder, int newX, int newY, int newWidth, int newHeight, int numRectangles, RDP_RECT *rectangles) +static void tsmf_gstreamer_update_rendering_area(ITSMFDecoder *decoder, + int newX, int newY, int newWidth, int newHeight, int numRectangles, + RDP_RECT *rectangles) { - DEBUG_DVC("tsmf_gstreamer_update_rendering_area"); TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; - if (!mdecoder) - return; - - if (mdecoder->shutdown) - return; - - if (GST_IS_X_OVERLAY (mdecoder->outsink)) - { - if (!mdecoder->disp) - mdecoder->disp = XOpenDisplay(NULL); + DEBUG_TSMF("x=%d, y=%d, w=%d, h=%d, rect=%d", newX, newY, newWidth, + newHeight, numRectangles); - //multi-mon test - int anewX = newX; - int anewY = newY; - if (!mdecoder->offsetObtained) - { - XSync(mdecoder->disp, FALSE); - RROutput primary_output; - XRRScreenResources *res = 0; - int screen = 0; - res = XRRGetScreenResourcesCurrent(mdecoder->disp, RootWindow(mdecoder->disp, screen)); - if (res) - { - DEBUG_DVC("number of output:%d", res->ncrtc); - primary_output = XRRGetOutputPrimary(mdecoder->disp, DefaultRootWindow(mdecoder->disp)); - DEBUG_DVC("primary_output:%d", (int)primary_output); - int i = 0; - for (i = 0; i < res->ncrtc; i++) - { - XRRCrtcInfo *info = XRRGetCrtcInfo(mdecoder->disp, res, res->crtcs[i]); - if (info) - { - if (info->noutput > 0) - { - if (info->outputs[0] == primary_output || i == 0) - { - mdecoder->xOffset = info->x; - mdecoder->yOffset = info->y; - } - DEBUG_DVC("output %d ID: %lu (x,y): (%d,%d) (w,h): (%d,%d) primary: %d", i, info->outputs[0], info->x, info->y, info->width, info->height, (info->outputs[0] == primary_output)); - } - XRRFreeCrtcInfo(info); - } - } - } - mdecoder->offsetObtained = TRUE; - } - anewX += mdecoder->xOffset; - anewY += mdecoder->yOffset; - - XSync(mdecoder->disp, FALSE); - //end of multi-mon test - - if(mdecoder->subwin) - { - XMoveWindow(mdecoder->disp, mdecoder->subwin, anewX, anewY); - if(newWidth > 0 && newHeight > 0) { - XResizeWindow(mdecoder->disp, mdecoder->subwin, newWidth, newHeight); - } else { - XResizeWindow(mdecoder->disp, mdecoder->subwin, 1, 1); - } + if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + tsmf_window_resize(mdecoder, newX, newY, newWidth, newHeight, + numRectangles, rectangles); +} - XSync(mdecoder->disp, FALSE); - XShapeCombineRectangles (mdecoder->disp, mdecoder->subwin, ShapeBounding, 0, 0,(XRectangle*) rectangles, numRectangles, ShapeSet, Unsorted); - XSync(mdecoder->disp, FALSE); - //Sending Expose Event so freeRDP can do a redraw. - XExposeEvent xpose; - xpose.type = Expose; - xpose.display = mdecoder->disp; - xpose.window = *mdecoder->xfwin; - xpose.x = 0; - xpose.y = 0; - XSendEvent(mdecoder->disp, *mdecoder->xfwin, TRUE, ExposureMask, (XEvent *)&xpose); - XSync(mdecoder->disp, FALSE); - } - gst_x_overlay_expose (GST_X_OVERLAY (mdecoder->outsink)); - } +BOOL tsmf_gstreamer_ack(ITSMFDecoder *decoder, BOOL (*cb)(void *, BOOL), void *stream) +{ + TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + DEBUG_TSMF(""); + mdecoder->ack_cb = cb; + mdecoder->stream = stream; + return TRUE; } -static int initialized = 0; +BOOL tsmf_gstreamer_sync(ITSMFDecoder *decoder, void (*cb)(void *), void *stream) +{ + TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + DEBUG_TSMF(""); + mdecoder->sync_cb = NULL; + mdecoder->stream = stream; + return TRUE; +} #ifdef STATIC_CHANNELS #define freerdp_tsmf_client_decoder_subsystem_entry gstreamer_freerdp_tsmf_client_decoder_subsystem_entry #endif -ITSMFDecoder* freerdp_tsmf_client_decoder_subsystem_entry(void) +ITSMFDecoder *freerdp_tsmf_client_decoder_subsystem_entry(void) { - TSMFGstreamerDecoder* decoder; + TSMFGstreamerDecoder *decoder; - if (!initialized) + if (!gst_is_initialized()) { - gst_init(0, 0); - initialized = 1; + gst_init(NULL, NULL); } decoder = malloc(sizeof(TSMFGstreamerDecoder)); memset(decoder, 0, sizeof(TSMFGstreamerDecoder)); - decoder->iface.SetFormat = tsmf_gstreamer_set_format; decoder->iface.Decode = NULL; decoder->iface.GetDecodedData = NULL; @@ -1599,28 +773,13 @@ ITSMFDecoder* freerdp_tsmf_client_decoder_subsystem_entry(void) decoder->iface.Control = tsmf_gstreamer_control; decoder->iface.DecodeEx = tsmf_gstreamer_decodeEx; decoder->iface.ChangeVolume = tsmf_gstreamer_change_volume; - decoder->iface.BufferLevel = tsmf_gstreamer_buffer_level; + decoder->iface.BufferFilled = tsmf_gstreamer_buffer_filled; + decoder->iface.SetAckFunc = tsmf_gstreamer_ack; + decoder->iface.SetSyncFunc = tsmf_gstreamer_sync; decoder->paused = FALSE; - decoder->subwin = 0; - decoder->xOffset = 0; - decoder->yOffset = 0; - decoder->offsetObtained = FALSE; decoder->gstVolume = 0.5; decoder->gstMuted = FALSE; decoder->state = GST_STATE_VOID_PENDING; /* No real state yet */ - pthread_mutex_init(&decoder->gst_mutex, NULL); - - int shmid = shmget(SHARED_MEM_KEY, sizeof(int), 0666); - if (shmid < 0) - { - DEBUG_WARN("tsmf_gstreamer_entry: failed to get access to shared memory - shmget()"); - } - else - { - decoder->xfwin = shmat(shmid, NULL, 0); - } - - XInitThreads(); - + tsmf_platform_create(decoder); return (ITSMFDecoder *) decoder; } diff --git a/channels/tsmf/client/gstreamer/tsmf_platform.h b/channels/tsmf/client/gstreamer/tsmf_platform.h new file mode 100644 index 000000000000..32484236ef2f --- /dev/null +++ b/channels/tsmf/client/gstreamer/tsmf_platform.h @@ -0,0 +1,83 @@ +/* + * FreeRDP: A Remote Desktop Protocol Implementation + * Video Redirection Virtual Channel - GStreamer Decoder + * platform specific functions + * + * (C) Copyright 2014 Thincast Technologies GmbH + * (C) Copyright 2014 Armin Novak + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#ifndef _TSMF_PLATFORM_H_ +#define _TSMF_PLATFORM_H_ + +#include +#include + +typedef struct _TSMFGstreamerDecoder +{ + ITSMFDecoder iface; + + int media_type; /* TSMF_MAJOR_TYPE_AUDIO or TSMF_MAJOR_TYPE_VIDEO */ + + gint64 duration; + + GstState state; + GstCaps *gst_caps; + + GstElement *pipe; + GstElement *src; + GstElement *outsink; + GstElement *volume; + + BOOL ready; + BOOL paused; + UINT64 last_sample_end_time; + + double gstVolume; + BOOL gstMuted; + + int pipeline_start_time_valid; /* We've set the start time and have not reset the pipeline */ + int shutdown; /* The decoder stream is shutting down */ + + void *platform; + + BOOL (*ack_cb)(void *,BOOL); + void (*sync_cb)(void *); + void *stream; + +} TSMFGstreamerDecoder; + +const char *get_type(TSMFGstreamerDecoder *mdecoder); + +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_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_pause(TSMFGstreamerDecoder *decoder); +int tsmf_window_resume(TSMFGstreamerDecoder *decoder); + +BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder *mdecoder); +void tsmf_gstreamer_remove_pad(TSMFGstreamerDecoder *mdecoder); + +#endif diff --git a/channels/tsmf/client/pulse/tsmf_pulse.c b/channels/tsmf/client/pulse/tsmf_pulse.c index 4524809d45d6..8b476eb23eb6 100644 --- a/channels/tsmf/client/pulse/tsmf_pulse.c +++ b/channels/tsmf/client/pulse/tsmf_pulse.c @@ -37,75 +37,70 @@ typedef struct _TSMFPulseAudioDevice ITSMFAudioDevice iface; char device[32]; - pa_threaded_mainloop* mainloop; - pa_context* context; + pa_threaded_mainloop *mainloop; + pa_context *context; pa_sample_spec sample_spec; - pa_stream* stream; + pa_stream *stream; } TSMFPulseAudioDevice; -static void tsmf_pulse_context_state_callback(pa_context* context, void* userdata) +static void tsmf_pulse_context_state_callback(pa_context *context, void *userdata) { - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata; + TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata; pa_context_state_t state; - state = pa_context_get_state(context); - switch (state) + switch(state) { case PA_CONTEXT_READY: - DEBUG_DVC("PA_CONTEXT_READY"); + DEBUG_TSMF("PA_CONTEXT_READY"); pa_threaded_mainloop_signal(pulse->mainloop, 0); break; - case PA_CONTEXT_FAILED: case PA_CONTEXT_TERMINATED: - DEBUG_DVC("state %d", (int)state); + DEBUG_TSMF("state %d", (int)state); pa_threaded_mainloop_signal(pulse->mainloop, 0); break; - default: - DEBUG_DVC("state %d", (int)state); + DEBUG_TSMF("state %d", (int)state); break; } } -static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice* pulse) +static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice *pulse) { pa_context_state_t state; - - if (!pulse->context) + if(!pulse->context) return FALSE; - - if (pa_context_connect(pulse->context, NULL, 0, NULL)) + if(pa_context_connect(pulse->context, NULL, 0, NULL)) { DEBUG_WARN("pa_context_connect failed (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); return FALSE; } pa_threaded_mainloop_lock(pulse->mainloop); - if (pa_threaded_mainloop_start(pulse->mainloop) < 0) + if(pa_threaded_mainloop_start(pulse->mainloop) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); DEBUG_WARN("pa_threaded_mainloop_start failed (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); return FALSE; } - for (;;) + for(;;) { state = pa_context_get_state(pulse->context); - if (state == PA_CONTEXT_READY) + if(state == PA_CONTEXT_READY) break; - if (!PA_CONTEXT_IS_GOOD(state)) + if(!PA_CONTEXT_IS_GOOD(state)) { - DEBUG_DVC("bad context state (%d)", - pa_context_errno(pulse->context)); + DEBUG_TSMF("bad context state (%d)", + pa_context_errno(pulse->context)); break; } pa_threaded_mainloop_wait(pulse->mainloop); } pa_threaded_mainloop_unlock(pulse->mainloop); - if (state == PA_CONTEXT_READY) + if(state == PA_CONTEXT_READY) { - DEBUG_DVC("connected"); + DEBUG_TSMF("connected"); return TRUE; } else @@ -115,166 +110,150 @@ static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice* pulse) } } -static BOOL tsmf_pulse_open(ITSMFAudioDevice* audio, const char* device) +static BOOL tsmf_pulse_open(ITSMFAudioDevice *audio, const char *device) { - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; - - if (device) + TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; + if(device) { strcpy(pulse->device, device); } - pulse->mainloop = pa_threaded_mainloop_new(); - if (!pulse->mainloop) + if(!pulse->mainloop) { DEBUG_WARN("pa_threaded_mainloop_new failed"); return FALSE; } pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), "freerdp"); - if (!pulse->context) + if(!pulse->context) { DEBUG_WARN("pa_context_new failed"); return FALSE; } pa_context_set_state_callback(pulse->context, tsmf_pulse_context_state_callback, pulse); - if (tsmf_pulse_connect(pulse)) + if(tsmf_pulse_connect(pulse)) { DEBUG_WARN("tsmf_pulse_connect failed"); return FALSE; } - - DEBUG_DVC("open device %s", pulse->device); + DEBUG_TSMF("open device %s", pulse->device); return TRUE; } -static void tsmf_pulse_stream_success_callback(pa_stream* stream, int success, void* userdata) +static void tsmf_pulse_stream_success_callback(pa_stream *stream, int success, void *userdata) { - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata; - + TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata; pa_threaded_mainloop_signal(pulse->mainloop, 0); } -static void tsmf_pulse_wait_for_operation(TSMFPulseAudioDevice* pulse, pa_operation* operation) +static void tsmf_pulse_wait_for_operation(TSMFPulseAudioDevice *pulse, pa_operation *operation) { - if (operation == NULL) + if(operation == NULL) return; - while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) + while(pa_operation_get_state(operation) == PA_OPERATION_RUNNING) { pa_threaded_mainloop_wait(pulse->mainloop); } pa_operation_unref(operation); } -static void tsmf_pulse_stream_state_callback(pa_stream* stream, void* userdata) +static void tsmf_pulse_stream_state_callback(pa_stream *stream, void *userdata) { - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata; + TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata; pa_stream_state_t state; - state = pa_stream_get_state(stream); - switch (state) + switch(state) { case PA_STREAM_READY: - DEBUG_DVC("PA_STREAM_READY"); - pa_threaded_mainloop_signal (pulse->mainloop, 0); + DEBUG_TSMF("PA_STREAM_READY"); + pa_threaded_mainloop_signal(pulse->mainloop, 0); break; - case PA_STREAM_FAILED: case PA_STREAM_TERMINATED: - DEBUG_DVC("state %d", (int)state); - pa_threaded_mainloop_signal (pulse->mainloop, 0); + DEBUG_TSMF("state %d", (int)state); + pa_threaded_mainloop_signal(pulse->mainloop, 0); break; - default: - DEBUG_DVC("state %d", (int)state); + DEBUG_TSMF("state %d", (int)state); break; } } -static void tsmf_pulse_stream_request_callback(pa_stream* stream, size_t length, void* userdata) +static void tsmf_pulse_stream_request_callback(pa_stream *stream, size_t length, void *userdata) { - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata; - - DEBUG_DVC("%d", (int) length); - + TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata; + DEBUG_TSMF("%d", (int) length); pa_threaded_mainloop_signal(pulse->mainloop, 0); } -static BOOL tsmf_pulse_close_stream(TSMFPulseAudioDevice* pulse) +static BOOL tsmf_pulse_close_stream(TSMFPulseAudioDevice *pulse) { - if (!pulse->context || !pulse->stream) + if(!pulse->context || !pulse->stream) return FALSE; - - DEBUG_DVC(""); - + DEBUG_TSMF(""); pa_threaded_mainloop_lock(pulse->mainloop); pa_stream_set_write_callback(pulse->stream, NULL, NULL); tsmf_pulse_wait_for_operation(pulse, - pa_stream_drain(pulse->stream, tsmf_pulse_stream_success_callback, pulse)); + pa_stream_drain(pulse->stream, tsmf_pulse_stream_success_callback, pulse)); pa_stream_disconnect(pulse->stream); pa_stream_unref(pulse->stream); pulse->stream = NULL; pa_threaded_mainloop_unlock(pulse->mainloop); - return TRUE; } -static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice* pulse) +static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice *pulse) { pa_stream_state_t state; pa_buffer_attr buffer_attr = { 0 }; - - if (!pulse->context) + if(!pulse->context) return FALSE; - - DEBUG_DVC(""); - + DEBUG_TSMF(""); pa_threaded_mainloop_lock(pulse->mainloop); pulse->stream = pa_stream_new(pulse->context, "freerdp", - &pulse->sample_spec, NULL); - if (!pulse->stream) + &pulse->sample_spec, NULL); + if(!pulse->stream) { pa_threaded_mainloop_unlock(pulse->mainloop); DEBUG_WARN("pa_stream_new failed (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); return FALSE; } pa_stream_set_state_callback(pulse->stream, - tsmf_pulse_stream_state_callback, pulse); + tsmf_pulse_stream_state_callback, pulse); pa_stream_set_write_callback(pulse->stream, - tsmf_pulse_stream_request_callback, pulse); + tsmf_pulse_stream_request_callback, pulse); buffer_attr.maxlength = pa_usec_to_bytes(500000, &pulse->sample_spec); buffer_attr.tlength = pa_usec_to_bytes(250000, &pulse->sample_spec); buffer_attr.prebuf = (UINT32) -1; buffer_attr.minreq = (UINT32) -1; buffer_attr.fragsize = (UINT32) -1; - if (pa_stream_connect_playback(pulse->stream, - pulse->device[0] ? pulse->device : NULL, &buffer_attr, - PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE, - NULL, NULL) < 0) + if(pa_stream_connect_playback(pulse->stream, + pulse->device[0] ? pulse->device : NULL, &buffer_attr, + PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE, + NULL, NULL) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); DEBUG_WARN("pa_stream_connect_playback failed (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); return FALSE; } - - for (;;) + for(;;) { state = pa_stream_get_state(pulse->stream); - if (state == PA_STREAM_READY) + if(state == PA_STREAM_READY) break; - if (!PA_STREAM_IS_GOOD(state)) + if(!PA_STREAM_IS_GOOD(state)) { DEBUG_WARN("bad stream state (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); break; } pa_threaded_mainloop_wait(pulse->mainloop); } pa_threaded_mainloop_unlock(pulse->mainloop); - if (state == PA_STREAM_READY) + if(state == PA_STREAM_READY) { - DEBUG_DVC("connected"); + DEBUG_TSMF("connected"); return TRUE; } else @@ -284,105 +263,93 @@ static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice* pulse) } } -static BOOL tsmf_pulse_set_format(ITSMFAudioDevice* audio, - UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample) +static BOOL tsmf_pulse_set_format(ITSMFAudioDevice *audio, + UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample) { - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; - - DEBUG_DVC("sample_rate %d channels %d bits_per_sample %d", - sample_rate, channels, bits_per_sample); - + TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; + DEBUG_TSMF("sample_rate %d channels %d bits_per_sample %d", + sample_rate, channels, bits_per_sample); pulse->sample_spec.rate = sample_rate; pulse->sample_spec.channels = channels; pulse->sample_spec.format = PA_SAMPLE_S16LE; - return tsmf_pulse_open_stream(pulse); } -static BOOL tsmf_pulse_play(ITSMFAudioDevice* audio, BYTE* data, UINT32 data_size) +static BOOL tsmf_pulse_play(ITSMFAudioDevice *audio, BYTE *data, UINT32 data_size) { - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; - BYTE* src; + TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; + BYTE *src; int len; int ret; - - DEBUG_DVC("data_size %d", data_size); - - if (pulse->stream) + DEBUG_TSMF("data_size %d", data_size); + if(pulse->stream) { pa_threaded_mainloop_lock(pulse->mainloop); - src = data; - while (data_size > 0) + while(data_size > 0) { - while ((len = pa_stream_writable_size(pulse->stream)) == 0) + while((len = pa_stream_writable_size(pulse->stream)) == 0) { - DEBUG_DVC("waiting"); + DEBUG_TSMF("waiting"); pa_threaded_mainloop_wait(pulse->mainloop); } - if (len < 0) + if(len < 0) break; - if (len > data_size) + if(len > data_size) len = data_size; ret = pa_stream_write(pulse->stream, src, len, NULL, 0LL, PA_SEEK_RELATIVE); - if (ret < 0) + if(ret < 0) { - DEBUG_DVC("pa_stream_write failed (%d)", - pa_context_errno(pulse->context)); + DEBUG_TSMF("pa_stream_write failed (%d)", + pa_context_errno(pulse->context)); break; } src += len; data_size -= len; } - pa_threaded_mainloop_unlock(pulse->mainloop); } free(data); - return TRUE; } -static UINT64 tsmf_pulse_get_latency(ITSMFAudioDevice* audio) +static UINT64 tsmf_pulse_get_latency(ITSMFAudioDevice *audio) { pa_usec_t usec; UINT64 latency = 0; - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; - - if (pulse->stream && pa_stream_get_latency(pulse->stream, &usec, NULL) == 0) + TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; + if(pulse->stream && pa_stream_get_latency(pulse->stream, &usec, NULL) == 0) { latency = ((UINT64)usec) * 10LL; } return latency; } -static void tsmf_pulse_flush(ITSMFAudioDevice* audio) +static void tsmf_pulse_flush(ITSMFAudioDevice *audio) { - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; - + TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; pa_threaded_mainloop_lock(pulse->mainloop); tsmf_pulse_wait_for_operation(pulse, - pa_stream_flush(pulse->stream, tsmf_pulse_stream_success_callback, pulse)); + pa_stream_flush(pulse->stream, tsmf_pulse_stream_success_callback, pulse)); pa_threaded_mainloop_unlock(pulse->mainloop); } -static void tsmf_pulse_free(ITSMFAudioDevice* audio) +static void tsmf_pulse_free(ITSMFAudioDevice *audio) { - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; - - DEBUG_DVC(""); - + TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; + DEBUG_TSMF(""); tsmf_pulse_close_stream(pulse); - if (pulse->mainloop) + if(pulse->mainloop) { pa_threaded_mainloop_stop(pulse->mainloop); } - if (pulse->context) + if(pulse->context) { pa_context_disconnect(pulse->context); pa_context_unref(pulse->context); pulse->context = NULL; } - if (pulse->mainloop) + if(pulse->mainloop) { pa_threaded_mainloop_free(pulse->mainloop); pulse->mainloop = NULL; @@ -394,20 +361,17 @@ static void tsmf_pulse_free(ITSMFAudioDevice* audio) #define freerdp_tsmf_client_audio_subsystem_entry pulse_freerdp_tsmf_client_audio_subsystem_entry #endif -ITSMFAudioDevice* freerdp_tsmf_client_audio_subsystem_entry(void) +ITSMFAudioDevice *freerdp_tsmf_client_audio_subsystem_entry(void) { - TSMFPulseAudioDevice* pulse; - - pulse = (TSMFPulseAudioDevice*) malloc(sizeof(TSMFPulseAudioDevice)); + TSMFPulseAudioDevice *pulse; + pulse = (TSMFPulseAudioDevice *) malloc(sizeof(TSMFPulseAudioDevice)); ZeroMemory(pulse, sizeof(TSMFPulseAudioDevice)); - pulse->iface.Open = tsmf_pulse_open; pulse->iface.SetFormat = tsmf_pulse_set_format; pulse->iface.Play = tsmf_pulse_play; pulse->iface.GetLatency = tsmf_pulse_get_latency; pulse->iface.Flush = tsmf_pulse_flush; pulse->iface.Free = tsmf_pulse_free; - - return (ITSMFAudioDevice*) pulse; + return (ITSMFAudioDevice *) pulse; } diff --git a/channels/tsmf/client/tsmf_codec.c b/channels/tsmf/client/tsmf_codec.c index 2b0af5031a66..5fac84991f8a 100644 --- a/channels/tsmf/client/tsmf_codec.c +++ b/channels/tsmf/client/tsmf_codec.c @@ -37,7 +37,7 @@ typedef struct _TSMFMediaTypeMap { BYTE guid[16]; - const char* name; + const char *name; int type; } TSMFMediaTypeMap; @@ -259,24 +259,23 @@ static const TSMFMediaTypeMap tsmf_format_type_map[] = } }; -static void tsmf_print_guid(const BYTE* guid) +static void tsmf_print_guid(const BYTE *guid) { -#ifdef WITH_DEBUG_DVC +#ifdef WITH_DEBUG_TSMF int i; - - for (i = 3; i >= 0; i--) + for(i = 3; i >= 0; i--) fprintf(stderr, "%02X", guid[i]); fprintf(stderr, "-"); - for (i = 5; i >= 4; i--) + for(i = 5; i >= 4; i--) fprintf(stderr, "%02X", guid[i]); fprintf(stderr, "-"); - for (i = 7; i >= 6; i--) + for(i = 7; i >= 6; i--) fprintf(stderr, "%02X", guid[i]); fprintf(stderr, "-"); - for (i = 8; i < 16; i++) + for(i = 8; i < 16; i++) { fprintf(stderr, "%02X", guid[i]); - if (i == 9) + if(i == 9) fprintf(stderr, "-"); } fprintf(stderr, "\n"); @@ -284,34 +283,29 @@ static void tsmf_print_guid(const BYTE* guid) } /* http://msdn.microsoft.com/en-us/library/dd318229.aspx */ -static UINT32 tsmf_codec_parse_BITMAPINFOHEADER(TS_AM_MEDIA_TYPE* mediatype, wStream* s, BOOL bypass) +static UINT32 tsmf_codec_parse_BITMAPINFOHEADER(TS_AM_MEDIA_TYPE *mediatype, wStream *s, BOOL bypass) { UINT32 biSize; UINT32 biWidth; UINT32 biHeight; - Stream_Read_UINT32(s, biSize); Stream_Read_UINT32(s, biWidth); Stream_Read_UINT32(s, biHeight); Stream_Seek(s, 28); - - if (mediatype->Width == 0) + if(mediatype->Width == 0) mediatype->Width = biWidth; - if (mediatype->Height == 0) + if(mediatype->Height == 0) mediatype->Height = biHeight; /* Assume there will be no color table for video? */ - - if (bypass && biSize > 40) + if(bypass && biSize > 40) Stream_Seek(s, biSize - 40); - return (bypass ? biSize : 40); } /* http://msdn.microsoft.com/en-us/library/dd407326.aspx */ -static UINT32 tsmf_codec_parse_VIDEOINFOHEADER2(TS_AM_MEDIA_TYPE* mediatype, wStream* s) +static UINT32 tsmf_codec_parse_VIDEOINFOHEADER2(TS_AM_MEDIA_TYPE *mediatype, wStream *s) { UINT64 AvgTimePerFrame; - /* VIDEOINFOHEADER2.rcSource, RECT(LONG left, LONG top, LONG right, LONG bottom) */ Stream_Seek_UINT32(s); Stream_Seek_UINT32(s); @@ -329,25 +323,23 @@ static UINT32 tsmf_codec_parse_VIDEOINFOHEADER2(TS_AM_MEDIA_TYPE* mediatype, wSt mediatype->SamplesPerSecond.Denominator = (int)(AvgTimePerFrame / 10LL); /* Remaining fields before bmiHeader */ Stream_Seek(s, 24); - return 72; } /* http://msdn.microsoft.com/en-us/library/dd390700.aspx */ -static UINT32 tsmf_codec_parse_VIDEOINFOHEADER(TS_AM_MEDIA_TYPE* mediatype, wStream* s) +static UINT32 tsmf_codec_parse_VIDEOINFOHEADER(TS_AM_MEDIA_TYPE *mediatype, wStream *s) { -/* -typedef struct tagVIDEOINFOHEADER { - RECT rcSource; //16 - RECT rcTarget; //16 32 - DWORD dwBitRate; //4 36 - DWORD dwBitErrorRate; //4 40 - REFERENCE_TIME AvgTimePerFrame; //8 48 - BITMAPINFOHEADER bmiHeader; -} VIDEOINFOHEADER; -*/ + /* + typedef struct tagVIDEOINFOHEADER { + RECT rcSource; //16 + RECT rcTarget; //16 32 + DWORD dwBitRate; //4 36 + DWORD dwBitErrorRate; //4 40 + REFERENCE_TIME AvgTimePerFrame; //8 48 + BITMAPINFOHEADER bmiHeader; + } VIDEOINFOHEADER; + */ UINT64 AvgTimePerFrame; - /* VIDEOINFOHEADER.rcSource, RECT(LONG left, LONG top, LONG right, LONG bottom) */ Stream_Seek_UINT32(s); Stream_Seek_UINT32(s); @@ -363,76 +355,66 @@ typedef struct tagVIDEOINFOHEADER { Stream_Read_UINT64(s, AvgTimePerFrame); mediatype->SamplesPerSecond.Numerator = 1000000; mediatype->SamplesPerSecond.Denominator = (int)(AvgTimePerFrame / 10LL); - return 48; } -BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s) +BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE *mediatype, wStream *s) { int i; UINT32 cbFormat; BOOL ret = TRUE; - memset(mediatype, 0, sizeof(TS_AM_MEDIA_TYPE)); - /* MajorType */ - DEBUG_DVC("MajorType:"); + DEBUG_TSMF("MajorType:"); tsmf_print_guid(Stream_Pointer(s)); - for (i = 0; tsmf_major_type_map[i].type != TSMF_MAJOR_TYPE_UNKNOWN; i++) + for(i = 0; tsmf_major_type_map[i].type != TSMF_MAJOR_TYPE_UNKNOWN; i++) { - if (memcmp(tsmf_major_type_map[i].guid, Stream_Pointer(s), 16) == 0) + if(memcmp(tsmf_major_type_map[i].guid, Stream_Pointer(s), 16) == 0) break; } mediatype->MajorType = tsmf_major_type_map[i].type; - if (mediatype->MajorType == TSMF_MAJOR_TYPE_UNKNOWN) + if(mediatype->MajorType == TSMF_MAJOR_TYPE_UNKNOWN) ret = FALSE; - DEBUG_DVC("MajorType %s", tsmf_major_type_map[i].name); + DEBUG_TSMF("MajorType %s", tsmf_major_type_map[i].name); Stream_Seek(s, 16); - /* SubType */ - DEBUG_DVC("SubType:"); + DEBUG_TSMF("SubType:"); tsmf_print_guid(Stream_Pointer(s)); - for (i = 0; tsmf_sub_type_map[i].type != TSMF_SUB_TYPE_UNKNOWN; i++) + for(i = 0; tsmf_sub_type_map[i].type != TSMF_SUB_TYPE_UNKNOWN; i++) { - if (memcmp(tsmf_sub_type_map[i].guid, Stream_Pointer(s), 16) == 0) + if(memcmp(tsmf_sub_type_map[i].guid, Stream_Pointer(s), 16) == 0) break; } mediatype->SubType = tsmf_sub_type_map[i].type; - if (mediatype->SubType == TSMF_SUB_TYPE_UNKNOWN) + if(mediatype->SubType == TSMF_SUB_TYPE_UNKNOWN) ret = FALSE; - DEBUG_DVC("SubType %s", tsmf_sub_type_map[i].name); + DEBUG_TSMF("SubType %s", tsmf_sub_type_map[i].name); Stream_Seek(s, 16); - /* bFixedSizeSamples, bTemporalCompression, SampleSize */ Stream_Seek(s, 12); - /* FormatType */ - DEBUG_DVC("FormatType:"); + DEBUG_TSMF("FormatType:"); tsmf_print_guid(Stream_Pointer(s)); - for (i = 0; tsmf_format_type_map[i].type != TSMF_FORMAT_TYPE_UNKNOWN; i++) + for(i = 0; tsmf_format_type_map[i].type != TSMF_FORMAT_TYPE_UNKNOWN; i++) { - if (memcmp(tsmf_format_type_map[i].guid, Stream_Pointer(s), 16) == 0) + if(memcmp(tsmf_format_type_map[i].guid, Stream_Pointer(s), 16) == 0) break; } mediatype->FormatType = tsmf_format_type_map[i].type; - if (mediatype->FormatType == TSMF_FORMAT_TYPE_UNKNOWN) + if(mediatype->FormatType == TSMF_FORMAT_TYPE_UNKNOWN) ret = FALSE; - DEBUG_DVC("FormatType %s", tsmf_format_type_map[i].name); + DEBUG_TSMF("FormatType %s", tsmf_format_type_map[i].name); Stream_Seek(s, 16); - /* cbFormat */ Stream_Read_UINT32(s, cbFormat); - DEBUG_DVC("cbFormat %d", cbFormat); - -#ifdef WITH_DEBUG_DVC + DEBUG_TSMF("cbFormat %d", cbFormat); +#ifdef WITH_DEBUG_TSMF winpr_HexDump(Stream_Pointer(s), cbFormat); #endif - - switch (mediatype->FormatType) + switch(mediatype->FormatType) { case TSMF_FORMAT_TYPE_MFVIDEOFORMAT: /* http://msdn.microsoft.com/en-us/library/aa473808.aspx */ - Stream_Seek(s, 8); /* dwSize and ? */ Stream_Read_UINT32(s, mediatype->Width); /* videoInfo.dwWidth */ Stream_Read_UINT32(s, mediatype->Height); /* videoInfo.dwHeight */ @@ -443,17 +425,14 @@ BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s) Stream_Seek(s, 80); Stream_Read_UINT32(s, mediatype->BitRate); /* compressedInfo.AvgBitrate */ Stream_Seek(s, 36); - - if (cbFormat > 176) + if(cbFormat > 176) { mediatype->ExtraDataSize = cbFormat - 176; mediatype->ExtraData = Stream_Pointer(s); } break; - case TSMF_FORMAT_TYPE_WAVEFORMATEX: /* http://msdn.microsoft.com/en-us/library/dd757720.aspx */ - Stream_Seek_UINT16(s); Stream_Read_UINT16(s, mediatype->Channels); Stream_Read_UINT32(s, mediatype->SamplesPerSecond.Numerator); @@ -463,66 +442,55 @@ BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s) Stream_Read_UINT16(s, mediatype->BlockAlign); Stream_Read_UINT16(s, mediatype->BitsPerSample); Stream_Read_UINT16(s, mediatype->ExtraDataSize); - if (mediatype->ExtraDataSize > 0) + if(mediatype->ExtraDataSize > 0) mediatype->ExtraData = Stream_Pointer(s); - break; - case TSMF_FORMAT_TYPE_MPEG1VIDEOINFO: /* http://msdn.microsoft.com/en-us/library/dd390700.aspx */ - i = tsmf_codec_parse_VIDEOINFOHEADER(mediatype, s); i += tsmf_codec_parse_BITMAPINFOHEADER(mediatype, s, TRUE); - if (cbFormat > i) + if(cbFormat > i) { mediatype->ExtraDataSize = cbFormat - i; mediatype->ExtraData = Stream_Pointer(s); } break; - case TSMF_FORMAT_TYPE_MPEG2VIDEOINFO: /* http://msdn.microsoft.com/en-us/library/dd390707.aspx */ - i = tsmf_codec_parse_VIDEOINFOHEADER2(mediatype, s); i += tsmf_codec_parse_BITMAPINFOHEADER(mediatype, s, TRUE); - if (cbFormat > i) + if(cbFormat > i) { mediatype->ExtraDataSize = cbFormat - i; mediatype->ExtraData = Stream_Pointer(s); } break; - case TSMF_FORMAT_TYPE_VIDEOINFO2: i = tsmf_codec_parse_VIDEOINFOHEADER2(mediatype, s); i += tsmf_codec_parse_BITMAPINFOHEADER(mediatype, s, FALSE); - if (cbFormat > i) + if(cbFormat > i) { mediatype->ExtraDataSize = cbFormat - i; mediatype->ExtraData = Stream_Pointer(s); } break; - default: break; } - - if (mediatype->SamplesPerSecond.Numerator == 0) + if(mediatype->SamplesPerSecond.Numerator == 0) mediatype->SamplesPerSecond.Numerator = 1; - if (mediatype->SamplesPerSecond.Denominator == 0) + if(mediatype->SamplesPerSecond.Denominator == 0) mediatype->SamplesPerSecond.Denominator = 1; - return ret; } -BOOL tsmf_codec_check_media_type(wStream* s) +BOOL tsmf_codec_check_media_type(wStream *s) { - BYTE* m; + 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); - return ret; } diff --git a/channels/tsmf/client/tsmf_decoder.c b/channels/tsmf/client/tsmf_decoder.c index 630154776acf..3d17c60d0e11 100644 --- a/channels/tsmf/client/tsmf_decoder.c +++ b/channels/tsmf/client/tsmf_decoder.c @@ -32,45 +32,41 @@ #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 == NULL) return NULL; - decoder = entry(); - - if (decoder == NULL) + if(decoder == NULL) { DEBUG_WARN("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; - - if (name) + ITSMFDecoder *decoder = NULL; + if(name) { decoder = tsmf_load_decoder_by_name(name, media_type); } - else - { +#if defined(WITH_GSTREAMER_1_0) || defined(WITH_GSTREAMER_0_10) + if(!decoder) + decoder = tsmf_load_decoder_by_name("gstreamer", media_type); +#endif +#if defined(WITH_FFMPEG) + if(!decoder) decoder = tsmf_load_decoder_by_name("ffmpeg", media_type); - } - +#endif return decoder; } diff --git a/channels/tsmf/client/tsmf_decoder.h b/channels/tsmf/client/tsmf_decoder.h index 792bc6e62e7b..1215d0e98258 100644 --- a/channels/tsmf/client/tsmf_decoder.h +++ b/channels/tsmf/client/tsmf_decoder.h @@ -26,9 +26,8 @@ typedef enum _ITSMFControlMsg { Control_Pause, - Control_Restart, - Control_Flush, - Control_EndOfStream + Control_Resume, + Control_Stop } ITSMFControlMsg; typedef struct _ITSMFDecoder ITSMFDecoder; @@ -36,36 +35,40 @@ typedef struct _ITSMFDecoder ITSMFDecoder; struct _ITSMFDecoder { /* Set the decoder format. Return true if supported. */ - BOOL (*SetFormat) (ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* media_type); + BOOL (*SetFormat)(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *media_type); /* Decode a sample. */ - BOOL (*Decode) (ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size, UINT32 extensions); + BOOL (*Decode)(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions); /* Get the decoded data */ - BYTE* (*GetDecodedData) (ITSMFDecoder* decoder, UINT32* size); + BYTE *(*GetDecodedData)(ITSMFDecoder *decoder, UINT32 *size); /* Get the pixel format of decoded video frame */ - UINT32 (*GetDecodedFormat) (ITSMFDecoder* decoder); + UINT32(*GetDecodedFormat)(ITSMFDecoder *decoder); /* Get the width and height of decoded video frame */ - BOOL (*GetDecodedDimension) (ITSMFDecoder* decoder, UINT32* width, UINT32* height); + BOOL (*GetDecodedDimension)(ITSMFDecoder *decoder, UINT32 *width, UINT32 *height); /* Free the decoder */ - void (*Free) (ITSMFDecoder * decoder); + void (*Free)(ITSMFDecoder *decoder); /* Optional Contol function */ - void (*Control) (ITSMFDecoder * decoder, ITSMFControlMsg control_msg, UINT32 *arg); + void (*Control)(ITSMFDecoder *decoder, ITSMFControlMsg control_msg, UINT32 *arg); /* Decode a sample with extended interface. */ - int (*DecodeEx) (ITSMFDecoder * decoder, const BYTE * data, UINT32 data_size, UINT32 extensions, - UINT64 start_time, UINT64 end_time, UINT64 duration); + int (*DecodeEx)(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions, + UINT64 start_time, UINT64 end_time, UINT64 duration); /* Get current play time */ - UINT64 (*GetRunningTime) (ITSMFDecoder * decoder); + UINT64(*GetRunningTime)(ITSMFDecoder *decoder); /* Update Gstreamer Rendering Area */ - void (*UpdateRenderingArea) (ITSMFDecoder * decoder, int newX, int newY, int newWidth, int newHeight, int numRectangles, RDP_RECT *rectangles); + void (*UpdateRenderingArea)(ITSMFDecoder *decoder, int newX, int newY, int newWidth, int newHeight, int numRectangles, RDP_RECT *rectangles); /* Change Gstreamer Audio Volume */ - void (*ChangeVolume) (ITSMFDecoder * decoder, UINT32 newVolume, UINT32 muted); + void (*ChangeVolume)(ITSMFDecoder *decoder, UINT32 newVolume, UINT32 muted); /* Check buffer level */ - UINT32 (*BufferLevel) (ITSMFDecoder * decoder); + BOOL (*BufferFilled)(ITSMFDecoder *decoder); + /* Register a callback for frame ack. */ + BOOL (*SetAckFunc)(ITSMFDecoder *decoder, BOOL (*cb)(void *,BOOL), void *stream); + /* Register a callback for stream seek detection. */ + BOOL (*SetSyncFunc)(ITSMFDecoder *decoder, void (*cb)(void *), void *stream); }; #define TSMF_DECODER_EXPORT_FUNC_NAME "TSMFDecoderEntry" -typedef ITSMFDecoder* (*TSMF_DECODER_ENTRY) (void); +typedef ITSMFDecoder *(*TSMF_DECODER_ENTRY)(void); -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); #endif diff --git a/channels/tsmf/client/tsmf_ifman.c b/channels/tsmf/client/tsmf_ifman.c index 03229adb5f01..40e89e439214 100644 --- a/channels/tsmf/client/tsmf_ifman.c +++ b/channels/tsmf/client/tsmf_ifman.c @@ -37,21 +37,18 @@ #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_DVC("server CapabilityValue %d", 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; @@ -59,32 +56,28 @@ 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); - DEBUG_DVC("server protocol version %d", v); + DEBUG_TSMF("server protocol version %d", v); break; case 2: /* Supported platform */ Stream_Peek_UINT32(ifman->output, v); - DEBUG_DVC("server supported platform %d", 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); + MMREDIR_CAPABILITY_PLATFORM_MF | MMREDIR_CAPABILITY_PLATFORM_DSHOW); break; default: DEBUG_WARN("unknown capability type %d", CapabilityType); @@ -93,81 +86,62 @@ 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_DVC("PlatformCookie %d numMediaType %d", PlatformCookie, numMediaType); - - if (!tsmf_codec_check_media_type(ifman->input)) + DEBUG_TSMF("PlatformCookie %d numMediaType %d", PlatformCookie, numMediaType); + if(!tsmf_codec_check_media_type(ifman->input)) FormatSupported = 0; - - if (FormatSupported) - DEBUG_DVC("format ok."); - + 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; - - DEBUG_DVC(""); - + TSMF_PRESENTATION *presentation; + DEBUG_TSMF(""); presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input)); - if (presentation) + if(presentation) { - DEBUG_DVC("Presentation already exists"); + 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 == NULL) 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; - - DEBUG_DVC(""); - + 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 == NULL) { status = 1; } @@ -176,41 +150,33 @@ 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_DVC(""); - + DEBUG_TSMF(""); Stream_EnsureRemainingCapacity(ifman->output, 8); Stream_Write_UINT32(ifman->output, 1); /* TopologyReady */ Stream_Write_UINT32(ifman->output, 0); /* Result */ ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB; - 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; - - DEBUG_DVC(""); - + 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 == NULL) { status = 1; } @@ -218,41 +184,34 @@ 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; } -float tsmf_stream_read_float(wStream* s) +float tsmf_stream_read_float(wStream *s) { float fValue; UINT32 iValue; - Stream_Read_UINT32(s, iValue); CopyMemory(&fValue, &iValue, 4); - 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; - - DEBUG_DVC(""); - + 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; } @@ -262,144 +221,117 @@ int tsmf_ifman_set_source_video_rect(TSMF_IFMAN* ifman) Top = tsmf_stream_read_float(ifman->input); /* Top (4 bytes) */ Right = tsmf_stream_read_float(ifman->input); /* Right (4 bytes) */ Bottom = tsmf_stream_read_float(ifman->input); /* Bottom (4 bytes) */ - - DEBUG_DVC("SetSourceVideoRect: Left: %f Top: %f Right: %f Bottom: %f", - Left, Top, Right, Bottom); + 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; - - DEBUG_DVC(""); - + TSMF_PRESENTATION *presentation; + DEBUG_TSMF(""); presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input)); - - if (presentation) + if(presentation) tsmf_presentation_free(presentation); else DEBUG_WARN("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; - - DEBUG_DVC("on stream volume"); - + 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; - Stream_Seek(ifman->input, 16); Stream_Read_UINT32(ifman->input, newVolume); - DEBUG_DVC("on stream volume: new volume=[%d]", newVolume); + DEBUG_TSMF("on stream volume: new volume=[%d]", newVolume); Stream_Read_UINT32(ifman->input, muted); - DEBUG_DVC("on stream volume: muted=[%d]", muted); + DEBUG_TSMF("on stream volume: muted=[%d]", muted); tsmf_presentation_volume_changed(presentation, newVolume, muted); } else { DEBUG_WARN("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; - - DEBUG_DVC("on channel volume"); - + 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; - Stream_Seek(ifman->input, 16); Stream_Read_UINT32(ifman->input, channelVolume); - DEBUG_DVC("on channel volume: channel volume=[%d]", channelVolume); + DEBUG_TSMF("on channel volume: channel volume=[%d]", channelVolume); Stream_Read_UINT32(ifman->input, changedChannel); - DEBUG_DVC("on stream volume: changed channel=[%d]", 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_DVC(""); + 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; UINT32 Width; UINT32 Height; UINT32 cbVisibleRect; - RDP_RECT* rects = NULL; + RDP_RECT *rects = NULL; int num_rects = 0; int error = 0; int i; int pos; - presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input)); Stream_Seek(ifman->input, 16); - Stream_Read_UINT32(ifman->input, numGeometryInfo); pos = Stream_GetPosition(ifman->input); - Stream_Seek(ifman->input, 12); /* VideoWindowId (8 bytes), VideoWindowState (4 bytes) */ Stream_Read_UINT32(ifman->input, Width); Stream_Read_UINT32(ifman->input, Height); Stream_Read_UINT32(ifman->input, Left); Stream_Read_UINT32(ifman->input, Top); - Stream_SetPosition(ifman->input, pos + numGeometryInfo); Stream_Read_UINT32(ifman->input, cbVisibleRect); num_rects = cbVisibleRect / 16; - - DEBUG_DVC("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) + 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) { error = 1; } else { - if (num_rects > 0) + if(num_rects > 0) { - rects = (RDP_RECT*) malloc(sizeof(RDP_RECT) * num_rects); + rects = (RDP_RECT *) malloc(sizeof(RDP_RECT) * num_rects); ZeroMemory(rects, sizeof(RDP_RECT) * num_rects); - - for (i = 0; i < num_rects; i++) + for(i = 0; i < num_rects; i++) { Stream_Read_UINT16(ifman->input, rects[i].y); /* Top */ Stream_Seek_UINT16(ifman->input); @@ -411,44 +343,40 @@ int tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman) Stream_Seek_UINT16(ifman->input); rects[i].width -= rects[i].x; rects[i].height -= rects[i].y; - - DEBUG_DVC("rect %d: %d %d %d %d", i, - rects[i].x, rects[i].y, rects[i].width, rects[i].height); + DEBUG_TSMF("rect %d: %d %d %d %d", i, + 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_DVC(""); + 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_DVC(""); + 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 */ @@ -458,183 +386,144 @@ 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_DVC("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); - + 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 == NULL) { DEBUG_WARN("unknown presentation id"); return 1; } - stream = tsmf_stream_find_by_id(presentation, StreamId); - - if (stream == NULL) + if(stream == NULL) { DEBUG_WARN("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_DVC("StreamId %d", StreamId); - + DEBUG_TSMF("StreamId %d", StreamId); presentation = tsmf_presentation_find_by_id(ifman->presentation_id); - - if (presentation == NULL) + if(presentation == NULL) { DEBUG_WARN("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_DVC("StreamId %d", StreamId); - + DEBUG_TSMF("StreamId %d", StreamId); Stream_EnsureRemainingCapacity(ifman->output, 16); Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */ Stream_Write_UINT32(ifman->output, StreamId); /* StreamId */ 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; - - DEBUG_DVC(""); - + TSMF_PRESENTATION *presentation; + DEBUG_TSMF(""); presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input)); - - if (presentation) + if(presentation) tsmf_presentation_start(presentation); else DEBUG_WARN("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; - - DEBUG_DVC(""); + 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 DEBUG_WARN("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; - - DEBUG_DVC(""); + 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 DEBUG_WARN("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; - - DEBUG_DVC(""); - + TSMF_PRESENTATION *presentation; + DEBUG_TSMF(""); presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input)); - - if (presentation) + if(presentation) tsmf_presentation_stop(presentation); else DEBUG_WARN("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_DVC(""); - + DEBUG_TSMF(""); 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_MONITORCHANGED); /* EventId */ Stream_Write_UINT32(ifman->output, 0); /* cbData */ ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY; - return 0; } diff --git a/channels/tsmf/client/tsmf_main.c b/channels/tsmf/client/tsmf_main.c index e449e5935f1f..ec1ee44c3829 100644 --- a/channels/tsmf/client/tsmf_main.c +++ b/channels/tsmf/client/tsmf_main.c @@ -47,19 +47,19 @@ struct _TSMF_LISTENER_CALLBACK { IWTSListenerCallback iface; - IWTSPlugin* plugin; - IWTSVirtualChannelManager* channel_mgr; + IWTSPlugin *plugin; + IWTSVirtualChannelManager *channel_mgr; }; struct _TSMF_CHANNEL_CALLBACK { IWTSVirtualChannelCallback iface; - IWTSPlugin* plugin; - IWTSVirtualChannelManager* channel_mgr; - IWTSVirtualChannel* channel; + IWTSPlugin *plugin; + IWTSVirtualChannelManager *channel_mgr; + IWTSVirtualChannel *channel; - BYTE presentation_id[16]; + BYTE presentation_id[GUID_SIZE]; UINT32 stream_id; }; @@ -67,20 +67,19 @@ struct _TSMF_PLUGIN { IWTSPlugin iface; - TSMF_LISTENER_CALLBACK* listener_callback; + TSMF_LISTENER_CALLBACK *listener_callback; - const char* decoder_name; - const char* audio_name; - const char* audio_device; + 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) +void tsmf_playback_ack(IWTSVirtualChannelCallback *pChannelCallback, + UINT32 message_id, UINT64 duration, UINT32 data_size) { - wStream* s; - int status; - TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback; - + 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); @@ -88,71 +87,66 @@ void tsmf_playback_ack(IWTSVirtualChannelCallback* pChannelCallback, Stream_Write_UINT32(s, callback->stream_id); /* StreamId */ Stream_Write_UINT64(s, duration); /* DataDuration */ Stream_Write_UINT64(s, data_size); /* cbData */ - - DEBUG_DVC("response size %d", (int) Stream_GetPosition(s)); - status = callback->channel->Write(callback->channel, Stream_GetPosition(s), Stream_Buffer(s), NULL); - - if (status) + DEBUG_TSMF("response size %d", (int) Stream_GetPosition(s)); + if(!callback || !callback->channel || !callback->channel->Write) + DEBUG_WARN("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) { DEBUG_WARN("response error %d", status); } - Stream_Free(s, TRUE); } -BOOL tsmf_push_event(IWTSVirtualChannelCallback* pChannelCallback, wMessage* event) +BOOL tsmf_push_event(IWTSVirtualChannelCallback *pChannelCallback, wMessage *event) { int status; - TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback; - + TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback; status = callback->channel_mgr->PushEvent(callback->channel_mgr, event); - - if (status) + if(status) { DEBUG_WARN("response error %d", status); return FALSE; } - return TRUE; } -static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, - UINT32 cbSize, - BYTE* pBuffer) +static int tsmf_on_data_received(IWTSVirtualChannelCallback *pChannelCallback, + UINT32 cbSize, + BYTE *pBuffer) { int length; - wStream* input; - wStream* output; + wStream *input; + wStream *output; int status = -1; TSMF_IFMAN ifman; UINT32 MessageId; UINT32 FunctionId; UINT32 InterfaceId; - TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback; - + TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback; /* 2.2.1 Shared Message Header (SHARED_MSG_HEADER) */ - if (cbSize < 12) + if(cbSize < 12) { DEBUG_WARN("invalid size. cbSize=%d", cbSize); return 1; } - - input = Stream_New((BYTE*) pBuffer, cbSize); + input = Stream_New((BYTE *) pBuffer, cbSize); output = Stream_New(NULL, 256); Stream_Seek(output, 8); - Stream_Read_UINT32(input, InterfaceId); Stream_Read_UINT32(input, MessageId); Stream_Read_UINT32(input, FunctionId); - DEBUG_DVC("cbSize=%d InterfaceId=0x%X MessageId=0x%X FunctionId=0x%X", - cbSize, InterfaceId, MessageId, FunctionId); - + DEBUG_TSMF("cbSize=%d InterfaceId=0x%X MessageId=0x%X FunctionId=0x%X", + cbSize, InterfaceId, MessageId, FunctionId); memset(&ifman, 0, 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, 16); + 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.stream_id = callback->stream_id; ifman.message_id = MessageId; ifman.input = input; @@ -160,139 +154,108 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, ifman.output = output; ifman.output_pending = FALSE; ifman.output_interface_id = InterfaceId; - - switch (InterfaceId) + 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; - 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), 16); - Stream_Seek(input, 16); + memcpy(callback->presentation_id, Stream_Pointer(input), GUID_SIZE); + Stream_Seek(input, GUID_SIZE); Stream_Read_UINT32(input, callback->stream_id); - DEBUG_DVC("SET_CHANNEL_PARAMS StreamId=%d", callback->stream_id); + DEBUG_TSMF("SET_CHANNEL_PARAMS StreamId=%d", callback->stream_id); ifman.output_pending = TRUE; status = 0; break; - case EXCHANGE_CAPABILITIES_REQ: status = tsmf_ifman_exchange_capability_request(&ifman); break; - case CHECK_FORMAT_SUPPORT_REQ: status = tsmf_ifman_check_format_support_request(&ifman); break; - case ON_NEW_PRESENTATION: status = tsmf_ifman_on_new_presentation(&ifman); break; - case ADD_STREAM: status = tsmf_ifman_add_stream(&ifman); break; - case SET_TOPOLOGY_REQ: status = tsmf_ifman_set_topology_request(&ifman); break; - case REMOVE_STREAM: status = tsmf_ifman_remove_stream(&ifman); break; - case SET_SOURCE_VIDEO_RECT: status = tsmf_ifman_set_source_video_rect(&ifman); break; - case SHUTDOWN_PRESENTATION_REQ: status = tsmf_ifman_shutdown_presentation(&ifman); break; - case ON_STREAM_VOLUME: status = tsmf_ifman_on_stream_volume(&ifman); break; - case ON_CHANNEL_VOLUME: status = tsmf_ifman_on_channel_volume(&ifman); break; - case SET_VIDEO_WINDOW: status = tsmf_ifman_set_video_window(&ifman); break; - case UPDATE_GEOMETRY_INFO: status = tsmf_ifman_update_geometry_info(&ifman); break; - case SET_ALLOCATOR: status = tsmf_ifman_set_allocator(&ifman); break; - case NOTIFY_PREROLL: status = tsmf_ifman_notify_preroll(&ifman); break; - case ON_SAMPLE: status = tsmf_ifman_on_sample(&ifman); break; - case ON_FLUSH: status = tsmf_ifman_on_flush(&ifman); break; - case ON_END_OF_STREAM: status = tsmf_ifman_on_end_of_stream(&ifman); break; - case ON_PLAYBACK_STARTED: status = tsmf_ifman_on_playback_started(&ifman); break; - case ON_PLAYBACK_PAUSED: status = tsmf_ifman_on_playback_paused(&ifman); break; - case ON_PLAYBACK_RESTARTED: status = tsmf_ifman_on_playback_restarted(&ifman); break; - case ON_PLAYBACK_STOPPED: status = tsmf_ifman_on_playback_stopped(&ifman); break; - case ON_PLAYBACK_RATE_CHANGED: status = tsmf_ifman_on_playback_rate_changed(&ifman); break; - default: break; } break; - default: break; } - Stream_Free(input, FALSE); 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) @@ -300,121 +263,98 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, status = 0; ifman.output_pending = 1; break; - case RIMCALL_QUERYINTERFACE: /* [MS-RDPEXPS] 2.2.2.1.2 Query Interface Response (QI_RSP) This message is not supported in this channel. */ status = 0; break; } - - if (status == -1) + if(status == -1) { DEBUG_WARN("InterfaceId 0x%X FunctionId 0x%X not processed.", - InterfaceId, FunctionId); + InterfaceId, 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); Stream_SetPosition(output, 0); Stream_Write_UINT32(output, ifman.output_interface_id); Stream_Write_UINT32(output, MessageId); - - DEBUG_DVC("response size %d", length); + DEBUG_TSMF("response size %d", length); status = callback->channel->Write(callback->channel, length, Stream_Buffer(output), NULL); - if (status) + if(status) { DEBUG_WARN("response error %d", status); } } - Stream_Free(output, TRUE); - return status; } -static int tsmf_on_close(IWTSVirtualChannelCallback* pChannelCallback) +static int tsmf_on_close(IWTSVirtualChannelCallback *pChannelCallback) { - TSMF_STREAM* stream; - TSMF_PRESENTATION* presentation; - TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback; - - DEBUG_DVC(""); - - if (callback->stream_id) + TSMF_STREAM *stream; + TSMF_PRESENTATION *presentation; + TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback; + DEBUG_TSMF(""); + 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; } -static int tsmf_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, - IWTSVirtualChannel* pChannel, - BYTE* Data, - int* pbAccept, - IWTSVirtualChannelCallback** ppCallback) +static int tsmf_on_new_channel_connection(IWTSListenerCallback *pListenerCallback, + IWTSVirtualChannel *pChannel, + BYTE *Data, + int *pbAccept, + IWTSVirtualChannelCallback **ppCallback) { - TSMF_CHANNEL_CALLBACK* callback; - TSMF_LISTENER_CALLBACK* listener_callback = (TSMF_LISTENER_CALLBACK*) pListenerCallback; - - DEBUG_DVC(""); - - callback = (TSMF_CHANNEL_CALLBACK*) malloc(sizeof(TSMF_CHANNEL_CALLBACK)); + 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->iface.OnDataReceived = tsmf_on_data_received; callback->iface.OnClose = tsmf_on_close; 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; - - DEBUG_DVC(""); - - tsmf->listener_callback = (TSMF_LISTENER_CALLBACK*) malloc(sizeof(TSMF_LISTENER_CALLBACK)); + 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->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); + (IWTSListenerCallback *) tsmf->listener_callback, NULL); } -static int tsmf_plugin_terminated(IWTSPlugin* pPlugin) +static int tsmf_plugin_terminated(IWTSPlugin *pPlugin) { - TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin; - - DEBUG_DVC(""); - - if (tsmf->listener_callback) + TSMF_PLUGIN *tsmf = (TSMF_PLUGIN *) pPlugin; + DEBUG_TSMF(""); + if(tsmf->listener_callback) free(tsmf->listener_callback); free(tsmf); - return 0; } @@ -426,27 +366,21 @@ COMMAND_LINE_ARGUMENT_A tsmf_args[] = { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; -static void tsmf_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args) +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") { tsmf->audio_name = _strdup(arg->Value); @@ -461,43 +395,35 @@ static void tsmf_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args) } CommandLineSwitchDefault(arg) { - } - 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; + tsmf = (TSMF_PLUGIN *) pEntryPoints->GetPlugin(pEntryPoints, "tsmf"); + if(tsmf == NULL) { - tsmf = (TSMF_PLUGIN*) malloc(sizeof(TSMF_PLUGIN)); + tsmf = (TSMF_PLUGIN *) malloc(sizeof(TSMF_PLUGIN)); ZeroMemory(tsmf, sizeof(TSMF_PLUGIN)); - 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); - + status = pEntryPoints->RegisterPlugin(pEntryPoints, "tsmf", (IWTSPlugin *) tsmf); tsmf_media_init(); } - - 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; } diff --git a/channels/tsmf/client/tsmf_media.c b/channels/tsmf/client/tsmf_media.c index eece46b652bd..51465554b4ad 100644 --- a/channels/tsmf/client/tsmf_media.c +++ b/channels/tsmf/client/tsmf_media.c @@ -22,6 +22,8 @@ #include "config.h" #endif +#include + #include #include #include @@ -52,33 +54,17 @@ #include "tsmf_codec.h" #include "tsmf_media.h" -#include - #define AUDIO_TOLERANCE 10000000LL struct _TSMF_PRESENTATION { BYTE presentation_id[GUID_SIZE]; - const char* audio_name; - const char* audio_device; + const char *audio_name; + const char *audio_device; int eos; - UINT32 last_x; - UINT32 last_y; - UINT32 last_width; - UINT32 last_height; - UINT16 last_num_rects; - RDP_RECT* last_rects; - - UINT32 output_x; - UINT32 output_y; - UINT32 output_width; - UINT32 output_height; - UINT16 output_num_rects; - RDP_RECT* output_rects; - - IWTSVirtualChannelCallback* channel_callback; + IWTSVirtualChannelCallback *channel_callback; UINT64 audio_start_time; UINT64 audio_end_time; @@ -86,26 +72,31 @@ struct _TSMF_PRESENTATION UINT32 volume; UINT32 muted; - HANDLE mutex; - HANDLE thread; + wArrayList *stream_list; + + int x; + int y; + int width; + int height; - wArrayList* stream_list; + int nr_rects; + void *rects; }; struct _TSMF_STREAM { UINT32 stream_id; - TSMF_PRESENTATION* presentation; + TSMF_PRESENTATION *presentation; - ITSMFDecoder* decoder; + ITSMFDecoder *decoder; int major_type; int eos; UINT32 width; UINT32 height; - ITSMFAudioDevice* audio; + ITSMFAudioDevice *audio; UINT32 sample_rate; UINT32 channels; UINT32 bits_per_sample; @@ -115,13 +106,13 @@ struct _TSMF_STREAM /* Next sample should not start before this system time. */ UINT64 next_start_time; - BOOL started; - - HANDLE thread; + HANDLE play_thread; + HANDLE ack_thread; HANDLE stopEvent; + HANDLE ready; - wQueue* sample_list; - wQueue* sample_ack_list; + wQueue *sample_list; + wQueue *sample_ack_list; }; struct _TSMF_SAMPLE @@ -132,36 +123,37 @@ struct _TSMF_SAMPLE UINT64 duration; UINT32 extensions; UINT32 data_size; - BYTE* data; + BYTE *data; UINT32 decoded_size; UINT32 pixfmt; - TSMF_STREAM* stream; - IWTSVirtualChannelCallback* channel_callback; + TSMF_STREAM *stream; + IWTSVirtualChannelCallback *channel_callback; UINT64 ack_time; }; -static wArrayList* presentation_list = NULL; -static UINT64 last_played_audio_time = 0; -static HANDLE tsmf_mutex = NULL; +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 UINT64 get_current_time(void) { struct timeval tp; - gettimeofday(&tp, 0); 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_STREAM *s; + TSMF_SAMPLE *sample; BOOL pending = FALSE; - TSMF_PRESENTATION* presentation = stream->presentation; + TSMF_PRESENTATION *presentation = stream->presentation; + assert(stream); if (Queue_Count(stream->sample_list) < 1) return NULL; @@ -178,18 +170,17 @@ static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync) if (stream->last_end_time > AUDIO_TOLERANCE) { ArrayList_Lock(presentation->stream_list); - count = ArrayList_Count(presentation->stream_list); for (index = 0; index < count; index++) { - s = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index); + s = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); if (s != stream && !s->eos && s->last_end_time && - s->last_end_time < stream->last_end_time - AUDIO_TOLERANCE) + s->last_end_time < stream->last_end_time - AUDIO_TOLERANCE) { - pending = TRUE; - break; + pending = TRUE; + break; } } @@ -203,7 +194,6 @@ static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync) pending = TRUE; } } - } } } @@ -211,7 +201,7 @@ static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync) if (pending) return NULL; - sample = (TSMF_SAMPLE*) Queue_Dequeue(stream->sample_list); + sample = (TSMF_SAMPLE *) Queue_Dequeue(stream->sample_list); if (sample && (sample->end_time > stream->last_end_time)) stream->last_end_time = sample->end_time; @@ -219,99 +209,106 @@ static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync) return sample; } -static void tsmf_sample_free(TSMF_SAMPLE* sample) +static void tsmf_sample_free(void *arg) { + TSMF_SAMPLE *sample = arg; + assert(sample); + if (sample->data) free(sample->data); free(sample); } -static void tsmf_sample_ack(TSMF_SAMPLE* sample) +static void tsmf_sample_ack(TSMF_SAMPLE *sample) { + assert(sample); 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) { - TSMF_STREAM* stream = sample->stream; - - Queue_Enqueue(stream->sample_ack_list, sample); + assert(sample); + assert(sample->stream); + Queue_Enqueue(sample->stream->sample_ack_list, sample); } -static void tsmf_stream_process_ack(TSMF_STREAM* stream) +static BOOL tsmf_stream_process_ack(void *arg, BOOL force) { - TSMF_SAMPLE* sample; + TSMF_STREAM *stream = arg; + TSMF_SAMPLE *sample; UINT64 ack_time; + BOOL rc = FALSE; + assert(stream); + Queue_Lock(stream->sample_ack_list); + sample = (TSMF_SAMPLE *) Queue_Peek(stream->sample_ack_list); - ack_time = get_current_time(); + if (!sample) + goto finally; - while ((Queue_Count(stream->sample_ack_list) > 0) && !(WaitForSingleObject(stream->stopEvent, 0) == WAIT_OBJECT_0)) + if (!force) { - sample = (TSMF_SAMPLE*) Queue_Peek(stream->sample_ack_list); - - if (!sample || (sample->ack_time > ack_time)) - break; + ack_time = get_current_time(); - sample = Queue_Dequeue(stream->sample_ack_list); - - tsmf_sample_ack(sample); - tsmf_sample_free(sample); + if (sample->ack_time > ack_time) + goto finally; } + + 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; - pthread_t thid = pthread_self(); - FILE* fout = NULL; - fout = fopen("/tmp/tsmf.tid", "wt"); - - if (fout) - { - fprintf(fout, "%d\n", (int) (size_t) thid); - fclose(fout); - } + TSMF_PRESENTATION *presentation; + assert(guid); + assert(pChannelCallback); + presentation = (TSMF_PRESENTATION *) calloc(1, sizeof(TSMF_PRESENTATION)); - presentation = tsmf_presentation_find_by_id(guid); - - if (presentation) + if (!presentation) { - DEBUG_WARN("duplicated presentation id!"); + DEBUG_WARN("calloc failed"); return NULL; } - presentation = (TSMF_PRESENTATION*) calloc(1, sizeof(TSMF_PRESENTATION)); - CopyMemory(presentation->presentation_id, guid, GUID_SIZE); presentation->channel_callback = pChannelCallback; - presentation->volume = 5000; /* 50% */ - presentation->muted = 0; - - presentation->mutex = CreateMutex(NULL, FALSE, NULL); presentation->stream_list = ArrayList_New(TRUE); - ArrayList_Object(presentation->stream_list)->fnObjectFree = (OBJECT_FREE_FN) tsmf_stream_free; - + ArrayList_Object(presentation->stream_list)->fnObjectFree = (OBJECT_FREE_FN) _tsmf_stream_free; ArrayList_Add(presentation_list, presentation); - return presentation; } -TSMF_PRESENTATION* tsmf_presentation_find_by_id(const BYTE* guid) +static char *guid_to_string(const BYTE *guid, char *str, size_t len) { + int i; + assert(guid); + assert(str); + + for (i=0; i 2*i; i++) + snprintf(str + (2*i), len - 2*i, "%02X", guid[i]); + + return str; +} + +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; - + 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) { @@ -322,122 +319,47 @@ TSMF_PRESENTATION* tsmf_presentation_find_by_id(const BYTE* guid) ArrayList_Unlock(presentation_list); - return (found) ? presentation : NULL; -} - -static void tsmf_presentation_restore_last_video_frame(TSMF_PRESENTATION* presentation) -{ - RDP_REDRAW_EVENT* revent; + if (!found) + DEBUG_WARN("presentation id %s not found", guid_to_string(guid, guid_str, sizeof(guid_str))); - if (presentation->last_width && presentation->last_height) - { - revent = (RDP_REDRAW_EVENT*) freerdp_event_new(TsmfChannel_Class, TsmfChannel_Redraw, - NULL, NULL); - - revent->x = presentation->last_x; - revent->y = presentation->last_y; - revent->width = presentation->last_width; - revent->height = presentation->last_height; - - if (!tsmf_push_event(presentation->channel_callback, (wMessage*) revent)) - { - freerdp_event_free((wMessage*) revent); - } - - presentation->last_x = 0; - presentation->last_y = 0; - presentation->last_width = 0; - presentation->last_height = 0; - } + 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; - - DEBUG_DVC("MessageId %d EndTime %d data_size %d consumed.", - sample->sample_id, (int)sample->end_time, sample->data_size); + RDP_VIDEO_FRAME_EVENT *vevent; + TSMF_STREAM *stream = sample->stream; + TSMF_PRESENTATION *presentation = stream->presentation; + DEBUG_TSMF("MessageId %d EndTime %d data_size %d consumed.", + sample->sample_id, (int)sample->end_time, sample->data_size); if (sample->data) { t = get_current_time(); if (stream->next_start_time > t && - (sample->end_time >= presentation->audio_start_time || - sample->end_time < stream->last_end_time)) + (sample->end_time >= presentation->audio_start_time || + sample->end_time < stream->last_end_time)) { USleep((stream->next_start_time - t) / 10); } - stream->next_start_time = t + sample->duration - 50000; - - if (presentation->last_x != presentation->output_x || - presentation->last_y != presentation->output_y || - presentation->last_width != presentation->output_width || - presentation->last_height != presentation->output_height || - presentation->last_num_rects != presentation->output_num_rects || - (presentation->last_rects && presentation->output_rects && - memcmp(presentation->last_rects, presentation->output_rects, - presentation->last_num_rects * sizeof(RDP_RECT)) != 0)) - { - tsmf_presentation_restore_last_video_frame(presentation); - - presentation->last_x = presentation->output_x; - presentation->last_y = presentation->output_y; - presentation->last_width = presentation->output_width; - presentation->last_height = presentation->output_height; - - if (presentation->last_rects) - { - free(presentation->last_rects); - presentation->last_rects = NULL; - } - - presentation->last_num_rects = presentation->output_num_rects; - - if (presentation->last_num_rects > 0) - { - presentation->last_rects = malloc(presentation->last_num_rects * sizeof(RDP_RECT)); - ZeroMemory(presentation->last_rects, presentation->last_num_rects * sizeof(RDP_RECT)); - - memcpy(presentation->last_rects, presentation->output_rects, - presentation->last_num_rects * sizeof(RDP_RECT)); - } - } - - vevent = (RDP_VIDEO_FRAME_EVENT*) freerdp_event_new(TsmfChannel_Class, TsmfChannel_VideoFrame, - NULL, NULL); + 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; - vevent->x = presentation->output_x; - vevent->y = presentation->output_y; - vevent->width = presentation->output_width; - vevent->height = presentation->output_height; - - if (presentation->output_num_rects > 0) - { - vevent->num_visible_rects = presentation->output_num_rects; - - vevent->visible_rects = (RDP_RECT*) malloc(presentation->output_num_rects * sizeof(RDP_RECT)); - ZeroMemory(vevent->visible_rects, presentation->output_num_rects * sizeof(RDP_RECT)); - - memcpy(vevent->visible_rects, presentation->output_rects, - presentation->output_num_rects * sizeof(RDP_RECT)); - } - /* 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)) + if (!tsmf_push_event(sample->channel_callback, (wMessage *) vevent)) { - freerdp_event_free((wMessage*) vevent); + freerdp_event_free((wMessage *) vevent); } #if 0 @@ -445,7 +367,8 @@ static void tsmf_sample_playback_video(TSMF_SAMPLE* sample) extract the Y values to create a grayscale image. */ static int frame_id = 0; char buf[100]; - FILE * fp; + FILE *fp; + if ((frame_id % 30) == 0) { snprintf(buf, sizeof(buf), "/tmp/FreeRDP_Frame_%d.ppm", frame_id); @@ -458,23 +381,23 @@ static void tsmf_sample_playback_video(TSMF_SAMPLE* sample) fflush(fp); fclose(fp); } + frame_id++; #endif } } -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; - - DEBUG_DVC("MessageId %d EndTime %d consumed.", - sample->sample_id, (int)sample->end_time); + 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->data, sample->decoded_size); sample->data = NULL; sample->decoded_size = 0; @@ -492,27 +415,26 @@ 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) { - tsmf_sample_ack(sample); - tsmf_sample_free(sample); + tsmf_sample_queue_ack(sample); return; } @@ -524,22 +446,25 @@ static void tsmf_sample_playback(TSMF_SAMPLE* sample) if (stream->decoder->GetDecodedFormat) { pixfmt = stream->decoder->GetDecodedFormat(stream->decoder); + if (pixfmt == ((UINT32) -1)) { - tsmf_sample_ack(sample); - tsmf_sample_free(sample); + tsmf_sample_queue_ack(sample); return; } + sample->pixfmt = pixfmt; } ret = FALSE ; + if (stream->decoder->GetDecodedDimension) { ret = stream->decoder->GetDecodedDimension(stream->decoder, &width, &height); + if (ret && (width != stream->width || height != stream->height)) { - DEBUG_DVC("video dimension changed to %d x %d", width, height); + DEBUG_TSMF("video dimension changed to %d x %d", width, height); stream->width = width; stream->height = height; } @@ -549,13 +474,14 @@ static void tsmf_sample_playback(TSMF_SAMPLE* sample) if (stream->decoder->GetDecodedData) { sample->data = stream->decoder->GetDecodedData(stream->decoder, &sample->decoded_size); + switch (sample->stream->major_type) { case TSMF_MAJOR_TYPE_VIDEO: tsmf_sample_playback_video(sample); - tsmf_sample_ack(sample); - tsmf_sample_free(sample); + tsmf_sample_queue_ack(sample); break; + case TSMF_MAJOR_TYPE_AUDIO: tsmf_sample_playback_audio(sample); tsmf_sample_queue_ack(sample); @@ -564,157 +490,124 @@ 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; - UINT32 bufferLevel = 0; + BOOL buffer_filled = TRUE; + if (stream->decoder->GetRunningTime) { currentRunningTime = stream->decoder->GetRunningTime(stream->decoder); } - if (stream->decoder->BufferLevel) + + if (stream->decoder->BufferFilled) { - bufferLevel = stream->decoder->BufferLevel(stream->decoder); + buffer_filled = stream->decoder->BufferFilled(stream->decoder); } + + if (buffer_filled) + { + if (currentRunningTime > sample->start_time) + { + ack_anticipation_time += sample->duration; + } + else if (currentRunningTime == 0) + { + ack_anticipation_time += sample->duration; + } + else + { + ack_anticipation_time += (sample->start_time - currentRunningTime); + } + } + else + ack_anticipation_time += sample->duration / 2; + switch (sample->stream->major_type) { case TSMF_MAJOR_TYPE_VIDEO: - { - TSMF_PRESENTATION * presentation = sample->stream->presentation; - /* - * Tell gstreamer that presentation screen area has moved. - * So it can render on the new area. - */ - if (presentation->last_x != presentation->output_x || presentation->last_y != presentation->output_y || - presentation->last_width != presentation->output_width || presentation->last_height != presentation->output_height) { - presentation->last_x = presentation->output_x; - presentation->last_y = presentation->output_y; - presentation->last_width = presentation->output_width; - presentation->last_height = presentation->output_height; - if(stream->decoder->UpdateRenderingArea) - { - stream->decoder->UpdateRenderingArea(stream->decoder, presentation->output_x, presentation->output_y, - presentation->output_width, presentation->output_height, presentation->output_num_rects, presentation->output_rects); - } + break; } - if ( presentation->last_num_rects != presentation->output_num_rects || (presentation->last_rects && presentation->output_rects && - memcmp(presentation->last_rects, presentation->output_rects, presentation->last_num_rects * sizeof(RDP_RECT)) != 0)) - { - if (presentation->last_rects) - { - free(presentation->last_rects); - presentation->last_rects = NULL; - } - presentation->last_num_rects = presentation->output_num_rects; - - if (presentation->last_num_rects > 0) - { - presentation->last_rects = malloc(presentation->last_num_rects * sizeof(RDP_RECT)); - ZeroMemory(presentation->last_rects, presentation->last_num_rects * sizeof(RDP_RECT)); - memcpy(presentation->last_rects, presentation->output_rects, presentation->last_num_rects * sizeof(RDP_RECT)); - } - if(stream->decoder->UpdateRenderingArea) - { - stream->decoder->UpdateRenderingArea(stream->decoder, presentation->output_x, presentation->output_y, - presentation->output_width, presentation->output_height, presentation->output_num_rects, presentation->output_rects); - } - } - - if (bufferLevel < 24) - { - ack_anticipation_time += sample->duration; - } - else - { - if (currentRunningTime > sample->start_time) - { - ack_anticipation_time += sample->duration; - } - else if(currentRunningTime == 0) - { - ack_anticipation_time += sample->duration; - } - else - { - ack_anticipation_time += (sample->start_time - currentRunningTime); - } - } - break; - } case TSMF_MAJOR_TYPE_AUDIO: - { - last_played_audio_time = currentRunningTime; - if (bufferLevel < 2) { - ack_anticipation_time += sample->duration; - } - else - { - if (currentRunningTime > sample->start_time) - { - ack_anticipation_time += sample->duration; - } - else if(currentRunningTime == 0) - { - ack_anticipation_time += sample->duration; - } - else - { - ack_anticipation_time += (sample->start_time - currentRunningTime); - } + break; } - break; - } } + sample->ack_time = ack_anticipation_time; tsmf_sample_queue_ack(sample); - } + } } -static void* tsmf_stream_playback_func(void* arg) +static void *tsmf_stream_ack_func(void *arg) { - TSMF_SAMPLE* sample; - TSMF_STREAM* stream = (TSMF_STREAM*) arg; - TSMF_PRESENTATION* presentation = stream->presentation; + TSMF_STREAM *stream = (TSMF_STREAM *) arg; + HANDLE hdl[2]; + DEBUG_TSMF("in %d", stream->stream_id); + hdl[0] = stream->stopEvent; + hdl[1] = Queue_Event(stream->sample_ack_list); + + while (1) + { + DWORD ev = WaitForMultipleObjects(2, hdl, FALSE, INFINITE); + + if (ev == WAIT_OBJECT_0) + break; + + if (!stream->decoder) + continue; + + if (stream->decoder->SetAckFunc) + continue; + + if (tsmf_stream_process_ack(stream, FALSE)) + break; + } - DEBUG_DVC("in %d", stream->stream_id); + DEBUG_TSMF("out %d", stream->stream_id); + ExitThread(0); + return NULL; +} + +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; + DEBUG_TSMF("in %d", stream->stream_id); if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO && - stream->sample_rate && stream->channels && stream->bits_per_sample) + stream->sample_rate && stream->channels && stream->bits_per_sample) { if (stream->decoder) { 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->sample_rate, stream->channels, stream->bits_per_sample); } } } } - while (!(WaitForSingleObject(stream->stopEvent, 0) == WAIT_OBJECT_0)) + hdl[0] = stream->stopEvent; + hdl[1] = Queue_Event(stream->sample_list); + + while (!(WaitForMultipleObjects(2, hdl, FALSE, INFINITE) == WAIT_OBJECT_0)) { - tsmf_stream_process_ack(stream); - sample = tsmf_stream_pop_sample(stream, 1); + sample = tsmf_stream_pop_sample(stream, 0); if (sample) tsmf_sample_playback(sample); - else - USleep(5000); - } - - if (stream->eos || presentation->eos) - { - while ((sample = tsmf_stream_pop_sample(stream, 1)) != NULL) - tsmf_sample_playback(sample); } if (stream->audio) @@ -723,48 +616,36 @@ static void* tsmf_stream_playback_func(void* arg) stream->audio = NULL; } - SetEvent(stream->stopEvent); - - DEBUG_DVC("out %d", stream->stream_id); - + DEBUG_TSMF("out %d", stream->stream_id); + ExitThread(0); return NULL; } -static void tsmf_stream_start(TSMF_STREAM* stream) +static void tsmf_stream_start(TSMF_STREAM *stream) { - if (!stream->started) + if (!stream || !stream->presentation || !stream->decoder) + return; + + if (stream->decoder->Control) { - ResumeThread(stream->thread); - stream->started = TRUE; + stream->decoder->Control(stream->decoder, Control_Resume, NULL); } } -static void tsmf_stream_stop(TSMF_STREAM* stream) +static void tsmf_stream_stop(TSMF_STREAM *stream) { - if (!stream) + if (!stream || !stream->decoder) return; - if (!stream->decoder) - return; - - if (stream->started) - { - SetEvent(stream->stopEvent); - stream->started = FALSE; - } - if (stream->decoder->Control) { - stream->decoder->Control(stream->decoder, Control_Flush, NULL); + stream->decoder->Control(stream->decoder, Control_Stop, NULL); } } -static void tsmf_stream_pause(TSMF_STREAM* stream) +static void tsmf_stream_pause(TSMF_STREAM *stream) { - if (!stream) - return; - - if (!stream->decoder) + if (!stream || !stream->decoder) return; if (stream->decoder->Control) @@ -773,25 +654,22 @@ 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) - return; - - if (!stream->decoder) + if (!stream || !stream->decoder) return; if (stream->decoder->Control) { - stream->decoder->Control(stream->decoder, Control_Restart, NULL); + stream->decoder->Control(stream->decoder, Control_Resume, NULL); } } -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) + if (!stream || !stream->decoder) return; - + if (stream->decoder != NULL && stream->decoder->ChangeVolume) { stream->decoder->ChangeVolume(stream->decoder, newVolume, muted); @@ -802,151 +680,169 @@ 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); - 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_change_volume(stream, newVolume, muted); } 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); 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_pause(stream); } 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); 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_restart(stream); } 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); 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_start(stream); } ArrayList_Unlock(presentation->stream_list); } -void tsmf_presentation_stop(TSMF_PRESENTATION* presentation) +void tsmf_presentation_sync(TSMF_PRESENTATION *presentation) { UINT32 index; UINT32 count; - TSMF_STREAM* stream; + ArrayList_Lock(presentation->stream_list); + count = ArrayList_Count(presentation->stream_list); - tsmf_presentation_flush(presentation); + for (index = 0; index < count; index++) + { + TSMF_STREAM *stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); + WaitForSingleObject(stream->ready, 500); + } - ArrayList_Lock(presentation->stream_list); + ArrayList_Unlock(presentation->stream_list); +} +void tsmf_presentation_stop(TSMF_PRESENTATION *presentation) +{ + UINT32 index; + UINT32 count; + TSMF_STREAM *stream; + tsmf_presentation_flush(presentation); + 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_stop(stream); } ArrayList_Unlock(presentation->stream_list); +} - tsmf_presentation_restore_last_video_frame(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; + + /* The server may send messages with invalid width / height. + * Ignore those messages. */ + if (!width || !height) + return; - if (presentation->last_rects) + if ((width == presentation->width) && (height == presentation->height) && + (x == presentation->x) && (y == presentation->y) && + (num_rects == presentation->nr_rects) && + (0 == memcmp(rects, presentation->rects, num_rects * sizeof(RDP_RECT)))) { - free(presentation->last_rects); - presentation->last_rects = NULL; + return; } - presentation->last_num_rects = 0; + presentation->x = x; + presentation->y = y; + presentation->width = width; + presentation->height = height; + presentation->nr_rects = num_rects; + presentation->rects = realloc(presentation->rects, sizeof(RDP_RECT) * num_rects); - if (presentation->output_rects) - { - free(presentation->output_rects); - presentation->output_rects = NULL; - } + if (presentation->rects) + memcpy(presentation->rects, rects, sizeof(RDP_RECT) * num_rects); - presentation->output_num_rects = 0; -} + ArrayList_Lock(presentation->stream_list); + count = ArrayList_Count(presentation->stream_list); -void tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation, - UINT32 x, UINT32 y, UINT32 width, UINT32 height, int num_rects, RDP_RECT* rects) -{ - presentation->output_x = x; - presentation->output_y = y; - presentation->output_width = width; - presentation->output_height = height; + for (index = 0; index < count; index++) + { + stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); - if (presentation->output_rects) - free(presentation->output_rects); + if (!stream->decoder) + continue; - presentation->output_rects = rects; - presentation->output_num_rects = num_rects; + if (stream->decoder->UpdateRenderingArea) + { + stream->decoder->UpdateRenderingArea(stream->decoder, x, y, width, height, num_rects, rects); + } + } + + 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 */ - if (stream->audio) stream->audio->Flush(stream->audio); @@ -961,45 +857,47 @@ 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); } ArrayList_Unlock(presentation->stream_list); - presentation->eos = 0; presentation->audio_start_time = 0; presentation->audio_end_time = 0; } -void tsmf_presentation_free(TSMF_PRESENTATION* presentation) +void _tsmf_presentation_free(TSMF_PRESENTATION *presentation) { tsmf_presentation_stop(presentation); - - ArrayList_Remove(presentation_list, presentation); + ArrayList_Clear(presentation->stream_list); ArrayList_Free(presentation->stream_list); - CloseHandle(presentation->mutex); + if (presentation->rects) + free(presentation->rects); + memset(presentation, 0, sizeof(TSMF_PRESENTATION)); free(presentation); } -TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, UINT32 stream_id) +void tsmf_presentation_free(TSMF_PRESENTATION *presentation) { - TSMF_STREAM* stream; + ArrayList_Remove(presentation_list, presentation); +} +TSMF_STREAM *tsmf_stream_new(TSMF_PRESENTATION *presentation, UINT32 stream_id) +{ + TSMF_STREAM *stream; stream = tsmf_stream_find_by_id(presentation, stream_id); if (stream) @@ -1008,42 +906,42 @@ TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, UINT32 stream_id) return NULL; } - stream = (TSMF_STREAM*) malloc(sizeof(TSMF_STREAM)); - ZeroMemory(stream, sizeof(TSMF_STREAM)); + stream = (TSMF_STREAM *) calloc(1, sizeof(TSMF_STREAM)); + + if (!stream) + { + DEBUG_WARN("Calloc failed"); + return NULL; + } stream->stream_id = stream_id; stream->presentation = presentation; - - stream->started = FALSE; - stream->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - stream->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) tsmf_stream_playback_func, stream, CREATE_SUSPENDED, NULL); - + stream->ready = CreateEvent(NULL, TRUE, TRUE, NULL); stream->sample_list = Queue_New(TRUE, -1, -1); - stream->sample_list->object.fnObjectFree = free; - + stream->sample_list->object.fnObjectFree = tsmf_sample_free; stream->sample_ack_list = Queue_New(TRUE, -1, -1); - stream->sample_ack_list->object.fnObjectFree = free; - + 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); 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) { @@ -1053,11 +951,16 @@ TSMF_STREAM* tsmf_stream_find_by_id(TSMF_PRESENTATION* presentation, UINT32 stre } ArrayList_Unlock(presentation->stream_list); - return (found) ? stream : NULL; } -void tsmf_stream_set_format(TSMF_STREAM* stream, const char* name, wStream* s) +static void tsmf_stream_resync(void *arg) +{ + TSMF_STREAM *stream = arg; + ResetEvent(stream->ready); +} + +void tsmf_stream_set_format(TSMF_STREAM *stream, const char *name, wStream *s) { TS_AM_MEDIA_TYPE mediatype; @@ -1071,17 +974,16 @@ void tsmf_stream_set_format(TSMF_STREAM* stream, const char* name, wStream* s) if (mediatype.MajorType == TSMF_MAJOR_TYPE_VIDEO) { - DEBUG_DVC("video width %d height %d bit_rate %d frame_rate %f codec_data %d", - mediatype.Width, mediatype.Height, mediatype.BitRate, - (double) mediatype.SamplesPerSecond.Numerator / (double) mediatype.SamplesPerSecond.Denominator, - mediatype.ExtraDataSize); + DEBUG_TSMF("video width %d height %d bit_rate %d frame_rate %f codec_data %d", + mediatype.Width, mediatype.Height, mediatype.BitRate, + (double) mediatype.SamplesPerSecond.Numerator / (double) mediatype.SamplesPerSecond.Denominator, + mediatype.ExtraDataSize); } else if (mediatype.MajorType == TSMF_MAJOR_TYPE_AUDIO) { - DEBUG_DVC("audio channel %d sample_rate %d bits_per_sample %d codec_data %d", - mediatype.Channels, mediatype.SamplesPerSecond.Numerator, mediatype.BitsPerSample, - mediatype.ExtraDataSize); - + DEBUG_TSMF("audio channel %d sample_rate %d bits_per_sample %d codec_data %d", + mediatype.Channels, mediatype.SamplesPerSecond.Numerator, mediatype.BitsPerSample, + mediatype.ExtraDataSize); stream->sample_rate = mediatype.SamplesPerSecond.Numerator; stream->channels = mediatype.Channels; stream->bits_per_sample = mediatype.BitsPerSample; @@ -1095,55 +997,83 @@ void tsmf_stream_set_format(TSMF_STREAM* stream, const char* name, wStream* s) stream->height = mediatype.Height; stream->decoder = tsmf_load_decoder(name, &mediatype); tsmf_stream_change_volume(stream, stream->presentation->volume, stream->presentation->muted); + + if (!stream->decoder) + return; + + if (stream->decoder->SetAckFunc) + stream->decoder->SetAckFunc(stream->decoder, tsmf_stream_process_ack, stream); + + if (stream->decoder->SetSyncFunc) + 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); stream->eos = 1; stream->presentation->eos = 1; } -void tsmf_stream_free(TSMF_STREAM* stream) +void _tsmf_stream_free(TSMF_STREAM *stream) { - TSMF_PRESENTATION* presentation = stream->presentation; - + assert(stream); tsmf_stream_stop(stream); tsmf_stream_flush(stream); + SetEvent(stream->stopEvent); - ArrayList_Remove(presentation->stream_list, stream); + if (stream->play_thread) + { + WaitForSingleObject(stream->play_thread, INFINITE); + CloseHandle(stream->play_thread); + stream->play_thread = NULL; + } + + if (stream->ack_thread) + { + WaitForSingleObject(stream->ack_thread, INFINITE); + CloseHandle(stream->ack_thread); + stream->ack_thread = NULL; + } Queue_Free(stream->sample_list); Queue_Free(stream->sample_ack_list); - if (stream->decoder) + if (stream->decoder && stream->decoder->Free) { stream->decoder->Free(stream->decoder); - stream->decoder = 0; + stream->decoder = NULL; } - SetEvent(stream->thread); - + CloseHandle(stream->stopEvent); + CloseHandle(stream->ready); + memset(stream, 0, sizeof(TSMF_STREAM)); free(stream); - stream = 0; } -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_free(TSMF_STREAM *stream) { - TSMF_SAMPLE* sample; + 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) +{ + TSMF_SAMPLE *sample; + SetEvent(stream->ready); - WaitForSingleObject(tsmf_mutex, INFINITE); - if (TERMINATING) + return; + + sample = (TSMF_SAMPLE *) calloc(1, sizeof(TSMF_SAMPLE)); + + if (!sample) { - ReleaseMutex(tsmf_mutex); + DEBUG_WARN("calloc failed!"); return; } - - ReleaseMutex(tsmf_mutex); - - sample = (TSMF_SAMPLE*) calloc(1, sizeof(TSMF_SAMPLE)); sample->sample_id = sample_id; sample->start_time = start_time; @@ -1153,10 +1083,16 @@ void tsmf_stream_push_sample(TSMF_STREAM* stream, IWTSVirtualChannelCallback* pC sample->stream = stream; sample->channel_callback = pChannelCallback; sample->data_size = data_size; - sample->data = malloc(data_size + TSMF_BUFFER_PADDING_SIZE); - ZeroMemory(sample->data, data_size + TSMF_BUFFER_PADDING_SIZE); - CopyMemory(sample->data, data, data_size); + sample->data = calloc(1, data_size + TSMF_BUFFER_PADDING_SIZE); + if (!sample->data) + { + DEBUG_WARN("calloc failed!"); + free(sample); + return; + } + + CopyMemory(sample->data, data, data_size); Queue_Enqueue(stream->sample_list, sample); } @@ -1164,14 +1100,9 @@ void tsmf_stream_push_sample(TSMF_STREAM* stream, IWTSVirtualChannelCallback* pC static void tsmf_signal_handler(int s) { - WaitForSingleObject(tsmf_mutex, INFINITE); TERMINATING = 1; - ReleaseMutex(tsmf_mutex); - ArrayList_Free(presentation_list); - unlink("/tmp/tsmf.tid"); - if (s == SIGINT) { signal(s, SIG_DFL); @@ -1196,11 +1127,9 @@ void tsmf_media_init(void) sigaction(SIGUSR1, &sigtrap, 0); #endif - tsmf_mutex = CreateMutex(NULL, FALSE, NULL); - if (!presentation_list) { presentation_list = ArrayList_New(TRUE); - ArrayList_Object(presentation_list)->fnObjectFree = (OBJECT_FREE_FN) tsmf_presentation_free; + ArrayList_Object(presentation_list)->fnObjectFree = (OBJECT_FREE_FN) _tsmf_presentation_free; } } diff --git a/channels/tsmf/client/tsmf_media.h b/channels/tsmf/client/tsmf_media.h index fe52ccd790ec..116ae088cbef 100644 --- a/channels/tsmf/client/tsmf_media.h +++ b/channels/tsmf/client/tsmf_media.h @@ -32,30 +32,31 @@ typedef struct _TSMF_STREAM TSMF_STREAM; typedef struct _TSMF_SAMPLE TSMF_SAMPLE; -TSMF_PRESENTATION* tsmf_presentation_new(const BYTE* guid, IWTSVirtualChannelCallback* pChannelCallback); -TSMF_PRESENTATION* tsmf_presentation_find_by_id(const BYTE* guid); -void tsmf_presentation_start(TSMF_PRESENTATION* presentation); -void tsmf_presentation_stop(TSMF_PRESENTATION* presentation); -void tsmf_presentation_paused(TSMF_PRESENTATION* presentation); -void tsmf_presentation_restarted(TSMF_PRESENTATION* presentation); -void tsmf_presentation_volume_changed(TSMF_PRESENTATION* presentation, UINT32 newVolume, UINT32 muted); -void tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation, - UINT32 x, UINT32 y, UINT32 width, UINT32 height, - int num_rects, RDP_RECT* rects); -void tsmf_presentation_set_audio_device(TSMF_PRESENTATION* presentation, - const char* name, const char* device); -void tsmf_presentation_flush(TSMF_PRESENTATION* presentation); -void tsmf_presentation_free(TSMF_PRESENTATION* presentation); - -TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, UINT32 stream_id); -TSMF_STREAM* tsmf_stream_find_by_id(TSMF_PRESENTATION* presentation, UINT32 stream_id); -void tsmf_stream_set_format(TSMF_STREAM* stream, const char* name, wStream* s); -void tsmf_stream_end(TSMF_STREAM* stream); -void tsmf_stream_free(TSMF_STREAM* 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); +TSMF_PRESENTATION *tsmf_presentation_new(const BYTE *guid, IWTSVirtualChannelCallback *pChannelCallback); +TSMF_PRESENTATION *tsmf_presentation_find_by_id(const BYTE *guid); +void tsmf_presentation_start(TSMF_PRESENTATION *presentation); +void tsmf_presentation_stop(TSMF_PRESENTATION *presentation); +void tsmf_presentation_sync(TSMF_PRESENTATION *presentation); +void tsmf_presentation_paused(TSMF_PRESENTATION *presentation); +void tsmf_presentation_restarted(TSMF_PRESENTATION *presentation); +void tsmf_presentation_volume_changed(TSMF_PRESENTATION *presentation, UINT32 newVolume, UINT32 muted); +void tsmf_presentation_set_geometry_info(TSMF_PRESENTATION *presentation, + UINT32 x, UINT32 y, UINT32 width, UINT32 height, + int num_rects, RDP_RECT *rects); +void tsmf_presentation_set_audio_device(TSMF_PRESENTATION *presentation, + const char *name, const char *device); +void tsmf_presentation_flush(TSMF_PRESENTATION *presentation); +void tsmf_presentation_free(TSMF_PRESENTATION *presentation); + +TSMF_STREAM *tsmf_stream_new(TSMF_PRESENTATION *presentation, UINT32 stream_id); +TSMF_STREAM *tsmf_stream_find_by_id(TSMF_PRESENTATION *presentation, UINT32 stream_id); +void tsmf_stream_set_format(TSMF_STREAM *stream, const char *name, wStream *s); +void tsmf_stream_end(TSMF_STREAM *stream); +void tsmf_stream_free(TSMF_STREAM *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_media_init(void); diff --git a/channels/tsmf/client/tsmf_types.h b/channels/tsmf/client/tsmf_types.h index 0ccdafae8668..4911209d44af 100644 --- a/channels/tsmf/client/tsmf_types.h +++ b/channels/tsmf/client/tsmf_types.h @@ -28,10 +28,10 @@ #include #include -#ifdef WITH_DEBUG_DVC -#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__) +#ifdef WITH_DEBUG_TSMF +#define DEBUG_TSMF(fmt, ...) DEBUG_CLASS(TSMF, fmt, ## __VA_ARGS__) #else -#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_TSMF(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) #endif typedef struct _TS_AM_MEDIA_TYPE @@ -41,7 +41,7 @@ typedef struct _TS_AM_MEDIA_TYPE int FormatType; UINT32 Width; - UINT32 Height; + UINT32 Height; UINT32 BitRate; struct { @@ -51,7 +51,7 @@ typedef struct _TS_AM_MEDIA_TYPE UINT32 Channels; UINT32 BitsPerSample; UINT32 BlockAlign; - const BYTE* ExtraData; + const BYTE *ExtraData; UINT32 ExtraDataSize; } TS_AM_MEDIA_TYPE; diff --git a/client/X11/generate_argument_docbook.c b/client/X11/generate_argument_docbook.c index dd7b9d9378f6..aaab2239c68c 100644 --- a/client/X11/generate_argument_docbook.c +++ b/client/X11/generate_argument_docbook.c @@ -9,33 +9,28 @@ * the argument struct. */ #include "../common/cmdline.c" -LPSTR tmp = NULL; - LPSTR tr_esc_str(LPCSTR arg) { + LPSTR tmp = NULL; size_t cs = 0, x, ds; size_t s; - - if( NULL == arg ) + if(NULL == arg) return NULL; - s = strlen(arg); - /* Find trailing whitespaces */ - while( (s > 0) && isspace(arg[s-1])) + while((s > 0) && isspace(arg[s-1])) s--; - /* Prepare a initial buffer with the size of the result string. */ - if (s) - tmp = (LPSTR)malloc(s * sizeof(CHAR)); - if( NULL == tmp ) + ds = s + 1; + if(s) + tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); + if(NULL == tmp) { fprintf(stderr, "Could not allocate string buffer."); exit(-2); } - /* Copy character for character and check, if it is necessary to escape. */ - ds = s + 1; + memset(tmp, 0, ds * sizeof(CHAR)); for(x=0; x': ds += 3; tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); - if( NULL == tmp ) + if(NULL == tmp) { fprintf(stderr, "Could not reallocate string buffer."); exit(-4); @@ -69,7 +64,7 @@ LPSTR tr_esc_str(LPCSTR arg) case '\'': ds += 5; tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); - if( NULL == tmp ) + if(NULL == tmp) { fprintf(stderr, "Could not reallocate string buffer."); exit(-5); @@ -84,7 +79,7 @@ LPSTR tr_esc_str(LPCSTR arg) case '"': ds += 5; tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); - if( NULL == tmp ) + if(NULL == tmp) { fprintf(stderr, "Could not reallocate string buffer."); exit(-6); @@ -99,7 +94,7 @@ LPSTR tr_esc_str(LPCSTR arg) case '&': ds += 4; tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); - if( NULL == tmp ) + if(NULL == tmp) { fprintf(stderr, "Could not reallocate string buffer."); exit(-7); @@ -114,11 +109,9 @@ LPSTR tr_esc_str(LPCSTR arg) tmp[cs++] = arg[x]; break; } - /* Assure, the string is '\0' terminated. */ tmp[ds-1] = '\0'; } - return tmp; } @@ -128,51 +121,46 @@ int main(int argc, char *argv[]) size_t x; const char *fname = "xfreerdp-argument.1.xml"; FILE *fp = NULL; - /* Open output file for writing, truncate if existing. */ fp = fopen(fname, "w"); - if( NULL == fp ) + if(NULL == fp) { fprintf(stderr, "Could not open '%s' for writing.", fname); return -1; } - /* The tag used as header in the manpage */ fprintf(fp, "\n"); fprintf(fp, "\tOptions\n"); fprintf(fp, "\t\t\n"); - - /* Iterate over argument struct and write data to docbook 4.5 + /* Iterate over argument struct and write data to docbook 4.5 * compatible XML */ - if( elements < 2 ) + if(elements < 2) { fprintf(stderr, "The argument array 'args' is empty, writing an empty file."); elements = 1; } - for(x=0; xName); + const char *format = tr_esc_str(arg->Format); + const char *text = tr_esc_str((LPSTR) arg->Text); fprintf(fp, "\t\t\t\n"); - if ( COMMAND_LINE_VALUE_REQUIRED == arg->Flags) - fprintf(fp, "\t\t\t\t %s\n", tr_esc_str((LPSTR) arg->Name), tr_esc_str(arg->Format) ); + if(COMMAND_LINE_VALUE_REQUIRED == arg->Flags) + fprintf(fp, "\t\t\t\t %s\n", name, format); else - fprintf(fp, "\t\t\t\t\n", tr_esc_str((LPSTR) arg->Name)); + fprintf(fp, "\t\t\t\t\n", name); fprintf(fp, "\t\t\t\t\n"); - fprintf(fp, "\t\t\t\t\t%s\n", tr_esc_str((LPSTR) arg->Text)); - + fprintf(fp, "\t\t\t\t\t%s\n", format); fprintf(fp, "\t\t\t\t\n"); fprintf(fp, "\t\t\t\n"); + free(name); + free(format); + free(text); } - fprintf(fp, "\t\t\n"); fprintf(fp, "\t\n"); fclose(fp); - - if(NULL != tmp) - free(tmp); - return 0; } diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index e8d09031a927..26a4bb5be3ee 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -102,73 +102,59 @@ static long xv_port = 0; static const size_t password_size = 512; -void xf_transform_window(xfContext* xfc) +void xf_transform_window(xfContext *xfc) { int ret; int w; int h; long supplied; Atom hints_atom; - XSizeHints* size_hints = NULL; - + XSizeHints *size_hints = NULL; hints_atom = XInternAtom(xfc->display, "WM_SIZE_HINTS", 1); - ret = XGetWMSizeHints(xfc->display, xfc->window->handle, size_hints, &supplied, hints_atom); - if(ret == 0) size_hints = XAllocSizeHints(); - w = (xfc->originalWidth * xfc->settings->ScalingFactor) + xfc->offset_x; h = (xfc->originalHeight * xfc->settings->ScalingFactor) + xfc->offset_y; - if(w < 1) w = 1; - if(h < 1) h = 1; - - if (size_hints) + if(size_hints) { size_hints->flags |= PMinSize | PMaxSize; size_hints->min_width = size_hints->max_width = w; size_hints->min_height = size_hints->max_height = h; XSetWMNormalHints(xfc->display, xfc->window->handle, size_hints); XResizeWindow(xfc->display, xfc->window->handle, w, h); - XFree(size_hints); } } -void xf_draw_screen_scaled(xfContext* xfc, int x, int y, int w, int h, BOOL scale) +void xf_draw_screen_scaled(xfContext *xfc, int x, int y, int w, int h, BOOL scale) { #ifdef WITH_XRENDER XTransform transform; Picture windowPicture; Picture primaryPicture; XRenderPictureAttributes pa; - XRenderPictFormat* picFormat; + XRenderPictFormat *picFormat; XRectangle xr; - picFormat = XRenderFindStandardFormat(xfc->display, PictStandardRGB24); pa.subwindow_mode = IncludeInferiors; primaryPicture = XRenderCreatePicture(xfc->display, xfc->primary, picFormat, CPSubwindowMode, &pa); windowPicture = XRenderCreatePicture(xfc->display, xfc->window->handle, picFormat, CPSubwindowMode, &pa); - transform.matrix[0][0] = XDoubleToFixed(1); transform.matrix[0][1] = XDoubleToFixed(0); transform.matrix[0][2] = XDoubleToFixed(0); - transform.matrix[1][0] = XDoubleToFixed(0); transform.matrix[1][1] = XDoubleToFixed(1); transform.matrix[1][2] = XDoubleToFixed(0); - transform.matrix[2][0] = XDoubleToFixed(0); transform.matrix[2][1] = XDoubleToFixed(0); transform.matrix[2][2] = XDoubleToFixed(xfc->settings->ScalingFactor); - - if( (w != 0) && (h != 0) ) + if((w != 0) && (h != 0)) { - if(scale == TRUE) { xr.x = x * xfc->settings->ScalingFactor; @@ -183,54 +169,42 @@ void xf_draw_screen_scaled(xfContext* xfc, int x, int y, int w, int h, BOOL scal xr.width = w; xr.height = h; } - XRenderSetPictureClipRectangles(xfc->display, primaryPicture, 0, 0, &xr, 1); } - XRenderSetPictureTransform(xfc->display, primaryPicture, &transform); - XRenderComposite(xfc->display, PictOpSrc, primaryPicture, 0, windowPicture, 0, 0, 0, 0, xfc->offset_x, xfc->offset_y, xfc->currentWidth, xfc->currentHeight); - XRenderFreePicture(xfc->display, primaryPicture); XRenderFreePicture(xfc->display, windowPicture); - #endif - } -void xf_sw_begin_paint(rdpContext* context) +void xf_sw_begin_paint(rdpContext *context) { - rdpGdi* gdi = context->gdi; + rdpGdi *gdi = context->gdi; gdi->primary->hdc->hwnd->invalid->null = 1; gdi->primary->hdc->hwnd->ninvalid = 0; } -void xf_sw_end_paint(rdpContext* context) +void xf_sw_end_paint(rdpContext *context) { - rdpGdi* gdi; + rdpGdi *gdi; INT32 x, y; UINT32 w, h; - xfContext* xfc = (xfContext*) context; - + xfContext *xfc = (xfContext *) context; gdi = context->gdi; - - if (!xfc->remote_app) + if(!xfc->remote_app) { - if (!xfc->complex_regions) + if(!xfc->complex_regions) { - if (gdi->primary->hdc->hwnd->invalid->null) + if(gdi->primary->hdc->hwnd->invalid->null) return; - x = gdi->primary->hdc->hwnd->invalid->x; y = gdi->primary->hdc->hwnd->invalid->y; w = gdi->primary->hdc->hwnd->invalid->w; h = gdi->primary->hdc->hwnd->invalid->h; - xf_lock_x11(xfc, FALSE); - XPutImage(xfc->display, xfc->primary, xfc->gc, xfc->image, x, y, x, y, w, h); - - if ( (xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y) ) + if((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) { xf_draw_screen_scaled(xfc, x, y, w, h, TRUE); } @@ -238,7 +212,6 @@ void xf_sw_end_paint(rdpContext* context) { XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc, x, y, w, h, x, y); } - xf_unlock_x11(xfc, FALSE); } else @@ -246,26 +219,20 @@ void xf_sw_end_paint(rdpContext* context) int i; int ninvalid; HGDI_RGN cinvalid; - - if (gdi->primary->hdc->hwnd->ninvalid < 1) + if(gdi->primary->hdc->hwnd->ninvalid < 1) return; - ninvalid = gdi->primary->hdc->hwnd->ninvalid; cinvalid = gdi->primary->hdc->hwnd->cinvalid; - xf_lock_x11(xfc, FALSE); - - for (i = 0; i < ninvalid; i++) + for(i = 0; i < ninvalid; i++) { x = cinvalid[i].x; y = cinvalid[i].y; w = cinvalid[i].w; h = cinvalid[i].h; - //combine xfc->primary with xfc->image XPutImage(xfc->display, xfc->primary, xfc->gc, xfc->image, x, y, x, y, w, h); - - if ( (xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y) ) + if((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) { xf_draw_screen_scaled(xfc, x, y, w, h, TRUE); } @@ -274,85 +241,69 @@ void xf_sw_end_paint(rdpContext* context) XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc, x, y, w, h, x, y); } } - XFlush(xfc->display); - xf_unlock_x11(xfc, FALSE); } } else { - if (gdi->primary->hdc->hwnd->invalid->null) + if(gdi->primary->hdc->hwnd->invalid->null) return; - x = gdi->primary->hdc->hwnd->invalid->x; y = gdi->primary->hdc->hwnd->invalid->y; w = gdi->primary->hdc->hwnd->invalid->w; h = gdi->primary->hdc->hwnd->invalid->h; - xf_lock_x11(xfc, FALSE); - xf_rail_paint(xfc, context->rail, x, y, x + w - 1, y + h - 1); - xf_unlock_x11(xfc, FALSE); } } -void xf_sw_desktop_resize(rdpContext* context) +void xf_sw_desktop_resize(rdpContext *context) { - rdpSettings* settings; - xfContext* xfc = (xfContext*) context; - + rdpSettings *settings; + xfContext *xfc = (xfContext *) context; settings = xfc->instance->settings; - xf_lock_x11(xfc, TRUE); - - if (!xfc->fullscreen) + if(!xfc->fullscreen) { - rdpGdi* gdi = context->gdi; + rdpGdi *gdi = context->gdi; gdi_resize(gdi, xfc->width, xfc->height); - - if (xfc->image) + if(xfc->image) { xfc->image->data = NULL; XDestroyImage(xfc->image); xfc->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, - (char*) gdi->primary_buffer, gdi->width, gdi->height, xfc->scanline_pad, 0); + (char *) gdi->primary_buffer, gdi->width, gdi->height, xfc->scanline_pad, 0); } } - xf_unlock_x11(xfc, TRUE); } -void xf_hw_begin_paint(rdpContext* context) +void xf_hw_begin_paint(rdpContext *context) { - xfContext* xfc = (xfContext*) context; - + xfContext *xfc = (xfContext *) context; xfc->hdc->hwnd->invalid->null = 1; xfc->hdc->hwnd->ninvalid = 0; } -void xf_hw_end_paint(rdpContext* context) +void xf_hw_end_paint(rdpContext *context) { INT32 x, y; UINT32 w, h; - xfContext* xfc = (xfContext*) context; - - if (!xfc->remote_app) + xfContext *xfc = (xfContext *) context; + if(!xfc->remote_app) { - if (!xfc->complex_regions) + if(!xfc->complex_regions) { - if (xfc->hdc->hwnd->invalid->null) + if(xfc->hdc->hwnd->invalid->null) return; - x = xfc->hdc->hwnd->invalid->x; y = xfc->hdc->hwnd->invalid->y; w = xfc->hdc->hwnd->invalid->w; h = xfc->hdc->hwnd->invalid->h; - xf_lock_x11(xfc, FALSE); - - if ( (xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y) ) + if((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) { xf_draw_screen_scaled(xfc, x, y, w, h, TRUE); } @@ -360,7 +311,6 @@ void xf_hw_end_paint(rdpContext* context) { XCopyArea(xfc->display, xfc->primary, xfc->drawable, xfc->gc, x, y, w, h, x, y); } - xf_unlock_x11(xfc, FALSE); } else @@ -368,23 +318,18 @@ void xf_hw_end_paint(rdpContext* context) int i; int ninvalid; HGDI_RGN cinvalid; - - if (xfc->hdc->hwnd->ninvalid < 1) + if(xfc->hdc->hwnd->ninvalid < 1) return; - ninvalid = xfc->hdc->hwnd->ninvalid; cinvalid = xfc->hdc->hwnd->cinvalid; - xf_lock_x11(xfc, FALSE); - - for (i = 0; i < ninvalid; i++) + for(i = 0; i < ninvalid; i++) { x = cinvalid[i].x; y = cinvalid[i].y; w = cinvalid[i].w; h = cinvalid[i].h; - - if ( (xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y) ) + if((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) { xf_draw_screen_scaled(xfc, x, y, w, h, TRUE); } @@ -393,58 +338,44 @@ void xf_hw_end_paint(rdpContext* context) XCopyArea(xfc->display, xfc->primary, xfc->drawable, xfc->gc, x, y, w, h, x, y); } } - XFlush(xfc->display); - xf_unlock_x11(xfc, FALSE); } } else { - if (xfc->hdc->hwnd->invalid->null) + if(xfc->hdc->hwnd->invalid->null) return; - x = xfc->hdc->hwnd->invalid->x; y = xfc->hdc->hwnd->invalid->y; w = xfc->hdc->hwnd->invalid->w; h = xfc->hdc->hwnd->invalid->h; - xf_lock_x11(xfc, FALSE); - xf_rail_paint(xfc, context->rail, x, y, x + w - 1, y + h - 1); - xf_unlock_x11(xfc, FALSE); } } -void xf_hw_desktop_resize(rdpContext* context) +void xf_hw_desktop_resize(rdpContext *context) { BOOL same; - rdpSettings* settings; - xfContext* xfc = (xfContext*) context; - + rdpSettings *settings; + xfContext *xfc = (xfContext *) context; settings = xfc->instance->settings; - xf_lock_x11(xfc, TRUE); - - if (!xfc->fullscreen) + if(!xfc->fullscreen) { xfc->width = settings->DesktopWidth; xfc->height = settings->DesktopHeight; - - if (xfc->window) + if(xfc->window) xf_ResizeDesktopWindow(xfc, xfc->window, settings->DesktopWidth, settings->DesktopHeight); - - if (xfc->primary) + if(xfc->primary) { same = (xfc->primary == xfc->drawing) ? TRUE : FALSE; - XFreePixmap(xfc->display, xfc->primary); - xfc->primary = XCreatePixmap(xfc->display, xfc->drawable, - xfc->width, xfc->height, xfc->depth); - - if (same) + xfc->width, xfc->height, xfc->depth); + if(same) xfc->drawing = xfc->primary; } } @@ -455,65 +386,51 @@ void xf_hw_desktop_resize(rdpContext* context) XSetForeground(xfc->display, xfc->gc, 0); XFillRectangle(xfc->display, xfc->drawable, xfc->gc, 0, 0, xfc->width, xfc->height); } - xf_unlock_x11(xfc, TRUE); } -BOOL xf_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, int* wcount) +BOOL xf_get_fds(freerdp *instance, void **rfds, int *rcount, void **wfds, int *wcount) { - xfContext* xfc = (xfContext*) instance->context; - - rfds[*rcount] = (void*)(long)(xfc->xfds); + xfContext *xfc = (xfContext *) instance->context; + rfds[*rcount] = (void *)(long)(xfc->xfds); (*rcount)++; - return TRUE; } -BOOL xf_process_x_events(freerdp* instance) +BOOL xf_process_x_events(freerdp *instance) { BOOL status; XEvent xevent; int pending_status; - xfContext* xfc = (xfContext*) instance->context; - + xfContext *xfc = (xfContext *) instance->context; status = TRUE; pending_status = TRUE; - - while (pending_status) + while(pending_status) { xf_lock_x11(xfc, FALSE); - pending_status = XPending(xfc->display); - xf_unlock_x11(xfc, FALSE); - - if (pending_status) + if(pending_status) { ZeroMemory(&xevent, sizeof(xevent)); - XNextEvent(xfc->display, &xevent); status = xf_event_process(instance, &xevent); - - if (!status) + if(!status) return status; } } - return status; } -void xf_create_window(xfContext* xfc) +void xf_create_window(xfContext *xfc) { XEvent xevent; int width, height; - char* windowTitle; - + char *windowTitle; ZeroMemory(&xevent, sizeof(xevent)); - width = xfc->width; height = xfc->height; - - if (!xfc->remote_app) + if(!xfc->remote_app) { xfc->attribs.background_pixel = BlackPixelOfScreen(xfc->screen); xfc->attribs.border_pixel = WhitePixelOfScreen(xfc->screen); @@ -522,30 +439,26 @@ void xf_create_window(xfContext* xfc) xfc->attribs.colormap = xfc->colormap; xfc->attribs.bit_gravity = NorthWestGravity; xfc->attribs.win_gravity = NorthWestGravity; - - if (xfc->instance->settings->WindowTitle) + if(xfc->instance->settings->WindowTitle) { windowTitle = _strdup(xfc->instance->settings->WindowTitle); } - else if (xfc->instance->settings->ServerPort == 3389) - { - windowTitle = malloc(1 + sizeof("FreeRDP: ") + strlen(xfc->instance->settings->ServerHostname)); - sprintf(windowTitle, "FreeRDP: %s", xfc->instance->settings->ServerHostname); - } else - { - windowTitle = malloc(1 + sizeof("FreeRDP: ") + strlen(xfc->instance->settings->ServerHostname) + sizeof(":00000")); - sprintf(windowTitle, "FreeRDP: %s:%i", xfc->instance->settings->ServerHostname, xfc->instance->settings->ServerPort); - } - + if(xfc->instance->settings->ServerPort == 3389) + { + windowTitle = malloc(1 + sizeof("FreeRDP: ") + strlen(xfc->instance->settings->ServerHostname)); + sprintf(windowTitle, "FreeRDP: %s", xfc->instance->settings->ServerHostname); + } + else + { + windowTitle = malloc(1 + sizeof("FreeRDP: ") + strlen(xfc->instance->settings->ServerHostname) + sizeof(":00000")); + sprintf(windowTitle, "FreeRDP: %s:%i", xfc->instance->settings->ServerHostname, xfc->instance->settings->ServerPort); + } xfc->window = xf_CreateDesktopWindow(xfc, windowTitle, width, height, xfc->settings->Decorations); free(windowTitle); - - if (xfc->fullscreen) + if(xfc->fullscreen) xf_SetWindowFullscreen(xfc, xfc->window, xfc->fullscreen); - xfc->unobscured = (xevent.xvisibility.state == VisibilityUnobscured); - XSetWMProtocols(xfc->display, xfc->window->handle, &(xfc->WM_DELETE_WINDOW), 1); xfc->drawable = xfc->window->handle; } @@ -555,81 +468,71 @@ void xf_create_window(xfContext* xfc) } } -void xf_toggle_fullscreen(xfContext* xfc) +void xf_toggle_fullscreen(xfContext *xfc) { Pixmap contents = 0; WindowStateChangeEventArgs e; - xf_lock_x11(xfc, TRUE); - contents = XCreatePixmap(xfc->display, xfc->window->handle, xfc->width, xfc->height, xfc->depth); XCopyArea(xfc->display, xfc->primary, contents, xfc->gc, 0, 0, xfc->width, xfc->height, 0, 0); - XDestroyWindow(xfc->display, xfc->window->handle); xfc->fullscreen = (xfc->fullscreen) ? FALSE : TRUE; xf_create_window(xfc); - XCopyArea(xfc->display, contents, xfc->primary, xfc->gc, 0, 0, xfc->width, xfc->height, 0, 0); XFreePixmap(xfc->display, contents); - xf_unlock_x11(xfc, TRUE); - EventArgsInit(&e, "xfreerdp"); e.state = xfc->fullscreen ? FREERDP_WINDOW_STATE_FULLSCREEN : 0; - PubSub_OnWindowStateChange(((rdpContext*) xfc)->pubSub, xfc, &e); + PubSub_OnWindowStateChange(((rdpContext *) xfc)->pubSub, xfc, &e); } -void xf_lock_x11(xfContext* xfc, BOOL display) +void xf_lock_x11(xfContext *xfc, BOOL display) { - if (!xfc->UseXThreads) + if(!xfc->UseXThreads) { WaitForSingleObject(xfc->mutex, INFINITE); } else { - if (display) + if(display) XLockDisplay(xfc->display); } } -void xf_unlock_x11(xfContext* xfc, BOOL display) +void xf_unlock_x11(xfContext *xfc, BOOL display) { - if (!xfc->UseXThreads) + if(!xfc->UseXThreads) { ReleaseMutex(xfc->mutex); } else { - if (display) + if(display) XUnlockDisplay(xfc->display); } } -BOOL xf_get_pixmap_info(xfContext* xfc) +BOOL xf_get_pixmap_info(xfContext *xfc) { int i; int vi_count; int pf_count; - XVisualInfo* vi; - XVisualInfo* vis; + XVisualInfo *vi; + XVisualInfo *vis; XVisualInfo template; - XPixmapFormatValues* pf; - XPixmapFormatValues* pfs; + XPixmapFormatValues *pf; + XPixmapFormatValues *pfs; XWindowAttributes window_attributes; - pfs = XListPixmapFormats(xfc->display, &pf_count); - - if (pfs == NULL) + if(pfs == NULL) { fprintf(stderr, "xf_get_pixmap_info: XListPixmapFormats failed\n"); return 1; } - - for (i = 0; i < pf_count; i++) + for(i = 0; i < pf_count; i++) { pf = pfs + i; - - if (pf->depth == xfc->depth) + if(pf->depth == xfc->depth) { xfc->bpp = pf->bits_per_pixel; xfc->scanline_pad = pf->scanline_pad; @@ -637,104 +540,86 @@ BOOL xf_get_pixmap_info(xfContext* xfc) } } XFree(pfs); - ZeroMemory(&template, sizeof(template)); template.class = TrueColor; template.screen = xfc->screen_number; - - if (XGetWindowAttributes(xfc->display, RootWindowOfScreen(xfc->screen), &window_attributes) == 0) + if(XGetWindowAttributes(xfc->display, RootWindowOfScreen(xfc->screen), &window_attributes) == 0) { fprintf(stderr, "xf_get_pixmap_info: XGetWindowAttributes failed\n"); return FALSE; } - vis = XGetVisualInfo(xfc->display, VisualClassMask | VisualScreenMask, &template, &vi_count); - - if (vis == NULL) + if(vis == NULL) { fprintf(stderr, "xf_get_pixmap_info: XGetVisualInfo failed\n"); return FALSE; } - vi = NULL; - for (i = 0; i < vi_count; i++) + for(i = 0; i < vi_count; i++) { vi = vis + i; - - if (vi->visual == window_attributes.visual) + if(vi->visual == window_attributes.visual) { xfc->visual = vi->visual; break; } } - - if (vi) + if(vi) { /* * Detect if the server visual has an inverted colormap * (BGR vs RGB, or red being the least significant byte) */ - - if (vi->red_mask & 0xFF) + if(vi->red_mask & 0xFF) { xfc->clrconv->invert = TRUE; } } - XFree(vis); - - if ((xfc->visual == NULL) || (xfc->scanline_pad == 0)) + if((xfc->visual == NULL) || (xfc->scanline_pad == 0)) { return FALSE; } - return TRUE; } -static int (*_def_error_handler)(Display*, XErrorEvent*); +static int (*_def_error_handler)(Display *, XErrorEvent *); -int xf_error_handler(Display* d, XErrorEvent* ev) +int xf_error_handler(Display *d, XErrorEvent *ev) { char buf[256]; int do_abort = TRUE; - XGetErrorText(d, ev->error_code, buf, sizeof(buf)); fprintf(stderr, "%s", buf); - - if (do_abort) + if(do_abort) abort(); - _def_error_handler(d, ev); - return FALSE; } -int _xf_error_handler(Display* d, XErrorEvent* ev) +int _xf_error_handler(Display *d, XErrorEvent *ev) { /* - * ungrab the keyboard, in case a debugger is running in - * another window. This make xf_error_handler() a potential - * debugger breakpoint. - */ + * ungrab the keyboard, in case a debugger is running in + * another window. This make xf_error_handler() a potential + * debugger breakpoint. + */ XUngrabKeyboard(d, CurrentTime); return xf_error_handler(d, ev); } static void xf_post_disconnect(freerdp *instance) { - xfContext* xfc = (xfContext*) instance->context; - + xfContext *xfc = (xfContext *) instance->context; assert(NULL != instance); assert(NULL != xfc); assert(NULL != instance->settings); - - if (xfc->mutex) + if(xfc->mutex) { WaitForSingleObject(xfc->mutex, INFINITE); CloseHandle(xfc->mutex); xfc->mutex = NULL; } - xf_monitors_free(xfc, instance->settings); } @@ -748,21 +633,17 @@ static void xf_post_disconnect(freerdp *instance) * @return TRUE if successful. FALSE otherwise. * Can exit with error code XF_EXIT_PARSE_ARGUMENTS if there is an error in the parameters. */ -BOOL xf_pre_connect(freerdp* instance) +BOOL xf_pre_connect(freerdp *instance) { - rdpChannels* channels; - rdpSettings* settings; - xfContext* xfc = (xfContext*) instance->context; - + rdpChannels *channels; + rdpSettings *settings; + xfContext *xfc = (xfContext *) instance->context; xfc->settings = instance->settings; xfc->instance = instance; - settings = instance->settings; channels = instance->context->channels; - settings->OsMajorType = OSMAJORTYPE_UNIX; settings->OsMinorType = OSMINORTYPE_NATIVE_XSERVER; - ZeroMemory(settings->OrderSupport, 32); settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE; settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE; @@ -788,55 +669,44 @@ BOOL xf_pre_connect(freerdp* instance) settings->OrderSupport[NEG_POLYGON_CB_INDEX] = (settings->SoftwareGdi) ? FALSE : TRUE; settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE; settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE; - xfc->UseXThreads = TRUE; - - if (xfc->UseXThreads) + if(xfc->UseXThreads) { - if (!XInitThreads()) + if(!XInitThreads()) { fprintf(stderr, "warning: XInitThreads() failure\n"); xfc->UseXThreads = FALSE; } } - xfc->display = XOpenDisplay(NULL); - - if (!xfc->display) + if(!xfc->display) { fprintf(stderr, "xf_pre_connect: failed to open display: %s\n", XDisplayName(NULL)); fprintf(stderr, "Please check that the $DISPLAY environment variable is properly set.\n"); return FALSE; } - - if (xfc->debug) + if(xfc->debug) { fprintf(stderr, "Enabling X11 debug mode.\n"); XSynchronize(xfc->display, TRUE); _def_error_handler = XSetErrorHandler(_xf_error_handler); } - xfc->mutex = CreateMutex(NULL, FALSE, NULL); - PubSub_SubscribeChannelConnected(instance->context->pubSub, - (pChannelConnectedEventHandler) xf_OnChannelConnectedEventHandler); - + (pChannelConnectedEventHandler) xf_OnChannelConnectedEventHandler); PubSub_SubscribeChannelDisconnected(instance->context->pubSub, - (pChannelDisconnectedEventHandler) xf_OnChannelDisconnectedEventHandler); - + (pChannelDisconnectedEventHandler) xf_OnChannelDisconnectedEventHandler); freerdp_client_load_addins(channels, instance->settings); - freerdp_channels_pre_connect(channels, instance); - - if (settings->AuthenticationOnly) + if(settings->AuthenticationOnly) { /* Check --authonly has a username and password. */ - if (settings->Username == NULL) + if(settings->Username == NULL) { fprintf(stderr, "--authonly, but no -u username. Please provide one.\n"); return FALSE; } - if (settings->Password == NULL) + if(settings->Password == NULL) { fprintf(stderr, "--authonly, but no -p password. Please provide one.\n"); return FALSE; @@ -845,7 +715,6 @@ BOOL xf_pre_connect(freerdp* instance) /* Avoid XWindows initialization and configuration below. */ return TRUE; } - xfc->_NET_WM_ICON = XInternAtom(xfc->display, "_NET_WM_ICON", False); xfc->_MOTIF_WM_HINTS = XInternAtom(xfc->display, "_MOTIF_WM_HINTS", False); xfc->_NET_CURRENT_DESKTOP = XInternAtom(xfc->display, "_NET_CURRENT_DESKTOP", False); @@ -853,7 +722,6 @@ BOOL xf_pre_connect(freerdp* instance) xfc->_NET_WM_STATE = XInternAtom(xfc->display, "_NET_WM_STATE", False); xfc->_NET_WM_STATE_FULLSCREEN = XInternAtom(xfc->display, "_NET_WM_STATE_FULLSCREEN", False); xfc->_NET_WM_WINDOW_TYPE = XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE", False); - xfc->_NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE_NORMAL", False); xfc->_NET_WM_WINDOW_TYPE_DIALOG = XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE_DIALOG", False); xfc->_NET_WM_WINDOW_TYPE_POPUP = XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE_POPUP", False); @@ -863,30 +731,22 @@ BOOL xf_pre_connect(freerdp* instance) xfc->_NET_WM_STATE_SKIP_PAGER = XInternAtom(xfc->display, "_NET_WM_STATE_SKIP_PAGER", False); xfc->_NET_WM_MOVERESIZE = XInternAtom(xfc->display, "_NET_WM_MOVERESIZE", False); xfc->_NET_MOVERESIZE_WINDOW = XInternAtom(xfc->display, "_NET_MOVERESIZE_WINDOW", False); - xfc->WM_PROTOCOLS = XInternAtom(xfc->display, "WM_PROTOCOLS", False); xfc->WM_DELETE_WINDOW = XInternAtom(xfc->display, "WM_DELETE_WINDOW", False); xfc->WM_STATE = XInternAtom(xfc->display, "WM_STATE", False); - xf_keyboard_init(xfc); - xfc->clrconv = freerdp_clrconv_new(CLRCONV_ALPHA); - instance->context->cache = cache_new(instance->settings); - xfc->xfds = ConnectionNumber(xfc->display); xfc->screen_number = DefaultScreen(xfc->display); xfc->screen = ScreenOfDisplay(xfc->display, xfc->screen_number); xfc->depth = DefaultDepthOfScreen(xfc->screen); xfc->big_endian = (ImageByteOrder(xfc->display) == MSBFirst); - xfc->complex_regions = TRUE; xfc->fullscreen = settings->Fullscreen; xfc->grab_keyboard = settings->GrabKeyboard; xfc->fullscreen_toggle = settings->ToggleFullscreen; - xf_detect_monitors(xfc, settings); - return TRUE; } @@ -895,107 +755,82 @@ BOOL xf_pre_connect(freerdp* instance) * It will be called only if the connection was initialized properly, and will continue the initialization based on the * newly created connection. */ -BOOL xf_post_connect(freerdp* instance) +BOOL xf_post_connect(freerdp *instance) { XGCValues gcv; - rdpCache* cache; - rdpChannels* channels; - rdpSettings* settings; + rdpCache *cache; + rdpChannels *channels; + rdpSettings *settings; ResizeWindowEventArgs e; - RFX_CONTEXT* rfx_context = NULL; - NSC_CONTEXT* nsc_context = NULL; - xfContext* xfc = (xfContext*) instance->context; - + RFX_CONTEXT *rfx_context = NULL; + NSC_CONTEXT *nsc_context = NULL; + xfContext *xfc = (xfContext *) instance->context; cache = instance->context->cache; channels = instance->context->channels; settings = instance->settings; - - if (!xf_get_pixmap_info(xfc)) + if(!xf_get_pixmap_info(xfc)) return FALSE; - xf_register_graphics(instance->context->graphics); - - if (xfc->settings->SoftwareGdi) + if(xfc->settings->SoftwareGdi) { - rdpGdi* gdi; + rdpGdi *gdi; UINT32 flags; - flags = CLRCONV_ALPHA; - - if (xfc->bpp > 16) + if(xfc->bpp > 16) flags |= CLRBUF_32BPP; else flags |= CLRBUF_16BPP; - gdi_init(instance, flags, NULL); gdi = instance->context->gdi; xfc->primary_buffer = gdi->primary_buffer; - rfx_context = gdi->rfx_context; } else { xfc->srcBpp = instance->settings->ColorDepth; xf_gdi_register_update_callbacks(instance->update); - xfc->hdc = gdi_CreateDC(xfc->clrconv, xfc->bpp); - - if (instance->settings->RemoteFxCodec) + if(instance->settings->RemoteFxCodec) { - rfx_context = (void*) rfx_context_new(FALSE); + rfx_context = (void *) rfx_context_new(FALSE); xfc->rfx_context = rfx_context; } - - if (instance->settings->NSCodec) + if(instance->settings->NSCodec) { - nsc_context = (void*) nsc_context_new(); + nsc_context = (void *) nsc_context_new(); xfc->nsc_context = nsc_context; } } - xfc->originalWidth = settings->DesktopWidth; xfc->originalHeight = settings->DesktopHeight; xfc->currentWidth = xfc->originalWidth; xfc->currentHeight = xfc->originalWidth; xfc->settings->ScalingFactor = 1.0; - xfc->offset_x = 0; xfc->offset_y = 0; - xfc->width = settings->DesktopWidth; xfc->height = settings->DesktopHeight; - - if (settings->RemoteApplicationMode) + if(settings->RemoteApplicationMode) xfc->remote_app = TRUE; - xf_create_window(xfc); - ZeroMemory(&gcv, sizeof(gcv)); - - if (xfc->modifierMap) + if(xfc->modifierMap) XFreeModifiermap(xfc->modifierMap); - xfc->modifierMap = XGetModifierMapping(xfc->display); - xfc->gc = XCreateGC(xfc->display, xfc->drawable, GCGraphicsExposures, &gcv); xfc->primary = XCreatePixmap(xfc->display, xfc->drawable, xfc->width, xfc->height, xfc->depth); xfc->drawing = xfc->primary; - xfc->bitmap_mono = XCreatePixmap(xfc->display, xfc->drawable, 8, 8, 1); xfc->gc_mono = XCreateGC(xfc->display, xfc->bitmap_mono, GCGraphicsExposures, &gcv); - XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); XSetForeground(xfc->display, xfc->gc, BlackPixelOfScreen(xfc->screen)); XFillRectangle(xfc->display, xfc->primary, xfc->gc, 0, 0, xfc->width, xfc->height); XFlush(xfc->display); - xfc->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, - (char*) xfc->primary_buffer, xfc->width, xfc->height, xfc->scanline_pad, 0); - - xfc->bmp_codec_none = (BYTE*) malloc(64 * 64 * 4); - - if (xfc->settings->SoftwareGdi) + (char *) xfc->primary_buffer, xfc->width, xfc->height, xfc->scanline_pad, 0); + xfc->bmp_codec_none = (BYTE *) malloc(64 * 64 * 4); + if(xfc->settings->SoftwareGdi) { instance->update->BeginPaint = xf_sw_begin_paint; instance->update->EndPaint = xf_sw_end_paint; @@ -1007,10 +842,8 @@ BOOL xf_post_connect(freerdp* instance) instance->update->EndPaint = xf_hw_end_paint; instance->update->DesktopResize = xf_hw_desktop_resize; } - pointer_cache_register_callbacks(instance->update); - - if (!xfc->settings->SoftwareGdi) + if(!xfc->settings->SoftwareGdi) { glyph_cache_register_callbacks(instance->update); brush_cache_register_callbacks(instance->update); @@ -1018,22 +851,16 @@ BOOL xf_post_connect(freerdp* instance) offscreen_cache_register_callbacks(instance->update); palette_cache_register_callbacks(instance->update); } - instance->context->rail = rail_new(instance->settings); rail_register_update_callbacks(instance->context->rail, instance->update); xf_rail_register_callbacks(xfc, instance->context->rail); - freerdp_channels_post_connect(channels, instance); - xf_tsmf_init(xfc, xv_port); - xf_cliprdr_init(xfc, channels); - EventArgsInit(&e, "xfreerdp"); e.width = settings->DesktopWidth; e.height = settings->DesktopHeight; - PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e); - + PubSub_OnResizeWindow(((rdpContext *) xfc)->pubSub, xfc, &e); return TRUE; } @@ -1049,15 +876,13 @@ BOOL xf_post_connect(freerdp* instance) * @param domain - unused * @return TRUE if a password was successfully entered. See freerdp_passphrase_read() for more details. */ -BOOL xf_authenticate(freerdp* instance, char** username, char** password, char** domain) +BOOL xf_authenticate(freerdp *instance, char **username, char **password, char **domain) { // FIXME: seems this callback may be called when 'username' is not known. // But it doesn't do anything to fix it... *password = malloc(password_size * sizeof(char)); - - if (freerdp_passphrase_read("Password: ", *password, password_size, instance->settings->CredentialsFromStdin) == NULL) + if(freerdp_passphrase_read("Password: ", *password, password_size, instance->settings->CredentialsFromStdin) == NULL) return FALSE; - return TRUE; } @@ -1071,346 +896,273 @@ BOOL xf_authenticate(freerdp* instance, char** username, char** password, char** * @param fingerprint * @return TRUE if the certificate is trusted. FALSE otherwise. */ -BOOL xf_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint) +BOOL xf_verify_certificate(freerdp *instance, char *subject, char *issuer, char *fingerprint) { char answer; - printf("Certificate details:\n"); printf("\tSubject: %s\n", subject); printf("\tIssuer: %s\n", issuer); printf("\tThumbprint: %s\n", fingerprint); printf("The above X.509 certificate could not be verified, possibly because you do not have " - "the CA certificate in your certificate store, or the certificate has expired. " - "Please look at the documentation on how to create local certificate store for a private CA.\n"); - - while (1) + "the CA certificate in your certificate store, or the certificate has expired. " + "Please look at the documentation on how to create local certificate store for a private CA.\n"); + while(1) { printf("Do you trust the above certificate? (Y/N) "); answer = fgetc(stdin); - - if (feof(stdin)) + if(feof(stdin)) { printf("\nError: Could not read answer from stdin."); - if (instance->settings->CredentialsFromStdin) + if(instance->settings->CredentialsFromStdin) printf(" - Run without parameter \"--from-stdin\" to set trust."); printf("\n"); return FALSE; } - - if (answer == 'y' || answer == 'Y') + if(answer == 'y' || answer == 'Y') { return TRUE; } - else if (answer == 'n' || answer == 'N') - { - break; - } + else + if(answer == 'n' || answer == 'N') + { + break; + } printf("\n"); } - return FALSE; } -int xf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type) +int xf_logon_error_info(freerdp *instance, UINT32 data, UINT32 type) { - xfContext* xfc = (xfContext*) instance->context; - + xfContext *xfc = (xfContext *) instance->context; xf_rail_disable_remoteapp_mode(xfc); - return 1; } -void xf_process_channel_event(rdpChannels* channels, freerdp* instance) +void xf_process_channel_event(rdpChannels *channels, freerdp *instance) { - xfContext* xfc; - wMessage* event; - - xfc = (xfContext*) instance->context; - + xfContext *xfc; + wMessage *event; + xfc = (xfContext *) instance->context; event = freerdp_channels_pop_event(channels); - - if (event) + if(event) { - switch (GetMessageClass(event->id)) + switch(GetMessageClass(event->id)) { case RailChannel_Class: xf_process_rail_event(xfc, channels, event); break; - case TsmfChannel_Class: xf_process_tsmf_event(xfc, event); break; - case CliprdrChannel_Class: xf_process_cliprdr_event(xfc, event); break; - case RdpeiChannel_Class: xf_process_rdpei_event(xfc, event); break; - default: break; } - freerdp_event_free(event); } } -void xf_window_free(xfContext* xfc) +void xf_window_free(xfContext *xfc) { - rdpContext* context = (rdpContext*) xfc; - + rdpContext *context = (rdpContext *) xfc; xf_keyboard_free(xfc); - - if (xfc->gc) + if(xfc->gc) { XFreeGC(xfc->display, xfc->gc); xfc->gc = 0; } - - if (xfc->gc_mono) + if(xfc->gc_mono) { XFreeGC(xfc->display, xfc->gc_mono); xfc->gc_mono = 0; } - - if (xfc->window) + if(xfc->window) { xf_DestroyWindow(xfc, xfc->window); xfc->window = NULL; } - - if (xfc->primary) + if(xfc->primary) { XFreePixmap(xfc->display, xfc->primary); xfc->primary = 0; } - - if (xfc->bitmap_mono) + if(xfc->bitmap_mono) { XFreePixmap(xfc->display, xfc->bitmap_mono); xfc->bitmap_mono = 0; } - - if (xfc->image) + if(xfc->image) { xfc->image->data = NULL; XDestroyImage(xfc->image); xfc->image = NULL; } - - if (context->cache) + if(context->cache) { cache_free(context->cache); context->cache = NULL; } - - if (context->rail) + if(context->rail) { rail_free(context->rail); context->rail = NULL; } - - if (xfc->rfx_context) + if(xfc->rfx_context) { rfx_context_free(xfc->rfx_context); xfc->rfx_context = NULL; } - - if (xfc->nsc_context) + if(xfc->nsc_context) { nsc_context_free(xfc->nsc_context); xfc->nsc_context = NULL; } - - if (xfc->clrconv) + if(xfc->clrconv) { freerdp_clrconv_free(xfc->clrconv); xfc->clrconv = NULL; } - - if (xfc->hdc) + if(xfc->hdc) gdi_DeleteDC(xfc->hdc); - - if (xfc->xv_context) + if(xfc->xv_context) { xf_tsmf_uninit(xfc); xfc->xv_context = NULL; } - - if (xfc->clipboard_context) + if(xfc->clipboard_context) { xf_cliprdr_uninit(xfc); xfc->clipboard_context = NULL; } } -void* xf_update_thread(void* arg) +void *xf_update_thread(void *arg) { int status; wMessage message; - wMessageQueue* queue; - freerdp* instance = (freerdp*) arg; - - assert( NULL != instance); - + wMessageQueue *queue; + freerdp *instance = (freerdp *) arg; + assert(NULL != instance); status = 1; queue = freerdp_get_message_queue(instance, FREERDP_UPDATE_MESSAGE_QUEUE); - - while (MessageQueue_Wait(queue)) + while(MessageQueue_Wait(queue)) { - while (MessageQueue_Peek(queue, &message, TRUE)) + while(MessageQueue_Peek(queue, &message, TRUE)) { status = freerdp_message_queue_process_message(instance, FREERDP_UPDATE_MESSAGE_QUEUE, &message); - - if (!status) + if(!status) break; } - - if (!status) + if(!status) break; } - ExitThread(0); return NULL; } -void* xf_input_thread(void* arg) +void *xf_input_thread(void *arg) { xfContext *xfc; - HANDLE event[2]; + HANDLE event; XEvent xevent; - wMessageQueue* queue; + wMessageQueue *queue; int pending_status = 1; int process_status = 1; - freerdp* instance = (freerdp*) arg; + freerdp *instance = (freerdp *) arg; assert(NULL != instance); - - xfc = (xfContext*) instance->context; + xfc = (xfContext *) instance->context; assert(NULL != xfc); - queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); - event[0] = CreateFileDescriptorEvent(NULL, FALSE, FALSE, xfc->xfds); - event[1] = MessageQueue_Event(queue); - while(TRUE) + event = CreateFileDescriptorEvent(NULL, FALSE, FALSE, xfc->xfds); + while(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0) { - DWORD ev = WaitForMultipleObjects(2, event, FALSE, INFINITE); - - if (ev == WAIT_OBJECT_0) + do { - do + xf_lock_x11(xfc, FALSE); + pending_status = XPending(xfc->display); + xf_unlock_x11(xfc, FALSE); + if(pending_status) { xf_lock_x11(xfc, FALSE); - - pending_status = XPending(xfc->display); - + ZeroMemory(&xevent, sizeof(xevent)); + XNextEvent(xfc->display, &xevent); + process_status = xf_event_process(instance, &xevent); xf_unlock_x11(xfc, FALSE); - - if (pending_status) - { - xf_lock_x11(xfc, FALSE); - - ZeroMemory(&xevent, sizeof(xevent)); - XNextEvent(xfc->display, &xevent); - process_status = xf_event_process(instance, &xevent); - - xf_unlock_x11(xfc, FALSE); - - if (!process_status) - break; - } + if(!process_status) + break; } - while(pending_status && WaitForSingleObject(event[1], 0) != WAIT_OBJECT_0); - if(!process_status) - break; - } - else if (ev == WAIT_OBJECT_0 + 1) - { - wMessage msg; - MessageQueue_Peek(queue, &msg, FALSE); - - if (msg.id == WMQ_QUIT) - break; } + while(pending_status); + if(!process_status) + break; } - MessageQueue_PostQuit(queue, 0); ExitThread(0); return NULL; } -void* xf_channels_thread(void* arg) +void *xf_channels_thread(void *arg) { int status; - xfContext* xfc; + xfContext *xfc; HANDLE event; - rdpChannels* channels; - freerdp* instance = (freerdp*) arg; + rdpChannels *channels; + freerdp *instance = (freerdp *) arg; assert(NULL != instance); - - xfc = (xfContext*) instance->context; + xfc = (xfContext *) instance->context; assert(NULL != xfc); - channels = instance->context->channels; event = freerdp_channels_get_event_handle(instance); - - while (WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0) + while(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0) { status = freerdp_channels_process_pending_messages(instance); - if (!status) + if(!status) break; - xf_process_channel_event(channels, instance); } - ExitThread(0); return NULL; } -BOOL xf_auto_reconnect(freerdp* instance) +BOOL xf_auto_reconnect(freerdp *instance) { - xfContext* xfc = (xfContext*) instance->context; - + xfContext *xfc = (xfContext *) instance->context; UINT32 num_retries = 0; UINT32 max_retries = instance->settings->AutoReconnectMaxRetries; - /* Only auto reconnect on network disconnects. */ - if (freerdp_error_info(instance) != 0) + if(freerdp_error_info(instance) != 0) return FALSE; - /* A network disconnect was detected */ fprintf(stderr, "Network disconnect!\n"); - - if (!instance->settings->AutoReconnectionEnabled) + if(!instance->settings->AutoReconnectionEnabled) { /* No auto-reconnect - just quit */ return FALSE; } - /* Perform an auto-reconnect. */ - for (;;) + for(;;) { /* Quit retrying if max retries has been exceeded */ - if (num_retries++ >= max_retries) + if(num_retries++ >= max_retries) { return FALSE; } - /* Attempt the next reconnect */ fprintf(stderr, "Attempting reconnect (%u of %u)\n", num_retries, max_retries); - - if (freerdp_reconnect(instance)) + if(freerdp_reconnect(instance)) { xfc->disconnect = FALSE; return TRUE; } - sleep(5); } - fprintf(stderr, "Maximum reconnect retries exceeded\n"); - return FALSE; } @@ -1421,21 +1173,21 @@ BOOL xf_auto_reconnect(freerdp* instance) * @param instance - pointer to the rdp_freerdp structure that contains the session's settings * @return A code from the enum XF_EXIT_CODE (0 if successful) */ -void* xf_thread(void* param) +void *xf_thread(void *param) { int i; int fds; - xfContext* xfc; + xfContext *xfc; int max_fds; int rcount; int wcount; BOOL status; int exit_code; - void* rfds[32]; - void* wfds[32]; + void *rfds[32]; + void *wfds[32]; fd_set rfds_set; fd_set wfds_set; - freerdp* instance; + freerdp *instance; int fd_input_event; HANDLE input_event; int select_status; @@ -1446,110 +1198,91 @@ void* xf_thread(void* param) HANDLE update_thread; HANDLE input_thread; HANDLE channels_thread; - rdpChannels* channels; - rdpSettings* settings; + rdpChannels *channels; + rdpSettings *settings; struct timeval timeout; - exit_code = 0; input_event = NULL; - - instance = (freerdp*) param; + instance = (freerdp *) param; assert(NULL != instance); - ZeroMemory(rfds, sizeof(rfds)); ZeroMemory(wfds, sizeof(wfds)); ZeroMemory(&timeout, sizeof(struct timeval)); - status = freerdp_connect(instance); - - xfc = (xfContext*) instance->context; + xfc = (xfContext *) instance->context; assert(NULL != xfc); - /* Connection succeeded. --authonly ? */ - if (instance->settings->AuthenticationOnly) + if(instance->settings->AuthenticationOnly) { freerdp_disconnect(instance); fprintf(stderr, "Authentication only, exit status %d\n", !status); ExitThread(exit_code); } - - if (!status) + if(!status) { - if (xfc->mutex) + if(xfc->mutex) { WaitForSingleObject(xfc->mutex, INFINITE); CloseHandle(xfc->mutex); xfc->mutex = NULL; } - xf_monitors_free(xfc, instance->settings); - exit_code = XF_EXIT_CONN_FAILED; ExitThread(exit_code); } - channels = instance->context->channels; settings = instance->context->settings; - async_update = settings->AsyncUpdate; async_input = settings->AsyncInput; async_channels = settings->AsyncChannels; async_transport = settings->AsyncTransport; - - if (async_update) + if(async_update) { update_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) xf_update_thread, instance, 0, NULL); } - - if (async_input) + if(async_input) { input_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) xf_input_thread, instance, 0, NULL); } - - if (async_channels) + if(async_channels) { channels_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) xf_channels_thread, instance, 0, NULL); } - - while (!xfc->disconnect && !freerdp_shall_disconnect(instance)) + while(!xfc->disconnect && !freerdp_shall_disconnect(instance)) { rcount = 0; wcount = 0; - /* * win8 and server 2k12 seem to have some timing issue/race condition * when a initial sync request is send to sync the keyboard inidcators * sending the sync event twice fixed this problem */ - if (freerdp_focus_required(instance)) + if(freerdp_focus_required(instance)) { xf_keyboard_focus_in(xfc); xf_keyboard_focus_in(xfc); } - - if (!async_transport) + if(!async_transport) { - if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) + if(freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) { fprintf(stderr, "Failed to get FreeRDP file descriptor\n"); exit_code = XF_EXIT_CONN_FAILED; break; } } - - if (!async_channels) + if(!async_channels) { - if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != TRUE) + if(freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != TRUE) { fprintf(stderr, "Failed to get channel manager file descriptor\n"); exit_code = XF_EXIT_CONN_FAILED; break; } } - - if (!async_input) + if(!async_input) { - if (xf_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) + if(xf_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) { fprintf(stderr, "Failed to get xfreerdp file descriptor\n"); exit_code = XF_EXIT_CONN_FAILED; @@ -1560,72 +1293,60 @@ void* xf_thread(void* param) { input_event = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE); fd_input_event = GetEventFileDescriptor(input_event); - rfds[rcount++] = (void*) (long) fd_input_event; + rfds[rcount++] = (void *)(long) fd_input_event; } - max_fds = 0; FD_ZERO(&rfds_set); FD_ZERO(&wfds_set); - - for (i = 0; i < rcount; i++) + for(i = 0; i < rcount; i++) { fds = (int)(long)(rfds[i]); - - if (fds > max_fds) + if(fds > max_fds) max_fds = fds; - FD_SET(fds, &rfds_set); } - - if (max_fds == 0) + if(max_fds == 0) break; - timeout.tv_sec = 1; timeout.tv_usec = 0; - select_status = select(max_fds + 1, &rfds_set, NULL, NULL, &timeout); - - if (select_status == 0) + if(select_status == 0) { continue; /* select timeout */ } - else if (select_status == -1) - { - /* these are not really errors */ - if (!((errno == EAGAIN) || (errno == EWOULDBLOCK) || - (errno == EINPROGRESS) || (errno == EINTR))) /* signal occurred */ + else + if(select_status == -1) { - fprintf(stderr, "xfreerdp_run: select failed\n"); - break; + /* these are not really errors */ + if(!((errno == EAGAIN) || (errno == EWOULDBLOCK) || + (errno == EINPROGRESS) || (errno == EINTR))) /* signal occurred */ + { + fprintf(stderr, "xfreerdp_run: select failed\n"); + break; + } } - } - - if (!async_transport) + if(!async_transport) { - if (freerdp_check_fds(instance) != TRUE) + if(freerdp_check_fds(instance) != TRUE) { - if (xf_auto_reconnect(instance)) + if(xf_auto_reconnect(instance)) continue; - fprintf(stderr, "Failed to check FreeRDP file descriptor\n"); break; } } - - if (!async_channels) + if(!async_channels) { - if (freerdp_channels_check_fds(channels, instance) != TRUE) + if(freerdp_channels_check_fds(channels, instance) != TRUE) { fprintf(stderr, "Failed to check channel manager file descriptor\n"); break; } - xf_process_channel_event(channels, instance); } - - if (!async_input) + if(!async_input) { - if (xf_process_x_events(instance) != TRUE) + if(xf_process_x_events(instance) != TRUE) { fprintf(stderr, "Closed from X11\n"); break; @@ -1633,9 +1354,9 @@ void* xf_thread(void* param) } else { - if (WaitForSingleObject(input_event, 0) == WAIT_OBJECT_0) + if(WaitForSingleObject(input_event, 0) == WAIT_OBJECT_0) { - if (!freerdp_message_queue_process_pending_messages(instance, FREERDP_INPUT_MESSAGE_QUEUE)) + if(!freerdp_message_queue_process_pending_messages(instance, FREERDP_INPUT_MESSAGE_QUEUE)) { fprintf(stderr, "User Disconnect\n"); xfc->disconnect = TRUE; @@ -1644,108 +1365,64 @@ void* xf_thread(void* param) } } } - /* Close the channels first. This will signal the internal message pipes * that the threads should quit. */ freerdp_channels_close(channels, instance); - - if (async_update) + if(async_update) { - wMessageQueue* update_queue = freerdp_get_message_queue(instance, FREERDP_UPDATE_MESSAGE_QUEUE); + wMessageQueue *update_queue = freerdp_get_message_queue(instance, FREERDP_UPDATE_MESSAGE_QUEUE); MessageQueue_PostQuit(update_queue, 0); WaitForSingleObject(update_thread, INFINITE); CloseHandle(update_thread); } - - if (async_input) + if(async_input) { - wMessageQueue* input_queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); + wMessageQueue *input_queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); MessageQueue_PostQuit(input_queue, 0); WaitForSingleObject(input_thread, INFINITE); CloseHandle(input_thread); } - - if (async_channels) + if(async_channels) { WaitForSingleObject(channels_thread, INFINITE); CloseHandle(channels_thread); } - - FILE* fin = fopen("/tmp/tsmf.tid", "rt"); - - if (fin) - { - FILE* fin1; - int thid = 0; - int timeout; - - fscanf(fin, "%d", &thid); - fclose(fin); - - pthread_kill((pthread_t) (size_t) thid, SIGUSR1); - - fin1 = fopen("/tmp/tsmf.tid", "rt"); - timeout = 5; - - while (fin1) - { - fclose(fin1); - sleep(1); - timeout--; - - if (timeout <= 0) - { - unlink("/tmp/tsmf.tid"); - pthread_kill((pthread_t) (size_t) thid, SIGKILL); - break; - } - - fin1 = fopen("/tmp/tsmf.tid", "rt"); - } - } - - if (!exit_code) + if(!exit_code) exit_code = freerdp_error_info(instance); - freerdp_channels_free(channels); freerdp_disconnect(instance); gdi_free(instance); - ExitThread(exit_code); - return NULL; } DWORD xf_exit_code_from_disconnect_reason(DWORD reason) { - if (reason == 0 || (reason >= XF_EXIT_PARSE_ARGUMENTS && reason <= XF_EXIT_CONN_FAILED)) - return reason; - + if(reason == 0 || (reason >= XF_EXIT_PARSE_ARGUMENTS && reason <= XF_EXIT_CONN_FAILED)) + return reason; /* License error set */ - else if (reason >= 0x100 && reason <= 0x10A) - reason -= 0x100 + XF_EXIT_LICENSE_INTERNAL; - + else + if(reason >= 0x100 && reason <= 0x10A) + reason -= 0x100 + XF_EXIT_LICENSE_INTERNAL; /* RDP protocol error set */ - else if (reason >= 0x10c9 && reason <= 0x1193) - reason = XF_EXIT_RDP; - + else + if(reason >= 0x10c9 && reason <= 0x1193) + reason = XF_EXIT_RDP; /* There's no need to test protocol-independent codes: they match */ - else if (!(reason <= 0xB)) - reason = XF_EXIT_UNKNOWN; - + else + if(!(reason <= 0xB)) + reason = XF_EXIT_UNKNOWN; return reason; } -void xf_TerminateEventHandler(rdpContext* context, TerminateEventArgs* e) +void xf_TerminateEventHandler(rdpContext *context, TerminateEventArgs *e) { - wMessageQueue* queue; - xfContext* xfc = (xfContext*) context; - - if (context->settings->AsyncInput) + wMessageQueue *queue; + xfContext *xfc = (xfContext *) context; + if(context->settings->AsyncInput) { queue = freerdp_get_message_queue(context->instance, FREERDP_INPUT_MESSAGE_QUEUE); - - if (queue) + if(queue) MessageQueue_PostQuit(queue, 0); } else @@ -1754,33 +1431,25 @@ void xf_TerminateEventHandler(rdpContext* context, TerminateEventArgs* e) } } -static void xf_ScalingFactorChangeEventHandler(rdpContext* context, ScalingFactorChangeEventArgs* e) +static void xf_ScalingFactorChangeEventHandler(rdpContext *context, ScalingFactorChangeEventArgs *e) { - xfContext* xfc = (xfContext*) context; - + xfContext *xfc = (xfContext *) context; xfc->settings->ScalingFactor += e->ScalingFactor; - - if (xfc->settings->ScalingFactor > 1.2) + if(xfc->settings->ScalingFactor > 1.2) xfc->settings->ScalingFactor = 1.2; - if (xfc->settings->ScalingFactor < 0.8) + if(xfc->settings->ScalingFactor < 0.8) xfc->settings->ScalingFactor = 0.8; - - xfc->currentWidth = xfc->originalWidth * xfc->settings->ScalingFactor; xfc->currentHeight = xfc->originalHeight * xfc->settings->ScalingFactor; - xf_transform_window(xfc); - { ResizeWindowEventArgs ev; - EventArgsInit(&ev, "xfreerdp"); ev.width = (int) xfc->originalWidth * xfc->settings->ScalingFactor; ev.height = (int) xfc->originalHeight * xfc->settings->ScalingFactor; - PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &ev); + PubSub_OnResizeWindow(((rdpContext *) xfc)->pubSub, xfc, &ev); } xf_draw_screen_scaled(xfc, 0, 0, 0, 0, FALSE); - } /** @@ -1799,107 +1468,85 @@ static void xfreerdp_client_global_uninit() freerdp_channels_global_uninit(); } -static int xfreerdp_client_start(rdpContext* context) +static int xfreerdp_client_start(rdpContext *context) { - xfContext* xfc = (xfContext*) context; - - rdpSettings* settings = context->settings; - - if (!settings->ServerHostname) + xfContext *xfc = (xfContext *) context; + rdpSettings *settings = context->settings; + if(!settings->ServerHostname) { fprintf(stderr, "error: server hostname was not specified with /v:[:port]\n"); return -1; } - xfc->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) xf_thread, - context->instance, 0, NULL); - + context->instance, 0, NULL); return 0; } -static int xfreerdp_client_stop(rdpContext* context) +static int xfreerdp_client_stop(rdpContext *context) { - xfContext* xfc = (xfContext*) context; - + xfContext *xfc = (xfContext *) context; assert(NULL != context); - - if (context->settings->AsyncInput) + if(context->settings->AsyncInput) { - wMessageQueue* queue; + wMessageQueue *queue; queue = freerdp_get_message_queue(context->instance, FREERDP_INPUT_MESSAGE_QUEUE); - - if (queue) + if(queue) MessageQueue_PostQuit(queue, 0); } else { xfc->disconnect = TRUE; } - - if (xfc->thread) + if(xfc->thread) { CloseHandle(xfc->thread); xfc->thread = NULL; } - return 0; } -static int xfreerdp_client_new(freerdp* instance, rdpContext* context) +static int xfreerdp_client_new(freerdp *instance, rdpContext *context) { - xfContext* xfc; - rdpSettings* settings; - - xfc = (xfContext*) instance->context; - + xfContext *xfc; + rdpSettings *settings; + xfc = (xfContext *) instance->context; instance->PreConnect = xf_pre_connect; instance->PostConnect = xf_post_connect; instance->PostDisconnect = xf_post_disconnect; instance->Authenticate = xf_authenticate; instance->VerifyCertificate = xf_verify_certificate; instance->LogonErrorInfo = xf_logon_error_info; - context->channels = freerdp_channels_new(); - settings = instance->settings; xfc->settings = instance->context->settings; - PubSub_SubscribeTerminate(context->pubSub, (pTerminateEventHandler) xf_TerminateEventHandler); PubSub_SubscribeScalingFactorChange(context->pubSub, (pScalingFactorChangeEventHandler) xf_ScalingFactorChangeEventHandler); - return 0; } -static void xfreerdp_client_free(freerdp* instance, rdpContext* context) +static void xfreerdp_client_free(freerdp *instance, rdpContext *context) { - xfContext* xfc = (xfContext*) context; - - if (context) + xfContext *xfc = (xfContext *) context; + if(context) { xf_window_free(xfc); - - if (xfc->bmp_codec_none) + if(xfc->bmp_codec_none) free(xfc->bmp_codec_none); - - if (xfc->display) + if(xfc->display) XCloseDisplay(xfc->display); } } -int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints) +int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS *pEntryPoints) { pEntryPoints->Version = 1; pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1); - pEntryPoints->GlobalInit = xfreerdp_client_global_init; pEntryPoints->GlobalUninit = xfreerdp_client_global_uninit; - pEntryPoints->ContextSize = sizeof(xfContext); pEntryPoints->ClientNew = xfreerdp_client_new; pEntryPoints->ClientFree = xfreerdp_client_free; - pEntryPoints->ClientStart = xfreerdp_client_start; pEntryPoints->ClientStop = xfreerdp_client_stop; - return 0; } diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c index 5b7c96b173e4..ba42368da633 100644 --- a/client/X11/xf_window.c +++ b/client/X11/xf_window.c @@ -3,7 +3,7 @@ * X11 Windows * * Copyright 2011 Marc-Andre Moreau - * Copyright 2012 HP Development Company, LLC + * Copyright 2012 HP Development Company, LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,9 +30,11 @@ #include #include -#include -#include +#include +#include +#include +#include #include #include @@ -93,9 +95,6 @@ #define PROP_MOTIF_WM_HINTS_ELEMENTS 5 -/* to be accessed by gstreamer plugin */ -#define SHARED_MEM_KEY 7777 - struct _PropMotifWmHints { unsigned long flags; @@ -109,164 +108,133 @@ typedef struct _PropMotifWmHints PropMotifWmHints; /** * Post an event from the client to the X server */ -void xf_SendClientEvent(xfContext* xfc, xfWindow* window, Atom atom, unsigned int numArgs, ...) +void xf_SendClientEvent(xfContext *xfc, xfWindow *window, Atom atom, unsigned int numArgs, ...) { - XEvent xevent; - unsigned int i; - va_list argp; - - va_start(argp, numArgs); - - xevent.xclient.type = ClientMessage; - xevent.xclient.serial = 0; - xevent.xclient.send_event = False; - xevent.xclient.display = xfc->display; - xevent.xclient.window = window->handle; - xevent.xclient.message_type = atom; - xevent.xclient.format = 32; - - for (i=0; idisplay, RootWindowOfScreen(xfc->screen), False, - SubstructureRedirectMask | SubstructureNotifyMask, &xevent); - XSync(xfc->display, False); - - va_end(argp); + XEvent xevent; + unsigned int i; + va_list argp; + va_start(argp, numArgs); + xevent.xclient.type = ClientMessage; + xevent.xclient.serial = 0; + xevent.xclient.send_event = False; + xevent.xclient.display = xfc->display; + xevent.xclient.window = window->handle; + xevent.xclient.message_type = atom; + xevent.xclient.format = 32; + for(i=0; idisplay, RootWindowOfScreen(xfc->screen), False, + SubstructureRedirectMask | SubstructureNotifyMask, &xevent); + XSync(xfc->display, False); + va_end(argp); } -void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen) +void xf_SetWindowFullscreen(xfContext *xfc, xfWindow *window, BOOL fullscreen) { - if (fullscreen) + if(fullscreen) { - rdpSettings* settings = xfc->instance->settings; - + rdpSettings *settings = xfc->instance->settings; xf_SetWindowDecorations(xfc, window, FALSE); - XMoveResizeWindow(xfc->display, window->handle, settings->DesktopPosX, settings->DesktopPosY, window->width, window->height); - XMapRaised(xfc->display, window->handle); - + XMapRaised(xfc->display, window->handle); window->fullscreen = TRUE; } } /* http://tronche.com/gui/x/xlib/window-information/XGetWindowProperty.html */ -BOOL xf_GetWindowProperty(xfContext* xfc, Window window, Atom property, int length, - unsigned long* nitems, unsigned long* bytes, BYTE** prop) +BOOL xf_GetWindowProperty(xfContext *xfc, Window window, Atom property, int length, + unsigned long *nitems, unsigned long *bytes, BYTE **prop) { int status; Atom actual_type; int actual_format; - - if (property == None) + if(property == None) return FALSE; - status = XGetWindowProperty(xfc->display, window, - property, 0, length, FALSE, AnyPropertyType, - &actual_type, &actual_format, nitems, bytes, prop); - - if (status != Success) + property, 0, length, FALSE, AnyPropertyType, + &actual_type, &actual_format, nitems, bytes, prop); + if(status != Success) return FALSE; - - if (actual_type == None) + if(actual_type == None) { DEBUG_WARN("Property %lu does not exist", property); return FALSE; } - return TRUE; } -BOOL xf_GetCurrentDesktop(xfContext* xfc) +BOOL xf_GetCurrentDesktop(xfContext *xfc) { BOOL status; unsigned long nitems; unsigned long bytes; - unsigned char* prop; - + unsigned char *prop; status = xf_GetWindowProperty(xfc, DefaultRootWindow(xfc->display), - xfc->_NET_CURRENT_DESKTOP, 1, &nitems, &bytes, &prop); - - if (!status) + xfc->_NET_CURRENT_DESKTOP, 1, &nitems, &bytes, &prop); + if(!status) return FALSE; - xfc->current_desktop = (int) *prop; free(prop); - return TRUE; } -BOOL xf_GetWorkArea(xfContext* xfc) +BOOL xf_GetWorkArea(xfContext *xfc) { - long* plong; + long *plong; BOOL status; unsigned long nitems; unsigned long bytes; - unsigned char* prop; - + unsigned char *prop; status = xf_GetCurrentDesktop(xfc); - - if (status != TRUE) + if(status != TRUE) return FALSE; - status = xf_GetWindowProperty(xfc, DefaultRootWindow(xfc->display), - xfc->_NET_WORKAREA, 32 * 4, &nitems, &bytes, &prop); - - if (status != TRUE) + xfc->_NET_WORKAREA, 32 * 4, &nitems, &bytes, &prop); + if(status != TRUE) return FALSE; - - if ((xfc->current_desktop * 4 + 3) >= nitems) + if((xfc->current_desktop * 4 + 3) >= nitems) { free(prop); return FALSE; } - - plong = (long*) prop; - + plong = (long *) prop; xfc->workArea.x = plong[xfc->current_desktop * 4 + 0]; xfc->workArea.y = plong[xfc->current_desktop * 4 + 1]; xfc->workArea.width = plong[xfc->current_desktop * 4 + 2]; xfc->workArea.height = plong[xfc->current_desktop * 4 + 3]; free(prop); - return TRUE; } -void xf_SetWindowDecorations(xfContext* xfc, xfWindow* window, BOOL show) +void xf_SetWindowDecorations(xfContext *xfc, xfWindow *window, BOOL show) { PropMotifWmHints hints; - hints.decorations = (show) ? MWM_DECOR_ALL : 0; - hints.functions = MWM_FUNC_ALL ; + hints.functions = MWM_FUNC_ALL ; hints.flags = MWM_HINTS_DECORATIONS | MWM_HINTS_FUNCTIONS; hints.inputMode = 0; hints.status = 0; - XChangeProperty(xfc->display, window->handle, xfc->_MOTIF_WM_HINTS, xfc->_MOTIF_WM_HINTS, 32, - PropModeReplace, (BYTE*) &hints, PROP_MOTIF_WM_HINTS_ELEMENTS); + PropModeReplace, (BYTE *) &hints, PROP_MOTIF_WM_HINTS_ELEMENTS); } -void xf_SetWindowUnlisted(xfContext* xfc, xfWindow* window) +void xf_SetWindowUnlisted(xfContext *xfc, xfWindow *window) { Atom window_state[2]; - window_state[0] = xfc->_NET_WM_STATE_SKIP_PAGER; window_state[1] = xfc->_NET_WM_STATE_SKIP_TASKBAR; - XChangeProperty(xfc->display, window->handle, xfc->_NET_WM_STATE, - XA_ATOM, 32, PropModeReplace, (BYTE*) &window_state, 2); + XA_ATOM, 32, PropModeReplace, (BYTE *) &window_state, 2); } -void xf_SetWindowStyle(xfContext* xfc, xfWindow* window, UINT32 style, UINT32 ex_style) +void xf_SetWindowStyle(xfContext *xfc, xfWindow *window, UINT32 style, UINT32 ex_style) { Atom window_type; - - if (/*(ex_style & WS_EX_TOPMOST) ||*/ (ex_style & WS_EX_TOOLWINDOW)) + if(/*(ex_style & WS_EX_TOPMOST) ||*/ (ex_style & WS_EX_TOOLWINDOW)) { /* * Tooltips and menu items should be unmanaged windows @@ -280,7 +248,6 @@ void xf_SetWindowStyle(xfContext* xfc, xfWindow* window, UINT32 style, UINT32 ex XSetWindowAttributes attrs; attrs.override_redirect = True; XChangeWindowAttributes(xfc->display, window->handle, CWOverrideRedirect, &attrs); - window->is_transient = TRUE; xf_SetWindowUnlisted(xfc, window); window_type = xfc->_NET_WM_WINDOW_TYPE_POPUP; @@ -289,61 +256,61 @@ void xf_SetWindowStyle(xfContext* xfc, xfWindow* window, UINT32 style, UINT32 ex * TOPMOST window that is not a toolwindow is treated like a regular window(ie. task manager). * Want to do this here, since the window may have type WS_POPUP */ - else if (ex_style & WS_EX_TOPMOST) - { - window_type = xfc->_NET_WM_WINDOW_TYPE_NORMAL; - } - else if (style & WS_POPUP) - { - /* this includes dialogs, popups, etc, that need to be full-fledged windows */ - window->is_transient = TRUE; - window_type = xfc->_NET_WM_WINDOW_TYPE_DIALOG; - xf_SetWindowUnlisted(xfc, window); - } else - { - window_type = xfc->_NET_WM_WINDOW_TYPE_NORMAL; - } - + if(ex_style & WS_EX_TOPMOST) + { + window_type = xfc->_NET_WM_WINDOW_TYPE_NORMAL; + } + else + if(style & WS_POPUP) + { + /* this includes dialogs, popups, etc, that need to be full-fledged windows */ + window->is_transient = TRUE; + window_type = xfc->_NET_WM_WINDOW_TYPE_DIALOG; + xf_SetWindowUnlisted(xfc, window); + } + else + { + window_type = xfc->_NET_WM_WINDOW_TYPE_NORMAL; + } XChangeProperty(xfc->display, window->handle, xfc->_NET_WM_WINDOW_TYPE, - XA_ATOM, 32, PropModeReplace, (BYTE*) &window_type, 1); - + XA_ATOM, 32, PropModeReplace, (BYTE *) &window_type, 1); } -void xf_SetWindowText(xfContext* xfc, xfWindow* window, char *name) +void xf_SetWindowText(xfContext *xfc, xfWindow *window, char *name) { XStoreName(xfc->display, window->handle, name); } -static void xf_SetWindowPID(xfContext* xfc, xfWindow* window, pid_t pid) +static void xf_SetWindowPID(xfContext *xfc, xfWindow *window, pid_t pid) { Atom am_wm_pid; - - if (!pid) + if(!pid) pid = getpid(); - am_wm_pid = XInternAtom(xfc->display, "_NET_WM_PID", False); - XChangeProperty(xfc->display, window->handle, am_wm_pid, XA_CARDINAL, - 32, PropModeReplace, (unsigned char *)&pid, 1); + 32, PropModeReplace, (unsigned char *)&pid, 1); } -xfWindow* xf_CreateDesktopWindow(xfContext* xfc, char* name, int width, int height, BOOL decorations) +static const char *get_shm_id() { - xfWindow* window; - XEvent xevent; - rdpSettings* settings; + static char shm_id[64]; + snprintf(shm_id, sizeof(shm_id), "com.freerdp.xfreerpd.tsmf_%016X", GetCurrentProcessId()); + return shm_id; +} - window = (xfWindow*) malloc(sizeof(xfWindow)); +xfWindow *xf_CreateDesktopWindow(xfContext *xfc, char *name, int width, int height, BOOL decorations) +{ + xfWindow *window; + XEvent xevent; + rdpSettings *settings; + window = (xfWindow *) malloc(sizeof(xfWindow)); ZeroMemory(window, sizeof(xfWindow)); settings = xfc->instance->settings; - - if (window) + if(window) { - int shmid; int input_mask; - XClassHint* class_hints; - + XClassHint *class_hints; window->width = width; window->height = height; window->fullscreen = FALSE; @@ -351,109 +318,89 @@ xfWindow* xf_CreateDesktopWindow(xfContext* xfc, char* name, int width, int heig window->local_move.state = LMS_NOT_ACTIVE; window->is_mapped = FALSE; window->is_transient = FALSE; - window->handle = XCreateWindow(xfc->display, RootWindowOfScreen(xfc->screen), - xfc->workArea.x, xfc->workArea.y, xfc->workArea.width, xfc->workArea.height, 0, xfc->depth, InputOutput, xfc->visual, - CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap | - CWBorderPixel | CWWinGravity | CWBitGravity, &xfc->attribs); - - shmid = shmget(SHARED_MEM_KEY, sizeof(int), IPC_CREAT | 0666); - - if (shmid < 0) + xfc->workArea.x, xfc->workArea.y, xfc->workArea.width, xfc->workArea.height, 0, xfc->depth, InputOutput, xfc->visual, + CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap | + CWBorderPixel | CWWinGravity | CWBitGravity, &xfc->attribs); + window->shmid = shm_open(get_shm_id(), O_CREAT | O_EXCL | O_RDWR, S_IREAD | S_IWRITE); + if(window->shmid < 0) { DEBUG_X11("xf_CreateDesktopWindow: failed to get access to shared memory - shmget()\n"); } else { - int* xfwin = shmat(shmid, NULL, 0); - - if (xfwin == (int*) -1) + ftruncate(window->shmid, sizeof(window->handle)); + window->xfwin = mmap(0, sizeof(window->handle), PROT_READ | PROT_WRITE, MAP_SHARED, window->shmid, 0); + if(window->xfwin == (int *) -1) { DEBUG_X11("xf_CreateDesktopWindow: failed to assign pointer to the memory address - shmat()\n"); } else { - *xfwin = (int) window->handle; + *window->xfwin = window->handle; } } - class_hints = XAllocClassHint(); - - if (class_hints) + if(class_hints) { class_hints->res_name = "xfreerdp"; - - if (xfc->instance->settings->WmClass) + if(xfc->instance->settings->WmClass) class_hints->res_class = xfc->instance->settings->WmClass; - else + else class_hints->res_class = "xfreerdp"; - XSetClassHint(xfc->display, window->handle, class_hints); XFree(class_hints); } - xf_ResizeDesktopWindow(xfc, window, width, height); xf_SetWindowDecorations(xfc, window, decorations); xf_SetWindowPID(xfc, window, 0); - input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | VisibilityChangeMask | FocusChangeMask | StructureNotifyMask | PointerMotionMask | ExposureMask | PropertyChangeMask; - - if (xfc->grab_keyboard) + if(xfc->grab_keyboard) input_mask |= EnterWindowMask | LeaveWindowMask; - XChangeProperty(xfc->display, window->handle, xfc->_NET_WM_ICON, XA_CARDINAL, 32, - PropModeReplace, (BYTE*) xf_icon_prop, ARRAYSIZE(xf_icon_prop)); - - if (xfc->settings->ParentWindowId) - XReparentWindow(xfc->display, window->handle, (Window) xfc->settings->ParentWindowId, 0, 0); - + PropModeReplace, (BYTE *) xf_icon_prop, ARRAYSIZE(xf_icon_prop)); + if(xfc->settings->ParentWindowId) + XReparentWindow(xfc->display, window->handle, (Window) xfc->settings->ParentWindowId, 0, 0); XSelectInput(xfc->display, window->handle, input_mask); XClearWindow(xfc->display, window->handle); XMapWindow(xfc->display, window->handle); - xf_input_init(xfc, window->handle); - /* - * NOTE: This must be done here to handle reparenting the window, + * NOTE: This must be done here to handle reparenting the window, * so that we don't miss the event and hang waiting for the next one */ - do - { - XMaskEvent(xfc->display, VisibilityChangeMask, &xevent); - } - while (xevent.type != VisibilityNotify); - + do + { + XMaskEvent(xfc->display, VisibilityChangeMask, &xevent); + } + while(xevent.type != VisibilityNotify); /* * The XCreateWindow call will start the window in the upper-left corner of our current * monitor instead of the upper-left monitor for remote app mode(which uses all monitors). * This extra call after the window is mapped will position the login window correctly */ - - if (xfc->instance->settings->RemoteApplicationMode) - { - XMoveWindow(xfc->display, window->handle, 0, 0); - } - else if (settings->DesktopPosX || settings->DesktopPosY) + if(xfc->instance->settings->RemoteApplicationMode) { - XMoveWindow(xfc->display, window->handle, settings->DesktopPosX, settings->DesktopPosY); + XMoveWindow(xfc->display, window->handle, 0, 0); } + else + if(settings->DesktopPosX || settings->DesktopPosY) + { + XMoveWindow(xfc->display, window->handle, settings->DesktopPosX, settings->DesktopPosY); + } } - xf_SetWindowText(xfc, window, name); - return window; } -void xf_ResizeDesktopWindow(xfContext* xfc, xfWindow* window, int width, int height) +void xf_ResizeDesktopWindow(xfContext *xfc, xfWindow *window, int width, int height) { - XSizeHints* size_hints; - + XSizeHints *size_hints; size_hints = XAllocSizeHints(); - - if (size_hints) + if(size_hints) { size_hints->flags = PMinSize | PMaxSize; size_hints->min_width = size_hints->max_width = xfc->width; @@ -464,37 +411,35 @@ void xf_ResizeDesktopWindow(xfContext* xfc, xfWindow* window, int width, int hei } } -void xf_FixWindowCoordinates(xfContext* xfc, int* x, int* y, int* width, int* height) +void xf_FixWindowCoordinates(xfContext *xfc, int *x, int *y, int *width, int *height) { int vscreen_width; int vscreen_height; - vscreen_width = xfc->vscreen.area.right - xfc->vscreen.area.left + 1; vscreen_height = xfc->vscreen.area.bottom - xfc->vscreen.area.top + 1; - - if (*width < 1) + if(*width < 1) { *width = 1; } - if (*height < 1) + if(*height < 1) { *height = 1; } - if (*x < xfc->vscreen.area.left) + if(*x < xfc->vscreen.area.left) { *width += *x; *x = xfc->vscreen.area.left; } - if (*y < xfc->vscreen.area.top) + if(*y < xfc->vscreen.area.top) { *height += *y; *y = xfc->vscreen.area.top; } - if (*width > vscreen_width) + if(*width > vscreen_width) { *width = vscreen_width; } - if (*height > vscreen_height) + if(*height > vscreen_height) { *height = vscreen_height; } @@ -502,59 +447,47 @@ void xf_FixWindowCoordinates(xfContext* xfc, int* x, int* y, int* width, int* he char rail_window_class[] = "RAIL:00000000"; -xfWindow* xf_CreateWindow(xfContext* xfc, rdpWindow* wnd, int x, int y, int width, int height, UINT32 id) +xfWindow *xf_CreateWindow(xfContext *xfc, rdpWindow *wnd, int x, int y, int width, int height, UINT32 id) { XGCValues gcv; int input_mask; - xfWindow* window; - XWMHints* InputModeHint; - XClassHint* class_hints; - - window = (xfWindow*) malloc(sizeof(xfWindow)); + xfWindow *window; + XWMHints *InputModeHint; + XClassHint *class_hints; + window = (xfWindow *) malloc(sizeof(xfWindow)); ZeroMemory(window, sizeof(xfWindow)); - xf_FixWindowCoordinates(xfc, &x, &y, &width, &height); - window->left = x; window->top = y; window->right = x + width - 1; window->bottom = y + height - 1; window->width = width; window->height = height; - /* * WS_EX_DECORATIONS is used by XRDP and instructs * the client to use local window decorations */ - window->decorations = (wnd->extendedStyle & WS_EX_DECORATIONS) ? TRUE : FALSE; - window->fullscreen = FALSE; window->window = wnd; window->local_move.state = LMS_NOT_ACTIVE; window->is_mapped = FALSE; window->is_transient = FALSE; window->rail_state = 0; - window->rail_ignore_configure = FALSE; - + window->rail_ignore_configure = FALSE; window->handle = XCreateWindow(xfc->display, RootWindowOfScreen(xfc->screen), - x, y, window->width, window->height, 0, xfc->depth, InputOutput, xfc->visual, - 0, &xfc->attribs); - + x, y, window->width, window->height, 0, xfc->depth, InputOutput, xfc->visual, + 0, &xfc->attribs); DEBUG_X11_LMS("Create window=0x%X rc={l=%d t=%d r=%d b=%d} w=%d h=%d rdp=0x%X", - (UINT32) window->handle, window->left, window->top, window->right, window->bottom, - window->width, window->height, wnd->windowId); - + (UINT32) window->handle, window->left, window->top, window->right, window->bottom, + window->width, window->height, wnd->windowId); ZeroMemory(&gcv, sizeof(gcv)); window->gc = XCreateGC(xfc->display, window->handle, GCGraphicsExposures, &gcv); - class_hints = XAllocClassHint(); - - if (class_hints) + if(class_hints) { - char* class = NULL; - - if (xfc->instance->settings->WmClass != NULL) + char *class = NULL; + if(xfc->instance->settings->WmClass != NULL) { class_hints->res_class = xfc->instance->settings->WmClass; } @@ -564,294 +497,242 @@ xfWindow* xf_CreateWindow(xfContext* xfc, rdpWindow* wnd, int x, int y, int widt snprintf(class, sizeof(rail_window_class), "RAIL:%08X", id); class_hints->res_class = class; } - class_hints->res_name = "RAIL"; XSetClassHint(xfc->display, window->handle, class_hints); XFree(class_hints); - - if (class) + if(class) free(class); } - /* Set the input mode hint for the WM */ - InputModeHint = XAllocWMHints(); - InputModeHint->flags = (1L << 0); - InputModeHint->input = True; - XSetWMHints(xfc->display, window->handle, InputModeHint); - XFree(InputModeHint); - + InputModeHint = XAllocWMHints(); + InputModeHint->flags = (1L << 0); + InputModeHint->input = True; + XSetWMHints(xfc->display, window->handle, InputModeHint); + XFree(InputModeHint); XSetWMProtocols(xfc->display, window->handle, &(xfc->WM_DELETE_WINDOW), 1); - input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | - ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | - PointerMotionMask | Button1MotionMask | Button2MotionMask | - Button3MotionMask | Button4MotionMask | Button5MotionMask | - ButtonMotionMask | KeymapStateMask | ExposureMask | - VisibilityChangeMask | StructureNotifyMask | SubstructureNotifyMask | - SubstructureRedirectMask | FocusChangeMask | PropertyChangeMask | - ColormapChangeMask | OwnerGrabButtonMask; - + ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | + PointerMotionMask | Button1MotionMask | Button2MotionMask | + Button3MotionMask | Button4MotionMask | Button5MotionMask | + ButtonMotionMask | KeymapStateMask | ExposureMask | + VisibilityChangeMask | StructureNotifyMask | SubstructureNotifyMask | + SubstructureRedirectMask | FocusChangeMask | PropertyChangeMask | + ColormapChangeMask | OwnerGrabButtonMask; XSelectInput(xfc->display, window->handle, input_mask); - xf_SetWindowDecorations(xfc, window, window->decorations); xf_SetWindowStyle(xfc, window, wnd->style, wnd->extendedStyle); xf_SetWindowPID(xfc, window, 0); xf_ShowWindow(xfc, window, WINDOW_SHOW); - XClearWindow(xfc->display, window->handle); XMapWindow(xfc->display, window->handle); - /* Move doesn't seem to work until window is mapped. */ xf_MoveWindow(xfc, window, x, y, width, height); - return window; } -void xf_SetWindowMinMaxInfo(xfContext* xfc, xfWindow* window, - int maxWidth, int maxHeight, int maxPosX, int maxPosY, - int minTrackWidth, int minTrackHeight, int maxTrackWidth, int maxTrackHeight) +void xf_SetWindowMinMaxInfo(xfContext *xfc, xfWindow *window, + int maxWidth, int maxHeight, int maxPosX, int maxPosY, + int minTrackWidth, int minTrackHeight, int maxTrackWidth, int maxTrackHeight) { - XSizeHints* size_hints; - + XSizeHints *size_hints; size_hints = XAllocSizeHints(); - - if (size_hints) + if(size_hints) { size_hints->flags = PMinSize | PMaxSize | PResizeInc; - size_hints->min_width = minTrackWidth; size_hints->min_height = minTrackHeight; - size_hints->max_width = maxTrackWidth; size_hints->max_height = maxTrackHeight; - /* to speedup window drawing we need to select optimal value for sizing step. */ size_hints->width_inc = size_hints->height_inc = 1; - XSetWMNormalHints(xfc->display, window->handle, size_hints); XFree(size_hints); } } -void xf_StartLocalMoveSize(xfContext* xfc, xfWindow* window, int direction, int x, int y) +void xf_StartLocalMoveSize(xfContext *xfc, xfWindow *window, int direction, int x, int y) { - if (window->local_move.state != LMS_NOT_ACTIVE) + if(window->local_move.state != LMS_NOT_ACTIVE) return; - DEBUG_X11_LMS("direction=%d window=0x%X rc={l=%d t=%d r=%d b=%d} w=%d h=%d " - "RDP=0x%X rc={l=%d t=%d} w=%d h=%d mouse_x=%d mouse_y=%d", - direction, (UINT32) window->handle, - window->left, window->top, window->right, window->bottom, - window->width, window->height, window->window->windowId, - window->window->windowOffsetX, window->window->windowOffsetY, - window->window->windowWidth, window->window->windowHeight, x, y); - + "RDP=0x%X rc={l=%d t=%d} w=%d h=%d mouse_x=%d mouse_y=%d", + direction, (UINT32) window->handle, + window->left, window->top, window->right, window->bottom, + window->width, window->height, window->window->windowId, + window->window->windowOffsetX, window->window->windowOffsetY, + window->window->windowWidth, window->window->windowHeight, x, y); /* * Save original mouse location relative to root. This will be needed * to end local move to RDP server and/or X server */ - window->local_move.root_x = x; + window->local_move.root_x = x; window->local_move.root_y = y; window->local_move.state = LMS_STARTING; window->local_move.direction = direction; - XUngrabPointer(xfc->display, CurrentTime); - - xf_SendClientEvent(xfc, window, - xfc->_NET_WM_MOVERESIZE, /* request X window manager to initiate a local move */ - 5, /* 5 arguments to follow */ - x, /* x relative to root window */ - y, /* y relative to root window */ - direction, /* extended ICCM direction flag */ - 1, /* simulated mouse button 1 */ - 1); /* 1 == application request per extended ICCM */ + xf_SendClientEvent(xfc, window, + xfc->_NET_WM_MOVERESIZE, /* request X window manager to initiate a local move */ + 5, /* 5 arguments to follow */ + x, /* x relative to root window */ + y, /* y relative to root window */ + direction, /* extended ICCM direction flag */ + 1, /* simulated mouse button 1 */ + 1); /* 1 == application request per extended ICCM */ } -void xf_EndLocalMoveSize(xfContext* xfc, xfWindow *window) +void xf_EndLocalMoveSize(xfContext *xfc, xfWindow *window) { - DEBUG_X11_LMS("state=%d window=0x%X rc={l=%d t=%d r=%d b=%d} w=%d h=%d " - "RDP=0x%X rc={l=%d t=%d} w=%d h=%d", - window->local_move.state, - (UINT32) window->handle, window->left, window->top, window->right, window->bottom, - window->width, window->height, window->window->windowId, - window->window->windowOffsetX, window->window->windowOffsetY, - window->window->windowWidth, window->window->windowHeight); - - if (window->local_move.state == LMS_NOT_ACTIVE) + "RDP=0x%X rc={l=%d t=%d} w=%d h=%d", + window->local_move.state, + (UINT32) window->handle, window->left, window->top, window->right, window->bottom, + window->width, window->height, window->window->windowId, + window->window->windowOffsetX, window->window->windowOffsetY, + window->window->windowWidth, window->window->windowHeight); + if(window->local_move.state == LMS_NOT_ACTIVE) return; - - if (window->local_move.state == LMS_STARTING) + if(window->local_move.state == LMS_STARTING) { /* * The move never was property started. This can happen due to race * conditions between the mouse button up and the communications to the * RDP server for local moves. We must cancel the X window manager move. - * Per ICCM, the X client can ask to cancel an active move. + * Per ICCM, the X client can ask to cancel an active move. */ - xf_SendClientEvent(xfc, window, - xfc->_NET_WM_MOVERESIZE, /* request X window manager to abort a local move */ - 5, /* 5 arguments to follow */ - window->local_move.root_x, /* x relative to root window */ - window->local_move.root_y, /* y relative to root window */ - _NET_WM_MOVERESIZE_CANCEL, /* extended ICCM direction flag */ - 1, /* simulated mouse button 1 */ - 1); /* 1 == application request per extended ICCM */ + xf_SendClientEvent(xfc, window, + xfc->_NET_WM_MOVERESIZE, /* request X window manager to abort a local move */ + 5, /* 5 arguments to follow */ + window->local_move.root_x, /* x relative to root window */ + window->local_move.root_y, /* y relative to root window */ + _NET_WM_MOVERESIZE_CANCEL, /* extended ICCM direction flag */ + 1, /* simulated mouse button 1 */ + 1); /* 1 == application request per extended ICCM */ } - window->local_move.state = LMS_NOT_ACTIVE; } -void xf_MoveWindow(xfContext* xfc, xfWindow* window, int x, int y, int width, int height) +void xf_MoveWindow(xfContext *xfc, xfWindow *window, int x, int y, int width, int height) { BOOL resize = FALSE; - - if ((width * height) < 1) + if((width * height) < 1) return; - - if ((window->width != width) || (window->height != height)) + if((window->width != width) || (window->height != height)) resize = TRUE; - - if (window->local_move.state == LMS_STARTING || - window->local_move.state == LMS_ACTIVE) + if(window->local_move.state == LMS_STARTING || + window->local_move.state == LMS_ACTIVE) return; - DEBUG_X11_LMS("window=0x%X rc={l=%d t=%d r=%d b=%d} w=%u h=%u " - "new rc={l=%d t=%d r=%d b=%d} w=%u h=%u" - " RDP=0x%X rc={l=%d t=%d} w=%d h=%d", - (UINT32) window->handle, window->left, window->top, - window->right, window->bottom, window->width, window->height, - x, y, x + width -1, y + height -1, width, height, - window->window->windowId, - window->window->windowOffsetX, window->window->windowOffsetY, - window->window->windowWidth, window->window->windowHeight); - + "new rc={l=%d t=%d r=%d b=%d} w=%u h=%u" + " RDP=0x%X rc={l=%d t=%d} w=%d h=%d", + (UINT32) window->handle, window->left, window->top, + window->right, window->bottom, window->width, window->height, + x, y, x + width -1, y + height -1, width, height, + window->window->windowId, + window->window->windowOffsetX, window->window->windowOffsetY, + window->window->windowWidth, window->window->windowHeight); window->left = x; window->top = y; window->right = x + width - 1; window->bottom = y + height - 1; window->width = width; window->height = height; - - if (resize) + if(resize) XMoveResizeWindow(xfc->display, window->handle, x, y, width, height); else XMoveWindow(xfc->display, window->handle, x, y); - xf_UpdateWindowArea(xfc, window, 0, 0, width, height); } -void xf_ShowWindow(xfContext* xfc, xfWindow* window, BYTE state) +void xf_ShowWindow(xfContext *xfc, xfWindow *window, BYTE state) { - switch (state) + switch(state) { case WINDOW_HIDE: XWithdrawWindow(xfc->display, window->handle, xfc->screen_number); break; - case WINDOW_SHOW_MINIMIZED: XIconifyWindow(xfc->display, window->handle, xfc->screen_number); break; - case WINDOW_SHOW_MAXIMIZED: /* Set the window as maximized */ xf_SendClientEvent(xfc, window, xfc->_NET_WM_STATE, 4, 1, - XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_VERT", False), - XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False), 0); - + XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_VERT", False), + XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False), 0); /* * This is a workaround for the case where the window is maximized locally before the rail server is told to maximize * the window, this appears to be a race condition where the local window with incomplete data and once the window is * actually maximized on the server - an update of the new areas may not happen. So, we simply to do a full update of * the entire window once the rail server notifies us that the window is now maximized. */ - - if (window->rail_state == WINDOW_SHOW_MAXIMIZED) - xf_UpdateWindowArea(xfc, window, 0, 0, window->window->windowWidth, window->window->windowHeight); + if(window->rail_state == WINDOW_SHOW_MAXIMIZED) + xf_UpdateWindowArea(xfc, window, 0, 0, window->window->windowWidth, window->window->windowHeight); break; - case WINDOW_SHOW: /* Ensure the window is not maximized */ xf_SendClientEvent(xfc, window, xfc->_NET_WM_STATE, 4, 0, - XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_VERT", False), - XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False), 0); - + XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_VERT", False), + XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False), 0); /* * Ignore configure requests until both the Maximized properties have been processed * to prevent condition where WM overrides size of request due to one or both of these properties * still being set - which causes a position adjustment to be sent back to the server * thus causing the window to not return to its original size */ - - if (window->rail_state == WINDOW_SHOW_MAXIMIZED) - window->rail_ignore_configure = TRUE; - - if (window->is_transient) + if(window->rail_state == WINDOW_SHOW_MAXIMIZED) + window->rail_ignore_configure = TRUE; + if(window->is_transient) xf_SetWindowUnlisted(xfc, window); - break; } - /* Save the current rail state of this window */ window->rail_state = state; - XFlush(xfc->display); } -void xf_SetWindowIcon(xfContext* xfc, xfWindow* window, rdpIcon* icon) +void xf_SetWindowIcon(xfContext *xfc, xfWindow *window, rdpIcon *icon) { int x, y; int pixels; int propsize; - long* propdata; - long* dstp; - UINT32* srcp; - - if (!icon->big) + long *propdata; + long *dstp; + UINT32 *srcp; + if(!icon->big) return; - pixels = icon->entry->width * icon->entry->height; propsize = 2 + pixels; propdata = malloc(propsize * sizeof(long)); - propdata[0] = icon->entry->width; propdata[1] = icon->entry->height; dstp = &(propdata[2]); - srcp = (UINT32*) icon->extra; - - for (y = 0; y < icon->entry->height; y++) + srcp = (UINT32 *) icon->extra; + for(y = 0; y < icon->entry->height; y++) { - for (x = 0; x < icon->entry->width; x++) + for(x = 0; x < icon->entry->width; x++) { *dstp++ = *srcp++; } } - XChangeProperty(xfc->display, window->handle, xfc->_NET_WM_ICON, XA_CARDINAL, 32, - PropModeReplace, (BYTE*) propdata, propsize); - + PropModeReplace, (BYTE *) propdata, propsize); XFlush(xfc->display); free(propdata); } -void xf_SetWindowRects(xfContext* xfc, xfWindow* window, RECTANGLE_16* rects, int nrects) +void xf_SetWindowRects(xfContext *xfc, xfWindow *window, RECTANGLE_16 *rects, int nrects) { int i; - XRectangle* xrects; - - if (nrects == 0) + XRectangle *xrects; + if(nrects == 0) return; - xrects = malloc(sizeof(XRectangle) * nrects); - - for (i = 0; i < nrects; i++) + for(i = 0; i < nrects; i++) { xrects[i].x = rects[i].left; xrects[i].y = rects[i].top; xrects[i].width = rects[i].right - rects[i].left; xrects[i].height = rects[i].bottom - rects[i].top; } - #ifdef WITH_XEXT /* * This is currently unsupported with the new logic to handle window placement with VisibleOffset variables @@ -860,28 +741,23 @@ void xf_SetWindowRects(xfContext* xfc, xfWindow* window, RECTANGLE_16* rects, in */ XShapeCombineRectangles(xfc->display, window->handle, ShapeBounding, 0, 0, xrects, nrects, ShapeSet, 0); #endif - free(xrects); } -void xf_SetWindowVisibilityRects(xfContext* xfc, xfWindow* window, RECTANGLE_16* rects, int nrects) +void xf_SetWindowVisibilityRects(xfContext *xfc, xfWindow *window, RECTANGLE_16 *rects, int nrects) { int i; - XRectangle* xrects; - - if (nrects == 0) + XRectangle *xrects; + if(nrects == 0) return; - xrects = malloc(sizeof(XRectangle) * nrects); - - for (i = 0; i < nrects; i++) + for(i = 0; i < nrects; i++) { xrects[i].x = rects[i].left; xrects[i].y = rects[i].top; xrects[i].width = rects[i].right - rects[i].left; xrects[i].height = rects[i].bottom - rects[i].top; } - #ifdef WITH_XEXT /* * This is currently unsupported with the new logic to handle window placement with VisibleOffset variables @@ -890,110 +766,94 @@ void xf_SetWindowVisibilityRects(xfContext* xfc, xfWindow* window, RECTANGLE_16* */ XShapeCombineRectangles(xfc->display, window->handle, ShapeBounding, 0, 0, xrects, nrects, ShapeSet, 0); #endif - free(xrects); } -void xf_UpdateWindowArea(xfContext* xfc, xfWindow* window, int x, int y, int width, int height) +void xf_UpdateWindowArea(xfContext *xfc, xfWindow *window, int x, int y, int width, int height) { int ax, ay; - rdpWindow* wnd; + rdpWindow *wnd; wnd = window->window; - /* RemoteApp mode uses visibleOffset instead of windowOffset */ - - if (!xfc->remote_app) + if(!xfc->remote_app) { ax = x + wnd->windowOffsetX; - ay = y + wnd->windowOffsetY; - - if (ax + width > wnd->windowOffsetX + wnd->windowWidth) + ay = y + wnd->windowOffsetY; + if(ax + width > wnd->windowOffsetX + wnd->windowWidth) width = (wnd->windowOffsetX + wnd->windowWidth - 1) - ax; - - if (ay + height > wnd->windowOffsetY + wnd->windowHeight) + if(ay + height > wnd->windowOffsetY + wnd->windowHeight) height = (wnd->windowOffsetY + wnd->windowHeight - 1) - ay; } else { ax = x + wnd->visibleOffsetX; - ay = y + wnd->visibleOffsetY; - - if (ax + width > wnd->visibleOffsetX + wnd->windowWidth) - width = (wnd->visibleOffsetX + wnd->windowWidth - 1) - ax; - - if (ay + height > wnd->visibleOffsetY + wnd->windowHeight) - height = (wnd->visibleOffsetY + wnd->windowHeight - 1) - ay; + ay = y + wnd->visibleOffsetY; + if(ax + width > wnd->visibleOffsetX + wnd->windowWidth) + width = (wnd->visibleOffsetX + wnd->windowWidth - 1) - ax; + if(ay + height > wnd->visibleOffsetY + wnd->windowHeight) + height = (wnd->visibleOffsetY + wnd->windowHeight - 1) - ay; } - WaitForSingleObject(xfc->mutex, INFINITE); - - if (xfc->settings->SoftwareGdi) + if(xfc->settings->SoftwareGdi) { XPutImage(xfc->display, xfc->primary, window->gc, xfc->image, - ax, ay, ax, ay, width, height); + ax, ay, ax, ay, width, height); } - XCopyArea(xfc->display, xfc->primary, window->handle, window->gc, - ax, ay, width, height, x, y); - + ax, ay, width, height, x, y); XFlush(xfc->display); - ReleaseMutex(xfc->mutex); } -BOOL xf_IsWindowBorder(xfContext* xfc, xfWindow* xfw, int x, int y) +BOOL xf_IsWindowBorder(xfContext *xfc, xfWindow *xfw, int x, int y) { - rdpWindow* wnd; + rdpWindow *wnd; BOOL clientArea = FALSE; BOOL windowArea = FALSE; - wnd = xfw->window; - - if (((x > wnd->clientOffsetX) && (x < wnd->clientOffsetX + wnd->clientAreaWidth)) && - ((y > wnd->clientOffsetY) && (y < wnd->clientOffsetY + wnd->clientAreaHeight))) + if(((x > wnd->clientOffsetX) && (x < wnd->clientOffsetX + wnd->clientAreaWidth)) && + ((y > wnd->clientOffsetY) && (y < wnd->clientOffsetY + wnd->clientAreaHeight))) clientArea = TRUE; - - if (((x > wnd->windowOffsetX) && (x < wnd->windowOffsetX + wnd->windowWidth)) && - ((y > wnd->windowOffsetY) && (y < wnd->windowOffsetY + wnd->windowHeight))) + if(((x > wnd->windowOffsetX) && (x < wnd->windowOffsetX + wnd->windowWidth)) && + ((y > wnd->windowOffsetY) && (y < wnd->windowOffsetY + wnd->windowHeight))) windowArea = TRUE; - return (windowArea && !(clientArea)); } -void xf_DestroyWindow(xfContext* xfc, xfWindow* window) +void xf_DestroyWindow(xfContext *xfc, xfWindow *window) { - if (window == NULL) + if(window == NULL) return; - - if (xfc->window == window) + if(xfc->window == window) xfc->window = NULL; - - if (window->gc) + if(window->gc) XFreeGC(xfc->display, window->gc); - - if (window->handle) + if(window->handle) { XUnmapWindow(xfc->display, window->handle); XDestroyWindow(xfc->display, window->handle); } - free(window); + if(window->xfwin) + munmap(0, sizeof(*window->xfwin)); + if(window->shmid >= 0) + close(window->shmid); + shm_unlink(get_shm_id()); + window->xfwin = -1; + window->shmid = -1; } -rdpWindow* xf_rdpWindowFromWindow(xfContext* xfc, Window wnd) +rdpWindow *xf_rdpWindowFromWindow(xfContext *xfc, Window wnd) { - rdpRail* rail; - - if (xfc) + rdpRail *rail; + if(xfc) { - if (wnd) + if(wnd) { - rail = ((rdpContext*) xfc)->rail; - - if (rail) - return window_list_get_by_extra_id(rail->list, (void*) (long) wnd); + rail = ((rdpContext *) xfc)->rail; + if(rail) + return window_list_get_by_extra_id(rail->list, (void *)(long) wnd); } } - return NULL; } diff --git a/client/X11/xf_window.h b/client/X11/xf_window.h index e800239819ba..cc3acf38faae 100644 --- a/client/X11/xf_window.h +++ b/client/X11/xf_window.h @@ -71,10 +71,12 @@ struct xf_window int bottom; int width; int height; + int shmid; Window handle; + Window *xfwin; BOOL fullscreen; BOOL decorations; - rdpWindow* window; + rdpWindow *window; BOOL is_mapped; BOOL is_transient; xfLocalMove local_move; @@ -82,39 +84,39 @@ struct xf_window BOOL rail_ignore_configure; }; -void xf_ewmhints_init(xfContext* xfc); +void xf_ewmhints_init(xfContext *xfc); -BOOL xf_GetCurrentDesktop(xfContext* xfc); -BOOL xf_GetWorkArea(xfContext* xfc); +BOOL xf_GetCurrentDesktop(xfContext *xfc); +BOOL xf_GetWorkArea(xfContext *xfc); -void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen); -void xf_SetWindowDecorations(xfContext* xfc, xfWindow* window, BOOL show); -void xf_SetWindowUnlisted(xfContext* xfc, xfWindow* window); +void xf_SetWindowFullscreen(xfContext *xfc, xfWindow *window, BOOL fullscreen); +void xf_SetWindowDecorations(xfContext *xfc, xfWindow *window, BOOL show); +void xf_SetWindowUnlisted(xfContext *xfc, xfWindow *window); -xfWindow* xf_CreateDesktopWindow(xfContext* xfc, char* name, int width, int height, BOOL decorations); -void xf_ResizeDesktopWindow(xfContext* xfc, xfWindow* window, int width, int height); +xfWindow *xf_CreateDesktopWindow(xfContext *xfc, char *name, int width, int height, BOOL decorations); +void xf_ResizeDesktopWindow(xfContext *xfc, xfWindow *window, int width, int height); -xfWindow* xf_CreateWindow(xfContext* xfc, rdpWindow* wnd, int x, int y, int width, int height, UINT32 id); -void xf_SetWindowText(xfContext* xfc, xfWindow* window, char *name); -void xf_MoveWindow(xfContext* xfc, xfWindow* window, int x, int y, int width, int height); -void xf_ShowWindow(xfContext* xfc, xfWindow* window, BYTE state); -void xf_SetWindowIcon(xfContext* xfc, xfWindow* window, rdpIcon* icon); -void xf_SetWindowRects(xfContext* xfc, xfWindow* window, RECTANGLE_16* rects, int nrects); -void xf_SetWindowVisibilityRects(xfContext* xfc, xfWindow* window, RECTANGLE_16* rects, int nrects); -void xf_SetWindowStyle(xfContext* xfc, xfWindow* window, UINT32 style, UINT32 ex_style); -void xf_UpdateWindowArea(xfContext* xfc, xfWindow* window, int x, int y, int width, int height); -BOOL xf_IsWindowBorder(xfContext* xfc, xfWindow* xfw, int x, int y); -void xf_DestroyWindow(xfContext* xfc, xfWindow* window); -rdpWindow* xf_rdpWindowFromWindow(xfContext* xfc, Window wnd); +xfWindow *xf_CreateWindow(xfContext *xfc, rdpWindow *wnd, int x, int y, int width, int height, UINT32 id); +void xf_SetWindowText(xfContext *xfc, xfWindow *window, char *name); +void xf_MoveWindow(xfContext *xfc, xfWindow *window, int x, int y, int width, int height); +void xf_ShowWindow(xfContext *xfc, xfWindow *window, BYTE state); +void xf_SetWindowIcon(xfContext *xfc, xfWindow *window, rdpIcon *icon); +void xf_SetWindowRects(xfContext *xfc, xfWindow *window, RECTANGLE_16 *rects, int nrects); +void xf_SetWindowVisibilityRects(xfContext *xfc, xfWindow *window, RECTANGLE_16 *rects, int nrects); +void xf_SetWindowStyle(xfContext *xfc, xfWindow *window, UINT32 style, UINT32 ex_style); +void xf_UpdateWindowArea(xfContext *xfc, xfWindow *window, int x, int y, int width, int height); +BOOL xf_IsWindowBorder(xfContext *xfc, xfWindow *xfw, int x, int y); +void xf_DestroyWindow(xfContext *xfc, xfWindow *window); +rdpWindow *xf_rdpWindowFromWindow(xfContext *xfc, Window wnd); -BOOL xf_GetWindowProperty(xfContext* xfc, Window window, Atom property, int length, - unsigned long* nitems, unsigned long* bytes, BYTE** prop); +BOOL xf_GetWindowProperty(xfContext *xfc, Window window, Atom property, int length, + unsigned long *nitems, unsigned long *bytes, BYTE **prop); -void xf_SetWindowMinMaxInfo(xfContext* xfc, xfWindow* window, int maxWidth, int maxHeight, - int maxPosX, int maxPosY, int minTrackWidth, int minTrackHeight, int maxTrackWidth, int maxTrackHeight); +void xf_SetWindowMinMaxInfo(xfContext *xfc, xfWindow *window, int maxWidth, int maxHeight, + int maxPosX, int maxPosY, int minTrackWidth, int minTrackHeight, int maxTrackWidth, int maxTrackHeight); -void xf_StartLocalMoveSize(xfContext* xfc, xfWindow* window, int direction, int x, int y); -void xf_EndLocalMoveSize(xfContext* xfc, xfWindow *window); -void xf_SendClientEvent(xfContext* xfc, xfWindow* window, Atom atom, unsigned int numArgs, ...); +void xf_StartLocalMoveSize(xfContext *xfc, xfWindow *window, int direction, int x, int y); +void xf_EndLocalMoveSize(xfContext *xfc, xfWindow *window); +void xf_SendClientEvent(xfContext *xfc, xfWindow *window, Atom atom, unsigned int numArgs, ...); #endif /* __XF_WINDOW_H */ diff --git a/cmake/ConfigOptions.cmake b/cmake/ConfigOptions.cmake index f644c8050277..d2e56eadee1b 100644 --- a/cmake/ConfigOptions.cmake +++ b/cmake/ConfigOptions.cmake @@ -100,6 +100,7 @@ option(WITH_DEBUG_CAPABILITIES "Print capability negotiation debug messages." ${ option(WITH_DEBUG_CHANNELS "Print channel manager debug messages." ${DEFAULT_DEBUG_OPTION}) option(WITH_DEBUG_CLIPRDR "Print clipboard redirection debug messages" ${DEFAULT_DEBUG_OPTION}) option(WITH_DEBUG_DVC "Print dynamic virtual channel debug messages." ${DEFAULT_DEBUG_OPTION}) +option(WITH_DEBUG_TSMF "Print TSMF virtual channel debug messages." ${DEFAULT_DEBUG_OPTION}) option(WITH_DEBUG_GDI "Print graphics debug messages." ${DEFAULT_DEBUG_OPTION}) option(WITH_DEBUG_KBD "Print keyboard related debug messages." ${DEFAULT_DEBUG_OPTION}) option(WITH_DEBUG_LICENSE "Print license debug messages." ${DEFAULT_DEBUG_OPTION}) diff --git a/cmake/FindGStreamer_0_10.cmake b/cmake/FindGStreamer_0_10.cmake new file mode 100644 index 000000000000..0342f4c64559 --- /dev/null +++ b/cmake/FindGStreamer_0_10.cmake @@ -0,0 +1,118 @@ +# - Try to find GStreamer +# Once done this will define +# +# GSTREAMER_0_10_FOUND - system has GStreamer +# GSTREAMER_0_10_INCLUDE_DIRS - the GStreamer include directory +# GSTREAMER_0_10_LIBRARIES - the libraries needed to use GStreamer +# GSTREAMER_0_10_DEFINITIONS - Compiler switches required for using GStreamer + +# Copyright (c) 2006, Tim Beaulen +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +# TODO: Other versions --> GSTREAMER_X_Y_FOUND (Example: GSTREAMER_0_8_FOUND and GSTREAMER_0_10_FOUND etc) + +IF (GSTREAMER_0_10_INCLUDE_DIRS AND GSTREAMER_0_10_LIBRARIES AND GSTREAMER_0_10_BASE_LIBRARY AND GSTREAMER_0_10_INTERFACE_LIBRARY) + # in cache already + SET(GSTREAMER_0_10_FIND_QUIETLY TRUE) +ELSE (GSTREAMER_0_10_INCLUDE_DIRS AND GSTREAMER_0_10_LIBRARIES AND GSTREAMER_0_10_BASE_LIBRARY AND GSTREAMER_0_10_INTERFACE_LIBRARY) + SET(GSTREAMER_0_10_FIND_QUIETLY FALSE) +ENDIF (GSTREAMER_0_10_INCLUDE_DIRS AND GSTREAMER_0_10_LIBRARIES AND GSTREAMER_0_10_BASE_LIBRARY AND GSTREAMER_0_10_INTERFACE_LIBRARY) + +IF (NOT WIN32) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + FIND_PACKAGE(PkgConfig) + PKG_CHECK_MODULES(PC_GSTREAMER_0_10 QUIET gstreamer-0.10) + #MESSAGE(STATUS "DEBUG: GStreamer include directory = ${GSTREAMER_0_10_INCLUDE_DIRSS}") + #MESSAGE(STATUS "DEBUG: GStreamer link directory = ${GSTREAMER_0_10_LIBRARY_DIRS}") + #MESSAGE(STATUS "DEBUG: GStreamer CFlags = ${GSTREAMER_0_10_CFLAGS_OTHER}") + SET(GSTREAMER_0_10_DEFINITIONS ${PC_GSTREAMER_0_10_CFLAGS_OTHER}) +ENDIF (NOT WIN32) + +FIND_PATH(GSTREAMER_0_10_INCLUDE_DIRS gst/gst.h + PATHS + ${PC_GSTREAMER_0_10_INCLUDEDIR} + ${PC_GSTREAMER_0_10_INCLUDE_DIRSS} + #PATH_SUFFIXES gst + ) + +FIND_LIBRARY(GSTREAMER_0_10_LIBRARIES NAMES gstreamer-0.10 + PATHS + ${PC_GSTREAMER_0_10_LIBDIR} + ${PC_GSTREAMER_0_10_LIBRARY_DIRS} + ) + +FIND_LIBRARY(GSTREAMER_0_10_BASE_LIBRARY NAMES gstbase-0.10 + PATHS + ${PC_GSTREAMER_0_10_LIBDIR} + ${PC_GSTREAMER_0_10_LIBRARY_DIRS} + ) + +FIND_LIBRARY(GSTREAMER_0_10_APP_LIBRARY NAMES gstapp-0.10 + PATHS + ${PC_GSTREAMER_0_10_LIBDIR} + ${PC_GSTREAMER_0_10_LIBRARY_DIRS} + ) + +FIND_LIBRARY(GSTREAMER_0_10_INTERFACE_LIBRARY NAMES gstinterfaces-0.10 + PATHS + ${PC_GSTREAMER_0_10_LIBDIR} + ${PC_GSTREAMER_0_10_LIBRARY_DIRS} + ) + +FIND_PACKAGE(Glib REQUIRED) +FIND_PACKAGE(LibXml2 REQUIRED) + +IF (GSTREAMER_0_10_INCLUDE_DIRS) + #MESSAGE(STATUS "DEBUG: Found GStreamer include dir: ${GSTREAMER_0_10_INCLUDE_DIRS}") +ELSE (GSTREAMER_0_10_INCLUDE_DIRS) + MESSAGE(STATUS "GStreamer: WARNING: include dir not found") +ENDIF (GSTREAMER_0_10_INCLUDE_DIRS) + +IF (GSTREAMER_0_10_LIBRARIES) + #MESSAGE(STATUS "DEBUG: Found GStreamer library: ${GSTREAMER_0_10_LIBRARIES}") +ELSE (GSTREAMER_0_10_LIBRARIES) + MESSAGE(STATUS "GStreamer: WARNING: library not found") +ENDIF (GSTREAMER_0_10_LIBRARIES) + +IF (GSTREAMER_0_10_INTERFACE_LIBRARY) + #MESSAGE(STATUS "DEBUG: Found GStreamer interface library: ${GSTREAMER_0_10_INTERFACE_LIBRARY}") +ELSE (GSTREAMER_0_10_INTERFACE_LIBRARY) + MESSAGE(STATUS "GStreamer: WARNING: interface library not found") +ENDIF (GSTREAMER_0_10_INTERFACE_LIBRARY) + +set(_GSTREAMER_0_10_REQUIRED_VARS + Glib_INCLUDE_DIRS + Glib_LIBRARIES + LIBXML2_INCLUDE_DIR + LIBXML2_LIBRARIES + GSTREAMER_0_10_INCLUDE_DIRS + GSTREAMER_0_10_LIBRARIES + VERSION_OK + GSTREAMER_0_10_BASE_INCLUDE_DIRS + GSTREAMER_0_10_BASE_LIBRARY + GSTREAMER_0_10_INTERFACE_INCLUDE_DIRS + GSTREAMER_0_10_INTERFACE_LIBRARY) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(GSTREAMER_0_10 DEFAULT_MSG + GSTREAMER_0_10_LIBRARIES + GSTREAMER_0_10_INCLUDE_DIRS + GSTREAMER_0_10_BASE_LIBRARY + GSTREAMER_0_10_INTERFACE_LIBRARY) + +list(APPEND GSTREAMER_0_10_INCLUDE_DIRS ${Glib_INCLUDE_DIRS}) +list(APPEND GSTREAMER_0_10_LIBRARIES ${Glib_LIBRARIES}) +list(APPEND GSTREAMER_0_10_INCLUDE_DIRS ${LIBXML2_INCLUDE_DIR}) +list(APPEND GSTREAMER_0_10_LIBRARIES ${LIBXML2_LIBRARIES}) +list(APPEND GSTREAMER_0_10_INCLUDE_DIRS ${GSTREAMER_0_10_BASE_INCLUDE_DIR}) +list(APPEND GSTREAMER_0_10_LIBRARIES ${GSTREAMER_0_10_BASE_LIBRARY}) +list(APPEND GSTREAMER_0_10_INCLUDE_DIRS ${GSTREAMER_0_10_APP_INCLUDE_DIR}) +list(APPEND GSTREAMER_0_10_LIBRARIES ${GSTREAMER_0_10_APP_LIBRARY}) +list(APPEND GSTREAMER_0_10_INCLUDE_DIRS ${GSTREAMER_0_10_INTERFACE_INCLUDE_DIR}) +list(APPEND GSTREAMER_0_10_LIBRARIES ${GSTREAMER_0_10_INTERFACE_LIBRARY}) + +MARK_AS_ADVANCED(GSTREAMER_0_10_INCLUDE_DIRS GSTREAMER_0_10_LIBRARIES GSTREAMER_0_10_BASE_LIBRARY GSTREAMER_0_10_INTERFACE_LIBRARY) + diff --git a/cmake/FindGStreamer_1_0.cmake b/cmake/FindGStreamer_1_0.cmake new file mode 100644 index 000000000000..f7bf990db605 --- /dev/null +++ b/cmake/FindGStreamer_1_0.cmake @@ -0,0 +1,153 @@ +# - Try to find Gstreamer and its plugins +# Once done, this will define +# +# GSTREAMER_1_0_FOUND - system has Gstreamer +# GSTREAMER_1_0_INCLUDE_DIRS - the Gstreamer include directories +# GSTREAMER_1_0_LIBRARIES - link these to use Gstreamer +# +# Additionally, gstreamer-base is always looked for and required, and +# the following related variables are defined: +# +# GSTREAMER_1_0_BASE_INCLUDE_DIRS - gstreamer-base's include directory +# GSTREAMER_1_0_BASE_LIBRARIES - link to these to use gstreamer-base +# +# Optionally, the COMPONENTS keyword can be passed to find_package() +# and Gstreamer plugins can be looked for. Currently, the following +# plugins can be searched, and they define the following variables if +# found: +# +# gstreamer-app: GSTREAMER_1_0_APP_INCLUDE_DIRS and GSTREAMER_1_0_APP_LIBRARIES +# gstreamer-audio: GSTREAMER_1_0_AUDIO_INCLUDE_DIRS and GSTREAMER_1_0_AUDIO_LIBRARIES +# gstreamer-fft: GSTREAMER_1_0_FFT_INCLUDE_DIRS and GSTREAMER_1_0_FFT_LIBRARIES +# gstreamer-pbutils: GSTREAMER_1_0_PBUTILS_INCLUDE_DIRS and GSTREAMER_1_0_PBUTILS_LIBRARIES +# gstreamer-video: GSTREAMER_1_0_VIDEO_INCLUDE_DIRS and GSTREAMER_1_0_VIDEO_LIBRARIES +# +# Copyright (C) 2012 Raphael Kubo da Costa +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS +# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +find_package(PkgConfig) + +# The minimum Gstreamer version we support. +set(GSTREAMER_1_0_MINIMUM_VERSION 1.0.5) + +# Helper macro to find a Gstreamer plugin (or Gstreamer itself) +# _component_prefix is prepended to the _INCLUDE_DIRS and _LIBRARIES variables (eg. "GSTREAMER_1_0_AUDIO") +# _pkgconfig_name is the component's pkg-config name (eg. "gstreamer-1.0", or "gstreamer-video-1.0"). +# _header is the component's header, relative to the gstreamer-1.0 directory (eg. "gst/gst.h"). +# _library is the component's library name (eg. "gstreamer-1.0" or "gstvideo-1.0") +macro(FIND_GSTREAMER_COMPONENT _component_prefix _pkgconfig_name _header _library) + # FIXME: The QUIET keyword can be used once we require CMake 2.8.2. + pkg_check_modules(PC_${_component_prefix} ${_pkgconfig_name}) + + find_path(${_component_prefix}_INCLUDE_DIRS + NAMES ${_header} + HINTS ${PC_${_component_prefix}_INCLUDE_DIRS} ${PC_${_component_prefix}_INCLUDEDIR} + PATH_SUFFIXES gstreamer-1.0 + ) + + find_library(${_component_prefix}_LIBRARIES + NAMES ${_library} gstreamer_android + HINTS ${PC_${_component_prefix}_LIBRARY_DIRS} ${PC_${_component_prefix}_LIBDIR} ${GSTREAMER_1_0_ROOT_DIR} + ) +endmacro() + +# ------------------------ +# 1. Find Gstreamer itself +# ------------------------ + +# 1.1. Find headers and libraries +set(GLIB_ROOT_DIR ${GSTREAMER_1_0_ROOT_DIR}) +find_package(Glib REQUIRED) +FIND_GSTREAMER_COMPONENT(GSTREAMER_1_0 gstreamer-1.0 gst/gst.h gstreamer-1.0) +FIND_GSTREAMER_COMPONENT(GSTREAMER_1_0_BASE gstreamer-base-1.0 gst/gst.h gstbase-1.0) + +# 1.2. Check Gstreamer version +if (GSTREAMER_1_0_INCLUDE_DIRS) + if (EXISTS "${GSTREAMER_1_0_INCLUDE_DIRS}/gst/gstversion.h") + file(READ "${GSTREAMER_1_0_INCLUDE_DIRS}/gst/gstversion.h" GSTREAMER_VERSION_CONTENTS) + + string(REGEX MATCH "#define +GST_VERSION_MAJOR +\\(([0-9]+)\\)" _dummy "${GSTREAMER_VERSION_CONTENTS}") + set(GSTREAMER_1_0_VERSION_MAJOR "${CMAKE_MATCH_1}") + + string(REGEX MATCH "#define +GST_VERSION_MINOR +\\(([0-9]+)\\)" _dummy "${GSTREAMER_1_0_VERSION_CONTENTS}") + set(GSTREAMER_1_0_VERSION_MINOR "${CMAKE_MATCH_1}") + + string(REGEX MATCH "#define +GST_VERSION_MICRO +\\(([0-9]+)\\)" _dummy "${GSTREAMER_1_0_VERSION_CONTENTS}") + set(GSTREAMER_1_0_VERSION_MICRO "${CMAKE_MATCH_1}") + + set(GSTREAMER_1_0_VERSION "${GSTREAMER_1_0_VERSION_MAJOR}.${GSTREAMER_1_0_VERSION_MINOR}.${GSTREAMER_1_0_VERSION_MICRO}") + endif () +endif () + +# FIXME: With CMake 2.8.3 we can just pass GSTREAMER_1_0_VERSION to FIND_PACKAGE_HANDLE_STANDARD_ARGS as VERSION_VAR +# and remove the version check here (GSTREAMER_1_0_MINIMUM_VERSION would be passed to FIND_PACKAGE). +set(VERSION_OK TRUE) +if ("${GSTREAMER_1_0_VERSION}" VERSION_LESS "${GSTREAMER_1_0_MINIMUM_VERSION}") + set(VERSION_OK FALSE) +endif () + +# ------------------------- +# 2. Find Gstreamer plugins +# ------------------------- + +FIND_GSTREAMER_COMPONENT(GSTREAMER_1_0_APP gstreamer-app-1.0 gst/app/gstappsink.h gstapp-1.0) +FIND_GSTREAMER_COMPONENT(GSTREAMER_1_0_AUDIO gstreamer-audio-1.0 gst/audio/audio.h gstaudio-1.0) +FIND_GSTREAMER_COMPONENT(GSTREAMER_1_0_FFT gstreamer-fft-1.0 gst/fft/gstfft.h gstfft-1.0) +FIND_GSTREAMER_COMPONENT(GSTREAMER_1_0_PBUTILS gstreamer-pbutils-1.0 gst/pbutils/pbutils.h gstpbutils-1.0) +FIND_GSTREAMER_COMPONENT(GSTREAMER_1_0_VIDEO gstreamer-video-1.0 gst/video/video.h gstvideo-1.0) + +# ------------------------------------------------ +# 3. Process the COMPONENTS passed to FIND_PACKAGE +# ------------------------------------------------ +set(_GSTREAMER_1_0_REQUIRED_VARS + Glib_INCLUDE_DIRS + Glib_LIBRARIES + GSTREAMER_1_0_INCLUDE_DIRS + GSTREAMER_1_0_LIBRARIES + VERSION_OK + GSTREAMER_1_0_BASE_INCLUDE_DIRS + GSTREAMER_1_0_BASE_LIBRARIES) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(GSTREAMER_1_0 DEFAULT_MSG GSTREAMER_1_0_LIBRARIES GSTREAMER_1_0_INCLUDE_DIRS) + +list(APPEND GSTREAMER_1_0_INCLUDE_DIRS ${Glib_INCLUDE_DIRS}) +list(APPEND GSTREAMER_1_0_LIBRARIES ${Glib_LIBRARIES}) +list(APPEND GSTREAMER_1_0_INCLUDE_DIRS ${GSTREAMER_1_0_BASE_INCLUDE_DIRS}) +list(APPEND GSTREAMER_1_0_LIBRARIES ${GSTREAMER_1_0_BASE_LIBRARIES}) +list(APPEND GSTREAMER_1_0_INCLUDE_DIRS ${GSTREAMER_1_0_APP_INCLUDE_DIRS}) +list(APPEND GSTREAMER_1_0_LIBRARIES ${GSTREAMER_1_0_APP_LIBRARIES}) +list(APPEND GSTREAMER_1_0_INCLUDE_DIRS ${GSTREAMER_1_0_VIDEO_INCLUDE_DIRS}) +list(APPEND GSTREAMER_1_0_LIBRARIES ${GSTREAMER_1_0_VIDEO_LIBRARIES}) + +foreach (_component ${Gstreamer_FIND_COMPONENTS}) + set(_gst_component "GSTREAMER_1_0_${_component}") + string(TOUPPER ${_gst_component} _UPPER_NAME) + + FIND_PACKAGE_HANDLE_STANDARD_ARGS(${_UPPER_NAME} DEFAULT_MSG ${_UPPER_NAME}_INCLUDE_DIRS ${_UPPER_NAME}_LIBRARIES) + list(APPEND GSTREAMER_1_0_INCLUDE_DIRS ${${_UPPER_NAME}_INCLUDE_DIRS}) + list(APPEND GSTREAMER_1_0_LIBRARIES ${${_UPPER_NAME}_LIBRARIES}) +endforeach () + +MARK_AS_ADVANCED(GSTREAMER_1_0_INCLUDE_DIRS GSTREAMER_1_0_LIBRARIES GSTREAMER_1_0_BASE_LIBRARY GSTREAMER_1_0_APP_LIBRARY) + diff --git a/cmake/FindGlib.cmake b/cmake/FindGlib.cmake new file mode 100644 index 000000000000..3e22eb0750e1 --- /dev/null +++ b/cmake/FindGlib.cmake @@ -0,0 +1,43 @@ +# - Try to find Glib-2.0 (with gobject) +# Once done, this will define +# +# Glib_FOUND - system has Glib +# Glib_INCLUDE_DIRS - the Glib include directories +# Glib_LIBRARIES - link these to use Glib +# +# GLIB_ROOT_DIR - Primary search directory +include(LibFindMacros) + +# Use pkg-config to get hints about paths +libfind_pkg_check_modules(Glib_PKGCONF glib-2.0) + +# Main include dir +find_path(Glib_INCLUDE_DIR + NAMES glib.h + PATHS ${Glib_PKGCONF_INCLUDE_DIRS} ${GLIB_ROOT_DIR} + PATH_SUFFIXES glib-2.0 + ) + +# Finally the library itself +find_library(Glib_LIBRARY + NAMES glib-2.0 gstreamer_android + PATHS ${Glib_PKGCONF_LIBRARY_DIRS} ${GLIB_ROOT_DIR} + ) +find_library(Gobject_LIBRARY + NAMES gobject-2.0 gstreamer_android + PATHS ${Glib_PKGCONF_LIBRARY_DIRS} ${GLIB_ROOT_DIR} + ) + +# Glib-related libraries also use a separate config header, which is in lib dir +find_path(GlibConfig_INCLUDE_DIR + NAMES glibconfig.h + PATHS ${Glib_PKGCONF_INCLUDE_DIRS} /usr ${GLIB_ROOT_DIR} + PATH_SUFFIXES lib/glib-2.0/include glib-2.0/include + ) + +# Set the include dir variables and the libraries and let libfind_process do the rest. +# NOTE: Singular variables for this library, plural for libraries this this lib depends on. +set(Glib_PROCESS_INCLUDES Glib_INCLUDE_DIR GlibConfig_INCLUDE_DIR) +set(Glib_PROCESS_LIBS Glib_LIBRARY Gobject_LIBRARY) +libfind_process(Glib) + diff --git a/cmake/FindGstreamer.cmake b/cmake/FindGstreamer.cmake deleted file mode 100644 index c4451c61ab6f..000000000000 --- a/cmake/FindGstreamer.cmake +++ /dev/null @@ -1,12 +0,0 @@ -include(FindPkgConfig) - -pkg_check_modules(PC_GSTREAMER_0_10 gstreamer-0.10) -pkg_check_modules(PC_GSTREAMER_PLUGINS_BASE_0_10 gstreamer-plugins-base-0.10) - -if(PC_GSTREAMER_0_10_FOUND AND PC_GSTREAMER_PLUGINS_BASE_0_10_FOUND) - set(GSTREAMER_INCLUDE_DIRS ${PC_GSTREAMER_0_10_INCLUDE_DIRS} ${PC_GSTREAMER_PLUGINS_BASE_0_10_INCLUDE_DIRS}) - set(GSTREAMER_LIBRARIES ${PC_GSTREAMER_0_10_LIBRARIES} ${PC_GSTREAMER_PLUGINS_BASE_0_10_LIBRARIES}) -endif() - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(GSTREAMER DEFAULT_MSG GSTREAMER_LIBRARIES GSTREAMER_INCLUDE_DIRS) diff --git a/cmake/LibFindMacros.cmake b/cmake/LibFindMacros.cmake new file mode 100644 index 000000000000..0e47404c5f1f --- /dev/null +++ b/cmake/LibFindMacros.cmake @@ -0,0 +1,116 @@ +# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments +# used for the current package. For this to work, the first parameter must be the +# prefix of the current package, then the prefix of the new package etc, which are +# passed to find_package. +macro(libfind_package PREFIX) + set(LIBFIND_PACKAGE_ARGS $ {ARGN}) + if($ {PREFIX} _FIND_QUIETLY) + set(LIBFIND_PACKAGE_ARGS $ {LIBFIND_PACKAGE_ARGS} QUIET) + endif($ {PREFIX} _FIND_QUIETLY) + if($ {PREFIX} _FIND_REQUIRED) + set(LIBFIND_PACKAGE_ARGS $ {LIBFIND_PACKAGE_ARGS} REQUIRED) + endif($ {PREFIX} _FIND_REQUIRED) + find_package($ {LIBFIND_PACKAGE_ARGS}) +endmacro(libfind_package) + +# CMake developers made the UsePkgConfig system deprecated in the same release (2.6) +# where they added pkg_check_modules. Consequently I need to support both in my scripts +# to avoid those deprecated warnings. Here's a helper that does just that. +# Works identically to pkg_check_modules, except that no checks are needed prior to use. +macro (libfind_pkg_check_modules PREFIX PKGNAME) + if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) + include(UsePkgConfig) + pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS) + else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_check_modules(${PREFIX} ${PKGNAME}) + endif (PKG_CONFIG_FOUND) + endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) +endmacro (libfind_pkg_check_modules) + +# Do the final processing once the paths have been detected. +# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain +# all the variables, each of which contain one include directory. +# Ditto for ${PREFIX}_PROCESS_LIBS and library files. +# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES. +# Also handles errors in case library detection was required, etc. +macro (libfind_process PREFIX) +# Skip processing if already processed during this run + if (NOT ${PREFIX}_FOUND) +# Start with the assumption that the library was found + set (${PREFIX}_FOUND TRUE) + +# Process all includes and set _FOUND to false if any are missing + foreach (i ${${PREFIX}_PROCESS_INCLUDES}) + if (${i}) + set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}}) + mark_as_advanced(${i}) + else (${i}) + set (${PREFIX}_FOUND FALSE) + endif (${i}) + endforeach (i) + +# Process all libraries and set _FOUND to false if any are missing + foreach (i ${${PREFIX}_PROCESS_LIBS}) + if (${i}) + set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}}) + mark_as_advanced(${i}) + else (${i}) + set (${PREFIX}_FOUND FALSE) + endif (${i}) + endforeach (i) + +# Print message and/or exit on fatal error + if (${PREFIX}_FOUND) + if (NOT ${PREFIX}_FIND_QUIETLY) + message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}") + endif (NOT ${PREFIX}_FIND_QUIETLY) + else (${PREFIX}_FOUND) + if (${PREFIX}_FIND_REQUIRED) + foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS}) + message("${i}=${${i}}") + endforeach (i) + message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.") + endif (${PREFIX}_FIND_REQUIRED) + endif (${PREFIX}_FOUND) + endif (NOT ${PREFIX}_FOUND) +endmacro (libfind_process) + +macro(libfind_library PREFIX basename) + set(TMP "") + if(MSVC80) + set(TMP -vc80) + endif(MSVC80) + if(MSVC90) + set(TMP -vc90) + endif(MSVC90) + set(${PREFIX}_LIBNAMES ${basename}${TMP}) + if(${ARGC} GREATER 2) + set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2}) + string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES}) + set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP}) + endif(${ARGC} GREATER 2) + find_library(${PREFIX}_LIBRARY + NAMES ${${PREFIX}_LIBNAMES} + PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS}) +endmacro(libfind_library) + +SET(THREE_PART_VERSION_REGEX "[0-9]+\\.[0-9]+\\.[0-9]+") +# Breaks up a string in the form n1.n2.n3 into three parts and stores +# them in major, minor, and patch. version should be a value, not a +# variable, while major, minor and patch should be variables. +MACRO(THREE_PART_VERSION_TO_VARS version major minor patch) + IF(${version} MATCHES ${THREE_PART_VERSION_REGEX}) + STRING(REPLACE "." " " version_list ${version}) + SEPARATE_ARGUMENTS(version_list) + LIST(GET version_list 0 ${major}) + LIST(GET version_list 1 ${minor}) + LIST(GET version_list 2 ${patch}) + ELSE(${version} MATCHES ${THREE_PART_VERSION_REGEX}) + MESSAGE("MACRO(THREE_PART_VERSION_TO_VARS ${version} ${major} ${minor} ${patch}") + MESSAGE(FATAL_ERROR "Problem parsing version string, I can't parse it properly.") + ENDIF(${version} MATCHES ${THREE_PART_VERSION_REGEX}) +ENDMACRO(THREE_PART_VERSION_TO_VARS) + + diff --git a/config.h.in b/config.h.in index 043dae23d46e..df9001f72775 100755 --- a/config.h.in +++ b/config.h.in @@ -39,6 +39,9 @@ #cmakedefine WITH_WIN8 #cmakedefine WITH_RDPSND_DSOUND +#cmakedefine WITH_FFMPEG +#cmakedefine WITH_GSTREAMER_1_0 +#cmakedefine WITH_GSTREAMER_0_10 #cmakedefine WITH_WINMM #cmakedefine WITH_MACAUDIO #cmakedefine WITH_ALSA @@ -58,6 +61,7 @@ #cmakedefine WITH_DEBUG_CHANNELS #cmakedefine WITH_DEBUG_CLIPRDR #cmakedefine WITH_DEBUG_DVC +#cmakedefine WITH_DEBUG_TSMF #cmakedefine WITH_DEBUG_GDI #cmakedefine WITH_DEBUG_KBD #cmakedefine WITH_DEBUG_LICENSE diff --git a/include/freerdp/channels/tsmf.h b/include/freerdp/channels/tsmf.h new file mode 100644 index 000000000000..f6a7ef4c2e6f --- /dev/null +++ b/include/freerdp/channels/tsmf.h @@ -0,0 +1,63 @@ +/* + * FreeRDP: A Remote Desktop Protocol Implementation + * Video Redirection Virtual Channel - Callback interface + * + * (C) Copyright 2014 Thincast Technologies GmbH + * (C) Copyright 2014 Armin Novak + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _TSMF_H_ +#define _TSMF_H_ + +#include + +/* 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 + diff --git a/include/freerdp/dvc.h b/include/freerdp/dvc.h index a2350bfe8f04..7911fa556a6e 100644 --- a/include/freerdp/dvc.h +++ b/include/freerdp/dvc.h @@ -65,96 +65,100 @@ typedef struct _IWTSVirtualChannelCallback IWTSVirtualChannelCallback; struct _IWTSListener { /* Retrieves the listener-specific configuration. */ - int (*GetConfiguration) (IWTSListener* pListener, - void** ppPropertyBag); + int (*GetConfiguration)(IWTSListener *pListener, + void **ppPropertyBag); - void* pInterface; + void *pInterface; }; struct _IWTSVirtualChannel { /* Starts a write request on the channel. */ - int (*Write) (IWTSVirtualChannel* pChannel, - UINT32 cbSize, - BYTE* pBuffer, - void* pReserved); + int (*Write)(IWTSVirtualChannel *pChannel, + UINT32 cbSize, + BYTE *pBuffer, + void *pReserved); /* Closes the channel. */ - int (*Close) (IWTSVirtualChannel* pChannel); + int (*Close)(IWTSVirtualChannel *pChannel); }; struct _IWTSVirtualChannelManager { /* Returns an instance of a listener object that listens on a specific endpoint, or creates a static channel. */ - int (*CreateListener) (IWTSVirtualChannelManager* pChannelMgr, - const char* pszChannelName, - UINT32 ulFlags, - IWTSListenerCallback* pListenerCallback, - IWTSListener** ppListener); + int (*CreateListener)(IWTSVirtualChannelManager *pChannelMgr, + const char *pszChannelName, + UINT32 ulFlags, + IWTSListenerCallback *pListenerCallback, + IWTSListener **ppListener); /* Push a virtual channel event. This is a FreeRDP extension to standard MS API. */ - int (*PushEvent) (IWTSVirtualChannelManager* pChannelMgr, - wMessage* pEvent); + int (*PushEvent)(IWTSVirtualChannelManager *pChannelMgr, + wMessage *pEvent); /* Find the channel or ID to send data to a specific endpoint. */ - UINT32 (*GetChannelId) (IWTSVirtualChannel * channel); - IWTSVirtualChannel* (*FindChannelById) (IWTSVirtualChannelManager* pChannelMgr, - UINT32 ChannelId); + UINT32(*GetChannelId)(IWTSVirtualChannel *channel); + IWTSVirtualChannel *(*FindChannelById)(IWTSVirtualChannelManager *pChannelMgr, + UINT32 ChannelId); }; struct _IWTSPlugin { /* Used for the first call that is made from the client to the plug-in. */ - int (*Initialize) (IWTSPlugin* pPlugin, - IWTSVirtualChannelManager* pChannelMgr); + int (*Initialize)(IWTSPlugin *pPlugin, + IWTSVirtualChannelManager *pChannelMgr); /* Notifies the plug-in that the Remote Desktop Connection (RDC) client has successfully connected to the Remote Desktop Session Host (RD Session Host) server. */ - int (*Connected) (IWTSPlugin* pPlugin); + int (*Connected)(IWTSPlugin *pPlugin); /* Notifies the plug-in that the Remote Desktop Connection (RDC) client has disconnected from the RD Session Host server. */ - int (*Disconnected) (IWTSPlugin* pPlugin, - UINT32 dwDisconnectCode); + int (*Disconnected)(IWTSPlugin *pPlugin, + UINT32 dwDisconnectCode); /* Notifies the plug-in that the Remote Desktop Connection (RDC) client has terminated. */ - int (*Terminated) (IWTSPlugin* pPlugin); + int (*Terminated)(IWTSPlugin *pPlugin); /* Extended */ - void* pInterface; + void *pInterface; }; struct _IWTSListenerCallback { /* Accepts or denies a connection request for an incoming connection to the associated listener. */ - int (*OnNewChannelConnection) (IWTSListenerCallback* pListenerCallback, - IWTSVirtualChannel* pChannel, - BYTE* Data, - int* pbAccept, - IWTSVirtualChannelCallback** ppCallback); + int (*OnNewChannelConnection)(IWTSListenerCallback *pListenerCallback, + IWTSVirtualChannel *pChannel, + BYTE *Data, + int *pbAccept, + IWTSVirtualChannelCallback **ppCallback); }; struct _IWTSVirtualChannelCallback { /* Notifies the user about data that is being received. */ - int (*OnDataReceived) (IWTSVirtualChannelCallback* pChannelCallback, - UINT32 cbSize, - BYTE* pBuffer); + int (*OnDataReceived)(IWTSVirtualChannelCallback *pChannelCallback, + UINT32 cbSize, + BYTE *pBuffer); /* Notifies the user that the channel has been closed. */ - int (*OnClose) (IWTSVirtualChannelCallback* pChannelCallback); + int (*OnClose)(IWTSVirtualChannelCallback *pChannelCallback); }; /* The DVC Plugin entry points */ typedef struct _IDRDYNVC_ENTRY_POINTS IDRDYNVC_ENTRY_POINTS; struct _IDRDYNVC_ENTRY_POINTS { - int (*RegisterPlugin) (IDRDYNVC_ENTRY_POINTS* pEntryPoints, - const char* name, IWTSPlugin* pPlugin); - IWTSPlugin* (*GetPlugin) (IDRDYNVC_ENTRY_POINTS* pEntryPoints, - const char* name); - ADDIN_ARGV* (*GetPluginData) (IDRDYNVC_ENTRY_POINTS* pEntryPoints); + int (*RegisterPlugin)(IDRDYNVC_ENTRY_POINTS *pEntryPoints, + const char *name, IWTSPlugin *pPlugin); + IWTSPlugin *(*GetPlugin)(IDRDYNVC_ENTRY_POINTS *pEntryPoints, + const char *name); + ADDIN_ARGV *(*GetPluginData)(IDRDYNVC_ENTRY_POINTS *pEntryPoints); }; -typedef int (*PDVC_PLUGIN_ENTRY) (IDRDYNVC_ENTRY_POINTS*); +typedef int (*PDVC_PLUGIN_ENTRY)(IDRDYNVC_ENTRY_POINTS *); + +void *get_callback_by_name(const char *name, void **context); +void add_callback_by_name(const char *name, void *fkt, void *context); +void remove_callback_by_name(const char *name, void *context); #endif /* FREERDP_DVC_H */ diff --git a/scripts/format_code.sh b/scripts/format_code.sh new file mode 100755 index 000000000000..d4c30e020e76 --- /dev/null +++ b/scripts/format_code.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +ASTYLE=`which astyle` + +if [ ! -x $ASTYLE ]; +then + echo "No astyle found in path, please install." + exit 1 +fi + +if [ $# -le 0 ]; then + echo "Usage:" + echo "\t$0 [ ...]" +# echo "\t$0 -r " + exit 2 +fi + +$ASTYLE --lineend=linux --mode=c --indent=force-tab=4 --brackets=linux --pad-header \ + --indent-switches --indent-cases --indent-preprocessor \ + --indent-col1-comments --delete-empty-lines --break-closing-brackets \ + --align-pointer=name --indent-labels --brackets=break \ + --unpad-paren --break-blocks $@ +exit $? diff --git a/winpr/libwinpr/utils/collections/ArrayList.c b/winpr/libwinpr/utils/collections/ArrayList.c index 938a17f93dbd..478f26b746e8 100644 --- a/winpr/libwinpr/utils/collections/ArrayList.c +++ b/winpr/libwinpr/utils/collections/ArrayList.c @@ -285,7 +285,11 @@ BOOL ArrayList_Remove(wArrayList* arrayList, void* obj) } if (found) + { + if (arrayList->object.fnObjectFree) + arrayList->object.fnObjectFree(arrayList->array[index]); ret = ArrayList_Shift(arrayList, index, -1); + } if (arrayList->synchronized) LeaveCriticalSection(&arrayList->lock); @@ -305,6 +309,8 @@ BOOL ArrayList_RemoveAt(wArrayList* arrayList, int index) if ((index >= 0) && (index < arrayList->size)) { + if (arrayList->object.fnObjectFree) + arrayList->object.fnObjectFree(arrayList->array[index]); ret = ArrayList_Shift(arrayList, index, -1); }