22#include <freerdp/config.h>
24#include <winpr/assert.h>
32#include <winpr/string.h>
33#include <winpr/platform.h>
37#include <gst/app/gstappsrc.h>
38#include <gst/app/gstappsink.h>
40#include "tsmf_constants.h"
41#include "tsmf_decoder.h"
42#include "tsmf_platform.h"
45#define SEEK_TOLERANCE 10 * 1000 * 1000
50 GstState desired_state);
51static BOOL tsmf_gstreamer_buffer_level(ITSMFDecoder* decoder);
58 switch (mdecoder->media_type)
60 case TSMF_MAJOR_TYPE_VIDEO:
62 case TSMF_MAJOR_TYPE_AUDIO:
69static void cb_child_added(GstChildProxy* child_proxy, GObject*
object,
72 DEBUG_TSMF(
"NAME: %s", G_OBJECT_TYPE_NAME(
object));
74 if (!g_strcmp0(G_OBJECT_TYPE_NAME(
object),
"GstXvImageSink") ||
75 !g_strcmp0(G_OBJECT_TYPE_NAME(
object),
"GstXImageSink") ||
76 !g_strcmp0(G_OBJECT_TYPE_NAME(
object),
"GstFluVAAutoSink"))
78 gst_base_sink_set_max_lateness((GstBaseSink*)
object, 10000000);
79 g_object_set(G_OBJECT(
object),
"sync", TRUE,
nullptr);
80 g_object_set(G_OBJECT(
object),
"async", TRUE,
nullptr);
83 else if (!g_strcmp0(G_OBJECT_TYPE_NAME(
object),
"GstAlsaSink") ||
84 !g_strcmp0(G_OBJECT_TYPE_NAME(
object),
"GstPulseSink"))
86 gst_base_sink_set_max_lateness((GstBaseSink*)
object, 10000000);
87 g_object_set(G_OBJECT(
object),
"slave-method", 1,
nullptr);
88 g_object_set(G_OBJECT(
object),
"buffer-time", (gint64)20000,
nullptr);
89 g_object_set(G_OBJECT(
object),
"drift-tolerance", (gint64)20000,
91 g_object_set(G_OBJECT(
object),
"latency-time", (gint64)10000,
nullptr);
92 g_object_set(G_OBJECT(
object),
"sync", TRUE,
nullptr);
93 g_object_set(G_OBJECT(
object),
"async", TRUE,
nullptr);
97static void tsmf_gstreamer_enough_data(GstAppSrc* src, gpointer user_data)
101 DEBUG_TSMF(
"%s", get_type(mdecoder));
104static void tsmf_gstreamer_need_data(GstAppSrc* src, guint length, gpointer user_data)
108 DEBUG_TSMF(
"%s length=%u", get_type(mdecoder), length);
111static gboolean tsmf_gstreamer_seek_data(GstAppSrc* src, guint64 offset, gpointer user_data)
115 DEBUG_TSMF(
"%s offset=%" PRIu64
"", get_type(mdecoder), offset);
120static BOOL tsmf_gstreamer_change_volume(ITSMFDecoder* decoder, UINT32 newVolume, UINT32 muted)
124 if (!mdecoder || !mdecoder->pipe)
127 if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
130 mdecoder->gstMuted = (BOOL)muted;
131 DEBUG_TSMF(
"mute=[%" PRId32
"]", mdecoder->gstMuted);
132 mdecoder->gstVolume = (double)newVolume / (
double)10000;
133 DEBUG_TSMF(
"gst_new_vol=[%f]", mdecoder->gstVolume);
135 if (!mdecoder->volume)
138 if (!G_IS_OBJECT(mdecoder->volume))
141 g_object_set(mdecoder->volume,
"mute", mdecoder->gstMuted,
nullptr);
142 g_object_set(mdecoder->volume,
"volume", mdecoder->gstVolume,
nullptr);
147static inline GstClockTime tsmf_gstreamer_timestamp_ms_to_gst(UINT64 ms_timestamp)
152 return (GstClockTime)(ms_timestamp * 100);
157 GstStateChangeReturn state_change;
159 const char* sname = get_type(mdecoder);
168 if (desired_state == mdecoder->state)
171 name = gst_element_state_get_name(desired_state);
172 DEBUG_TSMF(
"%s to %s", sname, name);
173 state_change = gst_element_set_state(mdecoder->pipe, desired_state);
175 if (state_change == GST_STATE_CHANGE_FAILURE)
177 WLog_ERR(TAG,
"%s: (%s) GST_STATE_CHANGE_FAILURE.", sname, name);
179 else if (state_change == GST_STATE_CHANGE_ASYNC)
181 WLog_ERR(TAG,
"%s: (%s) GST_STATE_CHANGE_ASYNC.", sname, name);
182 mdecoder->state = desired_state;
186 mdecoder->state = desired_state;
192static GstBuffer* tsmf_get_buffer_from_data(
const void* raw_data, gsize size)
203 data = g_malloc(size);
207 WLog_ERR(TAG,
"Could not allocate %" G_GSIZE_FORMAT
" bytes of data.", size);
211 CopyMemory(data, raw_data, size);
213#if GST_VERSION_MAJOR > 0
214 buffer = gst_buffer_new_wrapped(data, size);
216 buffer = gst_buffer_new();
220 WLog_ERR(TAG,
"Could not create GstBuffer");
225 GST_BUFFER_MALLOCDATA(buffer) = data;
226 GST_BUFFER_SIZE(buffer) = size;
227 GST_BUFFER_DATA(buffer) = GST_BUFFER_MALLOCDATA(buffer);
233static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder,
TS_AM_MEDIA_TYPE* media_type)
242 switch (media_type->MajorType)
244 case TSMF_MAJOR_TYPE_VIDEO:
245 mdecoder->media_type = TSMF_MAJOR_TYPE_VIDEO;
247 case TSMF_MAJOR_TYPE_AUDIO:
248 mdecoder->media_type = TSMF_MAJOR_TYPE_AUDIO;
254 switch (media_type->SubType)
256 case TSMF_SUB_TYPE_WVC1:
257 mdecoder->gst_caps = gst_caps_new_simple(
258 "video/x-wmv",
"bitrate", G_TYPE_UINT, media_type->BitRate,
"width", G_TYPE_INT,
259 media_type->Width,
"height", G_TYPE_INT, media_type->Height,
"wmvversion",
261#
if GST_VERSION_MAJOR > 0
262 "format", G_TYPE_STRING,
"WVC1",
264 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC(
'W',
'V',
'C',
'1'),
266 "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator,
267 media_type->SamplesPerSecond.Denominator,
"pixel-aspect-ratio", GST_TYPE_FRACTION,
270 case TSMF_SUB_TYPE_MP4S:
271 mdecoder->gst_caps = gst_caps_new_simple(
272 "video/x-divx",
"divxversion", G_TYPE_INT, 5,
"bitrate", G_TYPE_UINT,
273 media_type->BitRate,
"width", G_TYPE_INT, media_type->Width,
"height", G_TYPE_INT,
275#
if GST_VERSION_MAJOR > 0
276 "format", G_TYPE_STRING,
"MP42",
278 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC(
'M',
'P',
'4',
'2'),
280 "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator,
281 media_type->SamplesPerSecond.Denominator,
nullptr);
283 case TSMF_SUB_TYPE_MP42:
284 mdecoder->gst_caps = gst_caps_new_simple(
285 "video/x-msmpeg",
"msmpegversion", G_TYPE_INT, 42,
"bitrate", G_TYPE_UINT,
286 media_type->BitRate,
"width", G_TYPE_INT, media_type->Width,
"height", G_TYPE_INT,
288#
if GST_VERSION_MAJOR > 0
289 "format", G_TYPE_STRING,
"MP42",
291 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC(
'M',
'P',
'4',
'2'),
293 "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator,
294 media_type->SamplesPerSecond.Denominator,
nullptr);
296 case TSMF_SUB_TYPE_MP43:
297 mdecoder->gst_caps = gst_caps_new_simple(
298 "video/x-msmpeg",
"msmpegversion", G_TYPE_INT, 43,
"bitrate", G_TYPE_UINT,
299 media_type->BitRate,
"width", G_TYPE_INT, media_type->Width,
"height", G_TYPE_INT,
301#
if GST_VERSION_MAJOR > 0
302 "format", G_TYPE_STRING,
"MP43",
304 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC(
'M',
'P',
'4',
'3'),
306 "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator,
307 media_type->SamplesPerSecond.Denominator,
nullptr);
309 case TSMF_SUB_TYPE_M4S2:
310 mdecoder->gst_caps = gst_caps_new_simple(
311 "video/mpeg",
"mpegversion", G_TYPE_INT, 4,
"width", G_TYPE_INT, media_type->Width,
312 "height", G_TYPE_INT, media_type->Height,
313#
if GST_VERSION_MAJOR > 0
314 "format", G_TYPE_STRING,
"M4S2",
316 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC(
'M',
'4',
'S',
'2'),
318 "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator,
319 media_type->SamplesPerSecond.Denominator,
nullptr);
321 case TSMF_SUB_TYPE_WMA9:
322 mdecoder->gst_caps = gst_caps_new_simple(
323 "audio/x-wma",
"wmaversion", G_TYPE_INT, 3,
"rate", G_TYPE_INT,
324 media_type->SamplesPerSecond.Numerator,
"channels", G_TYPE_INT,
325 media_type->Channels,
"bitrate", G_TYPE_INT, media_type->BitRate,
"depth",
326 G_TYPE_INT, media_type->BitsPerSample,
"width", G_TYPE_INT,
327 media_type->BitsPerSample,
"block_align", G_TYPE_INT, media_type->BlockAlign,
330 case TSMF_SUB_TYPE_WMA1:
331 mdecoder->gst_caps = gst_caps_new_simple(
332 "audio/x-wma",
"wmaversion", G_TYPE_INT, 1,
"rate", G_TYPE_INT,
333 media_type->SamplesPerSecond.Numerator,
"channels", G_TYPE_INT,
334 media_type->Channels,
"bitrate", G_TYPE_INT, media_type->BitRate,
"depth",
335 G_TYPE_INT, media_type->BitsPerSample,
"width", G_TYPE_INT,
336 media_type->BitsPerSample,
"block_align", G_TYPE_INT, media_type->BlockAlign,
339 case TSMF_SUB_TYPE_WMA2:
340 mdecoder->gst_caps = gst_caps_new_simple(
341 "audio/x-wma",
"wmaversion", G_TYPE_INT, 2,
"rate", G_TYPE_INT,
342 media_type->SamplesPerSecond.Numerator,
"channels", G_TYPE_INT,
343 media_type->Channels,
"bitrate", G_TYPE_INT, media_type->BitRate,
"depth",
344 G_TYPE_INT, media_type->BitsPerSample,
"width", G_TYPE_INT,
345 media_type->BitsPerSample,
"block_align", G_TYPE_INT, media_type->BlockAlign,
348 case TSMF_SUB_TYPE_MP3:
350 gst_caps_new_simple(
"audio/mpeg",
"mpegversion", G_TYPE_INT, 1,
"layer", G_TYPE_INT,
351 3,
"rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator,
352 "channels", G_TYPE_INT, media_type->Channels,
nullptr);
354 case TSMF_SUB_TYPE_WMV1:
355 mdecoder->gst_caps = gst_caps_new_simple(
356 "video/x-wmv",
"bitrate", G_TYPE_UINT, media_type->BitRate,
"width", G_TYPE_INT,
357 media_type->Width,
"height", G_TYPE_INT, media_type->Height,
"wmvversion",
359#
if GST_VERSION_MAJOR > 0
360 "format", G_TYPE_STRING,
"WMV1",
362 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC(
'W',
'M',
'V',
'1'),
364 "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator,
365 media_type->SamplesPerSecond.Denominator,
nullptr);
367 case TSMF_SUB_TYPE_WMV2:
368 mdecoder->gst_caps = gst_caps_new_simple(
369 "video/x-wmv",
"width", G_TYPE_INT, media_type->Width,
"height", G_TYPE_INT,
370 media_type->Height,
"wmvversion", G_TYPE_INT, 2,
371#
if GST_VERSION_MAJOR > 0
372 "format", G_TYPE_STRING,
"WMV2",
374 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC(
'W',
'M',
'V',
'2'),
376 "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator,
377 media_type->SamplesPerSecond.Denominator,
"pixel-aspect-ratio", GST_TYPE_FRACTION,
380 case TSMF_SUB_TYPE_WMV3:
381 mdecoder->gst_caps = gst_caps_new_simple(
382 "video/x-wmv",
"bitrate", G_TYPE_UINT, media_type->BitRate,
"width", G_TYPE_INT,
383 media_type->Width,
"height", G_TYPE_INT, media_type->Height,
"wmvversion",
385#
if GST_VERSION_MAJOR > 0
386 "format", G_TYPE_STRING,
"WMV3",
388 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC(
'W',
'M',
'V',
'3'),
390 "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator,
391 media_type->SamplesPerSecond.Denominator,
"pixel-aspect-ratio", GST_TYPE_FRACTION,
394 case TSMF_SUB_TYPE_AVC1:
395 case TSMF_SUB_TYPE_H264:
396 mdecoder->gst_caps = gst_caps_new_simple(
397 "video/x-h264",
"width", G_TYPE_INT, media_type->Width,
"height", G_TYPE_INT,
398 media_type->Height,
"framerate", GST_TYPE_FRACTION,
399 media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator,
400 "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
"stream-format", G_TYPE_STRING,
401 "byte-stream",
"alignment", G_TYPE_STRING,
"nal",
nullptr);
403 case TSMF_SUB_TYPE_AC3:
404 mdecoder->gst_caps = gst_caps_new_simple(
405 "audio/x-ac3",
"rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator,
406 "channels", G_TYPE_INT, media_type->Channels,
nullptr);
408 case TSMF_SUB_TYPE_AAC:
413 if (media_type->ExtraData)
415 if (media_type->ExtraDataSize < 12)
417 media_type->ExtraData += 12;
418 media_type->ExtraDataSize -= 12;
421 mdecoder->gst_caps = gst_caps_new_simple(
422 "audio/mpeg",
"rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator,
423 "channels", G_TYPE_INT, media_type->Channels,
"mpegversion", G_TYPE_INT, 4,
424 "framed", G_TYPE_BOOLEAN, TRUE,
"stream-format", G_TYPE_STRING,
"raw",
nullptr);
426 case TSMF_SUB_TYPE_MP1A:
428 gst_caps_new_simple(
"audio/mpeg",
"mpegversion", G_TYPE_INT, 1,
"channels",
429 G_TYPE_INT, media_type->Channels,
nullptr);
431 case TSMF_SUB_TYPE_MP1V:
433 gst_caps_new_simple(
"video/mpeg",
"mpegversion", G_TYPE_INT, 1,
"width", G_TYPE_INT,
434 media_type->Width,
"height", G_TYPE_INT, media_type->Height,
435 "systemstream", G_TYPE_BOOLEAN, FALSE,
nullptr);
437 case TSMF_SUB_TYPE_YUY2:
438#if GST_VERSION_MAJOR > 0
439 mdecoder->gst_caps = gst_caps_new_simple(
440 "video/x-raw",
"format", G_TYPE_STRING,
"YUY2",
"width", G_TYPE_INT,
441 media_type->Width,
"height", G_TYPE_INT, media_type->Height,
nullptr);
443 mdecoder->gst_caps = gst_caps_new_simple(
444 "video/x-raw-yuv",
"format", G_TYPE_STRING,
"YUY2",
"width", G_TYPE_INT,
445 media_type->Width,
"height", G_TYPE_INT, media_type->Height,
"framerate",
446 GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator,
447 media_type->SamplesPerSecond.Denominator,
nullptr);
450 case TSMF_SUB_TYPE_MP2V:
452 gst_caps_new_simple(
"video/mpeg",
"mpegversion", G_TYPE_INT, 2,
"systemstream",
453 G_TYPE_BOOLEAN, FALSE,
nullptr);
455 case TSMF_SUB_TYPE_MP2A:
457 gst_caps_new_simple(
"audio/mpeg",
"mpegversion", G_TYPE_INT, 1,
"rate", G_TYPE_INT,
458 media_type->SamplesPerSecond.Numerator,
"channels", G_TYPE_INT,
459 media_type->Channels,
nullptr);
461 case TSMF_SUB_TYPE_FLAC:
462 mdecoder->gst_caps = gst_caps_new_simple(
"audio/x-flac",
"",
nullptr);
465 WLog_ERR(TAG,
"unknown format:(%d).", media_type->SubType);
469 if (media_type->ExtraDataSize > 0)
472 DEBUG_TSMF(
"Extra data available (%" PRIu32
")", media_type->ExtraDataSize);
473 buffer = tsmf_get_buffer_from_data(media_type->ExtraData, media_type->ExtraDataSize);
477 WLog_ERR(TAG,
"could not allocate GstBuffer!");
481 gst_caps_set_simple(mdecoder->gst_caps,
"codec_data", GST_TYPE_BUFFER, buffer,
nullptr);
484 DEBUG_TSMF(
"%p format '%s'", (
void*)mdecoder, gst_caps_to_string(mdecoder->gst_caps));
485 tsmf_platform_set_format(mdecoder);
488 if (!tsmf_gstreamer_pipeline_build(mdecoder))
496 if (!mdecoder || !mdecoder->pipe)
499 if (mdecoder->pipe && GST_OBJECT_REFCOUNT_VALUE(mdecoder->pipe) > 0)
501 tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_NULL);
502 gst_object_unref(mdecoder->pipe);
505 mdecoder->ready = FALSE;
506 mdecoder->paused = FALSE;
508 mdecoder->pipe =
nullptr;
509 mdecoder->src =
nullptr;
510 mdecoder->queue =
nullptr;
515#if GST_VERSION_MAJOR > 0
517 "appsrc name=videosource ! queue2 name=videoqueue ! decodebin name=videodecoder !";
519 "appsrc name=audiosource ! queue2 name=audioqueue ! decodebin name=audiodecoder ! "
520 "audioconvert ! audiorate ! audioresample ! volume name=audiovolume !";
523 "appsrc name=videosource ! queue2 name=videoqueue ! decodebin2 name=videodecoder !";
525 "appsrc name=audiosource ! queue2 name=audioqueue ! decodebin2 name=audiodecoder ! "
526 "audioconvert ! audiorate ! audioresample ! volume name=audiovolume !";
536 if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
538 if (sprintf_s(pipeline,
sizeof(pipeline),
"%s %s name=videosink", video,
539 tsmf_platform_get_video_sink()) < 0)
544 if (sprintf_s(pipeline,
sizeof(pipeline),
"%s %s name=audiosink", audio,
545 tsmf_platform_get_audio_sink()) < 0)
549 DEBUG_TSMF(
"pipeline=%s", pipeline);
550 mdecoder->pipe = gst_parse_launch(pipeline,
nullptr);
554 WLog_ERR(TAG,
"Failed to create new pipe");
558 if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
559 mdecoder->src = gst_bin_get_by_name(GST_BIN(mdecoder->pipe),
"videosource");
561 mdecoder->src = gst_bin_get_by_name(GST_BIN(mdecoder->pipe),
"audiosource");
565 WLog_ERR(TAG,
"Failed to get appsrc");
569 if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
570 mdecoder->queue = gst_bin_get_by_name(GST_BIN(mdecoder->pipe),
"videoqueue");
572 mdecoder->queue = gst_bin_get_by_name(GST_BIN(mdecoder->pipe),
"audioqueue");
574 if (!mdecoder->queue)
576 WLog_ERR(TAG,
"Failed to get queue");
580 if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
581 mdecoder->outsink = gst_bin_get_by_name(GST_BIN(mdecoder->pipe),
"videosink");
583 mdecoder->outsink = gst_bin_get_by_name(GST_BIN(mdecoder->pipe),
"audiosink");
585 if (!mdecoder->outsink)
587 WLog_ERR(TAG,
"Failed to get sink");
591 g_signal_connect(mdecoder->outsink,
"child-added", G_CALLBACK(cb_child_added), mdecoder);
593 if (mdecoder->media_type == TSMF_MAJOR_TYPE_AUDIO)
595 mdecoder->volume = gst_bin_get_by_name(GST_BIN(mdecoder->pipe),
"audiovolume");
597 if (!mdecoder->volume)
599 WLog_ERR(TAG,
"Failed to get volume");
603 tsmf_gstreamer_change_volume((ITSMFDecoder*)mdecoder, mdecoder->gstVolume * ((
double)10000),
607 tsmf_platform_register_handler(mdecoder);
609 GstAppSrcCallbacks callbacks = {
610 tsmf_gstreamer_need_data, tsmf_gstreamer_enough_data, tsmf_gstreamer_seek_data, {
nullptr }
612 g_object_set(mdecoder->src,
"format", GST_FORMAT_TIME,
nullptr);
613 g_object_set(mdecoder->src,
"is-live", FALSE,
nullptr);
614 g_object_set(mdecoder->src,
"block", FALSE,
nullptr);
615 g_object_set(mdecoder->src,
"blocksize", 1024,
nullptr);
616 gst_app_src_set_caps((GstAppSrc*)mdecoder->src, mdecoder->gst_caps);
617 gst_app_src_set_callbacks((GstAppSrc*)mdecoder->src, &callbacks, mdecoder,
nullptr);
618 gst_app_src_set_stream_type((GstAppSrc*)mdecoder->src, GST_APP_STREAM_TYPE_SEEKABLE);
619 gst_app_src_set_latency((GstAppSrc*)mdecoder->src, 0, -1);
620 gst_app_src_set_max_bytes((GstAppSrc*)mdecoder->src, (guint64)0);
621 g_object_set(G_OBJECT(mdecoder->queue),
"use-buffering", FALSE,
nullptr);
622 g_object_set(G_OBJECT(mdecoder->queue),
"use-rate-estimate", FALSE,
nullptr);
623 g_object_set(G_OBJECT(mdecoder->queue),
"max-size-buffers", 0,
nullptr);
624 g_object_set(G_OBJECT(mdecoder->queue),
"max-size-bytes", 0,
nullptr);
625 g_object_set(G_OBJECT(mdecoder->queue),
"max-size-time", (guint64)0,
nullptr);
629 if (!g_strcmp0(G_OBJECT_TYPE_NAME(mdecoder->outsink),
"GstAutoVideoSink") &&
630 !g_strcmp0(G_OBJECT_TYPE_NAME(mdecoder->outsink),
"GstAutoAudioSink"))
632 if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
634 gst_base_sink_set_max_lateness((GstBaseSink*)mdecoder->outsink,
639 gst_base_sink_set_max_lateness((GstBaseSink*)mdecoder->outsink,
641 g_object_set(G_OBJECT(mdecoder->outsink),
"buffer-time", (gint64)20000,
643 g_object_set(G_OBJECT(mdecoder->outsink),
"drift-tolerance", (gint64)20000,
645 g_object_set(G_OBJECT(mdecoder->outsink),
"latency-time", (gint64)10000,
647 g_object_set(G_OBJECT(mdecoder->outsink),
"slave-method", 1,
nullptr);
649 g_object_set(G_OBJECT(mdecoder->outsink),
"sync", TRUE,
651 g_object_set(G_OBJECT(mdecoder->outsink),
"async", TRUE,
655 tsmf_window_create(mdecoder);
656 tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_READY);
657 tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING);
658 mdecoder->pipeline_start_time_valid = 0;
659 mdecoder->shutdown = 0;
660 mdecoder->paused = FALSE;
662 GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(mdecoder->pipe), GST_DEBUG_GRAPH_SHOW_ALL,
668static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder,
const BYTE* data, UINT32 data_size,
669 UINT32 extensions, UINT64 start_time, UINT64 end_time,
674 UINT64 sample_time = tsmf_gstreamer_timestamp_ms_to_gst(start_time);
675 BOOL useTimestamps = TRUE;
679 WLog_ERR(TAG,
"Decoder not initialized!");
690 "%s. Start:(%" PRIu64
") End:(%" PRIu64
") Duration:(%" PRIu64
") Last Start:(%" PRIu64
")",
691 get_type(mdecoder), start_time, end_time, duration, mdecoder->last_sample_start_time);
693 if (mdecoder->shutdown)
695 WLog_ERR(TAG,
"decodeEx called on shutdown decoder");
699 if (mdecoder->gst_caps ==
nullptr)
701 WLog_ERR(TAG,
"tsmf_gstreamer_set_format not called or invalid format.");
706 tsmf_gstreamer_pipeline_build(mdecoder);
712 "failed to construct pipeline correctly. Unable to push buffer to source element.");
716 gst_buf = tsmf_get_buffer_from_data(data, data_size);
718 if (gst_buf ==
nullptr)
720 WLog_ERR(TAG,
"tsmf_get_buffer_from_data(%p, %" PRIu32
") failed.", (
void*)data, data_size);
727 if (extensions & 0x00000080)
729 DEBUG_TSMF(
"Ignoring the timestamps - relative - bit 8");
730 useTimestamps = FALSE;
734 if (extensions & 0x00000040)
736 DEBUG_TSMF(
"Ignoring the timestamps - none - bit 7");
737 useTimestamps = FALSE;
741 if (mdecoder->seeking)
743 mdecoder->seeking = FALSE;
744 tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PAUSED);
745 mdecoder->pipeline_start_time_valid = 0;
748 if (mdecoder->pipeline_start_time_valid)
750 DEBUG_TSMF(
"%s start time %" PRIu64
"", get_type(mdecoder), start_time);
756 UINT64 minTime = mdecoder->last_sample_start_time - (UINT64)SEEK_TOLERANCE;
757 UINT64 maxTime = mdecoder->last_sample_start_time + (UINT64)SEEK_TOLERANCE;
760 if (mdecoder->last_sample_start_time < (UINT64)SEEK_TOLERANCE)
765 if (((start_time > maxTime) || (start_time < minTime)) && useTimestamps)
767 DEBUG_TSMF(
"tsmf_gstreamer_decodeEx: start_time=[%" PRIu64
768 "] > last_sample_start_time=[%" PRIu64
"] OR ",
769 start_time, mdecoder->last_sample_start_time);
770 DEBUG_TSMF(
"tsmf_gstreamer_decodeEx: start_time=[%" PRIu64
771 "] < last_sample_start_time=[%" PRIu64
"] with",
772 start_time, mdecoder->last_sample_start_time);
774 "tsmf_gstreamer_decodeEX: a tolerance of more than [%lu] from the last sample",
776 DEBUG_TSMF(
"tsmf_gstreamer_decodeEX: minTime=[%" PRIu64
"] maxTime=[%" PRIu64
"]",
779 mdecoder->seeking = TRUE;
784 mdecoder->seek_offset = start_time;
789 DEBUG_TSMF(
"%s start time %" PRIu64
"", get_type(mdecoder), start_time);
794 gst_element_set_base_time(mdecoder->pipe, tsmf_gstreamer_timestamp_ms_to_gst(0));
795 gst_element_set_start_time(mdecoder->pipe, tsmf_gstreamer_timestamp_ms_to_gst(0));
796 mdecoder->pipeline_start_time_valid = 1;
800 mdecoder->seek_offset = start_time;
802 if (!gst_element_seek(mdecoder->pipe, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
803 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
805 WLog_ERR(TAG,
"seek failed");
809#if GST_VERSION_MAJOR > 0
811 GST_BUFFER_PTS(gst_buf) =
812 sample_time - tsmf_gstreamer_timestamp_ms_to_gst(mdecoder->seek_offset);
814 GST_BUFFER_PTS(gst_buf) = GST_CLOCK_TIME_NONE;
817 GST_BUFFER_TIMESTAMP(gst_buf) =
818 sample_time - tsmf_gstreamer_timestamp_ms_to_gst(mdecoder->seek_offset);
820 GST_BUFFER_TIMESTAMP(gst_buf) = GST_CLOCK_TIME_NONE;
822 GST_BUFFER_DURATION(gst_buf) = GST_CLOCK_TIME_NONE;
823 GST_BUFFER_OFFSET(gst_buf) = GST_BUFFER_OFFSET_NONE;
824#if GST_VERSION_MAJOR > 0
826 gst_buffer_set_caps(gst_buf, mdecoder->gst_caps);
828 gst_app_src_push_buffer(GST_APP_SRC(mdecoder->src), gst_buf);
833 mdecoder->last_sample_start_time = start_time;
834 mdecoder->last_sample_end_time = end_time;
837 if (mdecoder->pipe && (GST_STATE(mdecoder->pipe) != GST_STATE_PLAYING))
839 DEBUG_TSMF(
"%s: state=%s", get_type(mdecoder),
840 gst_element_state_get_name(GST_STATE(mdecoder->pipe)));
842 DEBUG_TSMF(
"%s Paused: %" PRIi32
" Shutdown: %i Ready: %" PRIi32
"", get_type(mdecoder),
843 mdecoder->paused, mdecoder->shutdown, mdecoder->ready);
844 if (!mdecoder->paused && !mdecoder->shutdown && mdecoder->ready)
845 tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING);
851static BOOL tsmf_gstreamer_control(ITSMFDecoder* decoder, ITSMFControlMsg control_msg, UINT32* arg)
857 WLog_ERR(TAG,
"Control called with no decoder!");
861 if (control_msg == Control_Pause)
863 DEBUG_TSMF(
"Control_Pause %s", get_type(mdecoder));
865 if (mdecoder->paused)
867 WLog_ERR(TAG,
"%s: Ignoring Control_Pause, already received!", get_type(mdecoder));
871 tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PAUSED);
872 mdecoder->shutdown = 0;
873 mdecoder->paused = TRUE;
875 else if (control_msg == Control_Resume)
877 DEBUG_TSMF(
"Control_Resume %s", get_type(mdecoder));
879 if (!mdecoder->paused && !mdecoder->shutdown)
881 WLog_ERR(TAG,
"%s: Ignoring Control_Resume, already received!", get_type(mdecoder));
885 mdecoder->shutdown = 0;
886 mdecoder->paused = FALSE;
888 else if (control_msg == Control_Stop)
890 DEBUG_TSMF(
"Control_Stop %s", get_type(mdecoder));
892 if (mdecoder->shutdown)
894 WLog_ERR(TAG,
"%s: Ignoring Control_Stop, already received!", get_type(mdecoder));
901 tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_NULL);
902 tsmf_window_destroy(mdecoder);
903 tsmf_gstreamer_clean_up(mdecoder);
905 mdecoder->seek_offset = 0;
906 mdecoder->pipeline_start_time_valid = 0;
907 mdecoder->shutdown = 1;
909 else if (control_msg == Control_Restart)
911 DEBUG_TSMF(
"Control_Restart %s", get_type(mdecoder));
912 mdecoder->shutdown = 0;
913 mdecoder->paused = FALSE;
915 if (mdecoder->pipeline_start_time_valid)
916 tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING);
919 WLog_ERR(TAG,
"Unknown control message %08x", control_msg);
924static BOOL tsmf_gstreamer_buffer_level(ITSMFDecoder* decoder)
934 if (G_IS_OBJECT(mdecoder->queue))
935 g_object_get(mdecoder->queue,
"current-level-buffers", &clbuff,
nullptr);
937 DEBUG_TSMF(
"%s buffer level %u", get_type(mdecoder), clbuff);
941static void tsmf_gstreamer_free(ITSMFDecoder* decoder)
944 DEBUG_TSMF(
"%s", get_type(mdecoder));
948 tsmf_window_destroy(mdecoder);
949 tsmf_gstreamer_clean_up(mdecoder);
951 if (mdecoder->gst_caps)
952 gst_caps_unref(mdecoder->gst_caps);
954 tsmf_platform_free(mdecoder);
961static UINT64 tsmf_gstreamer_get_running_time(ITSMFDecoder* decoder)
968 if (!mdecoder->outsink)
969 return mdecoder->last_sample_start_time;
974 GstFormat fmt = GST_FORMAT_TIME;
976#if GST_VERSION_MAJOR > 0
977 gst_element_query_position(mdecoder->pipe, fmt, &pos);
979 gst_element_query_position(mdecoder->pipe, &fmt, &pos);
981 return (UINT64)(pos / 100 + mdecoder->seek_offset);
984static BOOL tsmf_gstreamer_update_rendering_area(ITSMFDecoder* decoder,
int newX,
int newY,
985 int newWidth,
int newHeight,
int numRectangles,
989 DEBUG_TSMF(
"x=%d, y=%d, w=%d, h=%d, rect=%d", newX, newY, newWidth, newHeight, numRectangles);
991 if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
993 return tsmf_window_resize(mdecoder, newX, newY, newWidth, newHeight, numRectangles,
1000static BOOL tsmf_gstreamer_ack(ITSMFDecoder* decoder, BOOL (*cb)(
void*, BOOL),
void* stream)
1004 mdecoder->ack_cb =
nullptr;
1005 mdecoder->stream = stream;
1009static BOOL tsmf_gstreamer_sync(ITSMFDecoder* decoder,
void (*cb)(
void*),
void* stream)
1013 mdecoder->sync_cb =
nullptr;
1014 mdecoder->stream = stream;
1018FREERDP_ENTRY_POINT(UINT VCAPITYPE gstreamer_freerdp_tsmf_client_decoder_subsystem_entry(
void* ptr))
1020 ITSMFDecoder** sptr = (ITSMFDecoder**)ptr;
1024#if GST_CHECK_VERSION(0, 10, 31)
1025 if (!gst_is_initialized())
1027 gst_init(
nullptr,
nullptr);
1030 gst_init(
nullptr,
nullptr);
1037 return ERROR_OUTOFMEMORY;
1039 decoder->iface.SetFormat = tsmf_gstreamer_set_format;
1040 decoder->iface.Decode =
nullptr;
1041 decoder->iface.GetDecodedData =
nullptr;
1042 decoder->iface.GetDecodedFormat =
nullptr;
1043 decoder->iface.GetDecodedDimension =
nullptr;
1044 decoder->iface.GetRunningTime = tsmf_gstreamer_get_running_time;
1045 decoder->iface.UpdateRenderingArea = tsmf_gstreamer_update_rendering_area;
1046 decoder->iface.Free = tsmf_gstreamer_free;
1047 decoder->iface.Control = tsmf_gstreamer_control;
1048 decoder->iface.DecodeEx = tsmf_gstreamer_decodeEx;
1049 decoder->iface.ChangeVolume = tsmf_gstreamer_change_volume;
1050 decoder->iface.BufferLevel = tsmf_gstreamer_buffer_level;
1051 decoder->iface.SetAckFunc = tsmf_gstreamer_ack;
1052 decoder->iface.SetSyncFunc = tsmf_gstreamer_sync;
1053 decoder->paused = FALSE;
1054 decoder->gstVolume = 0.5;
1055 decoder->gstMuted = FALSE;
1056 decoder->state = GST_STATE_VOID_PENDING;
1057 decoder->last_sample_start_time = 0;
1058 decoder->last_sample_end_time = 0;
1059 decoder->seek_offset = 0;
1060 decoder->seeking = FALSE;
1062 if (tsmf_platform_create(decoder) < 0)
1065 return ERROR_INTERNAL_ERROR;
1068 *sptr = &decoder->iface;
1069 return CHANNEL_RC_OK;