1 /*
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * Video Redirection Virtual Channel - GStreamer Decoder
4  *
5  * (C) Copyright 2012 HP Development Company, LLC
6  * (C) Copyright 2014 Thincast Technologies GmbH
7  * (C) Copyright 2014 Armin Novak <armin.novak@thincast.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *     http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include <assert.h>
27 
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #include <winpr/string.h>
35 
36 #if __clang__
37 #pragma clang diagnostic push
38 #pragma clang diagnostic ignored "-Wparentheses-equality"
39 #endif /* __clang__ */
40 #include <gst/gst.h>
41 #if __clang__
42 #pragma clang diagnostic pop
43 #endif /* __clang__ */
44 
45 #include <gst/app/gstappsrc.h>
46 #include <gst/app/gstappsink.h>
47 
48 #include "tsmf_constants.h"
49 #include "tsmf_decoder.h"
50 #include "tsmf_platform.h"
51 
52 #ifdef HAVE_INTTYPES_H
53 #include <inttypes.h>
54 #endif
55 
56 /* 1 second = 10,000,000 100ns units*/
57 #define SEEK_TOLERANCE 10 * 1000 * 1000
58 
59 static BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder);
60 static void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder* mdecoder);
61 static int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder* mdecoder,
62                                              GstState desired_state);
63 static BOOL tsmf_gstreamer_buffer_level(ITSMFDecoder* decoder);
64 
get_type(TSMFGstreamerDecoder * mdecoder)65 static const char* get_type(TSMFGstreamerDecoder* mdecoder)
66 {
67 	if (!mdecoder)
68 		return NULL;
69 
70 	switch (mdecoder->media_type)
71 	{
72 		case TSMF_MAJOR_TYPE_VIDEO:
73 			return "VIDEO";
74 		case TSMF_MAJOR_TYPE_AUDIO:
75 			return "AUDIO";
76 		default:
77 			return "UNKNOWN";
78 	}
79 }
80 
cb_child_added(GstChildProxy * child_proxy,GObject * object,TSMFGstreamerDecoder * mdecoder)81 static void cb_child_added(GstChildProxy* child_proxy, GObject* object,
82                            TSMFGstreamerDecoder* mdecoder)
83 {
84 	DEBUG_TSMF("NAME: %s", G_OBJECT_TYPE_NAME(object));
85 
86 	if (!g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstXvImageSink") ||
87 	    !g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstXImageSink") ||
88 	    !g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstFluVAAutoSink"))
89 	{
90 		gst_base_sink_set_max_lateness((GstBaseSink*)object, 10000000); /* nanoseconds */
91 		g_object_set(G_OBJECT(object), "sync", TRUE, NULL);  /* synchronize on the clock */
92 		g_object_set(G_OBJECT(object), "async", TRUE, NULL); /* no async state changes */
93 	}
94 
95 	else if (!g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstAlsaSink") ||
96 	         !g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstPulseSink"))
97 	{
98 		gst_base_sink_set_max_lateness((GstBaseSink*)object, 10000000); /* nanoseconds */
99 		g_object_set(G_OBJECT(object), "slave-method", 1, NULL);
100 		g_object_set(G_OBJECT(object), "buffer-time", (gint64)20000, NULL);     /* microseconds */
101 		g_object_set(G_OBJECT(object), "drift-tolerance", (gint64)20000, NULL); /* microseconds */
102 		g_object_set(G_OBJECT(object), "latency-time", (gint64)10000, NULL);    /* microseconds */
103 		g_object_set(G_OBJECT(object), "sync", TRUE, NULL);  /* synchronize on the clock */
104 		g_object_set(G_OBJECT(object), "async", TRUE, NULL); /* no async state changes */
105 	}
106 }
107 
tsmf_gstreamer_enough_data(GstAppSrc * src,gpointer user_data)108 static void tsmf_gstreamer_enough_data(GstAppSrc* src, gpointer user_data)
109 {
110 	TSMFGstreamerDecoder* mdecoder = user_data;
111 	(void)mdecoder;
112 	DEBUG_TSMF("%s", get_type(mdecoder));
113 }
114 
tsmf_gstreamer_need_data(GstAppSrc * src,guint length,gpointer user_data)115 static void tsmf_gstreamer_need_data(GstAppSrc* src, guint length, gpointer user_data)
116 {
117 	TSMFGstreamerDecoder* mdecoder = user_data;
118 	(void)mdecoder;
119 	DEBUG_TSMF("%s length=%u", get_type(mdecoder), length);
120 }
121 
tsmf_gstreamer_seek_data(GstAppSrc * src,guint64 offset,gpointer user_data)122 static gboolean tsmf_gstreamer_seek_data(GstAppSrc* src, guint64 offset, gpointer user_data)
123 {
124 	TSMFGstreamerDecoder* mdecoder = user_data;
125 	(void)mdecoder;
126 	DEBUG_TSMF("%s offset=%" PRIu64 "", get_type(mdecoder), offset);
127 
128 	return TRUE;
129 }
130 
tsmf_gstreamer_change_volume(ITSMFDecoder * decoder,UINT32 newVolume,UINT32 muted)131 static BOOL tsmf_gstreamer_change_volume(ITSMFDecoder* decoder, UINT32 newVolume, UINT32 muted)
132 {
133 	TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder;
134 
135 	if (!mdecoder || !mdecoder->pipe)
136 		return TRUE;
137 
138 	if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
139 		return TRUE;
140 
141 	mdecoder->gstMuted = (BOOL)muted;
142 	DEBUG_TSMF("mute=[%" PRId32 "]", mdecoder->gstMuted);
143 	mdecoder->gstVolume = (double)newVolume / (double)10000;
144 	DEBUG_TSMF("gst_new_vol=[%f]", mdecoder->gstVolume);
145 
146 	if (!mdecoder->volume)
147 		return TRUE;
148 
149 	if (!G_IS_OBJECT(mdecoder->volume))
150 		return TRUE;
151 
152 	g_object_set(mdecoder->volume, "mute", mdecoder->gstMuted, NULL);
153 	g_object_set(mdecoder->volume, "volume", mdecoder->gstVolume, NULL);
154 
155 	return TRUE;
156 }
157 
tsmf_gstreamer_timestamp_ms_to_gst(UINT64 ms_timestamp)158 static inline GstClockTime tsmf_gstreamer_timestamp_ms_to_gst(UINT64 ms_timestamp)
159 {
160 	/*
161 	 * Convert Microsoft 100ns timestamps to Gstreamer 1ns units.
162 	 */
163 	return (GstClockTime)(ms_timestamp * 100);
164 }
165 
tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder * mdecoder,GstState desired_state)166 int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder* mdecoder, GstState desired_state)
167 {
168 	GstStateChangeReturn state_change;
169 	const char* name;
170 	const char* sname = get_type(mdecoder);
171 
172 	if (!mdecoder)
173 		return 0;
174 
175 	if (!mdecoder->pipe)
176 		return 0; /* Just in case this is called during startup or shutdown when we don't expect it
177 		           */
178 
179 	if (desired_state == mdecoder->state)
180 		return 0; /* Redundant request - Nothing to do */
181 
182 	name = gst_element_state_get_name(desired_state); /* For debug */
183 	DEBUG_TSMF("%s to %s", sname, name);
184 	state_change = gst_element_set_state(mdecoder->pipe, desired_state);
185 
186 	if (state_change == GST_STATE_CHANGE_FAILURE)
187 	{
188 		WLog_ERR(TAG, "%s: (%s) GST_STATE_CHANGE_FAILURE.", sname, name);
189 	}
190 	else if (state_change == GST_STATE_CHANGE_ASYNC)
191 	{
192 		WLog_ERR(TAG, "%s: (%s) GST_STATE_CHANGE_ASYNC.", sname, name);
193 		mdecoder->state = desired_state;
194 	}
195 	else
196 	{
197 		mdecoder->state = desired_state;
198 	}
199 
200 	return 0;
201 }
202 
tsmf_get_buffer_from_data(const void * raw_data,gsize size)203 static GstBuffer* tsmf_get_buffer_from_data(const void* raw_data, gsize size)
204 {
205 	GstBuffer* buffer;
206 	gpointer data;
207 
208 	if (!raw_data)
209 		return NULL;
210 
211 	if (size < 1)
212 		return NULL;
213 
214 	data = g_malloc(size);
215 
216 	if (!data)
217 	{
218 		WLog_ERR(TAG, "Could not allocate %" G_GSIZE_FORMAT " bytes of data.", size);
219 		return NULL;
220 	}
221 
222 	CopyMemory(data, raw_data, size);
223 
224 #if GST_VERSION_MAJOR > 0
225 	buffer = gst_buffer_new_wrapped(data, size);
226 #else
227 	buffer = gst_buffer_new();
228 
229 	if (!buffer)
230 	{
231 		WLog_ERR(TAG, "Could not create GstBuffer");
232 		free(data);
233 		return NULL;
234 	}
235 
236 	GST_BUFFER_MALLOCDATA(buffer) = data;
237 	GST_BUFFER_SIZE(buffer) = size;
238 	GST_BUFFER_DATA(buffer) = GST_BUFFER_MALLOCDATA(buffer);
239 #endif
240 
241 	return buffer;
242 }
243 
tsmf_gstreamer_set_format(ITSMFDecoder * decoder,TS_AM_MEDIA_TYPE * media_type)244 static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* media_type)
245 {
246 	TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder;
247 
248 	if (!mdecoder)
249 		return FALSE;
250 
251 	DEBUG_TSMF("");
252 
253 	switch (media_type->MajorType)
254 	{
255 		case TSMF_MAJOR_TYPE_VIDEO:
256 			mdecoder->media_type = TSMF_MAJOR_TYPE_VIDEO;
257 			break;
258 		case TSMF_MAJOR_TYPE_AUDIO:
259 			mdecoder->media_type = TSMF_MAJOR_TYPE_AUDIO;
260 			break;
261 		default:
262 			return FALSE;
263 	}
264 
265 	switch (media_type->SubType)
266 	{
267 		case TSMF_SUB_TYPE_WVC1:
268 			mdecoder->gst_caps = gst_caps_new_simple(
269 			    "video/x-wmv", "bitrate", G_TYPE_UINT, media_type->BitRate, "width", G_TYPE_INT,
270 			    media_type->Width, "height", G_TYPE_INT, media_type->Height, "wmvversion",
271 			    G_TYPE_INT, 3,
272 #if GST_VERSION_MAJOR > 0
273 			    "format", G_TYPE_STRING, "WVC1",
274 #else
275 			    "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('W', 'V', 'C', '1'),
276 #endif
277 			    "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator,
278 			    media_type->SamplesPerSecond.Denominator, "pixel-aspect-ratio", GST_TYPE_FRACTION,
279 			    1, 1, NULL);
280 			break;
281 		case TSMF_SUB_TYPE_MP4S:
282 			mdecoder->gst_caps = gst_caps_new_simple(
283 			    "video/x-divx", "divxversion", G_TYPE_INT, 5, "bitrate", G_TYPE_UINT,
284 			    media_type->BitRate, "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT,
285 			    media_type->Height,
286 #if GST_VERSION_MAJOR > 0
287 			    "format", G_TYPE_STRING, "MP42",
288 #else
289 			    "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('M', 'P', '4', '2'),
290 #endif
291 			    "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator,
292 			    media_type->SamplesPerSecond.Denominator, NULL);
293 			break;
294 		case TSMF_SUB_TYPE_MP42:
295 			mdecoder->gst_caps = gst_caps_new_simple(
296 			    "video/x-msmpeg", "msmpegversion", G_TYPE_INT, 42, "bitrate", G_TYPE_UINT,
297 			    media_type->BitRate, "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT,
298 			    media_type->Height,
299 #if GST_VERSION_MAJOR > 0
300 			    "format", G_TYPE_STRING, "MP42",
301 #else
302 			    "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('M', 'P', '4', '2'),
303 #endif
304 			    "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator,
305 			    media_type->SamplesPerSecond.Denominator, NULL);
306 			break;
307 		case TSMF_SUB_TYPE_MP43:
308 			mdecoder->gst_caps = gst_caps_new_simple(
309 			    "video/x-msmpeg", "msmpegversion", G_TYPE_INT, 43, "bitrate", G_TYPE_UINT,
310 			    media_type->BitRate, "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT,
311 			    media_type->Height,
312 #if GST_VERSION_MAJOR > 0
313 			    "format", G_TYPE_STRING, "MP43",
314 #else
315 			    "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('M', 'P', '4', '3'),
316 #endif
317 			    "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator,
318 			    media_type->SamplesPerSecond.Denominator, NULL);
319 			break;
320 		case TSMF_SUB_TYPE_M4S2:
321 			mdecoder->gst_caps = gst_caps_new_simple(
322 			    "video/mpeg", "mpegversion", G_TYPE_INT, 4, "width", G_TYPE_INT, media_type->Width,
323 			    "height", G_TYPE_INT, media_type->Height,
324 #if GST_VERSION_MAJOR > 0
325 			    "format", G_TYPE_STRING, "M4S2",
326 #else
327 			    "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('M', '4', 'S', '2'),
328 #endif
329 			    "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator,
330 			    media_type->SamplesPerSecond.Denominator, NULL);
331 			break;
332 		case TSMF_SUB_TYPE_WMA9:
333 			mdecoder->gst_caps = gst_caps_new_simple(
334 			    "audio/x-wma", "wmaversion", G_TYPE_INT, 3, "rate", G_TYPE_INT,
335 			    media_type->SamplesPerSecond.Numerator, "channels", G_TYPE_INT,
336 			    media_type->Channels, "bitrate", G_TYPE_INT, media_type->BitRate, "depth",
337 			    G_TYPE_INT, media_type->BitsPerSample, "width", G_TYPE_INT,
338 			    media_type->BitsPerSample, "block_align", G_TYPE_INT, media_type->BlockAlign, NULL);
339 			break;
340 		case TSMF_SUB_TYPE_WMA1:
341 			mdecoder->gst_caps = gst_caps_new_simple(
342 			    "audio/x-wma", "wmaversion", G_TYPE_INT, 1, "rate", G_TYPE_INT,
343 			    media_type->SamplesPerSecond.Numerator, "channels", G_TYPE_INT,
344 			    media_type->Channels, "bitrate", G_TYPE_INT, media_type->BitRate, "depth",
345 			    G_TYPE_INT, media_type->BitsPerSample, "width", G_TYPE_INT,
346 			    media_type->BitsPerSample, "block_align", G_TYPE_INT, media_type->BlockAlign, NULL);
347 			break;
348 		case TSMF_SUB_TYPE_WMA2:
349 			mdecoder->gst_caps = gst_caps_new_simple(
350 			    "audio/x-wma", "wmaversion", G_TYPE_INT, 2, "rate", G_TYPE_INT,
351 			    media_type->SamplesPerSecond.Numerator, "channels", G_TYPE_INT,
352 			    media_type->Channels, "bitrate", G_TYPE_INT, media_type->BitRate, "depth",
353 			    G_TYPE_INT, media_type->BitsPerSample, "width", G_TYPE_INT,
354 			    media_type->BitsPerSample, "block_align", G_TYPE_INT, media_type->BlockAlign, NULL);
355 			break;
356 		case TSMF_SUB_TYPE_MP3:
357 			mdecoder->gst_caps =
358 			    gst_caps_new_simple("audio/mpeg", "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT,
359 			                        3, "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator,
360 			                        "channels", G_TYPE_INT, media_type->Channels, NULL);
361 			break;
362 		case TSMF_SUB_TYPE_WMV1:
363 			mdecoder->gst_caps = gst_caps_new_simple(
364 			    "video/x-wmv", "bitrate", G_TYPE_UINT, media_type->BitRate, "width", G_TYPE_INT,
365 			    media_type->Width, "height", G_TYPE_INT, media_type->Height, "wmvversion",
366 			    G_TYPE_INT, 1,
367 #if GST_VERSION_MAJOR > 0
368 			    "format", G_TYPE_STRING, "WMV1",
369 #else
370 			    "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('W', 'M', 'V', '1'),
371 #endif
372 			    "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator,
373 			    media_type->SamplesPerSecond.Denominator, NULL);
374 			break;
375 		case TSMF_SUB_TYPE_WMV2:
376 			mdecoder->gst_caps = gst_caps_new_simple(
377 			    "video/x-wmv", "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT,
378 			    media_type->Height, "wmvversion", G_TYPE_INT, 2,
379 #if GST_VERSION_MAJOR > 0
380 			    "format", G_TYPE_STRING, "WMV2",
381 #else
382 			    "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('W', 'M', 'V', '2'),
383 #endif
384 			    "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator,
385 			    media_type->SamplesPerSecond.Denominator, "pixel-aspect-ratio", GST_TYPE_FRACTION,
386 			    1, 1, NULL);
387 			break;
388 		case TSMF_SUB_TYPE_WMV3:
389 			mdecoder->gst_caps = gst_caps_new_simple(
390 			    "video/x-wmv", "bitrate", G_TYPE_UINT, media_type->BitRate, "width", G_TYPE_INT,
391 			    media_type->Width, "height", G_TYPE_INT, media_type->Height, "wmvversion",
392 			    G_TYPE_INT, 3,
393 #if GST_VERSION_MAJOR > 0
394 			    "format", G_TYPE_STRING, "WMV3",
395 #else
396 			    "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('W', 'M', 'V', '3'),
397 #endif
398 			    "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator,
399 			    media_type->SamplesPerSecond.Denominator, "pixel-aspect-ratio", GST_TYPE_FRACTION,
400 			    1, 1, NULL);
401 			break;
402 		case TSMF_SUB_TYPE_AVC1:
403 		case TSMF_SUB_TYPE_H264:
404 			mdecoder->gst_caps = gst_caps_new_simple(
405 			    "video/x-h264", "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT,
406 			    media_type->Height, "framerate", GST_TYPE_FRACTION,
407 			    media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator,
408 			    "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, "stream-format", G_TYPE_STRING,
409 			    "byte-stream", "alignment", G_TYPE_STRING, "nal", NULL);
410 			break;
411 		case TSMF_SUB_TYPE_AC3:
412 			mdecoder->gst_caps = gst_caps_new_simple(
413 			    "audio/x-ac3", "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator,
414 			    "channels", G_TYPE_INT, media_type->Channels, NULL);
415 			break;
416 		case TSMF_SUB_TYPE_AAC:
417 
418 			/* For AAC the pFormat is a HEAACWAVEINFO struct, and the codec data
419 			   is at the end of it. See
420 			   http://msdn.microsoft.com/en-us/library/dd757806.aspx */
421 			if (media_type->ExtraData)
422 			{
423 				media_type->ExtraData += 12;
424 				media_type->ExtraDataSize -= 12;
425 			}
426 
427 			mdecoder->gst_caps = gst_caps_new_simple(
428 			    "audio/mpeg", "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator,
429 			    "channels", G_TYPE_INT, media_type->Channels, "mpegversion", G_TYPE_INT, 4,
430 			    "framed", G_TYPE_BOOLEAN, TRUE, "stream-format", G_TYPE_STRING, "raw", NULL);
431 			break;
432 		case TSMF_SUB_TYPE_MP1A:
433 			mdecoder->gst_caps =
434 			    gst_caps_new_simple("audio/mpeg", "mpegversion", G_TYPE_INT, 1, "channels",
435 			                        G_TYPE_INT, media_type->Channels, NULL);
436 			break;
437 		case TSMF_SUB_TYPE_MP1V:
438 			mdecoder->gst_caps =
439 			    gst_caps_new_simple("video/mpeg", "mpegversion", G_TYPE_INT, 1, "width", G_TYPE_INT,
440 			                        media_type->Width, "height", G_TYPE_INT, media_type->Height,
441 			                        "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
442 			break;
443 		case TSMF_SUB_TYPE_YUY2:
444 #if GST_VERSION_MAJOR > 0
445 			mdecoder->gst_caps = gst_caps_new_simple(
446 			    "video/x-raw", "format", G_TYPE_STRING, "YUY2", "width", G_TYPE_INT,
447 			    media_type->Width, "height", G_TYPE_INT, media_type->Height, NULL);
448 #else
449 			mdecoder->gst_caps = gst_caps_new_simple(
450 			    "video/x-raw-yuv", "format", G_TYPE_STRING, "YUY2", "width", G_TYPE_INT,
451 			    media_type->Width, "height", G_TYPE_INT, media_type->Height, "framerate",
452 			    GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator,
453 			    media_type->SamplesPerSecond.Denominator, NULL);
454 #endif
455 			break;
456 		case TSMF_SUB_TYPE_MP2V:
457 			mdecoder->gst_caps = gst_caps_new_simple("video/mpeg", "mpegversion", G_TYPE_INT, 2,
458 			                                         "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
459 			break;
460 		case TSMF_SUB_TYPE_MP2A:
461 			mdecoder->gst_caps =
462 			    gst_caps_new_simple("audio/mpeg", "mpegversion", G_TYPE_INT, 1, "rate", G_TYPE_INT,
463 			                        media_type->SamplesPerSecond.Numerator, "channels", G_TYPE_INT,
464 			                        media_type->Channels, NULL);
465 			break;
466 		case TSMF_SUB_TYPE_FLAC:
467 			mdecoder->gst_caps = gst_caps_new_simple("audio/x-flac", "", NULL);
468 			break;
469 		default:
470 			WLog_ERR(TAG, "unknown format:(%d).", media_type->SubType);
471 			return FALSE;
472 	}
473 
474 	if (media_type->ExtraDataSize > 0)
475 	{
476 		GstBuffer* buffer;
477 		DEBUG_TSMF("Extra data available (%" PRIu32 ")", media_type->ExtraDataSize);
478 		buffer = tsmf_get_buffer_from_data(media_type->ExtraData, media_type->ExtraDataSize);
479 
480 		if (!buffer)
481 		{
482 			WLog_ERR(TAG, "could not allocate GstBuffer!");
483 			return FALSE;
484 		}
485 
486 		gst_caps_set_simple(mdecoder->gst_caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL);
487 	}
488 
489 	DEBUG_TSMF("%p format '%s'", (void*)mdecoder, gst_caps_to_string(mdecoder->gst_caps));
490 	tsmf_platform_set_format(mdecoder);
491 
492 	/* Create the pipeline... */
493 	if (!tsmf_gstreamer_pipeline_build(mdecoder))
494 		return FALSE;
495 
496 	return TRUE;
497 }
498 
tsmf_gstreamer_clean_up(TSMFGstreamerDecoder * mdecoder)499 void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder* mdecoder)
500 {
501 	if (!mdecoder || !mdecoder->pipe)
502 		return;
503 
504 	if (mdecoder->pipe && GST_OBJECT_REFCOUNT_VALUE(mdecoder->pipe) > 0)
505 	{
506 		tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_NULL);
507 		gst_object_unref(mdecoder->pipe);
508 	}
509 
510 	mdecoder->ready = FALSE;
511 	mdecoder->paused = FALSE;
512 
513 	mdecoder->pipe = NULL;
514 	mdecoder->src = NULL;
515 	mdecoder->queue = NULL;
516 }
517 
tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder * mdecoder)518 BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder)
519 {
520 #if GST_VERSION_MAJOR > 0
521 	const char* video =
522 	    "appsrc name=videosource ! queue2 name=videoqueue ! decodebin name=videodecoder !";
523 	const char* audio =
524 	    "appsrc name=audiosource ! queue2 name=audioqueue ! decodebin name=audiodecoder ! "
525 	    "audioconvert ! audiorate ! audioresample ! volume name=audiovolume !";
526 #else
527 	const char* video =
528 	    "appsrc name=videosource ! queue2 name=videoqueue ! decodebin2 name=videodecoder !";
529 	const char* audio =
530 	    "appsrc name=audiosource ! queue2 name=audioqueue ! decodebin2 name=audiodecoder ! "
531 	    "audioconvert ! audiorate ! audioresample ! volume name=audiovolume !";
532 #endif
533 	char pipeline[1024];
534 
535 	if (!mdecoder)
536 		return FALSE;
537 
538 	/* TODO: Construction of the pipeline from a string allows easy overwrite with arguments.
539 	 *       The only fixed elements necessary are appsrc and the volume element for audio streams.
540 	 *       The rest could easily be provided in gstreamer pipeline notation from command line. */
541 	if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
542 		sprintf_s(pipeline, sizeof(pipeline), "%s %s name=videosink", video,
543 		          tsmf_platform_get_video_sink());
544 	else
545 		sprintf_s(pipeline, sizeof(pipeline), "%s %s name=audiosink", audio,
546 		          tsmf_platform_get_audio_sink());
547 
548 	DEBUG_TSMF("pipeline=%s", pipeline);
549 	mdecoder->pipe = gst_parse_launch(pipeline, NULL);
550 
551 	if (!mdecoder->pipe)
552 	{
553 		WLog_ERR(TAG, "Failed to create new pipe");
554 		return FALSE;
555 	}
556 
557 	if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
558 		mdecoder->src = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "videosource");
559 	else
560 		mdecoder->src = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "audiosource");
561 
562 	if (!mdecoder->src)
563 	{
564 		WLog_ERR(TAG, "Failed to get appsrc");
565 		return FALSE;
566 	}
567 
568 	if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
569 		mdecoder->queue = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "videoqueue");
570 	else
571 		mdecoder->queue = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "audioqueue");
572 
573 	if (!mdecoder->queue)
574 	{
575 		WLog_ERR(TAG, "Failed to get queue");
576 		return FALSE;
577 	}
578 
579 	if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
580 		mdecoder->outsink = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "videosink");
581 	else
582 		mdecoder->outsink = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "audiosink");
583 
584 	if (!mdecoder->outsink)
585 	{
586 		WLog_ERR(TAG, "Failed to get sink");
587 		return FALSE;
588 	}
589 
590 	g_signal_connect(mdecoder->outsink, "child-added", G_CALLBACK(cb_child_added), mdecoder);
591 
592 	if (mdecoder->media_type == TSMF_MAJOR_TYPE_AUDIO)
593 	{
594 		mdecoder->volume = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "audiovolume");
595 
596 		if (!mdecoder->volume)
597 		{
598 			WLog_ERR(TAG, "Failed to get volume");
599 			return FALSE;
600 		}
601 
602 		tsmf_gstreamer_change_volume((ITSMFDecoder*)mdecoder, mdecoder->gstVolume * ((double)10000),
603 		                             mdecoder->gstMuted);
604 	}
605 
606 	tsmf_platform_register_handler(mdecoder);
607 	/* AppSrc settings */
608 	GstAppSrcCallbacks callbacks = {
609 		tsmf_gstreamer_need_data, tsmf_gstreamer_enough_data, tsmf_gstreamer_seek_data, { NULL }
610 	};
611 	g_object_set(mdecoder->src, "format", GST_FORMAT_TIME, NULL);
612 	g_object_set(mdecoder->src, "is-live", FALSE, NULL);
613 	g_object_set(mdecoder->src, "block", FALSE, NULL);
614 	g_object_set(mdecoder->src, "blocksize", 1024, NULL);
615 	gst_app_src_set_caps((GstAppSrc*)mdecoder->src, mdecoder->gst_caps);
616 	gst_app_src_set_callbacks((GstAppSrc*)mdecoder->src, &callbacks, mdecoder, NULL);
617 	gst_app_src_set_stream_type((GstAppSrc*)mdecoder->src, GST_APP_STREAM_TYPE_SEEKABLE);
618 	gst_app_src_set_latency((GstAppSrc*)mdecoder->src, 0, -1);
619 	gst_app_src_set_max_bytes((GstAppSrc*)mdecoder->src, (guint64)0); // unlimited
620 	g_object_set(G_OBJECT(mdecoder->queue), "use-buffering", FALSE, NULL);
621 	g_object_set(G_OBJECT(mdecoder->queue), "use-rate-estimate", FALSE, NULL);
622 	g_object_set(G_OBJECT(mdecoder->queue), "max-size-buffers", 0, NULL);
623 	g_object_set(G_OBJECT(mdecoder->queue), "max-size-bytes", 0, NULL);
624 	g_object_set(G_OBJECT(mdecoder->queue), "max-size-time", (guint64)0, NULL);
625 
626 	/* Only set these properties if not an autosink, otherwise we will set properties when real
627 	 * sinks are added */
628 	if (!g_strcmp0(G_OBJECT_TYPE_NAME(mdecoder->outsink), "GstAutoVideoSink") &&
629 	    !g_strcmp0(G_OBJECT_TYPE_NAME(mdecoder->outsink), "GstAutoAudioSink"))
630 	{
631 		if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
632 		{
633 			gst_base_sink_set_max_lateness((GstBaseSink*)mdecoder->outsink,
634 			                               10000000); /* nanoseconds */
635 		}
636 		else
637 		{
638 			gst_base_sink_set_max_lateness((GstBaseSink*)mdecoder->outsink,
639 			                               10000000); /* nanoseconds */
640 			g_object_set(G_OBJECT(mdecoder->outsink), "buffer-time", (gint64)20000,
641 			             NULL); /* microseconds */
642 			g_object_set(G_OBJECT(mdecoder->outsink), "drift-tolerance", (gint64)20000,
643 			             NULL); /* microseconds */
644 			g_object_set(G_OBJECT(mdecoder->outsink), "latency-time", (gint64)10000,
645 			             NULL); /* microseconds */
646 			g_object_set(G_OBJECT(mdecoder->outsink), "slave-method", 1, NULL);
647 		}
648 		g_object_set(G_OBJECT(mdecoder->outsink), "sync", TRUE,
649 		             NULL); /* synchronize on the clock */
650 		g_object_set(G_OBJECT(mdecoder->outsink), "async", TRUE, NULL); /* no async state changes */
651 	}
652 
653 	tsmf_window_create(mdecoder);
654 	tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_READY);
655 	tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING);
656 	mdecoder->pipeline_start_time_valid = 0;
657 	mdecoder->shutdown = 0;
658 	mdecoder->paused = FALSE;
659 
660 	GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(mdecoder->pipe), GST_DEBUG_GRAPH_SHOW_ALL,
661 	                          get_type(mdecoder));
662 
663 	return TRUE;
664 }
665 
tsmf_gstreamer_decodeEx(ITSMFDecoder * decoder,const BYTE * data,UINT32 data_size,UINT32 extensions,UINT64 start_time,UINT64 end_time,UINT64 duration)666 static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size,
667                                     UINT32 extensions, UINT64 start_time, UINT64 end_time,
668                                     UINT64 duration)
669 {
670 	GstBuffer* gst_buf;
671 	TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder;
672 	UINT64 sample_time = tsmf_gstreamer_timestamp_ms_to_gst(start_time);
673 	BOOL useTimestamps = TRUE;
674 
675 	if (!mdecoder)
676 	{
677 		WLog_ERR(TAG, "Decoder not initialized!");
678 		return FALSE;
679 	}
680 
681 	/*
682 	 * This function is always called from a stream-specific thread.
683 	 * It should be alright to block here if necessary.
684 	 * We don't expect to block here often, since the pipeline should
685 	 * have more than enough buffering.
686 	 */
687 	DEBUG_TSMF(
688 	    "%s. Start:(%" PRIu64 ") End:(%" PRIu64 ") Duration:(%" PRIu64 ") Last Start:(%" PRIu64 ")",
689 	    get_type(mdecoder), start_time, end_time, duration, mdecoder->last_sample_start_time);
690 
691 	if (mdecoder->shutdown)
692 	{
693 		WLog_ERR(TAG, "decodeEx called on shutdown decoder");
694 		return TRUE;
695 	}
696 
697 	if (mdecoder->gst_caps == NULL)
698 	{
699 		WLog_ERR(TAG, "tsmf_gstreamer_set_format not called or invalid format.");
700 		return FALSE;
701 	}
702 
703 	if (!mdecoder->pipe)
704 		tsmf_gstreamer_pipeline_build(mdecoder);
705 
706 	if (!mdecoder->src)
707 	{
708 		WLog_ERR(
709 		    TAG,
710 		    "failed to construct pipeline correctly. Unable to push buffer to source element.");
711 		return FALSE;
712 	}
713 
714 	gst_buf = tsmf_get_buffer_from_data(data, data_size);
715 
716 	if (gst_buf == NULL)
717 	{
718 		WLog_ERR(TAG, "tsmf_get_buffer_from_data(%p, %" PRIu32 ") failed.", (void*)data, data_size);
719 		return FALSE;
720 	}
721 
722 	/* Relative timestamping will sometimes be set to 0
723 	 * so we ignore these timestamps just to be safe(bit 8)
724 	 */
725 	if (extensions & 0x00000080)
726 	{
727 		DEBUG_TSMF("Ignoring the timestamps - relative - bit 8");
728 		useTimestamps = FALSE;
729 	}
730 
731 	/* If no timestamps exist then we dont want to look at the timestamp values (bit 7) */
732 	if (extensions & 0x00000040)
733 	{
734 		DEBUG_TSMF("Ignoring the timestamps - none - bit 7");
735 		useTimestamps = FALSE;
736 	}
737 
738 	/* If performing a seek */
739 	if (mdecoder->seeking)
740 	{
741 		mdecoder->seeking = FALSE;
742 		tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PAUSED);
743 		mdecoder->pipeline_start_time_valid = 0;
744 	}
745 
746 	if (mdecoder->pipeline_start_time_valid)
747 	{
748 		DEBUG_TSMF("%s start time %" PRIu64 "", get_type(mdecoder), start_time);
749 
750 		/* Adjusted the condition for a seek to be based on start time only
751 		 * WMV1 and WMV2 files in particular have bad end time and duration values
752 		 * there seems to be no real side effects of just using the start time instead
753 		 */
754 		UINT64 minTime = mdecoder->last_sample_start_time - (UINT64)SEEK_TOLERANCE;
755 		UINT64 maxTime = mdecoder->last_sample_start_time + (UINT64)SEEK_TOLERANCE;
756 
757 		/* Make sure the minTime stops at 0 , should we be at the beginning of the stream */
758 		if (mdecoder->last_sample_start_time < (UINT64)SEEK_TOLERANCE)
759 			minTime = 0;
760 
761 		/* If the start_time is valid and different from the previous start time by more than the
762 		 * seek tolerance, then we have a seek condition */
763 		if (((start_time > maxTime) || (start_time < minTime)) && useTimestamps)
764 		{
765 			DEBUG_TSMF("tsmf_gstreamer_decodeEx: start_time=[%" PRIu64
766 			           "] > last_sample_start_time=[%" PRIu64 "] OR ",
767 			           start_time, mdecoder->last_sample_start_time);
768 			DEBUG_TSMF("tsmf_gstreamer_decodeEx: start_time=[%" PRIu64
769 			           "] < last_sample_start_time=[%" PRIu64 "] with",
770 			           start_time, mdecoder->last_sample_start_time);
771 			DEBUG_TSMF(
772 			    "tsmf_gstreamer_decodeEX: a tolerance of more than [%lu] from the last sample",
773 			    SEEK_TOLERANCE);
774 			DEBUG_TSMF("tsmf_gstreamer_decodeEX: minTime=[%" PRIu64 "] maxTime=[%" PRIu64 "]",
775 			           minTime, maxTime);
776 
777 			mdecoder->seeking = TRUE;
778 
779 			/* since we cant make the gstreamer pipeline jump to the new start time after a seek -
780 			 * we just maintain a offset between realtime and gstreamer time
781 			 */
782 			mdecoder->seek_offset = start_time;
783 		}
784 	}
785 	else
786 	{
787 		DEBUG_TSMF("%s start time %" PRIu64 "", get_type(mdecoder), start_time);
788 		/* Always set base/start time to 0. Will use seek offset to translate real buffer times
789 		 * back to 0. This allows the video to be started from anywhere and the ability to handle
790 		 * seeks without rebuilding the pipeline, etc. since that is costly
791 		 */
792 		gst_element_set_base_time(mdecoder->pipe, tsmf_gstreamer_timestamp_ms_to_gst(0));
793 		gst_element_set_start_time(mdecoder->pipe, tsmf_gstreamer_timestamp_ms_to_gst(0));
794 		mdecoder->pipeline_start_time_valid = 1;
795 
796 		/* Set the seek offset if buffer has valid timestamps. */
797 		if (useTimestamps)
798 			mdecoder->seek_offset = start_time;
799 
800 		if (!gst_element_seek(mdecoder->pipe, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
801 		                      GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
802 		{
803 			WLog_ERR(TAG, "seek failed");
804 		}
805 	}
806 
807 #if GST_VERSION_MAJOR > 0
808 	if (useTimestamps)
809 		GST_BUFFER_PTS(gst_buf) =
810 		    sample_time - tsmf_gstreamer_timestamp_ms_to_gst(mdecoder->seek_offset);
811 	else
812 		GST_BUFFER_PTS(gst_buf) = GST_CLOCK_TIME_NONE;
813 #else
814 	if (useTimestamps)
815 		GST_BUFFER_TIMESTAMP(gst_buf) =
816 		    sample_time - tsmf_gstreamer_timestamp_ms_to_gst(mdecoder->seek_offset);
817 	else
818 		GST_BUFFER_TIMESTAMP(gst_buf) = GST_CLOCK_TIME_NONE;
819 #endif
820 	GST_BUFFER_DURATION(gst_buf) = GST_CLOCK_TIME_NONE;
821 	GST_BUFFER_OFFSET(gst_buf) = GST_BUFFER_OFFSET_NONE;
822 #if GST_VERSION_MAJOR > 0
823 #else
824 	gst_buffer_set_caps(gst_buf, mdecoder->gst_caps);
825 #endif
826 	gst_app_src_push_buffer(GST_APP_SRC(mdecoder->src), gst_buf);
827 
828 	/* Should only update the last timestamps if the current ones are valid */
829 	if (useTimestamps)
830 	{
831 		mdecoder->last_sample_start_time = start_time;
832 		mdecoder->last_sample_end_time = end_time;
833 	}
834 
835 	if (mdecoder->pipe && (GST_STATE(mdecoder->pipe) != GST_STATE_PLAYING))
836 	{
837 		DEBUG_TSMF("%s: state=%s", get_type(mdecoder),
838 		           gst_element_state_get_name(GST_STATE(mdecoder->pipe)));
839 
840 		DEBUG_TSMF("%s Paused: %" PRIi32 "   Shutdown: %i   Ready: %" PRIi32 "", get_type(mdecoder),
841 		           mdecoder->paused, mdecoder->shutdown, mdecoder->ready);
842 		if (!mdecoder->paused && !mdecoder->shutdown && mdecoder->ready)
843 			tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING);
844 	}
845 
846 	return TRUE;
847 }
848 
tsmf_gstreamer_control(ITSMFDecoder * decoder,ITSMFControlMsg control_msg,UINT32 * arg)849 static BOOL tsmf_gstreamer_control(ITSMFDecoder* decoder, ITSMFControlMsg control_msg, UINT32* arg)
850 {
851 	TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder;
852 
853 	if (!mdecoder)
854 	{
855 		WLog_ERR(TAG, "Control called with no decoder!");
856 		return TRUE;
857 	}
858 
859 	if (control_msg == Control_Pause)
860 	{
861 		DEBUG_TSMF("Control_Pause %s", get_type(mdecoder));
862 
863 		if (mdecoder->paused)
864 		{
865 			WLog_ERR(TAG, "%s: Ignoring Control_Pause, already received!", get_type(mdecoder));
866 			return TRUE;
867 		}
868 
869 		tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PAUSED);
870 		mdecoder->shutdown = 0;
871 		mdecoder->paused = TRUE;
872 	}
873 	else if (control_msg == Control_Resume)
874 	{
875 		DEBUG_TSMF("Control_Resume %s", get_type(mdecoder));
876 
877 		if (!mdecoder->paused && !mdecoder->shutdown)
878 		{
879 			WLog_ERR(TAG, "%s: Ignoring Control_Resume, already received!", get_type(mdecoder));
880 			return TRUE;
881 		}
882 
883 		mdecoder->shutdown = 0;
884 		mdecoder->paused = FALSE;
885 	}
886 	else if (control_msg == Control_Stop)
887 	{
888 		DEBUG_TSMF("Control_Stop %s", get_type(mdecoder));
889 
890 		if (mdecoder->shutdown)
891 		{
892 			WLog_ERR(TAG, "%s: Ignoring Control_Stop, already received!", get_type(mdecoder));
893 			return TRUE;
894 		}
895 
896 		/* Reset stamps, flush buffers, etc */
897 		if (mdecoder->pipe)
898 		{
899 			tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_NULL);
900 			tsmf_window_destroy(mdecoder);
901 			tsmf_gstreamer_clean_up(mdecoder);
902 		}
903 		mdecoder->seek_offset = 0;
904 		mdecoder->pipeline_start_time_valid = 0;
905 		mdecoder->shutdown = 1;
906 	}
907 	else if (control_msg == Control_Restart)
908 	{
909 		DEBUG_TSMF("Control_Restart %s", get_type(mdecoder));
910 		mdecoder->shutdown = 0;
911 		mdecoder->paused = FALSE;
912 
913 		if (mdecoder->pipeline_start_time_valid)
914 			tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING);
915 	}
916 	else
917 		WLog_ERR(TAG, "Unknown control message %08x", control_msg);
918 
919 	return TRUE;
920 }
921 
tsmf_gstreamer_buffer_level(ITSMFDecoder * decoder)922 static BOOL tsmf_gstreamer_buffer_level(ITSMFDecoder* decoder)
923 {
924 	TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder;
925 	DEBUG_TSMF("");
926 
927 	if (!mdecoder)
928 		return FALSE;
929 
930 	guint clbuff = 0;
931 
932 	if (G_IS_OBJECT(mdecoder->queue))
933 		g_object_get(mdecoder->queue, "current-level-buffers", &clbuff, NULL);
934 
935 	DEBUG_TSMF("%s buffer level %u", get_type(mdecoder), clbuff);
936 	return clbuff;
937 }
938 
tsmf_gstreamer_free(ITSMFDecoder * decoder)939 static void tsmf_gstreamer_free(ITSMFDecoder* decoder)
940 {
941 	TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder;
942 	DEBUG_TSMF("%s", get_type(mdecoder));
943 
944 	if (mdecoder)
945 	{
946 		tsmf_window_destroy(mdecoder);
947 		tsmf_gstreamer_clean_up(mdecoder);
948 
949 		if (mdecoder->gst_caps)
950 			gst_caps_unref(mdecoder->gst_caps);
951 
952 		tsmf_platform_free(mdecoder);
953 		ZeroMemory(mdecoder, sizeof(TSMFGstreamerDecoder));
954 		free(mdecoder);
955 		mdecoder = NULL;
956 	}
957 }
958 
tsmf_gstreamer_get_running_time(ITSMFDecoder * decoder)959 static UINT64 tsmf_gstreamer_get_running_time(ITSMFDecoder* decoder)
960 {
961 	TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder;
962 
963 	if (!mdecoder)
964 		return 0;
965 
966 	if (!mdecoder->outsink)
967 		return mdecoder->last_sample_start_time;
968 
969 	if (!mdecoder->pipe)
970 		return 0;
971 
972 	GstFormat fmt = GST_FORMAT_TIME;
973 	gint64 pos = 0;
974 #if GST_VERSION_MAJOR > 0
975 	gst_element_query_position(mdecoder->pipe, fmt, &pos);
976 #else
977 	gst_element_query_position(mdecoder->pipe, &fmt, &pos);
978 #endif
979 	return (UINT64)(pos / 100 + mdecoder->seek_offset);
980 }
981 
tsmf_gstreamer_update_rendering_area(ITSMFDecoder * decoder,int newX,int newY,int newWidth,int newHeight,int numRectangles,RDP_RECT * rectangles)982 static BOOL tsmf_gstreamer_update_rendering_area(ITSMFDecoder* decoder, int newX, int newY,
983                                                  int newWidth, int newHeight, int numRectangles,
984                                                  RDP_RECT* rectangles)
985 {
986 	TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder;
987 	DEBUG_TSMF("x=%d, y=%d, w=%d, h=%d, rect=%d", newX, newY, newWidth, newHeight, numRectangles);
988 
989 	if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
990 	{
991 		return tsmf_window_resize(mdecoder, newX, newY, newWidth, newHeight, numRectangles,
992 		                          rectangles) == 0;
993 	}
994 
995 	return TRUE;
996 }
997 
tsmf_gstreamer_ack(ITSMFDecoder * decoder,BOOL (* cb)(void *,BOOL),void * stream)998 static BOOL tsmf_gstreamer_ack(ITSMFDecoder* decoder, BOOL (*cb)(void*, BOOL), void* stream)
999 {
1000 	TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder;
1001 	DEBUG_TSMF("");
1002 	mdecoder->ack_cb = NULL;
1003 	mdecoder->stream = stream;
1004 	return TRUE;
1005 }
1006 
tsmf_gstreamer_sync(ITSMFDecoder * decoder,void (* cb)(void *),void * stream)1007 static BOOL tsmf_gstreamer_sync(ITSMFDecoder* decoder, void (*cb)(void*), void* stream)
1008 {
1009 	TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder;
1010 	DEBUG_TSMF("");
1011 	mdecoder->sync_cb = NULL;
1012 	mdecoder->stream = stream;
1013 	return TRUE;
1014 }
1015 
1016 #ifdef BUILTIN_CHANNELS
1017 #define freerdp_tsmf_client_subsystem_entry gstreamer_freerdp_tsmf_client_decoder_subsystem_entry
1018 #else
1019 #define freerdp_tsmf_client_subsystem_entry FREERDP_API freerdp_tsmf_client_decoder_subsystem_entry
1020 #endif
1021 
freerdp_tsmf_client_subsystem_entry(void)1022 ITSMFDecoder* freerdp_tsmf_client_subsystem_entry(void)
1023 {
1024 	TSMFGstreamerDecoder* decoder;
1025 
1026 #if GST_CHECK_VERSION(0, 10, 31)
1027 	if (!gst_is_initialized())
1028 	{
1029 		gst_init(NULL, NULL);
1030 	}
1031 #else
1032 	gst_init(NULL, NULL);
1033 #endif
1034 
1035 	decoder = calloc(1, sizeof(TSMFGstreamerDecoder));
1036 
1037 	if (!decoder)
1038 		return NULL;
1039 
1040 	decoder->iface.SetFormat = tsmf_gstreamer_set_format;
1041 	decoder->iface.Decode = NULL;
1042 	decoder->iface.GetDecodedData = NULL;
1043 	decoder->iface.GetDecodedFormat = NULL;
1044 	decoder->iface.GetDecodedDimension = NULL;
1045 	decoder->iface.GetRunningTime = tsmf_gstreamer_get_running_time;
1046 	decoder->iface.UpdateRenderingArea = tsmf_gstreamer_update_rendering_area;
1047 	decoder->iface.Free = tsmf_gstreamer_free;
1048 	decoder->iface.Control = tsmf_gstreamer_control;
1049 	decoder->iface.DecodeEx = tsmf_gstreamer_decodeEx;
1050 	decoder->iface.ChangeVolume = tsmf_gstreamer_change_volume;
1051 	decoder->iface.BufferLevel = tsmf_gstreamer_buffer_level;
1052 	decoder->iface.SetAckFunc = tsmf_gstreamer_ack;
1053 	decoder->iface.SetSyncFunc = tsmf_gstreamer_sync;
1054 	decoder->paused = FALSE;
1055 	decoder->gstVolume = 0.5;
1056 	decoder->gstMuted = FALSE;
1057 	decoder->state = GST_STATE_VOID_PENDING; /* No real state yet */
1058 	decoder->last_sample_start_time = 0;
1059 	decoder->last_sample_end_time = 0;
1060 	decoder->seek_offset = 0;
1061 	decoder->seeking = FALSE;
1062 
1063 	if (tsmf_platform_create(decoder) < 0)
1064 	{
1065 		free(decoder);
1066 		return NULL;
1067 	}
1068 
1069 	return (ITSMFDecoder*)decoder;
1070 }
1071