|
1 /* |
|
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Implementation of UPnP GStreamer wrapper |
|
15 * |
|
16 */ |
|
17 |
|
18 // INCLUDES |
|
19 #include <bautils.h> |
|
20 |
|
21 #include <gst/app/gstappsink.h> |
|
22 |
|
23 #include <gst/app/gstappsink.h> |
|
24 #include <gst/app/gstappbuffer.h> |
|
25 |
|
26 #include <gst/gst.h> |
|
27 #include <gst/gstinfo.h> |
|
28 |
|
29 #include "upnpgstwrapper.h" |
|
30 |
|
31 _LIT( KComponentLogfile, "upnpgstwrapper.txt"); |
|
32 #include "upnplog.h" |
|
33 |
|
34 #define __FUNC_LOG __LOG8_1( "%s", __PRETTY_FUNCTION__ ); |
|
35 |
|
36 _LIT( KAlreadyInUseErrorMsg, "GST already in use (call Stop first)" ); |
|
37 _LIT( KUnknownErrorErrorMsg, "Unknown error" ); |
|
38 _LIT( KOutOfMemoryErrorMsg, "Out of memory" ); |
|
39 |
|
40 const char* const KMimeTypeVideo = "video/"; |
|
41 const char* const KMimeTypeAudio = "audio/"; |
|
42 const char* const KDemuxerName = "demux"; |
|
43 |
|
44 class CUpnpGstWrapperPimpl : CBase |
|
45 { |
|
46 |
|
47 public: // construction / destruction |
|
48 |
|
49 /** |
|
50 * Static NewL |
|
51 * |
|
52 * @param none |
|
53 * @return instance to CUpnpGstWrapperPimpl |
|
54 */ |
|
55 static CUpnpGstWrapperPimpl* NewL(); |
|
56 |
|
57 /** |
|
58 * Destructor |
|
59 */ |
|
60 ~CUpnpGstWrapperPimpl(); |
|
61 |
|
62 private: |
|
63 |
|
64 /** |
|
65 * Constructor |
|
66 */ |
|
67 CUpnpGstWrapperPimpl(); |
|
68 |
|
69 /** |
|
70 * 2nd phrase Constructor |
|
71 */ |
|
72 void ConstructL(); |
|
73 |
|
74 public: |
|
75 |
|
76 inline void SetPipeline( GstElement* aPipeline ); |
|
77 |
|
78 inline GstElement* Pipeline(); |
|
79 |
|
80 inline void SetDemuxer( GstElement* aDemuxer ); |
|
81 |
|
82 inline GstElement* Demuxer(); |
|
83 |
|
84 inline void InitAppSinkL(); |
|
85 |
|
86 inline TBool PullBufferL( TPtr8& aPointer,TInt aMaxBytesLength, RBuf8* aBuf ); |
|
87 |
|
88 inline TInt TranscodedBytes(); |
|
89 |
|
90 public: //callbacks |
|
91 |
|
92 /** |
|
93 * A function to receive any message occured within the pipeline |
|
94 * Note that the function will be called in the same thread context as |
|
95 * the posting object. |
|
96 * |
|
97 * @param GstBus* a bus to create the watch for |
|
98 * @param GstMessage* a message created within the pipeline |
|
99 * @param gponter the user data that has been given, |
|
100 * when registering the handler |
|
101 * @return GstBusSyncReply indicates whether the message is also added |
|
102 * into async queue (after this callback) or dropped |
|
103 */ |
|
104 static GstBusSyncReply SyncBusCallback( GstBus* aBus, GstMessage* aMsg, |
|
105 gpointer aData ); |
|
106 |
|
107 /** |
|
108 * A function to receive callback from demuxer whenever source pad is |
|
109 * added into it |
|
110 * |
|
111 * @param GstElement* an element (demuxer) where the source pad was added |
|
112 * @param GstPad* a souce pad that was added |
|
113 * @param gponter the user data that has been given, |
|
114 * when registering the handler |
|
115 */ |
|
116 static void DemuxPadAddedCallback( GstElement* aElement, GstPad* aPad, |
|
117 gpointer aData ); |
|
118 |
|
119 /** |
|
120 * Internal log handler. |
|
121 * Implements GStreamer's log handler callback. |
|
122 * Ouputs GStreamer debug traces if DEBUG_ENABLE flag is enabled in |
|
123 * GStreamer. |
|
124 */ |
|
125 static void LogCallback( GstDebugCategory *category, GstDebugLevel level, |
|
126 const gchar *file, const gchar *function, gint line, |
|
127 GObject *object, GstDebugMessage *message, gpointer data ); |
|
128 |
|
129 private: |
|
130 |
|
131 GstElement* iPipeline; |
|
132 GstElement* iDemuxer; |
|
133 |
|
134 TInt iBytesOffSet; |
|
135 |
|
136 GstElement* iAppsink; |
|
137 |
|
138 GstElement* iElement; |
|
139 |
|
140 GstBuffer* iGstBuffer; |
|
141 |
|
142 }; |
|
143 |
|
144 // -------------------------------------------------------------------------- |
|
145 // CUpnpGstWrapperPimpl::NewL |
|
146 //--------------------------------------------------------------------------- |
|
147 CUpnpGstWrapperPimpl* CUpnpGstWrapperPimpl::NewL() |
|
148 { |
|
149 __FUNC_LOG; |
|
150 |
|
151 CUpnpGstWrapperPimpl* self = new( ELeave ) CUpnpGstWrapperPimpl(); |
|
152 CleanupStack::PushL( self ); |
|
153 self->ConstructL(); |
|
154 CleanupStack::Pop( self ); |
|
155 return self; |
|
156 } |
|
157 |
|
158 // -------------------------------------------------------------------------- |
|
159 // CUpnpGstWrapperPimpl::~CUpnpGstWrapperPimpl |
|
160 //--------------------------------------------------------------------------- |
|
161 CUpnpGstWrapperPimpl::~CUpnpGstWrapperPimpl() |
|
162 { |
|
163 __FUNC_LOG; |
|
164 } |
|
165 |
|
166 // -------------------------------------------------------------------------- |
|
167 // CUpnpGstWrapperPimpl::CUpnpGstWrapperPimpl |
|
168 //--------------------------------------------------------------------------- |
|
169 CUpnpGstWrapperPimpl::CUpnpGstWrapperPimpl() |
|
170 { |
|
171 __FUNC_LOG; |
|
172 } |
|
173 |
|
174 // -------------------------------------------------------------------------- |
|
175 // CUpnpGstWrapperPimpl::ConstructL |
|
176 //--------------------------------------------------------------------------- |
|
177 void CUpnpGstWrapperPimpl::ConstructL() |
|
178 { |
|
179 __FUNC_LOG; |
|
180 } |
|
181 |
|
182 void CUpnpGstWrapperPimpl::SetPipeline( GstElement* aPipeline ) |
|
183 { |
|
184 __FUNC_LOG; |
|
185 |
|
186 iPipeline = aPipeline; |
|
187 } |
|
188 |
|
189 GstElement* CUpnpGstWrapperPimpl::Pipeline() |
|
190 { |
|
191 __FUNC_LOG; |
|
192 return iPipeline; |
|
193 } |
|
194 |
|
195 void CUpnpGstWrapperPimpl::SetDemuxer( GstElement* aDemuxer ) |
|
196 { |
|
197 __FUNC_LOG; |
|
198 |
|
199 iDemuxer = aDemuxer; |
|
200 } |
|
201 |
|
202 GstElement* CUpnpGstWrapperPimpl::Demuxer() |
|
203 { |
|
204 __FUNC_LOG; |
|
205 |
|
206 return iDemuxer; |
|
207 } |
|
208 |
|
209 void CUpnpGstWrapperPimpl::InitAppSinkL() |
|
210 { |
|
211 iAppsink = gst_bin_get_by_name ( |
|
212 GST_BIN ( iPipeline ), "sinkbuffer"); |
|
213 |
|
214 if( !iAppsink ) |
|
215 User::Leave( KErrNotFound); |
|
216 |
|
217 g_object_set ( |
|
218 G_OBJECT (iAppsink), "emit-signals", TRUE, "sync", FALSE, NULL); |
|
219 gst_object_unref (iAppsink); |
|
220 } |
|
221 |
|
222 TBool CUpnpGstWrapperPimpl::PullBufferL( TPtr8& aPointer,TInt aMaxBytesLength, RBuf8* aBuf ) |
|
223 { |
|
224 guint size; |
|
225 |
|
226 if( iGstBuffer ) |
|
227 { |
|
228 delete [] GST_BUFFER_DATA(iGstBuffer); |
|
229 GST_BUFFER_DATA(iGstBuffer) = NULL; |
|
230 } |
|
231 |
|
232 iGstBuffer = gst_app_sink_pull_buffer( GST_APP_SINK ( iAppsink )); |
|
233 |
|
234 if( iGstBuffer ) |
|
235 { |
|
236 size = GST_BUFFER_SIZE( iGstBuffer ); |
|
237 |
|
238 iBytesOffSet += size; |
|
239 |
|
240 if( aBuf && ( size + aBuf->Length() ) > aBuf->MaxLength() ) |
|
241 { |
|
242 HBufC8* tmp(NULL); |
|
243 TInt len(aBuf->Length()); |
|
244 if( len > 0 ) |
|
245 { |
|
246 tmp = aBuf->AllocLC(); |
|
247 } |
|
248 aBuf->Close(); |
|
249 aBuf->CreateL(size+len); |
|
250 if( tmp ) |
|
251 { |
|
252 aBuf->Append(*tmp); |
|
253 CleanupStack::PopAndDestroy(tmp); |
|
254 } |
|
255 |
|
256 aBuf->Append( (TUint8*)GST_BUFFER_DATA(iGstBuffer),size ); |
|
257 } |
|
258 else |
|
259 { |
|
260 __ASSERT( (aMaxBytesLength >= size), __FILE__, __LINE__ ); |
|
261 aPointer.Set((TUint8*)GST_BUFFER_DATA(iGstBuffer),size,aMaxBytesLength); |
|
262 } |
|
263 } |
|
264 return ( iGstBuffer ) ? EFalse : ETrue; |
|
265 } |
|
266 |
|
267 TInt CUpnpGstWrapperPimpl::TranscodedBytes() |
|
268 { |
|
269 return iBytesOffSet; |
|
270 } |
|
271 |
|
272 // -------------------------------------------------------------------------- |
|
273 // CUpnpGstWrapperPimpl::SyncBusCallback |
|
274 //--------------------------------------------------------------------------- |
|
275 GstBusSyncReply CUpnpGstWrapperPimpl::SyncBusCallback( GstBus* /*aBus*/, |
|
276 GstMessage* aMsg, gpointer aData ) |
|
277 { |
|
278 __FUNC_LOG; |
|
279 |
|
280 GstMessageType messageType = GST_MESSAGE_TYPE( aMsg ); |
|
281 |
|
282 if( messageType == GST_MESSAGE_EOS || |
|
283 messageType == GST_MESSAGE_ERROR ) |
|
284 { |
|
285 __ASSERT( aData, __FILE__, __LINE__ ); |
|
286 |
|
287 CUpnpGstWrapper* parent = static_cast<CUpnpGstWrapper*>( aData ); |
|
288 Gst::TEvent event = Gst::EUnknown; |
|
289 |
|
290 parent->iMutex.Wait(); |
|
291 |
|
292 switch( messageType ) |
|
293 { |
|
294 case GST_MESSAGE_EOS: |
|
295 { |
|
296 event = Gst::EEOS; |
|
297 break; |
|
298 } |
|
299 case GST_MESSAGE_ERROR: |
|
300 { |
|
301 GError* err = NULL; |
|
302 |
|
303 char* debug; |
|
304 gst_message_parse_error( aMsg, &err, &debug ); |
|
305 g_free( debug ); |
|
306 |
|
307 if( err ) |
|
308 { |
|
309 TRAP_IGNORE( parent->SetErrorMsg( |
|
310 parent->ConvertCharToDescL( |
|
311 err->message ) ) ); |
|
312 g_error_free( err ); |
|
313 err = NULL; |
|
314 } |
|
315 event = Gst::EError; |
|
316 break; |
|
317 } |
|
318 default: |
|
319 { |
|
320 __ASSERT( EFalse, __FILE__, __LINE__ ); |
|
321 } |
|
322 } |
|
323 |
|
324 parent->iEventQueue.Append( event ); |
|
325 |
|
326 __ASSERT( parent->IsActive(), __FILE__, __LINE__ ); |
|
327 if( parent->iStatus == KRequestPending ) |
|
328 { |
|
329 TRequestStatus* status = &parent->iStatus; |
|
330 RThread thread; |
|
331 TInt err = thread.Open( parent->iClientThreadId ); |
|
332 __ASSERT( !err, __FILE__, __LINE__ ); |
|
333 |
|
334 thread.RequestComplete( status, KErrNone ); |
|
335 thread.Close(); |
|
336 } |
|
337 |
|
338 parent->iMutex.Signal(); |
|
339 |
|
340 gst_message_unref( aMsg ); |
|
341 } |
|
342 |
|
343 return GST_BUS_DROP; //do not add anything into async queue |
|
344 } |
|
345 |
|
346 // -------------------------------------------------------------------------- |
|
347 // CUpnpGstWrapperPimpl::DemuxPadAddedCallback |
|
348 //--------------------------------------------------------------------------- |
|
349 void CUpnpGstWrapperPimpl::DemuxPadAddedCallback( GstElement* /*aElement*/, |
|
350 GstPad* aPad, gpointer aData ) |
|
351 { |
|
352 __FUNC_LOG; |
|
353 __ASSERT( aData, __FILE__, __LINE__ ); |
|
354 |
|
355 CUpnpGstWrapper* parent = static_cast<CUpnpGstWrapper*>( aData ); |
|
356 |
|
357 GstCaps* caps = gst_pad_get_caps( aPad ); |
|
358 char* str = gst_caps_to_string( caps ); |
|
359 Gst::TEvent event = Gst::EUnknown; |
|
360 |
|
361 parent->iMutex.Wait(); |
|
362 |
|
363 if( g_str_has_prefix( str, KMimeTypeVideo ) ) |
|
364 { |
|
365 delete parent->iVideoInfo; parent->iVideoInfo = NULL; |
|
366 TRAPD( err, parent->iVideoInfo = parent->ConvertCharToDescL( str ) ); |
|
367 if( !err ) |
|
368 { |
|
369 event = Gst::EVideoStreamInfoAvailable; |
|
370 } |
|
371 else |
|
372 { |
|
373 event = Gst::EError; |
|
374 TRAP_IGNORE( parent->SetErrorMsgL( KOutOfMemoryErrorMsg ) ); |
|
375 } |
|
376 } |
|
377 else if( g_str_has_prefix( str, KMimeTypeAudio ) ) |
|
378 { |
|
379 delete parent->iAudioInfo; parent->iAudioInfo = NULL; |
|
380 TRAPD( err, parent->iAudioInfo = parent->ConvertCharToDescL( str ) ); |
|
381 if( !err ) |
|
382 { |
|
383 event = Gst::EAudioStreamInfoAvailable; |
|
384 } |
|
385 else |
|
386 { |
|
387 event = Gst::EError; |
|
388 TRAP_IGNORE( parent->SetErrorMsgL( KOutOfMemoryErrorMsg ) ); |
|
389 } |
|
390 } |
|
391 else |
|
392 { |
|
393 __ASSERT( EFalse, __FILE__, __LINE__ ); |
|
394 } |
|
395 |
|
396 parent->iEventQueue.Append( event ); |
|
397 |
|
398 __ASSERT( parent->IsActive(), __FILE__, __LINE__ ); |
|
399 if( parent->iStatus == KRequestPending ) |
|
400 { |
|
401 TRequestStatus* status = &parent->iStatus; |
|
402 RThread thread; |
|
403 TInt err = thread.Open( parent->iClientThreadId ); |
|
404 __ASSERT( !err, __FILE__, __LINE__ ); |
|
405 |
|
406 thread.RequestComplete( status, KErrNone ); |
|
407 thread.Close(); |
|
408 } |
|
409 |
|
410 parent->iMutex.Signal(); |
|
411 |
|
412 g_free(str); |
|
413 } |
|
414 |
|
415 // -------------------------------------------------------------------------- |
|
416 // CUpnpGstWrapperPimpl::LogCallback |
|
417 //--------------------------------------------------------------------------- |
|
418 void CUpnpGstWrapperPimpl::LogCallback( GstDebugCategory* category, |
|
419 GstDebugLevel level, const char* file, const char* function, |
|
420 gint line, GObject* /*object*/, GstDebugMessage* message, |
|
421 gpointer /*data*/ ) |
|
422 { |
|
423 if (level > gst_debug_category_get_threshold (category)) |
|
424 { |
|
425 return; |
|
426 } |
|
427 |
|
428 #ifndef __UPNP_LOG_FILE |
|
429 const char* const KGstLogFmt = "%s %20s %s:%d:%s %s\n"; |
|
430 RDebug::Printf( KGstLogFmt, |
|
431 gst_debug_level_get_name (level), |
|
432 gst_debug_category_get_name (category), file, line, function, |
|
433 gst_debug_message_get (message) ); |
|
434 #else |
|
435 _LIT8( KGstLogFmtDesc, "%s %20s %s:%d:%s %s\n" ); |
|
436 RFileLogger::WriteFormat( KLogDir, KComponentLogfile, |
|
437 EFileLoggingModeAppend, KGstLogFmtDesc, |
|
438 gst_debug_level_get_name (level), |
|
439 gst_debug_category_get_name (category), file, line, function, |
|
440 gst_debug_message_get (message) ); |
|
441 #endif |
|
442 } |
|
443 |
|
444 // -------------------------------------------------------------------------- |
|
445 // CUpnpGstWrapper::GetInstanceL |
|
446 // See upnpgstwrapper.h |
|
447 //--------------------------------------------------------------------------- |
|
448 EXPORT_C CUpnpGstWrapper* CUpnpGstWrapper::GetInstanceL() |
|
449 { |
|
450 CUpnpGstWrapper* singleton = static_cast<CUpnpGstWrapper*>( Dll::Tls() ); |
|
451 if ( singleton == 0 ) |
|
452 { |
|
453 // singleton must be created first |
|
454 singleton = new ( ELeave ) CUpnpGstWrapper(); |
|
455 CleanupStack::PushL( singleton ); |
|
456 singleton->ConstructL(); |
|
457 User::LeaveIfError( Dll::SetTls( singleton ) ); |
|
458 CleanupStack::Pop( singleton ); |
|
459 } |
|
460 singleton->iSingletonRefCount++; |
|
461 |
|
462 return singleton; |
|
463 } |
|
464 |
|
465 // -------------------------------------------------------------------------- |
|
466 // CUpnpGstWrapper::Close |
|
467 // See upnpgstwrapper.h |
|
468 //--------------------------------------------------------------------------- |
|
469 EXPORT_C void CUpnpGstWrapper::Close() |
|
470 { |
|
471 if(--iSingletonRefCount == 0) |
|
472 { |
|
473 Dll::FreeTls(); |
|
474 delete this; |
|
475 } |
|
476 } |
|
477 |
|
478 // -------------------------------------------------------------------------- |
|
479 // CUpnpGstWrapper::~CUpnpGstWrapper |
|
480 // See upnpgstwrapper.h |
|
481 //--------------------------------------------------------------------------- |
|
482 EXPORT_C CUpnpGstWrapper::~CUpnpGstWrapper() |
|
483 { |
|
484 __FUNC_LOG; |
|
485 |
|
486 Stop(); |
|
487 |
|
488 Cancel(); |
|
489 |
|
490 gst_deinit(); |
|
491 |
|
492 delete iErrorMsg; |
|
493 delete iVideoInfo; |
|
494 delete iAudioInfo; |
|
495 |
|
496 iEventQueue.Close(); |
|
497 iMutex.Close(); |
|
498 iObservers.Close(); |
|
499 |
|
500 delete iPimpl; |
|
501 delete iPipeline; |
|
502 } |
|
503 |
|
504 // -------------------------------------------------------------------------- |
|
505 // CUpnpGstWrapper::CUpnpGstWrapper |
|
506 // See upnpgstwrapper.h |
|
507 //--------------------------------------------------------------------------- |
|
508 CUpnpGstWrapper::CUpnpGstWrapper() |
|
509 : CActive( EPriorityStandard ) |
|
510 , iDuration( KErrNotFound ) |
|
511 { |
|
512 __FUNC_LOG; |
|
513 |
|
514 CActiveScheduler::Add( this ); |
|
515 } |
|
516 |
|
517 // -------------------------------------------------------------------------- |
|
518 // CUpnpGstWrapper::ConstructL |
|
519 // See upnpgstwrapper.h |
|
520 //--------------------------------------------------------------------------- |
|
521 void CUpnpGstWrapper::ConstructL() |
|
522 { |
|
523 __FUNC_LOG; |
|
524 |
|
525 iPimpl = CUpnpGstWrapperPimpl::NewL(); |
|
526 |
|
527 iMutex.CreateLocal(); |
|
528 |
|
529 RThread thread; |
|
530 iClientThreadId = thread.Id(); |
|
531 |
|
532 /* |
|
533 * Install our own log handler |
|
534 * FIXME: After this there is two log handlers: |
|
535 * |
|
536 * Default: Uses glib's g_printerr() that prints |
|
537 * RDebug::RawPrints ONLY in full udeb mode |
|
538 * Our own: See behaviour in LogCallback function below |
|
539 * |
|
540 * We should somehow get rid of the default one... |
|
541 */ |
|
542 gst_debug_add_log_function( CUpnpGstWrapperPimpl::LogCallback, this ); |
|
543 |
|
544 __LOG( "Initializing GStreamer..." ); |
|
545 gst_init( NULL, NULL ); |
|
546 __LOG( "GStreamer initialization done!" ); |
|
547 } |
|
548 |
|
549 // -------------------------------------------------------------------------- |
|
550 // CUpnpGstWrapper::SetObserverL |
|
551 // See upnpgstwrapper.h |
|
552 //--------------------------------------------------------------------------- |
|
553 EXPORT_C void CUpnpGstWrapper::SetObserverL( |
|
554 MUpnpGstWrapperObserver& aObserver ) |
|
555 { |
|
556 if( iObservers.Find( &aObserver ) < 0 ) |
|
557 { |
|
558 iObservers.AppendL( &aObserver ); |
|
559 } |
|
560 } |
|
561 |
|
562 // -------------------------------------------------------------------------- |
|
563 // CUpnpGstWrapper::RemoveObserverL |
|
564 // See upnpgstwrapper.h |
|
565 //--------------------------------------------------------------------------- |
|
566 EXPORT_C void CUpnpGstWrapper::RemoveObserver( |
|
567 MUpnpGstWrapperObserver& aObserver ) |
|
568 { |
|
569 TInt index = iObservers.Find( &aObserver ); |
|
570 if( index >= 0 ) |
|
571 { |
|
572 iObservers.Remove( index ); |
|
573 } |
|
574 } |
|
575 |
|
576 // -------------------------------------------------------------------------- |
|
577 // CUpnpGstWrapper::StartL |
|
578 // See upnpgstwrapper.h |
|
579 //--------------------------------------------------------------------------- |
|
580 EXPORT_C void CUpnpGstWrapper::StartL() |
|
581 { |
|
582 __FUNC_LOG; |
|
583 |
|
584 if( !iPipeline ) |
|
585 { |
|
586 SetErrorMsgL( KAlreadyInUseErrorMsg ); |
|
587 User::Leave( KErrNotReady ); |
|
588 } |
|
589 |
|
590 //Create pipeline according to the input description |
|
591 char* pipelineStr = ConvertDescToCharL( *iPipeline ); |
|
592 |
|
593 GError* err = NULL; |
|
594 /** |
|
595 * Create a new pipeline based on command line syntax. |
|
596 * Please note that you might get a return value that is not NULL even |
|
597 * though the error is set. In this case there was a recoverable |
|
598 * parsing error and you can try to play the pipeline |
|
599 */ |
|
600 __LOG( "Parsing GStreamer pipeline..." ); |
|
601 GstElement* pipeline = gst_parse_launch( pipelineStr, &err ); |
|
602 __LOG( "GStreamer pipeline parsing done!" ); |
|
603 User::Free( pipelineStr ); |
|
604 |
|
605 if( err ) |
|
606 { |
|
607 SetErrorMsg( ConvertCharToDescL( err->message ) ); |
|
608 g_error_free( err ); |
|
609 err = NULL; |
|
610 User::Leave( KErrGeneral ); |
|
611 } |
|
612 |
|
613 iPimpl->SetPipeline( pipeline ); |
|
614 |
|
615 //TODO: Hardcoded demuxer name 'KDemuxerName -> should be fetched somehow |
|
616 //dynamically ?? |
|
617 GstElement* demuxer = gst_bin_get_by_name( GST_BIN( pipeline ), |
|
618 KDemuxerName ); |
|
619 |
|
620 //If a demuxer is found, create 'pad-added' callback; else do nothing |
|
621 if( demuxer ) |
|
622 { |
|
623 g_signal_connect( demuxer, "pad-added", |
|
624 G_CALLBACK( CUpnpGstWrapperPimpl::DemuxPadAddedCallback ), |
|
625 this ); |
|
626 iPimpl->SetDemuxer( demuxer ); |
|
627 } |
|
628 |
|
629 GstBus* bus = NULL; |
|
630 bus = gst_pipeline_get_bus( GST_PIPELINE( pipeline ) ); |
|
631 if( !bus ) |
|
632 { |
|
633 //unknown error |
|
634 User::Leave(KErrGeneral); |
|
635 } |
|
636 |
|
637 if( !IsActive() ) |
|
638 { |
|
639 iStatus = KRequestPending; |
|
640 SetActive(); |
|
641 } |
|
642 |
|
643 gst_bus_set_sync_handler( bus, CUpnpGstWrapperPimpl::SyncBusCallback, this ); |
|
644 |
|
645 gst_object_unref( bus ); |
|
646 |
|
647 gst_element_set_state( pipeline, GST_STATE_PLAYING ); |
|
648 } |
|
649 |
|
650 // -------------------------------------------------------------------------- |
|
651 // CUpnpGstWrapper::Stop |
|
652 // See upnpgstwrapper.h |
|
653 //--------------------------------------------------------------------------- |
|
654 EXPORT_C void CUpnpGstWrapper::Stop() |
|
655 { |
|
656 __FUNC_LOG; |
|
657 GstElement* demuxer = iPimpl->Demuxer(); |
|
658 if( demuxer ) |
|
659 { |
|
660 gst_object_unref( GST_OBJECT( demuxer ) ); |
|
661 iPimpl->SetDemuxer( NULL ); |
|
662 } |
|
663 |
|
664 GstElement* pipeline = iPimpl->Pipeline(); |
|
665 if( pipeline ) |
|
666 { |
|
667 gst_element_set_state( pipeline, GST_STATE_NULL ); |
|
668 gst_object_unref( GST_OBJECT( pipeline ) ); |
|
669 iPimpl->SetPipeline( NULL ); |
|
670 } |
|
671 //Cancel(); |
|
672 } |
|
673 |
|
674 // -------------------------------------------------------------------------- |
|
675 // CUpnpGstWrapper::ErrorMsg |
|
676 // See upnpgstwrapper.h |
|
677 //--------------------------------------------------------------------------- |
|
678 EXPORT_C const TDesC& CUpnpGstWrapper::ErrorMsg() |
|
679 { |
|
680 __FUNC_LOG; |
|
681 |
|
682 if( iErrorMsg ) |
|
683 { |
|
684 return *iErrorMsg; |
|
685 } |
|
686 else |
|
687 { |
|
688 return KUnknownErrorErrorMsg(); |
|
689 } |
|
690 } |
|
691 |
|
692 // -------------------------------------------------------------------------- |
|
693 // CUpnpGstWrapper::FeatureListL |
|
694 // See upnpgstwrapper.h |
|
695 //--------------------------------------------------------------------------- |
|
696 EXPORT_C CDesCArray* CUpnpGstWrapper::FeatureListL() |
|
697 { |
|
698 __FUNC_LOG; |
|
699 |
|
700 CDesCArray* array = new (ELeave) CDesCArrayFlat( 5 ); |
|
701 CleanupStack::PushL( array ); |
|
702 |
|
703 GList* features = gst_registry_get_feature_list( |
|
704 gst_registry_get_default(), GST_TYPE_ELEMENT_FACTORY ); |
|
705 while( features ) |
|
706 { |
|
707 GstPluginFeature* feature = (GstPluginFeature*)features->data; |
|
708 HBufC* tempBuf = ConvertCharToDescL( gst_plugin_feature_get_name( |
|
709 feature ) ); |
|
710 CleanupStack::PushL( tempBuf ); |
|
711 array->AppendL( *tempBuf ); |
|
712 CleanupStack::PopAndDestroy( tempBuf ); |
|
713 features = features->next; |
|
714 } |
|
715 |
|
716 CleanupStack::Pop( array ); |
|
717 return array; |
|
718 } |
|
719 |
|
720 // -------------------------------------------------------------------------- |
|
721 // CUpnpGstWrapper::VideoInfo |
|
722 // See upnpgstwrapper.h |
|
723 //--------------------------------------------------------------------------- |
|
724 EXPORT_C const TDesC& CUpnpGstWrapper::VideoInfo() |
|
725 { |
|
726 __FUNC_LOG; |
|
727 |
|
728 if( iVideoInfo ) |
|
729 { |
|
730 return *iVideoInfo; |
|
731 } |
|
732 else |
|
733 { |
|
734 return KNullDesC; |
|
735 } |
|
736 } |
|
737 |
|
738 // -------------------------------------------------------------------------- |
|
739 // CUpnpGstWrapper::AudioInfo |
|
740 // See upnpgstwrapper.h |
|
741 //--------------------------------------------------------------------------- |
|
742 EXPORT_C const TDesC& CUpnpGstWrapper::AudioInfo() |
|
743 { |
|
744 __FUNC_LOG; |
|
745 |
|
746 if( iAudioInfo ) |
|
747 { |
|
748 return *iAudioInfo; |
|
749 } |
|
750 else |
|
751 { |
|
752 return KNullDesC; |
|
753 } |
|
754 } |
|
755 // -------------------------------------------------------------------------- |
|
756 // CUpnpGstWrapper::Position |
|
757 // See upnpgstwrapper.h |
|
758 //--------------------------------------------------------------------------- |
|
759 EXPORT_C TInt64 CUpnpGstWrapper::Position() |
|
760 { |
|
761 __FUNC_LOG; |
|
762 |
|
763 GstFormat fmt = GST_FORMAT_TIME; |
|
764 TInt64 position = KErrNotFound; |
|
765 |
|
766 //fetch position from pipeline (not from the demuxer) |
|
767 GstElement* pipeline = iPimpl->Pipeline(); |
|
768 |
|
769 if( pipeline ) |
|
770 { |
|
771 gst_element_query_position( pipeline, &fmt, &position ); |
|
772 } |
|
773 |
|
774 return position; |
|
775 } |
|
776 |
|
777 // -------------------------------------------------------------------------- |
|
778 // CUpnpGstWrapper::Duration |
|
779 // See upnpgstwrapper.h |
|
780 //--------------------------------------------------------------------------- |
|
781 EXPORT_C TInt64 CUpnpGstWrapper::Duration() |
|
782 { |
|
783 __FUNC_LOG; |
|
784 |
|
785 if( iDuration < 0 ) |
|
786 { |
|
787 GstFormat fmt = GST_FORMAT_TIME; |
|
788 if( iPimpl->Demuxer() ) |
|
789 { |
|
790 //fetch duration from demuxer |
|
791 gst_element_query_duration( iPimpl->Demuxer(), &fmt, &iDuration ); |
|
792 } |
|
793 else if( iPimpl->Pipeline() ) |
|
794 { |
|
795 //backup plan: not so good choice as demuxer |
|
796 gst_element_query_position( iPimpl->Pipeline(), &fmt, &iDuration ); |
|
797 } |
|
798 } |
|
799 |
|
800 return iDuration; |
|
801 } |
|
802 |
|
803 EXPORT_C TAny* CUpnpGstWrapper::PipelinePtr() |
|
804 { |
|
805 return iPimpl->Pipeline(); |
|
806 } |
|
807 |
|
808 EXPORT_C void CUpnpGstWrapper::InitAppsinkL() |
|
809 { |
|
810 iPimpl->InitAppSinkL(); |
|
811 } |
|
812 |
|
813 EXPORT_C TBool CUpnpGstWrapper::PullBufferL( TPtr8& aPointer,TInt aMaxBytesLength, RBuf8* aBuf ) |
|
814 { |
|
815 return iPimpl->PullBufferL(aPointer,aMaxBytesLength,aBuf); |
|
816 } |
|
817 |
|
818 EXPORT_C TInt CUpnpGstWrapper::TranscodedBytes() |
|
819 { |
|
820 return iPimpl->TranscodedBytes(); |
|
821 } |
|
822 |
|
823 EXPORT_C void CUpnpGstWrapper::SetTranscodedFileSize( TInt aSize ) |
|
824 { |
|
825 iFileSize = aSize; |
|
826 } |
|
827 |
|
828 EXPORT_C TInt CUpnpGstWrapper::TranscodedFileSize() |
|
829 { |
|
830 return iFileSize; |
|
831 } |
|
832 |
|
833 EXPORT_C void CUpnpGstWrapper::SetPipelineL( const TDesC8& aPipeline ) |
|
834 { |
|
835 delete iPipeline; |
|
836 iPipeline = NULL; |
|
837 iPipeline = aPipeline.AllocL(); |
|
838 } |
|
839 |
|
840 |
|
841 // -------------------------------------------------------------------------- |
|
842 // CUpnpGstWrapper::SetErrorMsgL |
|
843 // See upnpgstwrapper.h |
|
844 //--------------------------------------------------------------------------- |
|
845 void CUpnpGstWrapper::SetErrorMsgL( const TDesC& aErrorMsg ) |
|
846 { |
|
847 __FUNC_LOG; |
|
848 |
|
849 delete iErrorMsg; iErrorMsg = NULL; |
|
850 iErrorMsg = aErrorMsg.AllocL(); |
|
851 |
|
852 __LOG1( "CUpnpGstWrapper::SetErrorMsgL Error desc: %S", iErrorMsg ); |
|
853 } |
|
854 |
|
855 // -------------------------------------------------------------------------- |
|
856 // CUpnpGstWrapper::SetErrorMsg |
|
857 // See upnpgstwrapper.h |
|
858 //--------------------------------------------------------------------------- |
|
859 void CUpnpGstWrapper::SetErrorMsg( HBufC* const aErrorMsg ) |
|
860 { |
|
861 delete iErrorMsg; iErrorMsg = NULL; |
|
862 iErrorMsg = aErrorMsg; |
|
863 |
|
864 __LOG1( "CUpnpGstWrapper::SetErrorMsg Error desc: %S", iErrorMsg ); |
|
865 } |
|
866 |
|
867 // -------------------------------------------------------------------------- |
|
868 // CUpnpGstWrapper::ConvertCharToDescL |
|
869 // See upnpgstwrapper.h |
|
870 //--------------------------------------------------------------------------- |
|
871 HBufC* CUpnpGstWrapper::ConvertCharToDescL( const char* aString ) |
|
872 { |
|
873 __FUNC_LOG; |
|
874 |
|
875 HBufC* desc = NULL; |
|
876 TPtrC8 tempPtr8( (TUint8*)(aString) ); |
|
877 desc = HBufC::NewL( tempPtr8.Length() ); |
|
878 desc->Des().Copy( tempPtr8 ); |
|
879 |
|
880 return desc; |
|
881 } |
|
882 |
|
883 |
|
884 // -------------------------------------------------------------------------- |
|
885 // CUpnpGstWrapper::ConvertDescToCharL |
|
886 // See upnpgstwrapper.h |
|
887 //--------------------------------------------------------------------------- |
|
888 char* CUpnpGstWrapper::ConvertDescToCharL( const TDesC8& aDescriptor ) |
|
889 { |
|
890 __FUNC_LOG; |
|
891 |
|
892 TUint length = aDescriptor.Length(); |
|
893 char* string = (char*)User::AllocL( length + 1 ); |
|
894 Mem::Copy((char*)string, aDescriptor.Ptr(), length ); |
|
895 string[length] = 0; //null terminated |
|
896 return string; |
|
897 } |
|
898 |
|
899 void CUpnpGstWrapper::SendEventToObsevers( Gst::TEvent aEvent ) |
|
900 { |
|
901 __FUNC_LOG; |
|
902 |
|
903 TInt observerCount = iObservers.Count(); |
|
904 for( TInt i = 0; i < observerCount; i++ ) |
|
905 { |
|
906 iObservers[i]->HandleGstEvent( aEvent ); |
|
907 } |
|
908 } |
|
909 |
|
910 // -------------------------------------------------------------------------- |
|
911 // CUpnpGstWrapper::RunL |
|
912 // See upnpgstwrapper.h |
|
913 //--------------------------------------------------------------------------- |
|
914 void CUpnpGstWrapper::RunL() |
|
915 { |
|
916 __FUNC_LOG; |
|
917 if( iStatus.Int() >= KErrNone ) |
|
918 { |
|
919 TBool completed = EFalse; |
|
920 |
|
921 iMutex.Wait(); |
|
922 |
|
923 TInt eventQueueCount = iEventQueue.Count(); |
|
924 for( TInt i = 0; i < eventQueueCount; i++ ) |
|
925 { |
|
926 Gst::TEvent event = iEventQueue[i]; |
|
927 SendEventToObsevers( event ); |
|
928 if( event == Gst::EEOS || event == Gst::EError ) |
|
929 { |
|
930 __LOG1( "CUpnpGstWrapper::RunL Completed: %d (2=Error, 3=EOS)", |
|
931 event); |
|
932 completed = ETrue; |
|
933 } |
|
934 } |
|
935 iEventQueue.Reset(); |
|
936 |
|
937 if( !completed ) |
|
938 { |
|
939 iStatus = KRequestPending; |
|
940 SetActive(); |
|
941 } |
|
942 iMutex.Signal(); |
|
943 } |
|
944 } |
|
945 |
|
946 // -------------------------------------------------------------------------- |
|
947 // CUpnpGstWrapper::DoCancel |
|
948 // See upnpgstwrapper.h |
|
949 //--------------------------------------------------------------------------- |
|
950 void CUpnpGstWrapper::DoCancel() |
|
951 { |
|
952 __FUNC_LOG; |
|
953 } |
|
954 |
|
955 // end of file |