From 3fde4f0bc2ea3f42f3fed90b8edff20d0fc9938a Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:04:51 +0200 Subject: [PATCH 01/37] Added callback dictionary with context to allow client to communicate with plugin. --- channels/drdynvc/client/dvcman.c | 395 ++++++++++++++++--------------- include/freerdp/dvc.h | 84 +++---- 2 files changed, 249 insertions(+), 230 deletions(-) diff --git a/channels/drdynvc/client/dvcman.c b/channels/drdynvc/client/dvcman.c index da170160dc95..1c25a887b47c 100644 --- a/channels/drdynvc/client/dvcman.c +++ b/channels/drdynvc/client/dvcman.c @@ -21,6 +21,8 @@ #include "config.h" #endif +#include + #include #include #include @@ -28,45 +30,45 @@ #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) { *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; - - if (dvcman->num_listeners < MAX_PLUGINS) + DVCMAN *dvcman = (DVCMAN *) pChannelMgr; + DVCMAN_LISTENER *listener; + if(dvcman->num_listeners < MAX_PLUGINS) { DEBUG_DVC("%d.%s.", dvcman->num_listeners, pszChannelName); - - listener = (DVCMAN_LISTENER*) malloc(sizeof(DVCMAN_LISTENER)); + listener = (DVCMAN_LISTENER *) malloc(sizeof(DVCMAN_LISTENER)); ZeroMemory(listener, sizeof(DVCMAN_LISTENER)); - 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; - - dvcman->listeners[dvcman->num_listeners++] = (IWTSListener*) listener; - + if(ppListener) + *ppListener = (IWTSListener *) listener; + dvcman->listeners[dvcman->num_listeners++] = (IWTSListener *) listener; return 0; } else @@ -76,14 +78,12 @@ 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; status = drdynvc_push_event(dvcman->drdynvc, pEvent); - - if (status == 0) + if(status == 0) { DEBUG_DVC("event_type %d pushed.", GetMessageType(pEvent->id)); } @@ -91,15 +91,13 @@ static int dvcman_push_event(IWTSVirtualChannelManager* pChannelMgr, wMessage* p { DEBUG_WARN("event_type %d push failed.", GetMessageType(pEvent->id)); } - 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; - - if (dvcman->num_plugins < MAX_PLUGINS) + DVCMAN *dvcman = ((DVCMAN_ENTRY_POINTS *) pEntryPoints)->dvcman; + if(dvcman->num_plugins < MAX_PLUGINS) { DEBUG_DVC("num_plugins %d", dvcman->num_plugins); dvcman->plugin_names[dvcman->num_plugins] = name; @@ -113,365 +111,299 @@ 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; - - for (i = 0; i < dvcman->num_plugins; i++) + DVCMAN *dvcman = ((DVCMAN_ENTRY_POINTS *) pEntryPoints)->dvcman; + for(i = 0; i < dvcman->num_plugins; i++) { - if (dvcman->plugin_names[i] == name || - strcmp(dvcman->plugin_names[i], name) == 0) + if(dvcman->plugin_names[i] == name || + strcmp(dvcman->plugin_names[i], name) == 0) { return dvcman->plugins[i]; } } - 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; + 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; + 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; ArrayList_Lock(dvcman->channels); - index = 0; - channel = (DVCMAN_CHANNEL*) ArrayList_GetItem(dvcman->channels, index++); - - while (channel) + channel = (DVCMAN_CHANNEL *) ArrayList_GetItem(dvcman->channels, index++); + while(channel) { - if (channel->channel_id == ChannelId) + if(channel->channel_id == ChannelId) { found = TRUE; 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; - - for (i = 0; i < dvcman->num_listeners; i++) + void *pInterface = NULL; + DVCMAN_LISTENER *listener; + DVCMAN *dvcman = (DVCMAN *) pChannelMgr; + for(i = 0; i < dvcman->num_listeners; i++) { - listener = (DVCMAN_LISTENER*) dvcman->listeners[i]; - - if (strcmp(listener->channel_name, ChannelName) == 0) + listener = (DVCMAN_LISTENER *) dvcman->listeners[i]; + if(strcmp(listener->channel_name, ChannelName) == 0) { pInterface = listener->iface.pInterface; found = TRUE; break; } } - return (found) ? pInterface : NULL; } -IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin) +IWTSVirtualChannelManager *dvcman_new(drdynvcPlugin *plugin) { - DVCMAN* dvcman; - - dvcman = (DVCMAN*) malloc(sizeof(DVCMAN)); + DVCMAN *dvcman; + dvcman = (DVCMAN *) malloc(sizeof(DVCMAN)); ZeroMemory(dvcman, sizeof(DVCMAN)); - dvcman->iface.CreateListener = dvcman_create_listener; dvcman->iface.PushEvent = dvcman_push_event; dvcman->iface.FindChannelById = dvcman_find_channel_by_id; 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; - 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); - - if (pDVCPluginEntry) + 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) { - if (channel->channel_callback) + 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; ArrayList_Lock(dvcman->channels); - count = ArrayList_Count(dvcman->channels); - - for (i = 0; i < count; i++) + 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++) + 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); } - - for (i = 0; i < dvcman->num_plugins; i++) + for(i = 0; i < dvcman->num_plugins; i++) { pPlugin = dvcman->plugins[i]; - - if (pPlugin->Terminated) + if(pPlugin->Terminated) pPlugin->Terminated(pPlugin); } - free(dvcman); } -int dvcman_init(IWTSVirtualChannelManager* pChannelMgr) +int dvcman_init(IWTSVirtualChannelManager *pChannelMgr) { int i; - IWTSPlugin* pPlugin; - DVCMAN* dvcman = (DVCMAN*) pChannelMgr; - - for (i = 0; i < dvcman->num_plugins; i++) + IWTSPlugin *pPlugin; + DVCMAN *dvcman = (DVCMAN *) pChannelMgr; + for(i = 0; i < dvcman->num_plugins; i++) { pPlugin = dvcman->plugins[i]; - - if (pPlugin->Initialize) + if(pPlugin->Initialize) pPlugin->Initialize(pPlugin, 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; 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; 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; - - channel = (DVCMAN_CHANNEL*) malloc(sizeof(DVCMAN_CHANNEL)); + DVCMAN_LISTENER *listener; + DVCMAN_CHANNEL *channel; + DrdynvcClientContext *context; + IWTSVirtualChannelCallback *pCallback; + DVCMAN *dvcman = (DVCMAN *) pChannelMgr; + channel = (DVCMAN_CHANNEL *) malloc(sizeof(DVCMAN_CHANNEL)); 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++) + for(i = 0; i < dvcman->num_listeners; i++) { - listener = (DVCMAN_LISTENER*) dvcman->listeners[i]; - - if (strcmp(listener->channel_name, ChannelName) == 0) + listener = (DVCMAN_LISTENER *) dvcman->listeners[i]; + 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; - - if (listener->listener_callback->OnNewChannelConnection(listener->listener_callback, - (IWTSVirtualChannel*) channel, NULL, &bAccept, &pCallback) == 0 && bAccept == 1) + if(listener->listener_callback->OnNewChannelConnection(listener->listener_callback, + (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; - 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; } } } - free(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); - - if (!channel) + DVCMAN_CHANNEL *channel; + IWTSVirtualChannel *ichannel; + DrdynvcClientContext *context; + DVCMAN *dvcman = (DVCMAN *) pChannelMgr; + channel = (DVCMAN_CHANNEL *) dvcman_find_channel_by_id(pChannelMgr, ChannelId); + if(!channel) { DEBUG_WARN("ChannelId %d not found!", ChannelId); return 1; } - - if (channel->dvc_data) + if(channel->dvc_data) { Stream_Free(channel->dvc_data, TRUE); channel->dvc_data = NULL; } - - if (channel->status == 0) + if(channel->status == 0) { 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); - - if (!channel) + DVCMAN_CHANNEL *channel; + channel = (DVCMAN_CHANNEL *) dvcman_find_channel_by_id(pChannelMgr, ChannelId); + if(!channel) { DEBUG_WARN("ChannelId %d not found!", ChannelId); return 1; } - - if (channel->dvc_data) + if(channel->dvc_data) 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); - - if (!channel) + DVCMAN_CHANNEL *channel; + channel = (DVCMAN_CHANNEL *) dvcman_find_channel_by_id(pChannelMgr, ChannelId); + if(!channel) { DEBUG_WARN("ChannelId %d not found!", ChannelId); return 1; } - - if (channel->dvc_data) + if(channel->dvc_data) { /* Fragmented data */ - if (Stream_GetPosition(channel->dvc_data) + data_size > (UINT32) Stream_Capacity(channel->dvc_data)) + if(Stream_GetPosition(channel->dvc_data) + data_size > (UINT32) Stream_Capacity(channel->dvc_data)) { DEBUG_WARN("data exceeding declared length!"); Stream_Free(channel->dvc_data, TRUE); channel->dvc_data = NULL; return 1; } - Stream_Write(channel->dvc_data, data, data_size); - - if (((size_t) Stream_GetPosition(channel->dvc_data)) >= Stream_Capacity(channel->dvc_data)) + 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; } @@ -480,6 +412,89 @@ int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 C { 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); + assert(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(!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/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 */ From 3c2779542d170dc1164f78fcc93506f6c0bf96a0 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:05:29 +0200 Subject: [PATCH 02/37] Added TSMF debug flag. Added FFMPEG and GSTREAMER flags. --- config.h.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config.h.in b/config.h.in index 043dae23d46e..7ba190034942 100755 --- a/config.h.in +++ b/config.h.in @@ -39,6 +39,8 @@ #cmakedefine WITH_WIN8 #cmakedefine WITH_RDPSND_DSOUND +#cmakedefine WITH_FFMPEG +#cmakedefine WITH_GSTREAMER #cmakedefine WITH_WINMM #cmakedefine WITH_MACAUDIO #cmakedefine WITH_ALSA @@ -58,6 +60,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 From 309f19f6530ae37f5140d03e36b12b9c9355031f Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:06:03 +0200 Subject: [PATCH 03/37] Added new cmake library search functions. --- cmake/FindGlib.cmake | 43 ++++++++++++++ cmake/LibFindMacros.cmake | 116 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 cmake/FindGlib.cmake create mode 100644 cmake/LibFindMacros.cmake diff --git a/cmake/FindGlib.cmake b/cmake/FindGlib.cmake new file mode 100644 index 000000000000..86427868fbff --- /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/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) + + From f8f611f952284f076c0f5f97a9c8cfdeef271d52 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:06:34 +0200 Subject: [PATCH 04/37] Added TSMF debug flag. --- cmake/ConfigOptions.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/ConfigOptions.cmake b/cmake/ConfigOptions.cmake index 00ce2edb1a4a..4f482b2ac7dc 100644 --- a/cmake/ConfigOptions.cmake +++ b/cmake/ConfigOptions.cmake @@ -98,6 +98,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}) From bcb7c09f5b15171bdffcc7827e1082883d996804 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:06:51 +0200 Subject: [PATCH 05/37] Updated to gstreamer 1.0 script. --- cmake/FindGstreamer.cmake | 149 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 141 insertions(+), 8 deletions(-) diff --git a/cmake/FindGstreamer.cmake b/cmake/FindGstreamer.cmake index c4451c61ab6f..f6823f5c9b8d 100644 --- a/cmake/FindGstreamer.cmake +++ b/cmake/FindGstreamer.cmake @@ -1,12 +1,145 @@ -include(FindPkgConfig) +# - Try to find Gstreamer and its plugins +# Once done, this will define +# +# GSTREAMER_FOUND - system has Gstreamer +# GSTREAMER_INCLUDE_DIRS - the Gstreamer include directories +# GSTREAMER_LIBRARIES - link these to use Gstreamer +# +# Additionally, gstreamer-base is always looked for and required, and +# the following related variables are defined: +# +# GSTREAMER_BASE_INCLUDE_DIRS - gstreamer-base's include directory +# GSTREAMER_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_APP_INCLUDE_DIRS and GSTREAMER_APP_LIBRARIES +# gstreamer-audio: GSTREAMER_AUDIO_INCLUDE_DIRS and GSTREAMER_AUDIO_LIBRARIES +# gstreamer-fft: GSTREAMER_FFT_INCLUDE_DIRS and GSTREAMER_FFT_LIBRARIES +# gstreamer-pbutils: GSTREAMER_PBUTILS_INCLUDE_DIRS and GSTREAMER_PBUTILS_LIBRARIES +# gstreamer-video: GSTREAMER_VIDEO_INCLUDE_DIRS and GSTREAMER_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. -pkg_check_modules(PC_GSTREAMER_0_10 gstreamer-0.10) -pkg_check_modules(PC_GSTREAMER_PLUGINS_BASE_0_10 gstreamer-plugins-base-0.10) +find_package(PkgConfig) -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() +# The minimum Gstreamer version we support. +set(GSTREAMER_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_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_ROOT_DIR} + ) +endmacro() + +# ------------------------ +# 1. Find Gstreamer itself +# ------------------------ + +# 1.1. Find headers and libraries +set(GLIB_ROOT_DIR ${GSTREAMER_ROOT_DIR}) +find_package(Glib REQUIRED) +FIND_GSTREAMER_COMPONENT(GSTREAMER gstreamer-1.0 gst/gst.h gstreamer-1.0) +FIND_GSTREAMER_COMPONENT(GSTREAMER_BASE gstreamer-base-1.0 gst/gst.h gstbase-1.0) + +# 1.2. Check Gstreamer version +if (GSTREAMER_INCLUDE_DIRS) + if (EXISTS "${GSTREAMER_INCLUDE_DIRS}/gst/gstversion.h") + file(READ "${GSTREAMER_INCLUDE_DIRS}/gst/gstversion.h" GSTREAMER_VERSION_CONTENTS) + + string(REGEX MATCH "#define +GST_VERSION_MAJOR +\\(([0-9]+)\\)" _dummy "${GSTREAMER_VERSION_CONTENTS}") + set(GSTREAMER_VERSION_MAJOR "${CMAKE_MATCH_1}") + + string(REGEX MATCH "#define +GST_VERSION_MINOR +\\(([0-9]+)\\)" _dummy "${GSTREAMER_VERSION_CONTENTS}") + set(GSTREAMER_VERSION_MINOR "${CMAKE_MATCH_1}") + + string(REGEX MATCH "#define +GST_VERSION_MICRO +\\(([0-9]+)\\)" _dummy "${GSTREAMER_VERSION_CONTENTS}") + set(GSTREAMER_VERSION_MICRO "${CMAKE_MATCH_1}") + + set(GSTREAMER_VERSION "${GSTREAMER_VERSION_MAJOR}.${GSTREAMER_VERSION_MINOR}.${GSTREAMER_VERSION_MICRO}") + endif () +endif () + +# FIXME: With CMake 2.8.3 we can just pass GSTREAMER_VERSION to FIND_PACKAGE_HANDLE_STANDARD_ARGS as VERSION_VAR +# and remove the version check here (GSTREAMER_MINIMUM_VERSION would be passed to FIND_PACKAGE). +set(VERSION_OK TRUE) +if ("${GSTREAMER_VERSION}" VERSION_LESS "${GSTREAMER_MINIMUM_VERSION}") + set(VERSION_OK FALSE) +endif () + +# ------------------------- +# 2. Find Gstreamer plugins +# ------------------------- + +FIND_GSTREAMER_COMPONENT(GSTREAMER_APP gstreamer-app-1.0 gst/app/gstappsink.h gstapp-1.0) +FIND_GSTREAMER_COMPONENT(GSTREAMER_AUDIO gstreamer-audio-1.0 gst/audio/audio.h gstaudio-1.0) +FIND_GSTREAMER_COMPONENT(GSTREAMER_FFT gstreamer-fft-1.0 gst/fft/gstfft.h gstfft-1.0) +FIND_GSTREAMER_COMPONENT(GSTREAMER_PBUTILS gstreamer-pbutils-1.0 gst/pbutils/pbutils.h gstpbutils-1.0) +FIND_GSTREAMER_COMPONENT(GSTREAMER_VIDEO gstreamer-video-1.0 gst/video/video.h gstvideo-1.0) + +# ------------------------------------------------ +# 3. Process the COMPONENTS passed to FIND_PACKAGE +# ------------------------------------------------ +set(_GSTREAMER_REQUIRED_VARS Glib_INCLUDE_DIRS Glib_LIBRARIES GSTREAMER_INCLUDE_DIRS GSTREAMER_LIBRARIES VERSION_OK GSTREAMER_BASE_INCLUDE_DIRS GSTREAMER_BASE_LIBRARIES) include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(GSTREAMER DEFAULT_MSG GSTREAMER_LIBRARIES GSTREAMER_INCLUDE_DIRS) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Gstreamer DEFAULT_MSG GSTREAMER_LIBRARIES GSTREAMER_INCLUDE_DIRS) + +list(APPEND GSTREAMER_INCLUDE_DIRS ${Glib_INCLUDE_DIRS}) +list(APPEND GSTREAMER_LIBRARIES ${Glib_LIBRARIES}) +list(APPEND GSTREAMER_INCLUDE_DIRS ${GSTREAMER_BASE_INCLUDE_DIRS}) +list(APPEND GSTREAMER_LIBRARIES ${GSTREAMER_BASE_LIBRARIES}) +list(APPEND GSTREAMER_INCLUDE_DIRS ${GSTREAMER_APP_INCLUDE_DIRS}) +list(APPEND GSTREAMER_LIBRARIES ${GSTREAMER_APP_LIBRARIES}) +list(APPEND GSTREAMER_INCLUDE_DIRS ${GSTREAMER_VIDEO_INCLUDE_DIRS}) +list(APPEND GSTREAMER_LIBRARIES ${GSTREAMER_VIDEO_LIBRARIES}) + +foreach (_component ${Gstreamer_FIND_COMPONENTS}) + set(_gst_component "GSTREAMER_${_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_INCLUDE_DIRS ${${_UPPER_NAME}_INCLUDE_DIRS}) + list(APPEND GSTREAMER_LIBRARIES ${${_UPPER_NAME}_LIBRARIES}) +endforeach () + + From 726265265fcde0d2266dd667e4e79f942dba1b11 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:07:07 +0200 Subject: [PATCH 06/37] Added code formatting script. --- scripts/format_code.sh | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 scripts/format_code.sh diff --git a/scripts/format_code.sh b/scripts/format_code.sh new file mode 100644 index 000000000000..f6e47add8886 --- /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 \ + --indent-switches --indent-cases --indent-preprocessor \ + --indent-col1-comments --delete-empty-lines --break-closing-brackets \ + --break-elseifs --align-pointer=name --indent-labels --brackets=break \ + --unpad-paren $@ +exit $? From 248955da4c6b3fb629c1925cfcbce298cd0fea38 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:07:37 +0200 Subject: [PATCH 07/37] Fixed memory leak in manpage generation script. --- client/X11/generate_argument_docbook.c | 64 +++++++++++--------------- 1 file changed, 26 insertions(+), 38 deletions(-) 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; } From 78f9472b417c33f559fa00220dce73608c20c140 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:08:22 +0200 Subject: [PATCH 08/37] Removed tsmf.tid hack. --- client/X11/xf_client.c | 943 +++++++++++++---------------------------- 1 file changed, 301 insertions(+), 642 deletions(-) diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 1f704cc40f4e..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,334 +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; + xfContext *xfc; 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 = CreateFileDescriptorEvent(NULL, FALSE, FALSE, xfc->xfds); - - while (WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0) + while(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0) { do { xf_lock_x11(xfc, FALSE); - pending_status = XPending(xfc->display); - xf_unlock_x11(xfc, FALSE); - - if (pending_status) + 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) + if(!process_status) break; } } - while (pending_status); - - if (!process_status) + 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; } @@ -1409,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; @@ -1434,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; @@ -1548,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; @@ -1621,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; @@ -1632,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 @@ -1742,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); - } /** @@ -1787,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; } From b1770c33fd80cc21a52534f6f443c1e035e34050 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:09:11 +0200 Subject: [PATCH 09/37] Now using posix shared memory with process specific identifier. --- client/X11/xf_window.c | 692 ++++++++++++++++------------------------- client/X11/xf_window.h | 58 ++-- 2 files changed, 306 insertions(+), 444 deletions(-) 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 */ From f62dab9fd3bd58a3d62ee8565bc903e34b2dc98e Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:10:34 +0200 Subject: [PATCH 10/37] Added callbacks and names for TSMF. --- include/freerdp/channels/tsmf.h | 63 +++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 include/freerdp/channels/tsmf.h 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 + From 30ffb98205b42286887c4a4bf5677b18f2526858 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:12:34 +0200 Subject: [PATCH 11/37] Now using TSMF debug print. --- channels/tsmf/client/alsa/tsmf_alsa.c | 180 ++++++------- channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c | 301 +++++++++------------- channels/tsmf/client/pulse/tsmf_pulse.c | 240 ++++++++--------- 3 files changed, 298 insertions(+), 423 deletions(-) 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/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; } From 309405592ef46ee84e8fd870726c0bd84298f938 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:43:14 +0200 Subject: [PATCH 12/37] Fixed broken ArrayList_Remove and ArrayList_RemoveAt functions, freeing element now. --- winpr/libwinpr/utils/collections/ArrayList.c | 6 ++++++ 1 file changed, 6 insertions(+) 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); } From 7b455448f2681edb352f369a35a78e2ab048de4e Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:46:37 +0200 Subject: [PATCH 13/37] New gstreamer 1.0 code. --- channels/tsmf/client/gstreamer/CMakeLists.txt | 45 +- channels/tsmf/client/gstreamer/tsmf_X11.c | 240 +++ .../tsmf/client/gstreamer/tsmf_gstreamer.c | 1902 +++++------------ .../tsmf/client/gstreamer/tsmf_platform.h | 68 + 4 files changed, 917 insertions(+), 1338 deletions(-) create mode 100644 channels/tsmf/client/gstreamer/tsmf_X11.c create mode 100644 channels/tsmf/client/gstreamer/tsmf_platform.h diff --git a/channels/tsmf/client/gstreamer/CMakeLists.txt b/channels/tsmf/client/gstreamer/CMakeLists.txt index 5080358c8c1a..e178f9df49ae 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,8 +17,36 @@ define_channel_client_subsystem("tsmf" "gstreamer" "decoder") -set(${MODULE_PREFIX}_SRCS - tsmf_gstreamer.c) +if(NOT GSTREAMER_FOUND) + message(FATAL_ERROR "GStreamer library not found, but required for TSMF module.") +endif() + +set(SRC "tsmf_gstreamer.c") +set(LIBS ${GSTREAMER_LIBRARIES}) +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}) @@ -28,15 +56,12 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N 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..a6cc57cc227e --- /dev/null +++ b/channels/tsmf/client/gstreamer/tsmf_X11.c @@ -0,0 +1,240 @@ +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#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 + { + int shmid; + GstVideoOverlay *overlay = GST_VIDEO_OVERLAY(decoder->outsink); + 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!"); + } + XSetWindowBackgroundPixmap(hdl->disp, hdl->subwin, None); + XMapWindow(hdl->disp, hdl->subwin); + XSync(hdl->disp, FALSE); + gst_video_overlay_set_window_handle(overlay, hdl->subwin); + decoder->ready = TRUE; +#if defined(WITH_XEXT) + hdl->has_shape = XShapeQueryExtension(hdl->disp, &event, &error); +#endif + } + gst_video_overlay_handle_events(overlay, TRUE); + 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 + { + GstVideoOverlay *overlay = GST_VIDEO_OVERLAY(decoder->outsink); + 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_video_overlay_set_render_rectangle(overlay, 0, 0, width, height)) + { + DEBUG_WARN("Could not resize overlay!"); + } + gst_video_overlay_expose(overlay); + 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) +{ + struct X11Handle *hdl = (struct X11Handle *)decoder->platform; + assert(decoder); + assert(hdl); + return 0; +} + +int tsmf_window_resume(TSMFGstreamerDecoder *decoder) +{ + struct X11Handle *hdl = (struct X11Handle *)decoder->platform; + assert(decoder); + assert(hdl); + 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..614db2c42285 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,90 +23,80 @@ #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 - -typedef struct _TSMFGstreamerDecoder -{ - 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) */ - - pthread_t eventloop_thread; - - GstCaps *gst_caps; /* Gstreamer description of the media type */ +static const char *NAME_GST_STATE_PLAYING = "GST_STATE_PLAYING"; +static const char *NAME_GST_STATE_PAUSED = "GST_STATE_PAUSED"; +static const char *NAME_GST_STATE_READY = "GST_STATE_READY"; +static const char *NAME_GST_STATE_NULL = "GST_STATE_NULL"; +static const char *NAME_GST_STATE_VOID_PENDING = "GST_STATE_VOID_PENDING"; +static const char *NAME_GST_STATE_OTHER = "GST_STATE_?"; - GstState state; +static BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder); +static void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder *mdecoder); +static void tsmf_gstreamer_clean_up_pad(TSMFGstreamerDecoder *mdecoder); +static int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, + GstState desired_state); - GstElement *pipe; - GstElement *src; - GstElement *queue; - GstElement *decbin; - GstElement *outbin; - GstElement *outconv; - GstElement *outsink; - GstElement *aVolume; - - BOOL paused; - UINT64 last_sample_end_time; - - Display *disp; - int *xfwin; - Window subwin; - int xOffset; - int yOffset; - BOOL offsetObtained; - int linked; - double gstVolume; - BOOL gstMuted; +const char *get_type(TSMFGstreamerDecoder *mdecoder) +{ + assert(mdecoder); + if(mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + return "VIDEO"; + else + return "AUDIO"; +} - 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; +static void tsmf_gstreamer_enough_data(GstAppSrc *src, gpointer user_data) +{ + TSMFGstreamerDecoder *mdecoder = user_data; + (void)mdecoder; + DEBUG_TSMF("%s", get_type(mdecoder)); +} -} TSMFGstreamerDecoder; +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); +} -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_?"; +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); + if(!mdecoder->paused) + gst_element_set_state(mdecoder->pipe, GST_STATE_PAUSED); + gst_app_src_end_of_stream((GstAppSrc *)mdecoder->src); + if(!mdecoder->paused) + gst_element_set_state(mdecoder->pipe, GST_STATE_PLAYING); + if(mdecoder->sync_cb) + mdecoder->sync_cb(mdecoder->stream); + 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); @@ -113,1481 +105,750 @@ static inline const GstClockTime tsmf_gstreamer_timestamp_ms_to_gst(UINT64 ms_ti static const char *tsmf_gstreamer_state_name(GstState state) { const char *name; - - 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; - + 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; -} - -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); - - return 0; -} -#endif - -static int tsmf_gstreamer_stop_eventloop_thread(TSMFGstreamerDecoder *mdecoder) -{ - DEBUG_DVC("tsmf_gstreamer_stop_eventloop_thread: "); - if (!mdecoder) - return 0; - - if (mdecoder->eventloop_thread != 0) - { - pthread_cancel(mdecoder->eventloop_thread); - } - - return 0; -} - -static int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder * mdecoder, GstState desired_state) +int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, GstState desired_state) { - 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) + if(!mdecoder) + return 0; + 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) + if(desired_state == mdecoder->state) return 0; /* Redundant request - Nothing to do */ - name = tsmf_gstreamer_state_name(desired_state); /* For debug */ - - 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:"); + DEBUG_TSMF("%s to %s", get_type(mdecoder), name); + state_change = gst_element_set_state(mdecoder->pipe, desired_state); + if(state_change == GST_STATE_CHANGE_FAILURE) + DEBUG_WARN("(%s) GST_STATE_CHANGE_FAILURE.", name); else - DEBUG_DVC("tsmf_gstreamer_pipeline_set_state_AUDIO:"); - - while (keep_waiting) - { - 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) + if(state_change == GST_STATE_CHANGE_ASYNC) { - DEBUG_DVC("tsmf_gstreamer_pipeline_set_state(%s) GST_STATE_CHANGE_SUCCESS.", name); + DEBUG_WARN("(%s) GST_STATE_CHANGE_ASYNC.", 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; - } - } - //sleep(1); + else + mdecoder->state = desired_state; return 0; } -static BOOL tsmf_gstreamer_set_format(ITSMFDecoder * decoder, TS_AM_MEDIA_TYPE * media_type) +static GstBuffer *tsmf_get_buffer_from_data(const void *raw_data, gsize size) { - TSMFGstreamerDecoder * mdecoder = (TSMFGstreamerDecoder *) decoder; - if (!mdecoder) - return FALSE; - GstBuffer *gst_buf_cap_codec_data; /* Buffer to hold extra descriptive codec-specific caps data */ + gpointer data; + GstMemory *mem; + GstBuffer *buffer = gst_buffer_new(); + assert(buffer); + assert(size > 0); + data = g_malloc(size); + memcpy(data, raw_data, size); + mem = gst_memory_new_wrapped(0, data, size, 0, size, data, g_free); + gst_buffer_insert_memory(buffer, -1, mem); + return buffer; +} - DEBUG_DVC("tsmf_gstreamer_set_format: "); +static GstBuffer *tsmf_get_buffer_from_payload(TS_AM_MEDIA_TYPE *media_type) +{ + return tsmf_get_buffer_from_data(media_type->ExtraData, media_type->ExtraDataSize); +} - switch (media_type->MajorType) +static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *media_type) +{ + TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + if(!mdecoder) + return FALSE; + 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; } - - switch (media_type->SubType) + 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, + "format", G_TYPE_STRING, "WVC1", + //"framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, + 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, + "format", G_TYPE_STRING, "MP43", + 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, + "format", G_TYPE_STRING, "WMV1", + 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, + "format", G_TYPE_STRING, "WMV2", + 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, + "format", G_TYPE_STRING, "WMV3", + //"framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, + 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, + //"framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, + 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 */ - if (media_type->ExtraData) + if(media_type->ExtraData) { 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); + mdecoder->gst_caps = gst_caps_new_simple("video/x-raw-yuv", + "format", G_TYPE_STRING, "YUY2", + //"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_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", + //"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); 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; } - + if(media_type->ExtraDataSize > 0) + { + GValue val = G_VALUE_INIT; + GstBuffer *buffer = tsmf_get_buffer_from_payload(media_type); + DEBUG_TSMF("Extra data available (%d)", media_type->ExtraDataSize); + g_value_init(&val, GST_TYPE_BUFFER); + g_value_set_boxed(&val, buffer); + gst_caps_set_value(mdecoder->gst_caps, "codec_data", &val); + } + DEBUG_TSMF("%p format '%s'", mdecoder, gst_caps_to_string(mdecoder->gst_caps)); + tsmf_platform_set_format(mdecoder); + /* Create the pipeline... */ + if(!tsmf_gstreamer_pipeline_build(mdecoder)) + return FALSE; return TRUE; } -static void tsmf_gstreamer_pipeline_send_end_of_stream(TSMFGstreamerDecoder * mdecoder) +void tsmf_gstreamer_clean_up_pad(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; + if(!mdecoder || !mdecoder->pipe) + return; + mdecoder->outconv = NULL; + mdecoder->outresample = NULL; + mdecoder->outsink = NULL; + mdecoder->volume = NULL; } -#ifdef __arm__ -/* code from TI to check whether OMX is being lock or not */ -static BOOL tsmf_gstreamer_pipeline_omx_available() +void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder *mdecoder) { - BOOL ret = TRUE; - int shm_fd = 0; - struct shm_info - { - pid_t pid; - }shm_info; - struct shm_info *info = NULL; - - 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)); + //Cleaning up elements + if(!mdecoder || !mdecoder->pipe) + return; + if(mdecoder->pipe && GST_OBJECT_REFCOUNT_VALUE(mdecoder->pipe) > 0) + { + gst_element_set_state(mdecoder->pipe, GST_STATE_NULL); + gst_object_unref(mdecoder->pipe); + } + tsmf_gstreamer_clean_up_pad(mdecoder); + tsmf_window_destroy(mdecoder); + mdecoder->ready = FALSE; + mdecoder->pipe = NULL; + mdecoder->src = NULL; + mdecoder->queue = NULL; + mdecoder->decbin = NULL; + mdecoder->outbin = NULL; +} - 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; +static void +cb_newpad(GstElement *decodebin, + GstPad *pad, + gpointer data) +{ + GstPad *outpad; + TSMFGstreamerDecoder *mdecoder = data; + /* only link once */ + outpad = gst_element_get_static_pad(mdecoder->outbin, "sink"); + if(GST_PAD_IS_LINKED(outpad)) + { + DEBUG_WARN("sink already linded!"); + gst_object_unref(outpad); + return; } + /* link'n'play */ + gst_pad_link(pad, outpad); + gst_object_unref(outpad); +} - if (info->pid) +static void +cb_freepad(GstElement *decodebin, + GstPad *pad, + gpointer data) +{ + GstPad *outpad; + TSMFGstreamerDecoder *mdecoder = data; + outpad = gst_element_get_static_pad(mdecoder->outbin, "sink"); + if(!outpad) { - DEBUG_DVC ("ERROR: omxcore is in use by '%d'", info->pid); - ret = FALSE; + DEBUG_WARN("sink pad does not exist!"); + return; } - else + if(!GST_PAD_IS_LINKED(outpad)) { - DEBUG_DVC ("omxcore is available for use"); + DEBUG_WARN("sink not linded!"); + gst_object_unref(outpad); + return; } - - - exit: - if (info) - munmap (info, sizeof(struct shm_info)); - - if (shm_fd) - close (shm_fd); - - return ret; + /* link'n'play */ + gst_pad_unlink(pad, outpad); + gst_object_unref(outpad); } -#endif -static void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder * mdecoder) +void tsmf_gstreamer_remove_pad(TSMFGstreamerDecoder *mdecoder) { - //Cleaning up elements - if (!mdecoder) - return; - - if (mdecoder->src) - { - gst_object_unref(mdecoder->src); - mdecoder->src = NULL; - } - 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; + gst_element_remove_pad(mdecoder->outbin, mdecoder->ghost_pad); + gst_object_unref(mdecoder->ghost_pad); + mdecoder->ghost_pad = NULL; } } - -static BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder * mdecoder) +BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder *mdecoder) { - if (!mdecoder) - return FALSE; - GstPad *out_pad; - mdecoder->pipe = gst_pipeline_new (NULL); - if (!mdecoder->pipe) - { - DEBUG_WARN("tsmf_gstreamer_pipeline_build: 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; - - switch (mdecoder->tsmf_media_type.SubType) + gboolean linkResult = FALSE; + switch(mdecoder->media_type) { - 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; - } - - 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) + case TSMF_MAJOR_TYPE_VIDEO: { - hwaccelflu = TRUE; + mdecoder->outconv = gst_element_factory_make("videoconvert", "videoconvert"); + mdecoder->outsink = gst_element_factory_make(tsmf_platform_get_video_sink(), "videosink"); + mdecoder->outresample = gst_element_factory_make("videoscale", "videoscale"); + mdecoder->volume = NULL; + DEBUG_TSMF("building Video Pipe"); + break; } - else + case TSMF_MAJOR_TYPE_AUDIO: { - if (OMXavailable) - { - mdecoder->decbin = gst_element_factory_make ("omx_h264dec", NULL); - if (mdecoder->decbin) - hwaccelomx = TRUE; - } - else - mdecoder->decbin = NULL; + mdecoder->outconv = gst_element_factory_make("audioconvert", "audioconvert"); + mdecoder->outresample = gst_element_factory_make("audioresample", "audioresample"); + mdecoder->volume = gst_element_factory_make("volume", "audiovolume"); + mdecoder->outsink = gst_element_factory_make(tsmf_platform_get_audio_sink(), "audiosink"); + DEBUG_TSMF("building Audio Pipe"); + break; } - if (!mdecoder->decbin) - mdecoder->decbin = gst_element_factory_make ("fluh264dec", NULL); - - 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); + DEBUG_WARN("Invalid media type %08X", mdecoder->media_type); + tsmf_gstreamer_clean_up_pad(mdecoder); return FALSE; } - if (!mdecoder->decbin) - { - DEBUG_WARN("tsmf_gstreamer_pipeline_build: Failed to load decoder plugin"); + /* Add audio / video specific elements to outbin */ + if(mdecoder->outconv) + gst_bin_add(GST_BIN(mdecoder->outbin), mdecoder->outconv); + if(mdecoder->outresample) + gst_bin_add(GST_BIN(mdecoder->outbin), mdecoder->outresample); + if(mdecoder->volume) + gst_bin_add(GST_BIN(mdecoder->outbin), mdecoder->volume); + if(mdecoder->outsink) + gst_bin_add(GST_BIN(mdecoder->outbin), mdecoder->outsink); + if(!mdecoder->outconv || ! mdecoder->outsink || !mdecoder->outresample) + { + DEBUG_WARN("Failed to load (some) output pipe elements"); + DEBUG_WARN("converter=%p, sink=%p, resample=%p", + mdecoder->outconv, mdecoder->outsink, mdecoder->outresample); + tsmf_gstreamer_clean_up_pad(mdecoder); return FALSE; } - - switch (mdecoder->media_type) + if(mdecoder->media_type == TSMF_MAJOR_TYPE_AUDIO) { - case TSMF_MAJOR_TYPE_VIDEO: + if(!mdecoder->volume) { - 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"); - - 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: - { - 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 load (some) audio output pipe elements"); + DEBUG_WARN("volume=%p", mdecoder->volume); + tsmf_gstreamer_clean_up_pad(mdecoder); + 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); - 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 */ - gst_app_src_set_caps((GstAppSrc *) mdecoder->src, mdecoder->gst_caps); - 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) + if(mdecoder->media_type == TSMF_MAJOR_TYPE_AUDIO) { - gst_bin_add(GST_BIN(mdecoder->outbin), mdecoder->aVolume); - linkResult = gst_element_link_many(mdecoder->outconv, mdecoder->aVolume, mdecoder->outsink, NULL); + g_object_set(mdecoder->volume, "mute", mdecoder->gstMuted, NULL); + g_object_set(mdecoder->volume, "volume", mdecoder->gstVolume, NULL); + linkResult = gst_element_link_many(mdecoder->outconv, mdecoder->outresample, + mdecoder->volume, mdecoder->outsink, NULL); } else { - linkResult = gst_element_link(mdecoder->outconv, mdecoder->outsink); + linkResult = gst_element_link_many(mdecoder->outconv, + mdecoder->outresample, mdecoder->outsink, NULL); } - if (!linkResult) + if(!linkResult) { - DEBUG_WARN("tsmf_gstreamer_pipeline_build: Failed to link these elements: converter->sink"); - tsmf_gstreamer_clean_up(mdecoder); + DEBUG_WARN("Failed to link these elements: converter->sink"); + tsmf_gstreamer_clean_up_pad(mdecoder); return FALSE; } - - gst_element_add_pad(mdecoder->outbin, gst_ghost_pad_new ("sink", out_pad)); + mdecoder->ghost_pad = gst_ghost_pad_new("sink", out_pad); + gst_element_add_pad(mdecoder->outbin, mdecoder->ghost_pad); gst_object_unref(out_pad); + return TRUE; +} - 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) +BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder) +{ + gboolean linkResult; + if(!mdecoder) + return FALSE; + mdecoder->pipe = gst_pipeline_new("pipeline"); + if(!mdecoder->pipe) { - DEBUG_WARN("tsmf_gstreamer_pipeline_build: Failed to link these elements: source->decoder"); - tsmf_gstreamer_clean_up(mdecoder); + DEBUG_WARN("Failed to create new pipe"); return FALSE; } - - 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_platform_register_handler(mdecoder); + mdecoder->src = gst_element_factory_make("appsrc", "source"); + mdecoder->queue = gst_element_factory_make("queue2", "queue"); + mdecoder->decbin = gst_element_factory_make("decodebin", "decoder"); + mdecoder->outbin = gst_bin_new("outbin"); + /* Add all elements to the bin allowing proper resource cleanup, + * if any step failed. */ + if(mdecoder->src) + gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->src); + if(mdecoder->queue) + gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->queue); + if(mdecoder->decbin) + gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->decbin); + if(mdecoder->outbin) + gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->outbin); + /* Check, if everything was loaded correctly. */ + if(!mdecoder->src || !mdecoder->queue || !mdecoder->decbin || + !mdecoder->outbin) + { + DEBUG_WARN("Failed to load (some) pipeline stage"); + DEBUG_WARN("src=%p, queue=%p, decoder=%p, output=%p", + mdecoder->src, mdecoder->queue, mdecoder->decbin, mdecoder->outbin); tsmf_gstreamer_clean_up(mdecoder); return FALSE; } - - if (GST_IS_X_OVERLAY (mdecoder->outsink)) + gst_pipeline_set_delay((GstPipeline *)mdecoder->pipe, 5000); + /* AppSrc settings */ + GstAppSrcCallbacks callbacks = { - //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(); - } + tsmf_gstreamer_need_data, + tsmf_gstreamer_enough_data, + tsmf_gstreamer_seek_data + }; + g_object_set(mdecoder->src, "format", GST_FORMAT_TIME, NULL); + g_object_set(mdecoder->src, "is-live", TRUE, NULL); + g_object_set(mdecoder->src, "block", TRUE, NULL); + 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); + gst_app_src_set_caps((GstAppSrc *) mdecoder->src, mdecoder->gst_caps); + /* Queue2 settings */ + g_object_set(mdecoder->queue, "use-buffering", FALSE, NULL); + // g_object_set(mdecoder->queue, "use-rate-estimate", TRUE, NULL); + g_object_set(mdecoder->queue, "max-size-buffers", 2, NULL); + /* DecodeBin settings */ + g_signal_connect(mdecoder->decbin, "pad-added", G_CALLBACK(cb_newpad), mdecoder); + g_signal_connect(mdecoder->decbin, "pad-removed", G_CALLBACK(cb_freepad), mdecoder); + /* Sink settings */ + // g_object_set(mdecoder->outsink, "async-handling", TRUE, NULL); + linkResult = gst_element_link_many(mdecoder->src, mdecoder->queue, + mdecoder->decbin, NULL); + if(!linkResult) + { + DEBUG_WARN("Failed to link elements."); + tsmf_gstreamer_clean_up(mdecoder); + return FALSE; } - - g_object_set(mdecoder->outsink, "preroll-queue-len", 10, NULL); + tsmf_gstreamer_add_pad(mdecoder); + 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; 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; - - if (!mdecoder) - { - return FALSE; - } - - int mutexret = pthread_mutex_lock(&mdecoder->gst_mutex); - - if (mutexret != 0) - return FALSE; - - if (mdecoder->shutdown) + 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) { - pthread_mutex_unlock(&mdecoder->gst_mutex); + DEBUG_WARN("Decoder not initialized!"); 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 + /* + * 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 - { - 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); - } - - if (mdecoder->gst_caps == NULL) + */ + 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->gst_caps == NULL) { - DEBUG_WARN("tsmf_gstreamer_decodeEx: tsmf_gstreamer_set_format not called or invalid format."); - pthread_mutex_unlock(&mdecoder->gst_mutex); + DEBUG_WARN("tsmf_gstreamer_set_format not called or invalid format."); return FALSE; } - - if (mdecoder->pipe == NULL) + if(!mdecoder->src) { - 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_start_eventloop_thread(mdecoder); - - 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) - { - 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_WARN("failed to construct pipeline correctly. Unable to push buffer to source element."); + return FALSE; } - - if (!mdecoder->src) + gst_buf = tsmf_get_buffer_from_data(data, data_size); + if(gst_buf == NULL) { - pthread_mutex_unlock(&mdecoder->gst_mutex); - DEBUG_WARN("tsmf_gstreamer_decodeEx: failed to construct pipeline correctly. Unable to push buffer to source element."); + DEBUG_WARN("tsmf_get_buffer_from_data(%p, %d) failed.", data, data_size); return FALSE; } - - if (GST_STATE(mdecoder->pipe) != GST_STATE_PAUSED && GST_STATE(mdecoder->pipe) != GST_STATE_PLAYING) + if(mdecoder->pipeline_start_time_valid) { - 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) + long long diff = start_time; + diff -= mdecoder->last_sample_end_time; + if(diff < 0) + diff *= -1; + /* The pipe is initialized, but there is a discontinuity. + * Seek to the start position... */ + if(diff > 50) { - 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) - { - fclose(fin); - unlink("/tmp/tsmf_video.ready"); - fin = NULL; - } - - fin = fopen("/tmp/tsmf_vseek.info", "rt"); - if (fin) + DEBUG_TSMF("%s seeking to %lld", get_type(mdecoder), start_time); + 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)) { - 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"); + DEBUG_WARN("seek failed"); } + 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); - + GST_BUFFER_PTS(gst_buf) = sample_time; + 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 (!mdecoder->paused) - { - if (mdecoder->subwin) - { - XMapWindow(mdecoder->disp, mdecoder->subwin); - XSync(mdecoder->disp, FALSE); - } + DEBUG_TSMF("state=%s", tsmf_gstreamer_state_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; - - if (mdecoder->shutdown) + TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + if(!mdecoder || !mdecoder->pipe) return; - - if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + 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); - - if (!mdecoder->aVolume) + DEBUG_TSMF("gst_new_vol=[%f]", mdecoder->gstVolume); + 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; - if (!mdecoder) + 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; - - if (mdecoder->subwin) + DEBUG_TSMF("Control_Pause %s", get_type(mdecoder)); + 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) - { - DEBUG_DVC("tsmf_gstreamer_control: Control_Restart"); - mdecoder->paused = FALSE; - if (mdecoder->subwin) + else + if(control_msg == Control_Resume) { - XMapWindow(mdecoder->disp, mdecoder->subwin); - XSync(mdecoder->disp, FALSE); - } - if (mdecoder->pipeline_start_time_valid) + DEBUG_TSMF("Control_Resume %s", get_type(mdecoder)); + if(!mdecoder->paused && !mdecoder->shutdown) + { + DEBUG_WARN("%s: Ignoring control RESUME, already received!", get_type(mdecoder)); + return; + } + + 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) - { - 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) - { - XUnmapWindow(mdecoder->disp, mdecoder->subwin); - XSync(mdecoder->disp, FALSE); } - } - 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 + if(control_msg == Control_Stop) + { + DEBUG_WARN("Control_Stop %s", get_type(mdecoder)); + if(mdecoder->shutdown) + { + 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 + 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"); - - if (!mdecoder) - return 0; - - if (mdecoder->shutdown) - return 0; - - if (!G_IS_OBJECT(mdecoder->queue)) - return 0; - + TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + DEBUG_TSMF(""); + if(!mdecoder) + return FALSE; + if(!G_IS_OBJECT(mdecoder->queue)) + return FALSE; + guint buff_max = 0; + g_object_get(mdecoder->queue, "max-size-buffers", &buff_max, NULL); 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"); - - if (mdecoder) + TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + DEBUG_WARN("%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); - if (mdecoder->gst_caps) + 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) + if(!mdecoder) return 0; - if (!mdecoder->outsink) + if(!mdecoder->outsink) return mdecoder->last_sample_end_time; - 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); + gst_element_query_position(mdecoder->outsink, fmt, &pos); 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); - - //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); - } + DEBUG_TSMF("x=%d, y=%d, w=%d, h=%d, rect=%d", newX, newY, newWidth, + newHeight, numRectangles); + if(mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + tsmf_window_resize(mdecoder, newX, newY, newWidth, newHeight, + numRectangles, rectangles); +} - 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; - - if (!initialized) + TSMFGstreamerDecoder *decoder; + 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 +860,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..3c130710dc6b --- /dev/null +++ b/channels/tsmf/client/gstreamer/tsmf_platform.h @@ -0,0 +1,68 @@ +#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 *queue; + GstElement *decbin; + GstElement *outbin; + GstElement *outconv; + GstElement *outresample; + GstElement *outsink; + GstElement *volume; + GstPad *ghost_pad; + + 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 From 29261a849dc3985ab0699c88cde5c28ce1b9a67c Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:47:28 +0200 Subject: [PATCH 14/37] Now respecting supported decoder backends in fallback, preferring gstreamer. --- channels/tsmf/client/tsmf_decoder.c | 34 +++++++++++++---------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/channels/tsmf/client/tsmf_decoder.c b/channels/tsmf/client/tsmf_decoder.c index 630154776acf..76a8d0eaf7d6 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) + 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; } From 933748a95ce4d8692963bd2db1a679ef16905dfc Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:48:02 +0200 Subject: [PATCH 15/37] Renamed control messages, removed unused ones. Added functions to allow custom ACK and SYNC functions. --- channels/tsmf/client/tsmf_decoder.h | 39 ++++++++++++++++------------- 1 file changed, 21 insertions(+), 18 deletions(-) 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 From 94b81e1bc2c5a5329abcd79d57ca5d9bccd96945 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:49:13 +0200 Subject: [PATCH 16/37] Using TSMF debug define now. Calling presentation sync after sample. --- channels/tsmf/client/tsmf_ifman.c | 337 ++++++++++-------------------- 1 file changed, 113 insertions(+), 224 deletions(-) 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; } From 0ec7ad4aec1274daaa963e51a0b3531caa1f0141 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:49:54 +0200 Subject: [PATCH 17/37] Using TSMF debug define now. Fixed missing NULL pointer checks, replaced magic numbers with define. --- channels/tsmf/client/tsmf_main.c | 264 +++++++++++-------------------- 1 file changed, 95 insertions(+), 169 deletions(-) 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; } From 46fed926ae69e855e1f7599f80f93c08ebe7dccd Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:50:52 +0200 Subject: [PATCH 18/37] Refactored and simplified stream and presentation layer. --- channels/tsmf/client/tsmf_media.c | 1015 +++++++++++------------------ channels/tsmf/client/tsmf_media.h | 49 +- 2 files changed, 414 insertions(+), 650 deletions(-) diff --git a/channels/tsmf/client/tsmf_media.c b/channels/tsmf/client/tsmf_media.c index eece46b652bd..bf574932e1d5 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,23 @@ struct _TSMF_PRESENTATION UINT32 volume; UINT32 muted; - HANDLE mutex; - HANDLE thread; - - wArrayList* stream_list; + wArrayList *stream_list; }; 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 +98,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,321 +115,220 @@ 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; - - if (Queue_Count(stream->sample_list) < 1) + TSMF_PRESENTATION *presentation = stream->presentation; + assert(stream); + if(Queue_Count(stream->sample_list) < 1) return NULL; - - if (sync) + if(sync) { - if (stream->decoder) + if(stream->decoder) { - if (stream->decoder->GetDecodedData) + if(stream->decoder->GetDecodedData) { - if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO) + if(stream->major_type == TSMF_MAJOR_TYPE_AUDIO) { /* Check if some other stream has earlier sample that needs to be played first */ - if (stream->last_end_time > AUDIO_TOLERANCE) + if(stream->last_end_time > AUDIO_TOLERANCE) { ArrayList_Lock(presentation->stream_list); - count = ArrayList_Count(presentation->stream_list); - - for (index = 0; index < count; index++) + for(index = 0; index < count; 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 = (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) { - pending = TRUE; - break; + pending = TRUE; + break; } } - ArrayList_Unlock(presentation->stream_list); } } else { - if (stream->last_end_time > presentation->audio_end_time) + if(stream->last_end_time > presentation->audio_end_time) { pending = TRUE; } } - } } } - - if (pending) + if(pending) return NULL; - - sample = (TSMF_SAMPLE*) Queue_Dequeue(stream->sample_list); - - if (sample && (sample->end_time > stream->last_end_time)) + sample = (TSMF_SAMPLE *) Queue_Dequeue(stream->sample_list); + if(sample && (sample->end_time > stream->last_end_time)) stream->last_end_time = sample->end_time; - return sample; } -static void tsmf_sample_free(TSMF_SAMPLE* sample) +static void tsmf_sample_free(void *arg) { - if (sample->data) + 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; - - ack_time = get_current_time(); - - while ((Queue_Count(stream->sample_ack_list) > 0) && !(WaitForSingleObject(stream->stopEvent, 0) == WAIT_OBJECT_0)) - { - sample = (TSMF_SAMPLE*) Queue_Peek(stream->sample_ack_list); - - if (!sample || (sample->ack_time > ack_time)) - break; - - sample = Queue_Dequeue(stream->sample_ack_list); - - tsmf_sample_ack(sample); - tsmf_sample_free(sample); - } -} - -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); - } - - presentation = tsmf_presentation_find_by_id(guid); - - if (presentation) - { - DEBUG_WARN("duplicated presentation id!"); - return NULL; - } - - presentation = (TSMF_PRESENTATION*) calloc(1, sizeof(TSMF_PRESENTATION)); - + BOOL rc = FALSE; + assert(stream); + Queue_Lock(stream->sample_ack_list); + sample = (TSMF_SAMPLE *) Queue_Peek(stream->sample_ack_list); + if(!sample) + goto finally; + if(!force) + { + ack_time = get_current_time(); + 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 *presentation; + assert(guid); + assert(pChannelCallback); + presentation = (TSMF_PRESENTATION *) calloc(1, sizeof(TSMF_PRESENTATION)); + ZeroMemory(presentation, 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++) + for(index = 0; index < count; index++) { - presentation = (TSMF_PRESENTATION*) ArrayList_GetItem(presentation_list, index); - - if (memcmp(presentation->presentation_id, guid, GUID_SIZE) == 0) + presentation = (TSMF_PRESENTATION *) ArrayList_GetItem(presentation_list, index); + if(memcmp(presentation->presentation_id, guid, GUID_SIZE) == 0) { found = TRUE; break; } } - ArrayList_Unlock(presentation_list); - + if(!found) + DEBUG_WARN("presentation id %s not found", guid_to_string(guid, guid_str, sizeof(guid_str))); return (found) ? presentation : NULL; } -static void tsmf_presentation_restore_last_video_frame(TSMF_PRESENTATION* presentation) -{ - RDP_REDRAW_EVENT* revent; - - 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; - } -} - -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); - - if (sample->data) + 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)) + if(stream->next_start_time > t && + (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); - + 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 /* Dump a .ppm image for every 30 frames. Assuming the frame is in YUV format, we extract the Y values to create a grayscale image. */ static int frame_id = 0; char buf[100]; - FILE * fp; - if ((frame_id % 30) == 0) + FILE *fp; + if((frame_id % 30) == 0) { snprintf(buf, sizeof(buf), "/tmp/FreeRDP_Frame_%d.ppm", frame_id); fp = fopen(buf, "wb"); @@ -463,98 +345,85 @@ static void tsmf_sample_playback_video(TSMF_SAMPLE* sample) } } -static void tsmf_sample_playback_audio(TSMF_SAMPLE* sample) +static void tsmf_sample_playback_audio(TSMF_SAMPLE *sample) { UINT64 latency = 0; - TSMF_STREAM* stream = sample->stream; - - DEBUG_DVC("MessageId %d EndTime %d consumed.", - sample->sample_id, (int)sample->end_time); - - if (sample->stream->audio && sample->data) + 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; - - if (stream->audio && stream->audio->GetLatency) + if(stream->audio && stream->audio->GetLatency) latency = stream->audio->GetLatency(stream->audio); } else { latency = 0; } - sample->ack_time = latency + get_current_time(); stream->last_end_time = sample->end_time + latency; stream->presentation->audio_start_time = sample->start_time + latency; 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; - - if (stream->decoder) + TSMF_STREAM *stream = sample->stream; + if(stream->decoder) { - if (stream->decoder->DecodeEx) + 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) + if(!ret) { - tsmf_sample_ack(sample); - tsmf_sample_free(sample); + tsmf_sample_queue_ack(sample); return; } - free(sample->data); sample->data = NULL; - - if (stream->major_type == TSMF_MAJOR_TYPE_VIDEO) + if(stream->major_type == TSMF_MAJOR_TYPE_VIDEO) { - if (stream->decoder->GetDecodedFormat) + if(stream->decoder->GetDecodedFormat) { pixfmt = stream->decoder->GetDecodedFormat(stream->decoder); - if (pixfmt == ((UINT32) -1)) + 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) + if(stream->decoder->GetDecodedDimension) { ret = stream->decoder->GetDecodedDimension(stream->decoder, &width, &height); - if (ret && (width != stream->width || height != stream->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; } } } - - if (stream->decoder->GetDecodedData) + if(stream->decoder->GetDecodedData) { sample->data = stream->decoder->GetDecodedData(stream->decoder, &sample->decoded_size); - switch (sample->stream->major_type) + 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); @@ -564,587 +433,490 @@ 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; - if (stream->decoder->GetRunningTime) + 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); } - switch (sample->stream->major_type) + if(buffer_filled) { - case TSMF_MAJOR_TYPE_VIDEO: + if(currentRunningTime > sample->start_time) { - 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); - } - } - 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 == 0) { 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); - } + ack_anticipation_time += (sample->start_time - currentRunningTime); } - break; - } - case TSMF_MAJOR_TYPE_AUDIO: - { - last_played_audio_time = currentRunningTime; - if (bufferLevel < 2) + } + else + ack_anticipation_time += sample->duration / 2; + switch(sample->stream->major_type) + { + case TSMF_MAJOR_TYPE_VIDEO: { - ack_anticipation_time += sample->duration; + break; } - else + case TSMF_MAJOR_TYPE_AUDIO: { - 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; - - DEBUG_DVC("in %d", stream->stream_id); + 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_TSMF("out %d", stream->stream_id); + ExitThread(0); + return NULL; +} - if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO && - stream->sample_rate && stream->channels && stream->bits_per_sample) +static void *tsmf_stream_playback_func(void *arg) +{ + 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) { - if (stream->decoder) + if(stream->decoder) { - if (stream->decoder->GetDecodedData) + 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); - if (stream->audio) + 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)) - { - tsmf_stream_process_ack(stream); - sample = tsmf_stream_pop_sample(stream, 1); - - if (sample) - tsmf_sample_playback(sample); - else - USleep(5000); - } - - if (stream->eos || presentation->eos) + while(!(WaitForSingleObject(stream->stopEvent, 0) == WAIT_OBJECT_0)) { - while ((sample = tsmf_stream_pop_sample(stream, 1)) != NULL) + sample = tsmf_stream_pop_sample(stream, 0); + if(sample) tsmf_sample_playback(sample); } - - if (stream->audio) + if(stream->audio) { stream->audio->Free(stream->audio); 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) - return; - - if (!stream->decoder) + if(!stream || !stream->decoder) return; - - if (stream->started) - { - SetEvent(stream->stopEvent); - stream->started = FALSE; - } - - if (stream->decoder->Control) + 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) + if(!stream || !stream->decoder) return; - - if (!stream->decoder) - return; - - if (stream->decoder->Control) + if(stream->decoder->Control) { stream->decoder->Control(stream->decoder, Control_Pause, NULL); } } -static void tsmf_stream_restart(TSMF_STREAM* stream) +static void tsmf_stream_restart(TSMF_STREAM *stream) { - if (!stream) + if(!stream || !stream->decoder) return; - - if (!stream->decoder) - return; - - if (stream->decoder->Control) + 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) + if(stream->decoder != NULL && stream->decoder->ChangeVolume) { stream->decoder->ChangeVolume(stream->decoder, newVolume, muted); } - else if (stream->audio != NULL && stream->audio->ChangeVolume) - { - stream->audio->ChangeVolume(stream->audio, newVolume, muted); - } + else + if(stream->audio != NULL && stream->audio->ChangeVolume) + { + stream->audio->ChangeVolume(stream->audio, newVolume, muted); + } } -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++) + 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++) + 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++) + 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++) + 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; - - tsmf_presentation_flush(presentation); - ArrayList_Lock(presentation->stream_list); - count = ArrayList_Count(presentation->stream_list); - - for (index = 0; index < count; index++) + for(index = 0; index < count; index++) { - stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index); - tsmf_stream_stop(stream); + TSMF_STREAM *stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); + WaitForSingleObject(stream->ready, 500); } - ArrayList_Unlock(presentation->stream_list); +} - tsmf_presentation_restore_last_video_frame(presentation); - - if (presentation->last_rects) - { - free(presentation->last_rects); - presentation->last_rects = NULL; - } - - presentation->last_num_rects = 0; - - if (presentation->output_rects) +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++) { - free(presentation->output_rects); - presentation->output_rects = NULL; + stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); + tsmf_stream_stop(stream); } - - presentation->output_num_rects = 0; + ArrayList_Unlock(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) +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; - - if (presentation->output_rects) - free(presentation->output_rects); - - presentation->output_rects = rects; - presentation->output_num_rects = num_rects; + UINT32 index; + UINT32 count; + TSMF_STREAM *stream; + /* The server may send messages with invalid width / height. + * Ignore those messages. */ + if(!width || !height) + return; + 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); + if(!stream->decoder) + continue; + 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) + if(stream->audio) stream->audio->Flush(stream->audio); - stream->eos = 0; stream->last_end_time = 0; stream->next_start_time = 0; - - if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO) + if(stream->major_type == TSMF_MAJOR_TYPE_AUDIO) { stream->presentation->audio_start_time = 0; stream->presentation->audio_end_time = 0; } } -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++) + 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); - + 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) + if(stream) { DEBUG_WARN("duplicated stream id %d!", stream_id); return NULL; } - - stream = (TSMF_STREAM*) malloc(sizeof(TSMF_STREAM)); + stream = (TSMF_STREAM *) malloc(sizeof(TSMF_STREAM)); ZeroMemory(stream, sizeof(TSMF_STREAM)); - 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++) + for(index = 0; index < count; index++) { - stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index); - - if (stream->stream_id == stream_id) + stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); + if(stream->stream_id == stream_id) { found = TRUE; break; } } - 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) { - TS_AM_MEDIA_TYPE mediatype; + TSMF_STREAM *stream = arg; + ResetEvent(stream->ready); +} - if (stream->decoder) +void tsmf_stream_set_format(TSMF_STREAM *stream, const char *name, wStream *s) +{ + TS_AM_MEDIA_TYPE mediatype; + if(stream->decoder) { DEBUG_WARN("duplicated call"); return; } - tsmf_codec_parse_media_type(&mediatype, 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); - } - else if (mediatype.MajorType == TSMF_MAJOR_TYPE_AUDIO) + if(mediatype.MajorType == TSMF_MAJOR_TYPE_VIDEO) { - DEBUG_DVC("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; - - if (stream->bits_per_sample == 0) - stream->bits_per_sample = 16; + 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_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; + if(stream->bits_per_sample == 0) + stream->bits_per_sample = 16; + } stream->major_type = mediatype.MajorType; stream->width = mediatype.Width; 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); - - ArrayList_Remove(presentation->stream_list, stream); - + SetEvent(stream->stopEvent); + 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); +} - WaitForSingleObject(tsmf_mutex, INFINITE); - - if (TERMINATING) - { - ReleaseMutex(tsmf_mutex); +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); + if(TERMINATING) return; - } - - ReleaseMutex(tsmf_mutex); - - sample = (TSMF_SAMPLE*) calloc(1, sizeof(TSMF_SAMPLE)); - + sample = (TSMF_SAMPLE *) calloc(1, sizeof(TSMF_SAMPLE)); sample->sample_id = sample_id; sample->start_time = start_time; sample->end_time = end_time; @@ -1154,9 +926,8 @@ void tsmf_stream_push_sample(TSMF_STREAM* stream, IWTSVirtualChannelCallback* pC 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); + ZeroMemory(sample->data + data_size, TSMF_BUFFER_PADDING_SIZE); CopyMemory(sample->data, data, data_size); - Queue_Enqueue(stream->sample_list, sample); } @@ -1164,23 +935,18 @@ 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) + if(s == SIGINT) { signal(s, SIG_DFL); kill(getpid(), s); } - else if (s == SIGUSR1) - { - signal(s, SIG_DFL); - } + else + if(s == SIGUSR1) + { + signal(s, SIG_DFL); + } } #endif @@ -1195,12 +961,9 @@ void tsmf_media_init(void) sigaction(SIGINT, &sigtrap, 0); sigaction(SIGUSR1, &sigtrap, 0); #endif - - tsmf_mutex = CreateMutex(NULL, FALSE, NULL); - - if (!presentation_list) + 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); From 12c053c3dccd46d9ef4622dc71a437890e15e681 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:51:14 +0200 Subject: [PATCH 19/37] Replaced DVC with TSMF debug define. --- channels/tsmf/client/tsmf_types.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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; From 3ae7dd123700bfddef36d222795d045fdea71f62 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 13:51:47 +0200 Subject: [PATCH 20/37] Using TSMF debug define now. --- channels/tsmf/client/tsmf_codec.c | 136 ++++++++++++------------------ 1 file changed, 52 insertions(+), 84 deletions(-) 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; } From c6f97b9e261cc8aaf61b318473a90a225d45efd3 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 15:30:04 +0200 Subject: [PATCH 21/37] Fixed formatting, added proper header padding and not removing empty lines. --- scripts/format_code.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) mode change 100644 => 100755 scripts/format_code.sh diff --git a/scripts/format_code.sh b/scripts/format_code.sh old mode 100644 new mode 100755 index f6e47add8886..23b19c1e57fd --- a/scripts/format_code.sh +++ b/scripts/format_code.sh @@ -15,9 +15,9 @@ if [ $# -le 0 ]; then exit 2 fi -$ASTYLE --lineend=linux --mode=c --indent=force-tab=4 --brackets=linux \ +$ASTYLE --lineend=linux --mode=c --indent=force-tab=4 --brackets=linux --style=bsd --pad-header \ --indent-switches --indent-cases --indent-preprocessor \ --indent-col1-comments --delete-empty-lines --break-closing-brackets \ --break-elseifs --align-pointer=name --indent-labels --brackets=break \ - --unpad-paren $@ + --unpad-paren --break-blocks $@ exit $? From 1f1a2fe6e53af9cf76ae97443a8e42a7b12bcab7 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 15:34:43 +0200 Subject: [PATCH 22/37] Fixed formatting of else if statements. --- scripts/format_code.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/format_code.sh b/scripts/format_code.sh index 23b19c1e57fd..d4c30e020e76 100755 --- a/scripts/format_code.sh +++ b/scripts/format_code.sh @@ -15,9 +15,9 @@ if [ $# -le 0 ]; then exit 2 fi -$ASTYLE --lineend=linux --mode=c --indent=force-tab=4 --brackets=linux --style=bsd --pad-header \ +$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 \ - --break-elseifs --align-pointer=name --indent-labels --brackets=break \ + --align-pointer=name --indent-labels --brackets=break \ --unpad-paren --break-blocks $@ exit $? From ec252a3bc407cb98b5177faf8e9927918277444c Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 23 May 2014 15:35:25 +0200 Subject: [PATCH 23/37] Fixed formatting. Replaced else if with switch. --- .../tsmf/client/gstreamer/tsmf_gstreamer.c | 376 ++++++++++++------ 1 file changed, 254 insertions(+), 122 deletions(-) diff --git a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c index 614db2c42285..1c0f83784219 100644 --- a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c +++ b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c @@ -59,7 +59,8 @@ static int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, const char *get_type(TSMFGstreamerDecoder *mdecoder) { assert(mdecoder); - if(mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + + if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) return "VIDEO"; else return "AUDIO"; @@ -84,13 +85,18 @@ static gboolean tsmf_gstreamer_seek_data(GstAppSrc *src, guint64 offset, gpointe TSMFGstreamerDecoder *mdecoder = user_data; (void)mdecoder; DEBUG_TSMF("%s offset=%llu", get_type(mdecoder), offset); - if(!mdecoder->paused) + + if (!mdecoder->paused) gst_element_set_state(mdecoder->pipe, GST_STATE_PAUSED); + gst_app_src_end_of_stream((GstAppSrc *)mdecoder->src); - if(!mdecoder->paused) + + if (!mdecoder->paused) gst_element_set_state(mdecoder->pipe, GST_STATE_PLAYING); - if(mdecoder->sync_cb) + + if (mdecoder->sync_cb) mdecoder->sync_cb(mdecoder->stream); + return TRUE; } @@ -105,22 +111,34 @@ static inline const GstClockTime tsmf_gstreamer_timestamp_ms_to_gst(UINT64 ms_ti static const char *tsmf_gstreamer_state_name(GstState state) { const char *name; - if(state == GST_STATE_PLAYING) - name = NAME_GST_STATE_PLAYING; - else - if(state == GST_STATE_PAUSED) + + switch (state) + { + case GST_STATE_PLAYING: + name = NAME_GST_STATE_PLAYING; + break; + + case 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; + break; + + case GST_STATE_READY: + name = NAME_GST_STATE_READY; + break; + + case GST_STATE_NULL: + name = NAME_GST_STATE_NULL; + break; + + case GST_STATE_VOID_PENDING: + name = NAME_GST_STATE_VOID_PENDING; + break; + + default: + name = NAME_GST_STATE_OTHER; + break; + } + return name; } @@ -128,25 +146,30 @@ int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, GstState d { GstStateChangeReturn state_change; const char *name; - if(!mdecoder) + + if (!mdecoder) return 0; - if(!mdecoder->pipe) + + 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) + + if (desired_state == mdecoder->state) return 0; /* Redundant request - Nothing to do */ + name = tsmf_gstreamer_state_name(desired_state); /* For debug */ DEBUG_TSMF("%s to %s", get_type(mdecoder), name); state_change = gst_element_set_state(mdecoder->pipe, desired_state); - if(state_change == GST_STATE_CHANGE_FAILURE) + + if (state_change == GST_STATE_CHANGE_FAILURE) DEBUG_WARN("(%s) GST_STATE_CHANGE_FAILURE.", name); + else if (state_change == GST_STATE_CHANGE_ASYNC) + { + DEBUG_WARN("(%s) GST_STATE_CHANGE_ASYNC.", name); + mdecoder->state = desired_state; + } else - if(state_change == GST_STATE_CHANGE_ASYNC) - { - DEBUG_WARN("(%s) GST_STATE_CHANGE_ASYNC.", name); - mdecoder->state = desired_state; - } - else - mdecoder->state = desired_state; + mdecoder->state = desired_state; + return 0; } @@ -172,21 +195,27 @@ static GstBuffer *tsmf_get_buffer_from_payload(TS_AM_MEDIA_TYPE *media_type) static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *media_type) { TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; - if(!mdecoder) + + if (!mdecoder) return FALSE; + DEBUG_TSMF(""); - switch(media_type->MajorType) + + switch (media_type->MajorType) { case TSMF_MAJOR_TYPE_VIDEO: mdecoder->media_type = TSMF_MAJOR_TYPE_VIDEO; break; + case TSMF_MAJOR_TYPE_AUDIO: mdecoder->media_type = TSMF_MAJOR_TYPE_AUDIO; break; + default: return FALSE; } - switch(media_type->SubType) + + switch (media_type->SubType) { case TSMF_SUB_TYPE_WVC1: mdecoder->gst_caps = gst_caps_new_simple("video/x-wmv", @@ -198,6 +227,7 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m //"framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, NULL); break; + case TSMF_SUB_TYPE_MP4S: mdecoder->gst_caps = gst_caps_new_simple("video/x-divx", "divxversion", G_TYPE_INT, 5, @@ -206,6 +236,7 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m "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, @@ -214,6 +245,7 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m "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, @@ -222,6 +254,7 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m "format", G_TYPE_STRING, "MP43", NULL); break; + case TSMF_SUB_TYPE_WMA9: mdecoder->gst_caps = gst_caps_new_simple("audio/x-wma", "wmaversion", G_TYPE_INT, 3, @@ -233,6 +266,7 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m "block_align", G_TYPE_INT, media_type->BlockAlign, NULL); break; + case TSMF_SUB_TYPE_WMA2: mdecoder->gst_caps = gst_caps_new_simple("audio/x-wma", "wmaversion", G_TYPE_INT, 2, @@ -244,6 +278,7 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m "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, @@ -252,6 +287,7 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m "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, @@ -261,6 +297,7 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m "format", G_TYPE_STRING, "WMV1", NULL); break; + case TSMF_SUB_TYPE_WMV2: mdecoder->gst_caps = gst_caps_new_simple("video/x-wmv", "width", G_TYPE_INT, media_type->Width, @@ -269,6 +306,7 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m "format", G_TYPE_STRING, "WMV2", NULL); break; + case TSMF_SUB_TYPE_WMV3: mdecoder->gst_caps = gst_caps_new_simple("video/x-wmv", "bitrate", G_TYPE_UINT, media_type->BitRate, @@ -279,6 +317,7 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m //"framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, NULL); break; + case TSMF_SUB_TYPE_AVC1: case TSMF_SUB_TYPE_H264: mdecoder->gst_caps = gst_caps_new_simple("video/x-h264", @@ -287,33 +326,39 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m //"framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, 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); 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 */ - if(media_type->ExtraData) + if (media_type->ExtraData) { media_type->ExtraData += 12; media_type->ExtraDataSize -= 12; } + 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: 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, @@ -322,6 +367,7 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); break; + case TSMF_SUB_TYPE_YUY2: mdecoder->gst_caps = gst_caps_new_simple("video/x-raw-yuv", "format", G_TYPE_STRING, "YUY2", @@ -330,6 +376,7 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m "height", G_TYPE_INT, media_type->Height, NULL); break; + case TSMF_SUB_TYPE_MP2V: mdecoder->gst_caps = gst_caps_new_simple("video/mpeg", //"bitrate", G_TYPE_UINT, media_type->BitRate, @@ -339,6 +386,7 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m "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, @@ -346,11 +394,13 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m "channels", G_TYPE_INT, media_type->Channels, NULL); break; + default: DEBUG_WARN("unknown format:(%d).", media_type->SubType); return FALSE; } - if(media_type->ExtraDataSize > 0) + + if (media_type->ExtraDataSize > 0) { GValue val = G_VALUE_INIT; GstBuffer *buffer = tsmf_get_buffer_from_payload(media_type); @@ -359,18 +409,22 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m g_value_set_boxed(&val, buffer); gst_caps_set_value(mdecoder->gst_caps, "codec_data", &val); } + DEBUG_TSMF("%p format '%s'", mdecoder, gst_caps_to_string(mdecoder->gst_caps)); tsmf_platform_set_format(mdecoder); + /* Create the pipeline... */ - if(!tsmf_gstreamer_pipeline_build(mdecoder)) + if (!tsmf_gstreamer_pipeline_build(mdecoder)) return FALSE; + return TRUE; } void tsmf_gstreamer_clean_up_pad(TSMFGstreamerDecoder *mdecoder) { - if(!mdecoder || !mdecoder->pipe) + if (!mdecoder || !mdecoder->pipe) return; + mdecoder->outconv = NULL; mdecoder->outresample = NULL; mdecoder->outsink = NULL; @@ -380,13 +434,15 @@ void tsmf_gstreamer_clean_up_pad(TSMFGstreamerDecoder *mdecoder) void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder *mdecoder) { //Cleaning up elements - if(!mdecoder || !mdecoder->pipe) + if (!mdecoder || !mdecoder->pipe) return; - if(mdecoder->pipe && GST_OBJECT_REFCOUNT_VALUE(mdecoder->pipe) > 0) + + if (mdecoder->pipe && GST_OBJECT_REFCOUNT_VALUE(mdecoder->pipe) > 0) { gst_element_set_state(mdecoder->pipe, GST_STATE_NULL); gst_object_unref(mdecoder->pipe); } + tsmf_gstreamer_clean_up_pad(mdecoder); tsmf_window_destroy(mdecoder); mdecoder->ready = FALSE; @@ -406,12 +462,14 @@ cb_newpad(GstElement *decodebin, TSMFGstreamerDecoder *mdecoder = data; /* only link once */ outpad = gst_element_get_static_pad(mdecoder->outbin, "sink"); - if(GST_PAD_IS_LINKED(outpad)) + + if (GST_PAD_IS_LINKED(outpad)) { DEBUG_WARN("sink already linded!"); gst_object_unref(outpad); return; } + /* link'n'play */ gst_pad_link(pad, outpad); gst_object_unref(outpad); @@ -425,17 +483,20 @@ cb_freepad(GstElement *decodebin, GstPad *outpad; TSMFGstreamerDecoder *mdecoder = data; outpad = gst_element_get_static_pad(mdecoder->outbin, "sink"); - if(!outpad) + + if (!outpad) { DEBUG_WARN("sink pad does not exist!"); return; } - if(!GST_PAD_IS_LINKED(outpad)) + + if (!GST_PAD_IS_LINKED(outpad)) { DEBUG_WARN("sink not linded!"); gst_object_unref(outpad); return; } + /* link'n'play */ gst_pad_unlink(pad, outpad); gst_object_unref(outpad); @@ -443,7 +504,7 @@ cb_freepad(GstElement *decodebin, void tsmf_gstreamer_remove_pad(TSMFGstreamerDecoder *mdecoder) { - if(mdecoder->outbin) + if (mdecoder->outbin) { gst_element_remove_pad(mdecoder->outbin, mdecoder->ghost_pad); gst_object_unref(mdecoder->ghost_pad); @@ -455,7 +516,8 @@ BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder *mdecoder) { GstPad *out_pad; gboolean linkResult = FALSE; - switch(mdecoder->media_type) + + switch (mdecoder->media_type) { case TSMF_MAJOR_TYPE_VIDEO: { @@ -466,6 +528,7 @@ BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder *mdecoder) DEBUG_TSMF("building Video Pipe"); break; } + case TSMF_MAJOR_TYPE_AUDIO: { mdecoder->outconv = gst_element_factory_make("audioconvert", "audioconvert"); @@ -475,21 +538,27 @@ BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder *mdecoder) DEBUG_TSMF("building Audio Pipe"); break; } + default: DEBUG_WARN("Invalid media type %08X", mdecoder->media_type); tsmf_gstreamer_clean_up_pad(mdecoder); return FALSE; } + /* Add audio / video specific elements to outbin */ - if(mdecoder->outconv) + if (mdecoder->outconv) gst_bin_add(GST_BIN(mdecoder->outbin), mdecoder->outconv); - if(mdecoder->outresample) + + if (mdecoder->outresample) gst_bin_add(GST_BIN(mdecoder->outbin), mdecoder->outresample); - if(mdecoder->volume) + + if (mdecoder->volume) gst_bin_add(GST_BIN(mdecoder->outbin), mdecoder->volume); - if(mdecoder->outsink) + + if (mdecoder->outsink) gst_bin_add(GST_BIN(mdecoder->outbin), mdecoder->outsink); - if(!mdecoder->outconv || ! mdecoder->outsink || !mdecoder->outresample) + + if (!mdecoder->outconv || ! mdecoder->outsink || !mdecoder->outresample) { DEBUG_WARN("Failed to load (some) output pipe elements"); DEBUG_WARN("converter=%p, sink=%p, resample=%p", @@ -497,9 +566,10 @@ BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder *mdecoder) tsmf_gstreamer_clean_up_pad(mdecoder); return FALSE; } - if(mdecoder->media_type == TSMF_MAJOR_TYPE_AUDIO) + + if (mdecoder->media_type == TSMF_MAJOR_TYPE_AUDIO) { - if(!mdecoder->volume) + if (!mdecoder->volume) { DEBUG_WARN("Failed to load (some) audio output pipe elements"); DEBUG_WARN("volume=%p", mdecoder->volume); @@ -507,8 +577,10 @@ BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder *mdecoder) return FALSE; } } + out_pad = gst_element_get_static_pad(mdecoder->outconv, "sink"); - if(mdecoder->media_type == TSMF_MAJOR_TYPE_AUDIO) + + if (mdecoder->media_type == TSMF_MAJOR_TYPE_AUDIO) { g_object_set(mdecoder->volume, "mute", mdecoder->gstMuted, NULL); g_object_set(mdecoder->volume, "volume", mdecoder->gstVolume, NULL); @@ -520,12 +592,14 @@ BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder *mdecoder) linkResult = gst_element_link_many(mdecoder->outconv, mdecoder->outresample, mdecoder->outsink, NULL); } - if(!linkResult) + + if (!linkResult) { DEBUG_WARN("Failed to link these elements: converter->sink"); tsmf_gstreamer_clean_up_pad(mdecoder); return FALSE; } + mdecoder->ghost_pad = gst_ghost_pad_new("sink", out_pad); gst_element_add_pad(mdecoder->outbin, mdecoder->ghost_pad); gst_object_unref(out_pad); @@ -535,31 +609,40 @@ BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder *mdecoder) BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder) { gboolean linkResult; - if(!mdecoder) + + if (!mdecoder) return FALSE; + mdecoder->pipe = gst_pipeline_new("pipeline"); - if(!mdecoder->pipe) + + if (!mdecoder->pipe) { DEBUG_WARN("Failed to create new pipe"); return FALSE; } + tsmf_platform_register_handler(mdecoder); mdecoder->src = gst_element_factory_make("appsrc", "source"); mdecoder->queue = gst_element_factory_make("queue2", "queue"); mdecoder->decbin = gst_element_factory_make("decodebin", "decoder"); mdecoder->outbin = gst_bin_new("outbin"); + /* Add all elements to the bin allowing proper resource cleanup, * if any step failed. */ - if(mdecoder->src) + if (mdecoder->src) gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->src); - if(mdecoder->queue) + + if (mdecoder->queue) gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->queue); - if(mdecoder->decbin) + + if (mdecoder->decbin) gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->decbin); - if(mdecoder->outbin) + + if (mdecoder->outbin) gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->outbin); + /* Check, if everything was loaded correctly. */ - if(!mdecoder->src || !mdecoder->queue || !mdecoder->decbin || + if (!mdecoder->src || !mdecoder->queue || !mdecoder->decbin || !mdecoder->outbin) { DEBUG_WARN("Failed to load (some) pipeline stage"); @@ -568,6 +651,7 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder) tsmf_gstreamer_clean_up(mdecoder); return FALSE; } + gst_pipeline_set_delay((GstPipeline *)mdecoder->pipe, 5000); /* AppSrc settings */ GstAppSrcCallbacks callbacks = @@ -593,12 +677,14 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder) // g_object_set(mdecoder->outsink, "async-handling", TRUE, NULL); linkResult = gst_element_link_many(mdecoder->src, mdecoder->queue, mdecoder->decbin, NULL); - if(!linkResult) + + if (!linkResult) { DEBUG_WARN("Failed to link elements."); tsmf_gstreamer_clean_up(mdecoder); return FALSE; } + tsmf_gstreamer_add_pad(mdecoder); tsmf_window_create(mdecoder); tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_READY); @@ -615,11 +701,13 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder *decoder, const BYTE *data, UIN 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) + + if (!mdecoder) { DEBUG_WARN("Decoder not initialized!"); return FALSE; } + /* * This function is always called from a stream-specific thread. * It should be alright to block here if necessary. @@ -629,39 +717,48 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder *decoder, const BYTE *data, UIN 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->gst_caps == NULL) + + if (mdecoder->gst_caps == NULL) { DEBUG_WARN("tsmf_gstreamer_set_format not called or invalid format."); return FALSE; } - if(!mdecoder->src) + + if (!mdecoder->src) { DEBUG_WARN("failed to construct pipeline correctly. Unable to push buffer to source element."); return FALSE; } + gst_buf = tsmf_get_buffer_from_data(data, data_size); - if(gst_buf == NULL) + + if (gst_buf == NULL) { DEBUG_WARN("tsmf_get_buffer_from_data(%p, %d) failed.", data, data_size); return FALSE; } - if(mdecoder->pipeline_start_time_valid) + + if (mdecoder->pipeline_start_time_valid) { long long diff = start_time; diff -= mdecoder->last_sample_end_time; - if(diff < 0) + + if (diff < 0) diff *= -1; + /* The pipe is initialized, but there is a discontinuity. * Seek to the start position... */ - if(diff > 50) + if (diff > 50) { DEBUG_TSMF("%s seeking to %lld", get_type(mdecoder), start_time); - 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)) + + 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)) { DEBUG_WARN("seek failed"); } + mdecoder->pipeline_start_time_valid = 0; } } @@ -670,36 +767,48 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder *decoder, const BYTE *data, UIN DEBUG_TSMF("%s start time %llu", get_type(mdecoder), sample_time); mdecoder->pipeline_start_time_valid = 1; } + GST_BUFFER_PTS(gst_buf) = sample_time; GST_BUFFER_DURATION(gst_buf) = sample_duration; gst_app_src_push_buffer(GST_APP_SRC(mdecoder->src), gst_buf); - if(mdecoder->ack_cb) + + if (mdecoder->ack_cb) mdecoder->ack_cb(mdecoder->stream, TRUE); + mdecoder->last_sample_end_time = end_time; - if(GST_STATE(mdecoder->pipe) != GST_STATE_PLAYING) + + if (GST_STATE(mdecoder->pipe) != GST_STATE_PLAYING) { DEBUG_TSMF("state=%s", tsmf_gstreamer_state_name(GST_STATE(mdecoder->pipe))); - if(!mdecoder->paused && !mdecoder->shutdown && mdecoder->ready) + + if (!mdecoder->paused && !mdecoder->shutdown && mdecoder->ready) tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); } + return TRUE; } static void tsmf_gstreamer_change_volume(ITSMFDecoder *decoder, UINT32 newVolume, UINT32 muted) { TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; - if(!mdecoder || !mdecoder->pipe) + + if (!mdecoder || !mdecoder->pipe) return; - if(mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + + if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) return; + mdecoder->gstMuted = (BOOL) muted; DEBUG_TSMF("mute=[%d]", mdecoder->gstMuted); mdecoder->gstVolume = (double) newVolume / (double) 10000; DEBUG_TSMF("gst_new_vol=[%f]", mdecoder->gstVolume); - if(!mdecoder->volume) + + if (!mdecoder->volume) return; - if(!G_IS_OBJECT(mdecoder->volume)) + + if (!G_IS_OBJECT(mdecoder->volume)) return; + g_object_set(mdecoder->volume, "mute", mdecoder->gstMuted, NULL); g_object_set(mdecoder->volume, "volume", mdecoder->gstVolume, NULL); } @@ -707,65 +816,78 @@ static void tsmf_gstreamer_change_volume(ITSMFDecoder *decoder, UINT32 newVolume static void tsmf_gstreamer_control(ITSMFDecoder *decoder, ITSMFControlMsg control_msg, UINT32 *arg) { TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; - if(!mdecoder) + + if (!mdecoder) return; - if(control_msg == Control_Pause) + + if (control_msg == Control_Pause) { DEBUG_TSMF("Control_Pause %s", get_type(mdecoder)); - if(mdecoder->paused) + + if (mdecoder->paused) { 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) + + if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) tsmf_window_pause(mdecoder); } - else - if(control_msg == Control_Resume) + else if (control_msg == Control_Resume) + { + DEBUG_TSMF("Control_Resume %s", get_type(mdecoder)); + + if (!mdecoder->paused && !mdecoder->shutdown) { - DEBUG_TSMF("Control_Resume %s", get_type(mdecoder)); - if(!mdecoder->paused && !mdecoder->shutdown) - { - DEBUG_WARN("%s: Ignoring control RESUME, already received!", get_type(mdecoder)); - return; - } + DEBUG_WARN("%s: Ignoring control RESUME, already received!", get_type(mdecoder)); + return; + } - 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); + 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_Stop) + { + DEBUG_WARN("Control_Stop %s", get_type(mdecoder)); + + if (mdecoder->shutdown) + { + DEBUG_WARN("%s: Ignoring control STOP, already received!", get_type(mdecoder)); + return; } - else - if(control_msg == Control_Stop) - { - DEBUG_WARN("Control_Stop %s", get_type(mdecoder)); - if(mdecoder->shutdown) - { - 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 - DEBUG_WARN("Unknown control message %08x", control_msg); + + 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 + DEBUG_WARN("Unknown control message %08x", control_msg); } static BOOL tsmf_gstreamer_buffer_filled(ITSMFDecoder *decoder) { TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; DEBUG_TSMF(""); - if(!mdecoder) + + if (!mdecoder) return FALSE; - if(!G_IS_OBJECT(mdecoder->queue)) + + if (!G_IS_OBJECT(mdecoder->queue)) return FALSE; + guint buff_max = 0; g_object_get(mdecoder->queue, "max-size-buffers", &buff_max, NULL); guint clbuff = 0; @@ -778,12 +900,15 @@ static void tsmf_gstreamer_free(ITSMFDecoder *decoder) { TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; DEBUG_WARN("%s", get_type(mdecoder)); - if(mdecoder) + + if (mdecoder) { mdecoder->shutdown = 1; tsmf_gstreamer_clean_up(mdecoder); - if(mdecoder->gst_caps) + + if (mdecoder->gst_caps) gst_caps_unref(mdecoder->gst_caps); + tsmf_platform_free(mdecoder); memset(mdecoder, 0, sizeof(TSMFGstreamerDecoder)); free(mdecoder); @@ -794,12 +919,16 @@ static void tsmf_gstreamer_free(ITSMFDecoder *decoder) static UINT64 tsmf_gstreamer_get_running_time(ITSMFDecoder *decoder) { TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; - if(!mdecoder) + + if (!mdecoder) return 0; - if(!mdecoder->outsink) + + 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); @@ -813,7 +942,8 @@ static void tsmf_gstreamer_update_rendering_area(ITSMFDecoder *decoder, TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; DEBUG_TSMF("x=%d, y=%d, w=%d, h=%d, rect=%d", newX, newY, newWidth, newHeight, numRectangles); - if(mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + + if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) tsmf_window_resize(mdecoder, newX, newY, newWidth, newHeight, numRectangles, rectangles); } @@ -843,10 +973,12 @@ BOOL tsmf_gstreamer_sync(ITSMFDecoder *decoder, void (*cb)(void *), void *stream ITSMFDecoder *freerdp_tsmf_client_decoder_subsystem_entry(void) { TSMFGstreamerDecoder *decoder; - if(!gst_is_initialized()) + + if (!gst_is_initialized()) { gst_init(NULL, NULL); } + decoder = malloc(sizeof(TSMFGstreamerDecoder)); memset(decoder, 0, sizeof(TSMFGstreamerDecoder)); decoder->iface.SetFormat = tsmf_gstreamer_set_format; From 058cba93830702c2036c4d175100c5317cf727cb Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Sat, 24 May 2014 13:56:12 +0200 Subject: [PATCH 24/37] Replaced custom state to name function with gstreamer version. --- .../tsmf/client/gstreamer/tsmf_gstreamer.c | 45 +------------------ 1 file changed, 2 insertions(+), 43 deletions(-) diff --git a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c index 1c0f83784219..4dd415e65301 100644 --- a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c +++ b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c @@ -43,13 +43,6 @@ #include #endif -static const char *NAME_GST_STATE_PLAYING = "GST_STATE_PLAYING"; -static const char *NAME_GST_STATE_PAUSED = "GST_STATE_PAUSED"; -static const char *NAME_GST_STATE_READY = "GST_STATE_READY"; -static const char *NAME_GST_STATE_NULL = "GST_STATE_NULL"; -static const char *NAME_GST_STATE_VOID_PENDING = "GST_STATE_VOID_PENDING"; -static const char *NAME_GST_STATE_OTHER = "GST_STATE_?"; - static BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder); static void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder *mdecoder); static void tsmf_gstreamer_clean_up_pad(TSMFGstreamerDecoder *mdecoder); @@ -108,40 +101,6 @@ static inline const GstClockTime tsmf_gstreamer_timestamp_ms_to_gst(UINT64 ms_ti return (GstClockTime)(ms_timestamp * 100); } -static const char *tsmf_gstreamer_state_name(GstState state) -{ - const char *name; - - switch (state) - { - case GST_STATE_PLAYING: - name = NAME_GST_STATE_PLAYING; - break; - - case GST_STATE_PAUSED: - name = NAME_GST_STATE_PAUSED; - break; - - case GST_STATE_READY: - name = NAME_GST_STATE_READY; - break; - - case GST_STATE_NULL: - name = NAME_GST_STATE_NULL; - break; - - case GST_STATE_VOID_PENDING: - name = NAME_GST_STATE_VOID_PENDING; - break; - - default: - name = NAME_GST_STATE_OTHER; - break; - } - - return name; -} - int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, GstState desired_state) { GstStateChangeReturn state_change; @@ -156,7 +115,7 @@ int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, GstState d if (desired_state == mdecoder->state) return 0; /* Redundant request - Nothing to do */ - name = tsmf_gstreamer_state_name(desired_state); /* For debug */ + name = gst_element_state_name(desired_state); /* For debug */ DEBUG_TSMF("%s to %s", get_type(mdecoder), name); state_change = gst_element_set_state(mdecoder->pipe, desired_state); @@ -779,7 +738,7 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder *decoder, const BYTE *data, UIN if (GST_STATE(mdecoder->pipe) != GST_STATE_PLAYING) { - DEBUG_TSMF("state=%s", tsmf_gstreamer_state_name(GST_STATE(mdecoder->pipe))); + DEBUG_TSMF("state=%s", gst_element_state_name(GST_STATE(mdecoder->pipe))); if (!mdecoder->paused && !mdecoder->shutdown && mdecoder->ready) tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); From 00c205cb84417d3a9257fcfca04fe62e2702e8f8 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Sat, 24 May 2014 15:55:55 +0200 Subject: [PATCH 25/37] Fixed busy loop. --- channels/tsmf/client/tsmf_media.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/channels/tsmf/client/tsmf_media.c b/channels/tsmf/client/tsmf_media.c index bf574932e1d5..ee2063f8ab18 100644 --- a/channels/tsmf/client/tsmf_media.c +++ b/channels/tsmf/client/tsmf_media.c @@ -505,6 +505,7 @@ static void *tsmf_stream_ack_func(void *arg) static void *tsmf_stream_playback_func(void *arg) { + HANDLE hdl[2]; TSMF_SAMPLE *sample; TSMF_STREAM *stream = (TSMF_STREAM *) arg; TSMF_PRESENTATION *presentation = stream->presentation; @@ -527,7 +528,10 @@ static void *tsmf_stream_playback_func(void *arg) } } } - 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)) { sample = tsmf_stream_pop_sample(stream, 0); if(sample) From 02649e73221be07d7a74e3cb2c5900293edaa37c Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Sat, 24 May 2014 18:21:40 +0200 Subject: [PATCH 26/37] Added cmake magic to allow selection of gstreamer 1.0 or 0.10 --- CMakeLists.txt | 25 ++- channels/tsmf/client/CMakeLists.txt | 2 +- channels/tsmf/client/gstreamer/CMakeLists.txt | 15 +- channels/tsmf/client/tsmf_decoder.c | 2 +- cmake/FindGStreamer_0_10.cmake | 118 ++++++++++++++ cmake/FindGStreamer_1_0.cmake | 153 ++++++++++++++++++ cmake/FindGlib.cmake | 8 +- config.h.in | 3 +- 8 files changed, 308 insertions(+), 18 deletions(-) create mode 100644 cmake/FindGStreamer_0_10.cmake create mode 100644 cmake/FindGStreamer_1_0.cmake 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/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/gstreamer/CMakeLists.txt b/channels/tsmf/client/gstreamer/CMakeLists.txt index e178f9df49ae..3415da717f65 100644 --- a/channels/tsmf/client/gstreamer/CMakeLists.txt +++ b/channels/tsmf/client/gstreamer/CMakeLists.txt @@ -17,12 +17,22 @@ define_channel_client_subsystem("tsmf" "gstreamer" "decoder") -if(NOT GSTREAMER_FOUND) +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") -set(LIBS ${GSTREAMER_LIBRARIES}) + +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) @@ -49,7 +59,6 @@ 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 "") diff --git a/channels/tsmf/client/tsmf_decoder.c b/channels/tsmf/client/tsmf_decoder.c index 76a8d0eaf7d6..3d17c60d0e11 100644 --- a/channels/tsmf/client/tsmf_decoder.c +++ b/channels/tsmf/client/tsmf_decoder.c @@ -60,7 +60,7 @@ ITSMFDecoder *tsmf_load_decoder(const char *name, TS_AM_MEDIA_TYPE *media_type) { decoder = tsmf_load_decoder_by_name(name, media_type); } -#if defined(WITH_GSTREAMER) +#if defined(WITH_GSTREAMER_1_0) || defined(WITH_GSTREAMER_0_10) if(!decoder) decoder = tsmf_load_decoder_by_name("gstreamer", media_type); #endif 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 index 86427868fbff..3e22eb0750e1 100644 --- a/cmake/FindGlib.cmake +++ b/cmake/FindGlib.cmake @@ -14,24 +14,24 @@ 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} + 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} + 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} + 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} + PATHS ${Glib_PKGCONF_INCLUDE_DIRS} /usr ${GLIB_ROOT_DIR} PATH_SUFFIXES lib/glib-2.0/include glib-2.0/include ) diff --git a/config.h.in b/config.h.in index 7ba190034942..df9001f72775 100755 --- a/config.h.in +++ b/config.h.in @@ -40,7 +40,8 @@ #cmakedefine WITH_RDPSND_DSOUND #cmakedefine WITH_FFMPEG -#cmakedefine WITH_GSTREAMER +#cmakedefine WITH_GSTREAMER_1_0 +#cmakedefine WITH_GSTREAMER_0_10 #cmakedefine WITH_WINMM #cmakedefine WITH_MACAUDIO #cmakedefine WITH_ALSA From e3d5413eb891244db6d28da1f5f08a460a85fdff Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Sat, 24 May 2014 18:22:05 +0200 Subject: [PATCH 27/37] Removed obsolete gstreamer detection script. --- cmake/FindGstreamer.cmake | 145 -------------------------------------- 1 file changed, 145 deletions(-) delete mode 100644 cmake/FindGstreamer.cmake diff --git a/cmake/FindGstreamer.cmake b/cmake/FindGstreamer.cmake deleted file mode 100644 index f6823f5c9b8d..000000000000 --- a/cmake/FindGstreamer.cmake +++ /dev/null @@ -1,145 +0,0 @@ -# - Try to find Gstreamer and its plugins -# Once done, this will define -# -# GSTREAMER_FOUND - system has Gstreamer -# GSTREAMER_INCLUDE_DIRS - the Gstreamer include directories -# GSTREAMER_LIBRARIES - link these to use Gstreamer -# -# Additionally, gstreamer-base is always looked for and required, and -# the following related variables are defined: -# -# GSTREAMER_BASE_INCLUDE_DIRS - gstreamer-base's include directory -# GSTREAMER_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_APP_INCLUDE_DIRS and GSTREAMER_APP_LIBRARIES -# gstreamer-audio: GSTREAMER_AUDIO_INCLUDE_DIRS and GSTREAMER_AUDIO_LIBRARIES -# gstreamer-fft: GSTREAMER_FFT_INCLUDE_DIRS and GSTREAMER_FFT_LIBRARIES -# gstreamer-pbutils: GSTREAMER_PBUTILS_INCLUDE_DIRS and GSTREAMER_PBUTILS_LIBRARIES -# gstreamer-video: GSTREAMER_VIDEO_INCLUDE_DIRS and GSTREAMER_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_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_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_ROOT_DIR} - ) -endmacro() - -# ------------------------ -# 1. Find Gstreamer itself -# ------------------------ - -# 1.1. Find headers and libraries -set(GLIB_ROOT_DIR ${GSTREAMER_ROOT_DIR}) -find_package(Glib REQUIRED) -FIND_GSTREAMER_COMPONENT(GSTREAMER gstreamer-1.0 gst/gst.h gstreamer-1.0) -FIND_GSTREAMER_COMPONENT(GSTREAMER_BASE gstreamer-base-1.0 gst/gst.h gstbase-1.0) - -# 1.2. Check Gstreamer version -if (GSTREAMER_INCLUDE_DIRS) - if (EXISTS "${GSTREAMER_INCLUDE_DIRS}/gst/gstversion.h") - file(READ "${GSTREAMER_INCLUDE_DIRS}/gst/gstversion.h" GSTREAMER_VERSION_CONTENTS) - - string(REGEX MATCH "#define +GST_VERSION_MAJOR +\\(([0-9]+)\\)" _dummy "${GSTREAMER_VERSION_CONTENTS}") - set(GSTREAMER_VERSION_MAJOR "${CMAKE_MATCH_1}") - - string(REGEX MATCH "#define +GST_VERSION_MINOR +\\(([0-9]+)\\)" _dummy "${GSTREAMER_VERSION_CONTENTS}") - set(GSTREAMER_VERSION_MINOR "${CMAKE_MATCH_1}") - - string(REGEX MATCH "#define +GST_VERSION_MICRO +\\(([0-9]+)\\)" _dummy "${GSTREAMER_VERSION_CONTENTS}") - set(GSTREAMER_VERSION_MICRO "${CMAKE_MATCH_1}") - - set(GSTREAMER_VERSION "${GSTREAMER_VERSION_MAJOR}.${GSTREAMER_VERSION_MINOR}.${GSTREAMER_VERSION_MICRO}") - endif () -endif () - -# FIXME: With CMake 2.8.3 we can just pass GSTREAMER_VERSION to FIND_PACKAGE_HANDLE_STANDARD_ARGS as VERSION_VAR -# and remove the version check here (GSTREAMER_MINIMUM_VERSION would be passed to FIND_PACKAGE). -set(VERSION_OK TRUE) -if ("${GSTREAMER_VERSION}" VERSION_LESS "${GSTREAMER_MINIMUM_VERSION}") - set(VERSION_OK FALSE) -endif () - -# ------------------------- -# 2. Find Gstreamer plugins -# ------------------------- - -FIND_GSTREAMER_COMPONENT(GSTREAMER_APP gstreamer-app-1.0 gst/app/gstappsink.h gstapp-1.0) -FIND_GSTREAMER_COMPONENT(GSTREAMER_AUDIO gstreamer-audio-1.0 gst/audio/audio.h gstaudio-1.0) -FIND_GSTREAMER_COMPONENT(GSTREAMER_FFT gstreamer-fft-1.0 gst/fft/gstfft.h gstfft-1.0) -FIND_GSTREAMER_COMPONENT(GSTREAMER_PBUTILS gstreamer-pbutils-1.0 gst/pbutils/pbutils.h gstpbutils-1.0) -FIND_GSTREAMER_COMPONENT(GSTREAMER_VIDEO gstreamer-video-1.0 gst/video/video.h gstvideo-1.0) - -# ------------------------------------------------ -# 3. Process the COMPONENTS passed to FIND_PACKAGE -# ------------------------------------------------ -set(_GSTREAMER_REQUIRED_VARS Glib_INCLUDE_DIRS Glib_LIBRARIES GSTREAMER_INCLUDE_DIRS GSTREAMER_LIBRARIES VERSION_OK GSTREAMER_BASE_INCLUDE_DIRS GSTREAMER_BASE_LIBRARIES) - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(Gstreamer DEFAULT_MSG GSTREAMER_LIBRARIES GSTREAMER_INCLUDE_DIRS) - -list(APPEND GSTREAMER_INCLUDE_DIRS ${Glib_INCLUDE_DIRS}) -list(APPEND GSTREAMER_LIBRARIES ${Glib_LIBRARIES}) -list(APPEND GSTREAMER_INCLUDE_DIRS ${GSTREAMER_BASE_INCLUDE_DIRS}) -list(APPEND GSTREAMER_LIBRARIES ${GSTREAMER_BASE_LIBRARIES}) -list(APPEND GSTREAMER_INCLUDE_DIRS ${GSTREAMER_APP_INCLUDE_DIRS}) -list(APPEND GSTREAMER_LIBRARIES ${GSTREAMER_APP_LIBRARIES}) -list(APPEND GSTREAMER_INCLUDE_DIRS ${GSTREAMER_VIDEO_INCLUDE_DIRS}) -list(APPEND GSTREAMER_LIBRARIES ${GSTREAMER_VIDEO_LIBRARIES}) - -foreach (_component ${Gstreamer_FIND_COMPONENTS}) - set(_gst_component "GSTREAMER_${_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_INCLUDE_DIRS ${${_UPPER_NAME}_INCLUDE_DIRS}) - list(APPEND GSTREAMER_LIBRARIES ${${_UPPER_NAME}_LIBRARIES}) -endforeach () - - From 86e0ff861004500b31d3ce1867f99568af5a3211 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Sat, 24 May 2014 22:22:33 +0200 Subject: [PATCH 28/37] Added support for gstreamer 0.10 --- channels/tsmf/client/gstreamer/tsmf_X11.c | 96 ++++++++++++++----- .../tsmf/client/gstreamer/tsmf_gstreamer.c | 90 +++++++++++------ .../tsmf/client/gstreamer/tsmf_platform.h | 1 + 3 files changed, 135 insertions(+), 52 deletions(-) diff --git a/channels/tsmf/client/gstreamer/tsmf_X11.c b/channels/tsmf/client/gstreamer/tsmf_X11.c index a6cc57cc227e..8b48681bf579 100644 --- a/channels/tsmf/client/gstreamer/tsmf_X11.c +++ b/channels/tsmf/client/gstreamer/tsmf_X11.c @@ -9,7 +9,12 @@ #include #include +#include +#if GST_VERSION_MAJOR > 0 #include +#else +#include +#endif #include #include @@ -59,15 +64,18 @@ int tsmf_platform_create(TSMFGstreamerDecoder *decoder) assert(decoder); assert(!decoder->platform); hdl = malloc(sizeof(struct X11Handle)); - if(!hdl) + + 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) + + if (hdl->shmid < 0) { DEBUG_WARN("%s: failed to get access to shared memory - shmget()", __func__); @@ -75,26 +83,32 @@ int tsmf_platform_create(TSMFGstreamerDecoder *decoder) } else hdl->xfwin = mmap(0, sizeof(void *), PROT_READ | PROT_WRITE, MAP_SHARED, hdl->shmid, 0); - if(hdl->xfwin == (int *)-1) + + if (hdl->xfwin == (int *)-1) { DEBUG_WARN("%s: shmat failed!", __func__); return -3; } + hdl->disp = XOpenDisplay(NULL); - if(!hdl->disp) + + 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) + + if (decoder->media_type == TSMF_MAJOR_TYPE_VIDEO) { } + return 0; } @@ -103,25 +117,32 @@ int tsmf_platform_register_handler(TSMFGstreamerDecoder *decoder) assert(decoder); assert(decoder->pipe); GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(decoder->pipe)); - if(!bus) + + 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) + + if (!hdl) return -1; - if(hdl->disp) + + if (hdl->disp) XCloseDisplay(hdl->disp); - if(hdl->xfwin) + + if (hdl->xfwin) munmap(0, sizeof(void *)); - if(hdl->shmid >= 0) + + if (hdl->shmid >= 0) close(hdl->shmid); + free(hdl); decoder->platform = NULL; return 0; @@ -129,36 +150,47 @@ int tsmf_platform_free(TSMFGstreamerDecoder *decoder) int tsmf_window_create(TSMFGstreamerDecoder *decoder) { - if(decoder->media_type != TSMF_MAJOR_TYPE_VIDEO) + if (decoder->media_type != TSMF_MAJOR_TYPE_VIDEO) { decoder->ready = TRUE; return -3; } else { - int shmid; +#if GST_VERSION_MAJOR > 0 GstVideoOverlay *overlay = GST_VIDEO_OVERLAY(decoder->outsink); +#endif struct X11Handle *hdl = (struct X11Handle *)decoder->platform; assert(decoder); assert(hdl); - if(!hdl->subwin) + + if (!hdl->subwin) { int event, error; hdl->subwin = XCreateSimpleWindow(hdl->disp, *(int *)hdl->xfwin, 0, 0, 1, 1, 0, 0, 0); - if(!hdl->subwin) + + if (!hdl->subwin) { DEBUG_WARN("Could not create subwindow!"); } + XSetWindowBackgroundPixmap(hdl->disp, hdl->subwin, None); 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(GST_X_OVERLAY(decoder->outsink), *hdl->xfwin); +#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); +#endif return 0; } } @@ -166,58 +198,68 @@ int tsmf_window_create(TSMFGstreamerDecoder *decoder) 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) + if (decoder->media_type != TSMF_MAJOR_TYPE_VIDEO) return -3; else { +#if GST_VERSION_MAJOR > 0 GstVideoOverlay *overlay = GST_VIDEO_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_video_overlay_set_render_rectangle(overlay, 0, 0, width, height)) +#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); - if(hdl->subwin) +#else + gst_x_overlay_expose(GST_X_OVERLAY(decoder->outsink)); +#endif + + if (hdl->subwin) { XMoveResizeWindow(hdl->disp, hdl->subwin, x, y, width, height); #if defined(WITH_XEXT) - if(hdl->has_shape) + + 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) { - struct X11Handle *hdl = (struct X11Handle *)decoder->platform; assert(decoder); - assert(hdl); return 0; } int tsmf_window_resume(TSMFGstreamerDecoder *decoder) { - struct X11Handle *hdl = (struct X11Handle *)decoder->platform; assert(decoder); - assert(hdl); return 0; } @@ -225,15 +267,19 @@ int tsmf_window_destroy(TSMFGstreamerDecoder *decoder) { struct X11Handle *hdl = (struct X11Handle *)decoder->platform; decoder->ready = FALSE; - if(decoder->media_type != TSMF_MAJOR_TYPE_VIDEO) + + if (decoder->media_type != TSMF_MAJOR_TYPE_VIDEO) return -3; + assert(decoder); assert(hdl); - if(hdl->subwin) + + 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 4dd415e65301..402b24468fa9 100644 --- a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c +++ b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c @@ -115,7 +115,7 @@ int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, GstState d if (desired_state == mdecoder->state) return 0; /* Redundant request - Nothing to do */ - name = gst_element_state_name(desired_state); /* For debug */ + name = gst_element_state_get_name(desired_state); /* For debug */ DEBUG_TSMF("%s to %s", get_type(mdecoder), name); state_change = gst_element_set_state(mdecoder->pipe, desired_state); @@ -134,21 +134,36 @@ int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, GstState d static GstBuffer *tsmf_get_buffer_from_data(const void *raw_data, gsize size) { + GstBuffer *buffer; gpointer data; - GstMemory *mem; - GstBuffer *buffer = gst_buffer_new(); - assert(buffer); + assert(raw_data); assert(size > 0); data = g_malloc(size); + + if (!data) + { + DEBUG_WARN("Could not allocate %d bytes of data.", size); + return NULL; + } + memcpy(data, raw_data, size); - mem = gst_memory_new_wrapped(0, data, size, 0, size, data, g_free); - gst_buffer_insert_memory(buffer, -1, mem); - return buffer; -} +#if GST_VERSION_MAJOR > 0 + buffer = gst_buffer_new_wrapped(data, size); +#else + buffer = gst_buffer_new(); -static GstBuffer *tsmf_get_buffer_from_payload(TS_AM_MEDIA_TYPE *media_type) -{ - return tsmf_get_buffer_from_data(media_type->ExtraData, media_type->ExtraDataSize); + if (!buffer) + { + DEBUG_WARN("Could not create GstBuffer"); + free(data); + return NULL; + } + + 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) @@ -361,12 +376,17 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m if (media_type->ExtraDataSize > 0) { - GValue val = G_VALUE_INIT; - GstBuffer *buffer = tsmf_get_buffer_from_payload(media_type); + GstBuffer *buffer; DEBUG_TSMF("Extra data available (%d)", media_type->ExtraDataSize); - g_value_init(&val, GST_TYPE_BUFFER); - g_value_set_boxed(&val, buffer); - gst_caps_set_value(mdecoder->gst_caps, "codec_data", &val); + buffer = tsmf_get_buffer_from_data(media_type->ExtraData, media_type->ExtraDataSize); + + if (!buffer) + { + DEBUG_WARN("could not allocate GstBuffer!"); + return FALSE; + } + + 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)); @@ -385,6 +405,7 @@ void tsmf_gstreamer_clean_up_pad(TSMFGstreamerDecoder *mdecoder) return; mdecoder->outconv = NULL; + mdecoder->outrate = NULL; mdecoder->outresample = NULL; mdecoder->outsink = NULL; mdecoder->volume = NULL; @@ -480,7 +501,12 @@ BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder *mdecoder) { case TSMF_MAJOR_TYPE_VIDEO: { +#if GST_VERSION_MAJOR > 0 mdecoder->outconv = gst_element_factory_make("videoconvert", "videoconvert"); +#else + mdecoder->outconv = gst_element_factory_make("ffmpegcolorspace", "videoconvert"); +#endif + mdecoder->outrate = gst_element_factory_make("videorate", "videorate"); mdecoder->outsink = gst_element_factory_make(tsmf_platform_get_video_sink(), "videosink"); mdecoder->outresample = gst_element_factory_make("videoscale", "videoscale"); mdecoder->volume = NULL; @@ -491,6 +517,7 @@ BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder *mdecoder) case TSMF_MAJOR_TYPE_AUDIO: { mdecoder->outconv = gst_element_factory_make("audioconvert", "audioconvert"); + mdecoder->outrate = gst_element_factory_make("audiorate", "audiorate"); mdecoder->outresample = gst_element_factory_make("audioresample", "audioresample"); mdecoder->volume = gst_element_factory_make("volume", "audiovolume"); mdecoder->outsink = gst_element_factory_make(tsmf_platform_get_audio_sink(), "audiosink"); @@ -504,24 +531,27 @@ BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder *mdecoder) return FALSE; } - /* Add audio / video specific elements to outbin */ + /* Add audio / video specific elements to pipe */ if (mdecoder->outconv) - gst_bin_add(GST_BIN(mdecoder->outbin), mdecoder->outconv); + gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->outconv); + + if (mdecoder->outrate) + gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->outrate); if (mdecoder->outresample) - gst_bin_add(GST_BIN(mdecoder->outbin), mdecoder->outresample); + gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->outresample); if (mdecoder->volume) - gst_bin_add(GST_BIN(mdecoder->outbin), mdecoder->volume); + gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->volume); if (mdecoder->outsink) - gst_bin_add(GST_BIN(mdecoder->outbin), mdecoder->outsink); + gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->outsink); - if (!mdecoder->outconv || ! mdecoder->outsink || !mdecoder->outresample) + if (!mdecoder->outconv || !mdecoder->outrate || ! mdecoder->outsink || !mdecoder->outresample) { DEBUG_WARN("Failed to load (some) output pipe elements"); - DEBUG_WARN("converter=%p, sink=%p, resample=%p", - mdecoder->outconv, mdecoder->outsink, mdecoder->outresample); + DEBUG_WARN("converter=%p, rate=%p, sink=%p, resample=%p", + mdecoder->outconv, mdecoder->outrate, mdecoder->outsink, mdecoder->outresample); tsmf_gstreamer_clean_up_pad(mdecoder); return FALSE; } @@ -627,13 +657,11 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder) gst_app_src_set_caps((GstAppSrc *) mdecoder->src, mdecoder->gst_caps); /* Queue2 settings */ g_object_set(mdecoder->queue, "use-buffering", FALSE, NULL); - // g_object_set(mdecoder->queue, "use-rate-estimate", TRUE, NULL); g_object_set(mdecoder->queue, "max-size-buffers", 2, NULL); /* DecodeBin settings */ g_signal_connect(mdecoder->decbin, "pad-added", G_CALLBACK(cb_newpad), mdecoder); g_signal_connect(mdecoder->decbin, "pad-removed", G_CALLBACK(cb_freepad), mdecoder); /* Sink settings */ - // g_object_set(mdecoder->outsink, "async-handling", TRUE, NULL); linkResult = gst_element_link_many(mdecoder->src, mdecoder->queue, mdecoder->decbin, NULL); @@ -727,7 +755,11 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder *decoder, const BYTE *data, UIN mdecoder->pipeline_start_time_valid = 1; } +#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); @@ -738,7 +770,7 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder *decoder, const BYTE *data, UIN if (GST_STATE(mdecoder->pipe) != GST_STATE_PLAYING) { - DEBUG_TSMF("state=%s", gst_element_state_name(GST_STATE(mdecoder->pipe))); + DEBUG_TSMF("state=%s", 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); @@ -890,7 +922,11 @@ static UINT64 tsmf_gstreamer_get_running_time(ITSMFDecoder *decoder) GstFormat fmt = GST_FORMAT_TIME; gint64 pos = 0; +#if GST_VERSION_MAJOR > 0 gst_element_query_position(mdecoder->outsink, fmt, &pos); + gst_element_query_position(mdecoder->outsink, &fmt, &pos); +#else +#endif return pos/100; } diff --git a/channels/tsmf/client/gstreamer/tsmf_platform.h b/channels/tsmf/client/gstreamer/tsmf_platform.h index 3c130710dc6b..0698a61ec5cc 100644 --- a/channels/tsmf/client/gstreamer/tsmf_platform.h +++ b/channels/tsmf/client/gstreamer/tsmf_platform.h @@ -21,6 +21,7 @@ typedef struct _TSMFGstreamerDecoder GstElement *decbin; GstElement *outbin; GstElement *outconv; + GstElement *outrate; GstElement *outresample; GstElement *outsink; GstElement *volume; From e5f81b5a36700bd308099b756c1a3158d1177c6c Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Sat, 24 May 2014 22:23:51 +0200 Subject: [PATCH 29/37] Fixed c/p error. --- channels/tsmf/client/gstreamer/tsmf_gstreamer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c index 402b24468fa9..e7fd5215831a 100644 --- a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c +++ b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c @@ -924,8 +924,8 @@ static UINT64 tsmf_gstreamer_get_running_time(ITSMFDecoder *decoder) gint64 pos = 0; #if GST_VERSION_MAJOR > 0 gst_element_query_position(mdecoder->outsink, fmt, &pos); - gst_element_query_position(mdecoder->outsink, &fmt, &pos); #else + gst_element_query_position(mdecoder->outsink, &fmt, &pos); #endif return pos/100; } From 50e5338f764b1cc52361e16831cb7d74d0d08641 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Sat, 24 May 2014 22:58:54 +0200 Subject: [PATCH 30/37] Added equality check for update rendering area. --- channels/tsmf/client/tsmf_media.c | 412 +++++++++++++++++++++--------- 1 file changed, 287 insertions(+), 125 deletions(-) diff --git a/channels/tsmf/client/tsmf_media.c b/channels/tsmf/client/tsmf_media.c index ee2063f8ab18..51465554b4ad 100644 --- a/channels/tsmf/client/tsmf_media.c +++ b/channels/tsmf/client/tsmf_media.c @@ -73,6 +73,14 @@ struct _TSMF_PRESENTATION UINT32 muted; wArrayList *stream_list; + + int x; + int y; + int width; + int height; + + int nr_rects; + void *rects; }; struct _TSMF_STREAM @@ -146,37 +154,42 @@ static TSMF_SAMPLE *tsmf_stream_pop_sample(TSMF_STREAM *stream, int sync) BOOL pending = FALSE; TSMF_PRESENTATION *presentation = stream->presentation; assert(stream); - if(Queue_Count(stream->sample_list) < 1) + + if (Queue_Count(stream->sample_list) < 1) return NULL; - if(sync) + + if (sync) { - if(stream->decoder) + if (stream->decoder) { - if(stream->decoder->GetDecodedData) + if (stream->decoder->GetDecodedData) { - if(stream->major_type == TSMF_MAJOR_TYPE_AUDIO) + if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO) { /* Check if some other stream has earlier sample that needs to be played first */ - if(stream->last_end_time > AUDIO_TOLERANCE) + if (stream->last_end_time > AUDIO_TOLERANCE) { ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); - for(index = 0; index < count; index++) + + for (index = 0; index < count; index++) { s = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); - if(s != stream && !s->eos && s->last_end_time && + + if (s != stream && !s->eos && s->last_end_time && s->last_end_time < stream->last_end_time - AUDIO_TOLERANCE) { pending = TRUE; break; } } + ArrayList_Unlock(presentation->stream_list); } } else { - if(stream->last_end_time > presentation->audio_end_time) + if (stream->last_end_time > presentation->audio_end_time) { pending = TRUE; } @@ -184,11 +197,15 @@ static TSMF_SAMPLE *tsmf_stream_pop_sample(TSMF_STREAM *stream, int sync) } } } - if(pending) + + if (pending) return NULL; + sample = (TSMF_SAMPLE *) Queue_Dequeue(stream->sample_list); - if(sample && (sample->end_time > stream->last_end_time)) + + if (sample && (sample->end_time > stream->last_end_time)) stream->last_end_time = sample->end_time; + return sample; } @@ -196,8 +213,10 @@ static void tsmf_sample_free(void *arg) { TSMF_SAMPLE *sample = arg; assert(sample); - if(sample->data) + + if (sample->data) free(sample->data); + free(sample); } @@ -223,14 +242,18 @@ static BOOL tsmf_stream_process_ack(void *arg, BOOL force) assert(stream); Queue_Lock(stream->sample_ack_list); sample = (TSMF_SAMPLE *) Queue_Peek(stream->sample_ack_list); - if(!sample) + + if (!sample) goto finally; - if(!force) + + if (!force) { ack_time = get_current_time(); - if(sample->ack_time > ack_time) + + if (sample->ack_time > ack_time) goto finally; } + sample = Queue_Dequeue(stream->sample_ack_list); tsmf_sample_ack(sample); tsmf_sample_free(sample); @@ -245,11 +268,16 @@ TSMF_PRESENTATION *tsmf_presentation_new(const BYTE *guid, IWTSVirtualChannelCal assert(guid); assert(pChannelCallback); presentation = (TSMF_PRESENTATION *) calloc(1, sizeof(TSMF_PRESENTATION)); - ZeroMemory(presentation, sizeof(TSMF_PRESENTATION)); + + if (!presentation) + { + DEBUG_WARN("calloc failed"); + return NULL; + } + CopyMemory(presentation->presentation_id, guid, GUID_SIZE); presentation->channel_callback = pChannelCallback; presentation->volume = 5000; /* 50% */ - presentation->muted = 0; presentation->stream_list = ArrayList_New(TRUE); ArrayList_Object(presentation->stream_list)->fnObjectFree = (OBJECT_FREE_FN) _tsmf_stream_free; ArrayList_Add(presentation_list, presentation); @@ -261,8 +289,10 @@ 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++) + + for (i=0; i 2*i; i++) snprintf(str + (2*i), len - 2*i, "%02X", guid[i]); + return str; } @@ -275,18 +305,23 @@ TSMF_PRESENTATION *tsmf_presentation_find_by_id(const BYTE *guid) TSMF_PRESENTATION *presentation; ArrayList_Lock(presentation_list); count = ArrayList_Count(presentation_list); - for(index = 0; index < count; index++) + + for (index = 0; index < count; index++) { presentation = (TSMF_PRESENTATION *) ArrayList_GetItem(presentation_list, index); - if(memcmp(presentation->presentation_id, guid, GUID_SIZE) == 0) + + if (memcmp(presentation->presentation_id, guid, GUID_SIZE) == 0) { found = TRUE; break; } } + ArrayList_Unlock(presentation_list); - if(!found) + + if (!found) DEBUG_WARN("presentation id %s not found", guid_to_string(guid, guid_str, sizeof(guid_str))); + return (found) ? presentation : NULL; } @@ -298,15 +333,18 @@ static void tsmf_sample_playback_video(TSMF_SAMPLE *sample) 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) + + if (sample->data) { t = get_current_time(); - if(stream->next_start_time > t && + + if (stream->next_start_time > t && (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; vevent = (RDP_VIDEO_FRAME_EVENT *) freerdp_event_new(TsmfChannel_Class, TsmfChannel_VideoFrame, NULL, NULL); @@ -318,17 +356,20 @@ static void tsmf_sample_playback_video(TSMF_SAMPLE *sample) /* 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); } + #if 0 /* Dump a .ppm image for every 30 frames. Assuming the frame is in YUV format, we extract the Y values to create a grayscale image. */ static int frame_id = 0; char buf[100]; FILE *fp; - if((frame_id % 30) == 0) + + if ((frame_id % 30) == 0) { snprintf(buf, sizeof(buf), "/tmp/FreeRDP_Frame_%d.ppm", frame_id); fp = fopen(buf, "wb"); @@ -340,6 +381,7 @@ static void tsmf_sample_playback_video(TSMF_SAMPLE *sample) fflush(fp); fclose(fp); } + frame_id++; #endif } @@ -351,19 +393,22 @@ static void tsmf_sample_playback_audio(TSMF_SAMPLE *sample) 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) + + if (sample->stream->audio && sample->data) { sample->stream->audio->Play(sample->stream->audio, sample->data, sample->decoded_size); sample->data = NULL; sample->decoded_size = 0; - if(stream->audio && stream->audio->GetLatency) + + if (stream->audio && stream->audio->GetLatency) latency = stream->audio->GetLatency(stream->audio); } else { latency = 0; } + sample->ack_time = latency + get_current_time(); stream->last_end_time = sample->end_time + latency; stream->presentation->audio_start_time = sample->start_time + latency; @@ -377,38 +422,47 @@ static void tsmf_sample_playback(TSMF_SAMPLE *sample) UINT32 height; UINT32 pixfmt = 0; TSMF_STREAM *stream = sample->stream; - if(stream->decoder) + + if (stream->decoder) { - if(stream->decoder->DecodeEx) + 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); else ret = stream->decoder->Decode(stream->decoder, sample->data, sample->data_size, sample->extensions); } - if(!ret) + + if (!ret) { tsmf_sample_queue_ack(sample); return; } + free(sample->data); sample->data = NULL; - if(stream->major_type == TSMF_MAJOR_TYPE_VIDEO) + + if (stream->major_type == TSMF_MAJOR_TYPE_VIDEO) { - if(stream->decoder->GetDecodedFormat) + if (stream->decoder->GetDecodedFormat) { pixfmt = stream->decoder->GetDecodedFormat(stream->decoder); - if(pixfmt == ((UINT32) -1)) + + if (pixfmt == ((UINT32) -1)) { tsmf_sample_queue_ack(sample); return; } + sample->pixfmt = pixfmt; } + ret = FALSE ; - if(stream->decoder->GetDecodedDimension) + + if (stream->decoder->GetDecodedDimension) { ret = stream->decoder->GetDecodedDimension(stream->decoder, &width, &height); - if(ret && (width != stream->width || height != stream->height)) + + if (ret && (width != stream->width || height != stream->height)) { DEBUG_TSMF("video dimension changed to %d x %d", width, height); stream->width = width; @@ -416,15 +470,18 @@ static void tsmf_sample_playback(TSMF_SAMPLE *sample) } } } - if(stream->decoder->GetDecodedData) + + if (stream->decoder->GetDecodedData) { sample->data = stream->decoder->GetDecodedData(stream->decoder, &sample->decoded_size); - switch(sample->stream->major_type) + + switch (sample->stream->major_type) { case TSMF_MAJOR_TYPE_VIDEO: tsmf_sample_playback_video(sample); tsmf_sample_queue_ack(sample); break; + case TSMF_MAJOR_TYPE_AUDIO: tsmf_sample_playback_audio(sample); tsmf_sample_queue_ack(sample); @@ -437,43 +494,48 @@ static void tsmf_sample_playback(TSMF_SAMPLE *sample) UINT64 ack_anticipation_time = get_current_time(); UINT64 currentRunningTime = sample->start_time; BOOL buffer_filled = TRUE; - if(stream->decoder->GetRunningTime) + + if (stream->decoder->GetRunningTime) { currentRunningTime = stream->decoder->GetRunningTime(stream->decoder); } - if(stream->decoder->BufferFilled) + + if (stream->decoder->BufferFilled) { buffer_filled = stream->decoder->BufferFilled(stream->decoder); } - if(buffer_filled) + + if (buffer_filled) { - if(currentRunningTime > sample->start_time) + if (currentRunningTime > sample->start_time) + { + ack_anticipation_time += sample->duration; + } + else if (currentRunningTime == 0) { ack_anticipation_time += sample->duration; } else - if(currentRunningTime == 0) - { - ack_anticipation_time += sample->duration; - } - else - { - ack_anticipation_time += (sample->start_time - currentRunningTime); - } + { + ack_anticipation_time += (sample->start_time - currentRunningTime); + } } else ack_anticipation_time += sample->duration / 2; - switch(sample->stream->major_type) + + switch (sample->stream->major_type) { case TSMF_MAJOR_TYPE_VIDEO: { break; } + case TSMF_MAJOR_TYPE_AUDIO: { break; } } + sample->ack_time = ack_anticipation_time; tsmf_sample_queue_ack(sample); } @@ -486,18 +548,24 @@ static void *tsmf_stream_ack_func(void *arg) DEBUG_TSMF("in %d", stream->stream_id); hdl[0] = stream->stopEvent; hdl[1] = Queue_Event(stream->sample_ack_list); - while(1) + + while (1) { DWORD ev = WaitForMultipleObjects(2, hdl, FALSE, INFINITE); - if(ev == WAIT_OBJECT_0) + + if (ev == WAIT_OBJECT_0) break; - if(!stream->decoder) + + if (!stream->decoder) continue; - if(stream->decoder->SetAckFunc) + + if (stream->decoder->SetAckFunc) continue; - if(tsmf_stream_process_ack(stream, FALSE)) + + if (tsmf_stream_process_ack(stream, FALSE)) break; } + DEBUG_TSMF("out %d", stream->stream_id); ExitThread(0); return NULL; @@ -510,17 +578,19 @@ static void *tsmf_stream_playback_func(void *arg) 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 && + + if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO && stream->sample_rate && stream->channels && stream->bits_per_sample) { - if(stream->decoder) + if (stream->decoder) { - if(stream->decoder->GetDecodedData) + 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); - if(stream->audio) + + if (stream->audio) { stream->audio->SetFormat(stream->audio, stream->sample_rate, stream->channels, stream->bits_per_sample); @@ -531,17 +601,21 @@ static void *tsmf_stream_playback_func(void *arg) hdl[0] = stream->stopEvent; hdl[1] = Queue_Event(stream->sample_list); - while(!(WaitForMultipleObjects(2, hdl, FALSE, INFINITE) == WAIT_OBJECT_0)) + + while (!(WaitForMultipleObjects(2, hdl, FALSE, INFINITE) == WAIT_OBJECT_0)) { sample = tsmf_stream_pop_sample(stream, 0); - if(sample) + + if (sample) tsmf_sample_playback(sample); } - if(stream->audio) + + if (stream->audio) { stream->audio->Free(stream->audio); stream->audio = NULL; } + DEBUG_TSMF("out %d", stream->stream_id); ExitThread(0); return NULL; @@ -549,9 +623,10 @@ static void *tsmf_stream_playback_func(void *arg) static void tsmf_stream_start(TSMF_STREAM *stream) { - if(!stream || !stream->presentation || !stream->decoder) + if (!stream || !stream->presentation || !stream->decoder) return; - if(stream->decoder->Control) + + if (stream->decoder->Control) { stream->decoder->Control(stream->decoder, Control_Resume, NULL); } @@ -559,9 +634,10 @@ static void tsmf_stream_start(TSMF_STREAM *stream) static void tsmf_stream_stop(TSMF_STREAM *stream) { - if(!stream || !stream->decoder) + if (!stream || !stream->decoder) return; - if(stream->decoder->Control) + + if (stream->decoder->Control) { stream->decoder->Control(stream->decoder, Control_Stop, NULL); } @@ -569,9 +645,10 @@ static void tsmf_stream_stop(TSMF_STREAM *stream) static void tsmf_stream_pause(TSMF_STREAM *stream) { - if(!stream || !stream->decoder) + if (!stream || !stream->decoder) return; - if(stream->decoder->Control) + + if (stream->decoder->Control) { stream->decoder->Control(stream->decoder, Control_Pause, NULL); } @@ -579,9 +656,10 @@ static void tsmf_stream_pause(TSMF_STREAM *stream) static void tsmf_stream_restart(TSMF_STREAM *stream) { - if(!stream || !stream->decoder) + if (!stream || !stream->decoder) return; - if(stream->decoder->Control) + + if (stream->decoder->Control) { stream->decoder->Control(stream->decoder, Control_Resume, NULL); } @@ -589,17 +667,17 @@ static void tsmf_stream_restart(TSMF_STREAM *stream) static void tsmf_stream_change_volume(TSMF_STREAM *stream, UINT32 newVolume, UINT32 muted) { - if(!stream || !stream->decoder) + if (!stream || !stream->decoder) return; - if(stream->decoder != NULL && stream->decoder->ChangeVolume) + + if (stream->decoder != NULL && stream->decoder->ChangeVolume) { stream->decoder->ChangeVolume(stream->decoder, newVolume, muted); } - else - if(stream->audio != NULL && stream->audio->ChangeVolume) - { - stream->audio->ChangeVolume(stream->audio, newVolume, muted); - } + else if (stream->audio != NULL && stream->audio->ChangeVolume) + { + stream->audio->ChangeVolume(stream->audio, newVolume, muted); + } } void tsmf_presentation_volume_changed(TSMF_PRESENTATION *presentation, UINT32 newVolume, UINT32 muted) @@ -611,11 +689,13 @@ void tsmf_presentation_volume_changed(TSMF_PRESENTATION *presentation, UINT32 ne presentation->muted = muted; ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); - for(index = 0; index < count; index++) + + for (index = 0; index < count; index++) { stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); tsmf_stream_change_volume(stream, newVolume, muted); } + ArrayList_Unlock(presentation->stream_list); } @@ -626,11 +706,13 @@ void tsmf_presentation_paused(TSMF_PRESENTATION *presentation) TSMF_STREAM *stream; ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); - for(index = 0; index < count; index++) + + for (index = 0; index < count; index++) { stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); tsmf_stream_pause(stream); } + ArrayList_Unlock(presentation->stream_list); } @@ -641,11 +723,13 @@ void tsmf_presentation_restarted(TSMF_PRESENTATION *presentation) TSMF_STREAM *stream; ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); - for(index = 0; index < count; index++) + + for (index = 0; index < count; index++) { stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); tsmf_stream_restart(stream); } + ArrayList_Unlock(presentation->stream_list); } @@ -656,11 +740,13 @@ void tsmf_presentation_start(TSMF_PRESENTATION *presentation) TSMF_STREAM *stream; ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); - for(index = 0; index < count; index++) + + for (index = 0; index < count; index++) { stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); tsmf_stream_start(stream); } + ArrayList_Unlock(presentation->stream_list); } @@ -670,11 +756,13 @@ void tsmf_presentation_sync(TSMF_PRESENTATION *presentation) UINT32 count; ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); - for(index = 0; index < count; index++) + + for (index = 0; index < count; index++) { TSMF_STREAM *stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); WaitForSingleObject(stream->ready, 500); } + ArrayList_Unlock(presentation->stream_list); } @@ -686,11 +774,13 @@ void tsmf_presentation_stop(TSMF_PRESENTATION *presentation) tsmf_presentation_flush(presentation); ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); - for(index = 0; index < count; index++) + + for (index = 0; index < count; index++) { stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); tsmf_stream_stop(stream); } + ArrayList_Unlock(presentation->stream_list); } @@ -700,22 +790,46 @@ void tsmf_presentation_set_geometry_info(TSMF_PRESENTATION *presentation, UINT32 index; UINT32 count; TSMF_STREAM *stream; + /* The server may send messages with invalid width / height. * Ignore those messages. */ - if(!width || !height) + if (!width || !height) + return; + + 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)))) + { return; + } + + 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->rects) + memcpy(presentation->rects, rects, sizeof(RDP_RECT) * num_rects); + ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); - for(index = 0; index < count; index++) + + for (index = 0; index < count; index++) { stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); - if(!stream->decoder) + + if (!stream->decoder) continue; - if(stream->decoder->UpdateRenderingArea) + + if (stream->decoder->UpdateRenderingArea) { stream->decoder->UpdateRenderingArea(stream->decoder, x, y, width, height, num_rects, rects); } } + ArrayList_Unlock(presentation->stream_list); } @@ -729,12 +843,14 @@ static void tsmf_stream_flush(TSMF_STREAM *stream) { //TSMF_SAMPLE* sample; /* TODO: free lists */ - if(stream->audio) + if (stream->audio) stream->audio->Flush(stream->audio); + stream->eos = 0; stream->last_end_time = 0; stream->next_start_time = 0; - if(stream->major_type == TSMF_MAJOR_TYPE_AUDIO) + + if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO) { stream->presentation->audio_start_time = 0; stream->presentation->audio_end_time = 0; @@ -748,11 +864,13 @@ void tsmf_presentation_flush(TSMF_PRESENTATION *presentation) TSMF_STREAM *stream; ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); - for(index = 0; index < count; index++) + + for (index = 0; index < count; 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; @@ -764,6 +882,10 @@ void _tsmf_presentation_free(TSMF_PRESENTATION *presentation) tsmf_presentation_stop(presentation); ArrayList_Clear(presentation->stream_list); ArrayList_Free(presentation->stream_list); + + if (presentation->rects) + free(presentation->rects); + memset(presentation, 0, sizeof(TSMF_PRESENTATION)); free(presentation); } @@ -777,13 +899,21 @@ 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) + + if (stream) { DEBUG_WARN("duplicated stream id %d!", 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->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); @@ -808,15 +938,18 @@ TSMF_STREAM *tsmf_stream_find_by_id(TSMF_PRESENTATION *presentation, UINT32 stre TSMF_STREAM *stream; ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); - for(index = 0; index < count; index++) + + for (index = 0; index < count; index++) { stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); - if(stream->stream_id == stream_id) + + if (stream->stream_id == stream_id) { found = TRUE; break; } } + ArrayList_Unlock(presentation->stream_list); return (found) ? stream : NULL; } @@ -830,41 +963,48 @@ static void tsmf_stream_resync(void *arg) void tsmf_stream_set_format(TSMF_STREAM *stream, const char *name, wStream *s) { TS_AM_MEDIA_TYPE mediatype; - if(stream->decoder) + + if (stream->decoder) { DEBUG_WARN("duplicated call"); return; } + tsmf_codec_parse_media_type(&mediatype, s); - if(mediatype.MajorType == TSMF_MAJOR_TYPE_VIDEO) + + if (mediatype.MajorType == TSMF_MAJOR_TYPE_VIDEO) { 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_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; - if(stream->bits_per_sample == 0) - stream->bits_per_sample = 16; - } + else if (mediatype.MajorType == TSMF_MAJOR_TYPE_AUDIO) + { + 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; + + if (stream->bits_per_sample == 0) + stream->bits_per_sample = 16; + } + stream->major_type = mediatype.MajorType; stream->width = mediatype.Width; 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) + + if (!stream->decoder) return; - if(stream->decoder->SetAckFunc) + + if (stream->decoder->SetAckFunc) stream->decoder->SetAckFunc(stream->decoder, tsmf_stream_process_ack, stream); - if(stream->decoder->SetSyncFunc) + + if (stream->decoder->SetSyncFunc) stream->decoder->SetSyncFunc(stream->decoder, tsmf_stream_resync, stream); } @@ -881,25 +1021,30 @@ void _tsmf_stream_free(TSMF_STREAM *stream) tsmf_stream_stop(stream); tsmf_stream_flush(stream); SetEvent(stream->stopEvent); - if(stream->play_thread) + + if (stream->play_thread) { WaitForSingleObject(stream->play_thread, INFINITE); CloseHandle(stream->play_thread); stream->play_thread = NULL; } - if(stream->ack_thread) + + 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 && stream->decoder->Free) + + if (stream->decoder && stream->decoder->Free) { stream->decoder->Free(stream->decoder); stream->decoder = NULL; } + CloseHandle(stream->stopEvent); CloseHandle(stream->ready); memset(stream, 0, sizeof(TSMF_STREAM)); @@ -918,9 +1063,18 @@ void tsmf_stream_push_sample(TSMF_STREAM *stream, IWTSVirtualChannelCallback *pC { TSMF_SAMPLE *sample; SetEvent(stream->ready); - if(TERMINATING) + + if (TERMINATING) return; + sample = (TSMF_SAMPLE *) calloc(1, sizeof(TSMF_SAMPLE)); + + if (!sample) + { + DEBUG_WARN("calloc failed!"); + return; + } + sample->sample_id = sample_id; sample->start_time = start_time; sample->end_time = end_time; @@ -929,8 +1083,15 @@ 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); + 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); } @@ -941,16 +1102,16 @@ static void tsmf_signal_handler(int s) { TERMINATING = 1; ArrayList_Free(presentation_list); - if(s == SIGINT) + + if (s == SIGINT) { signal(s, SIG_DFL); kill(getpid(), s); } - else - if(s == SIGUSR1) - { - signal(s, SIG_DFL); - } + else if (s == SIGUSR1) + { + signal(s, SIG_DFL); + } } #endif @@ -965,7 +1126,8 @@ void tsmf_media_init(void) sigaction(SIGINT, &sigtrap, 0); sigaction(SIGUSR1, &sigtrap, 0); #endif - if(!presentation_list) + + if (!presentation_list) { presentation_list = ArrayList_New(TRUE); ArrayList_Object(presentation_list)->fnObjectFree = (OBJECT_FREE_FN) _tsmf_presentation_free; From faf955b0525ab306fbcf4643aa5e187cf7eeb826 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Sat, 24 May 2014 23:21:05 +0200 Subject: [PATCH 31/37] Added resize code for gstreamer 0.10 --- channels/tsmf/client/gstreamer/tsmf_X11.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/channels/tsmf/client/gstreamer/tsmf_X11.c b/channels/tsmf/client/gstreamer/tsmf_X11.c index 8b48681bf579..63eef16f82bf 100644 --- a/channels/tsmf/client/gstreamer/tsmf_X11.c +++ b/channels/tsmf/client/gstreamer/tsmf_X11.c @@ -159,6 +159,8 @@ int tsmf_window_create(TSMFGstreamerDecoder *decoder) { #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); @@ -174,13 +176,12 @@ int tsmf_window_create(TSMFGstreamerDecoder *decoder) DEBUG_WARN("Could not create subwindow!"); } - XSetWindowBackgroundPixmap(hdl->disp, hdl->subwin, None); 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(GST_X_OVERLAY(decoder->outsink), *hdl->xfwin); + gst_x_overlay_set_window_handle(overlay, hdl->subwin); #endif decoder->ready = TRUE; #if defined(WITH_XEXT) @@ -190,6 +191,8 @@ int tsmf_window_create(TSMFGstreamerDecoder *decoder) #if GST_VERSION_MAJOR > 0 gst_video_overlay_handle_events(overlay, TRUE); +#else + gst_x_overlay_handle_events(overlay, TRUE); #endif return 0; } @@ -204,6 +207,8 @@ int tsmf_window_resize(TSMFGstreamerDecoder *decoder, int x, int y, int width, { #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); @@ -218,7 +223,12 @@ int tsmf_window_resize(TSMFGstreamerDecoder *decoder, int x, int y, int width, gst_video_overlay_expose(overlay); #else - gst_x_overlay_expose(GST_X_OVERLAY(decoder->outsink)); + 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) From 2610f7ff50004925509ca82f6005a6c41970b616 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Sat, 24 May 2014 23:32:47 +0200 Subject: [PATCH 32/37] Using wrapper set state function now everywhere. --- channels/tsmf/client/gstreamer/tsmf_gstreamer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c index e7fd5215831a..c925cd1e6c72 100644 --- a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c +++ b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c @@ -80,12 +80,12 @@ static gboolean tsmf_gstreamer_seek_data(GstAppSrc *src, guint64 offset, gpointe DEBUG_TSMF("%s offset=%llu", get_type(mdecoder), offset); if (!mdecoder->paused) - gst_element_set_state(mdecoder->pipe, GST_STATE_PAUSED); + tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PAUSED); gst_app_src_end_of_stream((GstAppSrc *)mdecoder->src); if (!mdecoder->paused) - gst_element_set_state(mdecoder->pipe, GST_STATE_PLAYING); + tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); if (mdecoder->sync_cb) mdecoder->sync_cb(mdecoder->stream); @@ -419,7 +419,7 @@ void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder *mdecoder) if (mdecoder->pipe && GST_OBJECT_REFCOUNT_VALUE(mdecoder->pipe) > 0) { - gst_element_set_state(mdecoder->pipe, GST_STATE_NULL); + tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_NULL); gst_object_unref(mdecoder->pipe); } @@ -770,7 +770,7 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder *decoder, const BYTE *data, UIN if (GST_STATE(mdecoder->pipe) != GST_STATE_PLAYING) { - DEBUG_TSMF("state=%s", gst_element_state_get_name(GST_STATE(mdecoder->pipe))); + 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); From bbd63b6024ea6d759bbba6178c6e7c004f2f2166 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Sun, 25 May 2014 10:08:50 +0200 Subject: [PATCH 33/37] Using gst_parse_launch now instead of manual pipeline. --- .../tsmf/client/gstreamer/tsmf_gstreamer.c | 259 +++--------------- .../tsmf/client/gstreamer/tsmf_platform.h | 7 - 2 files changed, 32 insertions(+), 234 deletions(-) diff --git a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c index c925cd1e6c72..ead4e8249d11 100644 --- a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c +++ b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c @@ -45,7 +45,6 @@ static BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder); static void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder *mdecoder); -static void tsmf_gstreamer_clean_up_pad(TSMFGstreamerDecoder *mdecoder); static int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, GstState desired_state); @@ -105,6 +104,7 @@ int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, GstState d { GstStateChangeReturn state_change; const char *name; + const char *sname = get_type(mdecoder); if (!mdecoder) return 0; @@ -116,14 +116,14 @@ int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, GstState d return 0; /* Redundant request - Nothing to do */ name = gst_element_state_get_name(desired_state); /* For debug */ - DEBUG_TSMF("%s to %s", get_type(mdecoder), name); + DEBUG_TSMF("%s to %s", sname, name); state_change = gst_element_set_state(mdecoder->pipe, desired_state); if (state_change == GST_STATE_CHANGE_FAILURE) - DEBUG_WARN("(%s) GST_STATE_CHANGE_FAILURE.", name); + DEBUG_WARN("%s: (%s) GST_STATE_CHANGE_FAILURE.", sname, name); else if (state_change == GST_STATE_CHANGE_ASYNC) { - DEBUG_WARN("(%s) GST_STATE_CHANGE_ASYNC.", name); + DEBUG_WARN("%s: (%s) GST_STATE_CHANGE_ASYNC.", sname, name); mdecoder->state = desired_state; } else @@ -399,18 +399,6 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m return TRUE; } -void tsmf_gstreamer_clean_up_pad(TSMFGstreamerDecoder *mdecoder) -{ - if (!mdecoder || !mdecoder->pipe) - return; - - mdecoder->outconv = NULL; - mdecoder->outrate = NULL; - mdecoder->outresample = NULL; - mdecoder->outsink = NULL; - mdecoder->volume = NULL; -} - void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder *mdecoder) { //Cleaning up elements @@ -423,223 +411,60 @@ void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder *mdecoder) gst_object_unref(mdecoder->pipe); } - tsmf_gstreamer_clean_up_pad(mdecoder); tsmf_window_destroy(mdecoder); mdecoder->ready = FALSE; mdecoder->pipe = NULL; mdecoder->src = NULL; - mdecoder->queue = NULL; - mdecoder->decbin = NULL; - mdecoder->outbin = NULL; } -static void -cb_newpad(GstElement *decodebin, - GstPad *pad, - gpointer data) -{ - GstPad *outpad; - TSMFGstreamerDecoder *mdecoder = data; - /* only link once */ - outpad = gst_element_get_static_pad(mdecoder->outbin, "sink"); - - if (GST_PAD_IS_LINKED(outpad)) - { - DEBUG_WARN("sink already linded!"); - gst_object_unref(outpad); - return; - } - - /* link'n'play */ - gst_pad_link(pad, outpad); - gst_object_unref(outpad); -} - -static void -cb_freepad(GstElement *decodebin, - GstPad *pad, - gpointer data) +BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder) { - GstPad *outpad; - TSMFGstreamerDecoder *mdecoder = data; - outpad = gst_element_get_static_pad(mdecoder->outbin, "sink"); - - if (!outpad) - { - DEBUG_WARN("sink pad does not exist!"); - return; - } + const char *appsrc = "appsrc name=source ! decodebin name=decoder !"; + const char *video = "autovideoconvert ! videorate ! videoscale !"; + const char *audio = "audioconvert ! audiorate ! audioresample ! volume name=audiovolume !"; + char pipeline[1024]; - if (!GST_PAD_IS_LINKED(outpad)) - { - DEBUG_WARN("sink not linded!"); - gst_object_unref(outpad); - return; - } + if (!mdecoder) + return FALSE; - /* link'n'play */ - gst_pad_unlink(pad, outpad); - gst_object_unref(outpad); -} + 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_WARN("pipeline=%s", pipeline); + mdecoder->pipe = gst_parse_launch(pipeline, NULL); -void tsmf_gstreamer_remove_pad(TSMFGstreamerDecoder *mdecoder) -{ - if (mdecoder->outbin) + if (!mdecoder->pipe) { - gst_element_remove_pad(mdecoder->outbin, mdecoder->ghost_pad); - gst_object_unref(mdecoder->ghost_pad); - mdecoder->ghost_pad = NULL; + DEBUG_WARN("Failed to create new pipe"); + return FALSE; } -} -BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder *mdecoder) -{ - GstPad *out_pad; - gboolean linkResult = FALSE; - - switch (mdecoder->media_type) + mdecoder->src = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "source"); + if (!mdecoder->src) { - case TSMF_MAJOR_TYPE_VIDEO: - { -#if GST_VERSION_MAJOR > 0 - mdecoder->outconv = gst_element_factory_make("videoconvert", "videoconvert"); -#else - mdecoder->outconv = gst_element_factory_make("ffmpegcolorspace", "videoconvert"); -#endif - mdecoder->outrate = gst_element_factory_make("videorate", "videorate"); - mdecoder->outsink = gst_element_factory_make(tsmf_platform_get_video_sink(), "videosink"); - mdecoder->outresample = gst_element_factory_make("videoscale", "videoscale"); - mdecoder->volume = NULL; - DEBUG_TSMF("building Video Pipe"); - break; - } - - case TSMF_MAJOR_TYPE_AUDIO: - { - mdecoder->outconv = gst_element_factory_make("audioconvert", "audioconvert"); - mdecoder->outrate = gst_element_factory_make("audiorate", "audiorate"); - mdecoder->outresample = gst_element_factory_make("audioresample", "audioresample"); - mdecoder->volume = gst_element_factory_make("volume", "audiovolume"); - mdecoder->outsink = gst_element_factory_make(tsmf_platform_get_audio_sink(), "audiosink"); - DEBUG_TSMF("building Audio Pipe"); - break; - } - - default: - DEBUG_WARN("Invalid media type %08X", mdecoder->media_type); - tsmf_gstreamer_clean_up_pad(mdecoder); - return FALSE; + DEBUG_WARN("Failed to get appsrc"); + return FALSE; } - /* Add audio / video specific elements to pipe */ - if (mdecoder->outconv) - gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->outconv); - - if (mdecoder->outrate) - gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->outrate); - - if (mdecoder->outresample) - gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->outresample); - - if (mdecoder->volume) - gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->volume); - - if (mdecoder->outsink) - gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->outsink); - - if (!mdecoder->outconv || !mdecoder->outrate || ! mdecoder->outsink || !mdecoder->outresample) + mdecoder->outsink = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "outsink"); + if (!mdecoder->outsink) { - DEBUG_WARN("Failed to load (some) output pipe elements"); - DEBUG_WARN("converter=%p, rate=%p, sink=%p, resample=%p", - mdecoder->outconv, mdecoder->outrate, mdecoder->outsink, mdecoder->outresample); - tsmf_gstreamer_clean_up_pad(mdecoder); + DEBUG_WARN("Failed to get sink"); return FALSE; } - if (mdecoder->media_type == TSMF_MAJOR_TYPE_AUDIO) + if (mdecoder->media_type != TSMF_MAJOR_TYPE_VIDEO) { + mdecoder->volume = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "audiovolume"); if (!mdecoder->volume) { - DEBUG_WARN("Failed to load (some) audio output pipe elements"); - DEBUG_WARN("volume=%p", mdecoder->volume); - tsmf_gstreamer_clean_up_pad(mdecoder); + DEBUG_WARN("Failed to get volume"); return FALSE; } } - out_pad = gst_element_get_static_pad(mdecoder->outconv, "sink"); - - if (mdecoder->media_type == TSMF_MAJOR_TYPE_AUDIO) - { - g_object_set(mdecoder->volume, "mute", mdecoder->gstMuted, NULL); - g_object_set(mdecoder->volume, "volume", mdecoder->gstVolume, NULL); - linkResult = gst_element_link_many(mdecoder->outconv, mdecoder->outresample, - mdecoder->volume, mdecoder->outsink, NULL); - } - else - { - linkResult = gst_element_link_many(mdecoder->outconv, - mdecoder->outresample, mdecoder->outsink, NULL); - } - - if (!linkResult) - { - DEBUG_WARN("Failed to link these elements: converter->sink"); - tsmf_gstreamer_clean_up_pad(mdecoder); - return FALSE; - } - - mdecoder->ghost_pad = gst_ghost_pad_new("sink", out_pad); - gst_element_add_pad(mdecoder->outbin, mdecoder->ghost_pad); - gst_object_unref(out_pad); - return TRUE; -} - -BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder) -{ - gboolean linkResult; - - if (!mdecoder) - return FALSE; - - mdecoder->pipe = gst_pipeline_new("pipeline"); - - if (!mdecoder->pipe) - { - DEBUG_WARN("Failed to create new pipe"); - return FALSE; - } - tsmf_platform_register_handler(mdecoder); - mdecoder->src = gst_element_factory_make("appsrc", "source"); - mdecoder->queue = gst_element_factory_make("queue2", "queue"); - mdecoder->decbin = gst_element_factory_make("decodebin", "decoder"); - mdecoder->outbin = gst_bin_new("outbin"); - - /* Add all elements to the bin allowing proper resource cleanup, - * if any step failed. */ - if (mdecoder->src) - gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->src); - - if (mdecoder->queue) - gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->queue); - - if (mdecoder->decbin) - gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->decbin); - - if (mdecoder->outbin) - gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->outbin); - - /* Check, if everything was loaded correctly. */ - if (!mdecoder->src || !mdecoder->queue || !mdecoder->decbin || - !mdecoder->outbin) - { - DEBUG_WARN("Failed to load (some) pipeline stage"); - DEBUG_WARN("src=%p, queue=%p, decoder=%p, output=%p", - mdecoder->src, mdecoder->queue, mdecoder->decbin, mdecoder->outbin); - tsmf_gstreamer_clean_up(mdecoder); - return FALSE; - } gst_pipeline_set_delay((GstPipeline *)mdecoder->pipe, 5000); /* AppSrc settings */ @@ -655,25 +480,9 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder) 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); gst_app_src_set_caps((GstAppSrc *) mdecoder->src, mdecoder->gst_caps); - /* Queue2 settings */ - g_object_set(mdecoder->queue, "use-buffering", FALSE, NULL); - g_object_set(mdecoder->queue, "max-size-buffers", 2, NULL); - /* DecodeBin settings */ - g_signal_connect(mdecoder->decbin, "pad-added", G_CALLBACK(cb_newpad), mdecoder); - g_signal_connect(mdecoder->decbin, "pad-removed", G_CALLBACK(cb_freepad), mdecoder); - /* Sink settings */ - linkResult = gst_element_link_many(mdecoder->src, mdecoder->queue, - mdecoder->decbin, NULL); - - if (!linkResult) - { - DEBUG_WARN("Failed to link elements."); - tsmf_gstreamer_clean_up(mdecoder); - return FALSE; - } - tsmf_gstreamer_add_pad(mdecoder); 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; @@ -776,6 +585,7 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder *decoder, const BYTE *data, UIN tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); } + return TRUE; } @@ -876,13 +686,8 @@ static BOOL tsmf_gstreamer_buffer_filled(ITSMFDecoder *decoder) if (!mdecoder) return FALSE; - if (!G_IS_OBJECT(mdecoder->queue)) - return FALSE; - guint buff_max = 0; - g_object_get(mdecoder->queue, "max-size-buffers", &buff_max, NULL); guint clbuff = 0; - g_object_get(mdecoder->queue, "current-level-buffers", &clbuff, NULL); DEBUG_TSMF("%s buffer fill %u/%u", get_type(mdecoder), clbuff, buff_max); return clbuff >= buff_max ? TRUE : FALSE; } diff --git a/channels/tsmf/client/gstreamer/tsmf_platform.h b/channels/tsmf/client/gstreamer/tsmf_platform.h index 0698a61ec5cc..53324b173646 100644 --- a/channels/tsmf/client/gstreamer/tsmf_platform.h +++ b/channels/tsmf/client/gstreamer/tsmf_platform.h @@ -17,15 +17,8 @@ typedef struct _TSMFGstreamerDecoder GstElement *pipe; GstElement *src; - GstElement *queue; - GstElement *decbin; - GstElement *outbin; - GstElement *outconv; - GstElement *outrate; - GstElement *outresample; GstElement *outsink; GstElement *volume; - GstPad *ghost_pad; BOOL ready; BOOL paused; From fd7ba77cd14e03877acc293a04cb1c5a26008922 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 26 May 2014 07:46:11 +0200 Subject: [PATCH 34/37] Removed argument from caps, as it is not supported by decoders. Fixed