RDK Documentation (Open Sourced RDK Components)
rne-player.cpp
1 /*
2  * If not stated otherwise in this file or this component's Licenses.txt file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2016 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 #ifdef ENABLE_BREAKPAD
21 #include "client/linux/handler/exception_handler.h"
22 #endif
23 
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <signal.h>
28 #include <gst/gst.h>
29 
30 #include "wayland-client.h"
31 
32 #define UNUSED( x ) ((void)(x))
33 
34 typedef struct _AppCtx
35 {
36  struct wl_display *display;
37  struct wl_registry *registry;
38  struct wl_output *output;
39  GstElement *pipeline;
40  GstElement *player;
41  GstElement *westerossink;
42  GstBus *bus;
43  GMainLoop *loop;
44 } AppCtx;
45 #ifdef ENABLE_BREAKPAD
46 static bool breakpadDumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
47  void* context,
48  bool succeeded)
49 {
50  printf("\nbreakpadDumpCallback: application crashed ---- Dump path: %s\n",descriptor.path());
51  return succeeded;
52 }
53 
54 #endif
55 
56 
57 static void showUsage()
58 {
59  printf("usage:\n");
60  printf(" rne_player [options] <uri>\n" );
61  printf(" uri - URI of video asset to play\n" );
62  printf("where [options] are:\n" );
63  printf(" -? : show usage\n" );
64  printf("\n" );
65 }
66 
67 static void outputHandleGeometry( void *data,
68  struct wl_output *output,
69  int x,
70  int y,
71  int mmWidth,
72  int mmHeight,
73  int subPixel,
74  const char *make,
75  const char *model,
76  int transform )
77 {
78  UNUSED(data);
79  UNUSED(output);
80  UNUSED(x);
81  UNUSED(y);
82  UNUSED(mmWidth);
83  UNUSED(mmHeight);
84  UNUSED(subPixel);
85  UNUSED(make);
86  UNUSED(model);
87  UNUSED(transform);
88 }
89 
90 static void outputHandleMode( void *data,
91  struct wl_output *output,
92  uint32_t flags,
93  int width,
94  int height,
95  int refreshRate )
96 {
97  AppCtx *ctx= (AppCtx*)data;
98  char work[32];
99 
100  if ( flags & WL_OUTPUT_MODE_CURRENT )
101  {
102  printf("outputMode: %dx%d flags %X\n", width, height, flags);
103 
104  if ( ctx->westerossink )
105  {
106  sprintf( work, "%d,%d,%d,%d", 0, 0, width, height );
107  g_object_set(G_OBJECT(ctx->westerossink), "window-set", work, NULL );
108  }
109  }
110 }
111 
112 static void outputHandleDone( void *data,
113  struct wl_output *output )
114 {
115  UNUSED(data);
116  UNUSED(output);
117 }
118 
119 static void outputHandleScale( void *data,
120  struct wl_output *output,
121  int32_t scale )
122 {
123  UNUSED(data);
124  UNUSED(output);
125  UNUSED(scale);
126 }
127 
128 static const struct wl_output_listener outputListener = {
129  outputHandleGeometry,
130  outputHandleMode,
131  outputHandleDone,
132  outputHandleScale
133 };
134 
135 static void registryHandleGlobal(void *data,
136  struct wl_registry *registry, uint32_t id,
137  const char *interface, uint32_t version)
138 {
139  AppCtx *ctx= (AppCtx*)data;
140  int len;
141 
142  len= strlen(interface);
143  if ( (len==9) && !strncmp(interface, "wl_output", len) ) {
144  ctx->output= (struct wl_output*)wl_registry_bind(registry, id, &wl_output_interface, 2);
145  wl_output_add_listener(ctx->output, &outputListener, ctx);
146  wl_display_roundtrip( ctx->display );
147  }
148 }
149 
150 static void registryHandleGlobalRemove(void *data,
151  struct wl_registry *registry,
152  uint32_t name)
153 {
154  UNUSED(data);
155  UNUSED(registry);
156  UNUSED(name);
157 }
158 
159 static const struct wl_registry_listener registryListener =
160 {
161  registryHandleGlobal,
162  registryHandleGlobalRemove
163 };
164 
165 static gboolean busCallback(GstBus *bus, GstMessage *message, gpointer data)
166 {
167  AppCtx *ctx= (AppCtx*)data;
168 
169  switch ( GST_MESSAGE_TYPE(message) )
170  {
171  case GST_MESSAGE_ERROR:
172  {
173  GError *error;
174  gchar *debug;
175 
176  gst_message_parse_error(message, &error, &debug);
177  g_print("Error: %s\n", error->message);
178  if ( debug )
179  {
180  g_print("Debug info: %s\n", debug);
181  }
182  g_error_free(error);
183  g_free(debug);
184  g_main_loop_quit( ctx->loop );
185  }
186  break;
187  case GST_MESSAGE_EOS:
188  g_print( "EOS ctx %p\n", ctx );
189  g_main_loop_quit( ctx->loop );
190  break;
191  case GST_MESSAGE_BUFFERING:
192  {
193  gint percent;
194  static bool triggerPlay = false;
195  gst_message_parse_buffering (message, &percent);
196  if(percent >= 50 && !triggerPlay)
197  {
198  triggerPlay = true;
199  printf("50 percent buffered, going to play!\n");
200  gst_element_set_state(ctx->pipeline, GST_STATE_PLAYING);
201  }
202  }
203  break;
204  default:
205  break;
206  }
207  return TRUE;
208 }
209 
210 /* Function demonstrating how to setup proxy for accessing URLs */
211 static void cb_playbin_source_setup( GObject *obj )
212 {
213  const char* rne_proxy = getenv("RNE_PROXY");
214  GObject *source_element;
215 
216  if( g_object_class_find_property( G_OBJECT_GET_CLASS( obj ), "source" ) )
217  {
218  /* Get source element of playbin*/
219  g_object_get(obj, "source", &source_element, NULL);
220 
221  if( NULL != rne_proxy )
222  {
223  printf( "The proxy is %s\n", rne_proxy );
224  if( g_object_class_find_property ( G_OBJECT_GET_CLASS( source_element ), "proxy" ) )
225  {
226  g_object_set( G_OBJECT( source_element ), "proxy", rne_proxy, NULL );
227  }
228  }
229  //Set strict-tls property to false
230  if( g_object_class_find_property ( G_OBJECT_GET_CLASS( source_element ), "ssl-strict" ) )
231  {
232  g_object_set( G_OBJECT( source_element ), "ssl-strict", FALSE , NULL );
233  }
234  g_object_unref( source_element );
235  }
236 }
237 
238 bool createPipeline( AppCtx *ctx )
239 {
240  bool result= false;
241  int argc= 0;
242  char **argv= 0;
243  gint64 bufferDuration = 10 * GST_SECOND;
244 
245  gst_init( &argc, &argv );
246 
247  ctx->pipeline= gst_pipeline_new("pipeline");
248  if ( !ctx->pipeline )
249  {
250  printf("Error: unable to create pipeline instance\n" );
251  goto exit;
252  }
253 
254  ctx->bus= gst_pipeline_get_bus( GST_PIPELINE(ctx->pipeline) );
255  if ( !ctx->bus )
256  {
257  printf("Error: unable to get pipeline bus\n");
258  goto exit;
259  }
260  gst_bus_add_watch( ctx->bus, busCallback, ctx );
261 
262  ctx->player= gst_element_factory_make( "playbin", "player" );
263  g_object_set(G_OBJECT(ctx->player),"buffer-duration",bufferDuration,NULL);
264 
265  if ( !ctx->player )
266  {
267  printf("Error: unable to create playbin instance\n" );
268  goto exit;
269  }
270  gst_object_ref( ctx->player );
271 
272  ctx->westerossink= gst_element_factory_make( "westerossink", "vsink" );
273  if ( !ctx->westerossink )
274  {
275  printf("Error: unable to create westerossink instance\n" );
276  goto exit;
277  }
278  gst_object_ref( ctx->westerossink );
279 
280  g_object_set(G_OBJECT(ctx->player), "video-sink", ctx->westerossink, NULL );
281 
282  /* Secure video path - SVP is available for Broadcom platform 16.2 and above */
283  if( g_object_class_find_property( G_OBJECT_GET_CLASS( ctx->westerossink ), "secure-video" ) )
284  {
285  g_object_set( G_OBJECT( ctx->westerossink ), "secure-video", true, NULL );
286  }
287 
288  if ( !gst_bin_add( GST_BIN(ctx->pipeline), ctx->player) )
289  {
290  printf("Error: unable to add playbin to pipeline\n");
291  goto exit;
292  }
293 
294  g_signal_connect( G_OBJECT( ctx->player ), "source-setup", G_CALLBACK( cb_playbin_source_setup ), NULL );
295 
296  result= true;
297 
298 exit:
299 
300  return result;
301 }
302 
303 void destroyPipeline( AppCtx *ctx )
304 {
305  if ( ctx->pipeline )
306  {
307  gst_element_set_state(ctx->pipeline, GST_STATE_NULL);
308  }
309  if ( ctx->westerossink )
310  {
311  gst_object_unref( ctx->westerossink );
312  ctx->westerossink= 0;
313  }
314  if ( ctx->player )
315  {
316  gst_object_unref( ctx->player );
317  ctx->player= 0;
318  }
319  if ( ctx->bus )
320  {
321  gst_object_unref( ctx->bus );
322  ctx->bus= 0;
323  }
324  if ( ctx->pipeline )
325  {
326  gst_object_unref( GST_OBJECT(ctx->pipeline) );
327  ctx->pipeline= 0;
328  }
329 }
330 
331 static AppCtx *g_ctx= 0;
332 
333 static void signalHandler(int signum)
334 {
335  printf("signalHandler: signum %d\n", signum);
336  if ( g_ctx )
337  {
338  g_main_loop_quit( g_ctx->loop );
339  g_ctx= 0;
340  }
341 }
342 
343 int main( int argc, char **argv )
344 {
345  int result= -1;
346  int argidx;
347  const char *uri= "http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_720p_h264.mov";
348  AppCtx *ctx= 0;
349  struct sigaction sigint;
350 #ifdef ENABLE_BREAKPAD
351  google_breakpad::MinidumpDescriptor descriptor("/tmp");
352  google_breakpad::ExceptionHandler eh(descriptor, NULL, breakpadDumpCallback, NULL, true, -1);
353 #endif
354  printf("rne_player: v1.0\n\n" );
355 /*
356  if ( argc < 2 )
357  {
358  showUsage();
359  goto exit;
360  }
361 */
362  argidx= 1;
363  while ( argidx < argc )
364  {
365  if ( argv[argidx][0] == '-' )
366  {
367  switch( argv[argidx][1] )
368  {
369  case '?':
370  showUsage();
371  goto exit;
372  default:
373  printf( "unknown option %s\n\n", argv[argidx] );
374  exit( -1 );
375  break;
376  }
377  }
378  else
379  {
380  uri= argv[argidx];
381 /*
382  if ( !uri )
383  {
384  uri= argv[argidx];
385  }
386  else
387  {
388  printf( "ignoring extra argument: %s\n", argv[argidx] );
389  }
390 */
391  }
392 
393  ++argidx;
394  }
395 
396  if ( !uri )
397  {
398  printf( "missing uri argument\n" );
399  goto exit;
400  }
401 
402  printf( "playing asset: %s\n", uri );
403 
404  ctx= (AppCtx*)calloc( 1, sizeof(AppCtx) );
405  if ( !ctx )
406  {
407  printf("Error: unable to allocate application context\n");
408  goto exit;
409  }
410 
411  ctx->display= wl_display_connect( NULL );
412  if ( !ctx->display )
413  {
414  printf("Error: unable to open default wayland display\n");
415  goto exit;
416  }
417  ctx->registry= wl_display_get_registry(ctx->display);
418  if ( !ctx->registry )
419  {
420  printf("Error: unable to get wayland registry\n");
421  goto exit;
422  }
423  wl_registry_add_listener(ctx->registry, &registryListener, ctx);
424  wl_display_roundtrip(ctx->display);
425 
426  if ( createPipeline( ctx ) )
427  {
428  printf("pipeline created\n");
429  ctx->loop= g_main_loop_new(NULL,FALSE);
430 
431  if ( ctx->loop )
432  {
433  g_object_set(G_OBJECT(ctx->player), "uri", uri, NULL );
434 
435  if ( GST_STATE_CHANGE_FAILURE != gst_element_set_state(ctx->pipeline, GST_STATE_PAUSED) )
436  {
437  sigint.sa_handler = signalHandler;
438  sigemptyset(&sigint.sa_mask);
439  sigint.sa_flags = SA_RESETHAND;
440  sigaction(SIGINT, &sigint, NULL);
441 
442  g_ctx= ctx;
443 
444  g_main_loop_run( ctx->loop );
445  }
446  }
447  else
448  {
449  printf( "Error: unable to create main loop\n");
450  }
451  }
452  else
453  {
454  printf( "Error: unable to create player pipeline\n" );
455  }
456 
457 
458  result= 0;
459 
460 exit:
461 
462  if ( ctx )
463  {
464  if ( ctx->output )
465  {
466  wl_output_destroy( ctx->output );
467  ctx->output= 0;
468  }
469 
470  if ( ctx->registry )
471  {
472  wl_registry_destroy(ctx->registry);
473  ctx->registry= 0;
474  }
475 
476  if ( ctx->display )
477  {
478  wl_display_disconnect(ctx->display);
479  ctx->display= 0;
480  }
481 
482  destroyPipeline( ctx );
483 
484  if ( ctx->loop )
485  {
486  g_main_loop_unref(ctx->loop);
487  ctx->loop= 0;
488  }
489 
490  free( ctx );
491  }
492 
493  return result;
494 }
495 
TRUE
#define TRUE
Defines for TRUE/FALSE/ENABLE flags.
Definition: wifi_common_hal.h:199
_AppCtx
Definition: rne-triangle.cpp:136