RDK Documentation (Open Sourced RDK Components)
aampgstplayer.cpp
Go to the documentation of this file.
1 /*
2  * If not stated otherwise in this file or this component's license file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2018 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18 */
19 
20 /**
21  * @file aampgstplayer.cpp
22  * @brief Gstreamer based player impl for AAMP
23  */
24 
25 #include "AampMemoryUtils.h"
26 #include "aampgstplayer.h"
27 #include "AampFnLogger.h"
28 #include "isobmffbuffer.h"
29 #include "AampUtils.h"
30 #include "AampGstUtils.h"
31 #include <gst/gst.h>
32 #include <gst/app/gstappsrc.h>
33 #include <gst/app/gstappsink.h>
34 #include <string.h>
35 #include <assert.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include "priv_aamp.h"
39 #include <pthread.h>
40 #include <atomic>
41 
42 #ifdef __APPLE__
43  #include "gst/video/videooverlay.h"
44  guintptr (*gCbgetWindowContentView)() = NULL;
45 #endif
46 
47 #ifdef AAMP_MPD_DRM
48 #include "aampoutputprotection.h"
49 #endif
50 
51 /**
52  * @enum GstPlayFlags
53  * @brief Enum of configuration flags used by playbin
54  */
55 typedef enum {
56  GST_PLAY_FLAG_VIDEO = (1 << 0), /**< value is 0x001 */
57  GST_PLAY_FLAG_AUDIO = (1 << 1), /**< value is 0x002 */
58  GST_PLAY_FLAG_TEXT = (1 << 2), /**< value is 0x004 */
59  GST_PLAY_FLAG_VIS = (1 << 3), /**< value is 0x008 */
60  GST_PLAY_FLAG_SOFT_VOLUME = (1 << 4), /**< value is 0x010 */
61  GST_PLAY_FLAG_NATIVE_AUDIO = (1 << 5), /**< value is 0x020 */
62  GST_PLAY_FLAG_NATIVE_VIDEO = (1 << 6), /**< value is 0x040 */
63  GST_PLAY_FLAG_DOWNLOAD = (1 << 7), /**< value is 0x080 */
64  GST_PLAY_FLAG_BUFFERING = (1 << 8), /**< value is 0x100 */
65  GST_PLAY_FLAG_DEINTERLACE = (1 << 9), /**< value is 0x200 */
66  GST_PLAY_FLAG_SOFT_COLORBALANCE = (1 << 10) /**< value is 0x400 */
67 } GstPlayFlags;
68 
69 //#define SUPPORT_MULTI_AUDIO
70 #define GST_ELEMENT_GET_STATE_RETRY_CNT_MAX 5
71 
72 /*Playersinkbin events*/
73 #define GSTPLAYERSINKBIN_EVENT_HAVE_VIDEO 0x01
74 #define GSTPLAYERSINKBIN_EVENT_HAVE_AUDIO 0x02
75 #define GSTPLAYERSINKBIN_EVENT_FIRST_VIDEO_FRAME 0x03
76 #define GSTPLAYERSINKBIN_EVENT_FIRST_AUDIO_FRAME 0x04
77 #define GSTPLAYERSINKBIN_EVENT_ERROR_VIDEO_UNDERFLOW 0x06
78 #define GSTPLAYERSINKBIN_EVENT_ERROR_AUDIO_UNDERFLOW 0x07
79 #define GSTPLAYERSINKBIN_EVENT_ERROR_VIDEO_PTS 0x08
80 #define GSTPLAYERSINKBIN_EVENT_ERROR_AUDIO_PTS 0x09
81 
82 #ifdef INTELCE
83 #define INPUT_GAIN_DB_MUTE (gdouble)-145
84 #define INPUT_GAIN_DB_UNMUTE (gdouble)0
85 #endif
86 #define DEFAULT_BUFFERING_TO_MS 10 /**< TimeOut interval to check buffer fullness */
87 #if defined(REALTEKCE)
88 #define DEFAULT_BUFFERING_QUEUED_FRAMES_MIN (3) /**< if the video decoder has this many queued frames start.. */
89 #define DEFAULT_AVSYNC_FREERUN_THRESHOLD_SECS 12 /**< Currently MAX FRAG DURATION + 2 per Realtek */
90 #else
91 #define DEFAULT_BUFFERING_QUEUED_FRAMES_MIN (5) /**< if the video decoder has this many queued frames start.. even at 60fps, close to 100ms... */
92 #endif
93 
94 #define DEFAULT_BUFFERING_MAX_MS (1000) /**< max buffering time */
95 #define DEFAULT_BUFFERING_MAX_CNT (DEFAULT_BUFFERING_MAX_MS/DEFAULT_BUFFERING_TO_MS) /**< max buffering timeout count */
96 #define AAMP_MIN_PTS_UPDATE_INTERVAL 4000 /**< Time duration in milliseconds if exceeded and pts has not changed; it is concluded pts is not changing */
97 #define AAMP_DELAY_BETWEEN_PTS_CHECK_FOR_EOS_ON_UNDERFLOW 500 /**< A timeout interval in milliseconds to check pts in case of underflow */
98 #define BUFFERING_TIMEOUT_PRIORITY -70 /**< 0 is DEFAULT priority whereas -100 is the HIGH_PRIORITY */
99 #define AAMP_MIN_DECODE_ERROR_INTERVAL 10000 /**< Minimum time interval in milliseconds between two decoder error CB to send anomaly error */
100 #define VIDEO_COORDINATES_SIZE 32
101 
102 /**
103  * @name gmapDecoderLoookUptable
104  *
105  * @brief Decoder map list lookup table
106  * convert from codec to string map list of gstreamer
107  * component.
108  */
109 static std::map <std::string, std::vector<std::string>> gmapDecoderLoookUptable =
110 {
111  {"ac-3", {"omxac3dec", "avdec_ac3", "avdec_ac3_fixed"}},
112  {"ac-4", {"omxac4dec"}}
113 };
114 
115 /**
116  * @struct media_stream
117  * @brief Holds stream(Audio, Video, Subtitle and Aux-Audio) specific variables.
118  */
120 {
121  GstElement *sinkbin; /**< Sink element to consume data */
122  GstElement *source; /**< to provide data to the pipleline */
123  StreamOutputFormat format; /**< Stream output format for this stream */
124  gboolean using_playersinkbin; /**< Set to TRUE if stream type is MPEG transport stream. Playersink consists of demux, decoder and sink elements */
125  bool flush; /**< used to flush the pipleline */
126  bool resetPosition; /**< To indicate that the position of the stream is reset */
127  bool bufferUnderrun;
128  bool eosReached; /**< To indicate the status of End of Stream reached */
129  bool sourceConfigured; /**< To indicate that the current source is initialised and configured */
130  pthread_mutex_t sourceLock;
131  uint32_t timeScale;
132  int32_t trackId; /**< Current Audio Track Id,so far it is implimented for AC4 track selection only */
133 
134  media_stream() : sinkbin(NULL), source(NULL), format(FORMAT_INVALID),
135  using_playersinkbin(FALSE), flush(false), resetPosition(false),
136  bufferUnderrun(false), eosReached(false), sourceConfigured(false), sourceLock(PTHREAD_MUTEX_INITIALIZER)
137  , timeScale(1), trackId(-1)
138  {
139 
140  }
141 };
142 
143 /**
144  * @struct AAMPGstPlayerPriv
145  * @brief Holds private variables of AAMPGstPlayer
146  */
148 {
149  AAMPGstPlayerPriv(const AAMPGstPlayerPriv&) = delete;
150  AAMPGstPlayerPriv& operator=(const AAMPGstPlayerPriv&) = delete;
151 
153  GstElement *pipeline; /**< GstPipeline used for playback. */
154  GstBus *bus; /**< Bus for receiving GstEvents from pipeline. */
155  int current_rate;
156  guint64 total_bytes;
157  gint n_audio; /**< Number of audio tracks. */
158  gint current_audio; /**< Offset of current audio track. */
159  std::mutex TaskControlMutex; /**< For scheduling/de-scheduling or resetting async tasks/variables and timers */
160  TaskControlData firstProgressCallbackIdleTask;
161  guint periodicProgressCallbackIdleTaskId; /**< ID of timed handler created for notifying progress events. */
162  guint bufferingTimeoutTimerId; /**< ID of timer handler created for buffering timeout. */
163  GstElement *video_dec; /**< Video decoder used by pipeline. */
164  GstElement *audio_dec; /**< Audio decoder used by pipeline. */
165  GstElement *video_sink; /**< Video sink used by pipeline. */
166  GstElement *audio_sink; /**< Audio sink used by pipeline. */
167  GstElement *subtitle_sink; /**< Subtitle sink used by pipeline. */
168 #ifdef INTELCE_USE_VIDRENDSINK
169  GstElement *video_pproc; /**< Video element used by pipeline.(only for Intel). */
170 #endif
171 
172  int rate; /**< Current playback rate. */
173  double playbackrate; /**< playback rate in fractions */
174  VideoZoomMode zoom; /**< Video-zoom setting. */
175  bool videoMuted; /**< Video mute status. */
176  bool audioMuted; /**< Audio mute status. */
177  std::mutex volumeMuteMutex; /**< Mutex to ensure setVolumeOrMuteUnMute is thread-safe. */
178  bool subtitleMuted; /**< Subtitle mute status. */
179  double audioVolume; /**< Audio volume. */
180  guint eosCallbackIdleTaskId; /**< ID of idle handler created for notifying EOS event. */
181  std::atomic<bool> eosCallbackIdleTaskPending; /**< Set if any eos callback is pending. */
182  bool firstFrameReceived; /**< Flag that denotes if first frame was notified. */
183  char videoRectangle[VIDEO_COORDINATES_SIZE]; /**< Video-rectangle co-ordinates in format x,y,w,h. */
184  bool pendingPlayState; /**< Flag that denotes if set pipeline to PLAYING state is pending. */
185  bool decoderHandleNotified; /**< Flag that denotes if decoder handle was notified. */
186  guint firstFrameCallbackIdleTaskId; /**< ID of idle handler created for notifying first frame event. */
187  GstEvent *protectionEvent[AAMP_TRACK_COUNT]; /**< GstEvent holding the pssi data to be sent downstream. */
188  std::atomic<bool> firstFrameCallbackIdleTaskPending; /**< Set if any first frame callback is pending. */
189  bool using_westerossink; /**< true if westros sink is used as video sink */
190  guint busWatchId; /**< Id of the event source assigned to the message bus */
191  std::atomic<bool> eosSignalled; /**< Indicates if EOS has signaled */
192  gboolean buffering_enabled; /**< enable buffering based on multiqueue */
193  gboolean buffering_in_progress; /**< buffering is in progress */
194  guint buffering_timeout_cnt; /**< make sure buffering_timeout doesn't get stuck */
195  GstState buffering_target_state; /**< the target state after buffering */
196 #ifdef INTELCE
197  bool keepLastFrame; /**< Keep last frame over next pipeline delete/ create cycle */
198 #endif
199  gint64 lastKnownPTS; /**< To store the PTS of last displayed video */
200  long long ptsUpdatedTimeMS; /**< Timestamp when PTS was last updated */
201  guint ptsCheckForEosOnUnderflowIdleTaskId; /**< ID of task to ensure video PTS is not moving before notifying EOS on underflow. */
202  int numberOfVideoBuffersSent; /**< Number of video buffers sent to pipeline */
203  gint64 segmentStart; /**< segment start value; required when qtdemux is enabled and restamping is disabled */
204  GstQuery *positionQuery; /**< pointer that holds a position query object */
205  GstQuery *durationQuery; /**< pointer that holds a duration query object */
206  bool paused; /**< if pipeline is deliberately put in PAUSED state due to user interaction */
207  GstState pipelineState; /**< current state of pipeline */
208  guint firstVideoFrameDisplayedCallbackIdleTaskId; /**< ID of idle handler created for notifying state changed to Playing */
209  std::atomic<bool> firstVideoFrameDisplayedCallbackIdleTaskPending; /**< Set if any state changed to Playing callback is pending. */
210 #if defined(REALTEKCE)
211  bool firstTuneWithWesterosSinkOff; /**< DELIA-33640: track if first tune was done for Realtekce build */
212 #endif
213  long long decodeErrorMsgTimeMS; /**< Timestamp when decode error message last posted */
214  int decodeErrorCBCount; /**< Total decode error cb received within thresold time */
215  bool progressiveBufferingEnabled;
216  bool progressiveBufferingStatus;
217  bool forwardAudioBuffers; /**< flag denotes if audio buffers to be forwarded to aux pipeline */
218  bool enableSEITimeCode; /**< Enables SEI Time Code handling */
219  bool firstVideoFrameReceived; /**< flag that denotes if first video frame was notified. */
220  bool firstAudioFrameReceived; /**< flag that denotes if first audio frame was notified */
221  int NumberOfTracks; /**< Indicates the number of tracks */
222  AAMPGstPlayerPriv() : pipeline(NULL), bus(NULL), current_rate(0),
223  total_bytes(0), n_audio(0), current_audio(0),
224  periodicProgressCallbackIdleTaskId(AAMP_TASK_ID_INVALID),
225  bufferingTimeoutTimerId(AAMP_TASK_ID_INVALID), video_dec(NULL), audio_dec(NULL),TaskControlMutex(),firstProgressCallbackIdleTask("FirstProgressCallback"),
226  video_sink(NULL), audio_sink(NULL), subtitle_sink(NULL),
227 #ifdef INTELCE_USE_VIDRENDSINK
228  video_pproc(NULL),
229 #endif
230  rate(AAMP_NORMAL_PLAY_RATE), zoom(VIDEO_ZOOM_FULL), videoMuted(false), audioMuted(false), volumeMuteMutex(), subtitleMuted(false),
231  audioVolume(1.0), eosCallbackIdleTaskId(AAMP_TASK_ID_INVALID), eosCallbackIdleTaskPending(false),
234  using_westerossink(false), busWatchId(0), eosSignalled(false),
236  buffering_target_state(GST_STATE_NULL),
237  playbackrate(AAMP_NORMAL_PLAY_RATE),
238 #ifdef INTELCE
239  keepLastFrame(false),
240 #endif
243  paused(false), pipelineState(GST_STATE_NULL), firstVideoFrameDisplayedCallbackIdleTaskId(AAMP_TASK_ID_INVALID),
245 #if defined(REALTEKCE)
246  firstTuneWithWesterosSinkOff(false),
247 #endif
249  progressiveBufferingEnabled(false), progressiveBufferingStatus(false)
251  {
252  memset(videoRectangle, '\0', VIDEO_COORDINATES_SIZE);
253 #ifdef INTELCE
254  strcpy(videoRectangle, "0,0,0,0");
255 #else
256  /* DELIA-45366-default video scaling should take into account actual graphics
257  * resolution instead of assuming 1280x720.
258  * By default we where setting the resolution has 0,0,1280,720.
259  * For Full HD this default resolution will not scale to full size.
260  * So, we no need to set any default rectangle size here,
261  * since the video will display full screen, if a gstreamer pipeline is started
262  * using the westerossink connected using westeros compositor.
263  */
264  strcpy(videoRectangle, "");
265 #endif
266  for(int i = 0; i < AAMP_TRACK_COUNT; i++)
267  {
268  protectionEvent[i] = NULL;
269  }
270  }
271 
272 };
273 
274 static const char* GstPluginNamePR = "aampplayreadydecryptor";
275 static const char* GstPluginNameWV = "aampwidevinedecryptor";
276 static const char* GstPluginNameCK = "aampclearkeydecryptor";
277 static const char* GstPluginNameVMX = "aampverimatrixdecryptor";
278 
279 /**
280  * @brief Called from the mainloop when a message is available on the bus
281  * @param[in] bus the GstBus that sent the message
282  * @param[in] msg the GstMessage
283  * @param[in] _this pointer to AAMPGstPlayer instance
284  * @retval FALSE if the event source should be removed.
285  */
286 static gboolean bus_message(GstBus * bus, GstMessage * msg, AAMPGstPlayer * _this);
287 
288 /**
289  * @fn bus_sync_handler
290  * @brief Invoked synchronously when a message is available on the bus
291  * @param[in] bus the GstBus that sent the message
292  * @param[in] msg the GstMessage
293  * @param[in] _this pointer to AAMPGstPlayer instance
294  * @retval GST_BUS_PASS to pass the message to the async queue
295  */
296 static GstBusSyncReply bus_sync_handler(GstBus * bus, GstMessage * msg, AAMPGstPlayer * _this);
297 
298 /**
299  * @brief g_timeout callback to wait for buffering to change
300  * pipeline from paused->playing
301  */
302 static gboolean buffering_timeout (gpointer data);
303 
304 /**
305  * @brief check if elemement is instance (BCOM-3563)
306  */
307 static void type_check_instance( const char * str, GstElement * elem);
308 
309 /**
310  * @fn SetStateWithWarnings
311  * @brief wraps gst_element_set_state and adds log messages where applicable
312  * @param[in] element the GstElement whose state is to be changed
313  * @param[in] targetState the GstState to apply to element
314  * @param[in] _this pointer to AAMPGstPlayer instance
315  * @retval Result of the state change (from inner gst_element_set_state())
316  */
317 static GstStateChangeReturn SetStateWithWarnings(GstElement *element, GstState targetState);
318 
319 #define PLUGINS_TO_LOWER_RANK_MAX 2
321  "aacparse",
322  "ac3parse",
323 };
324 
325 /**
326  * @brief AAMPGstPlayer Constructor
327  */
329 #ifdef RENDER_FRAMES_IN_APP_CONTEXT
330  , std::function< void(uint8_t *, int, int, int) > exportFrames
331 #endif
332  ) : mLogObj(logObj), aamp(NULL) , privateContext(NULL), mBufferingLock(), mProtectionLock(), PipelineSetToReady(false), trickTeardown(false)
333 #ifdef RENDER_FRAMES_IN_APP_CONTEXT
334  , cbExportYUVFrame(NULL)
335 #endif
336 {
337  FN_TRACE( __FUNCTION__ );
338  privateContext = new AAMPGstPlayerPriv();
339  if(privateContext)
340  {
341  this->aamp = aamp;
342 
343  pthread_mutex_init(&mBufferingLock, NULL);
344  pthread_mutex_init(&mProtectionLock, NULL);
345  for (int i = 0; i < AAMP_TRACK_COUNT; i++)
346  pthread_mutex_init(&privateContext->stream[i].sourceLock, NULL);
347 
348 #ifdef RENDER_FRAMES_IN_APP_CONTEXT
349  this->cbExportYUVFrame = exportFrames;
350 #endif
351  CreatePipeline();
352  }
353  else
354  {
355  AAMPLOG_WARN("privateContext is null"); //CID:85372 - Null Returns
356  }
357 }
358 
359 /**
360  * @brief AAMPGstPlayer Destructor
361  */
363 {
364  FN_TRACE( __FUNCTION__ );
365  DestroyPipeline();
366  for (int i = 0; i < AAMP_TRACK_COUNT; i++)
367  pthread_mutex_destroy(&privateContext->stream[i].sourceLock);
368  SAFE_DELETE(privateContext);
369  pthread_mutex_destroy(&mBufferingLock);
370  pthread_mutex_destroy(&mProtectionLock);
371 }
372 
373 /**
374  * @brief IdleTaskAdd - add an async/idle task in a thread safe manner, assuming it is not queued
375  */
377 {
378  FN_TRACE( __FUNCTION__ );
379  bool ret = false;
380  std::lock_guard<std::mutex> lock(privateContext->TaskControlMutex);
381 
382  if (0 == taskDetails.taskID)
383  {
384  taskDetails.taskIsPending = false;
385  taskDetails.taskID = aamp->ScheduleAsyncTask(funcPtr, (void *)this);
386  // Wait for scheduler response , if failed to create task for wrong state , not to make pending flag as true
387  if(0 != taskDetails.taskID)
388  {
389  taskDetails.taskIsPending = true;
390  ret = true;
391  AAMPLOG_INFO("Task '%.50s' was added with ID = %d.", taskDetails.taskName.c_str(), taskDetails.taskID);
392  }
393  else
394  {
395  AAMPLOG_INFO("Task '%.50s' was not added or already ran.", taskDetails.taskName.c_str());
396  }
397  }
398  else
399  {
400  AAMPLOG_WARN("Task '%.50s' was already pending.", taskDetails.taskName.c_str());
401  }
402  return ret;
403 }
404 
405 /**
406  * @brief IdleTaskRemove - remove an async task in a thread safe manner, if it is queued
407  */
409 {
410  FN_TRACE( __FUNCTION__ );
411  bool ret = false;
412  std::lock_guard<std::mutex> lock(privateContext->TaskControlMutex);
413 
414  if (0 != taskDetails.taskID)
415  {
416  AAMPLOG_INFO("AAMPGstPlayer: Remove task <%.50s> with ID %d", taskDetails.taskName.c_str(), taskDetails.taskID);
417  aamp->RemoveAsyncTask(taskDetails.taskID);
418  taskDetails.taskID = 0;
419  ret = true;
420  }
421  else
422  {
423  AAMPLOG_TRACE("AAMPGstPlayer: Task already removed <%.50s>, with ID %d", taskDetails.taskName.c_str(), taskDetails.taskID);
424  }
425  taskDetails.taskIsPending = false;
426  return ret;
427 }
428 
429 /**
430  * @brief IdleTaskClearFlags - clear async task id and pending flag in a thread safe manner
431  * e.g. called when the task executes
432  */
434 {
435  FN_TRACE( __FUNCTION__ );
436  std::lock_guard<std::mutex> lock(privateContext->TaskControlMutex);
437  if ( 0 != taskDetails.taskID )
438  {
439  AAMPLOG_INFO("AAMPGstPlayer: Clear task control flags <%.50s> with ID %d", taskDetails.taskName.c_str(), taskDetails.taskID);
440  }
441  else
442  {
443  AAMPLOG_TRACE("AAMPGstPlayer: Task control flags were already cleared <%.50s> with ID %d", taskDetails.taskName.c_str(), taskDetails.taskID);
444  }
445  taskDetails.taskIsPending = false;
446  taskDetails.taskID = 0;
447 }
448 
449 /**
450  * @brief TimerAdd - add a new glib timer in thread safe manner
451  */
452 void AAMPGstPlayer::TimerAdd(GSourceFunc funcPtr, int repeatTimeout, guint& taskId, gpointer user_data, const char* timerName)
453 {
454  FN_TRACE( __FUNCTION__ );
455  std::lock_guard<std::mutex> lock(privateContext->TaskControlMutex);
456  if (funcPtr && user_data)
457  {
458  if (0 == taskId)
459  {
460  /* Sets the function pointed by functPtr to be called at regular intervals of repeatTimeout, supplying user_data to the function */
461  taskId = g_timeout_add(repeatTimeout, funcPtr, user_data);
462  AAMPLOG_INFO("AAMPGstPlayer: Added timer '%.50s', %d", (nullptr!=timerName) ? timerName : "unknown" , taskId);
463  }
464  else
465  {
466  AAMPLOG_INFO("AAMPGstPlayer: Timer '%.50s' already added, taskId=%d", (nullptr!=timerName) ? timerName : "unknown", taskId);
467  }
468  }
469  else
470  {
471  AAMPLOG_ERR("Bad pointer.");
472  }
473 }
474 
475 /**
476  * @brief TimerRemove - remove a glib timer in thread safe manner, if it exists
477  */
478 void AAMPGstPlayer::TimerRemove(guint& taskId, const char* timerName)
479 {
480  FN_TRACE( __FUNCTION__ );
481  std::lock_guard<std::mutex> lock(privateContext->TaskControlMutex);
482  if ( 0 != taskId )
483  {
484  AAMPLOG_INFO("AAMPGstPlayer: Remove timer '%.50s', %d", (nullptr!=timerName) ? timerName : "unknown", taskId);
485  g_source_remove(taskId); /* Removes the source as per the taskId */
486  taskId = 0;
487  }
488  else
489  {
490  AAMPLOG_TRACE("Timer '%.50s' with taskId = %d already removed.", (nullptr!=timerName) ? timerName : "unknown", taskId);
491  }
492 }
493 
494 /**
495  * @brief TimerIsRunning - Check whether timer is currently running
496  */
497 bool AAMPGstPlayer::TimerIsRunning(guint& taskId)
498 {
499  FN_TRACE( __FUNCTION__ );
500  std::lock_guard<std::mutex> lock(privateContext->TaskControlMutex);
501 
502  return (AAMP_TASK_ID_INVALID != taskId);
503 }
504 
505 /**
506  * @brief Analyze stream info from the GstPipeline
507  * @param[in] _this pointer to AAMPGstPlayer instance
508  */
509 static void analyze_streams(AAMPGstPlayer *_this)
510 {
511  FN_TRACE( __FUNCTION__ );
512 #ifdef SUPPORT_MULTI_AUDIO
513  GstElement *sinkbin = _this->privateContext->stream[eMEDIATYPE_VIDEO].sinkbin;
514 
515  g_object_get(sinkbin, "n-audio", &_this->privateContext->n_audio, NULL);
516  g_print("audio:\n");
517  for (gint i = 0; i < _this->privateContext->n_audio; i++)
518  {
519  GstTagList *tags = NULL;
520  g_signal_emit_by_name(sinkbin, "get-audio-tags", i, &tags);
521  if (tags)
522  {
523  gchar *str;
524  guint rate;
525 
526  g_print("audio stream %d:\n", i);
527  if (gst_tag_list_get_string(tags, GST_TAG_AUDIO_CODEC, &str)) {
528  g_print(" codec: %s\n", str);
529  g_free(str);
530  }
531  if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &str)) {
532  g_print(" language: %s\n", str);
533  g_free(str);
534  }
535  if (gst_tag_list_get_uint(tags, GST_TAG_BITRATE, &rate)) {
536  g_print(" bitrate: %d\n", rate);
537  }
538  gst_tag_list_free(tags);
539  }
540  }
541  g_object_get(sinkbin, "current-audio", &_this->privateContext->current_audio, NULL);
542 #endif
543 }
544 
545 
546 /**
547  * @brief Callback for appsrc "need-data" signal
548  * @param[in] source pointer to appsrc instance triggering "need-data" signal
549  * @param[in] size size of data required
550  * @param[in] _this pointer to AAMPGstPlayer instance associated with the playback
551  */
552 static void need_data(GstElement *source, guint size, AAMPGstPlayer * _this)
553 {
554  if (source == _this->privateContext->stream[eMEDIATYPE_SUBTITLE].source)
555  {
556  _this->aamp->ResumeTrackDownloads(eMEDIATYPE_SUBTITLE); // signal fragment downloader thread
557  }
558  else if (source == _this->privateContext->stream[eMEDIATYPE_AUDIO].source)
559  {
560  _this->aamp->ResumeTrackDownloads(eMEDIATYPE_AUDIO); // signal fragment downloader thread
561  }
562  else if (source == _this->privateContext->stream[eMEDIATYPE_AUX_AUDIO].source)
563  {
564  _this->aamp->ResumeTrackDownloads(eMEDIATYPE_AUX_AUDIO); // signal fragment downloader thread
565  }
566  else
567  {
568  _this->aamp->ResumeTrackDownloads(eMEDIATYPE_VIDEO); // signal fragment downloader thread
569  }
570 }
571 
572 
573 /**
574  * @brief Callback for appsrc "enough-data" signal
575  * @param[in] source pointer to appsrc instance triggering "enough-data" signal
576  * @param[in] _this pointer to AAMPGstPlayer instance associated with the playback
577  */
578 static void enough_data(GstElement *source, AAMPGstPlayer * _this)
579 {
580  if (_this->aamp->DownloadsAreEnabled()) // avoid processing enough data if the downloads are already disabled.
581  {
582  if (source == _this->privateContext->stream[eMEDIATYPE_SUBTITLE].source)
583  {
584  _this->aamp->StopTrackDownloads(eMEDIATYPE_SUBTITLE); // signal fragment downloader thread
585  }
586  else if (source == _this->privateContext->stream[eMEDIATYPE_AUDIO].source)
587  {
588  _this->aamp->StopTrackDownloads(eMEDIATYPE_AUDIO); // signal fragment downloader thread
589  }
590  else if (source == _this->privateContext->stream[eMEDIATYPE_AUX_AUDIO].source)
591  {
592  _this->aamp->StopTrackDownloads(eMEDIATYPE_AUX_AUDIO); // signal fragment downloader thread
593  }
594  else
595  {
596  _this->aamp->StopTrackDownloads(eMEDIATYPE_VIDEO); // signal fragment downloader thread
597  }
598  }
599 }
600 
601 
602 /**
603  * @brief Callback for appsrc "seek-data" signal
604  * @param[in] src pointer to appsrc instance triggering "seek-data" signal
605  * @param[in] offset seek position offset
606  * @param[in] _this pointer to AAMPGstPlayer instance associated with the playback
607  */
608 static gboolean appsrc_seek(GstAppSrc *src, guint64 offset, AAMPGstPlayer * _this)
609 {
610 #ifdef TRACE
611  AAMPLOG_WARN("appsrc %p seek-signal - offset %" G_GUINT64_FORMAT, src, offset);
612 #endif
613  return TRUE;
614 }
615 
616 
617 /**
618  * @brief Initialize properties/callback of appsrc
619  * @param[in] _this pointer to AAMPGstPlayer instance associated with the playback
620  * @param[in] source pointer to appsrc instance to be initialized
621  * @param[in] mediaType stream type
622  */
623 static void InitializeSource(AAMPGstPlayer *_this, GObject *source, MediaType mediaType = eMEDIATYPE_VIDEO)
624 {
625  media_stream *stream = &_this->privateContext->stream[mediaType];
626  GstCaps * caps = NULL;
627  g_signal_connect(source, "need-data", G_CALLBACK(need_data), _this); /* Sets up the call back function for need data event */
628  g_signal_connect(source, "enough-data", G_CALLBACK(enough_data), _this); /* Sets up the call back function for enough data event */
629  g_signal_connect(source, "seek-data", G_CALLBACK(appsrc_seek), _this); /* Sets up the call back function for seek data event */
630  gst_app_src_set_stream_type(GST_APP_SRC(source), GST_APP_STREAM_TYPE_SEEKABLE);
631  if (eMEDIATYPE_VIDEO == mediaType )
632  {
633  int MaxGstVideoBufBytes = 0;
634  _this->aamp->mConfig->GetConfigValue(eAAMPConfig_GstVideoBufBytes,MaxGstVideoBufBytes);
635  AAMPLOG_INFO("Setting gst Video buffer max bytes to %d", MaxGstVideoBufBytes);
636  g_object_set(source, "max-bytes", (guint64)MaxGstVideoBufBytes, NULL); /* Sets the maximum video buffer bytes as per configuration*/
637  }
638  else if (eMEDIATYPE_AUDIO == mediaType || eMEDIATYPE_AUX_AUDIO == mediaType)
639  {
640  int MaxGstAudioBufBytes = 0;
641  _this->aamp->mConfig->GetConfigValue(eAAMPConfig_GstAudioBufBytes,MaxGstAudioBufBytes);
642  AAMPLOG_INFO("Setting gst Audio buffer max bytes to %d", MaxGstAudioBufBytes);
643  g_object_set(source, "max-bytes", (guint64)MaxGstAudioBufBytes, NULL); /* Sets the maximum audio buffer bytes as per configuration*/
644  }
645  g_object_set(source, "min-percent", 50, NULL); /* Trigger the need data event when the queued bytes fall below 50% */
646  g_object_set(source, "format", GST_FORMAT_TIME, NULL); /* "format" can be used to perform seek or query/conversion operation*/
647  /* gstreamer.freedesktop.org recommends to use GST_FORMAT_TIME
648  'if you don't have a good reason to query for samples/frames' */
649  caps = GetGstCaps(stream->format);
650  if (caps != NULL)
651  {
652  gst_app_src_set_caps(GST_APP_SRC(source), caps);
653  gst_caps_unref(caps);
654  }
655  else
656  {
657  g_object_set(source, "typefind", TRUE, NULL); /* If capabilites can not be established, set typefind TRUE.
658  typefind determines the media-type of a stream and once type has been
659  detected it sets its src pad caps to the found media type*/
660  }
661  stream->sourceConfigured = true;
662 }
663 
664 
665 /**
666  * @brief Callback when source is added by playbin
667  * @param[in] object a GstObject
668  * @param[in] orig the object that originated the signal
669  * @param[in] pspec the property that changed
670  * @param[in] _this pointer to AAMPGstPlayer instance associated with the playback
671  */
672 static void found_source(GObject * object, GObject * orig, GParamSpec * pspec, AAMPGstPlayer * _this )
673 {
674  MediaType mediaType = eMEDIATYPE_DEFAULT;
675  if (object == G_OBJECT(_this->privateContext->stream[eMEDIATYPE_VIDEO].sinkbin))
676  {
677  AAMPLOG_WARN("Found source for video");
678  mediaType = eMEDIATYPE_VIDEO;
679  }
680  else if (object == G_OBJECT(_this->privateContext->stream[eMEDIATYPE_AUDIO].sinkbin))
681  {
682  AAMPLOG_WARN("Found source for audio");
683  mediaType = eMEDIATYPE_AUDIO;
684  }
685  else if (object == G_OBJECT(_this->privateContext->stream[eMEDIATYPE_AUX_AUDIO].sinkbin))
686  {
687  AAMPLOG_WARN("Found source for auxiliary audio");
688  mediaType = eMEDIATYPE_AUX_AUDIO;
689  }
690  else if (object == G_OBJECT(_this->privateContext->stream[eMEDIATYPE_SUBTITLE].sinkbin))
691  {
692  AAMPLOG_WARN("Found source for subtitle");
693  mediaType = eMEDIATYPE_SUBTITLE;
694  }
695  else
696  {
697  AAMPLOG_WARN("found_source didn't find a valid source");
698  }
699  if( mediaType != eMEDIATYPE_DEFAULT)
700  {
701  media_stream *stream;
702  stream = &_this->privateContext->stream[mediaType];
703  g_object_get(orig, pspec->name, &stream->source, NULL);
704  InitializeSource(_this, G_OBJECT(stream->source), mediaType);
705  }
706 }
707 
708 /**
709  * @brief callback when the source has been created
710  * @param[in] element is the pipeline
711  * @param[in] source the creation of source triggered this callback
712  * @param[in] data pointer to data associated with the playback
713  */
714 static void httpsoup_source_setup (GstElement * element, GstElement * source, gpointer data)
715 {
716  AAMPGstPlayer * _this = (AAMPGstPlayer *)data;
717 
718  if (!strcmp(GST_ELEMENT_NAME(source), "source"))
719  {
720  std::string networkProxyValue = _this->aamp->GetNetworkProxy(); /* Get the proxy network setting from configuration*/
721  if(!networkProxyValue.empty())
722  {
723  g_object_set(source, "proxy", networkProxyValue.c_str(), NULL);
724  AAMPLOG_WARN("httpsoup -> Set network proxy '%s'", networkProxyValue.c_str());
725  }
726  }
727 }
728 
729 
730 /**
731  * @brief Idle callback to notify first frame rendered event
732  * @param[in] user_data pointer to AAMPGstPlayer instance
733  * @retval G_SOURCE_REMOVE, if the source should be removed
734  */
735 static gboolean IdleCallbackOnFirstFrame(gpointer user_data)
736 {
737  AAMPGstPlayer *_this = (AAMPGstPlayer *)user_data;
738  if (_this)
739  {
740  _this->aamp->NotifyFirstFrameReceived();
741  _this->privateContext->firstFrameCallbackIdleTaskId = AAMP_TASK_ID_INVALID;
742  _this->privateContext->firstFrameCallbackIdleTaskPending = false;
743  }
744  return G_SOURCE_REMOVE;
745 }
746 
747 
748 /**
749  * @brief Idle callback to notify end-of-stream event
750  * @param[in] user_data pointer to AAMPGstPlayer instance
751  * @retval G_SOURCE_REMOVE, if the source should be removed
752  */
753 static gboolean IdleCallbackOnEOS(gpointer user_data)
754 {
755  AAMPGstPlayer *_this = (AAMPGstPlayer *)user_data;
756  if (_this)
757  {
758  AAMPLOG_WARN("eosCallbackIdleTaskId %d", _this->privateContext->eosCallbackIdleTaskId);
759  _this->aamp->NotifyEOSReached();
760  _this->privateContext->eosCallbackIdleTaskId = AAMP_TASK_ID_INVALID;
761  _this->privateContext->eosCallbackIdleTaskPending = false;
762  }
763  return G_SOURCE_REMOVE;
764 }
765 
766 
767 
768 /**
769  * @brief Timer's callback to notify playback progress event
770  * @param[in] user_data pointer to AAMPGstPlayer instance
771  * @retval G_SOURCE_CONTINUE, this function to be called periodically
772  */
773 static gboolean ProgressCallbackOnTimeout(gpointer user_data)
774 {
775  AAMPGstPlayer *_this = (AAMPGstPlayer *)user_data;
776  if (_this)
777  {
778  _this->aamp->ReportProgress();
779  AAMPLOG_TRACE("current %d, stored %d ", g_source_get_id(g_main_current_source()), _this->privateContext->periodicProgressCallbackIdleTaskId);
780  }
781  return G_SOURCE_CONTINUE;
782 }
783 
784 
785 /**
786  * @brief Idle callback to start progress notifier timer
787  * @param[in] user_data pointer to AAMPGstPlayer instance
788  * @retval G_SOURCE_REMOVE, if the source should be removed
789  */
790 static gboolean IdleCallback(gpointer user_data)
791 {
792  AAMPGstPlayer *_this = (AAMPGstPlayer *)user_data;
793  if (_this)
794  {
795  // mAsyncTuneEnabled passed, because this could be called from Scheduler or main loop
796  _this->aamp->ReportProgress();
797  _this->IdleTaskClearFlags(_this->privateContext->firstProgressCallbackIdleTask);
798 
799  if ( !(_this->TimerIsRunning(_this->privateContext->periodicProgressCallbackIdleTaskId)) )
800  {
801  double reportProgressInterval;
802  _this->aamp->mConfig->GetConfigValue(eAAMPConfig_ReportProgressInterval,reportProgressInterval);
803  reportProgressInterval *= 1000; //convert s to ms
804 
805  GSourceFunc timerFunc = ProgressCallbackOnTimeout;
806  _this->TimerAdd(timerFunc, (int)reportProgressInterval, _this->privateContext->periodicProgressCallbackIdleTaskId, user_data, "periodicProgressCallbackIdleTask");
807  AAMPLOG_WARN("current %d, periodicProgressCallbackIdleTaskId %d", g_source_get_id(g_main_current_source()), _this->privateContext->periodicProgressCallbackIdleTaskId);
808  }
809  else
810  {
811  AAMPLOG_INFO("Progress callback already available: periodicProgressCallbackIdleTaskId %d", _this->privateContext->periodicProgressCallbackIdleTaskId);
812  }
813  }
814  return G_SOURCE_REMOVE;
815 }
816 
817 /**
818  * @brief Idle callback to notify first video frame was displayed
819  * @param[in] user_data pointer to AAMPGstPlayer instance
820  * @retval G_SOURCE_REMOVE, if the source should be removed
821  */
822 static gboolean IdleCallbackFirstVideoFrameDisplayed(gpointer user_data)
823 {
824  AAMPGstPlayer *_this = (AAMPGstPlayer *)user_data;
825  if (_this)
826  {
827  _this->aamp->NotifyFirstVideoFrameDisplayed();
828  _this->privateContext->firstVideoFrameDisplayedCallbackIdleTaskPending = false;
829  _this->privateContext->firstVideoFrameDisplayedCallbackIdleTaskId = AAMP_TASK_ID_INVALID;
830  }
831  return G_SOURCE_REMOVE;
832 }
833 
834 /**
835  * @brief Notify first Audio and Video frame through an idle function to make the playersinkbin halding same as normal(playbin) playback.
836  */
838 {
839  FN_TRACE( __FUNCTION__ );
840  // RDK-34481 :LogTuneComplete will be noticed after getting video first frame.
841  // incase of audio or video only playback NumberofTracks =1, so in that case also LogTuneCompleted needs to captured when either audio/video frame received.
842  if (!privateContext->firstFrameReceived && (privateContext->firstVideoFrameReceived
843  || (1 == privateContext->NumberOfTracks && (privateContext->firstAudioFrameReceived || privateContext->firstVideoFrameReceived))))
844  {
845  privateContext->firstFrameReceived = true;
846  aamp->LogFirstFrame();
847  aamp->LogTuneComplete();
849  }
850 
851  if (eMEDIATYPE_VIDEO == type)
852  {
853  AAMPLOG_WARN("AAMPGstPlayer_OnFirstVideoFrameCallback. got First Video Frame");
854 
855  // DELIA-42262: No additional checks added here, since the NotifyFirstFrame will be invoked only once
856  // in westerossink disabled case until BCOM fixes it. Also aware of NotifyFirstBufferProcessed called
857  // twice in this function, since it updates timestamp for calculating time elapsed, its trivial
859 
860  if (!privateContext->decoderHandleNotified)
861  {
862  privateContext->decoderHandleNotified = true;
863  privateContext->firstFrameCallbackIdleTaskPending = false;
864  privateContext->firstFrameCallbackIdleTaskId = aamp->ScheduleAsyncTask(IdleCallbackOnFirstFrame, (void *)this, "FirstFrameCallback");
865  // Wait for scheduler response , if failed to create task for wrong state , not to make pending flag as true
866  if(privateContext->firstFrameCallbackIdleTaskId != AAMP_TASK_ID_INVALID)
867  {
868  privateContext->firstFrameCallbackIdleTaskPending = true;
869  }
870  }
871  else if (PipelineSetToReady)
872  {
873  //If pipeline is set to ready forcefully due to change in track_id, then re-initialize CC
874  aamp->InitializeCC();
875  }
876 
877  IdleTaskAdd(privateContext->firstProgressCallbackIdleTask, IdleCallback);
878 
881  {
882  privateContext->firstVideoFrameDisplayedCallbackIdleTaskPending = false;
884  aamp->ScheduleAsyncTask(IdleCallbackFirstVideoFrameDisplayed, (void *)this, "FirstVideoFrameDisplayedCallback");
885  if(privateContext->firstVideoFrameDisplayedCallbackIdleTaskId != AAMP_TASK_ID_INVALID)
886  {
888  }
889  }
890  PipelineSetToReady = false;
891  }
892  else if (eMEDIATYPE_AUDIO == type)
893  {
894  AAMPLOG_WARN("AAMPGstPlayer_OnAudioFirstFrameAudDecoder. got First Audio Frame");
895  if (aamp->mAudioOnlyPb)
896  {
897  if (!privateContext->decoderHandleNotified)
898  {
899  privateContext->decoderHandleNotified = true;
900  privateContext->firstFrameCallbackIdleTaskPending = false;
901  privateContext->firstFrameCallbackIdleTaskId = aamp->ScheduleAsyncTask(IdleCallbackOnFirstFrame, (void *)this, "FirstFrameCallback");
902  // Wait for scheduler response , if failed to create task for wrong state , not to make pending flag as true
903  if(privateContext->firstFrameCallbackIdleTaskId != AAMP_TASK_ID_INVALID)
904  {
905  privateContext->firstFrameCallbackIdleTaskPending = true;
906  }
907  }
908  IdleTaskAdd(privateContext->firstProgressCallbackIdleTask, IdleCallback);
909  }
910  }
911 
912 }
913 
914 /**
915  * @brief Callback invoked after first video frame decoded
916  * @param[in] object pointer to element raising the callback
917  * @param[in] arg0 number of arguments
918  * @param[in] arg1 array of arguments
919  * @param[in] _this pointer to AAMPGstPlayer instance
920  */
921 static void AAMPGstPlayer_OnFirstVideoFrameCallback(GstElement* object, guint arg0, gpointer arg1,
922  AAMPGstPlayer * _this)
923 
924 {
925  _this->privateContext->firstVideoFrameReceived = true;
927 
928 }
929 
930 /**
931  * @brief Callback invoked after receiving the SEI Time Code information
932  * @param[in] object pointer to element raising the callback
933  * @param[in] hours Hour value of the SEI Timecode
934  * @param[in] minutes Minute value of the SEI Timecode
935  * @param[in] seconds Second value of the SEI Timecode
936  * @param[in] user_data pointer to AAMPGstPlayer instance
937  */
938 static void AAMPGstPlayer_redButtonCallback(GstElement* object, guint hours, guint minutes, guint seconds, gpointer user_data)
939 {
940  AAMPGstPlayer *_this = (AAMPGstPlayer *)user_data;
941  if (_this)
942  {
943  char buffer[16];
944  snprintf(buffer,16,"%d:%d:%d",hours,minutes,seconds);
945  _this->aamp->seiTimecode.assign(buffer);
946  }
947 }
948 
949 /**
950  * @brief Callback invoked after first audio buffer decoded
951  * @param[in] object pointer to element raising the callback
952  * @param[in] arg0 number of arguments
953  * @param[in] arg1 array of arguments
954  * @param[in] _this pointer to AAMPGstPlayer instance
955  */
956 static void AAMPGstPlayer_OnAudioFirstFrameAudDecoder(GstElement* object, guint arg0, gpointer arg1,
957  AAMPGstPlayer * _this)
958 {
959  _this->privateContext->firstAudioFrameReceived = true;
961 }
962 
963 /**
964  * @brief Check if gstreamer element is video decoder
965  * @param[in] name Name of the element
966  * @param[in] _this pointer to AAMPGstPlayer instance
967  * @retval TRUE if element name is that of the decoder
968  */
969 bool AAMPGstPlayer_isVideoDecoder(const char* name, AAMPGstPlayer * _this)
970 {
971 #if defined (REALTEKCE)
972  return (aamp_StartsWith(name, "omxwmvdec") || aamp_StartsWith(name, "omxh26")
973  || aamp_StartsWith(name, "omxav1dec") || aamp_StartsWith(name, "omxvp") || aamp_StartsWith(name, "omxmpeg"));
974 #else
975  return (_this->privateContext->using_westerossink ? aamp_StartsWith(name, "westerossink"): aamp_StartsWith(name, "brcmvideodecoder"));
976 #endif
977 }
978 
979 /**
980  * @brief Check if gstreamer element is video sink
981  * @param[in] name Name of the element
982  * @param[in] _this pointer to AAMPGstPlayer instance
983  * @retval TRUE if element name is that of video sink
984  */
985 bool AAMPGstPlayer_isVideoSink(const char* name, AAMPGstPlayer * _this)
986 {
987 #if defined (REALTEKCE)
988  return (aamp_StartsWith(name, "westerossink") || aamp_StartsWith(name, "rtkv1sink"));
989 #else
990  return (!_this->privateContext->using_westerossink && aamp_StartsWith(name, "brcmvideosink") == true) || // brcmvideosink0, brcmvideosink1, ...
991  ( _this->privateContext->using_westerossink && aamp_StartsWith(name, "westerossink") == true);
992 #endif
993 }
994 
995 /**
996  * @brief Check if gstreamer element is audio sink or audio decoder
997  * @param[in] name Name of the element
998  * @param[in] _this pointer to AAMPGstPlayer instance
999  * @retval TRUE if element name is that of audio sink or audio decoder
1000  */
1002 {
1003 #if defined (REALTEKCE)
1004  return (aamp_StartsWith(name, "rtkaudiosink")
1005  || aamp_StartsWith(name, "alsasink")
1006  || aamp_StartsWith(name, "fakesink"));
1007 #else
1008  return (aamp_StartsWith(name, "brcmaudiodecoder") || aamp_StartsWith(name, "amlhalasink"));
1009 #endif
1010 }
1011 
1012 /**
1013  * @brief Check if gstreamer element is audio decoder
1014  * @param[in] name Name of the element
1015  * @param[in] _this pointer to AAMPGstPlayer instance
1016  * @retval TRUE if element name is that of audio or video decoder
1017  */
1019 {
1020  // The idea is to identify video or audio decoder plugin created at runtime by playbin and register to its first-frame/pts-error callbacks
1021  // This support is available in BCOM plugins in RDK builds and hence checking only for such plugin instances here
1022  // While using playersinkbin, these callbacks are supported via "event-callback" signal and hence not requried to do explicitly
1023  // For platforms that doesnt support callback, we use GST_STATE_PLAYING state change of playbin to notify first frame to app
1024  bool isAudioOrVideoDecoder = false;
1025  if (!_this->privateContext->stream[eMEDIATYPE_VIDEO].using_playersinkbin &&
1026  !_this->privateContext->using_westerossink && aamp_StartsWith(name, "brcmvideodecoder"))
1027  {
1028  isAudioOrVideoDecoder = true;
1029  }
1030 #if defined (REALTEKCE)
1031  else if (aamp_StartsWith(name, "omx"))
1032  {
1033  isAudioOrVideoDecoder = true;
1034  }
1035 #else
1036  else if (_this->privateContext->using_westerossink && aamp_StartsWith(name, "westerossink"))
1037  {
1038  isAudioOrVideoDecoder = true;
1039  }
1040 #endif
1041  else if (aamp_StartsWith(name, "brcmaudiodecoder"))
1042  {
1043  isAudioOrVideoDecoder = true;
1044  }
1045 
1046 
1047  return isAudioOrVideoDecoder;
1048 }
1049 
1050 /**
1051  * @brief Notifies EOS if video decoder pts is stalled
1052  * @param[in] user_data pointer to AAMPGstPlayer instance
1053  * @retval G_SOURCE_REMOVE, if the source should be removed
1054  */
1055 static gboolean VideoDecoderPtsCheckerForEOS(gpointer user_data)
1056 {
1057  AAMPGstPlayer *_this = (AAMPGstPlayer *) user_data;
1058  AAMPGstPlayerPriv *privateContext = _this->privateContext;
1059 #ifndef INTELCE
1060  gint64 currentPTS = _this->GetVideoPTS(); /* Gets the currentPTS from the 'video-pts' property of the element */
1061 
1062  if (currentPTS == privateContext->lastKnownPTS)
1063  {
1064  AAMPLOG_WARN("PTS not changed");
1065  _this->NotifyEOS(); /* Notify EOS if the PTS has not changed */
1066  }
1067  else
1068  {
1069  AAMPLOG_WARN("Video PTS still moving lastKnownPTS %" G_GUINT64_FORMAT " currentPTS %" G_GUINT64_FORMAT " ##", privateContext->lastKnownPTS, currentPTS);
1070  }
1071 #endif
1072  privateContext->ptsCheckForEosOnUnderflowIdleTaskId = AAMP_TASK_ID_INVALID;
1073  return G_SOURCE_REMOVE;
1074 }
1075 
1076 #ifdef RENDER_FRAMES_IN_APP_CONTEXT
1077 
1078 /**
1079  * @brief Callback function to get video frames
1080  */
1081 GstFlowReturn AAMPGstPlayer::AAMPGstPlayer_OnVideoSample(GstElement* object, AAMPGstPlayer * _this)
1082 {
1083  FN_TRACE( __FUNCTION__ );
1084  using ::mLogObj; //To use global log object
1085  GstSample *sample;
1086  GstBuffer *buffer;
1087  GstMapInfo map;
1088 
1089  if(_this && _this->cbExportYUVFrame)
1090  {
1091  sample = gst_app_sink_pull_sample (GST_APP_SINK (object));
1092  if (sample)
1093  {
1094  int width, height;
1095  GstCaps *caps = gst_sample_get_caps(sample);
1096  GstStructure *capsStruct = gst_caps_get_structure(caps,0);
1097  gst_structure_get_int(capsStruct,"width",&width);
1098  gst_structure_get_int(capsStruct,"height",&height);
1099  //AAMPLOG_WARN("StrCAPS=%s\n", gst_caps_to_string(caps));
1100  buffer = gst_sample_get_buffer (sample);
1101  if (buffer)
1102  {
1103  if (gst_buffer_map(buffer, &map, GST_MAP_READ))
1104  {
1105  _this->cbExportYUVFrame(map.data, map.size, width, height);
1106 
1107  gst_buffer_unmap(buffer, &map);
1108  }
1109  else
1110  {
1111  AAMPLOG_WARN("buffer map failed\n");
1112  }
1113  }
1114  else
1115  {
1116  AAMPLOG_WARN("buffer NULL\n");
1117  }
1118  gst_sample_unref (sample);
1119  }
1120  else
1121  {
1122  AAMPLOG_WARN("sample NULL\n");
1123  }
1124  }
1125  return GST_FLOW_OK;
1126 }
1127 #endif
1128 
1129 /**
1130  * @brief Callback invoked when facing an underflow
1131  * @param[in] object pointer to element raising the callback
1132  * @param[in] arg0 number of arguments
1133  * @param[in] arg1 array of arguments
1134  * @param[in] _this pointer to AAMPGstPlayer instance
1135  */
1136 static void AAMPGstPlayer_OnGstBufferUnderflowCb(GstElement* object, guint arg0, gpointer arg1,
1137  AAMPGstPlayer * _this)
1138 {
1139  if (_this->aamp->mConfig->IsConfigSet(eAAMPConfig_DisableUnderflow))
1140  { // optionally ignore underflow
1141  AAMPLOG_WARN("## [WARN] Ignored underflow from %s, disableUnderflow config enabled ##", GST_ELEMENT_NAME(object));
1142  }
1143  else
1144  {
1145  //TODO - Handle underflow
1146  MediaType type = eMEDIATYPE_DEFAULT; //CID:89173 - Resolve Uninit
1147  AAMPGstPlayerPriv *privateContext = _this->privateContext;
1148 #ifdef REALTEKCE
1149  if (AAMPGstPlayer_isVideoSink(GST_ELEMENT_NAME(object), _this))
1150 #else
1151  if (AAMPGstPlayer_isVideoDecoder(GST_ELEMENT_NAME(object), _this))
1152 #endif
1153  {
1154  type = eMEDIATYPE_VIDEO;
1155  }
1156  else if (AAMPGstPlayer_isAudioSinkOrAudioDecoder(GST_ELEMENT_NAME(object), _this))
1157  {
1158  type = eMEDIATYPE_AUDIO;
1159  }
1160  else
1161  {
1162  AAMPLOG_WARN("## WARNING!! Underflow message from %s not handled, unmapped underflow!", GST_ELEMENT_NAME(object));
1163  return;
1164  }
1165 
1166  AAMPLOG_WARN("## Got Underflow message from %s type %d ##", GST_ELEMENT_NAME(object), type);
1167 
1168  _this->privateContext->stream[type].bufferUnderrun = true;
1169 
1170  if ((_this->privateContext->stream[type].eosReached) && (_this->privateContext->rate > 0))
1171  {
1172  if (!privateContext->ptsCheckForEosOnUnderflowIdleTaskId)
1173  {
1174  privateContext->lastKnownPTS =_this->GetVideoPTS(); /* Gets the currentPTS from the 'video-pts' property of the element */
1175  privateContext->ptsUpdatedTimeMS = NOW_STEADY_TS_MS;
1177  /*g_timeout_add - Sets the function VideoDecoderPtsCheckerForEOS to be called at regular intervals*/
1178  }
1179  else
1180  {
1181  AAMPLOG_WARN("ptsCheckForEosOnUnderflowIdleTask ID %d already running, ignore underflow", (int)privateContext->ptsCheckForEosOnUnderflowIdleTaskId);
1182  }
1183  }
1184  else
1185  {
1186  AAMPLOG_WARN("Mediatype %d underrun, when eosReached is %d", type, _this->privateContext->stream[type].eosReached);
1187  _this->aamp->ScheduleRetune(eGST_ERROR_UNDERFLOW, type); /* Schedule a retune */
1188  }
1189  }
1190 }
1191 
1192 /**
1193  * @brief Callback invoked a PTS error is encountered
1194  * @param[in] object pointer to element raising the callback
1195  * @param[in] arg0 number of arguments
1196  * @param[in] arg1 array of arguments
1197  * @param[in] _this pointer to AAMPGstPlayer instance
1198  */
1199 static void AAMPGstPlayer_OnGstPtsErrorCb(GstElement* object, guint arg0, gpointer arg1,
1200  AAMPGstPlayer * _this)
1201 {
1202  AAMPLOG_WARN("## Got PTS error message from %s ##", GST_ELEMENT_NAME(object));
1203 #ifdef REALTEKCE
1204  if (AAMPGstPlayer_isVideoSink(GST_ELEMENT_NAME(object), _this))
1205 #else
1206  if (AAMPGstPlayer_isVideoDecoder(GST_ELEMENT_NAME(object), _this))
1207 #endif
1208  {
1210  }
1211  else if (AAMPGstPlayer_isAudioSinkOrAudioDecoder(GST_ELEMENT_NAME(object), _this))
1212  {
1214  }
1215 }
1216 
1217 /**
1218  * @brief Callback invoked a Decode error is encountered
1219  * @param[in] object pointer to element raising the callback
1220  * @param[in] arg0 number of arguments
1221  * @param[in] arg1 array of arguments
1222  * @param[in] _this pointer to AAMPGstPlayer instance
1223  */
1224 static void AAMPGstPlayer_OnGstDecodeErrorCb(GstElement* object, guint arg0, gpointer arg1,
1225  AAMPGstPlayer * _this)
1226 {
1227  long long deltaMS = NOW_STEADY_TS_MS - _this->privateContext->decodeErrorMsgTimeMS;
1228  _this->privateContext->decodeErrorCBCount += 1;
1229  if (deltaMS >= AAMP_MIN_DECODE_ERROR_INTERVAL)
1230  {
1231  _this->aamp->SendAnomalyEvent(ANOMALY_WARNING, "Decode Error Message Callback=%d time=%d",_this->privateContext->decodeErrorCBCount, AAMP_MIN_DECODE_ERROR_INTERVAL);
1232  _this->privateContext->decodeErrorMsgTimeMS = NOW_STEADY_TS_MS;
1233  AAMPLOG_WARN("## Got Decode Error message from %s ## total_cb=%d timeMs=%d", GST_ELEMENT_NAME(object), _this->privateContext->decodeErrorCBCount, AAMP_MIN_DECODE_ERROR_INTERVAL);
1234  _this->privateContext->decodeErrorCBCount = 0;
1235  }
1236 }
1237 
1238 static gboolean buffering_timeout (gpointer data)
1239 {
1240  AAMPGstPlayer * _this = (AAMPGstPlayer *) data;
1241  if (_this && _this->privateContext)
1242  {
1243  AAMPGstPlayerPriv * privateContext = _this->privateContext;
1244  if (_this->privateContext->buffering_in_progress)
1245  {
1246  int frames = -1;
1247  if (_this->privateContext->video_dec)
1248  {
1249  g_object_get(_this->privateContext->video_dec,"queued_frames",(uint*)&frames,NULL);
1250  AAMPLOG_TRACE("queued_frames: %i", frames);
1251  }
1252  MediaFormat mediaFormatRet;
1253  mediaFormatRet = _this->aamp->GetMediaFormatTypeEnum();
1254  /* DELIA-34654: Disable re-tune on buffering timeout for DASH as unlike HLS,
1255  DRM key acquisition can end after injection, and buffering is not expected
1256  to be completed by the 1 second timeout
1257  */
1258  if (G_UNLIKELY(((mediaFormatRet != eMEDIAFORMAT_DASH) && (mediaFormatRet != eMEDIAFORMAT_PROGRESSIVE) && (mediaFormatRet != eMEDIAFORMAT_HLS_MP4)) && (privateContext->buffering_timeout_cnt == 0) && _this->aamp->mConfig->IsConfigSet(eAAMPConfig_ReTuneOnBufferingTimeout) && (privateContext->numberOfVideoBuffersSent > 0)))
1259  {
1260  AAMPLOG_WARN("Schedule retune. numberOfVideoBuffersSent %d frames %i", privateContext->numberOfVideoBuffersSent, frames);
1261  privateContext->buffering_in_progress = false;
1262  _this->DumpDiagnostics();
1264  }
1265 
1266 #if !defined(__APPLE__)
1267  else if (frames == -1 || frames > DEFAULT_BUFFERING_QUEUED_FRAMES_MIN || privateContext->buffering_timeout_cnt-- == 0)
1268 #endif
1269  {
1270  AAMPLOG_WARN("Set pipeline state to %s - buffering_timeout_cnt %u frames %i", gst_element_state_get_name(_this->privateContext->buffering_target_state), (_this->privateContext->buffering_timeout_cnt+1), frames);
1271  SetStateWithWarnings (_this->privateContext->pipeline, _this->privateContext->buffering_target_state);
1272  _this->privateContext->buffering_in_progress = false;
1273  if(!_this->aamp->mConfig->IsConfigSet(eAAMPConfig_GstSubtecEnabled))
1274  {
1275  _this->aamp->UpdateSubtitleTimestamp();
1276  }
1277  }
1278  }
1279  if (!_this->privateContext->buffering_in_progress)
1280  {
1281  //reset timer id after buffering operation is completed
1282  _this->privateContext->bufferingTimeoutTimerId = AAMP_TASK_ID_INVALID;
1283  }
1284  return _this->privateContext->buffering_in_progress;
1285  }
1286  else
1287  {
1288  AAMPLOG_WARN("in buffering_timeout got invalid or NULL handle ! _this = %p _this->privateContext = %p ",
1289  _this, (_this? _this->privateContext: NULL) );
1290  return false;
1291  }
1292 
1293 }
1294 
1295 /**
1296  * @brief Called from the mainloop when a message is available on the bus
1297  * @param[in] bus the GstBus that sent the message
1298  * @param[in] msg the GstMessage
1299  * @param[in] _this pointer to AAMPGstPlayer instance
1300  * @retval FALSE if the event source should be removed.
1301  */
1302 static gboolean bus_message(GstBus * bus, GstMessage * msg, AAMPGstPlayer * _this)
1303 {
1304  GError *error;
1305  gchar *dbg_info;
1306  bool isPlaybinStateChangeEvent;
1307 
1308  switch (GST_MESSAGE_TYPE(msg))
1309  { // see https://developer.gnome.org/gstreamer/stable/gstreamer-GstMessage.html#GstMessage
1310  case GST_MESSAGE_ERROR:
1311  gst_message_parse_error(msg, &error, &dbg_info); /* Extracts the GError and debug string from the GstMessage i.e msg */
1312  g_printerr("GST_MESSAGE_ERROR %s: %s\n", GST_OBJECT_NAME(msg->src), error->message);
1313  char errorDesc[MAX_ERROR_DESCRIPTION_LENGTH];
1314  memset(errorDesc, '\0', MAX_ERROR_DESCRIPTION_LENGTH);
1315  strncpy(errorDesc, "GstPipeline Error:", 18);
1316  strncat(errorDesc, error->message, MAX_ERROR_DESCRIPTION_LENGTH - 18 - 1); /* Constructs erroDesc string, describing error for further action */
1317  if (strstr(error->message, "video decode error") != NULL)
1318  {
1319  _this->aamp->SendErrorEvent(AAMP_TUNE_GST_PIPELINE_ERROR, errorDesc, false); /* Forward the information to handle error */
1320  }
1321  else if(strstr(error->message, "HDCP Compliance Check Failure") != NULL)
1322  {
1323  // Trying to play a 4K content on a non-4K TV .Report error to XRE with no retune
1324  _this->aamp->SendErrorEvent(AAMP_TUNE_HDCP_COMPLIANCE_ERROR, errorDesc, false); /* Forward the information to handle error */
1325  }
1326  else if (strstr(error->message, "Internal data stream error") && _this->aamp->mConfig->IsConfigSet(eAAMPConfig_RetuneForGSTError))
1327  {
1328  // This can be executed only for Peacock when it hits Internal data stream error.
1329  AAMPLOG_WARN("Schedule retune for GstPipeline Error");
1331  }
1332  else
1333  {
1334  _this->aamp->SendErrorEvent(AAMP_TUNE_GST_PIPELINE_ERROR, errorDesc); /* Forward the information to handle error */
1335  }
1336  g_printerr("Debug Info: %s\n", (dbg_info) ? dbg_info : "none");
1337  g_clear_error(&error); /* Frees the resources allocated to error and sets error to NULL */
1338  g_free(dbg_info); /* Frees memory resources used by dbg_info */
1339  break;
1340 
1341  case GST_MESSAGE_WARNING:
1342  gst_message_parse_warning(msg, &error, &dbg_info); /* Extracts the GError and debug string from the GstMessage i.e msg */
1343  g_printerr("GST_MESSAGE_WARNING %s: %s\n", GST_OBJECT_NAME(msg->src), error->message);
1344  if (_this->aamp->mConfig->IsConfigSet(eAAMPConfig_DecoderUnavailableStrict) && strstr(error->message, "No decoder available") != NULL)
1345  {
1346  char warnDesc[MAX_ERROR_DESCRIPTION_LENGTH];
1347  snprintf( warnDesc, MAX_ERROR_DESCRIPTION_LENGTH, "GstPipeline Error:%s", error->message );
1348  // decoding failures due to unsupported codecs are received as warnings, i.e.
1349  // "No decoder available for type 'video/x-gst-fourcc-av01"
1350  _this->aamp->SendErrorEvent(AAMP_TUNE_GST_PIPELINE_ERROR, warnDesc, false); /* Forward the information to handle error */
1351  }
1352  g_printerr("Debug Info: %s\n", (dbg_info) ? dbg_info : "none");
1353  g_clear_error(&error); /* Frees the resources allocated to error and sets error to NULL */
1354  g_free(dbg_info); /* Frees memory resources used by dbg_info */
1355  break;
1356 
1357  case GST_MESSAGE_EOS:
1358  /**
1359  * pipeline event: end-of-stream reached
1360  * application may perform flushing seek to resume playback
1361  */
1362  AAMPLOG_WARN("GST_MESSAGE_EOS");
1363  _this->NotifyEOS();
1364  break;
1365 
1366  case GST_MESSAGE_STATE_CHANGED:
1367  GstState old_state, new_state, pending_state;
1368  gst_message_parse_state_changed(msg, &old_state, &new_state, &pending_state); /* Extracts the old and new states from the GstMessage.*/
1369 
1370  isPlaybinStateChangeEvent = (GST_MESSAGE_SRC(msg) == GST_OBJECT(_this->privateContext->pipeline));
1371 
1372  if (_this->aamp->mConfig->IsConfigSet(eAAMPConfig_GSTLogging) || isPlaybinStateChangeEvent)
1373  {
1374  AAMPLOG_WARN("%s %s -> %s (pending %s)",
1375  GST_OBJECT_NAME(msg->src),
1376  gst_element_state_get_name(old_state),
1377  gst_element_state_get_name(new_state),
1378  gst_element_state_get_name(pending_state));
1379 
1380  if (isPlaybinStateChangeEvent && new_state == GST_STATE_PLAYING)
1381  {
1382  // progressive ff case, notify to update trickStartUTCMS
1383  if (_this->aamp->mMediaFormat == eMEDIAFORMAT_PROGRESSIVE)
1384  {
1385  _this->aamp->NotifyFirstBufferProcessed();
1386  _this->IdleTaskAdd(_this->privateContext->firstProgressCallbackIdleTask, IdleCallback);
1387  }
1388 #if defined(REALTEKCE)
1389  // DELIA-33640: For Realtekce build and westeros-sink disabled
1390  // prevent calling NotifyFirstFrame after first tune, ie when upausing
1391  // pipeline during flush
1392  if(_this->privateContext->firstTuneWithWesterosSinkOff)
1393  {
1394  _this->privateContext->firstTuneWithWesterosSinkOff = false;
1395  _this->privateContext->firstVideoFrameReceived = true;
1396  _this->privateContext->firstAudioFrameReceived = true;
1398  }
1399 #endif
1400 #if (defined(INTELCE) || defined(RPI) || defined(__APPLE__) || defined(UBUNTU))
1401  if(!_this->privateContext->firstFrameReceived)
1402  {
1403  _this->privateContext->firstFrameReceived = true;
1404  _this->aamp->LogFirstFrame();
1405  _this->aamp->LogTuneComplete();
1406  }
1407  _this->aamp->NotifyFirstFrameReceived();
1408  //Note: Progress event should be sent after the decoderAvailable event only.
1409  //BRCM platform sends progress event after AAMPGstPlayer_OnFirstVideoFrameCallback.
1410  _this->IdleTaskAdd(_this->privateContext->firstProgressCallbackIdleTask, IdleCallback);
1411 #endif
1412  analyze_streams(_this);
1413 
1414  if (_this->aamp->mConfig->IsConfigSet(eAAMPConfig_GSTLogging))
1415  {
1416  GST_DEBUG_BIN_TO_DOT_FILE((GstBin *)_this->privateContext->pipeline, GST_DEBUG_GRAPH_SHOW_ALL, "myplayer");
1417  // output graph to .dot format which can be visualized with Graphviz tool if:
1418  // gstreamer is configured with --gst-enable-gst-debug
1419  // and "gst" is enabled in aamp.cfg
1420  // and environment variable GST_DEBUG_DUMP_DOT_DIR is set to a basepath(e.g. /opt).
1421  }
1422 
1423  // First Video Frame Displayed callback for westeros-sink is initialized
1424  // via OnFirstVideoFrameCallback()->NotifyFirstFrame() which is more accurate
1425  if( (!_this->privateContext->using_westerossink)
1426  && (!_this->privateContext->firstVideoFrameDisplayedCallbackIdleTaskPending)
1427  && (_this->aamp->IsFirstVideoFrameDisplayedRequired()) )
1428  {
1429  _this->privateContext->firstVideoFrameDisplayedCallbackIdleTaskPending = true;
1430  _this->privateContext->firstVideoFrameDisplayedCallbackIdleTaskId =
1431  _this->aamp->ScheduleAsyncTask(IdleCallbackFirstVideoFrameDisplayed, (void *)_this,"FirstVideoFrameDisplayedCallback");
1432  }
1433 
1434  if(_this->aamp->mSetPlayerRateAfterFirstframe
1435 #ifdef REALTEKCE
1436  ||((AAMP_SLOWMOTION_RATE == _this->aamp->playerrate) && (_this->aamp->rate != _this->aamp->playerrate))
1437 #endif /*REALTEKCE*/
1438  )
1439  {
1440  if(_this->aamp->mSetPlayerRateAfterFirstframe)
1441  {
1442  _this->aamp->mSetPlayerRateAfterFirstframe=false;
1443  if(false!=_this->aamp->mStreamSink->SetPlayBackRate(_this->aamp->playerrate))
1444  {
1445  _this->aamp->rate=_this->aamp->playerrate;
1446  _this->aamp->SetAudioVolume(0);
1447  }
1448  }
1449 #ifdef REALTEKCE
1450  else
1451  {
1452  if(false!=_this->aamp->mStreamSink->SetPlayBackRate(_this->aamp->rate))
1453  {
1454  _this->aamp->playerrate=_this->aamp->rate;
1455  }
1456  }
1457 #endif /*REALTEKCE*/
1458  }
1459  }
1460  }
1461  if ((NULL != msg->src) && AAMPGstPlayer_isVideoOrAudioDecoder(GST_OBJECT_NAME(msg->src), _this))
1462  {
1463 #ifdef AAMP_MPD_DRM
1464  // This is the video decoder, send this to the output protection module
1465  // so it can get the source width/height
1466  if (AAMPGstPlayer_isVideoDecoder(GST_OBJECT_NAME(msg->src), _this))
1467  {
1469  {
1471  pInstance->setGstElement((GstElement *)(msg->src));
1472  pInstance->Release();
1473  }
1474  }
1475 #endif
1476  }
1477 
1478  if ((NULL != msg->src) &&
1479 #if defined(REALTEKCE)
1480  AAMPGstPlayer_isVideoSink(GST_OBJECT_NAME(msg->src), _this)
1481 #else
1482  AAMPGstPlayer_isVideoOrAudioDecoder(GST_OBJECT_NAME(msg->src), _this)
1483 #endif
1484  )
1485  {
1486  if (old_state == GST_STATE_NULL && new_state == GST_STATE_READY)
1487  {
1488  g_signal_connect(msg->src, "buffer-underflow-callback",
1489  G_CALLBACK(AAMPGstPlayer_OnGstBufferUnderflowCb), _this); /* Sets up the call back function on 'buffer-underflow-callback' event */
1490  g_signal_connect(msg->src, "pts-error-callback",
1491  G_CALLBACK(AAMPGstPlayer_OnGstPtsErrorCb), _this);
1492 #if !defined(REALTEKCE)
1493  // To register decode-error-callback for video decoder source alone
1494  if (AAMPGstPlayer_isVideoDecoder(GST_OBJECT_NAME(msg->src), _this))
1495  {
1496  g_signal_connect(msg->src, "decode-error-callback",
1497  G_CALLBACK(AAMPGstPlayer_OnGstDecodeErrorCb), _this);
1498  }
1499 #endif
1500  }
1501  }
1502  break;
1503 
1504  case GST_MESSAGE_TAG:
1505  break;
1506 
1507  case GST_MESSAGE_QOS:
1508  {
1509  gboolean live;
1510  guint64 running_time;
1511  guint64 stream_time;
1512  guint64 timestamp;
1513  guint64 duration;
1514  gst_message_parse_qos(msg, &live, &running_time, &stream_time, &timestamp, &duration);
1515  break;
1516  }
1517 
1518  case GST_MESSAGE_CLOCK_LOST:
1519  /* In this case, the current clock as selected by the pipeline has become unusable. The pipeline will select a new clock on the next PLAYING state change.
1520  As per the gstreamer.desktop org, the application should set the pipeline to PAUSED and back to PLAYING when GST_MESSAGE_CLOCK_LOST is received.*/
1521  AAMPLOG_WARN("GST_MESSAGE_CLOCK_LOST");
1522  // get new clock - needed?
1523  SetStateWithWarnings(_this->privateContext->pipeline, GST_STATE_PAUSED);
1524  SetStateWithWarnings(_this->privateContext->pipeline, GST_STATE_PLAYING);
1525  break;
1526 
1527  case GST_MESSAGE_RESET_TIME: /* Message from pipeline to request resetting its running time */
1528 #ifdef TRACE
1529  GstClockTime running_time;
1530  gst_message_parse_reset_time (msg, &running_time);
1531  printf("GST_MESSAGE_RESET_TIME %llu\n", (unsigned long long)running_time);
1532 #endif
1533  break;
1534 
1535  case GST_MESSAGE_STREAM_STATUS:
1536  case GST_MESSAGE_ELEMENT: // can be used to collect pts, dts, pid
1537  case GST_MESSAGE_DURATION:
1538  case GST_MESSAGE_LATENCY:
1539  case GST_MESSAGE_NEW_CLOCK:
1540  break;
1541  case GST_MESSAGE_APPLICATION:
1542  const GstStructure *msgS;
1543  msgS = gst_message_get_structure (msg);
1544  if (gst_structure_has_name (msgS, "HDCPProtectionFailure")) {
1545  AAMPLOG_WARN("Received HDCPProtectionFailure event.Schedule Retune ");
1546  _this->Flush(0, AAMP_NORMAL_PLAY_RATE, true);
1548  }
1549  break;
1550 
1551  default:
1552  AAMPLOG_WARN("msg type: %s", gst_message_type_get_name(msg->type));
1553  break;
1554  }
1555  return TRUE;
1556 }
1557 
1558 
1559 /**
1560  * @brief Invoked synchronously when a message is available on the bus
1561  * @param[in] bus the GstBus that sent the message
1562  * @param[in] msg the GstMessage
1563  * @param[in] _this pointer to AAMPGstPlayer instance
1564  * @retval GST_BUS_PASS to pass the message to the async queue
1565  */
1566 static GstBusSyncReply bus_sync_handler(GstBus * bus, GstMessage * msg, AAMPGstPlayer * _this)
1567 {
1568  switch(GST_MESSAGE_TYPE(msg))
1569  {
1570  case GST_MESSAGE_STATE_CHANGED:
1571  GstState old_state, new_state;
1572  gst_message_parse_state_changed(msg, &old_state, &new_state, NULL);
1573 
1574  if (GST_MESSAGE_SRC(msg) == GST_OBJECT(_this->privateContext->pipeline))
1575  {
1576  _this->privateContext->pipelineState = new_state;
1577  }
1578 
1579  /* Moved the below code block from bus_message() async handler to bus_sync_handler()
1580  * to avoid a timing case crash when accessing wrong video_sink element after it got deleted during pipeline reconfigure on codec change in mid of playback.
1581  */
1582  if (!_this->privateContext->stream[eMEDIATYPE_VIDEO].using_playersinkbin)
1583  {
1584 #ifndef INTELCE
1585  if (new_state == GST_STATE_PAUSED && old_state == GST_STATE_READY)
1586  {
1587  if (AAMPGstPlayer_isVideoSink(GST_OBJECT_NAME(msg->src), _this))
1588  { // video scaling patch
1589  /*
1590  brcmvideosink doesn't sets the rectangle property correct by default
1591  gst-inspect-1.0 brcmvideosink
1592  g_object_get(_this->privateContext->pipeline, "video-sink", &videoSink, NULL); - reports NULL
1593  note: alternate "window-set" works as well
1594  */
1595  _this->privateContext->video_sink = (GstElement *) msg->src;
1596  if (_this->privateContext->using_westerossink && !_this->aamp->mConfig->IsConfigSet(eAAMPConfig_EnableRectPropertyCfg))
1597  {
1598  AAMPLOG_WARN("AAMPGstPlayer - using westerossink, setting cached video mute and zoom");
1599  g_object_set(msg->src, "zoom-mode", VIDEO_ZOOM_FULL == _this->privateContext->zoom ? 0 : 1, NULL);
1600  g_object_set(msg->src, "show-video-window", !_this->privateContext->videoMuted, NULL);
1601  }
1602  else
1603  {
1604  AAMPLOG_WARN("AAMPGstPlayer setting cached rectangle, video mute and zoom");
1605  g_object_set(msg->src, "rectangle", _this->privateContext->videoRectangle, NULL);
1606  g_object_set(msg->src, "zoom-mode", VIDEO_ZOOM_FULL == _this->privateContext->zoom ? 0 : 1, NULL);
1607  g_object_set(msg->src, "show-video-window", !_this->privateContext->videoMuted, NULL);
1608  }
1609  }
1610  else if (aamp_StartsWith(GST_OBJECT_NAME(msg->src), "brcmaudiosink") == true)
1611  {
1612  _this->privateContext->audio_sink = (GstElement *) msg->src;
1613 
1614  _this->setVolumeOrMuteUnMute();
1615  }
1616  else if (aamp_StartsWith(GST_OBJECT_NAME(msg->src), "amlhalasink") == true)
1617  {
1618  _this->privateContext->audio_sink = (GstElement *) msg->src;
1619 
1620  g_object_set(_this->privateContext->audio_sink, "disable-xrun", TRUE, NULL);
1621  // Apply audio settings that may have been set before pipeline was ready
1622  _this->setVolumeOrMuteUnMute();
1623  }
1624  else if (strstr(GST_OBJECT_NAME(msg->src), "brcmaudiodecoder"))
1625  {
1626  // this reduces amount of data in the fifo, which is flushed/lost when transition from expert to normal modes
1627  g_object_set(msg->src, "limit_buffering_ms", 1500, NULL); /* default 500ms was a bit low.. try 1500ms */
1628  g_object_set(msg->src, "limit_buffering", 1, NULL);
1629  AAMPLOG_WARN("Found audiodecoder, limiting audio decoder buffering");
1630 
1631  /* if aamp->mAudioDecoderStreamSync==false, tell decoder not to look for 2nd/next frame sync, decode if it finds a single frame sync */
1632  g_object_set(msg->src, "stream_sync_mode", (_this->aamp->mAudioDecoderStreamSync)? 1 : 0, NULL);
1633  AAMPLOG_WARN("For audiodecoder set 'stream_sync_mode': %d", _this->aamp->mAudioDecoderStreamSync);
1634  }
1635 #if defined (REALTEKCE)
1636  else if ( aamp_StartsWith(GST_OBJECT_NAME(msg->src), "rtkaudiosink")
1637  || aamp_StartsWith(GST_OBJECT_NAME(msg->src), "alsasink")
1638  || aamp_StartsWith(GST_OBJECT_NAME(msg->src), "fakesink") )
1639  {
1640  _this->privateContext->audio_sink = (GstElement *) msg->src;
1641  // Apply audio settings that may have been set before pipeline was ready
1642  _this->setVolumeOrMuteUnMute();
1643  }
1644 #endif
1645 
1646  StreamOutputFormat audFormat = _this->privateContext->stream[eMEDIATYPE_AUDIO].format;
1647  }
1648 #endif
1649  }
1650  if (old_state == GST_STATE_NULL && new_state == GST_STATE_READY)
1651  {
1652 #ifndef INTELCE
1653  if ((NULL != msg->src) && AAMPGstPlayer_isVideoOrAudioDecoder(GST_OBJECT_NAME(msg->src), _this))
1654  {
1655  if (AAMPGstPlayer_isVideoDecoder(GST_OBJECT_NAME(msg->src), _this))
1656  {
1657  _this->privateContext->video_dec = (GstElement *) msg->src;
1658  type_check_instance("bus_sync_handle: video_dec ", _this->privateContext->video_dec);
1659  g_signal_connect(_this->privateContext->video_dec, "first-video-frame-callback",
1660  G_CALLBACK(AAMPGstPlayer_OnFirstVideoFrameCallback), _this);
1661 #if !defined(REALTEKCE)
1662  g_object_set(msg->src, "report_decode_errors", TRUE, NULL);
1663 #endif
1664 
1665  }
1666  else
1667  {
1668  _this->privateContext->audio_dec = (GstElement *) msg->src;
1669  type_check_instance("bus_sync_handle: audio_dec ", _this->privateContext->audio_dec);
1670 #if !defined(REALTEKCE)
1671  g_signal_connect(msg->src, "first-audio-frame-callback",
1672  G_CALLBACK(AAMPGstPlayer_OnAudioFirstFrameAudDecoder), _this);
1673 #endif
1674  int trackId = _this->privateContext->stream[eMEDIATYPE_AUDIO].trackId;
1675  if (trackId >= 0) /** AC4 track selected **/
1676  {
1677 #if !defined(BRCM) /** AC4 support added for non Broadcom platforms */
1678  AAMPLOG_INFO("Selecting AC4 Track Id : %d", trackId);
1679  g_object_set(msg->src, "ac4-presentation-group-index", trackId, NULL);
1680 #else
1681  AAMPLOG_WARN("AC4 support has not done for this platform - track Id: %d", trackId);
1682 #endif
1683  }
1684  }
1685  }
1686  if ((NULL != msg->src) && AAMPGstPlayer_isVideoSink(GST_OBJECT_NAME(msg->src), _this))
1687  {
1688  if(_this->privateContext->enableSEITimeCode)
1689  {
1690  g_object_set(msg->src, "enable-timecode", 1, NULL);
1691  g_signal_connect(msg->src, "timecode-callback",
1692  G_CALLBACK(AAMPGstPlayer_redButtonCallback), _this);
1693  }
1694 #if !defined(REALTEKCE)
1695  }
1696 #else
1697  g_object_set(msg->src, "freerun-threshold", DEFAULT_AVSYNC_FREERUN_THRESHOLD_SECS, NULL);
1698  }
1699 
1700  if ((NULL != msg->src) && aamp_StartsWith(GST_OBJECT_NAME(msg->src), "rtkaudiosink"))
1701  g_signal_connect(msg->src, "first-audio-frame",
1702  G_CALLBACK(AAMPGstPlayer_OnAudioFirstFrameAudDecoder), _this);
1703 #endif
1704 #else
1705  if (aamp_StartsWith(GST_OBJECT_NAME(msg->src), "ismdgstaudiosink") == true)
1706  {
1707  _this->privateContext->audio_sink = (GstElement *) msg->src;
1708 
1709  AAMPLOG_WARN("AAMPGstPlayer setting audio-sync");
1710  g_object_set(msg->src, "sync", TRUE, NULL);
1711 
1712  _this->setVolumeOrMuteUnMute();
1713  }
1714  else
1715  {
1716 #ifndef INTELCE_USE_VIDRENDSINK
1717  if (aamp_StartsWith(GST_OBJECT_NAME(msg->src), "ismdgstvidsink") == true)
1718 #else
1719  if (aamp_StartsWith(GST_OBJECT_NAME(msg->src), "ismdgstvidrendsink") == true)
1720 #endif
1721  {
1722  AAMPGstPlayerPriv *privateContext = _this->privateContext;
1723  privateContext->video_sink = (GstElement *) msg->src;
1724  AAMPLOG_WARN("AAMPGstPlayer setting stop-keep-frame %d", (int)(privateContext->keepLastFrame));
1725  g_object_set(msg->src, "stop-keep-frame", privateContext->keepLastFrame, NULL);
1726 #if defined(INTELCE) && !defined(INTELCE_USE_VIDRENDSINK)
1727  AAMPLOG_WARN("AAMPGstPlayer setting rectangle %s", privateContext->videoRectangle);
1728  g_object_set(msg->src, "rectangle", privateContext->videoRectangle, NULL);
1729  AAMPLOG_WARN("AAMPGstPlayer setting zoom %s", (VIDEO_ZOOM_FULL == privateContext->zoom) ? "FULL" : "NONE");
1730  g_object_set(msg->src, "scale-mode", (VIDEO_ZOOM_FULL == privateContext->zoom) ? 0 : 3, NULL);
1731  AAMPLOG_WARN("AAMPGstPlayer setting crop-lines to FALSE");
1732  g_object_set(msg->src, "crop-lines", FALSE, NULL);
1733 #endif
1734  AAMPLOG_WARN("AAMPGstPlayer setting video mute %d", privateContext->videoMuted);
1735  g_object_set(msg->src, "mute", privateContext->videoMuted, NULL);
1736  }
1737  else if (aamp_StartsWith(GST_OBJECT_NAME(msg->src), "ismdgsth264viddec") == true)
1738  {
1739  _this->privateContext->video_dec = (GstElement *) msg->src;
1740  }
1741 #ifdef INTELCE_USE_VIDRENDSINK
1742  else if (aamp_StartsWith(GST_OBJECT_NAME(msg->src), "ismdgstvidpproc") == true)
1743  {
1744  _this->privateContext->video_pproc = (GstElement *) msg->src;
1745  AAMPLOG_WARN("AAMPGstPlayer setting rectangle %s", _this->privateContext->videoRectangle);
1746  g_object_set(msg->src, "rectangle", _this->privateContext->videoRectangle, NULL);
1747  AAMPLOG_WARN("AAMPGstPlayer setting zoom %d", _this->privateContext->zoom);
1748  g_object_set(msg->src, "scale-mode", (VIDEO_ZOOM_FULL == _this->privateContext->zoom) ? 0 : 3, NULL);
1749  }
1750 #endif
1751  }
1752 #endif
1753  /*This block is added to share the PrivateInstanceAAMP object
1754  with PlayReadyDecryptor Plugin, for tune time profiling
1755 
1756  AAMP is added as a property of playready plugin
1757  */
1758  if(aamp_StartsWith(GST_OBJECT_NAME(msg->src), GstPluginNamePR) == true ||
1759  aamp_StartsWith(GST_OBJECT_NAME(msg->src), GstPluginNameWV) == true ||
1760  aamp_StartsWith(GST_OBJECT_NAME(msg->src), GstPluginNameCK) == true ||
1761  aamp_StartsWith(GST_OBJECT_NAME(msg->src), GstPluginNameVMX) == true)
1762  {
1763  AAMPLOG_WARN("AAMPGstPlayer setting aamp instance for %s decryptor", GST_OBJECT_NAME(msg->src));
1764  GValue val = { 0, };
1765  g_value_init(&val, G_TYPE_POINTER);
1766  g_value_set_pointer(&val, (gpointer) _this->aamp);
1767  g_object_set_property(G_OBJECT(msg->src), "aamp",&val);
1768  }
1769  }
1770  break;
1771  case GST_MESSAGE_NEED_CONTEXT:
1772 
1773  /*
1774  * Code to avoid logs flooding with NEED-CONTEXT message for DRM systems
1775  */
1776  const gchar* contextType;
1777  gst_message_parse_context_type(msg, &contextType);
1778  if (!g_strcmp0(contextType, "drm-preferred-decryption-system-id"))
1779  {
1780  AAMPLOG_WARN("Setting %s as preferred drm",GetDrmSystemName(_this->aamp->GetPreferredDRM()));
1781  GstContext* context = gst_context_new("drm-preferred-decryption-system-id", FALSE);
1782  GstStructure* contextStructure = gst_context_writable_structure(context); /* Gets a writeable structure of context, context still own the structure*/
1783  gst_structure_set(contextStructure, "decryption-system-id", G_TYPE_STRING, GetDrmSystemID(_this->aamp->GetPreferredDRM()), NULL);
1784  gst_element_set_context(GST_ELEMENT(GST_MESSAGE_SRC(msg)), context);
1785 /* TODO: Fix this once preferred DRM is correct
1786  _this->aamp->setCurrentDrm(_this->aamp->GetPreferredDRM());
1787  */
1788  }
1789 
1790  break;
1791 #ifdef __APPLE__
1792  case GST_MESSAGE_ELEMENT:
1793  if (
1794 #ifdef RENDER_FRAMES_IN_APP_CONTEXT
1795  (nullptr == _this->cbExportYUVFrame) &&
1796 #endif
1797  gCbgetWindowContentView && gst_is_video_overlay_prepare_window_handle_message(msg))
1798  {
1799  AAMPLOG_WARN("Received prepare-window-handle. Attaching video to window handle=%lu",(*gCbgetWindowContentView)());
1800  /*
1801  DELIA-58839 [OSX] [AAMP Simulator] Mac OS Ventura Update - gst_gl_window_cocoa_queue_resize crash when playing streams
1802  Commented out line below, gst_video_overlay_set_window_handle, to temporarily avoid crash on MacOS 13 or higher. Expect line to be reinstated or permanent fix to be found in the future.
1803  */
1804  //gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (GST_MESSAGE_SRC (msg)), (*gCbgetWindowContentView)());
1805  }
1806  break;
1807 #endif
1808  case GST_MESSAGE_ASYNC_DONE:
1809  AAMPLOG_INFO("Received GST_MESSAGE_ASYNC_DONE message");
1810  if (_this->privateContext->buffering_in_progress)
1811  {
1812  _this->privateContext->bufferingTimeoutTimerId = g_timeout_add_full(BUFFERING_TIMEOUT_PRIORITY, DEFAULT_BUFFERING_TO_MS, buffering_timeout, _this, NULL);
1813  }
1814 
1815  break;
1816 
1817  default:
1818  break;
1819  }
1820 
1821  return GST_BUS_PASS; /* pass the message to the async queue */
1822 }
1823 
1824 /**
1825  * @brief Create a new Gstreamer pipeline
1826  */
1828 {
1829  FN_TRACE( __FUNCTION__ );
1830  bool ret = false;
1831 
1832  /* Destroy any existing pipeline before creating a new one */
1833  if (privateContext->pipeline || privateContext->bus)
1834  {
1835  DestroyPipeline();
1836  }
1837 
1838  /*DELIA-56028 - Each "Creating gstreamer pipeline" should be paired with one, subsequent "Destroying gstreamer pipeline" log entry.
1839  "Creating gstreamer pipeline" is intentionally placed after the DestroyPipeline() call above to maintain this sequence*/
1840  AAMPLOG_WARN("Creating gstreamer pipeline");
1841  privateContext->pipeline = gst_pipeline_new("AAMPGstPlayerPipeline");
1842  if (privateContext->pipeline)
1843  {
1844  privateContext->bus = gst_pipeline_get_bus(GST_PIPELINE(privateContext->pipeline)); /*Gets the GstBus of pipeline. The bus allows applications to receive GstMessage packets.*/
1845  if (privateContext->bus)
1846  {
1847  privateContext->busWatchId = gst_bus_add_watch(privateContext->bus, (GstBusFunc) bus_message, this); /* Creates a watch for privateContext->bus, invoking 'bus_message'
1848  when a asynchronous message on the bus is available */
1849  gst_bus_set_sync_handler(privateContext->bus, (GstBusSyncHandler) bus_sync_handler, this, NULL); /* Assigns a synchronous bus_sync_handler for synchronous messages */
1851  privateContext->buffering_in_progress = false;
1853  privateContext->buffering_target_state = GST_STATE_NULL;
1854 #ifdef INTELCE
1855  privateContext->buffering_enabled = false;
1856  AAMPLOG_WARN("%s buffering_enabled forced 0, INTELCE", GST_ELEMENT_NAME(privateContext->pipeline));
1857 #else
1858  AAMPLOG_WARN("%s buffering_enabled %u", GST_ELEMENT_NAME(privateContext->pipeline), privateContext->buffering_enabled);
1859 #endif
1860  if (privateContext->positionQuery == NULL)
1861  {
1862  /* Construct a new position query that will used to query the 'current playback position' when needed.
1863  The time base specified is in nanoseconds */
1864  privateContext->positionQuery = gst_query_new_position(GST_FORMAT_TIME);
1865  }
1866 
1867  /* Use to enable the timing synchronisation with gstreamer */
1869  ret = true;
1870  }
1871  else
1872  {
1873  AAMPLOG_WARN("AAMPGstPlayer - gst_pipeline_get_bus failed");
1874  }
1875  }
1876  else
1877  {
1878  AAMPLOG_WARN("AAMPGstPlayer - gst_pipeline_new failed");
1879  }
1880 
1881  return ret;
1882 }
1883 
1884 /**
1885  * @brief Cleanup an existing Gstreamer pipeline and associated resources
1886  */
1888 {
1889  FN_TRACE( __FUNCTION__ );
1890  if (privateContext->pipeline)
1891  {
1892  /*DELIA-56028 - "Destroying gstreamer pipeline" should only be logged when there is a pipeline to destroy
1893  and each "Destroying gstreamer pipeline" log entry should have one, prior "Creating gstreamer pipeline" log entry*/
1894  AAMPLOG_WARN("Destroying gstreamer pipeline");
1895  gst_object_unref(privateContext->pipeline); /* Decreases the reference count on privateContext->pipeline, in this case it will become zero,
1896  the reference to privateContext->pipeline will be freed in gstreamer */
1897  privateContext->pipeline = NULL;
1898  }
1899  if (privateContext->busWatchId != 0)
1900  {
1901  g_source_remove(privateContext->busWatchId); /* Remove the source that has privateContext->busWatchId from the default main context*/
1902  privateContext->busWatchId = 0;
1903  }
1904  if (privateContext->bus)
1905  {
1906  gst_object_unref(privateContext->bus); /* Decreases the reference count on privateContext->bus, in this case it will become zero,
1907  the reference to privateContext->bus will be freed in gstreamer */
1908  privateContext->bus = NULL;
1909  }
1910 
1911  if (privateContext->positionQuery)
1912  {
1913  /* Decrease the refcount of the query. If the refcount reaches 0, the query will be freed */
1914  gst_query_unref(privateContext->positionQuery);
1915  privateContext->positionQuery = NULL;
1916  }
1917 
1918  //video decoder handle will change with new pipeline
1919  privateContext->decoderHandleNotified = false;
1920  privateContext->NumberOfTracks = 0;
1921 }
1922 
1923 /**
1924  * @brief Retrieve the video decoder handle from pipeline
1925  */
1927 {
1928  FN_TRACE( __FUNCTION__ );
1929  gpointer dec_handle = NULL;
1930  if (this->privateContext->stream[eMEDIATYPE_VIDEO].using_playersinkbin && this->privateContext->stream[eMEDIATYPE_VIDEO].sinkbin != NULL)
1931  {
1932  AAMPLOG_WARN("Querying playersinkbin for handle");
1933  g_object_get(this->privateContext->stream[eMEDIATYPE_VIDEO].sinkbin, "video-decode-handle", &dec_handle, NULL);
1934  }
1935  else if(this->privateContext->video_dec != NULL)
1936  {
1937  AAMPLOG_WARN("Querying video decoder for handle");
1938 #ifndef INTELCE
1939 #if defined (REALTEKCE)
1940  dec_handle = this->privateContext->video_dec;
1941 #else
1942  g_object_get(this->privateContext->video_dec, "videodecoder", &dec_handle, NULL);
1943 #endif
1944 #else
1945  g_object_get(privateContext->video_dec, "decode-handle", &dec_handle, NULL);
1946 #endif
1947  }
1948  AAMPLOG_WARN("video decoder handle received %p for video_dec %p", dec_handle, privateContext->video_dec);
1949  return (unsigned long)dec_handle;
1950 }
1951 
1952 /**
1953  * @brief Generate a protection event
1954  */
1955 void AAMPGstPlayer::QueueProtectionEvent(const char *protSystemId, const void *initData, size_t initDataSize, MediaType type)
1956 {
1957  FN_TRACE( __FUNCTION__ );
1958 #ifdef AAMP_MPD_DRM
1959  /* There is a possibility that only single protection event is queued for multiple type since they are encrypted using same id.
1960  * Don't worry if you see only one protection event queued here.
1961  */
1962  pthread_mutex_lock(&mProtectionLock);
1963  if (privateContext->protectionEvent[type] != NULL)
1964  {
1965  AAMPLOG_WARN("Previously cached protection event is present for type(%d), clearing!", type);
1966  gst_event_unref(privateContext->protectionEvent[type]);
1967  privateContext->protectionEvent[type] = NULL;
1968  }
1969  pthread_mutex_unlock(&mProtectionLock);
1970 
1971  AAMPLOG_WARN("Queueing protection event for type(%d) keysystem(%s) initData(%p) initDataSize(%d)", type, protSystemId, initData, initDataSize);
1972 
1973  /* Giving invalid initData into ProtectionEvent causing "GStreamer-CRITICAL" assertion error. So if the initData is valid then its good to call the ProtectionEvent further. */
1974  if (initData && initDataSize)
1975  {
1976  GstBuffer *pssi;
1977 
1978  pssi = gst_buffer_new_wrapped(g_memdup (initData, initDataSize), initDataSize);
1979  pthread_mutex_lock(&mProtectionLock);
1980  if (this->aamp->IsDashAsset())
1981  {
1982  privateContext->protectionEvent[type] = gst_event_new_protection (protSystemId, pssi, "dash/mpd");
1983  }
1984  else
1985  {
1986  privateContext->protectionEvent[type] = gst_event_new_protection (protSystemId, pssi, "hls/m3u8");
1987  }
1988  pthread_mutex_unlock(&mProtectionLock);
1989 
1990  gst_buffer_unref (pssi);
1991  }
1992 #endif
1993 }
1994 
1995 /**
1996  * @brief Cleanup generated protection event
1997  */
1999 {
2000  FN_TRACE( __FUNCTION__ );
2001  pthread_mutex_lock(&mProtectionLock);
2002  for (int i = 0; i < AAMP_TRACK_COUNT; i++)
2003  {
2004  if(privateContext->protectionEvent[i])
2005  {
2006  AAMPLOG_WARN("removing protection event! ");
2007  gst_event_unref (privateContext->protectionEvent[i]);
2008  privateContext->protectionEvent[i] = NULL;
2009  }
2010  }
2011  pthread_mutex_unlock(&mProtectionLock);
2012 }
2013 
2014 /**
2015  * @brief Callback for receiving playersinkbin gstreamer events
2016  * @param[in] playersinkbin instance of playersinkbin
2017  * @param[in] status event name
2018  * @param[in] arg user data (pointer to AAMPGstPlayer instance)
2019  */
2020 static void AAMPGstPlayer_PlayersinkbinCB(GstElement * playersinkbin, gint status, void* arg)
2021 {
2022  AAMPGstPlayer *_this = (AAMPGstPlayer *)arg;
2023  switch (status)
2024  {
2025  case GSTPLAYERSINKBIN_EVENT_HAVE_VIDEO:
2026  GST_INFO("got Video PES.\n");
2027  break;
2028  case GSTPLAYERSINKBIN_EVENT_HAVE_AUDIO:
2029  GST_INFO("got Audio PES\n");
2030  break;
2031  case GSTPLAYERSINKBIN_EVENT_FIRST_VIDEO_FRAME:
2032  GST_INFO("got First Video Frame\n");
2034  break;
2035  case GSTPLAYERSINKBIN_EVENT_FIRST_AUDIO_FRAME:
2036  GST_INFO("got First Audio Sample\n");
2038  break;
2039  case GSTPLAYERSINKBIN_EVENT_ERROR_VIDEO_UNDERFLOW:
2040  //TODO - Handle underflow
2041  AAMPLOG_WARN("## Got Underflow message from video pipeline ##");
2042  break;
2043  case GSTPLAYERSINKBIN_EVENT_ERROR_AUDIO_UNDERFLOW:
2044  //TODO - Handle underflow
2045  AAMPLOG_WARN("## Got Underflow message from audio pipeline ##");
2046  break;
2047  case GSTPLAYERSINKBIN_EVENT_ERROR_VIDEO_PTS:
2048  //TODO - Handle PTS error
2049  AAMPLOG_WARN("## Got PTS error message from video pipeline ##");
2050  break;
2051  case GSTPLAYERSINKBIN_EVENT_ERROR_AUDIO_PTS:
2052  //TODO - Handle PTS error
2053  AAMPLOG_WARN("## Got PTS error message from audio pipeline ##");
2054  break;
2055  default:
2056  GST_INFO("%s status = 0x%x (Unknown)\n", __FUNCTION__, status);
2057  break;
2058  }
2059 }
2060 
2061 
2062 /**
2063  * @brief Create an appsrc element for a particular format
2064  * @param[in] _this pointer to AAMPGstPlayer instance
2065  * @param[in] mediaType media type
2066  * @retval pointer to appsrc instance
2067  */
2068 static GstElement* AAMPGstPlayer_GetAppSrc(AAMPGstPlayer *_this, MediaType mediaType)
2069 {
2070  GstElement *source;
2071  source = gst_element_factory_make("appsrc", NULL);
2072  if (NULL == source)
2073  {
2074  AAMPLOG_WARN("AAMPGstPlayer_GetAppSrc Cannot create source");
2075  return NULL;
2076  }
2077  InitializeSource(_this, G_OBJECT(source), mediaType);
2078 
2079  if (eMEDIATYPE_SUBTITLE == mediaType)
2080  {
2081  auto stream_format = _this->privateContext->stream[eMEDIATYPE_SUBTITLE].format;
2082 
2083  if (stream_format == FORMAT_SUBTITLE_MP4)
2084  {
2085  AAMPLOG_INFO("Subtitle seeking first PTS %02f", _this->aamp->GetFirstPTS());
2086  gst_element_seek_simple(GST_ELEMENT(source), GST_FORMAT_TIME, GST_SEEK_FLAG_NONE, _this->aamp->GetFirstPTS() * GST_SECOND);
2087  /* Perform a seek on the source, seeking relative to the start of the stream */
2088  }
2089  }
2090  return source;
2091 }
2092 
2093 /**
2094  * @brief Cleanup resources and flags for a particular stream type
2095  */
2097 {
2098  FN_TRACE( __FUNCTION__ );
2099  media_stream* stream = &privateContext->stream[mediaType];
2100  stream->bufferUnderrun = false;
2101  stream->eosReached = false;
2102  stream->flush = false;
2103  if (stream->format != FORMAT_INVALID)
2104  {
2105  pthread_mutex_lock(&stream->sourceLock);
2106  if (privateContext->pipeline)
2107  {
2108  privateContext->buffering_in_progress = false; /* stopping pipeline, don't want to change state if GST_MESSAGE_ASYNC_DONE message comes in */
2109  /* set the playbin state to NULL before detach it */
2110  if (stream->sinkbin)
2111  {
2112  if (GST_STATE_CHANGE_FAILURE == SetStateWithWarnings(GST_ELEMENT(stream->sinkbin), GST_STATE_NULL))
2113  {
2114  AAMPLOG_WARN("AAMPGstPlayer::TearDownStream: Failed to set NULL state for sinkbin");
2115  }
2116  if (!gst_bin_remove(GST_BIN(privateContext->pipeline), GST_ELEMENT(stream->sinkbin))) /* Removes the sinkbin element from the pipeline */
2117  {
2118  AAMPLOG_WARN("AAMPGstPlayer::TearDownStream: Unable to remove sinkbin from pipeline");
2119  }
2120  }
2121  else
2122  {
2123  AAMPLOG_WARN("AAMPGstPlayer::TearDownStream: sinkbin = NULL, skip remove sinkbin from pipeline");
2124  }
2125 
2126  if (stream->using_playersinkbin && stream->source)
2127  {
2128  if (GST_STATE_CHANGE_FAILURE == SetStateWithWarnings(GST_ELEMENT(stream->source), GST_STATE_NULL))
2129  {
2130  AAMPLOG_WARN("AAMPGstPlayer::TearDownStream: Failed to set NULL state for source");
2131  }
2132  if (!gst_bin_remove(GST_BIN(privateContext->pipeline), GST_ELEMENT(stream->source))) /* Removes the stream->source element from the pipeline */
2133  {
2134  AAMPLOG_WARN("AAMPGstPlayer::TearDownStream: Unable to remove source from pipeline");
2135  }
2136  }
2137  }
2138  //After sinkbin is removed from pipeline, a new decoder handle may be generated
2139  if (mediaType == eMEDIATYPE_VIDEO)
2140  {
2141  privateContext->decoderHandleNotified = false;
2142  }
2143  stream->format = FORMAT_INVALID;
2144  stream->sinkbin = NULL;
2145  stream->source = NULL;
2146  stream->sourceConfigured = false;
2147  pthread_mutex_unlock(&stream->sourceLock);
2148  }
2149  if (mediaType == eMEDIATYPE_VIDEO)
2150  {
2151  privateContext->video_dec = NULL;
2152 #if !defined(INTELCE) || defined(INTELCE_USE_VIDRENDSINK)
2153  privateContext->video_sink = NULL;
2154 #endif
2155 
2156 #ifdef INTELCE_USE_VIDRENDSINK
2157  privateContext->video_pproc = NULL;
2158 #endif
2159  }
2160  else if (mediaType == eMEDIATYPE_AUDIO)
2161  {
2162  privateContext->audio_dec = NULL;
2163  privateContext->audio_sink = NULL;
2164  }
2165  else if (mediaType == eMEDIATYPE_SUBTITLE)
2166  {
2167  privateContext->subtitle_sink = NULL;
2168  }
2169  AAMPLOG_WARN("AAMPGstPlayer::TearDownStream: exit mediaType = %d", mediaType);
2170 }
2171 
2172 #define NO_PLAYBIN 1
2173 /**
2174  * @brief Setup pipeline for a particular stream type
2175  * @param[in] _this pointer to AAMPGstPlayer instance
2176  * @param[in] streamId stream type
2177  * @retval 0, if setup successfully. -1, for failure
2178  */
2180 {
2181  media_stream* stream = &_this->privateContext->stream[streamId];
2182 
2183  if (!stream->using_playersinkbin)
2184  {
2185  if (eMEDIATYPE_SUBTITLE == streamId)
2186  {
2187  if(_this->aamp->mConfig->IsConfigSet(eAAMPConfig_GstSubtecEnabled))
2188  {
2189 #ifdef NO_PLAYBIN
2190  _this->aamp->StopTrackDownloads(eMEDIATYPE_SUBTITLE); /* Stop any ongoing downloads before setting up a new subtitle stream */
2191  AAMPLOG_INFO("AAMPGstPlayer_SetupStream - subs using subtecbin");
2192  stream->sinkbin = gst_element_factory_make("subtecbin", NULL); /* Creates a new element of "subtecbin" type and returns a new GstElement */
2193  if (!stream->sinkbin) /* When a new element can not be created a NULL is returned */
2194  {
2195  AAMPLOG_WARN("Cannot set up subtitle subtecbin");
2196  return -1;
2197  }
2198  g_object_set(G_OBJECT(stream->sinkbin), "sync", FALSE, NULL);
2199 
2201  gst_bin_add_many(GST_BIN(_this->privateContext->pipeline), stream->source, stream->sinkbin, NULL); /* Add source and sink to the current pipeline */
2202 
2203  if (!gst_element_link_many(stream->source, stream->sinkbin, NULL)) /* forms a GstElement link chain; linking stream->source to stream->sinkbin */
2204  {
2205  AAMPLOG_WARN("Failed to link subtitle elements");
2206  return -1;
2207  }
2208 
2209  gst_element_sync_state_with_parent(stream->source);
2210  gst_element_sync_state_with_parent(stream->sinkbin);
2211  _this->privateContext->subtitle_sink = stream->sinkbin;
2212  g_object_set(stream->sinkbin, "mute", _this->privateContext->subtitleMuted ? TRUE : FALSE, NULL);
2213 
2214  return 0;
2215 #else
2216  AAMPLOG_INFO("AAMPGstPlayer_SetupStream - subs using playbin");
2217  stream->sinkbin = gst_element_factory_make("playbin", NULL);
2218  auto vipertransform = gst_element_factory_make("vipertransform", NULL);
2219  auto textsink = gst_element_factory_make("subtecsink", NULL);
2220  auto subtitlebin = gst_bin_new("subtitlebin");
2221  gst_bin_add_many(GST_BIN(subtitlebin), vipertransform, textsink, NULL);
2222  gst_element_link(vipertransform, textsink);
2223  gst_element_add_pad(subtitlebin, gst_ghost_pad_new("sink", gst_element_get_static_pad(vipertransform, "sink")));
2224 
2225  g_object_set(stream->sinkbin, "text-sink", subtitlebin, NULL);
2226 #endif
2227  }
2228  }
2229  else
2230  {
2231  AAMPLOG_INFO("AAMPGstPlayer_SetupStream - using playbin"); /* Media is not subtitle, use the generic playbin */
2232  stream->sinkbin = gst_element_factory_make("playbin", NULL); /* Creates a new element of "playbin" type and returns a new GstElement */
2233  if (_this->privateContext->using_westerossink && eMEDIATYPE_VIDEO == streamId)
2234  {
2235  AAMPLOG_INFO("AAMPGstPlayer_SetupStream - using westerossink");
2236  GstElement* vidsink = gst_element_factory_make("westerossink", NULL);
2237 #if defined(BRCM) && defined(CONTENT_4K_SUPPORTED)
2238  g_object_set(vidsink, "secure-video", TRUE, NULL);
2239 #endif
2240  g_object_set(stream->sinkbin, "video-sink", vidsink, NULL); /* In the stream->sinkbin, set the video-sink property to vidsink */
2241  }
2242  else if (!_this->privateContext->using_westerossink && eMEDIATYPE_VIDEO == streamId)
2243  {
2244  GstElement* vidsink = gst_element_factory_make("brcmvideosink", NULL);
2245 #if defined(BRCM) && defined(CONTENT_4K_SUPPORTED)
2246  g_object_set(vidsink, "secure-video", TRUE, NULL);
2247 #endif
2248  g_object_set(stream->sinkbin, "video-sink", vidsink, NULL);
2249  }
2250 #ifdef RENDER_FRAMES_IN_APP_CONTEXT
2251  //else if(_this->cbExportYUVFrame)
2252  {
2253  if (eMEDIATYPE_VIDEO == streamId)
2254  {
2255  AAMPLOG_WARN("AAMPGstPlayer_SetupStream - using appsink\n");
2256  GstElement* appsink = gst_element_factory_make("appsink", NULL);
2257  assert(appsink);
2258  GstCaps *caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "I420", NULL);
2259  gst_app_sink_set_caps (GST_APP_SINK(appsink), caps);
2260  g_object_set (G_OBJECT (appsink), "emit-signals", TRUE, "sync", TRUE, NULL);
2261  g_signal_connect (appsink, "new-sample", G_CALLBACK (AAMPGstPlayer::AAMPGstPlayer_OnVideoSample), _this);
2262  g_object_set(stream->sinkbin, "video-sink", appsink, NULL);
2263  _this->privateContext->video_sink = appsink;
2264  }
2265  }
2266 #endif
2267  if (eMEDIATYPE_AUX_AUDIO == streamId)
2268  {
2269  // We need to route audio through audsrvsink
2270  GstElement *audiosink = gst_element_factory_make("audsrvsink", NULL); /* Creates a new element of "audsrvsink" type and returns a new GstElement */
2271  g_object_set(audiosink, "session-type", 2, NULL );
2272  g_object_set(audiosink, "session-name", "btSAP", NULL );
2273  g_object_set(audiosink, "session-private", TRUE, NULL );
2274 
2275  g_object_set(stream->sinkbin, "audio-sink", audiosink, NULL); /* In the stream->sinkbin, set the audio-sink property to audiosink */
2276  AAMPLOG_WARN("AAMPGstPlayer_SetupStream - using audsrvsink");
2277  }
2278  }
2279 #if defined(INTELCE) && !defined(INTELCE_USE_VIDRENDSINK)
2280  if (eMEDIATYPE_VIDEO == streamId)
2281  {
2282  AAMPLOG_WARN("using ismd_vidsink");
2283  GstElement* vidsink = _this->privateContext->video_sink;
2284  if(NULL == vidsink)
2285  {
2286  vidsink = gst_element_factory_make("ismd_vidsink", NULL);
2287  if(!vidsink)
2288  {
2289  AAMPLOG_WARN("Could not create ismd_vidsink element");
2290  }
2291  else
2292  {
2293  _this->privateContext->video_sink = GST_ELEMENT(gst_object_ref( vidsink));
2294  }
2295  }
2296  else
2297  {
2298  AAMPLOG_WARN("Reusing existing vidsink element");
2299  }
2300  AAMPLOG_WARN("Set video-sink %p to playbin %p", vidsink, stream->sinkbin);
2301  g_object_set(stream->sinkbin, "video-sink", vidsink, NULL);
2302  }
2303 #endif
2304  gst_bin_add(GST_BIN(_this->privateContext->pipeline), stream->sinkbin); /* Add the stream sink to the pipeline */
2305  gint flags;
2306  g_object_get(stream->sinkbin, "flags", &flags, NULL); /* Read the state of the current flags */
2307  AAMPLOG_WARN("playbin flags1: 0x%x", flags); // 0x617 on settop
2308 #if (defined(__APPLE__) || defined(NO_NATIVE_AV))
2310 #elif defined (REALTEKCE)
2312 #else
2314 #endif
2315  if (eMEDIATYPE_SUBTITLE == streamId) flags = GST_PLAY_FLAG_TEXT;
2316  g_object_set(stream->sinkbin, "flags", flags, NULL); // needed?
2317  MediaFormat mediaFormat = _this->aamp->GetMediaFormatTypeEnum(); /* Get the Media format type of current media */
2318  if((mediaFormat != eMEDIAFORMAT_PROGRESSIVE) || _this->aamp->mConfig->IsConfigSet(eAAMPConfig_UseAppSrcForProgressivePlayback))
2319  {
2320  g_object_set(stream->sinkbin, "uri", "appsrc://", NULL); /* Assign uri property to appsrc, this will enable data insertion into pipeline */
2321  g_signal_connect(stream->sinkbin, "deep-notify::source", G_CALLBACK(found_source), _this);
2322  }
2323  else
2324  {
2325  g_object_set(stream->sinkbin, "uri", _this->aamp->GetManifestUrl().c_str(), NULL);
2326  g_signal_connect (stream->sinkbin, "source-setup", G_CALLBACK (httpsoup_source_setup), _this);
2327  }
2328 
2329 #if defined(REALTEKCE)
2330  if (eMEDIATYPE_VIDEO == streamId && (mediaFormat==eMEDIAFORMAT_DASH || mediaFormat==eMEDIAFORMAT_HLS_MP4) )
2331  { // enable multiqueue (Refer : XIONE-6138)
2332  int MaxGstVideoBufBytes = 0;
2333  _this->aamp->mConfig->GetConfigValue(eAAMPConfig_GstVideoBufBytes,MaxGstVideoBufBytes);
2334  AAMPLOG_INFO("Setting gst Video buffer size bytes to %d", MaxGstVideoBufBytes);
2335  g_object_set(stream->sinkbin, "buffer-size", (guint64)MaxGstVideoBufBytes, NULL);
2336  g_object_set(stream->sinkbin, "buffer-duration", 3000000000, NULL); //3000000000(ns), 3s
2337  }
2338 #endif
2339  gst_element_sync_state_with_parent(stream->sinkbin);
2340  }
2341  else
2342  {
2343  //TODO: For auxiliary audio playback, when using playersinkbin, we might have to set some additional
2344  // properties, need to check
2345  stream->source = AAMPGstPlayer_GetAppSrc(_this, streamId);
2346  gst_bin_add(GST_BIN(_this->privateContext->pipeline), stream->source);
2347  gst_element_sync_state_with_parent(stream->source);
2348  stream->sinkbin = gst_element_factory_make("playersinkbin", NULL);
2349  if (NULL == stream->sinkbin)
2350  {
2351  AAMPLOG_WARN("AAMPGstPlayer_SetupStream Cannot create sink");
2352  return -1;
2353  }
2354  g_signal_connect(stream->sinkbin, "event-callback", G_CALLBACK(AAMPGstPlayer_PlayersinkbinCB), _this);
2355  gst_bin_add(GST_BIN(_this->privateContext->pipeline), stream->sinkbin);
2356  gst_element_link(stream->source, stream->sinkbin);
2357  if(!gst_element_link(stream->source, stream->sinkbin))
2358  {
2359  AAMPLOG_WARN("gst_element_link is error"); //CID:90331- checked return
2360  }
2361  gst_element_sync_state_with_parent(stream->sinkbin);
2362 
2363  AAMPLOG_WARN("AAMPGstPlayer_SetupStream: Created playersinkbin. Setting rectangle");
2364  g_object_set(stream->sinkbin, "rectangle", _this->privateContext->videoRectangle, NULL);
2365  g_object_set(stream->sinkbin, "zoom", _this->privateContext->zoom, NULL);
2366  g_object_set(stream->sinkbin, "video-mute", _this->privateContext->videoMuted, NULL);
2367  g_object_set(stream->sinkbin, "volume", _this->privateContext->audioVolume, NULL);
2368  }
2369  return 0;
2370 }
2371 
2372 /**
2373  * @fn RecalculatePTS
2374  * @param[in] mediaType stream type
2375  * @param[in] ptr buffer pointer
2376  * @param[in] len length of buffer
2377  */
2378 double AAMPGstPlayer::RecalculatePTS(MediaType mediaType, const void *ptr, size_t len)
2379 {
2380  double ret = 0;
2381  uint32_t timeScale = 0;
2382 
2383  if(mediaType == eMEDIATYPE_VIDEO)
2384  {
2385  timeScale = aamp->GetVidTimeScale();
2386  }
2387  else if(mediaType == eMEDIATYPE_AUDIO || mediaType == eMEDIATYPE_AUX_AUDIO)
2388  {
2389  timeScale = aamp->GetAudTimeScale();
2390  }
2391 
2392 
2393  IsoBmffBuffer isobuf(mLogObj);
2394  isobuf.setBuffer((uint8_t *)ptr, len);
2395  bool bParse = false;
2396  try
2397  {
2398  bParse = isobuf.parseBuffer();
2399  }
2400  catch( std::bad_alloc& ba)
2401  {
2402  AAMPLOG_ERR("Bad allocation: %s", ba.what() );
2403  }
2404  catch( std::exception &e)
2405  {
2406  AAMPLOG_ERR("Unhandled exception: %s", e.what() );
2407  }
2408  catch( ... )
2409  {
2410  AAMPLOG_ERR("Unknown exception");
2411  }
2412  if(bParse && (0 != timeScale))
2413  {
2414  uint64_t fPts = 0;
2415  bool bParse = isobuf.getFirstPTS(fPts);
2416  if (bParse)
2417  {
2418  ret = fPts/(timeScale*1.0);
2419  AAMPLOG_TRACE("restamped PTS : %lf", ret);
2420  }
2421  }
2422  return ret;
2423 }
2424 
2425 /**
2426  * @fn SendGstEvents
2427  * @param[in] mediaType stream type
2428  * @param[in] pts PTS of next buffer
2429  * @param[in] ptr buffer pointer
2430  * @param[in] len length of buffer
2431  */
2432 void AAMPGstPlayer::SendGstEvents(MediaType mediaType, GstClockTime pts, const void *ptr, size_t len)
2433 {
2434  media_stream* stream = &privateContext->stream[mediaType];
2435  gboolean enableOverride = FALSE;
2436  GstPad* sourceEleSrcPad = gst_element_get_static_pad(GST_ELEMENT(stream->source), "src"); /* Retrieves the src pad */
2437  if(stream->flush)
2438  {
2439  AAMPLOG_WARN("flush pipeline");
2440  gboolean ret = gst_pad_push_event(sourceEleSrcPad, gst_event_new_flush_start()); /* Allocates a new flush event and pushes it into the sourceEleSrcPad*/
2441  if (!ret) AAMPLOG_WARN("flush start error");
2442  GstEvent* event = gst_event_new_flush_stop(FALSE);
2443  ret = gst_pad_push_event(sourceEleSrcPad, event);
2444  if (!ret) AAMPLOG_WARN("flush stop error");
2445  stream->flush = false;
2446  }
2447 
2448  if (stream->format == FORMAT_ISO_BMFF && mediaType != eMEDIATYPE_SUBTITLE)
2449  {
2450 #ifdef ENABLE_AAMP_QTDEMUX_OVERRIDE
2451  enableOverride = TRUE;
2452 #else
2453  enableOverride = (privateContext->rate != AAMP_NORMAL_PLAY_RATE);
2454 #endif
2455  /* The below statement creates a new eventStruct with the name 'aamp_override' and sets its three variables as follows:-
2456  1) the variable 'enable' has datatype of G_TYPE_BOOLEAN and has value enableOverride.
2457  2) the variable 'rate' has datatype of G_TYPE_FLOAT and is set to (float)privateContext->rate.
2458  3) the variable 'aampplayer' has datatype of G_TYPE_BOOLEAN and a value of TRUE.
2459  */
2460  GstStructure * eventStruct = gst_structure_new("aamp_override", "enable", G_TYPE_BOOLEAN, enableOverride, "rate", G_TYPE_FLOAT, (float)privateContext->rate, "aampplayer", G_TYPE_BOOLEAN, TRUE, NULL);
2461 #ifdef ENABLE_AAMP_QTDEMUX_OVERRIDE
2462  if ( privateContext->rate == AAMP_NORMAL_PLAY_RATE )
2463  {
2464  guint64 basePTS = aamp->GetFirstPTS() * GST_SECOND;
2465  if(0 == basePTS)
2466  {
2467  basePTS = RecalculatePTS(mediaType, ptr, len) * GST_SECOND;
2468  }
2469  AAMPLOG_WARN("Set override event's basePTS [ %" G_GUINT64_FORMAT "]", basePTS);
2470  gst_structure_set (eventStruct, "basePTS", G_TYPE_UINT64, basePTS, NULL);
2471  }
2472 #endif
2473  if (!gst_pad_push_event(sourceEleSrcPad, gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, eventStruct)))
2474  {
2475  AAMPLOG_WARN("Error on sending rate override event");
2476  }
2477  }
2478 
2479  if (mediaType == eMEDIATYPE_VIDEO)
2480  {
2481  // DELIA-39530 - Westerossink gives position as an absolute value from segment.start. In AAMP's GStreamer pipeline
2482  // appsrc's base class - basesrc sends an additional segment event since we performed a flushing seek.
2483  // To figure out the new segment.start, we need to send a segment query which will be replied
2484  // by basesrc to get the updated segment event values.
2485  // When override is enabled qtdemux internally restamps and sends segment.start = 0 which is part of
2486  // AAMP's change in qtdemux so we don't need to query segment.start
2487  // Enabling position query based progress reporting for non-westerossink configurations
2488  if (ISCONFIGSET(eAAMPConfig_EnableGstPositionQuery) && enableOverride == FALSE)
2489  {
2490  privateContext->segmentStart = -1;
2491  }
2492  else
2493  {
2494  privateContext->segmentStart = 0;
2495  }
2496  }
2497 
2498  if (stream->format == FORMAT_ISO_BMFF)
2499  {
2500  // There is a possibility that only single protection event is queued for multiple type
2501  // since they are encrypted using same id. Hence check if proection event is queued for
2502  // other types
2503  GstEvent* event = privateContext->protectionEvent[mediaType];
2504  if (event == NULL)
2505  {
2506  // Check protection event for other types
2507  for (int i = 0; i < AAMP_TRACK_COUNT; i++)
2508  {
2509  if (i != mediaType && privateContext->protectionEvent[i] != NULL)
2510  {
2511  event = privateContext->protectionEvent[i];
2512  break;
2513  }
2514  }
2515  }
2516  if(event)
2517  {
2518  AAMPLOG_WARN("pushing protection event! mediatype: %d", mediaType);
2519  if (!gst_pad_push_event(sourceEleSrcPad, gst_event_ref(event)))
2520  {
2521  AAMPLOG_WARN("push protection event failed!");
2522  }
2523  }
2524  }
2525 #ifdef INTELCE
2526  if (!gst_pad_push_event(sourceEleSrcPad, gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, gst_structure_new("discard-segment-event-with-zero-start", "enable", G_TYPE_BOOLEAN, TRUE, NULL))))
2527  {
2528  AAMPLOG_WARN("Error on sending discard-segment-event-with-zero-start custom event");
2529  }
2530 #endif
2531 
2532  gst_object_unref(sourceEleSrcPad);
2533  stream->resetPosition = false;
2534  stream->flush = false;
2535 }
2536 
2537 
2538 /**
2539  * @fn hasId3Header
2540  * @brief Check if segment starts with an ID3 section
2541  * @param[in] data pointer to segment buffer
2542  * @param[in] length length of segment buffer
2543  * @retval true if segment has an ID3 section
2544  */
2545 bool hasId3Header(MediaType mediaType, const uint8_t* data, int32_t length)
2546 {
2547  if ((mediaType == eMEDIATYPE_AUDIO || mediaType == eMEDIATYPE_VIDEO || mediaType == eMEDIATYPE_DSM_CC)
2548  && length >= 3)
2549  {
2550  /* Check file identifier ("ID3" = ID3v2) and major revision matches (>= ID3v2.2.x). */
2551  /* The ID3 header has first three bytes as "ID3" and in the next two bytes first byte is the major version and second byte is its revision number */
2552  if (*data++ == 'I' && *data++ == 'D' && *data++ == '3' && *data++ >= 2)
2553  {
2554  return true;
2555  }
2556  }
2557 
2558  return false;
2559 }
2560 
2561 #define ID3_HEADER_SIZE 10 /**< Header size for ID3v2 header */
2562 
2563 /**
2564  * @fn getId3TagSize
2565  * @brief Get the size of the ID3v2 tag.
2566  * @param[in] data buffer pointer
2567  * @retval size of ID3 tag or 0 for bad header format
2568  */
2569 uint32_t getId3TagSize(const uint8_t *data)
2570 {
2571  uint32_t bufferSize = 0;
2572  uint8_t tagSize[4];
2573 
2574  memcpy(tagSize, data+6, 4);
2575 
2576  // bufferSize is encoded as a syncsafe integer - this means that bit 7 is always zeroed
2577  // Check for any 1s in bit 7
2578  if (tagSize[0] > 0x7f || tagSize[1] > 0x7f || tagSize[2] > 0x7f || tagSize[3] > 0x7f)
2579  {
2580  AAMPLOG_WARN("Bad header format");
2581  return 0;
2582  }
2583 
2584  bufferSize = tagSize[0] << 21;
2585  bufferSize += tagSize[1] << 14;
2586  bufferSize += tagSize[2] << 7;
2587  bufferSize += tagSize[3];
2588  bufferSize += ID3_HEADER_SIZE;
2589 
2590  return bufferSize;
2591 }
2592 
2593 /**
2594  * @brief Send new segment event to pipeline
2595  */
2596 void AAMPGstPlayer::SendNewSegmentEvent(MediaType mediaType, GstClockTime startPts ,GstClockTime stopPts)
2597 {
2598  FN_TRACE( __FUNCTION__ );
2599  media_stream* stream = &privateContext->stream[mediaType];
2600  GstPad* sourceEleSrcPad = gst_element_get_static_pad(GST_ELEMENT(stream->source), "src");
2601  if (stream->format == FORMAT_ISO_BMFF)
2602  {
2603  GstSegment segment;
2604  gst_segment_init(&segment, GST_FORMAT_TIME);
2605 
2606  segment.start = startPts;
2607  segment.position = 0;
2608  segment.rate = AAMP_NORMAL_PLAY_RATE;
2609  segment.applied_rate = AAMP_NORMAL_PLAY_RATE;
2610  if(stopPts) segment.stop = stopPts;
2611 
2612 #if defined(AMLOGIC)
2613  //AMLOGIC-2143 notify westerossink of rate to run in Vmaster mode
2614  if (mediaType == eMEDIATYPE_VIDEO)
2615  segment.applied_rate = privateContext->rate;
2616 #endif
2617 
2618  AAMPLOG_INFO("Sending segment event for mediaType[%d]. start %" G_GUINT64_FORMAT " stop %" G_GUINT64_FORMAT" rate %f applied_rate %f", mediaType, segment.start, segment.stop, segment.rate, segment.applied_rate);
2619  GstEvent* event = gst_event_new_segment (&segment);
2620  if (!gst_pad_push_event(sourceEleSrcPad, event))
2621  {
2622  AAMPLOG_ERR("gst_pad_push_event segment error");
2623  }
2624  }
2625 }
2626 
2627 /**
2628  * @brief Inject stream buffer to gstreamer pipeline
2629  */
2630 bool AAMPGstPlayer::SendHelper(MediaType mediaType, const void *ptr, size_t len, double fpts, double fdts, double fDuration, bool copy, bool initFragment)
2631 {
2633  {
2634  if( privateContext->numberOfVideoBuffersSent == 0 )
2635  { // required in order for subtitle harvesting/processing to work
2636  privateContext->numberOfVideoBuffersSent++;
2637  aamp->UpdateSubtitleTimestamp();
2638  }
2639  return false;
2640  }
2641  FN_TRACE( __FUNCTION__ );
2642  GstClockTime pts = (GstClockTime)(fpts * GST_SECOND);
2643  GstClockTime dts = (GstClockTime)(fdts * GST_SECOND);
2644  GstClockTime duration = (GstClockTime)(fDuration * 1000000000LL);
2645 
2647  hasId3Header(mediaType, static_cast<const uint8_t*>(ptr), len))
2648  {
2649  uint32_t len = getId3TagSize(static_cast<const uint8_t*>(ptr));
2650  if (len && (len != aamp->lastId3DataLen[mediaType] ||
2651  !aamp->lastId3Data[mediaType] ||
2652  (memcmp(ptr, aamp->lastId3Data[mediaType], aamp->lastId3DataLen[mediaType]) != 0)))
2653  {
2654  AAMPLOG_INFO("AAMPGstPlayer: Found new ID3 frame");
2655  aamp->ReportID3Metadata(mediaType, static_cast<const uint8_t*>(ptr), len);
2656  }
2657  }
2658 
2659  // Ignore eMEDIATYPE_DSM_CC packets
2660  if(mediaType == eMEDIATYPE_DSM_CC)
2661  {
2662  return false;
2663  }
2664 
2665  media_stream *stream = &privateContext->stream[mediaType];
2666  bool isFirstBuffer = stream->resetPosition;
2667  // Flag to wait sending Gst events until receiving a valid buffer for PTS restamping. HLS mp4 already has PTS restamping.
2668  bool waitForPtsRestamp = ((eMEDIAFORMAT_DASH == aamp->mMediaFormat) && (initFragment) && (0 == aamp->GetFirstPTS()));
2669  // Make sure source element is present before data is injected
2670  // If format is FORMAT_INVALID, we don't know what we are doing here
2671  pthread_mutex_lock(&stream->sourceLock);
2672 
2673  if (!stream->sourceConfigured && stream->format != FORMAT_INVALID)
2674  {
2675  bool status = WaitForSourceSetup(mediaType);
2676 
2677  if (!aamp->DownloadsAreEnabled() || !status)
2678  {
2679  pthread_mutex_unlock(&stream->sourceLock);
2680  return false;
2681  }
2682  }
2683  if (isFirstBuffer && !waitForPtsRestamp)
2684  {
2685  //Send Gst Event when first buffer received after new tune, seek or period change
2686  SendGstEvents(mediaType, pts, ptr, len);
2687 
2688  if (mediaType == eMEDIATYPE_AUDIO && ForwardAudioBuffersToAux())
2689  {
2690  SendGstEvents(eMEDIATYPE_AUX_AUDIO, pts, ptr, len);
2691  }
2692 
2693 #if defined(AMLOGIC)
2694  // AMLOGIC-3130: included to fix av sync / trickmode speed issues in LLAMA-4291
2695  // LLAMA-6788 - Also add check for trick-play on 1st frame.
2696  if(!aamp->mbNewSegmentEvtSent[mediaType] || (mediaType == eMEDIATYPE_VIDEO && aamp->rate != AAMP_NORMAL_PLAY_RATE))
2697  {
2698  SendNewSegmentEvent(mediaType, pts ,0);
2699  aamp->mbNewSegmentEvtSent[mediaType]=true;
2700  }
2701 #endif
2702 
2703  AAMPLOG_TRACE("mediaType[%d] SendGstEvents - first buffer received !!! initFragment: %d", mediaType, initFragment);
2704  }
2705 
2706 
2707  if( aamp->DownloadsAreEnabled())
2708  {
2709  GstBuffer *buffer;
2710  bool bPushBuffer = true;
2711 
2712  if(copy)
2713  {
2714  buffer = gst_buffer_new_and_alloc((guint)len);
2715 
2716  if (buffer)
2717  {
2718  GstMapInfo map;
2719  gst_buffer_map(buffer, &map, GST_MAP_WRITE);
2720  memcpy(map.data, ptr, len);
2721  gst_buffer_unmap(buffer, &map);
2722  GST_BUFFER_PTS(buffer) = pts;
2723  GST_BUFFER_DTS(buffer) = dts;
2724  GST_BUFFER_DURATION(buffer) = duration;
2725  AAMPLOG_TRACE("Sending segment for mediaType[%d]. pts %" G_GUINT64_FORMAT " dts %" G_GUINT64_FORMAT" ", mediaType, pts, dts);
2726  }
2727  else
2728  {
2729  bPushBuffer = false;
2730  }
2731  }
2732  else
2733  { // transfer
2734  buffer = gst_buffer_new_wrapped((gpointer)ptr,(gsize)len);
2735 
2736  if (buffer)
2737  {
2738  GST_BUFFER_PTS(buffer) = pts;
2739  GST_BUFFER_DTS(buffer) = dts;
2740  GST_BUFFER_DURATION(buffer) = duration;
2741  AAMPLOG_TRACE("Sending segment for mediaType[%d]. pts %" G_GUINT64_FORMAT " dts %" G_GUINT64_FORMAT" ", mediaType, pts, dts);
2742  }
2743  else
2744  {
2745  bPushBuffer = false;
2746  }
2747  }
2748 
2749  if (bPushBuffer)
2750  {
2751  if (mediaType == eMEDIATYPE_AUDIO && ForwardAudioBuffersToAux())
2752  {
2754  }
2755 
2756  GstFlowReturn ret = gst_app_src_push_buffer(GST_APP_SRC(stream->source), buffer);
2757 
2758  if (ret != GST_FLOW_OK)
2759  {
2760  AAMPLOG_WARN("gst_app_src_push_buffer error: %d[%s] mediaType %d", ret, gst_flow_get_name (ret), (int)mediaType);
2761  if (ret != GST_FLOW_EOS && ret != GST_FLOW_FLUSHING)
2762  assert(false);
2763  }
2764  else if (stream->bufferUnderrun)
2765  {
2766  stream->bufferUnderrun = false;
2767  }
2768 
2769  // PROFILE_BUCKET_FIRST_BUFFER after successfull push of first gst buffer
2770  if (isFirstBuffer == true && ret == GST_FLOW_OK)
2771  this->aamp->profiler.ProfilePerformed(PROFILE_BUCKET_FIRST_BUFFER);
2772  }
2773  }
2774 
2775  pthread_mutex_unlock(&stream->sourceLock);
2776 
2777  if (eMEDIATYPE_VIDEO == mediaType)
2778  {
2779  // HACK!
2780  // DELIA-42262: For westerossink, it will send first-video-frame-callback signal after each flush
2781  // So we can move NotifyFirstBufferProcessed to the more accurate signal callback
2782  if (isFirstBuffer)
2783  {
2784  if (!privateContext->using_westerossink)
2785  {
2787  }
2788 
2789 #ifdef REALTEKCE // HACK: Have this hack until reakteck Westeros fixes missing first frame call back missing during trick play.
2790  aamp->ResetTrickStartUTCTime();
2791 #endif
2792  }
2793 
2794  privateContext->numberOfVideoBuffersSent++;
2795 
2796  StopBuffering(false);
2797  }
2798 
2799  return true;
2800 }
2801 
2802 /**
2803  * @brief inject HLS/ts elementary stream buffer to gstreamer pipeline
2804  */
2805 bool AAMPGstPlayer::SendCopy(MediaType mediaType, const void *ptr, size_t len, double fpts, double fdts, double fDuration)
2806 {
2807  FN_TRACE( __FUNCTION__ );
2808  return SendHelper( mediaType, ptr, len, fpts, fdts, fDuration, true /*copy*/ );
2809 }
2810 
2811 /**
2812  * @brief inject mp4 segment to gstreamer pipeline
2813  */
2814 bool AAMPGstPlayer::SendTransfer(MediaType mediaType, void *ptr, size_t len, double fpts, double fdts, double fDuration, bool initFragment)
2815 
2816 {
2817  FN_TRACE( __FUNCTION__ );
2818  return SendHelper( mediaType, ptr, len, fpts, fdts, fDuration, false /*transfer*/, initFragment );
2819 }
2820 
2821 /**
2822  * @brief To start playback
2823  */
2825 {
2826  FN_TRACE( __FUNCTION__ );
2827 }
2828 
2829 
2830 /**
2831  * @brief Configure pipeline based on A/V formats
2832  */
2833 void AAMPGstPlayer::Configure(StreamOutputFormat format, StreamOutputFormat audioFormat, StreamOutputFormat auxFormat, StreamOutputFormat subFormat, bool bESChangeStatus, bool forwardAudioToAux, bool setReadyAfterPipelineCreation)
2834 {
2835  FN_TRACE( __FUNCTION__ );
2836  AAMPLOG_WARN("videoFormat %d audioFormat %d auxFormat %d subFormat %d",format, audioFormat, auxFormat, subFormat);
2838  newFormat[eMEDIATYPE_VIDEO] = format;
2839  newFormat[eMEDIATYPE_AUDIO] = audioFormat;
2840 
2841  if(ISCONFIGSET(eAAMPConfig_GstSubtecEnabled)) /* Ignore the sub titles if Subtec is not enabled */
2842  {
2843  newFormat[eMEDIATYPE_SUBTITLE] = subFormat;
2844  AAMPLOG_WARN("Gstreamer subs enabled");
2845  }
2846  else
2847  {
2849  AAMPLOG_WARN("Gstreamer subs disabled");
2850  }
2851 
2852  /* Enable sending of audio data to the auxiliary output */
2853  if (forwardAudioToAux)
2854  {
2855  AAMPLOG_WARN("AAMPGstPlayer: Override auxFormat %d -> %d", auxFormat, audioFormat);
2856  privateContext->forwardAudioBuffers = true;
2857  newFormat[eMEDIATYPE_AUX_AUDIO] = audioFormat;
2858  }
2859  else
2860  {
2861  privateContext->forwardAudioBuffers = false;
2862  newFormat[eMEDIATYPE_AUX_AUDIO] = auxFormat;
2863  }
2864 
2866  {
2867  privateContext->using_westerossink = false;
2868 #if defined(REALTEKCE)
2869  privateContext->firstTuneWithWesterosSinkOff = true;
2870 #endif
2871  }
2872  else
2873  {
2874  privateContext->using_westerossink = true;
2875  }
2876 
2877 #ifdef AAMP_STOP_SINK_ON_SEEK
2878  privateContext->rate = aamp->rate;
2879 #endif
2880 
2881  if (privateContext->pipeline == NULL || privateContext->bus == NULL)
2882  {
2883  CreatePipeline(); /* Create a new pipeline if pipeline or the message bus does not exist */
2884  }
2885 
2886  if (setReadyAfterPipelineCreation)
2887  {
2888  if(SetStateWithWarnings(this->privateContext->pipeline, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE)
2889  {
2890  AAMPLOG_ERR("AAMPGstPlayer_Configure GST_STATE_READY failed on forceful set");
2891  }
2892  else
2893  {
2894  AAMPLOG_INFO("Forcefully set pipeline to ready state due to track_id change");
2895  PipelineSetToReady = true;
2896  }
2897  }
2898 
2899  bool configureStream[AAMP_TRACK_COUNT];
2900  memset(configureStream, 0, sizeof(configureStream));
2901 
2902  for (int i = 0; i < AAMP_TRACK_COUNT; i++)
2903  {
2904  media_stream *stream = &privateContext->stream[i];
2905  if (stream->format != newFormat[i])
2906  {
2907  if (newFormat[i] != FORMAT_INVALID)
2908  {
2909  AAMPLOG_WARN("Closing stream %d old format = %d, new format = %d",
2910  i, stream->format, newFormat[i]);
2911  configureStream[i] = true;
2912  privateContext->NumberOfTracks++;
2913  }
2914  }
2915 
2916 #if defined(__APPLE__) || defined(UBUNTU)
2917  if (this->privateContext->rate > 1 || this->privateContext->rate < 0)
2918  {
2919  if (eMEDIATYPE_VIDEO == i)
2920  configureStream[i] = true;
2921  else
2922  {
2924  configureStream[i] = false;
2925  }
2926  }
2927 #endif
2928 
2929  /* Force configure the bin for mid stream audio type change */
2930  if (!configureStream[i] && bESChangeStatus && (eMEDIATYPE_AUDIO == i))
2931  {
2932  AAMPLOG_WARN("AudioType Changed. Force configure pipeline");
2933  configureStream[i] = true;
2934  }
2935 
2936  stream->resetPosition = true;
2937  stream->eosReached = false;
2938  }
2939 
2940  for (int i = 0; i < AAMP_TRACK_COUNT; i++)
2941  {
2942  media_stream *stream = &privateContext->stream[i];
2943 
2944  if ((configureStream[i] && (newFormat[i] != FORMAT_INVALID)) ||
2945  /* Allow to create audio pipeline along with video pipeline if trickplay initiated before the pipeline going to play/paused state to fix unthrottled trickplay */
2946  (trickTeardown && (eMEDIATYPE_AUDIO == i)))
2947  {
2948  trickTeardown = false;
2950  stream->format = newFormat[i];
2951  stream->trackId = aamp->GetCurrentAudioTrackId();
2952  #ifdef USE_PLAYERSINKBIN
2953  if (FORMAT_MPEGTS == stream->format )
2954  {
2955  AAMPLOG_WARN("using playersinkbin, track = %d", i);
2956  stream->using_playersinkbin = TRUE;
2957  }
2958  else
2959  #endif
2960  {
2961  stream->using_playersinkbin = FALSE;
2962  }
2963  if (0 != AAMPGstPlayer_SetupStream(this, (MediaType)i)) /* Sets up the stream for the given MediaType */
2964  {
2965  AAMPLOG_WARN("AAMPGstPlayer: track %d failed", i);
2966  //Don't kill the tune for subtitles
2967  if (eMEDIATYPE_SUBTITLE != (MediaType)i)
2968  {
2969  return;
2970  }
2971  }
2972  }
2973  }
2974 
2975  /* If buffering is enabled, set the pipeline in Paused state, once sufficient content has been buffered the pipeline will be set to GST_STATE_PLAYING */
2976  if (this->privateContext->buffering_enabled && format != FORMAT_INVALID && AAMP_NORMAL_PLAY_RATE == privateContext->rate)
2977  {
2978  this->privateContext->buffering_target_state = GST_STATE_PLAYING;
2979  this->privateContext->buffering_in_progress = true;
2980  this->privateContext->buffering_timeout_cnt = DEFAULT_BUFFERING_MAX_CNT;
2981  if (SetStateWithWarnings(this->privateContext->pipeline, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE)
2982  {
2983  AAMPLOG_WARN("AAMPGstPlayer_Configure GST_STATE_PLAUSED failed");
2984  }
2985  privateContext->pendingPlayState = false;
2986  }
2987  else
2988  {
2989  if (SetStateWithWarnings(this->privateContext->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE)
2990  {
2991  AAMPLOG_WARN("AAMPGstPlayer: GST_STATE_PLAYING failed");
2992  }
2993  privateContext->pendingPlayState = false;
2994  }
2995  privateContext->eosSignalled = false;
2996  privateContext->numberOfVideoBuffersSent = 0;
2997  privateContext->paused = false;
2998  privateContext->decodeErrorMsgTimeMS = 0;
2999  privateContext->decodeErrorCBCount = 0;
3000 #ifdef TRACE
3001  AAMPLOG_WARN("exiting AAMPGstPlayer");
3002 #endif
3003 }
3004 
3005 
3006 /**
3007  * @fn AAMPGstPlayer_SignalEOS
3008  * @brief To signal EOS to a particular appsrc instance
3009  * @param[in] source pointer to appsrc instance
3010  */
3011 static void AAMPGstPlayer_SignalEOS(GstElement *source )
3012 {
3013  if (source )
3014  {
3015  GstFlowReturn ret;
3016  g_signal_emit_by_name(source, "end-of-stream", &ret); /* Emits "end-of-stream" signal from the source */
3017  if (ret != GST_FLOW_OK)
3018  {
3019  AAMPLOG_WARN("gst_app_src_push_buffer error: %d", ret);
3020  }
3021  }
3022 }
3023 
3024 /**
3025  * @brief Starts processing EOS for a particular stream type
3026  */
3028 {
3029  FN_TRACE( __FUNCTION__ );
3030  AAMPLOG_WARN("entering AAMPGstPlayer_EndOfStreamReached type %d", (int)type);
3031 
3032  media_stream *stream = &privateContext->stream[type];
3033  stream->eosReached = true;
3034  if ((stream->format != FORMAT_INVALID) && stream->resetPosition == true)
3035  {
3036  AAMPLOG_WARN("EOS received as first buffer ");
3037  NotifyEOS();
3038  }
3039  else
3040  {
3041  NotifyFragmentCachingComplete(); /*Set pipeline to PLAYING state once fragment caching is complete*/
3043 
3044  /*For trickmodes, give EOS to audio source*/
3045  if (AAMP_NORMAL_PLAY_RATE != privateContext->rate)
3046  {
3047  AAMPGstPlayer_SignalEOS(privateContext->stream[eMEDIATYPE_AUDIO].source);
3048  if (privateContext->stream[eMEDIATYPE_SUBTITLE].source)
3049  {
3050  AAMPGstPlayer_SignalEOS(privateContext->stream[eMEDIATYPE_SUBTITLE].source);
3051  }
3052  }
3053  else
3054  {
3055  if ((privateContext->stream[eMEDIATYPE_AUDIO].eosReached) &&
3056  (!privateContext->stream[eMEDIATYPE_SUBTITLE].eosReached) &&
3057  (privateContext->stream[eMEDIATYPE_SUBTITLE].source))
3058  {
3059  privateContext->stream[eMEDIATYPE_SUBTITLE].eosReached = true;
3060  AAMPGstPlayer_SignalEOS(privateContext->stream[eMEDIATYPE_SUBTITLE].source);
3061  }
3062  }
3063 
3064  // We are in buffering, but we received end of stream, un-pause pipeline
3065  StopBuffering(true);
3066  }
3067 }
3068 
3069 /**
3070  * @brief Stop playback and any idle handlers active at the time
3071  */
3072 void AAMPGstPlayer::Stop(bool keepLastFrame)
3073 {
3074  FN_TRACE( __FUNCTION__ );
3075  AAMPLOG_WARN("entering AAMPGstPlayer_Stop keepLastFrame %d", keepLastFrame);
3076 
3077  //XIONE-8595 - make the execution of this function more deterministic and reduce scope for potential pipeline lockups
3078  gst_bus_remove_watch(privateContext->bus); /* Remove the watch from bus so that gstreamer no longer sends messages to it */
3079 
3080 #ifdef INTELCE
3081  if (privateContext->video_sink)
3082  {
3083  privateContext->keepLastFrame = keepLastFrame;
3084  g_object_set(privateContext->video_sink, "stop-keep-frame", keepLastFrame, NULL);
3085 #if !defined(INTELCE_USE_VIDRENDSINK)
3086  if (!keepLastFrame)
3087  {
3088  gst_object_unref(privateContext->video_sink);
3089  privateContext->video_sink = NULL;
3090  }
3091  else
3092  {
3093  g_object_set(privateContext->video_sink, "reuse-vidrend", keepLastFrame, NULL);
3094  }
3095 #endif
3096  }
3097 #endif
3098  if(!keepLastFrame)
3099  {
3100  privateContext->firstFrameReceived = false;
3101  privateContext->firstVideoFrameReceived = false;
3102  privateContext->firstAudioFrameReceived = false ;
3103  }
3104 
3105  this->IdleTaskRemove(privateContext->firstProgressCallbackIdleTask); /* removes firstProgressCallbackIdleTask in a thread safe manner */
3106 
3107  this->TimerRemove(this->privateContext->periodicProgressCallbackIdleTaskId, "periodicProgressCallbackIdleTaskId"); /* Removes the timer with the id of periodicProgressCallbackIdleTaskId */
3108 
3109  if (this->privateContext->bufferingTimeoutTimerId)
3110  {
3111  AAMPLOG_WARN("AAMPGstPlayer: Remove bufferingTimeoutTimerId %d", privateContext->bufferingTimeoutTimerId);
3112  g_source_remove(privateContext->bufferingTimeoutTimerId);
3113  privateContext->bufferingTimeoutTimerId = AAMP_TASK_ID_INVALID;
3114  }
3115  if (privateContext->ptsCheckForEosOnUnderflowIdleTaskId)
3116  {
3117  AAMPLOG_WARN("AAMPGstPlayer: Remove ptsCheckForEosCallbackIdleTaskId %d", privateContext->ptsCheckForEosOnUnderflowIdleTaskId);
3118  g_source_remove(privateContext->ptsCheckForEosOnUnderflowIdleTaskId);
3119  privateContext->ptsCheckForEosOnUnderflowIdleTaskId = AAMP_TASK_ID_INVALID;
3120  }
3121  if (this->privateContext->eosCallbackIdleTaskPending)
3122  {
3123  AAMPLOG_WARN("AAMPGstPlayer: Remove eosCallbackIdleTaskId %d", privateContext->eosCallbackIdleTaskId);
3124  aamp->RemoveAsyncTask(privateContext->eosCallbackIdleTaskId);
3125  privateContext->eosCallbackIdleTaskPending = false;
3126  privateContext->eosCallbackIdleTaskId = AAMP_TASK_ID_INVALID;
3127  }
3128  if (this->privateContext->firstFrameCallbackIdleTaskPending)
3129  {
3130  AAMPLOG_WARN("AAMPGstPlayer: Remove firstFrameCallbackIdleTaskId %d", privateContext->firstFrameCallbackIdleTaskId);
3131  aamp->RemoveAsyncTask(privateContext->firstFrameCallbackIdleTaskId);
3132  privateContext->firstFrameCallbackIdleTaskPending = false;
3133  privateContext->firstFrameCallbackIdleTaskId = AAMP_TASK_ID_INVALID;
3134  }
3135  if (this->privateContext->firstVideoFrameDisplayedCallbackIdleTaskPending)
3136  {
3137  AAMPLOG_WARN("AAMPGstPlayer: Remove firstVideoFrameDisplayedCallbackIdleTaskId %d", privateContext->firstVideoFrameDisplayedCallbackIdleTaskId);
3139  privateContext->firstVideoFrameDisplayedCallbackIdleTaskPending = false;
3140  privateContext->firstVideoFrameDisplayedCallbackIdleTaskId = AAMP_TASK_ID_INVALID;
3141  }
3142  if (this->privateContext->pipeline)
3143  {
3144  privateContext->buffering_in_progress = false; /* stopping pipeline, don't want to change state if GST_MESSAGE_ASYNC_DONE message comes in */
3145  SetStateWithWarnings(this->privateContext->pipeline, GST_STATE_NULL);
3146  AAMPLOG_WARN("AAMPGstPlayer: Pipeline state set to null");
3147  }
3148 #ifdef AAMP_MPD_DRM
3150  {
3152  pInstance->setGstElement((GstElement *)(NULL));
3153  pInstance->Release();
3154  }
3155 #endif
3160  DestroyPipeline();
3161  privateContext->rate = AAMP_NORMAL_PLAY_RATE;
3162  privateContext->lastKnownPTS = 0;
3163  privateContext->segmentStart = 0;
3164  privateContext->paused = false;
3165  privateContext->pipelineState = GST_STATE_NULL;
3166  AAMPLOG_WARN("exiting AAMPGstPlayer_Stop");
3167 }
3168 
3169 /**
3170  * @brief Generates a state description for gst target, next and pending state i.e. **not current state**.
3171  * @param[in] state - the state of the current element
3172  * @param[in] start - a char to place before the state text e.g. on open bracket
3173  * @param[in] end - a char to place after the state text e.g. a close bracket
3174  * @param[in] currentState - the current state from the same element as 'state'
3175  * @param[in] parentState - the state of the parent, if there is one
3176  * @return - "" unless state is 'interesting' otherwise *start* *state description* *end* e.g. {GST_STATE_READY}
3177  */
3178 static std::string StateText(GstState state, char start, char end, GstState currentState, GstState parentState = GST_STATE_VOID_PENDING)
3179 {
3180  if((state == GST_STATE_VOID_PENDING) || ((state == currentState) && ((state == parentState) || (parentState == GST_STATE_VOID_PENDING))))
3181  {
3182  return "";
3183  }
3184  else
3185  {
3186  std::string returnStringBuilder(1, start);
3187  returnStringBuilder += gst_element_state_get_name(state);
3188  returnStringBuilder += end;
3189  return returnStringBuilder;
3190  }
3191 }
3192 
3193 /**
3194  * @brief wraps gst_element_get_name handling unnamed elements and resource freeing
3195  * @param[in] element a GstElement
3196  * @retval The name of element or "unnamed element" as a std::string
3197  */
3198 static std::string SafeName(GstElement *element)
3199 {
3200  std::string name;
3201  auto elementName = gst_element_get_name(element);
3202  if(elementName)
3203  {
3204  name = elementName;
3205  g_free((void *)elementName);
3206  }
3207  else
3208  {
3209  name = "unnamed element";
3210  }
3211  return name;
3212 }
3213 
3214 /**
3215  * @brief - returns a string describing pElementOrBin and its children (if any).
3216  * The top level elements name:state are shown along with any child elements in () separated by ,
3217  * State information is displayed as GST_STATE[GST_STATE_TARGET]{GST_STATE_NEXT}<GST_STATE_PENDING>
3218  * Target state, next state and pending state are not always shown.
3219  * Where GST_STATE_CHANGE for the element is not GST_STATE_CHANGE_SUCCESS an additional character is appended to the element name:
3220  GST_STATE_CHANGE_FAILURE: "!", GST_STATE_CHANGE_ASYNC:"~", GST_STATE_CHANGE_NO_PREROLL:"*"
3221  * @param[in] pElementOrBin - pointer to a gst element or bin
3222  * @param[in] pParent - parent (optional)
3223  * @param recursionCount - variable shared with self calls to limit recursion depth
3224  * @return - description string
3225  */
3226 static std::string GetStatus(gpointer pElementOrBin, int& recursionCount, gpointer pParent = nullptr)
3227 {
3228  recursionCount++;
3229  constexpr int RECURSION_LIMIT = 10;
3230  if(RECURSION_LIMIT < recursionCount)
3231  {
3232  return "recursion limit exceeded";
3233  }
3234 
3235  std::string returnStringBuilder("");
3236  if(nullptr !=pElementOrBin)
3237  {
3238  if(GST_IS_ELEMENT(pElementOrBin))
3239  {
3240  auto pElement = reinterpret_cast<_GstElement*>(pElementOrBin);
3241 
3242  bool validParent = (pParent != nullptr) && GST_IS_ELEMENT(pParent);
3243 
3244  returnStringBuilder += SafeName(pElement);
3245  GstState state;
3246  GstState statePending;
3247  auto changeStatus = gst_element_get_state(pElement, &state, &statePending, 0);
3248  switch(changeStatus)
3249  {
3250  case GST_STATE_CHANGE_FAILURE:
3251  returnStringBuilder +="!";
3252  break;
3253 
3254  case GST_STATE_CHANGE_SUCCESS:
3255  //no annnotation
3256  break;
3257 
3258  case GST_STATE_CHANGE_ASYNC:
3259  returnStringBuilder +="~";
3260  break;
3261 
3262  case GST_STATE_CHANGE_NO_PREROLL:
3263  returnStringBuilder +="*";
3264  break;
3265 
3266  default:
3267  returnStringBuilder +="?";
3268  break;
3269  }
3270 
3271  returnStringBuilder += ":";
3272 
3273  returnStringBuilder += gst_element_state_get_name(state);
3274  auto parentState = validParent?GST_STATE(pParent):GST_STATE_VOID_PENDING;
3275 
3276  returnStringBuilder += StateText(statePending, '<', '>', state,
3277  validParent?GST_STATE_PENDING(pParent):GST_STATE_VOID_PENDING);
3278  returnStringBuilder += StateText(GST_STATE_TARGET(pElement), '[', ']', state,
3279  validParent?GST_STATE_TARGET(pParent):GST_STATE_VOID_PENDING);
3280  returnStringBuilder += StateText(GST_STATE_NEXT(pElement), '{', '}', state,
3281  validParent?GST_STATE_NEXT(pParent):GST_STATE_VOID_PENDING);
3282  }
3283 
3284  //note bin inherits from element so name bin name is also printed above, with state info where applicable
3285  if(GST_IS_BIN(pElementOrBin))
3286  {
3287  returnStringBuilder += " (";
3288 
3289  auto pBin = reinterpret_cast<_GstElement*>(pElementOrBin);
3290  bool first = true;
3291  for (auto currentListItem = GST_BIN_CHILDREN(pBin);
3292  currentListItem;
3293  currentListItem = currentListItem->next)
3294  {
3295  if(first)
3296  {
3297  first = false;
3298  }
3299  else
3300  {
3301  returnStringBuilder += ", ";
3302  }
3303 
3304  auto currentChildElement = currentListItem->data;
3305  if (nullptr != currentChildElement)
3306  {
3307  returnStringBuilder += GetStatus(currentChildElement, recursionCount, pBin);
3308  }
3309  }
3310  returnStringBuilder += ")";
3311  }
3312  }
3313  recursionCount--;
3314  return returnStringBuilder;
3315 }
3316 
3317 static void LogStatus(GstElement* pElementOrBin)
3318 {
3319  int recursionCount = 0;
3320  AAMPLOG_WARN("AAMPGstPlayer: %s Status: %s",SafeName(pElementOrBin).c_str(), GetStatus(pElementOrBin, recursionCount).c_str());
3321 }
3322 
3323 /**
3324  * @brief Log the various info related to playback
3325  */
3327 {
3328  FN_TRACE( __FUNCTION__ );
3329  GstElement *source = this->privateContext->stream[eMEDIATYPE_VIDEO].source;
3330  gboolean rcBool;
3331  guint64 rcUint64;
3332  gint64 rcInt64;
3333  GstFormat rcFormat;
3334 
3335  //https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-appsrc.html
3336 
3337  rcBool = 0;
3338  g_object_get(source, "block", &rcBool, NULL);
3339  AAMPLOG_WARN("\tblock=%d", (int)rcBool); // 0
3340 
3341  rcBool = 0;
3342  g_object_get(source, "emit-signals", &rcBool, NULL);
3343  AAMPLOG_WARN("\temit-signals=%d", (int)rcBool); // 1
3344 
3345  rcFormat = (GstFormat)0;
3346  g_object_get(source, "format", &rcFormat, NULL);
3347  AAMPLOG_WARN("\tformat=%d", (int)rcFormat); // 2
3348 
3349  rcBool = 0;
3350  g_object_get(source, "is-live", &rcBool, NULL);
3351  AAMPLOG_WARN("\tis-live=%d", (int)rcBool); // 0
3352 
3353  rcUint64 = 0;
3354  g_object_get(source, "max-bytes", &rcUint64, NULL);
3355  AAMPLOG_WARN("\tmax-bytes=%d", (int)rcUint64); // 200000
3356 
3357  rcInt64 = 0;
3358  g_object_get(source, "max-latency", &rcInt64, NULL);
3359  AAMPLOG_WARN("\tmax-latency=%d", (int)rcInt64); // -1
3360 
3361  rcInt64 = 0;
3362  g_object_get(source, "min-latency", &rcInt64, NULL);
3363  AAMPLOG_WARN("\tmin-latency=%d", (int)rcInt64); // -1
3364 
3365  rcInt64 = 0;
3366  g_object_get(source, "size", &rcInt64, NULL);
3367  AAMPLOG_WARN("\tsize=%d", (int)rcInt64); // -1
3368 
3369  gint64 pos, len;
3370  GstFormat format = GST_FORMAT_TIME;
3371  if (gst_element_query_position(privateContext->pipeline, format, &pos) &&
3372  gst_element_query_duration(privateContext->pipeline, format, &len))
3373  {
3374  AAMPLOG_WARN("Position: %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r",
3375  GST_TIME_ARGS(pos), GST_TIME_ARGS(len));
3376  }
3377 
3378  LogStatus(privateContext->pipeline);
3379 }
3380 
3381 
3382 /**
3383  * @brief Validate pipeline state transition within a max timeout
3384  * @param[in] _this pointer to AAMPGstPlayer instance
3385  * @param[in] stateToValidate state to be validated
3386  * @param[in] msTimeOut max timeout in MS
3387  * @retval Current pipeline state
3388  */
3389 static GstState validateStateWithMsTimeout( AAMPGstPlayer *_this, GstState stateToValidate, guint msTimeOut)
3390 {
3391  GstState gst_current;
3392  GstState gst_pending;
3393  float timeout = 100.0;
3394  gint gstGetStateCnt = GST_ELEMENT_GET_STATE_RETRY_CNT_MAX;
3395 
3396  do
3397  {
3398  if ((GST_STATE_CHANGE_SUCCESS
3399  == gst_element_get_state(_this->privateContext->pipeline, &gst_current, &gst_pending, timeout * GST_MSECOND))
3400  && (gst_current == stateToValidate))
3401  {
3402  GST_WARNING(
3403  "validateStateWithMsTimeout - PIPELINE gst_element_get_state - SUCCESS : State = %d, Pending = %d",
3404  gst_current, gst_pending);
3405  return gst_current;
3406  }
3407  g_usleep (msTimeOut * 1000); // Let pipeline safely transition to required state
3408  }
3409  while ((gst_current != stateToValidate) && (gstGetStateCnt-- != 0));
3410 
3411  AAMPLOG_WARN("validateStateWithMsTimeout - PIPELINE gst_element_get_state - FAILURE : State = %d, Pending = %d",
3412  gst_current, gst_pending);
3413  return gst_current;
3414 }
3415 
3416 /**
3417  * @brief wraps gst_element_set_state and adds log messages where applicable
3418  * @param[in] element the GstElement whose state is to be changed
3419  * @param[in] targetState the GstState to apply to element
3420  * @param[in] _this pointer to AAMPGstPlayer instance
3421  * @retval Result of the state change (from inner gst_element_set_state())
3422  */
3423 static GstStateChangeReturn SetStateWithWarnings(GstElement *element, GstState targetState)
3424 {
3425  GstStateChangeReturn rc = GST_STATE_CHANGE_FAILURE;
3426  if(element)
3427  {
3428  //XIONE-8595 - in a synchronous only transition gst_element_set_state can lockup if there are pipeline errors
3429  bool syncOnlyTransition = (targetState==GST_STATE_NULL)||(targetState==GST_STATE_READY);
3430 
3431  GstState current; /* To hold the current state of the element */
3432  GstState pending; /* Pending state, used in printing the pending state of the element */
3433 
3434  auto stateChangeReturn = gst_element_get_state(element, &current, &pending, 0); /* Get the current playing state of the element with no blocking timeout, this function is MT-safe */
3435  switch(stateChangeReturn)
3436  {
3437  case GST_STATE_CHANGE_FAILURE:
3438  AAMPLOG_WARN("AAMPGstPlayer: %s is in FAILURE state : current %s pending %s", SafeName(element).c_str(),gst_element_state_get_name(current), gst_element_state_get_name(pending));
3439  LogStatus(element);
3440  break;
3441  case GST_STATE_CHANGE_SUCCESS:
3442  break;
3443  case GST_STATE_CHANGE_ASYNC:
3444  if(syncOnlyTransition)
3445  {
3446  AAMPLOG_WARN("AAMPGstPlayer: %s state is changing asynchronously : current %s pending %s", SafeName(element).c_str(),gst_element_state_get_name(current), gst_element_state_get_name(pending));
3447  LogStatus(element);
3448  }
3449  break;
3450  default:
3451  AAMPLOG_ERR("AAMPGstPlayer: %s is in an unknown state", SafeName(element).c_str());
3452  break;
3453  }
3454 
3455  if(syncOnlyTransition)
3456  {
3457  AAMPLOG_WARN("AAMPGstPlayer: Attempting to set %s state to %s", SafeName(element).c_str(), gst_element_state_get_name(targetState));
3458  }
3459  rc = gst_element_set_state(element, targetState); /* Set the state of the element to the targetState, this function is MT-safe*/
3460  if(syncOnlyTransition)
3461  {
3462  AAMPLOG_WARN("AAMPGstPlayer: %s state set to %s", SafeName(element).c_str(), gst_element_state_get_name(targetState));
3463  }
3464  }
3465  else
3466  {
3467  AAMPLOG_ERR("AAMPGstPlayer: Attempted to set the state of a null pointer");
3468  }
3469  return rc;
3470 }
3471 
3472 
3473 /**
3474  * @brief Flush the buffers in pipeline
3475  */
3477 {
3478  FN_TRACE( __FUNCTION__ );
3479  if (privateContext->pipeline)
3480  {
3481  PauseAndFlush(false);
3482  }
3483 }
3484 
3485 /**
3486  * @brief PauseAndFlush pipeline and flush
3487  */
3488 void AAMPGstPlayer::PauseAndFlush(bool playAfterFlush)
3489 {
3490  FN_TRACE( __FUNCTION__ );
3491  aamp->SyncBegin();
3492  AAMPLOG_WARN("Entering AAMPGstPlayer::PauseAndFlush() pipeline state %s",
3493  gst_element_state_get_name(GST_STATE(privateContext->pipeline)));
3494  GstStateChangeReturn rc;
3495  GstState stateBeforeFlush = GST_STATE_PAUSED;
3496 #ifndef USE_PLAYERSINKBIN
3497  /*On pc, tsdemux requires null transition*/
3498  stateBeforeFlush = GST_STATE_NULL;
3499 #endif
3500  rc = SetStateWithWarnings(this->privateContext->pipeline, stateBeforeFlush);
3501  if (GST_STATE_CHANGE_ASYNC == rc)
3502  {
3503  if (GST_STATE_PAUSED != validateStateWithMsTimeout(this,GST_STATE_PAUSED, 50))
3504  {
3505  AAMPLOG_WARN("AAMPGstPlayer_Flush - validateStateWithMsTimeout - FAILED GstState %d", GST_STATE_PAUSED);
3506  }
3507  }
3508  else if (GST_STATE_CHANGE_SUCCESS != rc)
3509  {
3510  AAMPLOG_WARN("AAMPGstPlayer_Flush - gst_element_set_state - FAILED rc %d", rc);
3511  }
3512  gboolean ret = gst_element_send_event( GST_ELEMENT(privateContext->pipeline), gst_event_new_flush_start());
3513  if (!ret) AAMPLOG_WARN("AAMPGstPlayer_Flush: flush start error");
3514  ret = gst_element_send_event(GST_ELEMENT(privateContext->pipeline), gst_event_new_flush_stop(TRUE));
3515  if (!ret) AAMPLOG_WARN("AAMPGstPlayer_Flush: flush stop error");
3516  if (playAfterFlush)
3517  {
3518  rc = SetStateWithWarnings(this->privateContext->pipeline, GST_STATE_PLAYING);
3519 
3520  if (GST_STATE_CHANGE_ASYNC == rc)
3521  {
3522 #ifdef AAMP_WAIT_FOR_PLAYING_STATE
3523  if (GST_STATE_PLAYING != validateStateWithMsTimeout( GST_STATE_PLAYING, 50))
3524  {
3525  AAMPLOG_WARN("AAMPGstPlayer_Flush - validateStateWithMsTimeout - FAILED GstState %d",
3526  GST_STATE_PLAYING);
3527  }
3528 #endif
3529  }
3530  else if (GST_STATE_CHANGE_SUCCESS != rc)
3531  {
3532  AAMPLOG_WARN("AAMPGstPlayer_Flush - gst_element_set_state - FAILED rc %d", rc);
3533  }
3534  }
3535  this->privateContext->total_bytes = 0;
3536  privateContext->pendingPlayState = false;
3537  //privateContext->total_duration = 0;
3538  AAMPLOG_WARN("exiting AAMPGstPlayer_FlushEvent");
3539  aamp->SyncEnd();
3540 }
3541 
3542 /**
3543  * @brief Get playback duration in MS
3544  */
3546 {
3547  FN_TRACE( __FUNCTION__ );
3548  long rc = 0;
3549  if( privateContext->pipeline )
3550  {
3551  if( privateContext->pipelineState == GST_STATE_PLAYING || // playing
3552  (privateContext->pipelineState == GST_STATE_PAUSED && privateContext->paused) ) // paused by user
3553  {
3554  privateContext->durationQuery = gst_query_new_duration(GST_FORMAT_TIME); /*Constructs a new stream duration query object to query in the given format */
3555  if( privateContext->durationQuery )
3556  {
3557  gboolean res = gst_element_query(privateContext->pipeline,privateContext->durationQuery);
3558  if( res )
3559  {
3560  gint64 duration;
3561  gst_query_parse_duration(privateContext->durationQuery, NULL, &duration); /* parses the value into duration */
3562  rc = GST_TIME_AS_MSECONDS(duration);
3563  }
3564  else
3565  {
3566  AAMPLOG_WARN("Duration query failed");
3567  }
3568  gst_query_unref(privateContext->durationQuery); /* Decreases the refcount of the durationQuery. In this case the count will be zero, so it will be freed*/
3569  }
3570  else
3571  {
3572  AAMPLOG_WARN("Duration query is NULL");
3573  }
3574  }
3575  else
3576  {
3577  AAMPLOG_WARN("Pipeline is in %s state", gst_element_state_get_name(privateContext->pipelineState) );
3578  }
3579  }
3580  else
3581  {
3582  AAMPLOG_WARN("Pipeline is null");
3583  }
3584  return rc;
3585 }
3586 
3587 /**
3588  * @brief Get playback position in MS
3589  */
3591 {
3592  FN_TRACE( __FUNCTION__ );
3593  long rc = 0;
3594  if (privateContext->pipeline == NULL)
3595  {
3596  AAMPLOG_ERR("Pipeline is NULL");
3597  return rc;
3598  }
3599 
3600  if (privateContext->positionQuery == NULL)
3601  {
3602  AAMPLOG_ERR("Position query is NULL");
3603  return rc;
3604  }
3605 
3606  // Perform gstreamer query and related operation only when pipeline is playing or if deliberately put in paused
3607  if (privateContext->pipelineState != GST_STATE_PLAYING &&
3608  !(privateContext->pipelineState == GST_STATE_PAUSED && privateContext->paused) &&
3609  // XIONE-8379 - The player should be (and probably soon will be) in the playing state so don't exit early.
3610  GST_STATE_TARGET(privateContext->pipeline) != GST_STATE_PLAYING)
3611  {
3612  AAMPLOG_INFO("Pipeline is in %s state, returning position as %ld", gst_element_state_get_name(privateContext->pipelineState), rc);
3613  return rc;
3614  }
3615 
3616  media_stream* video = &privateContext->stream[eMEDIATYPE_VIDEO];
3617 
3618  // segment.start needs to be queried
3619  if (privateContext->segmentStart == -1)
3620  {
3621  GstQuery *segmentQuery = gst_query_new_segment(GST_FORMAT_TIME);
3622  // DELIA-39530 - send query to video playbin in pipeline.
3623  // Special case include trickplay, where only video playbin is active
3624  if (gst_element_query(video->source, segmentQuery) == TRUE)
3625  {
3626  gint64 start;
3627  gst_query_parse_segment(segmentQuery, NULL, NULL, &start, NULL);
3628  privateContext->segmentStart = GST_TIME_AS_MSECONDS(start);
3629  AAMPLOG_WARN("AAMPGstPlayer: Segment start: %" G_GINT64_FORMAT, privateContext->segmentStart);
3630  }
3631  else
3632  {
3633  AAMPLOG_ERR("AAMPGstPlayer: segment query failed");
3634  }
3635  gst_query_unref(segmentQuery);
3636  }
3637 
3638  if (gst_element_query(video->sinkbin, privateContext->positionQuery) == TRUE)
3639  {
3640  gint64 pos = 0;
3641  int rate = privateContext->rate;
3642  gst_query_parse_position(privateContext->positionQuery, NULL, &pos);
3643  if (aamp->mMediaFormat == eMEDIAFORMAT_PROGRESSIVE)
3644  {
3645  rate = 1; // MP4 position query alaways return absolute value
3646  }
3647 
3648 #if !defined(REALTEKCE) // Pos always start from "0" in Realtek
3649  if (privateContext->segmentStart > 0)
3650  {
3651  // DELIA-39530 - Deduct segment.start to find the actual time of media that's played.
3652  rc = (GST_TIME_AS_MSECONDS(pos) - privateContext->segmentStart) * rate;
3653  }
3654  else
3655 #endif
3656  {
3657  rc = GST_TIME_AS_MSECONDS(pos) * rate;
3658  }
3659  //AAMPLOG_WARN("AAMPGstPlayer: pos - %" G_GINT64_FORMAT " rc - %ld", GST_TIME_AS_MSECONDS(pos), rc);
3660 
3661  //positionQuery is not unref-ed here, because it could be reused for future position queries
3662  }
3663  return rc;
3664 }
3665 
3666 /**
3667  * @brief To pause/play pipeline
3668  */
3669 bool AAMPGstPlayer::Pause( bool pause, bool forceStopGstreamerPreBuffering )
3670 {
3671  FN_TRACE( __FUNCTION__ );
3672  bool retValue = true;
3673 
3674  aamp->SyncBegin(); /* Obtains a mutex lock */
3675 
3676  AAMPLOG_WARN("entering AAMPGstPlayer_Pause - pause(%d) stop-pre-buffering(%d)", pause, forceStopGstreamerPreBuffering);
3677 
3678  if (privateContext->pipeline != NULL)
3679  {
3680  GstState nextState = pause ? GST_STATE_PAUSED : GST_STATE_PLAYING;
3681 
3682  if (GST_STATE_PAUSED == nextState && forceStopGstreamerPreBuffering)
3683  {
3684  /* maybe in a timing case during the playback start,
3685  * gstreamer pre buffering and underflow buffering runs simultaneously and
3686  * it will end up pausing the pipeline due to buffering_target_state has the value as GST_STATE_PAUSED.
3687  * To avoid this case, stopping the gstreamer pre buffering logic by setting the buffering_in_progress to false
3688  * and the resume play will be handled from StopBuffering once after getting enough buffer/frames.
3689  */
3690  privateContext->buffering_in_progress = false;
3691  }
3692 
3693  GstStateChangeReturn rc = SetStateWithWarnings(this->privateContext->pipeline, nextState);
3694  if (GST_STATE_CHANGE_ASYNC == rc)
3695  {
3696  /* wait a bit longer for the state change to conclude */
3697  if (nextState != validateStateWithMsTimeout(this,nextState, 100))
3698  {
3699  AAMPLOG_WARN("AAMPGstPlayer_Pause - validateStateWithMsTimeout - FAILED GstState %d", nextState);
3700  }
3701  }
3702  else if (GST_STATE_CHANGE_SUCCESS != rc)
3703  {
3704  AAMPLOG_WARN("AAMPGstPlayer_Pause - gst_element_set_state - FAILED rc %d", rc);
3705  }
3706  privateContext->buffering_target_state = nextState;
3707  privateContext->paused = pause;
3708  privateContext->pendingPlayState = false;
3710  aamp->PauseSubtitleParser(pause);
3711  }
3712  else
3713  {
3714  AAMPLOG_WARN("Pipeline is NULL");
3715  retValue = false;
3716  }
3717 
3718 #if 0
3719  GstStateChangeReturn rc;
3720  for (int iTrack = 0; iTrack < AAMP_TRACK_COUNT; iTrack++)
3721  {
3722  media_stream *stream = &privateContext->stream[iTrack];
3723  if (stream->source)
3724  {
3725  rc = SetStateWithWarnings(privateContext->stream->sinkbin, GST_STATE_PAUSED);
3726  }
3727  }
3728 #endif
3729 
3730  aamp->SyncEnd(); /* Releases the mutex */
3731 
3732  return retValue;
3733 }
3734 
3735 /**
3736  * @brief Set video display rectangle co-ordinates
3737  */
3738 void AAMPGstPlayer::SetVideoRectangle(int x, int y, int w, int h)
3739 {
3740  FN_TRACE( __FUNCTION__ );
3741  int currentX = 0, currentY = 0, currentW = 0, currentH = 0;
3742 
3743 #ifdef INTELCE
3744  if (strcmp(privateContext->videoRectangle, "0,0,0,0") != 0)
3745 #else
3746  if (strcmp(privateContext->videoRectangle, "") != 0)
3747 #endif
3748  sscanf(privateContext->videoRectangle,"%d,%d,%d,%d",&currentX,&currentY,&currentW,&currentH);
3749 
3750  //check the existing VideoRectangle co-ordinates
3751  if ((currentX == x) && (currentY == y) && (currentW == w) && (currentH == h))
3752  {
3753  AAMPLOG_TRACE("Ignoring new co-ordinates, same as current Rect (x:%d, y:%d, w:%d, h:%d)", currentX, currentY, currentW, currentH);
3754  //ignore setting same rectangle co-ordinates and return
3755  return;
3756  }
3757 
3758  media_stream *stream = &privateContext->stream[eMEDIATYPE_VIDEO];
3759  snprintf(privateContext->videoRectangle, sizeof(privateContext->videoRectangle), "%d,%d,%d,%d", x,y,w,h);
3760  AAMPLOG_WARN("Rect %s, using_playersinkbin = %d, video_sink =%p",
3761  privateContext->videoRectangle, stream->using_playersinkbin, privateContext->video_sink);
3762  if (ISCONFIGSET(eAAMPConfig_EnableRectPropertyCfg)) //As part of DELIA-37804
3763  {
3764  if (stream->using_playersinkbin)
3765  {
3766  g_object_set(stream->sinkbin, "rectangle", privateContext->videoRectangle, NULL);
3767  }
3768 #ifndef INTELCE
3769  else if (privateContext->video_sink)
3770  {
3771  g_object_set(privateContext->video_sink, "rectangle", privateContext->videoRectangle, NULL);
3772  }
3773 #else
3774 #if defined(INTELCE_USE_VIDRENDSINK)
3775  else if (privateContext->video_pproc)
3776  {
3777  g_object_set(privateContext->video_pproc, "rectangle", privateContext->videoRectangle, NULL);
3778  }
3779 #else
3780  else if (privateContext->video_sink)
3781  {
3782  g_object_set(privateContext->video_sink, "rectangle", privateContext->videoRectangle, NULL);
3783  }
3784 #endif
3785 #endif
3786  else
3787  {
3788  AAMPLOG_WARN("Scaling not possible at this time");
3789  }
3790  }
3791  else
3792  {
3793  AAMPLOG_WARN("New co-ordinates ignored since westerossink is used");
3794  }
3795 }
3796 
3797 /**
3798  * @brief Set video zoom
3799  */
3801 {
3802  FN_TRACE( __FUNCTION__ );
3803  media_stream *stream = &privateContext->stream[eMEDIATYPE_VIDEO];
3804  AAMPLOG_INFO("SetVideoZoom :: ZoomMode %d, using_playersinkbin = %d, video_sink =%p",
3805  zoom, stream->using_playersinkbin, privateContext->video_sink);
3806 
3807  privateContext->zoom = zoom;
3808  if (stream->using_playersinkbin && stream->sinkbin)
3809  {
3810  g_object_set(stream->sinkbin, "zoom", zoom, NULL);
3811  }
3812 #ifndef INTELCE
3813  else if (privateContext->video_sink)
3814  {
3815  g_object_set(privateContext->video_sink, "zoom-mode", VIDEO_ZOOM_FULL == zoom ? 0 : 1, NULL);
3816  }
3817 #elif defined(INTELCE_USE_VIDRENDSINK)
3818  else if (privateContext->video_pproc)
3819  {
3820  g_object_set(privateContext->video_pproc, "scale-mode", VIDEO_ZOOM_FULL == zoom ? 0 : 3, NULL);
3821  }
3822 #else
3823  else if (privateContext->video_sink)
3824  {
3825  g_object_set(privateContext->video_sink, "scale-mode", VIDEO_ZOOM_FULL == zoom ? 0 : 3, NULL);
3826  }
3827 #endif
3828 }
3829 
3830 void AAMPGstPlayer::SetSubtitlePtsOffset(std::uint64_t pts_offset)
3831 {
3832  FN_TRACE( __FUNCTION__ );
3833 
3834  if (privateContext->subtitle_sink)
3835  {
3836  AAMPLOG_INFO("pts_offset %" G_GUINT64_FORMAT ", seek_pos_seconds %2f, subtitle_sink =%p", pts_offset, aamp->seek_pos_seconds, privateContext->subtitle_sink);
3837  //We use seek_pos_seconds as an offset durinig seek, so we subtract that here to get an offset from zero position
3838  g_object_set(privateContext->subtitle_sink, "pts-offset", static_cast<std::uint64_t>(pts_offset), NULL);
3839  }
3840  else
3841  AAMPLOG_INFO("subtitle_sink is NULL");
3842 }
3843 
3845 {
3846  FN_TRACE( __FUNCTION__ );
3847  media_stream *stream = &privateContext->stream[eMEDIATYPE_SUBTITLE];
3848  privateContext->subtitleMuted = muted;
3849 
3850  if (privateContext->subtitle_sink)
3851  {
3852  AAMPLOG_INFO("muted %d, subtitle_sink =%p", muted, privateContext->subtitle_sink);
3853 
3854  g_object_set(privateContext->subtitle_sink, "mute", privateContext->subtitleMuted ? TRUE : FALSE, NULL); /* Update the 'mute' property of the sink */
3855  }
3856  else
3857  AAMPLOG_INFO("subtitle_sink is NULL");
3858 }
3859 
3860 /**
3861  * @brief Set video mute
3862  */
3864 {
3865  FN_TRACE( __FUNCTION__ );
3866 
3867  //AAMPLOG_WARN(" mute == %s", muted?"true":"false");
3868 
3869  media_stream *stream = &privateContext->stream[eMEDIATYPE_VIDEO];
3870  AAMPLOG_INFO("using_playersinkbin = %d, video_sink =%p", stream->using_playersinkbin, privateContext->video_sink);
3871 
3872  privateContext->videoMuted = muted;
3873  if (stream->using_playersinkbin && stream->sinkbin)
3874  {
3875  g_object_set(stream->sinkbin, "video-mute", privateContext->videoMuted, NULL); /* Sets the 'video-mute' property of the sinkbin to requested status */
3876  }
3877  else if (privateContext->video_sink)
3878  {
3879 #ifndef INTELCE
3880  g_object_set(privateContext->video_sink, "show-video-window", !privateContext->videoMuted, NULL); /* videoMuted to true implies setting the 'show-video-window' to false */
3881 #else
3882  g_object_set(privateContext->video_sink, "mute", privateContext->videoMuted, NULL);
3883 #endif
3884  }
3885 }
3886 
3887 /**
3888  * @brief Set audio volume
3889  */
3891 {
3892  FN_TRACE( __FUNCTION__ );
3893 
3894  privateContext->audioVolume = volume / 100.0;
3896 
3897 }
3898 
3899 /**
3900  * @brief Set audio volume or mute
3901  */
3903 {
3904  const std::lock_guard<std::mutex> lock(privateContext->volumeMuteMutex);
3905  FN_TRACE( __FUNCTION__ );
3906  GstElement *gSource = NULL;
3907  char *propertyName = NULL;
3908  media_stream *stream = &privateContext->stream[eMEDIATYPE_AUDIO];
3909 
3910  AAMPLOG_WARN(" volume == %lf muted == %s", privateContext->audioVolume, privateContext->audioMuted?"true":"false");
3911 
3912  AAMPLOG_INFO("AAMPGstPlayer: using_playersinkbin = %d, audio_sink = %p",
3913  stream->using_playersinkbin, privateContext->audio_sink);
3914 
3915  if (stream->using_playersinkbin && stream->sinkbin)
3916  {
3917  gSource = stream->sinkbin;
3918  propertyName = (char*)"audio-mute";
3919  }
3920 #if (defined(__APPLE__) || defined(REALTEKCE))
3921  else if (stream->sinkbin)
3922  {
3923  gSource = stream->sinkbin;
3924  propertyName = (char*)"mute";
3925  }
3926 #endif
3927  else if (privateContext->audio_sink)
3928  {
3929  gSource = privateContext->audio_sink;
3930  propertyName = (char*)"mute";
3931  }
3932  else
3933  {
3934  return; /* Return here if the sinkbin or audio_sink is not valid, no need to proceed further */
3935  }
3936 
3937 #ifdef AMLOGIC /*For AMLOGIC platform*/
3938  /*Using "stream-volume" property of audio-sink for setting volume and mute for AMLOGIC platform*/
3939  AAMPLOG_WARN("AAMPGstPlayer: Setting Volume %f using stream-volume property of audio-sink", privateContext->audioVolume);
3940  g_object_set(gSource, "stream-volume", privateContext->audioVolume, NULL);
3941 
3942  /* Avoid mute property setting for AMLOGIC as use of "mute" property on pipeline is impacting all other players*/
3943 #else
3944  /* Muting the audio decoder in general to avoid audio passthrough in expert mode for locked channel */
3945  if (0 == privateContext->audioVolume)
3946  {
3947  AAMPLOG_WARN("AAMPGstPlayer: Audio Muted");
3948 #ifdef INTELCE
3949  if (!stream->using_playersinkbin)
3950  {
3951  AAMPLOG_WARN("AAMPGstPlayer: Setting input-gain to %f", INPUT_GAIN_DB_MUTE);
3952  g_object_set(privateContext->audio_sink, "input-gain", INPUT_GAIN_DB_MUTE, NULL);
3953  }
3954  else
3955 #endif
3956  {
3957  g_object_set(gSource, propertyName, true, NULL);
3958  }
3959  privateContext->audioMuted = true;
3960  }
3961  else
3962  {
3963  if (privateContext->audioMuted)
3964  {
3965  AAMPLOG_WARN("AAMPGstPlayer: Audio Unmuted after a Mute");
3966 #ifdef INTELCE
3967  if (!stream->using_playersinkbin)
3968  {
3969  AAMPLOG_WARN("AAMPGstPlayer: Setting input-gain to %f", INPUT_GAIN_DB_UNMUTE);
3970  g_object_set(privateContext->audio_sink, "input-gain", INPUT_GAIN_DB_UNMUTE, NULL);
3971  }
3972  else
3973 #endif
3974  {
3975  g_object_set(gSource, propertyName, false, NULL);
3976  }
3977  privateContext->audioMuted = false;
3978  }
3979 
3980  AAMPLOG_WARN("AAMPGstPlayer: Setting Volume %f", privateContext->audioVolume);
3981  g_object_set(gSource, "volume", privateContext->audioVolume, NULL);
3982  }
3983 #endif
3984 }
3985 
3986 /**
3987  * @brief Flush cached GstBuffers and set seek position & rate
3988  */
3989 void AAMPGstPlayer::Flush(double position, int rate, bool shouldTearDown)
3990 {
3992  {
3993  return;
3994  }
3995  FN_TRACE( __FUNCTION__ );
3996  media_stream *stream = &privateContext->stream[eMEDIATYPE_VIDEO];
3997  privateContext->rate = rate;
3998  //TODO: Need to decide if required for AUX_AUDIO
3999  privateContext->stream[eMEDIATYPE_VIDEO].bufferUnderrun = false;
4000  privateContext->stream[eMEDIATYPE_AUDIO].bufferUnderrun = false;
4001 
4002  if (privateContext->eosCallbackIdleTaskPending)
4003  {
4004  AAMPLOG_WARN("AAMPGstPlayer: Remove eosCallbackIdleTaskId %d", privateContext->eosCallbackIdleTaskId);
4005  aamp->RemoveAsyncTask(privateContext->eosCallbackIdleTaskId);
4006  privateContext->eosCallbackIdleTaskId = AAMP_TASK_ID_INVALID;
4007  privateContext->eosCallbackIdleTaskPending = false;
4008  }
4009 
4010  if (privateContext->ptsCheckForEosOnUnderflowIdleTaskId)
4011  {
4012  AAMPLOG_WARN("AAMPGstPlayer: Remove ptsCheckForEosCallbackIdleTaskId %d", privateContext->ptsCheckForEosOnUnderflowIdleTaskId);
4013  g_source_remove(privateContext->ptsCheckForEosOnUnderflowIdleTaskId);
4014  privateContext->ptsCheckForEosOnUnderflowIdleTaskId = AAMP_TASK_ID_INVALID;
4015  }
4016 
4017  if (privateContext->bufferingTimeoutTimerId)
4018  {
4019  AAMPLOG_WARN("AAMPGstPlayer: Remove bufferingTimeoutTimerId %d", privateContext->bufferingTimeoutTimerId);
4020  g_source_remove(privateContext->bufferingTimeoutTimerId);
4021  privateContext->bufferingTimeoutTimerId = AAMP_TASK_ID_INVALID;
4022  }
4023 
4024  if (stream->using_playersinkbin)
4025  {
4026  Flush();
4027  }
4028  else
4029  {
4030  if (privateContext->pipeline == NULL)
4031  {
4032  AAMPLOG_WARN("AAMPGstPlayer: Pipeline is NULL");
4033  return;
4034  }
4035 #if defined (REALTEKCE)
4036  bool bAsyncModify = FALSE;
4037  if (privateContext->audio_sink)
4038  {
4039  PrivAAMPState state = eSTATE_IDLE;
4040  aamp->GetState(state);
4041  if (privateContext->audio_sink)
4042  {
4043  if (privateContext->rate > 1 || privateContext->rate < 0 || state == eSTATE_SEEKING)
4044  {
4045  //aamp won't feed audio bitstreame to gstreamer at trickplay.
4046  //It needs to disable async of audio base sink to prevent audio sink never sends ASYNC_DONE to pipeline.
4047  AAMPLOG_WARN("Disable async for audio stream at trickplay");
4048  if(gst_base_sink_is_async_enabled(GST_BASE_SINK(privateContext->audio_sink)) == TRUE)
4049  {
4050  gst_base_sink_set_async_enabled(GST_BASE_SINK(privateContext->audio_sink), FALSE);
4051  bAsyncModify = TRUE;
4052  }
4053  }
4054  }
4055  }
4056 #endif
4057  //Check if pipeline is in playing/paused state. If not flush doesn't work
4058  GstState current, pending;
4059  GstStateChangeReturn ret;
4060  ret = gst_element_get_state(privateContext->pipeline, &current, &pending, 100 * GST_MSECOND);
4061  if ((current != GST_STATE_PLAYING && current != GST_STATE_PAUSED) || ret == GST_STATE_CHANGE_FAILURE)
4062  {
4063  AAMPLOG_WARN("AAMPGstPlayer: Pipeline state %s, ret %u", gst_element_state_get_name(current), ret);
4064  if (shouldTearDown)
4065  {
4066  AAMPLOG_WARN("AAMPGstPlayer: Pipeline is not in playing/paused state, hence resetting it");
4067  if(rate > AAMP_NORMAL_PLAY_RATE)
4068  {
4069  trickTeardown = true;
4070  }
4071  Stop(true);
4072  }
4073  return;
4074  }
4075  else
4076  {
4077  /* BCOM-3563, pipeline may enter paused state even when audio decoder is not ready, check again */
4078  if (privateContext->audio_dec)
4079  {
4080  GstState aud_current, aud_pending;
4081  ret = gst_element_get_state(privateContext->audio_dec, &aud_current, &aud_pending, 0);
4082  if ((aud_current != GST_STATE_PLAYING && aud_current != GST_STATE_PAUSED) || ret == GST_STATE_CHANGE_FAILURE)
4083  {
4084  if (shouldTearDown)
4085  {
4086  AAMPLOG_WARN("AAMPGstPlayer: Pipeline is in playing/paused state, but audio_dec is in %s state, resetting it ret %u\n",
4087  gst_element_state_get_name(aud_current), ret);
4088  Stop(true);
4089  return;
4090  }
4091  }
4092  }
4093  AAMPLOG_WARN("AAMPGstPlayer: Pipeline is in %s state position %f ret %d\n", gst_element_state_get_name(current), position, ret);
4094  }
4095  /* Disabling the flush flag as part of DELIA-42607 to avoid */
4096  /* flush call again (which may cause freeze sometimes) */
4097  /* from SendGstEvents() API. */
4098  for (int i = 0; i < AAMP_TRACK_COUNT; i++)
4099  {
4100  privateContext->stream[i].resetPosition = true;
4101  privateContext->stream[i].flush = false;
4102  privateContext->stream[i].eosReached = false;
4103  }
4104 
4105  AAMPLOG_INFO("AAMPGstPlayer: Pipeline flush seek - start = %f rate = %d", position, rate);
4106  double playRate = 1.0;
4107  if (eMEDIAFORMAT_PROGRESSIVE == aamp->mMediaFormat)
4108  {
4109  playRate = rate;
4110  }
4111 #if defined (REALTEKCE)
4112  /* XIONE-9423
4113  * A work around for a timing issue that can occur around scrubbing.
4114  * This causes trick play issues if applied to rates >1.
4115  */
4116  if(abs(rate)<=1)
4117  {
4118  GstState targetState, currentState;
4119  gst_element_get_state(privateContext->pipeline, &currentState, &targetState, 100 * GST_MSECOND);
4120 
4121  if((targetState != GST_STATE_PAUSED) &&
4122  ((targetState == GST_STATE_PLAYING) || (currentState == GST_STATE_PLAYING)))
4123  {
4124  AAMPLOG_WARN("AAMPGstPlayer: Pause before seek, Setting Pipeline to GST_STATE_PAUSED.");
4125  SetStateWithWarnings(privateContext->pipeline, GST_STATE_PAUSED);
4126  }
4127  else
4128  {
4129  AAMPLOG_WARN("AAMPGstPlayer: Pause before seek, not required (targetState=%s, currentState=%s)",
4130  gst_element_state_get_name(targetState),
4131  gst_element_state_get_name(currentState));
4132  }
4133  }
4134  else
4135  {
4136  AAMPLOG_INFO("AAMPGstPlayer: Pause before seek, not required (rate = %d).",rate);
4137  }
4138 #endif
4139 
4140  if (!gst_element_seek(privateContext->pipeline, playRate, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
4141  position * GST_SECOND, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
4142  {
4143  AAMPLOG_WARN("Seek failed");
4144  }
4145 #if defined (REALTEKCE)
4146  if(bAsyncModify == TRUE)
4147  {
4148  gst_base_sink_set_async_enabled(GST_BASE_SINK(privateContext->audio_sink), TRUE);
4149  }
4150 #endif
4151  }
4152  privateContext->eosSignalled = false;
4153  privateContext->numberOfVideoBuffersSent = 0;
4154 }
4155 
4156 /**
4157  * @brief Process discontinuity for a stream type
4158  */
4160 {
4161  FN_TRACE( __FUNCTION__ );
4162  bool ret = false;
4163  media_stream *stream = &privateContext->stream[type];
4164  AAMPLOG_WARN("Entering AAMPGstPlayer: type(%d) format(%d) resetPosition(%d)", (int)type, stream->format, stream->resetPosition);
4165  /*Handle discontinuity only if atleast one buffer is pushed*/
4166  if (stream->format != FORMAT_INVALID && stream->resetPosition == true)
4167  {
4168  AAMPLOG_WARN("Discontinuity received before first buffer - ignoring");
4169  }
4170  else
4171  {
4172  AAMPLOG_TRACE("stream->format %d, stream->resetPosition %d, stream->flush %d", stream->format , stream->resetPosition, stream->flush);
4174  // We are in buffering, but we received discontinuity, un-pause pipeline
4175  StopBuffering(true);
4176  ret = true;
4177 
4178  //If we have an audio discontinuity, signal subtec as well
4179  if ((type == eMEDIATYPE_AUDIO) && (privateContext->stream[eMEDIATYPE_SUBTITLE].source))
4180  {
4181  AAMPGstPlayer_SignalEOS(privateContext->stream[eMEDIATYPE_SUBTITLE].source);
4182  }
4183 
4184  }
4185  return ret;
4186 }
4187 
4188 /**
4189  * @brief Check if PTS is changing
4190  * @retval true if PTS changed from lastKnown PTS or timeout hasn't expired, will optimistically return true^M^M
4191  * if video-pts attribute is not available from decoder
4192  */
4194 {
4195  FN_TRACE( __FUNCTION__ );
4196  bool ret = true;
4197 #ifndef INTELCE
4198  gint64 currentPTS = GetVideoPTS(); /* Gets the currentPTS from the 'video-pts' property of the element */
4199  if (currentPTS != 0)
4200  {
4201  if (currentPTS != privateContext->lastKnownPTS)
4202  {
4203  AAMPLOG_WARN("AAMPGstPlayer: There is an update in PTS prevPTS:%" G_GINT64_FORMAT " newPTS: %" G_GINT64_FORMAT "\n",
4204  privateContext->lastKnownPTS, currentPTS);
4205  privateContext->ptsUpdatedTimeMS = NOW_STEADY_TS_MS; /* save a copy of the current steady clock in milliseconds */
4206  privateContext->lastKnownPTS = currentPTS;
4207  }
4208  else
4209  {
4210  long diff = NOW_STEADY_TS_MS - privateContext->ptsUpdatedTimeMS;
4211  if (diff > timeout)
4212  {
4213  AAMPLOG_WARN("AAMPGstPlayer: Video PTS hasn't been updated for %ld ms and timeout - %ld ms", diff, timeout);
4214  ret = false;
4215  }
4216  }
4217  }
4218  else
4219  {
4220  AAMPLOG_WARN("AAMPGstPlayer: video-pts parsed is: %" G_GINT64_FORMAT "\n",
4221  currentPTS);
4222  }
4223 #endif
4224  return ret;
4225 }
4226 
4227 /**
4228  * @brief Gets Video PTS
4229  */
4231 {
4232  FN_TRACE( __FUNCTION__ );
4233  gint64 currentPTS = 0;
4234  GstElement *element;
4235 #if defined (REALTEKCE)
4236  element = privateContext->video_sink;
4237 #else
4238  element = privateContext->video_dec;
4239 #endif
4240  if( element )
4241  {
4242  g_object_get(element, "video-pts", &currentPTS, NULL); /* Gets the 'video-pts' from the element into the currentPTS */
4243 
4244 #ifndef REALTEKCE
4245  //Westeros sink sync returns PTS in 90Khz format where as BCM returns in 45 KHz,
4246  // hence converting to 90Khz for BCM
4247  if(!privateContext->using_westerossink)
4248  {
4249  currentPTS = currentPTS * 2; // convert from 45 KHz to 90 Khz PTS
4250  }
4251 #endif
4252  }
4253  return (long long) currentPTS;
4254 }
4255 
4256 /**
4257  * @brief Reset EOS SignalledFlag
4258  */
4260 {
4261  privateContext->eosSignalled = false;
4262 }
4263 
4264 /**
4265  * @brief Check if cache empty for a media type
4266  */
4268 {
4269  FN_TRACE( __FUNCTION__ );
4270  bool ret = true;
4271  media_stream *stream = &privateContext->stream[mediaType];
4272  if (stream->source)
4273  {
4274  guint64 cacheLevel = gst_app_src_get_current_level_bytes (GST_APP_SRC(stream->source)); /*Get the number of currently queued bytes inside stream->source)*/
4275  if(0 != cacheLevel)
4276  {
4277  AAMPLOG_TRACE("AAMPGstPlayer::Cache level %" G_GUINT64_FORMAT "", cacheLevel);
4278  ret = false;
4279  }
4280  else
4281  {
4282  // Changed from logprintf to AAMPLOG_TRACE, to avoid log flooding (seen on xi3 and xid).
4283  // We're seeing this logged frequently during live linear playback, despite no user-facing problem.
4284  AAMPLOG_TRACE("AAMPGstPlayer::Cache level empty");
4285  if (privateContext->stream[eMEDIATYPE_VIDEO].bufferUnderrun == true ||
4286  privateContext->stream[eMEDIATYPE_AUDIO].bufferUnderrun == true) /* Interpret bufferUnderun as cachelevel being empty */
4287  {
4288  AAMPLOG_WARN("AAMPGstPlayer::Received buffer underrun signal for video(%d) or audio(%d) previously",privateContext->stream[eMEDIATYPE_VIDEO].bufferUnderrun,
4289  privateContext->stream[eMEDIATYPE_AUDIO].bufferUnderrun);
4290  }
4291 #ifndef INTELCE
4292  else
4293  {
4295  if(!ptsChanged)
4296  {
4297  //PTS hasn't changed for the timeout value
4298  AAMPLOG_WARN("AAMPGstPlayer: Appsrc cache is empty and PTS hasn't been updated for more than %dms and ret(%d)",
4300  }
4301  else
4302  {
4303  ret = false; /* Pts changing, conclude that cache is not empty */
4304  }
4305  }
4306 #endif
4307  }
4308  }
4309  return ret;
4310 }
4311 
4312 /**
4313  * @brief Set pipeline to PLAYING state once fragment caching is complete
4314  */
4316 {
4317  FN_TRACE( __FUNCTION__ );
4318  if(privateContext->pendingPlayState)
4319  {
4320  AAMPLOG_WARN("AAMPGstPlayer: Setting pipeline to PLAYING state ");
4321  if (SetStateWithWarnings(privateContext->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE)
4322  {
4323  AAMPLOG_WARN("AAMPGstPlayer_Configure GST_STATE_PLAYING failed");
4324  }
4325  privateContext->pendingPlayState = false;
4326  }
4327  else
4328  {
4329  AAMPLOG_WARN("AAMPGstPlayer: No pending PLAYING state");
4330  }
4331 }
4332 
4333 /**
4334  * @brief Set pipeline to PAUSED state to wait on NotifyFragmentCachingComplete()
4335  */
4337 {
4338  FN_TRACE( __FUNCTION__ );
4339  if(!privateContext->paused)
4340  {
4341  Pause(true, true);
4342  }
4343  privateContext->pendingPlayState = true;
4344 }
4345 
4346 /**
4347  * @brief Get video display's width and height
4348  */
4349 void AAMPGstPlayer::GetVideoSize(int &width, int &height)
4350 {
4351  FN_TRACE( __FUNCTION__ );
4352  int x, y, w, h;
4353  sscanf(privateContext->videoRectangle, "%d,%d,%d,%d", &x, &y, &w, &h);
4354  if (w > 0 && h > 0)
4355  {
4356  width = w;
4357  height = h;
4358  }
4359 }
4360 
4361 /***
4362  * @fn IsCodecSupported
4363  *
4364  * @brief Check whether Gstreamer platform has support of the given codec or not.
4365  * codec to component mapping done in gstreamer side.
4366  * @param codecName - Name of codec to be checked
4367  * @return True if platform has the support else false
4368  */
4369 
4370 bool AAMPGstPlayer::IsCodecSupported(const std::string &codecName)
4371 {
4372  FN_TRACE( __FUNCTION__ );
4373  bool retValue = false;
4374  GstRegistry* registry = gst_registry_get();
4375  for (std::string &componentName: gmapDecoderLoookUptable[codecName])
4376  {
4377  GstPluginFeature* pluginFeature = gst_registry_lookup_feature(registry, componentName.c_str()); /* searches for codec in the registry */
4378  if (pluginFeature != NULL)
4379  {
4380  retValue = true;
4381  break;
4382  }
4383  }
4384 
4385  return retValue;
4386 }
4387 
4388 /**
4389  * @brief Increase the rank of AAMP decryptor plugins
4390  */
4392 {
4393  FN_TRACE( __FUNCTION__ );
4394 #ifdef AAMP_MPD_DRM
4395  GstRegistry* registry = gst_registry_get();
4396 
4397  GstPluginFeature* pluginFeature = gst_registry_lookup_feature(registry, GstPluginNamePR);
4398 
4399  if (pluginFeature == NULL)
4400  {
4401  AAMPLOG_ERR("AAMPGstPlayer: %s plugin feature not available; reloading aamp plugin", GstPluginNamePR);
4402  GstPlugin * plugin = gst_plugin_load_by_name ("aamp");
4403  if(plugin)
4404  {
4405  gst_object_unref(plugin);
4406  }
4407  pluginFeature = gst_registry_lookup_feature(registry, GstPluginNamePR);
4408  if(pluginFeature == NULL)
4409  AAMPLOG_ERR("AAMPGstPlayer: %s plugin feature not available", GstPluginNamePR);
4410  }
4411  if(pluginFeature)
4412  {
4413  gst_registry_remove_feature (registry, pluginFeature);//Added as a work around to handle DELIA-31716
4414  gst_registry_add_feature (registry, pluginFeature);
4415 
4416 
4417  AAMPLOG_WARN("AAMPGstPlayer: %s plugin priority set to GST_RANK_PRIMARY + 111", GstPluginNamePR);
4418  gst_plugin_feature_set_rank(pluginFeature, GST_RANK_PRIMARY + 111);
4419  gst_object_unref(pluginFeature);
4420  }
4421 
4422  pluginFeature = gst_registry_lookup_feature(registry, GstPluginNameWV);
4423 
4424  if (pluginFeature == NULL)
4425  {
4426  AAMPLOG_ERR("AAMPGstPlayer: %s plugin feature not available", GstPluginNameWV);
4427  }
4428  else
4429  {
4430  AAMPLOG_WARN("AAMPGstPlayer: %s plugin priority set to GST_RANK_PRIMARY + 111", GstPluginNameWV);
4431  gst_plugin_feature_set_rank(pluginFeature, GST_RANK_PRIMARY + 111);
4432  gst_object_unref(pluginFeature);
4433  }
4434 
4435  pluginFeature = gst_registry_lookup_feature(registry, GstPluginNameCK);
4436 
4437  if (pluginFeature == NULL)
4438  {
4439  AAMPLOG_ERR("AAMPGstPlayer: %s plugin feature not available", GstPluginNameCK);
4440  }
4441  else
4442  {
4443  AAMPLOG_WARN("AAMPGstPlayer: %s plugin priority set to GST_RANK_PRIMARY + 111", GstPluginNameCK);
4444  gst_plugin_feature_set_rank(pluginFeature, GST_RANK_PRIMARY + 111);
4445  gst_object_unref(pluginFeature);
4446  }
4447 
4448  pluginFeature = gst_registry_lookup_feature(registry, GstPluginNameVMX);
4449 
4450  if (pluginFeature == NULL)
4451  {
4452  AAMPLOG_ERR("AAMPGstPlayer::%s():%d %s plugin feature not available", __FUNCTION__, __LINE__, GstPluginNameVMX);
4453  }
4454  else
4455  {
4456  AAMPLOG_WARN("AAMPGstPlayer::%s():%d %s plugin priority set to GST_RANK_PRIMARY + 111", __FUNCTION__, __LINE__, GstPluginNameVMX);
4457  gst_plugin_feature_set_rank(pluginFeature, GST_RANK_PRIMARY + 111);
4458  gst_object_unref(pluginFeature);
4459  }
4460 #ifndef INTELCE
4461  for (int i=0; i<PLUGINS_TO_LOWER_RANK_MAX; i++) {
4462  pluginFeature = gst_registry_lookup_feature(registry, plugins_to_lower_rank[i]);
4463  if(pluginFeature) {
4464  gst_plugin_feature_set_rank(pluginFeature, GST_RANK_PRIMARY - 1);
4465  gst_object_unref(pluginFeature);
4466  AAMPLOG_WARN("AAMPGstPlayer: %s plugin priority set to GST_RANK_PRIMARY - 1\n", plugins_to_lower_rank[i]);
4467  }
4468  }
4469 #endif
4470 #endif
4471 }
4472 
4473 /**
4474  * @brief Notify EOS to core aamp asynchronously if required.
4475  * @note Used internally by AAMPGstPlayer
4476  */
4478 {
4479  FN_TRACE( __FUNCTION__ );
4480  if (!privateContext->eosSignalled)
4481  {
4482  if (!privateContext->eosCallbackIdleTaskPending)
4483  {
4484  privateContext->eosCallbackIdleTaskId = aamp->ScheduleAsyncTask(IdleCallbackOnEOS, (void *)this, "IdleCallbackOnEOS");
4485  if (privateContext->eosCallbackIdleTaskId != AAMP_TASK_ID_INVALID)
4486  {
4487  privateContext->eosCallbackIdleTaskPending = true;
4488  }
4489  else
4490  {
4491  AAMPLOG_WARN("eosCallbackIdleTask scheduled, eosCallbackIdleTaskId %d", privateContext->eosCallbackIdleTaskId);
4492  }
4493  }
4494  else
4495  {
4496  AAMPLOG_WARN("IdleCallbackOnEOS already registered previously, hence skip!");
4497  }
4498  privateContext->eosSignalled = true;
4499  }
4500  else
4501  {
4502  AAMPLOG_WARN("EOS already signaled, hence skip!");
4503  }
4504 }
4505 
4506 /**
4507  * @brief Dump a file to log
4508  */
4509 static void DumpFile(const char* fileName)
4510 {
4511  int c;
4512  FILE *fp = fopen(fileName, "r");
4513  if (fp)
4514  {
4515  printf("\n************************Dump %s **************************\n", fileName);
4516  c = getc(fp);
4517  while (c != EOF)
4518  {
4519  printf("%c", c);
4520  c = getc(fp);
4521  }
4522  fclose(fp);
4523  printf("\n**********************Dump %s end *************************\n", fileName);
4524  }
4525  else
4526  {
4527  AAMPLOG_WARN("Could not open %s", fileName);
4528  }
4529 }
4530 
4531 /**
4532  * @brief Dump diagnostic information
4533  *
4534  */
4536 {
4537  FN_TRACE( __FUNCTION__ );
4538  AAMPLOG_WARN("video_dec %p audio_dec %p video_sink %p audio_sink %p numberOfVideoBuffersSent %d",
4539  privateContext->video_dec, privateContext->audio_dec, privateContext->video_sink,
4540  privateContext->audio_sink, privateContext->numberOfVideoBuffersSent);
4541 #ifndef INTELCE
4542  DumpFile("/proc/brcm/transport");
4543  DumpFile("/proc/brcm/video_decoder");
4544  DumpFile("/proc/brcm/audio");
4545 #endif
4546 }
4547 
4548 /**
4549  * @brief Signal trick mode discontinuity to gstreamer pipeline
4550  */
4552 {
4553  FN_TRACE( __FUNCTION__ );
4554  media_stream* stream = &privateContext->stream[eMEDIATYPE_VIDEO];
4555  if (stream && (privateContext->rate != AAMP_NORMAL_PLAY_RATE) )
4556  {
4557  GstPad* sourceEleSrcPad = gst_element_get_static_pad(GST_ELEMENT(stream->source), "src");
4558  int vodTrickplayFPS;
4559  GETCONFIGVALUE(eAAMPConfig_VODTrickPlayFPS,vodTrickplayFPS);
4560  GstStructure * eventStruct = gst_structure_new("aamp-tm-disc", "fps", G_TYPE_UINT, (guint)vodTrickplayFPS, NULL);
4561  if (!gst_pad_push_event(sourceEleSrcPad, gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, eventStruct)))
4562  {
4563  AAMPLOG_WARN("Error on sending aamp-tm-disc");
4564  }
4565  else
4566  {
4567  AAMPLOG_WARN("Sent aamp-tm-disc event");
4568  }
4569  gst_object_unref(sourceEleSrcPad);
4570  }
4571 }
4572 
4573 /**
4574  * @brief Flush the data in case of a new tune pipeline
4575  */
4576 void AAMPGstPlayer::SeekStreamSink(double position, double rate)
4577 {
4578  FN_TRACE( __FUNCTION__ );
4579  // shouldTearDown is set to false, because in case of a new tune pipeline
4580  // might not be in a playing/paused state which causes Flush() to destroy
4581  // pipeline. This has to be avoided.
4582  Flush(position, rate, false);
4583 
4584 }
4585 
4586 /**
4587  * @brief Get the video rectangle co-ordinates
4588  */
4590 {
4591  FN_TRACE( __FUNCTION__ );
4592  return std::string(privateContext->videoRectangle);
4593 }
4594 
4595 /**
4596  * @brief Un-pause pipeline and notify buffer end event to player
4597  */
4598 void AAMPGstPlayer::StopBuffering(bool forceStop)
4599 {
4600  FN_TRACE( __FUNCTION__ );
4601  pthread_mutex_lock(&mBufferingLock);
4602  //Check if we are in buffering
4603  if (ISCONFIGSET(eAAMPConfig_ReportBufferEvent) && privateContext->video_dec && aamp->GetBufUnderFlowStatus())
4604  {
4605  bool stopBuffering = forceStop;
4606 #if ( !defined(INTELCE) && !defined(RPI) && !defined(__APPLE__) )
4607  int frames = -1;
4608  g_object_get(privateContext->video_dec,"queued_frames",(uint*)&frames,NULL);
4609  if (frames != -1)
4610  {
4611  stopBuffering = stopBuffering || (frames > DEFAULT_BUFFERING_QUEUED_FRAMES_MIN); //TODO: the minimum frame values should be configurable from aamp.cfg
4612  }
4613  else
4614 #endif
4615  stopBuffering = true;
4616 
4617  if (stopBuffering)
4618  {
4619 #if ( !defined(INTELCE) && !defined(RPI) && !defined(__APPLE__) )
4620  AAMPLOG_WARN("Enough data available to stop buffering, frames %d !", frames);
4621 #endif
4622  GstState current, pending;
4623  bool sendEndEvent = false;
4624 
4625  if(GST_STATE_CHANGE_FAILURE != gst_element_get_state(privateContext->pipeline, &current, &pending, 0 * GST_MSECOND))
4626  {
4627  if (current == GST_STATE_PLAYING)
4628  {
4629  sendEndEvent = true;
4630  }
4631  else
4632  {
4633  sendEndEvent = aamp->PausePipeline(false, false);
4634  aamp->UpdateSubtitleTimestamp();
4635  }
4636  }
4637  else
4638  {
4639  sendEndEvent = false;
4640  }
4641 
4642  if( !sendEndEvent )
4643  {
4644  AAMPLOG_ERR("Failed to un-pause pipeline for stop buffering!");
4645  }
4646  else
4647  {
4648  aamp->SendBufferChangeEvent(); /* To indicate buffer availability */
4649  }
4650  }
4651  else
4652  {
4653  static int bufferLogCount = 0;
4654  if (0 == (bufferLogCount++ % 10) )
4655  {
4656 #if ( !defined(INTELCE) && !defined(RPI) && !defined(__APPLE__) )
4657  AAMPLOG_WARN("Not enough data available to stop buffering, frames %d !", frames);
4658 #endif
4659  }
4660  }
4661  }
4662  pthread_mutex_unlock(&mBufferingLock);
4663 }
4664 
4665 
4666 void type_check_instance(const char * str, GstElement * elem)
4667 {
4668  AAMPLOG_WARN("%s %p type_check %d", str, elem, G_TYPE_CHECK_INSTANCE (elem));
4669 }
4670 
4671 /**
4672  * @brief Wait for source element to be configured.
4673  */
4675 {
4676  bool ret = false;
4677  int timeRemaining = -1;
4678  GETCONFIGVALUE(eAAMPConfig_SourceSetupTimeout, timeRemaining);
4679  media_stream *stream = &privateContext->stream[mediaType];
4680 
4681  int waitInterval = 100; //ms
4682 
4683  AAMPLOG_WARN("Source element[%p] for track[%d] not configured, wait for setup to complete!", stream->source, mediaType);
4684  while(timeRemaining >= 0)
4685  {
4686  aamp->InterruptableMsSleep(waitInterval); /*Sleep until timeout is reached or interrupted*/
4687  if (aamp->DownloadsAreEnabled())
4688  {
4689  if (stream->sourceConfigured)
4690  {
4691  AAMPLOG_WARN("Source element[%p] for track[%d] setup completed!", stream->source, mediaType);
4692  ret = true;
4693  break;
4694  }
4695  }
4696  else
4697  {
4698  //Playback stopped by application
4699  break;
4700  }
4701  timeRemaining -= waitInterval;
4702  }
4703 
4704  if (!ret)
4705  {
4706  AAMPLOG_WARN("Wait for source element setup for track[%d] exited/timedout!", mediaType);
4707  }
4708  return ret;
4709 }
4710 
4711 /**
4712  * @brief Forward buffer to aux pipeline
4713  */
4715 {
4716  media_stream *stream = &privateContext->stream[eMEDIATYPE_AUX_AUDIO];
4717  if (!stream->sourceConfigured && stream->format != FORMAT_INVALID)
4718  {
4720  if (!aamp->DownloadsAreEnabled() || !status)
4721  {
4722  // Buffer is not owned by us, no need to free
4723  return;
4724  }
4725  }
4726 
4727  GstBuffer *fwdBuffer = gst_buffer_new();
4728  if (fwdBuffer != NULL)
4729  {
4730  if (FALSE == gst_buffer_copy_into(fwdBuffer, buffer, GST_BUFFER_COPY_ALL, 0, -1))
4731  {
4732  AAMPLOG_ERR("Error while copying audio buffer to auxiliary buffer!!");
4733  gst_buffer_unref(fwdBuffer);
4734  return;
4735  }
4736  //AAMPLOG_TRACE("Forward audio buffer to auxiliary pipeline!!");
4737  GstFlowReturn ret = gst_app_src_push_buffer(GST_APP_SRC(stream->source), fwdBuffer);
4738  if (ret != GST_FLOW_OK)
4739  {
4740  AAMPLOG_ERR("gst_app_src_push_buffer error: %d[%s] mediaType %d", ret, gst_flow_get_name (ret), (int)eMEDIATYPE_AUX_AUDIO);
4741  assert(false);
4742  }
4743  }
4744 }
4745 
4746 /**
4747  * @brief Check if audio buffers to be forwarded or not
4748  */
4750 {
4751  return (privateContext->forwardAudioBuffers && privateContext->stream[eMEDIATYPE_AUX_AUDIO].format != FORMAT_INVALID);
4752 }
4753 
4754 /**
4755  * @}
4756  */
4757 
4758 /**
4759  * @brief Set playback rate to audio/video sinks
4760  */
4762 {
4763  int ret=0;
4764 
4765 #if defined (REALTEKCE)
4766  GstStructure* s = gst_structure_new("custom-instant-rate-change", "rate", G_TYPE_DOUBLE, rate, NULL);
4767  /* The above statement creates a new GstStructure with the name 'custom-instant-rate-change' that has a member variable
4768  'rate' of G_TYPE_DOUBLE and a value of rate i.e. second last parameter */
4769 
4770  ret = gst_element_send_event( privateContext->pipeline, gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s) );
4771  if(!ret)
4772  {
4773  AAMPLOG_WARN("AAMPGstPlayer: Set custom rate change failed");
4774  return false;
4775  }
4776  AAMPLOG_WARN ("Current rate: %g", rate);
4777 #elif defined (AMLOGIC)
4778  AAMPLOG_WARN("Setting new segment with rate as:%f to audiosink", rate);
4779  media_stream* audstream = &privateContext->stream[eMEDIATYPE_AUDIO];
4780  GstElement *audsink=NULL;
4781 
4782  GstSegment* segment = gst_segment_new();
4783  gst_segment_init(segment, GST_FORMAT_TIME);
4784  segment->rate = rate;
4785  segment->start = GST_CLOCK_TIME_NONE;
4786  segment->position = GST_CLOCK_TIME_NONE;
4787 
4788  AAMPLOG_WARN("Sending new segment");
4789  g_object_get (audstream->sinkbin, "audio-sink", &audsink, NULL);
4790  if(NULL != audsink)
4791  {
4792  ret=gst_pad_send_event (GST_BASE_SINK_PAD(audsink), gst_event_new_segment(segment));
4793  AAMPLOG_WARN("send new segment to audio ret:%d", ret);
4794  }
4795  else
4796  {
4797  AAMPLOG_WARN("audio-sink device not found");
4798  }
4799  AAMPLOG_WARN ("Current rate: %g", rate);
4800 #else //Broadcom
4801  gint64 position;
4802  GstEvent *seek_event=NULL, *vidseek=NULL;
4803  media_stream* stream = &privateContext->stream[eMEDIATYPE_VIDEO];
4804  media_stream* audstream = &privateContext->stream[eMEDIATYPE_AUDIO];
4805  GstElement* vidsink = NULL, *audsink=NULL;
4806 
4807  if (privateContext->pipeline == NULL)
4808  {
4809  AAMPLOG_WARN("AAMPGstPlayer: Pipeline is NULL");
4810  return false;
4811  }
4812 
4813  /* Obtain the current position, needed for the seek event */
4814  if (!gst_element_query_position (privateContext->pipeline, GST_FORMAT_TIME, &position))
4815  {
4816  AAMPLOG_WARN ("Unable to retrieve current position:%lld.", position);
4817  position=0;
4818  }
4819 
4820  AAMPLOG_WARN ("pipeline current position:%lld.", position);
4821 
4822  if ( 0 == position && privateContext->positionQuery )
4823  {
4824  if (gst_element_query(stream->sinkbin, privateContext->positionQuery) == TRUE)
4825  {
4826  gst_query_parse_position(privateContext->positionQuery, NULL, &position);
4827  AAMPLOG_WARN ("video sink current position:%lld.", position);
4828  }
4829  }
4830 
4831  /* Create the seek event */
4832  if (rate > 0)
4833  {
4834  seek_event = gst_event_new_seek (rate, GST_FORMAT_TIME,
4835  (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), GST_SEEK_TYPE_SET,
4836  position, GST_SEEK_TYPE_END, 0);
4837 
4838  vidseek = gst_event_new_seek (rate, GST_FORMAT_TIME,
4839  (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), GST_SEEK_TYPE_SET,
4840  position, GST_SEEK_TYPE_END, 0);
4841  }
4842  else
4843  {
4844  AAMPLOG_WARN ( "Negative player rate for slow motion is not supported");
4845  return false;
4846  }
4847 
4848  g_object_get (stream->sinkbin, "video-sink", &vidsink, NULL);
4849  if(NULL != vidsink)
4850  {
4851  ret = gst_element_send_event (vidsink, vidseek);
4852  AAMPLOG_WARN("send seek event for video ret:%d", ret);
4853  }
4854 
4855  g_object_get (audstream->sinkbin, "audio-sink", &audsink, NULL);
4856  if(NULL != audsink)
4857  {
4858  // seek_event=gst_event_ref(seek_event);
4859  ret=gst_element_send_event (audsink, seek_event);
4860  AAMPLOG_WARN("send seek event for audio ret:%d", ret);
4861  }
4862 
4863  // g_object_unref(vidsink);
4864  // g_object_unref(audsink);
4865  // gst_event_unref(seek_event);
4866  AAMPLOG_WARN ("Current rate: %g, position:%lld", rate, position);
4867 #endif /*REALTEKCE*/
4868 
4869  return true;
4870 }
4871 
4872 /**
4873  * @brief adjust playback rate
4874  */
4875 bool AAMPGstPlayer::AdjustPlayBackRate(double position, double rate)
4876 {
4877  FN_TRACE( __FUNCTION__ );
4878  bool ErrSuccess = false;
4879  if (privateContext->pipeline == NULL)
4880  {
4881  AAMPLOG_WARN("AAMPGstPlayer: Pipeline is NULL");
4882  }
4883  else
4884  {
4885  PrivAAMPState state = eSTATE_IDLE;
4886  aamp->GetState(state);
4887  if( ( rate != privateContext->playbackrate ) && ( state == eSTATE_PLAYING ) )
4888  {
4889  gint64 position1=0;
4890  /* Obtain the current position, needed for the seek event */
4891  if (!gst_element_query_position (privateContext->pipeline, GST_FORMAT_TIME, &position1))
4892  {
4893  AAMPLOG_WARN("AAMPGstPlayer: Unable to query gst element position");
4894  }
4895  else
4896  {
4897  if (!gst_element_seek(privateContext->pipeline, rate, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
4898  GST_SEEK_TYPE_SET, position1, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
4899  {
4900  AAMPLOG_WARN("AAMPGstPlayer: playrate adjustment failed");
4901  }
4902  else
4903  {
4904  AAMPLOG_INFO("AAMPGstPlayer: playrate adjustment success");
4905  privateContext->playbackrate = rate;
4906  ErrSuccess = true;
4907  }
4908  }
4909  }
4910  else
4911  {
4912  AAMPLOG_TRACE("AAMPGstPlayer: rate is already in %lf rate",rate);
4913  ErrSuccess = true;
4914  }
4915  }
4916  return ErrSuccess;
4917 }
4918 
AampOutputProtection::IsAampOutputProcectionInstanceActive
static bool IsAampOutputProcectionInstanceActive()
Check if AampOutputProcectionInstance active.
Definition: aampoutputprotection.cpp:428
AAMPGstPlayer::NotifyFragmentCachingOngoing
void NotifyFragmentCachingOngoing()
Set pipeline to PAUSED state to wait on NotifyFragmentCachingComplete()
Definition: aampgstplayer.cpp:4336
AAMPGstPlayer::EndOfStreamReached
void EndOfStreamReached(MediaType type)
Starts processing EOS for a particular stream type.
Definition: aampgstplayer.cpp:3027
PrivateInstanceAAMP::GetVidTimeScale
uint32_t GetVidTimeScale(void)
Gets Video TimeScale.
Definition: priv_aamp.cpp:11604
AAMPGstPlayerPriv::n_audio
gint n_audio
Definition: aampgstplayer.cpp:157
AAMPGstPlayer::~AAMPGstPlayer
~AAMPGstPlayer()
AAMPGstPlayer Destructor.
Definition: aampgstplayer.cpp:362
AAMPGstPlayerPriv::bufferingTimeoutTimerId
guint bufferingTimeoutTimerId
Definition: aampgstplayer.cpp:162
eMEDIAFORMAT_PROGRESSIVE
@ eMEDIAFORMAT_PROGRESSIVE
Definition: AampDrmMediaFormat.h:36
StreamOutputFormat
StreamOutputFormat
Media output format.
Definition: main_aamp.h:106
DumpFile
static void DumpFile(const char *fileName)
Dump a file to log.
Definition: aampgstplayer.cpp:4509
eGST_ERROR_GST_PIPELINE_INTERNAL
@ eGST_ERROR_GST_PIPELINE_INTERNAL
Definition: priv_aamp.h:180
eGST_ERROR_OUTPUT_PROTECTION_ERROR
@ eGST_ERROR_OUTPUT_PROTECTION_ERROR
Definition: priv_aamp.h:177
ProgressCallbackOnTimeout
static gboolean ProgressCallbackOnTimeout(gpointer user_data)
Timer's callback to notify playback progress event.
Definition: aampgstplayer.cpp:773
VIDEO_ZOOM_FULL
@ VIDEO_ZOOM_FULL
Definition: main_aamp.h:131
PrivateInstanceAAMP::NotifyEOSReached
void NotifyEOSReached()
Process EOS from Sink and notify listeners if required.
Definition: priv_aamp.cpp:2831
AAMP_TUNE_GST_PIPELINE_ERROR
@ AAMP_TUNE_GST_PIPELINE_ERROR
Definition: AampEvent.h:138
aampoutputprotection.h
Output protection management for Aamp.
AAMPGstPlayer_SignalEOS
static void AAMPGstPlayer_SignalEOS(GstElement *source)
Definition: aampgstplayer.cpp:3011
GST_PLAY_FLAG_DOWNLOAD
@ GST_PLAY_FLAG_DOWNLOAD
Definition: aampgstplayer.cpp:63
AAMPGstPlayer::TimerAdd
void TimerAdd(GSourceFunc funcPtr, int repeatTimeout, guint &taskId, gpointer user_data, const char *timerName=nullptr)
TimerAdd - add a new glib timer in thread safe manner.
Definition: aampgstplayer.cpp:452
AAMPGstPlayerPriv::protectionEvent
GstEvent * protectionEvent[4]
Definition: aampgstplayer.cpp:187
AAMPGstPlayerPriv::enableSEITimeCode
bool enableSEITimeCode
Definition: aampgstplayer.cpp:218
AAMPGstPlayerPriv::rate
int rate
Definition: aampgstplayer.cpp:172
AAMPGstPlayerPriv::decodeErrorCBCount
int decodeErrorCBCount
Definition: aampgstplayer.cpp:214
AAMPGstPlayerPriv::eosCallbackIdleTaskId
guint eosCallbackIdleTaskId
Definition: aampgstplayer.cpp:180
eMEDIATYPE_VIDEO
@ eMEDIATYPE_VIDEO
Definition: AampMediaType.h:39
eAAMPConfig_DecoderUnavailableStrict
@ eAAMPConfig_DecoderUnavailableStrict
Definition: AampConfig.h:132
AAMPGstPlayer::NotifyEOS
void NotifyEOS()
Notify EOS to core aamp asynchronously if required.
Definition: aampgstplayer.cpp:4477
AAMPGstPlayer::trickTeardown
bool trickTeardown
Definition: aampgstplayer.h:338
AAMPGstPlayer_OnFirstVideoFrameCallback
static void AAMPGstPlayer_OnFirstVideoFrameCallback(GstElement *object, guint arg0, gpointer arg1, AAMPGstPlayer *_this)
Callback invoked after first video frame decoded.
Definition: aampgstplayer.cpp:921
PrivateInstanceAAMP::NotifyFirstBufferProcessed
void NotifyFirstBufferProcessed()
Notify if first buffer processed by gstreamer.
Definition: priv_aamp.cpp:8471
AAMPGstPlayer::QueueProtectionEvent
void QueueProtectionEvent(const char *protSystemId, const void *ptr, size_t len, MediaType type)
Generate a protection event.
Definition: aampgstplayer.cpp:1955
PrivateInstanceAAMP::InterruptableMsSleep
void InterruptableMsSleep(int timeInMs)
Sleep until timeout is reached or interrupted.
Definition: priv_aamp.cpp:6771
PrivateInstanceAAMP::LogTuneComplete
void LogTuneComplete(void)
Notify tune end for profiling/logging.
Definition: priv_aamp.cpp:3045
PrivateInstanceAAMP::ResetTrickStartUTCTime
void ResetTrickStartUTCTime()
Reset trick start position.
Definition: priv_aamp.cpp:8512
AAMPGstPlayer::CreatePipeline
bool CreatePipeline()
Create a new Gstreamer pipeline.
Definition: aampgstplayer.cpp:1827
AAMP_MIN_PTS_UPDATE_INTERVAL
#define AAMP_MIN_PTS_UPDATE_INTERVAL
Definition: aampgstplayer.cpp:96
AAMPGstPlayer::DumpDiagnostics
void DumpDiagnostics()
Dump diagnostic information.
Definition: aampgstplayer.cpp:4535
GstPluginNameWV
static const char * GstPluginNameWV
Definition: aampgstplayer.cpp:275
AAMPGstPlayerPriv::segmentStart
gint64 segmentStart
Definition: aampgstplayer.cpp:203
AAMPGstPlayer::WaitForSourceSetup
bool WaitForSourceSetup(MediaType mediaType)
Wait for source element to be configured.
Definition: aampgstplayer.cpp:4674
FORMAT_INVALID
@ FORMAT_INVALID
Definition: main_aamp.h:108
AAMPGstPlayer::IdleTaskClearFlags
void IdleTaskClearFlags(TaskControlData &taskDetails)
IdleTaskClearFlags - clear async task id and pending flag in a thread safe manner e....
Definition: aampgstplayer.cpp:433
AampFnLogger.h
AAMP Log unitility.
FORMAT_ISO_BMFF
@ FORMAT_ISO_BMFF
Definition: main_aamp.h:110
AAMPGstPlayerPriv::decoderHandleNotified
bool decoderHandleNotified
Definition: aampgstplayer.cpp:185
AAMPGstPlayerPriv::eosCallbackIdleTaskPending
std::atomic< bool > eosCallbackIdleTaskPending
Definition: aampgstplayer.cpp:181
AAMPGstPlayer::TearDownStream
void TearDownStream(MediaType mediaType)
Cleanup resources and flags for a particular stream type.
Definition: aampgstplayer.cpp:2096
AAMPGstPlayer_PlayersinkbinCB
static void AAMPGstPlayer_PlayersinkbinCB(GstElement *playersinkbin, gint status, void *arg)
Callback for receiving playersinkbin gstreamer events.
Definition: aampgstplayer.cpp:2020
found_source
static void found_source(GObject *object, GObject *orig, GParamSpec *pspec, AAMPGstPlayer *_this)
Callback when source is added by playbin.
Definition: aampgstplayer.cpp:672
AAMPGstPlayerPriv::pipeline
GstElement * pipeline
Definition: aampgstplayer.cpp:153
AAMPGstPlayer::Stream
void Stream(void)
To start playback.
Definition: aampgstplayer.cpp:2824
AAMPGstPlayer::Configure
void Configure(StreamOutputFormat format, StreamOutputFormat audioFormat, StreamOutputFormat auxFormat, StreamOutputFormat subFormat, bool bESChangeStatus, bool forwardAudioToAux, bool setReadyAfterPipelineCreation=false)
Configure pipeline based on A/V formats.
Definition: aampgstplayer.cpp:2833
AAMPGstPlayerPriv::current_audio
gint current_audio
Definition: aampgstplayer.cpp:158
PrivateInstanceAAMP::GetCurrentAudioTrackId
int GetCurrentAudioTrackId(void)
Get the Current Audio Track Id Currently it is implimented for AC4 track selection only.
Definition: priv_aamp.cpp:2810
PrivateInstanceAAMP::SetAudioVolume
void SetAudioVolume(int volume)
Set audio volume.
Definition: priv_aamp.cpp:6732
eAAMPConfig_SEITimeCode
@ eAAMPConfig_SEITimeCode
Definition: AampConfig.h:180
AAMPGstPlayer
Class declaration of Gstreamer based player.
Definition: aampgstplayer.h:64
AAMPGstPlayerPriv::pipelineState
GstState pipelineState
Definition: aampgstplayer.cpp:207
AAMPGstPlayer::SendHelper
bool SendHelper(MediaType mediaType, const void *ptr, size_t len, double fpts, double fdts, double duration, bool copy, bool initFragment=0)
Inject stream buffer to gstreamer pipeline.
Definition: aampgstplayer.cpp:2630
bus_sync_handler
static GstBusSyncReply bus_sync_handler(GstBus *bus, GstMessage *msg, AAMPGstPlayer *_this)
Invoked synchronously when a message is available on the bus.
Definition: aampgstplayer.cpp:1566
need_data
static void need_data(GstElement *source, guint size, AAMPGstPlayer *_this)
Callback for appsrc "need-data" signal.
Definition: aampgstplayer.cpp:552
gmapDecoderLoookUptable
static std::map< std::string, std::vector< std::string > > gmapDecoderLoookUptable
Definition: aampgstplayer.cpp:109
eAAMPConfig_ReportProgressInterval
@ eAAMPConfig_ReportProgressInterval
Definition: AampConfig.h:286
AAMPGstPlayerPriv::durationQuery
GstQuery * durationQuery
Definition: aampgstplayer.cpp:205
plugins_to_lower_rank
const char * plugins_to_lower_rank[2]
Definition: aampgstplayer.cpp:320
AAMPGstPlayerPriv::NumberOfTracks
int NumberOfTracks
Definition: aampgstplayer.cpp:221
ID3_HEADER_SIZE
#define ID3_HEADER_SIZE
Definition: aampgstplayer.cpp:2561
eAAMPConfig_GSTLogging
@ eAAMPConfig_GSTLogging
Definition: AampConfig.h:141
AAMPGstPlayer::SendTransfer
bool SendTransfer(MediaType mediaType, void *ptr, size_t len, double fpts, double fdts, double fDuration, bool initFragment)
inject mp4 segment to gstreamer pipeline
Definition: aampgstplayer.cpp:2814
AAMPGstPlayer::TimerIsRunning
bool TimerIsRunning(guint &taskId)
TimerIsRunning - Check whether timer is currently running.
Definition: aampgstplayer.cpp:497
ISCONFIGSET
#define ISCONFIGSET(x)
Definition: AampConfig.h:84
AAMPGstPlayerPriv::bus
GstBus * bus
Definition: aampgstplayer.cpp:154
GST_PLAY_FLAG_VIS
@ GST_PLAY_FLAG_VIS
Definition: aampgstplayer.cpp:59
AAMPGstPlayer::DumpStatus
void DumpStatus(void)
Log the various info related to playback.
Definition: aampgstplayer.cpp:3326
StreamSink::SetPlayBackRate
virtual bool SetPlayBackRate(double rate)
Set player rate to audio/video sink.
Definition: main_aamp.h:474
media_stream::format
StreamOutputFormat format
Definition: aampgstplayer.cpp:123
AAMPGstPlayerPriv::buffering_target_state
GstState buffering_target_state
Definition: aampgstplayer.cpp:195
AAMPGstPlayer::SetVideoMute
void SetVideoMute(bool muted)
Set video mute.
Definition: aampgstplayer.cpp:3863
AAMPGstPlayer::GetPositionMilliseconds
long GetPositionMilliseconds(void)
Get playback position in MS.
Definition: aampgstplayer.cpp:3590
media_stream
Holds stream(Audio, Video, Subtitle and Aux-Audio) specific variables.
Definition: aampgstplayer.cpp:119
eMEDIATYPE_AUX_AUDIO
@ eMEDIATYPE_AUX_AUDIO
Definition: AampMediaType.h:42
AAMPGstPlayer::getCCDecoderHandle
unsigned long getCCDecoderHandle(void)
Retrieve the video decoder handle from pipeline.
Definition: aampgstplayer.cpp:1926
eMEDIAFORMAT_DASH
@ eMEDIAFORMAT_DASH
Definition: AampDrmMediaFormat.h:35
AAMPGstPlayer_isVideoDecoder
bool AAMPGstPlayer_isVideoDecoder(const char *name, AAMPGstPlayer *_this)
Check if gstreamer element is video decoder.
Definition: aampgstplayer.cpp:969
AAMPGstPlayer::GetDurationMilliseconds
long GetDurationMilliseconds(void)
Get playback duration in MS.
Definition: aampgstplayer.cpp:3545
AAMPGstPlayer::Pause
bool Pause(bool pause, bool forceStopGstreamerPreBuffering)
To pause/play pipeline.
Definition: aampgstplayer.cpp:3669
AAMPGstPlayerPriv::firstVideoFrameDisplayedCallbackIdleTaskId
guint firstVideoFrameDisplayedCallbackIdleTaskId
Definition: aampgstplayer.cpp:208
AAMPGstPlayer::setVolumeOrMuteUnMute
void setVolumeOrMuteUnMute(void)
Set audio volume or mute.
Definition: aampgstplayer.cpp:3902
PrivateInstanceAAMP::RemoveAsyncTask
bool RemoveAsyncTask(int taskId)
Remove async task scheduled earlier.
Definition: priv_aamp.cpp:10653
eAAMPConfig_GstAudioBufBytes
@ eAAMPConfig_GstAudioBufBytes
Definition: AampConfig.h:252
PrivateInstanceAAMP::mAudioDecoderStreamSync
bool mAudioDecoderStreamSync
Definition: priv_aamp.h:1050
AAMPGstPlayerPriv::video_sink
GstElement * video_sink
Definition: aampgstplayer.cpp:165
AampLogManager
AampLogManager Class.
Definition: AampLogManager.h:150
AAMPGstPlayerPriv::using_westerossink
bool using_westerossink
Definition: aampgstplayer.cpp:189
FORMAT_MPEGTS
@ FORMAT_MPEGTS
Definition: main_aamp.h:109
AAMPGstPlayer_isVideoSink
bool AAMPGstPlayer_isVideoSink(const char *name, AAMPGstPlayer *_this)
Check if gstreamer element is video sink.
Definition: aampgstplayer.cpp:985
AAMPGstPlayer::ForwardBuffersToAuxPipeline
void ForwardBuffersToAuxPipeline(GstBuffer *buffer)
Forward buffer to aux pipeline.
Definition: aampgstplayer.cpp:4714
eAAMPConfig_GstVideoBufBytes
@ eAAMPConfig_GstVideoBufBytes
Definition: AampConfig.h:251
PrivateInstanceAAMP::UpdateSubtitleTimestamp
void UpdateSubtitleTimestamp()
Sets up the timestamp sync for subtitle renderer.
Definition: priv_aamp.cpp:8448
AAMPGstPlayer::SignalTrickModeDiscontinuity
void SignalTrickModeDiscontinuity()
Signal trick mode discontinuity to gstreamer pipeline.
Definition: aampgstplayer.cpp:4551
PrivateInstanceAAMP::ScheduleRetune
void ScheduleRetune(PlaybackErrorType errorType, MediaType trackType)
Schedules retune or discontinuity processing based on state.
Definition: priv_aamp.cpp:7559
AAMPGstPlayerPriv::volumeMuteMutex
std::mutex volumeMuteMutex
Definition: aampgstplayer.cpp:177
AAMPGstPlayerPriv::eosSignalled
std::atomic< bool > eosSignalled
Definition: aampgstplayer.cpp:191
AAMPGstPlayerPriv::forwardAudioBuffers
bool forwardAudioBuffers
Definition: aampgstplayer.cpp:217
PrivateInstanceAAMP::GetManifestUrl
std::string & GetManifestUrl(void)
Get manifest URL.
Definition: priv_aamp.h:1890
AAMPGstPlayerPriv::buffering_in_progress
gboolean buffering_in_progress
Definition: aampgstplayer.cpp:193
LogStatus
static void LogStatus(GstElement *pElementOrBin)
Definition: aampgstplayer.cpp:3317
PrivateInstanceAAMP::InitializeCC
void InitializeCC(void)
Initialize CC after first frame received Sends CC handle event to listeners when first frame receives...
Definition: priv_aamp.cpp:7460
PrivateInstanceAAMP::seiTimecode
std::string seiTimecode
Definition: priv_aamp.h:1127
eMEDIATYPE_DEFAULT
@ eMEDIATYPE_DEFAULT
Definition: AampMediaType.h:58
AampConfig::GetConfigValue
bool GetConfigValue(AAMPConfigSettings cfg, std::string &value)
GetConfigValue - Gets configuration for string data type.
Definition: AampConfig.cpp:748
VideoZoomMode
VideoZoomMode
Video zoom mode.
Definition: main_aamp.h:129
AAMPGstPlayerPriv::audio_dec
GstElement * audio_dec
Definition: aampgstplayer.cpp:164
SetStateWithWarnings
static GstStateChangeReturn SetStateWithWarnings(GstElement *element, GstState targetState)
wraps gst_element_set_state and adds log messages where applicable
Definition: aampgstplayer.cpp:3423
ProfileEventAAMP::ProfilePerformed
void ProfilePerformed(ProfilerBucketType type)
Method to mark the end of a bucket, for which beginning is not marked.
Definition: AampProfiler.cpp:354
SafeName
static std::string SafeName(GstElement *element)
wraps gst_element_get_name handling unnamed elements and resource freeing
Definition: aampgstplayer.cpp:3198
bus_message
static gboolean bus_message(GstBus *bus, GstMessage *msg, AAMPGstPlayer *_this)
Called from the mainloop when a message is available on the bus.
Definition: aampgstplayer.cpp:1302
PrivateInstanceAAMP::GetState
void GetState(PrivAAMPState &state)
Get player state.
Definition: priv_aamp.cpp:7769
PrivateInstanceAAMP::IsDashAsset
bool IsDashAsset(void)
To check if current asset is DASH or not.
Definition: priv_aamp.h:2939
PrivateInstanceAAMP::lastId3Data
uint8_t * lastId3Data[eMEDIATYPE_DEFAULT]
Definition: priv_aamp.h:1071
PrivateInstanceAAMP::IsEventListenerAvailable
bool IsEventListenerAvailable(AAMPEventType eventType)
IsEventListenerAvailable Check if Event is registered.
Definition: priv_aamp.cpp:2261
GstPluginNameCK
static const char * GstPluginNameCK
Definition: aampgstplayer.cpp:276
AAMPGstPlayerPriv::audioMuted
bool audioMuted
Definition: aampgstplayer.cpp:176
AAMPGstPlayer_isVideoOrAudioDecoder
bool AAMPGstPlayer_isVideoOrAudioDecoder(const char *name, AAMPGstPlayer *_this)
Check if gstreamer element is audio decoder.
Definition: aampgstplayer.cpp:1018
AampOutputProtection
Class to enforce HDCP authentication.
Definition: aampoutputprotection.h:119
GST_PLAY_FLAG_DEINTERLACE
@ GST_PLAY_FLAG_DEINTERLACE
Definition: aampgstplayer.cpp:65
AAMPGstPlayer::SendGstEvents
void SendGstEvents(MediaType mediaType, GstClockTime pts, const void *ptr, size_t len)
Definition: aampgstplayer.cpp:2432
aamp_StartsWith
bool aamp_StartsWith(const char *inputStr, const char *prefix)
Check if string start with a prefix.
Definition: AampUtils.cpp:284
hasId3Header
bool hasId3Header(MediaType mediaType, const uint8_t *data, int32_t length)
Definition: aampgstplayer.cpp:2545
eMEDIATYPE_AUDIO
@ eMEDIATYPE_AUDIO
Definition: AampMediaType.h:40
AAMPGstPlayerPriv::firstFrameCallbackIdleTaskPending
std::atomic< bool > firstFrameCallbackIdleTaskPending
Definition: aampgstplayer.cpp:188
IdleCallbackFirstVideoFrameDisplayed
static gboolean IdleCallbackFirstVideoFrameDisplayed(gpointer user_data)
Idle callback to notify first video frame was displayed.
Definition: aampgstplayer.cpp:822
AAMPGstPlayerPriv::subtitleMuted
bool subtitleMuted
Definition: aampgstplayer.cpp:178
GST_PLAY_FLAG_BUFFERING
@ GST_PLAY_FLAG_BUFFERING
Definition: aampgstplayer.cpp:64
GetDrmSystemName
const char * GetDrmSystemName(DRMSystems drmSystem)
Get name of DRM system.
Definition: AampUtils.cpp:625
GstPluginNameVMX
static const char * GstPluginNameVMX
Definition: aampgstplayer.cpp:277
AAMPGstPlayer::IdleTaskRemove
bool IdleTaskRemove(TaskControlData &taskDetails)
IdleTaskRemove - remove an async task in a thread safe manner, if it is queued.
Definition: aampgstplayer.cpp:408
AAMPGstPlayer::Discontinuity
bool Discontinuity(MediaType mediaType)
Process discontinuity for a stream type.
Definition: aampgstplayer.cpp:4159
AAMPGstPlayerPriv::playbackrate
double playbackrate
Definition: aampgstplayer.cpp:173
PrivateInstanceAAMP::GetMediaFormatTypeEnum
MediaFormat GetMediaFormatTypeEnum() const
Get Mediaformat type.
Definition: priv_aamp.cpp:8557
media_stream::sinkbin
GstElement * sinkbin
Definition: aampgstplayer.cpp:121
GST_PLAY_FLAG_TEXT
@ GST_PLAY_FLAG_TEXT
Definition: aampgstplayer.cpp:58
AAMPGstPlayer::IsCodecSupported
static bool IsCodecSupported(const std::string &codecName)
Definition: aampgstplayer.cpp:4370
AampMemoryUtils.h
Header file of helper functions for memory management.
AAMPGstPlayerPriv::numberOfVideoBuffersSent
int numberOfVideoBuffersSent
Definition: aampgstplayer.cpp:202
eAAMPConfig_EnableGstPositionQuery
@ eAAMPConfig_EnableGstPositionQuery
Definition: AampConfig.h:150
AAMPGstPlayer::ForwardAudioBuffersToAux
bool ForwardAudioBuffersToAux()
Check if audio buffers to be forwarded or not.
Definition: aampgstplayer.cpp:4749
AAMP_DELAY_BETWEEN_PTS_CHECK_FOR_EOS_ON_UNDERFLOW
#define AAMP_DELAY_BETWEEN_PTS_CHECK_FOR_EOS_ON_UNDERFLOW
Definition: aampgstplayer.cpp:97
eGST_ERROR_PTS
@ eGST_ERROR_PTS
Definition: priv_aamp.h:174
AAMPGstPlayer::IdleTaskAdd
bool IdleTaskAdd(TaskControlData &taskDetails, BackgroundTask funcPtr)
IdleTaskAdd - add an async/idle task in a thread safe manner, assuming it is not queued.
Definition: aampgstplayer.cpp:376
AampGstUtils.h
Header for utility functions for AAMP's GST impl.
AAMPGstPlayer::SetSubtitlePtsOffset
void SetSubtitlePtsOffset(std::uint64_t pts_offset)
Definition: aampgstplayer.cpp:3830
AAMPGstPlayerPriv::ptsUpdatedTimeMS
long long ptsUpdatedTimeMS
Definition: aampgstplayer.cpp:200
AAMPGstPlayerPriv::audioVolume
double audioVolume
Definition: aampgstplayer.cpp:179
AAMPGstPlayer::TimerRemove
void TimerRemove(guint &taskId, const char *timerName=nullptr)
TimerRemove - remove a glib timer in thread safe manner, if it exists.
Definition: aampgstplayer.cpp:478
GST_PLAY_FLAG_NATIVE_AUDIO
@ GST_PLAY_FLAG_NATIVE_AUDIO
Definition: aampgstplayer.cpp:61
PrivateInstanceAAMP::GetNetworkProxy
std::string GetNetworkProxy()
To get the network proxy.
Definition: priv_aamp.cpp:9079
AAMPGstPlayerPriv::firstVideoFrameDisplayedCallbackIdleTaskPending
std::atomic< bool > firstVideoFrameDisplayedCallbackIdleTaskPending
Definition: aampgstplayer.cpp:209
GST_PLAY_FLAG_SOFT_COLORBALANCE
@ GST_PLAY_FLAG_SOFT_COLORBALANCE
Definition: aampgstplayer.cpp:66
eGST_ERROR_UNDERFLOW
@ eGST_ERROR_UNDERFLOW
Definition: priv_aamp.h:175
eAAMPConfig_EnableRectPropertyCfg
@ eAAMPConfig_EnableRectPropertyCfg
Definition: AampConfig.h:130
MediaType
MediaType
Media types.
Definition: AampMediaType.h:37
IsoBmffBuffer
Class for ISO BMFF Buffer.
Definition: isobmffbuffer.h:39
PrivateInstanceAAMP::NotifyFirstFrameReceived
void NotifyFirstFrameReceived(void)
Notify first frame is displayed. Sends CC handle event to listeners.
Definition: priv_aamp.cpp:7499
AAMPGstPlayerPriv::pendingPlayState
bool pendingPlayState
Definition: aampgstplayer.cpp:184
IsoBmffBuffer::setBuffer
void setBuffer(uint8_t *buf, size_t sz)
Set buffer.
Definition: isobmffbuffer.cpp:47
eAAMPConfig_DisableUnderflow
@ eAAMPConfig_DisableUnderflow
Definition: AampConfig.h:174
AAMPGstPlayerPriv::videoRectangle
char videoRectangle[32]
Definition: aampgstplayer.cpp:183
AAMPGstPlayer::NotifyFirstFrame
void NotifyFirstFrame(MediaType type)
Notify first Audio and Video frame through an idle function to make the playersinkbin halding same as...
Definition: aampgstplayer.cpp:837
GST_PLAY_FLAG_VIDEO
@ GST_PLAY_FLAG_VIDEO
Definition: aampgstplayer.cpp:56
eAAMPConfig_GStreamerBufferingBeforePlay
@ eAAMPConfig_GStreamerBufferingBeforePlay
Definition: AampConfig.h:123
GstPlayFlags
GstPlayFlags
Enum of configuration flags used by playbin.
Definition: aampgstplayer.cpp:55
PrivateInstanceAAMP::StopTrackDownloads
void StopTrackDownloads(MediaType type)
Stop downloads for a track. Called from StreamSink to control flow.
Definition: priv_aamp.cpp:3179
AAMPGstPlayer::SetAudioVolume
void SetAudioVolume(int volume)
Set audio volume.
Definition: aampgstplayer.cpp:3890
eAAMPConfig_UseWesterosSink
@ eAAMPConfig_UseWesterosSink
Definition: AampConfig.h:153
AAMPGstPlayer_SetupStream
static int AAMPGstPlayer_SetupStream(AAMPGstPlayer *_this, MediaType streamId)
Setup pipeline for a particular stream type.
Definition: aampgstplayer.cpp:2179
eAAMPConfig_GstSubtecEnabled
@ eAAMPConfig_GstSubtecEnabled
Definition: AampConfig.h:194
PrivateInstanceAAMP::GetPreferredDRM
DRMSystems GetPreferredDRM()
Get Preferred DRM.
Definition: priv_aamp.cpp:8843
IdleCallback
static gboolean IdleCallback(gpointer user_data)
Idle callback to start progress notifier timer.
Definition: aampgstplayer.cpp:790
AAMPGstPlayerPriv::firstFrameReceived
bool firstFrameReceived
Definition: aampgstplayer.cpp:182
AAMP_TRACK_COUNT
#define AAMP_TRACK_COUNT
Definition: priv_aamp.h:67
PrivateInstanceAAMP::SyncBegin
void SyncBegin(void)
GStreamer operation start.
Definition: priv_aamp.cpp:1893
eAAMPConfig_SuppressDecode
@ eAAMPConfig_SuppressDecode
Definition: AampConfig.h:196
AAMPGstPlayer::SetVideoRectangle
void SetVideoRectangle(int x, int y, int w, int h)
Set video display rectangle co-ordinates.
Definition: aampgstplayer.cpp:3738
AAMPGstPlayer::SetPlayBackRate
bool SetPlayBackRate(double rate)
Set playback rate to audio/video sinks.
Definition: aampgstplayer.cpp:4761
aampgstplayer.h
Gstreamer based player for AAMP.
GstPluginNamePR
static const char * GstPluginNamePR
Definition: aampgstplayer.cpp:274
AAMPGstPlayer_OnGstBufferUnderflowCb
static void AAMPGstPlayer_OnGstBufferUnderflowCb(GstElement *object, guint arg0, gpointer arg1, AAMPGstPlayer *_this)
Callback invoked when facing an underflow.
Definition: aampgstplayer.cpp:1136
GST_PLAY_FLAG_SOFT_VOLUME
@ GST_PLAY_FLAG_SOFT_VOLUME
Definition: aampgstplayer.cpp:60
AampOutputProtection::setGstElement
void setGstElement(GstElement *element)
Set GstElement.
Definition: aampoutputprotection.h:248
AAMPGstPlayerPriv::buffering_enabled
gboolean buffering_enabled
Definition: aampgstplayer.cpp:192
AAMPGstPlayerPriv::decodeErrorMsgTimeMS
long long decodeErrorMsgTimeMS
Definition: aampgstplayer.cpp:213
AAMPGstPlayerPriv
Holds private variables of AAMPGstPlayer.
Definition: aampgstplayer.cpp:147
AAMPGstPlayer::ClearProtectionEvent
void ClearProtectionEvent()
Cleanup generated protection event.
Definition: aampgstplayer.cpp:1998
IdleCallbackOnFirstFrame
static gboolean IdleCallbackOnFirstFrame(gpointer user_data)
Idle callback to notify first frame rendered event.
Definition: aampgstplayer.cpp:735
validateStateWithMsTimeout
static GstState validateStateWithMsTimeout(AAMPGstPlayer *_this, GstState stateToValidate, guint msTimeOut)
Validate pipeline state transition within a max timeout.
Definition: aampgstplayer.cpp:3389
AAMPGstPlayer::GetVideoPTS
virtual long long GetVideoPTS(void)
Gets Video PTS.
Definition: aampgstplayer.cpp:4230
eAAMPConfig_RetuneForGSTError
@ eAAMPConfig_RetuneForGSTError
Definition: AampConfig.h:156
AAMPGstPlayer::SetVideoZoom
void SetVideoZoom(VideoZoomMode zoom)
Set video zoom.
Definition: aampgstplayer.cpp:3800
AAMPGstPlayerPriv::busWatchId
guint busWatchId
Definition: aampgstplayer.cpp:190
AampOutputProtection::GetAampOutputProcectionInstance
static AampOutputProtection * GetAampOutputProcectionInstance()
Singleton for object creation.
Definition: aampoutputprotection.cpp:441
AAMPGstPlayer_OnGstPtsErrorCb
static void AAMPGstPlayer_OnGstPtsErrorCb(GstElement *object, guint arg0, gpointer arg1, AAMPGstPlayer *_this)
Callback invoked a PTS error is encountered.
Definition: aampgstplayer.cpp:1199
DEFAULT_BUFFERING_MAX_CNT
#define DEFAULT_BUFFERING_MAX_CNT
Definition: aampgstplayer.cpp:95
AAMPGstPlayer::Flush
void Flush(double position, int rate, bool shouldTearDown)
Flush cached GstBuffers and set seek position & rate.
Definition: aampgstplayer.cpp:3989
IsoBmffBuffer::getFirstPTS
bool getFirstPTS(uint64_t &pts)
Get first PTS of buffer.
Definition: isobmffbuffer.cpp:249
AAMPGstPlayer_isAudioSinkOrAudioDecoder
bool AAMPGstPlayer_isAudioSinkOrAudioDecoder(const char *name, AAMPGstPlayer *_this)
Check if gstreamer element is audio sink or audio decoder.
Definition: aampgstplayer.cpp:1001
type_check_instance
static void type_check_instance(const char *str, GstElement *elem)
check if elemement is instance (BCOM-3563)
Definition: aampgstplayer.cpp:4666
StateText
static std::string StateText(GstState state, char start, char end, GstState currentState, GstState parentState=GST_STATE_VOID_PENDING)
Generates a state description for gst target, next and pending state i.e. not current state.
Definition: aampgstplayer.cpp:3178
eMEDIATYPE_DSM_CC
@ eMEDIATYPE_DSM_CC
Definition: AampMediaType.h:56
PrivateInstanceAAMP::NotifyFirstVideoFrameDisplayed
void NotifyFirstVideoFrameDisplayed()
Notify First Video Frame was displayed.
Definition: priv_aamp.cpp:9834
AAMPGstPlayer::PipelineSetToReady
bool PipelineSetToReady
Definition: aampgstplayer.h:337
PrivateInstanceAAMP::ReportID3Metadata
void ReportID3Metadata(MediaType mediaType, const uint8_t *ptr, uint32_t len, const char *schemeIdURI=NULL, const char *id3Value=NULL, uint64_t presTime=0, uint32_t id3ID=0, uint32_t eventDur=0, uint32_t tScale=0, uint64_t tStampOffset=0)
Report ID3 metadata events.
Definition: priv_aamp.cpp:11540
AAMPGstPlayer_OnGstDecodeErrorCb
static void AAMPGstPlayer_OnGstDecodeErrorCb(GstElement *object, guint arg0, gpointer arg1, AAMPGstPlayer *_this)
Callback invoked a Decode error is encountered.
Definition: aampgstplayer.cpp:1224
AAMP_EVENT_ID3_METADATA
@ AAMP_EVENT_ID3_METADATA
Definition: AampEvent.h:82
priv_aamp.h
Private functions and types used internally by AAMP.
AAMPGstPlayerPriv::firstVideoFrameReceived
bool firstVideoFrameReceived
Definition: aampgstplayer.cpp:219
AAMPGstPlayerPriv::TaskControlMutex
std::mutex TaskControlMutex
Definition: aampgstplayer.cpp:159
PrivateInstanceAAMP::seek_pos_seconds
double seek_pos_seconds
Definition: priv_aamp.h:954
AAMPGstPlayer::AAMPGstPlayer
AAMPGstPlayer(AampLogManager *logObj, PrivateInstanceAAMP *aamp)
AAMPGstPlayer Constructor.
Definition: aampgstplayer.cpp:328
media_stream::eosReached
bool eosReached
Definition: aampgstplayer.cpp:128
IsoBmffBuffer::parseBuffer
bool parseBuffer(bool correctBoxSize=false, int newTrackId=-1)
Parse ISOBMFF boxes from buffer.
Definition: isobmffbuffer.cpp:59
GetStatus
static std::string GetStatus(gpointer pElementOrBin, int &recursionCount, gpointer pParent=nullptr)
returns a string describing pElementOrBin and its children (if any). The top level elements name:stat...
Definition: aampgstplayer.cpp:3226
FORMAT_SUBTITLE_MP4
@ FORMAT_SUBTITLE_MP4
Definition: main_aamp.h:121
PrivateInstanceAAMP::ScheduleAsyncTask
int ScheduleAsyncTask(IdleTask task, void *arg, std::string taskName="")
Add async task to scheduler.
Definition: priv_aamp.cpp:10632
eAAMPConfig_ReTuneOnBufferingTimeout
@ eAAMPConfig_ReTuneOnBufferingTimeout
Definition: AampConfig.h:125
AAMPGstPlayer::DestroyPipeline
void DestroyPipeline()
Cleanup an existing Gstreamer pipeline and associated resources.
Definition: aampgstplayer.cpp:1887
AAMPGstPlayerPriv::ptsCheckForEosOnUnderflowIdleTaskId
guint ptsCheckForEosOnUnderflowIdleTaskId
Definition: aampgstplayer.cpp:201
AAMPGstPlayer::GetVideoRectangle
std::string GetVideoRectangle()
Get the video rectangle co-ordinates.
Definition: aampgstplayer.cpp:4589
AAMPGstPlayerPriv::periodicProgressCallbackIdleTaskId
guint periodicProgressCallbackIdleTaskId
Definition: aampgstplayer.cpp:161
AAMPLOG_TRACE
#define AAMPLOG_TRACE(FORMAT,...)
AAMP logging defines, this can be enabled through setLogLevel() as per the need.
Definition: AampLogManager.h:83
TaskControlData
data for scheduling and handling asynchronous tasks
Definition: aampgstplayer.h:44
isobmffbuffer.h
Header file for ISO Base Media File Format Buffer.
DEFAULT_BUFFERING_QUEUED_FRAMES_MIN
#define DEFAULT_BUFFERING_QUEUED_FRAMES_MIN
Definition: aampgstplayer.cpp:91
PrivateInstanceAAMP
Class representing the AAMP player's private instance, which is not exposed to outside world.
Definition: priv_aamp.h:640
PrivAAMPState
PrivAAMPState
Mapping all required status codes based on JS player requirement. These requirements may be forced by...
Definition: AampEvent.h:156
AAMPGstPlayerPriv::firstAudioFrameReceived
bool firstAudioFrameReceived
Definition: aampgstplayer.cpp:220
PrivateInstanceAAMP::GetAudTimeScale
uint32_t GetAudTimeScale(void)
Gets Audio TimeScale.
Definition: priv_aamp.cpp:11620
AAMPGstPlayer_OnAudioFirstFrameAudDecoder
static void AAMPGstPlayer_OnAudioFirstFrameAudDecoder(GstElement *object, guint arg0, gpointer arg1, AAMPGstPlayer *_this)
Callback invoked after first audio buffer decoded.
Definition: aampgstplayer.cpp:956
AAMPGstPlayer::SendNewSegmentEvent
void SendNewSegmentEvent(MediaType mediaType, GstClockTime startPts, GstClockTime stopPts=0)
Send new segment event to pipeline.
Definition: aampgstplayer.cpp:2596
PrivateInstanceAAMP::SyncEnd
void SyncEnd(void)
GStreamer operation end.
Definition: priv_aamp.cpp:1902
PrivateInstanceAAMP::IsFirstVideoFrameDisplayedRequired
bool IsFirstVideoFrameDisplayedRequired()
Check if First Video Frame Displayed Notification is required.
Definition: priv_aamp.cpp:9826
PrivateInstanceAAMP::SendErrorEvent
void SendErrorEvent(AAMPTuneFailure tuneFailure, const char *description=NULL, bool isRetryEnabled=true, int32_t secManagerClassCode=-1, int32_t secManagerReasonCode=-1, int32_t secClientBusinessStatus=-1)
Handles errors and sends events to application if required. For download failures,...
Definition: priv_aamp.cpp:2454
AAMPGstPlayer::SendCopy
bool SendCopy(MediaType mediaType, const void *ptr, size_t len, double fpts, double fdts, double fDuration)
inject HLS/ts elementary stream buffer to gstreamer pipeline
Definition: aampgstplayer.cpp:2805
AAMP_MIN_DECODE_ERROR_INTERVAL
#define AAMP_MIN_DECODE_ERROR_INTERVAL
Definition: aampgstplayer.cpp:99
AAMPGstPlayer::InitializeAAMPGstreamerPlugins
static void InitializeAAMPGstreamerPlugins(AampLogManager *logObj=NULL)
Increase the rank of AAMP decryptor plugins.
Definition: aampgstplayer.cpp:4391
buffering_timeout
static gboolean buffering_timeout(gpointer data)
g_timeout callback to wait for buffering to change pipeline from paused->playing
Definition: aampgstplayer.cpp:1238
AAMPGstPlayerPriv::buffering_timeout_cnt
guint buffering_timeout_cnt
Definition: aampgstplayer.cpp:194
AAMPGstPlayerPriv::audio_sink
GstElement * audio_sink
Definition: aampgstplayer.cpp:166
PrivateInstanceAAMP::PausePipeline
bool PausePipeline(bool pause, bool forceStopGstreamerPreBuffering)
To change the the gstreamer pipeline to pause/play.
Definition: priv_aamp.cpp:2440
GetDrmSystemID
const char * GetDrmSystemID(DRMSystems drmSystem)
Get ID of DRM system.
Definition: AampUtils.cpp:649
GST_PLAY_FLAG_AUDIO
@ GST_PLAY_FLAG_AUDIO
Definition: aampgstplayer.cpp:57
PrivateInstanceAAMP::SendAnomalyEvent
void SendAnomalyEvent(AAMPAnomalyMessageType type, const char *format,...)
Sends Anomaly Error/warning messages.
Definition: priv_aamp.cpp:2391
getId3TagSize
uint32_t getId3TagSize(const uint8_t *data)
Definition: aampgstplayer.cpp:2569
PrivateInstanceAAMP::PauseSubtitleParser
void PauseSubtitleParser(bool pause)
pause/un-pause subtitles
Definition: priv_aamp.cpp:8460
AAMPGstPlayer::Stop
void Stop(bool keepLastFrame)
Stop playback and any idle handlers active at the time.
Definition: aampgstplayer.cpp:3072
AAMPGstPlayer::RecalculatePTS
double RecalculatePTS(MediaType mediaType, const void *ptr, size_t len)
Definition: aampgstplayer.cpp:2378
PrivateInstanceAAMP::ReportProgress
void ReportProgress(bool sync=true, bool beginningOfStream=false)
Report progress event to listeners.
Definition: priv_aamp.cpp:1928
AAMPGstPlayerPriv::positionQuery
GstQuery * positionQuery
Definition: aampgstplayer.cpp:204
BackgroundTask
int(* BackgroundTask)(void *arg)
Function pointer for the idle task.
Definition: aampgstplayer.h:57
AAMPGstPlayer::ResetEOSSignalledFlag
void ResetEOSSignalledFlag()
Reset EOS SignalledFlag.
Definition: aampgstplayer.cpp:4259
eSTATE_IDLE
@ eSTATE_IDLE
Definition: AampEvent.h:158
PrivateInstanceAAMP::GetFirstPTS
double GetFirstPTS()
Get PTS of first sample.
Definition: priv_aamp.cpp:8638
eAAMPConfig_VODTrickPlayFPS
@ eAAMPConfig_VODTrickPlayFPS
Definition: AampConfig.h:225
GetGstCaps
GstCaps * GetGstCaps(StreamOutputFormat format)
Parse format to generate GstCaps.
Definition: AampGstUtils.cpp:32
AAMPGstPlayerPriv::firstFrameCallbackIdleTaskId
guint firstFrameCallbackIdleTaskId
Definition: aampgstplayer.cpp:186
AAMPGstPlayer::Flush
void Flush(void)
Flush the buffers in pipeline.
Definition: aampgstplayer.cpp:3476
media_stream::flush
bool flush
Definition: aampgstplayer.cpp:125
AAMPGstPlayerPriv::zoom
VideoZoomMode zoom
Definition: aampgstplayer.cpp:174
httpsoup_source_setup
static void httpsoup_source_setup(GstElement *element, GstElement *source, gpointer data)
callback when the source has been created
Definition: aampgstplayer.cpp:714
PrivateInstanceAAMP::DownloadsAreEnabled
bool DownloadsAreEnabled(void)
Check if downloads are enabled.
Definition: priv_aamp.cpp:6752
AAMPGstPlayer_redButtonCallback
static void AAMPGstPlayer_redButtonCallback(GstElement *object, guint hours, guint minutes, guint seconds, gpointer user_data)
Callback invoked after receiving the SEI Time Code information.
Definition: aampgstplayer.cpp:938
AampConfig::IsConfigSet
bool IsConfigSet(AAMPConfigSettings cfg)
Gets the boolean configuration value.
Definition: AampConfig.cpp:649
AAMPGstPlayer::CheckForPTSChangeWithTimeout
bool CheckForPTSChangeWithTimeout(long timeout)
Check if PTS is changing.
Definition: aampgstplayer.cpp:4193
AAMPGstPlayer::SeekStreamSink
void SeekStreamSink(double position, double rate)
Flush the data in case of a new tune pipeline.
Definition: aampgstplayer.cpp:4576
enough_data
static void enough_data(GstElement *source, AAMPGstPlayer *_this)
Callback for appsrc "enough-data" signal.
Definition: aampgstplayer.cpp:578
AAMPGstPlayerPriv::subtitle_sink
GstElement * subtitle_sink
Definition: aampgstplayer.cpp:167
AAMPGstPlayerPriv::video_dec
GstElement * video_dec
Definition: aampgstplayer.cpp:163
eMEDIAFORMAT_HLS_MP4
@ eMEDIAFORMAT_HLS_MP4
Definition: AampDrmMediaFormat.h:37
AAMPGstPlayer::IsCacheEmpty
bool IsCacheEmpty(MediaType mediaType)
Check if cache empty for a media type.
Definition: aampgstplayer.cpp:4267
AAMPGstPlayer::GetVideoSize
void GetVideoSize(int &w, int &h)
Get video display's width and height.
Definition: aampgstplayer.cpp:4349
BUFFERING_TIMEOUT_PRIORITY
#define BUFFERING_TIMEOUT_PRIORITY
Definition: aampgstplayer.cpp:98
PrivateInstanceAAMP::LogFirstFrame
void LogFirstFrame(void)
Notifies profiler that first frame is presented.
Definition: priv_aamp.cpp:3107
AAMPGstPlayerPriv::lastKnownPTS
gint64 lastKnownPTS
Definition: aampgstplayer.cpp:199
media_stream::using_playersinkbin
gboolean using_playersinkbin
Definition: aampgstplayer.cpp:124
PLUGINS_TO_LOWER_RANK_MAX
#define PLUGINS_TO_LOWER_RANK_MAX
Definition: aampgstplayer.cpp:319
eAAMPConfig_SourceSetupTimeout
@ eAAMPConfig_SourceSetupTimeout
Definition: AampConfig.h:248
AAMPGstPlayer::SetSubtitleMute
void SetSubtitleMute(bool mute)
Definition: aampgstplayer.cpp:3844
eMEDIATYPE_SUBTITLE
@ eMEDIATYPE_SUBTITLE
Definition: AampMediaType.h:41
AAMPGstPlayer::NotifyFragmentCachingComplete
void NotifyFragmentCachingComplete()
Set pipeline to PLAYING state once fragment caching is complete.
Definition: aampgstplayer.cpp:4315
media_stream::sourceConfigured
bool sourceConfigured
Definition: aampgstplayer.cpp:129
PrivateInstanceAAMP::lastId3DataLen
int32_t lastId3DataLen[eMEDIATYPE_DEFAULT]
Definition: priv_aamp.h:1070
DEFAULT_BUFFERING_TO_MS
#define DEFAULT_BUFFERING_TO_MS
Definition: aampgstplayer.cpp:86
PROFILE_BUCKET_FIRST_BUFFER
@ PROFILE_BUCKET_FIRST_BUFFER
Definition: AampProfiler.h:72
AAMPGstPlayerPriv::videoMuted
bool videoMuted
Definition: aampgstplayer.cpp:175
MediaFormat
MediaFormat
Media format types.
Definition: AampDrmMediaFormat.h:32
AAMP_TUNE_HDCP_COMPLIANCE_ERROR
@ AAMP_TUNE_HDCP_COMPLIANCE_ERROR
Definition: AampEvent.h:143
InitializeSource
static void InitializeSource(AAMPGstPlayer *_this, GObject *source, MediaType mediaType=eMEDIATYPE_VIDEO)
Initialize properties/callback of appsrc.
Definition: aampgstplayer.cpp:623
AAMPGstPlayer::PauseAndFlush
void PauseAndFlush(bool playAfterFlush)
PauseAndFlush pipeline and flush.
Definition: aampgstplayer.cpp:3488
eSTATE_PLAYING
@ eSTATE_PLAYING
Definition: AampEvent.h:166
AAMPGstPlayerPriv::paused
bool paused
Definition: aampgstplayer.cpp:206
AAMPGstPlayer::AdjustPlayBackRate
bool AdjustPlayBackRate(double position, double rate)
adjust playback rate
Definition: aampgstplayer.cpp:4875
eAAMPConfig_ReportBufferEvent
@ eAAMPConfig_ReportBufferEvent
Definition: AampConfig.h:135
appsrc_seek
static gboolean appsrc_seek(GstAppSrc *src, guint64 offset, AAMPGstPlayer *_this)
Callback for appsrc "seek-data" signal.
Definition: aampgstplayer.cpp:608
media_stream::source
GstElement * source
Definition: aampgstplayer.cpp:122
TRUE
#define TRUE
Defines for TRUE/FALSE/ENABLE flags.
Definition: wifi_common_hal.h:199
AAMPGstPlayer::StopBuffering
void StopBuffering(bool forceStop)
Un-pause pipeline and notify buffer end event to player.
Definition: aampgstplayer.cpp:4598
PrivateInstanceAAMP::ResumeTrackDownloads
void ResumeTrackDownloads(MediaType type)
Resume downloads for a track. Called from StreamSink to control flow.
Definition: priv_aamp.cpp:3202
eGST_ERROR_VIDEO_BUFFERING
@ eGST_ERROR_VIDEO_BUFFERING
Definition: priv_aamp.h:176
PrivateInstanceAAMP::SendBufferChangeEvent
void SendBufferChangeEvent(bool bufferingStopped=false)
Sends UnderFlow Event messages.
Definition: priv_aamp.cpp:2424
ANOMALY_WARNING
@ ANOMALY_WARNING
Definition: main_aamp.h:72
VideoDecoderPtsCheckerForEOS
static gboolean VideoDecoderPtsCheckerForEOS(gpointer user_data)
Notifies EOS if video decoder pts is stalled.
Definition: aampgstplayer.cpp:1055
PrivateInstanceAAMP::rate
float rate
Definition: priv_aamp.h:955
media_stream::resetPosition
bool resetPosition
Definition: aampgstplayer.cpp:126
GST_PLAY_FLAG_NATIVE_VIDEO
@ GST_PLAY_FLAG_NATIVE_VIDEO
Definition: aampgstplayer.cpp:62
eSTATE_SEEKING
@ eSTATE_SEEKING
Definition: AampEvent.h:165
eAAMPConfig_UseAppSrcForProgressivePlayback
@ eAAMPConfig_UseAppSrcForProgressivePlayback
Definition: AampConfig.h:133
IdleCallbackOnEOS
static gboolean IdleCallbackOnEOS(gpointer user_data)
Idle callback to notify end-of-stream event.
Definition: aampgstplayer.cpp:753
PrivateInstanceAAMP::mAudioOnlyPb
bool mAudioOnlyPb
Definition: priv_aamp.h:1102
analyze_streams
static void analyze_streams(AAMPGstPlayer *_this)
Analyze stream info from the GstPipeline.
Definition: aampgstplayer.cpp:509
media_stream::trackId
int32_t trackId
Definition: aampgstplayer.cpp:132
AAMPGstPlayer_GetAppSrc
static GstElement * AAMPGstPlayer_GetAppSrc(AAMPGstPlayer *_this, MediaType mediaType)
Create an appsrc element for a particular format.
Definition: aampgstplayer.cpp:2068