Add GStreamer plugin for Multi-media redirection

This commit is contained in:
Irwan Halim 2012-06-13 14:45:58 -05:00
parent cc9e584301
commit c9c22fa331
13 changed files with 2232 additions and 45 deletions

View File

@ -4,6 +4,7 @@
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
# 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.
@ -117,6 +118,7 @@ if(NOT WIN32)
if(NOT APPLE)
find_suggested_package(FFmpeg)
find_suggested_package(Gstreamer)
find_suggested_package(ALSA)
else(NOT APPLE)
find_optional_package(FFmpeg)

View File

@ -4,6 +4,7 @@
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
# Copyright 2012 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -47,6 +48,10 @@ if(WITH_FFMPEG)
add_subdirectory(ffmpeg)
endif()
if(GSTREAMER_FOUND)
add_subdirectory(gstreamer)
endif()
if(WITH_ALSA)
add_subdirectory(alsa)
endif()

View File

@ -0,0 +1,34 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script for gstreamer plugin
#
# (C) Copyright 2012 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set(TSMF_GSTREAMER_SRCS
tsmf_gstreamer.c
)
include_directories(..)
include_directories(${GSTREAMER_INCLUDE_DIRS})
add_library(tsmf_gstreamer ${TSMF_GSTREAMER_SRCS})
set_target_properties(tsmf_gstreamer PROPERTIES PREFIX "")
target_link_libraries(tsmf_gstreamer freerdp-utils)
target_link_libraries(tsmf_gstreamer ${GSTREAMER_LIBRARIES} gstapp-0.10 gstinterfaces-0.10 Xrandr X11 Xext)
install(TARGETS tsmf_gstreamer DESTINATION ${FREERDP_PLUGIN_PATH})

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@
* Video Redirection Virtual Channel - Codec
*
* Copyright 2010-2011 Vic Lee
* Copyright 2012 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -103,6 +104,20 @@ static const TSMFMediaTypeMap tsmf_sub_type_map[] =
TSMF_SUB_TYPE_MP2V
},
/* 31564D57-0000-0010-8000-00AA00389B71 */
{
{ 0x57, 0x4D, 0x56, 0x31, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
"MEDIASUBTYPE_WMV1",
TSMF_SUB_TYPE_WMV1
},
/* 32564D57-0000-0010-8000-00AA00389B71 */
{
{ 0x57, 0x4D, 0x56, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
"MEDIASUBTYPE_WMV2",
TSMF_SUB_TYPE_WMV2
},
/* 33564D57-0000-0010-8000-00AA00389B71 */
{
{ 0x57, 0x4D, 0x56, 0x33, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
@ -131,12 +146,62 @@ static const TSMFMediaTypeMap tsmf_sub_type_map[] =
TSMF_SUB_TYPE_AVC1
},
/* 3334504D-0000-0010-8000-00AA00389B71 */
{
{ 0x4D, 0x50, 0x34, 0x33, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
"MEDIASUBTYPE_MP43",
TSMF_SUB_TYPE_MP43
},
/* 5634504D-0000-0010-8000-00AA00389B71 */
{
{ 0x4D, 0x50, 0x34, 0x56, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
"MEDIASUBTYPE_MP4S",
TSMF_SUB_TYPE_MP4S
},
/* 3234504D-0000-0010-8000-00AA00389B71 */
{
{ 0x4D, 0x50, 0x34, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
"MEDIASUBTYPE_MP42",
TSMF_SUB_TYPE_MP42
},
/* E436EB81-524F-11CE-9F53-0020AF0BA770 */
/*
{
{ 0x81, 0xEB, 0x36, 0xE4, 0x4F, 0x52, 0xCE, 0x11, 0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70 },
"MEDIASUBTYPE_MP1V",
TSMF_SUB_TYPE_MP1V
},
*/
/* 00000050-0000-0010-8000-00AA00389B71 */
/*
{
{ 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
"MEDIASUBTYPE_MP1A",
TSMF_SUB_TYPE_MP1A
},
*/
/* E06D802C-DB46-11CF-B4D1-00805F6CBBEA */
/*
{
{ 0x2C, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA },
"MEDIASUBTYPE_DOLBY_AC3",
TSMF_SUB_TYPE_AC3
},
*/
/* 32595559-0000-0010-8000-00AA00389B71 */
/*
{
{ 0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
"MEDIASUBTYPE_YUY2",
TSMF_SUB_TYPE_YUY2
},
*/
{
{ 0 },
@ -176,6 +241,13 @@ static const TSMFMediaTypeMap tsmf_format_type_map[] =
TSMF_FORMAT_TYPE_VIDEOINFO2
},
/* 05589F82-C356-11CE-BF01-00AA0055595A */
{
{ 0x82, 0x9F, 0x58, 0x05, 0x56, 0xC3, 0xCE, 0x11, 0xBF, 0x01, 0x00, 0xAA, 0x00, 0x55, 0x59, 0x5A },
"FORMAT_MPEG1_VIDEO",
TSMF_FORMAT_TYPE_MPEG1VIDEOINFO
},
{
{ 0 },
"Unknown",
@ -257,6 +329,40 @@ static uint32 tsmf_codec_parse_VIDEOINFOHEADER2(TS_AM_MEDIA_TYPE* mediatype, STR
return 72;
}
/* http://msdn.microsoft.com/en-us/library/dd390700.aspx */
static uint32 tsmf_codec_parse_VIDEOINFOHEADER(TS_AM_MEDIA_TYPE* mediatype, STREAM* 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;
*/
uint64 AvgTimePerFrame;
/* VIDEOINFOHEADER.rcSource, RECT(LONG left, LONG top, LONG right, LONG bottom) */
stream_seek_uint32(s);
stream_seek_uint32(s);
stream_read_uint32(s, mediatype->Width);
stream_read_uint32(s, mediatype->Height);
/* VIDEOINFOHEADER.rcTarget */
stream_seek(s, 16);
/* VIDEOINFOHEADER.dwBitRate */
stream_read_uint32(s, mediatype->BitRate);
/* VIDEOINFOHEADER.dwBitErrorRate */
stream_seek_uint32(s);
/* VIDEOINFOHEADER.AvgTimePerFrame */
stream_read_uint64(s, AvgTimePerFrame);
mediatype->SamplesPerSecond.Numerator = 1000000;
mediatype->SamplesPerSecond.Denominator = (int)(AvgTimePerFrame / 10LL);
return 48;
}
boolean tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, STREAM* s)
{
int i;
@ -358,6 +464,18 @@ boolean tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, STREAM* 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)
{
mediatype->ExtraDataSize = cbFormat - i;
mediatype->ExtraData = stream_get_tail(s);
}
break;
case TSMF_FORMAT_TYPE_MPEG2VIDEOINFO:
/* http://msdn.microsoft.com/en-us/library/dd390707.aspx */

View File

@ -3,6 +3,7 @@
* Video Redirection Virtual Channel - Constants
*
* Copyright 2010-2011 Vic Lee
* Copyright 2012 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -108,6 +109,14 @@
#define TSMF_SUB_TYPE_H264 9
#define TSMF_SUB_TYPE_AVC1 10
#define TSMF_SUB_TYPE_AC3 11
#define TSMF_SUB_TYPE_WMV2 12
#define TSMF_SUB_TYPE_WMV1 13
#define TSMF_SUB_TYPE_MP1V 14
#define TSMF_SUB_TYPE_MP1A 15
#define TSMF_SUB_TYPE_YUY2 16
#define TSMF_SUB_TYPE_MP43 17
#define TSMF_SUB_TYPE_MP4S 18
#define TSMF_SUB_TYPE_MP42 19
/* FormatType */
#define TSMF_FORMAT_TYPE_UNKNOWN 0
@ -115,6 +124,7 @@
#define TSMF_FORMAT_TYPE_WAVEFORMATEX 2
#define TSMF_FORMAT_TYPE_MPEG2VIDEOINFO 3
#define TSMF_FORMAT_TYPE_VIDEOINFO2 4
#define TSMF_FORMAT_TYPE_MPEG1VIDEOINFO 5
#endif

View File

@ -3,6 +3,7 @@
* Video Redirection Virtual Channel - Decoder
*
* Copyright 2010-2011 Vic Lee
* Copyright 2012 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -23,6 +24,14 @@
#include "drdynvc_types.h"
#include "tsmf_types.h"
typedef enum _ITSMFControlMsg
{
Control_Pause,
Control_Restart,
Control_Flush,
Control_EndOfStream
} ITSMFControlMsg;
typedef struct _ITSMFDecoder ITSMFDecoder;
struct _ITSMFDecoder
@ -39,6 +48,19 @@ struct _ITSMFDecoder
boolean (*GetDecodedDimension) (ITSMFDecoder* decoder, uint32* width, uint32* height);
/* Free the decoder */
void (*Free) (ITSMFDecoder * decoder);
/* Optional Contol function */
void (*Control) (ITSMFDecoder * decoder, ITSMFControlMsg control_msg, uint32 *arg);
/* Decode a sample with extended interface. */
int (*DecodeEx) (ITSMFDecoder * decoder, const uint8 * data, uint32 data_size, uint32 extensions,
uint64 start_time, uint64 end_time, uint64 duration);
/* Get current play time */
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);
/* Change Gstreamer Audio Volume */
void (*ChangeVolume) (ITSMFDecoder * decoder, uint32 newVolume, uint32 muted);
/* Check buffer level */
uint32 (*BufferLevel) (ITSMFDecoder * decoder);
};
#define TSMF_DECODER_EXPORT_FUNC_NAME "TSMFDecoderEntry"

View File

@ -3,6 +3,7 @@
* Video Redirection Virtual Channel - Interface Manipulation
*
* Copyright 2010-2011 Vic Lee
* Copyright 2012 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -118,14 +119,23 @@ int tsmf_ifman_check_format_support_request(TSMF_IFMAN* ifman)
return 0;
}
static TSMF_PRESENTATION* pexisted = 0;
int tsmf_ifman_on_new_presentation(TSMF_IFMAN* ifman)
{
int error = 0;
TSMF_PRESENTATION* presentation;
DEBUG_DVC("");
if (pexisted)
{
ifman->output_pending = false;
return 0;
}
presentation = tsmf_presentation_new(stream_get_tail(ifman->input), ifman->channel_callback);
pexisted = presentation;
if (presentation == NULL)
error = 1;
else
@ -208,6 +218,8 @@ int tsmf_ifman_shutdown_presentation(TSMF_IFMAN* ifman)
if (presentation)
tsmf_presentation_free(presentation);
pexisted = 0;
stream_check_size(ifman->output, 4);
stream_write_uint32(ifman->output, 0); /* Result */
ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
@ -216,14 +228,42 @@ int tsmf_ifman_shutdown_presentation(TSMF_IFMAN* ifman)
int tsmf_ifman_on_stream_volume(TSMF_IFMAN* ifman)
{
DEBUG_DVC("");
DEBUG_DVC("on stream volume");
TSMF_PRESENTATION* presentation;
presentation = tsmf_presentation_find_by_id(stream_get_tail(ifman->input));
if (presentation)
{
stream_seek(ifman->input, 16);
uint32 newVolume;
uint32 muted;
stream_read_uint32(ifman->input, newVolume);
DEBUG_DVC("on stream volume: new volume=[%d]", newVolume);
stream_read_uint32(ifman->input, muted);
DEBUG_DVC("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)
{
DEBUG_DVC("");
DEBUG_DVC("on channel volume");
TSMF_PRESENTATION* presentation;
presentation = tsmf_presentation_find_by_id(stream_get_tail(ifman->input));
if (presentation)
{
stream_seek(ifman->input, 16);
uint32 channelVolume;
uint32 changedChannel;
stream_read_uint32(ifman->input, channelVolume);
DEBUG_DVC("on channel volume: channel volume=[%d]", channelVolume);
stream_read_uint32(ifman->input, changedChannel);
DEBUG_DVC("on stream volume: changed channel=[%d]", changedChannel);
}
ifman->output_pending = true;
return 0;
}
@ -434,6 +474,14 @@ int tsmf_ifman_on_playback_paused(TSMF_IFMAN* ifman)
{
DEBUG_DVC("");
ifman->output_pending = true;
/* Added pause control so gstreamer pipeline can be paused accordingly */
TSMF_PRESENTATION* presentation;
presentation = tsmf_presentation_find_by_id(stream_get_tail(ifman->input));
if (presentation)
tsmf_presentation_paused(presentation);
else
DEBUG_WARN("unknown presentation id");
return 0;
}
@ -441,6 +489,14 @@ int tsmf_ifman_on_playback_restarted(TSMF_IFMAN* ifman)
{
DEBUG_DVC("");
ifman->output_pending = true;
/* Added restart control so gstreamer pipeline can be resumed accordingly */
TSMF_PRESENTATION* presentation;
presentation = tsmf_presentation_find_by_id(stream_get_tail(ifman->input));
if (presentation)
tsmf_presentation_restarted(presentation);
else
DEBUG_WARN("unknown presentation id");
return 0;
}

View File

@ -3,6 +3,7 @@
* Video Redirection Virtual Channel - Media Container
*
* Copyright 2010-2011 Vic Lee
* Copyright 2012 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,6 +21,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/stream.h>
@ -123,6 +126,9 @@ struct _TSMF_SAMPLE
};
static LIST* presentation_list = NULL;
static uint64 last_played_audio_time = 0;
static pthread_mutex_t tsmf_mutex = PTHREAD_MUTEX_INITIALIZER;
static int TERMINATING = 0;
static uint64 get_current_time(void)
{
@ -144,6 +150,10 @@ static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync)
return NULL;
if (sync)
{
if (stream->decoder)
{
if (stream->decoder->GetDecodedData)
{
if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO)
{
@ -171,7 +181,11 @@ static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync)
pending = true;
}
}
}
}
}
if (pending)
return NULL;
@ -224,6 +238,15 @@ static void tsmf_stream_process_ack(TSMF_STREAM* stream)
TSMF_PRESENTATION* tsmf_presentation_new(const uint8* guid, IWTSVirtualChannelCallback* pChannelCallback)
{
pthread_t thid = pthread_self();
FILE* fout = NULL;
fout = fopen("/tmp/tsmf.tid", "wt");
if (fout)
{
fprintf(fout, "%d\n", (int) thid);
fclose(fout);
}
TSMF_PRESENTATION* presentation;
presentation = tsmf_presentation_find_by_id(guid);
@ -423,7 +446,14 @@ static void tsmf_sample_playback(TSMF_SAMPLE* sample)
TSMF_STREAM* stream = sample->stream;
if (stream->decoder)
{
if (stream->decoder->DecodeEx)
ret = stream->decoder->DecodeEx(stream->decoder, sample->data, sample->data_size, sample->extensions,
sample->start_time, sample->end_time, sample->duration);
else
ret = stream->decoder->Decode(stream->decoder, sample->data, sample->data_size, sample->extensions);
}
if (!ret)
{
tsmf_sample_ack(sample);
@ -450,6 +480,7 @@ static void tsmf_sample_playback(TSMF_SAMPLE* sample)
ret = false ;
if (stream->decoder->GetDecodedDimension)
{
ret = stream->decoder->GetDecodedDimension(stream->decoder, &width, &height);
if (ret && (width != stream->width || height != stream->height))
{
@ -458,12 +489,11 @@ static void tsmf_sample_playback(TSMF_SAMPLE* sample)
stream->height = height;
}
}
}
if (stream->decoder->GetDecodedData)
{
sample->data = stream->decoder->GetDecodedData(stream->decoder, &sample->decoded_size);
}
switch (sample->stream->major_type)
{
case TSMF_MAJOR_TYPE_VIDEO:
@ -477,6 +507,113 @@ static void tsmf_sample_playback(TSMF_SAMPLE* sample)
break;
}
}
else
{
TSMF_STREAM * stream = sample->stream;
uint64 ack_anticipation_time = get_current_time();
uint64 currentRunningTime = sample->start_time;
uint32 bufferLevel = 0;
if (stream->decoder->GetRunningTime)
{
currentRunningTime = stream->decoder->GetRunningTime(stream->decoder);
}
if (stream->decoder->BufferLevel)
{
bufferLevel = stream->decoder->BufferLevel(stream->decoder);
}
switch (sample->stream->major_type)
{
case TSMF_MAJOR_TYPE_VIDEO:
{
TSMF_PRESENTATION * presentation = sample->stream->presentation;
/*
* Tell gstreamer that presentation screen area has moved.
* So it can render on the new area.
*/
if (presentation->last_x != presentation->output_x || presentation->last_y != presentation->output_y ||
presentation->last_width != presentation->output_width || presentation->last_height != presentation->output_height)
{
presentation->last_x = presentation->output_x;
presentation->last_y = presentation->output_y;
presentation->last_width = presentation->output_width;
presentation->last_height = presentation->output_height;
if(stream->decoder->UpdateRenderingArea)
{
stream->decoder->UpdateRenderingArea(stream->decoder, presentation->output_x, presentation->output_y,
presentation->output_width, presentation->output_height, presentation->output_num_rects, presentation->output_rects);
}
}
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)
{
xfree(presentation->last_rects);
presentation->last_rects = NULL;
}
presentation->last_num_rects = presentation->output_num_rects;
if (presentation->last_num_rects > 0)
{
presentation->last_rects = xzalloc(presentation->last_num_rects * sizeof(RDP_RECT));
memcpy(presentation->last_rects, presentation->output_rects, presentation->last_num_rects * sizeof(RDP_RECT));
}
if(stream->decoder->UpdateRenderingArea)
{
stream->decoder->UpdateRenderingArea(stream->decoder, presentation->output_x, presentation->output_y,
presentation->output_width, presentation->output_height, presentation->output_num_rects, presentation->output_rects);
}
}
if (bufferLevel < 24)
{
ack_anticipation_time += sample->duration;
}
else
{
if (currentRunningTime > sample->start_time)
{
ack_anticipation_time += sample->duration;
}
else if(currentRunningTime == 0)
{
ack_anticipation_time += sample->duration;
}
else
{
ack_anticipation_time += (sample->start_time - currentRunningTime);
}
}
break;
}
case TSMF_MAJOR_TYPE_AUDIO:
{
last_played_audio_time = currentRunningTime;
if (bufferLevel < 2)
{
ack_anticipation_time += sample->duration;
}
else
{
if (currentRunningTime > sample->start_time)
{
ack_anticipation_time += sample->duration;
}
else if(currentRunningTime == 0)
{
ack_anticipation_time += sample->duration;
}
else
{
ack_anticipation_time += (sample->start_time - currentRunningTime);
}
}
break;
}
}
sample->ack_time = ack_anticipation_time;
tsmf_sample_queue_ack(sample);
}
}
static void* tsmf_stream_playback_func(void* arg)
{
@ -488,6 +625,10 @@ static void* tsmf_stream_playback_func(void* arg)
if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO &&
stream->sample_rate && stream->channels && stream->bits_per_sample)
{
if (stream->decoder)
{
if (stream->decoder->GetDecodedData)
{
stream->audio = tsmf_load_audio_device(
presentation->audio_name && presentation->audio_name[0] ? presentation->audio_name : NULL,
@ -498,6 +639,8 @@ static void* tsmf_stream_playback_func(void* arg)
stream->sample_rate, stream->channels, stream->bits_per_sample);
}
}
}
}
while (!freerdp_thread_is_stopped(stream->thread))
{
tsmf_stream_process_ack(stream);
@ -535,10 +678,99 @@ static void tsmf_stream_start(TSMF_STREAM* stream)
static void tsmf_stream_stop(TSMF_STREAM* stream)
{
if (!stream)
return;
if (!stream->decoder)
return;
if (freerdp_thread_is_running(stream->thread))
{
freerdp_thread_stop(stream->thread);
}
if (stream->decoder->Control)
{
stream->decoder->Control(stream->decoder, Control_Flush, NULL);
}
}
static void tsmf_stream_pause(TSMF_STREAM* stream)
{
if (!stream)
return;
if (!stream->decoder)
return;
if (stream->decoder->Control)
{
stream->decoder->Control(stream->decoder, Control_Pause, NULL);
}
}
static void tsmf_stream_restart(TSMF_STREAM* stream)
{
if (!stream)
return;
if (!stream->decoder)
return;
if (stream->decoder->Control)
{
stream->decoder->Control(stream->decoder, Control_Restart, NULL);
}
}
static void tsmf_stream_change_volume(TSMF_STREAM* stream, uint32 newVolume, uint32 muted)
{
if (!stream)
return;
if (!stream->decoder)
return;
if (stream->decoder->ChangeVolume)
{
stream->decoder->ChangeVolume(stream->decoder, newVolume, muted);
}
}
void tsmf_presentation_volume_changed(TSMF_PRESENTATION* presentation, uint32 newVolume, uint32 muted)
{
LIST_ITEM* item;
TSMF_STREAM* stream;
for (item = presentation->stream_list->head; item; item = item->next)
{
stream = (TSMF_STREAM*) item->data;
tsmf_stream_change_volume(stream, newVolume, muted);
}
}
void tsmf_presentation_paused(TSMF_PRESENTATION* presentation)
{
LIST_ITEM* item;
TSMF_STREAM* stream;
for (item = presentation->stream_list->head; item; item = item->next)
{
stream = (TSMF_STREAM*) item->data;
tsmf_stream_pause(stream);
}
}
void tsmf_presentation_restarted(TSMF_PRESENTATION* presentation)
{
LIST_ITEM* item;
TSMF_STREAM* stream;
for (item = presentation->stream_list->head; item; item = item->next)
{
stream = (TSMF_STREAM*) item->data;
tsmf_stream_restart(stream);
}
}
void tsmf_presentation_start(TSMF_PRESENTATION* presentation)
@ -645,7 +877,9 @@ void tsmf_presentation_free(TSMF_PRESENTATION* presentation)
TSMF_STREAM* stream;
tsmf_presentation_stop(presentation);
freerdp_mutex_lock(presentation->mutex);
list_remove(presentation_list, presentation);
freerdp_mutex_unlock(presentation->mutex);
while (list_size(presentation->stream_list) > 0)
{
@ -757,17 +991,28 @@ void tsmf_stream_free(TSMF_STREAM* stream)
list_free(stream->sample_ack_list);
if (stream->decoder)
{
stream->decoder->Free(stream->decoder);
stream->decoder = 0;
}
freerdp_thread_free(stream->thread);
xfree(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, uint8* data)
{
pthread_mutex_lock(&tsmf_mutex);
if (TERMINATING)
{
pthread_mutex_unlock(&tsmf_mutex);
return;
}
pthread_mutex_unlock(&tsmf_mutex);
TSMF_SAMPLE* sample;
sample = xnew(TSMF_SAMPLE);
@ -788,8 +1033,51 @@ void tsmf_stream_push_sample(TSMF_STREAM* stream, IWTSVirtualChannelCallback* pC
freerdp_thread_unlock(stream->thread);
}
static void tsmf_signal_handler(int s)
{
pthread_mutex_lock(&tsmf_mutex);
TERMINATING = 1;
pthread_mutex_unlock(&tsmf_mutex);
LIST_ITEM* p_item;
TSMF_PRESENTATION* presentation;
LIST_ITEM* s_item;
TSMF_STREAM* _stream;
if (presentation_list)
{
for (p_item = presentation_list->head; p_item; p_item = p_item->next)
{
presentation = (TSMF_PRESENTATION*) p_item->data;
for (s_item = presentation->stream_list->head; s_item; s_item = s_item->next)
{
_stream = (TSMF_STREAM*) s_item->data;
tsmf_stream_free(_stream);
}
tsmf_presentation_free(presentation);
}
}
unlink("/tmp/tsmf.tid");
if (s == SIGINT)
{
signal(s, SIG_DFL);
kill(getpid(), s);
}
else if (s == SIGUSR1)
{
signal(s, SIG_DFL);
}
}
void tsmf_media_init(void)
{
struct sigaction sigtrap;
sigtrap.sa_handler = tsmf_signal_handler;
sigemptyset(&sigtrap.sa_mask);
sigtrap.sa_flags = 0;
sigaction(SIGINT, &sigtrap, 0);
sigaction(SIGUSR1, &sigtrap, 0);
if (presentation_list == NULL)
presentation_list = list_new();
}

View File

@ -3,6 +3,7 @@
* Video Redirection Virtual Channel - Media Container
*
* Copyright 2010-2011 Vic Lee
* Copyright 2012 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -35,6 +36,9 @@ TSMF_PRESENTATION* tsmf_presentation_new(const uint8* guid, IWTSVirtualChannelCa
TSMF_PRESENTATION* tsmf_presentation_find_by_id(const uint8* 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);

View File

@ -3,6 +3,7 @@
* X11 Windows
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* 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.
@ -21,6 +22,9 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <freerdp/rail.h>
#include <freerdp/utils/rail.h>
@ -61,6 +65,9 @@
#define PROP_MOTIF_WM_HINTS_ELEMENTS 5
/*to be accessed by gstreamer plugin*/
#define SHARED_MEM_KEY 7777
struct _PropMotifWmHints
{
unsigned long flags;
@ -294,6 +301,24 @@ xfWindow* xf_CreateDesktopWindow(xfInfo* xfi, char* name, int width, int height,
CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
CWBorderPixel | CWWinGravity | CWBitGravity, &xfi->attribs);
int shmid = shmget(SHARED_MEM_KEY, sizeof(int), IPC_CREAT | 0666);
if (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)
{
DEBUG_X11("xf_CreateDesktopWindow: failed to assign pointer to the memory address - shmat()\n");
}
else
{
*xfwin = (int)window->handle;
}
}
class_hints = XAllocClassHint();
if (class_hints != NULL)

View File

@ -3,6 +3,7 @@
* X11 Client
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* 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.
@ -1156,6 +1157,31 @@ int xfreerdp_run(freerdp* instance)
xf_process_channel_event(channels, instance);
}
FILE *fin = fopen("/tmp/tsmf.tid", "rt");
if(fin)
{
int thid = 0;
fscanf(fin, "%d", &thid);
fclose(fin);
pthread_kill((pthread_t) thid, SIGUSR1);
FILE *fin1 = fopen("/tmp/tsmf.tid", "rt");
int timeout = 5;
while (fin1)
{
fclose(fin1);
sleep(1);
timeout--;
if (timeout <= 0)
{
unlink("/tmp/tsmf.tid");
pthread_kill((pthread_t) thid, SIGKILL);
break;
}
fin1 = fopen("/tmp/tsmf.tid", "rt");
}
}
if (!ret)
ret = freerdp_error_info(instance);

View File

@ -0,0 +1,2 @@
pkg_check_modules(GSTREAMER gstreamer-plugins-base-0.10 gstreamer-0.10)