xref: /AOO41X/main/avmedia/source/gstreamer/gstframegrabber.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir #include "gstframegrabber.hxx"
29*cdf0e10cSrcweir #include "gstplayer.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir #include <vcl/graph.hxx>
32*cdf0e10cSrcweir #include <vcl/bmpacc.hxx>
33*cdf0e10cSrcweir 
34*cdf0e10cSrcweir #include <string>
35*cdf0e10cSrcweir 
36*cdf0e10cSrcweir 
37*cdf0e10cSrcweir using namespace ::com::sun::star;
38*cdf0e10cSrcweir 
39*cdf0e10cSrcweir namespace avmedia { namespace gst {
40*cdf0e10cSrcweir 
41*cdf0e10cSrcweir const gulong GRAB_TIMEOUT = 10000000;
42*cdf0e10cSrcweir 
43*cdf0e10cSrcweir // ----------------
44*cdf0e10cSrcweir // - FrameGrabber -
45*cdf0e10cSrcweir // ----------------
46*cdf0e10cSrcweir 
47*cdf0e10cSrcweir FrameGrabber::FrameGrabber( GString* pURI ) :
48*cdf0e10cSrcweir     mpFrameMutex( g_mutex_new() ),
49*cdf0e10cSrcweir     mpFrameCond( g_cond_new() ),
50*cdf0e10cSrcweir     mpLastPixbuf( NULL ),
51*cdf0e10cSrcweir     mbIsInGrabMode( false )
52*cdf0e10cSrcweir {
53*cdf0e10cSrcweir 	if( pURI )
54*cdf0e10cSrcweir     {
55*cdf0e10cSrcweir         OSL_TRACE( ">>> --------------------------------" );
56*cdf0e10cSrcweir         OSL_TRACE( ">>> Creating Player object with URL: %s", pURI->str );
57*cdf0e10cSrcweir 
58*cdf0e10cSrcweir         mpThread = g_thread_create( Player::implThreadFunc, this, true, NULL );
59*cdf0e10cSrcweir     }
60*cdf0e10cSrcweir }
61*cdf0e10cSrcweir 
62*cdf0e10cSrcweir // ------------------------------------------------------------------------------
63*cdf0e10cSrcweir 
64*cdf0e10cSrcweir FrameGrabber::~FrameGrabber()
65*cdf0e10cSrcweir {
66*cdf0e10cSrcweir     if( g_atomic_pointer_get( &mpPlayer ) )
67*cdf0e10cSrcweir     {
68*cdf0e10cSrcweir         implQuitThread();
69*cdf0e10cSrcweir     }
70*cdf0e10cSrcweir 
71*cdf0e10cSrcweir     // thread has ended, so that no more synchronization is necessary
72*cdf0e10cSrcweir     if( mpLastPixbuf )
73*cdf0e10cSrcweir     {
74*cdf0e10cSrcweir         g_object_unref( mpLastPixbuf );
75*cdf0e10cSrcweir         mpLastPixbuf = NULL;
76*cdf0e10cSrcweir     }
77*cdf0e10cSrcweir 
78*cdf0e10cSrcweir     g_cond_free( mpFrameCond );
79*cdf0e10cSrcweir     g_mutex_free( mpFrameMutex );
80*cdf0e10cSrcweir }
81*cdf0e10cSrcweir 
82*cdf0e10cSrcweir // ------------------------------------------------------------------------------
83*cdf0e10cSrcweir 
84*cdf0e10cSrcweir FrameGrabber* FrameGrabber::create( const GString* pURI )
85*cdf0e10cSrcweir {
86*cdf0e10cSrcweir     FrameGrabber* pFrameGrabber = NULL;
87*cdf0e10cSrcweir 
88*cdf0e10cSrcweir     if( pURI && pURI->len )
89*cdf0e10cSrcweir     {
90*cdf0e10cSrcweir         // safely initialize GLib threading framework
91*cdf0e10cSrcweir         try
92*cdf0e10cSrcweir         {
93*cdf0e10cSrcweir             if( !g_thread_supported() )
94*cdf0e10cSrcweir             {
95*cdf0e10cSrcweir                 g_thread_init( NULL );
96*cdf0e10cSrcweir             }
97*cdf0e10cSrcweir         }
98*cdf0e10cSrcweir         catch( ... )
99*cdf0e10cSrcweir         {}
100*cdf0e10cSrcweir 
101*cdf0e10cSrcweir         if( g_thread_supported() )
102*cdf0e10cSrcweir         {
103*cdf0e10cSrcweir             pFrameGrabber = new FrameGrabber( g_string_new( pURI->str ) );
104*cdf0e10cSrcweir 
105*cdf0e10cSrcweir             // wait until thread signals that it has finished initialization
106*cdf0e10cSrcweir             if( pFrameGrabber->mpThread )
107*cdf0e10cSrcweir             {
108*cdf0e10cSrcweir                 g_mutex_lock( pFrameGrabber->mpMutex );
109*cdf0e10cSrcweir 
110*cdf0e10cSrcweir                 while( !pFrameGrabber->implIsInitialized() )
111*cdf0e10cSrcweir                 {
112*cdf0e10cSrcweir                     g_cond_wait( pFrameGrabber->mpCond, pFrameGrabber->mpMutex );
113*cdf0e10cSrcweir                 }
114*cdf0e10cSrcweir 
115*cdf0e10cSrcweir                 g_mutex_unlock( pFrameGrabber->mpMutex );
116*cdf0e10cSrcweir             }
117*cdf0e10cSrcweir 
118*cdf0e10cSrcweir             GstElement* pPixbufSink = gst_element_factory_make( "gdkpixbufsink", NULL );
119*cdf0e10cSrcweir 
120*cdf0e10cSrcweir             // check if player pipeline and GdkPixbufSink could be initialized
121*cdf0e10cSrcweir             if( !pFrameGrabber->mpPlayer || !pPixbufSink )
122*cdf0e10cSrcweir             {
123*cdf0e10cSrcweir                 delete pFrameGrabber;
124*cdf0e10cSrcweir                 pFrameGrabber = NULL;
125*cdf0e10cSrcweir             }
126*cdf0e10cSrcweir             else
127*cdf0e10cSrcweir             {
128*cdf0e10cSrcweir                 g_object_set( pFrameGrabber->mpPlayer, "audio-sink", gst_element_factory_make( "fakesink", NULL ), NULL );
129*cdf0e10cSrcweir                 g_object_set( pFrameGrabber->mpPlayer, "video-sink", pPixbufSink, NULL );
130*cdf0e10cSrcweir             }
131*cdf0e10cSrcweir         }
132*cdf0e10cSrcweir     }
133*cdf0e10cSrcweir 
134*cdf0e10cSrcweir     return( pFrameGrabber );
135*cdf0e10cSrcweir }
136*cdf0e10cSrcweir 
137*cdf0e10cSrcweir // ------------------------------------------------------------------------------
138*cdf0e10cSrcweir 
139*cdf0e10cSrcweir gboolean FrameGrabber::busCallback( GstBus* pBus, GstMessage* pMsg )
140*cdf0e10cSrcweir {
141*cdf0e10cSrcweir     bool bDone = false;
142*cdf0e10cSrcweir 
143*cdf0e10cSrcweir     if( pMsg && pMsg->structure )
144*cdf0e10cSrcweir     {
145*cdf0e10cSrcweir         GstStructure* pStruct = pMsg->structure;
146*cdf0e10cSrcweir         const gchar* pStructName = gst_structure_get_name( pStruct );
147*cdf0e10cSrcweir 
148*cdf0e10cSrcweir         if( ( ::std::string( pStructName ).find( "pixbuf" ) != ::std::string::npos ) &&
149*cdf0e10cSrcweir             gst_structure_has_field ( pStruct, "pixbuf") )
150*cdf0e10cSrcweir         {
151*cdf0e10cSrcweir             bool bFrameGrabbed = false;
152*cdf0e10cSrcweir 
153*cdf0e10cSrcweir             g_mutex_lock( mpFrameMutex );
154*cdf0e10cSrcweir 
155*cdf0e10cSrcweir             if( mbIsInGrabMode && ( getMediaTime() >= mfGrabTime ) )
156*cdf0e10cSrcweir             {
157*cdf0e10cSrcweir                 OSL_TRACE( "Grabbing frame at %fs", getMediaTime() );
158*cdf0e10cSrcweir 
159*cdf0e10cSrcweir                 if( mpLastPixbuf )
160*cdf0e10cSrcweir                 {
161*cdf0e10cSrcweir                     g_object_unref( mpLastPixbuf );
162*cdf0e10cSrcweir                     mpLastPixbuf = NULL;
163*cdf0e10cSrcweir                 }
164*cdf0e10cSrcweir 
165*cdf0e10cSrcweir                 mpLastPixbuf = GDK_PIXBUF( g_value_dup_object( gst_structure_get_value( pStruct, "pixbuf" ) ) );
166*cdf0e10cSrcweir                 bFrameGrabbed = true;
167*cdf0e10cSrcweir             }
168*cdf0e10cSrcweir 
169*cdf0e10cSrcweir             g_mutex_unlock( mpFrameMutex );
170*cdf0e10cSrcweir 
171*cdf0e10cSrcweir             if( bFrameGrabbed )
172*cdf0e10cSrcweir             {
173*cdf0e10cSrcweir                 g_cond_signal( mpFrameCond );
174*cdf0e10cSrcweir             }
175*cdf0e10cSrcweir 
176*cdf0e10cSrcweir             bDone = true;
177*cdf0e10cSrcweir         }
178*cdf0e10cSrcweir     }
179*cdf0e10cSrcweir 
180*cdf0e10cSrcweir     return( bDone || Player::busCallback( pBus, pMsg ) );
181*cdf0e10cSrcweir }
182*cdf0e10cSrcweir 
183*cdf0e10cSrcweir // ------------------------------------------------------------------------------
184*cdf0e10cSrcweir 
185*cdf0e10cSrcweir uno::Reference< graphic::XGraphic > SAL_CALL FrameGrabber::grabFrame( double fMediaTime )
186*cdf0e10cSrcweir     throw (uno::RuntimeException)
187*cdf0e10cSrcweir {
188*cdf0e10cSrcweir     uno::Reference< graphic::XGraphic > xRet;
189*cdf0e10cSrcweir 
190*cdf0e10cSrcweir     if( implInitPlayer() )
191*cdf0e10cSrcweir     {
192*cdf0e10cSrcweir         OSL_TRACE( "Trying to grab frame at %fs", fMediaTime );
193*cdf0e10cSrcweir 
194*cdf0e10cSrcweir         GTimeVal aTimeoutTime;
195*cdf0e10cSrcweir 
196*cdf0e10cSrcweir         g_get_current_time( &aTimeoutTime );
197*cdf0e10cSrcweir         g_time_val_add( &aTimeoutTime, GRAB_TIMEOUT );
198*cdf0e10cSrcweir         setMediaTime( fMediaTime );
199*cdf0e10cSrcweir         start();
200*cdf0e10cSrcweir 
201*cdf0e10cSrcweir         if( isPlaying() )
202*cdf0e10cSrcweir         {
203*cdf0e10cSrcweir             g_mutex_lock( mpFrameMutex );
204*cdf0e10cSrcweir 
205*cdf0e10cSrcweir             mbIsInGrabMode = true;
206*cdf0e10cSrcweir             mfGrabTime = fMediaTime;
207*cdf0e10cSrcweir             g_cond_timed_wait( mpFrameCond, mpFrameMutex, &aTimeoutTime );
208*cdf0e10cSrcweir             mbIsInGrabMode = false;
209*cdf0e10cSrcweir 
210*cdf0e10cSrcweir             g_mutex_unlock( mpFrameMutex );
211*cdf0e10cSrcweir 
212*cdf0e10cSrcweir             stop();
213*cdf0e10cSrcweir         }
214*cdf0e10cSrcweir 
215*cdf0e10cSrcweir         OSL_ENSURE( g_atomic_pointer_get( &mpLastPixbuf ), "FrameGrabber timed out without receiving a Pixbuf" );
216*cdf0e10cSrcweir 
217*cdf0e10cSrcweir         if( g_atomic_pointer_get( &mpLastPixbuf ) )
218*cdf0e10cSrcweir         {
219*cdf0e10cSrcweir             OSL_TRACE( "FrameGrabber received a GdkPixbuf");
220*cdf0e10cSrcweir 
221*cdf0e10cSrcweir             g_mutex_lock( mpFrameMutex );
222*cdf0e10cSrcweir 
223*cdf0e10cSrcweir             const int nWidth = gdk_pixbuf_get_width( mpLastPixbuf );
224*cdf0e10cSrcweir             const int nHeight = gdk_pixbuf_get_height( mpLastPixbuf );
225*cdf0e10cSrcweir             const int nChannels = gdk_pixbuf_get_n_channels( mpLastPixbuf );
226*cdf0e10cSrcweir             const guchar* pBuffer = gdk_pixbuf_get_pixels( mpLastPixbuf );
227*cdf0e10cSrcweir 
228*cdf0e10cSrcweir             if( pBuffer && ( nWidth > 0 ) && ( nHeight > 0 ) )
229*cdf0e10cSrcweir             {
230*cdf0e10cSrcweir                 Bitmap aFrame( Size( nWidth, nHeight), 24 );
231*cdf0e10cSrcweir                 bool bInit = false;
232*cdf0e10cSrcweir 
233*cdf0e10cSrcweir                 if( ( gdk_pixbuf_get_colorspace( mpLastPixbuf ) == GDK_COLORSPACE_RGB ) &&
234*cdf0e10cSrcweir                     ( nChannels >= 3 ) && ( nChannels <= 4 ) &&
235*cdf0e10cSrcweir                     ( gdk_pixbuf_get_bits_per_sample( mpLastPixbuf ) == 8 ) )
236*cdf0e10cSrcweir                 {
237*cdf0e10cSrcweir                     BitmapWriteAccess* pAcc = aFrame.AcquireWriteAccess();
238*cdf0e10cSrcweir 
239*cdf0e10cSrcweir                     if( pAcc )
240*cdf0e10cSrcweir                     {
241*cdf0e10cSrcweir                         BitmapColor aPixel( 0, 0, 0 );
242*cdf0e10cSrcweir                         const int nRowStride = gdk_pixbuf_get_rowstride( mpLastPixbuf );
243*cdf0e10cSrcweir                         const bool bAlpha = ( nChannels == 4  );
244*cdf0e10cSrcweir 
245*cdf0e10cSrcweir                         for( int nRow = 0; nRow < nHeight; ++nRow )
246*cdf0e10cSrcweir                         {
247*cdf0e10cSrcweir                             guchar* pCur = const_cast< guchar* >( pBuffer + nRow * nRowStride );
248*cdf0e10cSrcweir 
249*cdf0e10cSrcweir                             for( int nCol = 0; nCol < nWidth; ++nCol )
250*cdf0e10cSrcweir                             {
251*cdf0e10cSrcweir                                 aPixel.SetRed( *pCur++ );
252*cdf0e10cSrcweir                                 aPixel.SetGreen( *pCur++ );
253*cdf0e10cSrcweir                                 aPixel.SetBlue( *pCur++ );
254*cdf0e10cSrcweir 
255*cdf0e10cSrcweir                                 // ignore alpha channel
256*cdf0e10cSrcweir                                 if( bAlpha )
257*cdf0e10cSrcweir                                 {
258*cdf0e10cSrcweir                                     ++pCur;
259*cdf0e10cSrcweir                                 }
260*cdf0e10cSrcweir 
261*cdf0e10cSrcweir                                 pAcc->SetPixel( nRow, nCol, aPixel );
262*cdf0e10cSrcweir                             }
263*cdf0e10cSrcweir                         }
264*cdf0e10cSrcweir 
265*cdf0e10cSrcweir                         aFrame.ReleaseAccess( pAcc );
266*cdf0e10cSrcweir                         bInit = true;
267*cdf0e10cSrcweir                     }
268*cdf0e10cSrcweir                 }
269*cdf0e10cSrcweir 
270*cdf0e10cSrcweir                 if( !bInit )
271*cdf0e10cSrcweir                 {
272*cdf0e10cSrcweir                     aFrame.Erase( Color( COL_BLACK ) );
273*cdf0e10cSrcweir                 }
274*cdf0e10cSrcweir 
275*cdf0e10cSrcweir                 xRet = Graphic( aFrame ).GetXGraphic();
276*cdf0e10cSrcweir             }
277*cdf0e10cSrcweir 
278*cdf0e10cSrcweir             g_object_unref( mpLastPixbuf );
279*cdf0e10cSrcweir             mpLastPixbuf = NULL;
280*cdf0e10cSrcweir 
281*cdf0e10cSrcweir             g_mutex_unlock( mpFrameMutex );
282*cdf0e10cSrcweir         }
283*cdf0e10cSrcweir     }
284*cdf0e10cSrcweir 
285*cdf0e10cSrcweir     return xRet;
286*cdf0e10cSrcweir }
287*cdf0e10cSrcweir 
288*cdf0e10cSrcweir // ------------------------------------------------------------------------------
289*cdf0e10cSrcweir 
290*cdf0e10cSrcweir ::rtl::OUString SAL_CALL FrameGrabber::getImplementationName(  )
291*cdf0e10cSrcweir     throw (uno::RuntimeException)
292*cdf0e10cSrcweir {
293*cdf0e10cSrcweir     return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( AVMEDIA_GSTREAMER_FRAMEGRABBER_IMPLEMENTATIONNAME ) );
294*cdf0e10cSrcweir }
295*cdf0e10cSrcweir 
296*cdf0e10cSrcweir // ------------------------------------------------------------------------------
297*cdf0e10cSrcweir 
298*cdf0e10cSrcweir sal_Bool SAL_CALL FrameGrabber::supportsService( const ::rtl::OUString& ServiceName )
299*cdf0e10cSrcweir     throw (uno::RuntimeException)
300*cdf0e10cSrcweir {
301*cdf0e10cSrcweir     return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( AVMEDIA_GSTREAMER_FRAMEGRABBER_SERVICENAME ) );
302*cdf0e10cSrcweir }
303*cdf0e10cSrcweir 
304*cdf0e10cSrcweir // ------------------------------------------------------------------------------
305*cdf0e10cSrcweir 
306*cdf0e10cSrcweir uno::Sequence< ::rtl::OUString > SAL_CALL FrameGrabber::getSupportedServiceNames(  )
307*cdf0e10cSrcweir     throw (uno::RuntimeException)
308*cdf0e10cSrcweir {
309*cdf0e10cSrcweir     uno::Sequence< ::rtl::OUString > aRet(1);
310*cdf0e10cSrcweir     aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( AVMEDIA_GSTREAMER_FRAMEGRABBER_SERVICENAME ) );
311*cdf0e10cSrcweir 
312*cdf0e10cSrcweir     return aRet;
313*cdf0e10cSrcweir }
314*cdf0e10cSrcweir 
315*cdf0e10cSrcweir } // namespace win
316*cdf0e10cSrcweir } // namespace avmedia
317