qtmobility/plugins/multimedia/gstreamer/mediaplayer/qgstreamerplayersession.cpp
changeset 14 6fbed849b4f4
parent 11 06b8e2af4411
child 15 1f895d8a5b2b
equal deleted inserted replaced
11:06b8e2af4411 14:6fbed849b4f4
    56 QGstreamerPlayerSession::QGstreamerPlayerSession(QObject *parent)
    56 QGstreamerPlayerSession::QGstreamerPlayerSession(QObject *parent)
    57     :QObject(parent),
    57     :QObject(parent),
    58      m_state(QMediaPlayer::StoppedState),
    58      m_state(QMediaPlayer::StoppedState),
    59      m_busHelper(0),
    59      m_busHelper(0),
    60      m_playbin(0),
    60      m_playbin(0),
    61      m_nullVideoOutput(0),
    61      m_videoSink(0),
       
    62      m_pendingVideoSink(0),
       
    63      m_nullVideoSink(0),
    62      m_bus(0),
    64      m_bus(0),
       
    65      m_videoOutput(0),
    63      m_renderer(0),
    66      m_renderer(0),
    64      m_volume(100),
    67      m_volume(100),
    65      m_playbackRate(1.0),
    68      m_playbackRate(1.0),
    66      m_muted(false),
    69      m_muted(false),
    67      m_audioAvailable(false),
    70      m_audioAvailable(false),
    80     m_playbin = gst_element_factory_make("playbin2", NULL);
    83     m_playbin = gst_element_factory_make("playbin2", NULL);
    81 #else
    84 #else
    82     m_playbin = gst_element_factory_make("playbin", NULL);
    85     m_playbin = gst_element_factory_make("playbin", NULL);
    83 #endif
    86 #endif
    84 
    87 
       
    88     m_videoOutputBin = gst_bin_new("video-output-bin");
       
    89     gst_object_ref(GST_OBJECT(m_videoOutputBin));
       
    90 
       
    91     m_videoIdentity = gst_element_factory_make("identity", "identity-vo");
       
    92     m_colorSpace = gst_element_factory_make("ffmpegcolorspace", "ffmpegcolorspace-vo");
       
    93     m_videoScale = gst_element_factory_make("videoscale","videoscale-vo");
       
    94     m_nullVideoSink = gst_element_factory_make("fakesink", NULL);
       
    95     gst_object_ref(GST_OBJECT(m_nullVideoSink));
       
    96     gst_bin_add_many(GST_BIN(m_videoOutputBin), m_videoIdentity, m_colorSpace, m_videoScale, m_nullVideoSink, NULL);
       
    97     gst_element_link_many(m_videoIdentity, m_colorSpace, m_videoScale, m_nullVideoSink, NULL);
       
    98 
       
    99     m_videoSink = m_nullVideoSink;
       
   100 
       
   101     // add ghostpads
       
   102     GstPad *pad = gst_element_get_static_pad(m_videoIdentity,"sink");
       
   103     gst_element_add_pad(GST_ELEMENT(m_videoOutputBin), gst_ghost_pad_new("videosink", pad));
       
   104     gst_object_unref(GST_OBJECT(pad));
       
   105 
    85     if (m_playbin != 0) {
   106     if (m_playbin != 0) {
    86         // Sort out messages
   107         // Sort out messages
    87         m_bus = gst_element_get_bus(m_playbin);
   108         m_bus = gst_element_get_bus(m_playbin);
    88         m_busHelper = new QGstreamerBusHelper(m_bus, this);
   109         m_busHelper = new QGstreamerBusHelper(m_bus, this);
    89         connect(m_busHelper, SIGNAL(message(QGstreamerMessage)), SLOT(busMessage(QGstreamerMessage)));
   110         connect(m_busHelper, SIGNAL(message(QGstreamerMessage)), SLOT(busMessage(QGstreamerMessage)));
    90         m_busHelper->installSyncEventFilter(this);
   111         m_busHelper->installSyncEventFilter(this);
    91 
   112 
    92         m_nullVideoOutput = gst_element_factory_make("fakesink", NULL);
   113         g_object_set(G_OBJECT(m_playbin), "video-sink", m_videoOutputBin, NULL);
    93         gst_object_ref(GST_OBJECT(m_nullVideoOutput));
       
    94         g_object_set(G_OBJECT(m_playbin), "video-sink", m_nullVideoOutput, NULL);
       
    95 
   114 
    96         // Initial volume
   115         // Initial volume
    97         double volume = 1.0;
   116         double volume = 1.0;
    98         g_object_get(G_OBJECT(m_playbin), "volume", &volume, NULL);
   117         g_object_get(G_OBJECT(m_playbin), "volume", &volume, NULL);
    99         m_volume = int(volume*100);
   118         m_volume = int(volume*100);
   106         stop();
   125         stop();
   107 
   126 
   108         delete m_busHelper;
   127         delete m_busHelper;
   109         gst_object_unref(GST_OBJECT(m_bus));
   128         gst_object_unref(GST_OBJECT(m_bus));
   110         gst_object_unref(GST_OBJECT(m_playbin));
   129         gst_object_unref(GST_OBJECT(m_playbin));
   111         gst_object_unref(GST_OBJECT(m_nullVideoOutput));
   130         gst_object_unref(GST_OBJECT(m_nullVideoSink));
       
   131         gst_object_unref(GST_OBJECT(m_videoOutputBin));
   112     }
   132     }
   113 }
   133 }
   114 
   134 
   115 void QGstreamerPlayerSession::load(const QUrl &url)
   135 void QGstreamerPlayerSession::load(const QUrl &url)
   116 {
   136 {
   156 {
   176 {
   157     if (!qFuzzyCompare(m_playbackRate, rate)) {
   177     if (!qFuzzyCompare(m_playbackRate, rate)) {
   158         m_playbackRate = rate;
   178         m_playbackRate = rate;
   159         if (m_playbin) {
   179         if (m_playbin) {
   160             gst_element_seek(m_playbin, rate, GST_FORMAT_TIME,
   180             gst_element_seek(m_playbin, rate, GST_FORMAT_TIME,
   161                              GstSeekFlags(GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT),
   181                              GstSeekFlags(GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH),
   162                              GST_SEEK_TYPE_NONE,0,
   182                              GST_SEEK_TYPE_NONE,0,
   163                              GST_SEEK_TYPE_NONE,0 );
   183                              GST_SEEK_TYPE_NONE,0 );
   164         }
   184         }
   165     }
   185     }
   166 }
   186 }
       
   187 
       
   188 //#define DEBUG_VO_BIN_DUMP
       
   189 //#define DEBUG_PLAYBIN_STATES
   167 
   190 
   168 
   191 
   169 int QGstreamerPlayerSession::activeStream(QMediaStreamsControl::StreamType streamType) const
   192 int QGstreamerPlayerSession::activeStream(QMediaStreamsControl::StreamType streamType) const
   170 {
   193 {
   171     int streamNumber = -1;
   194     int streamNumber = -1;
   239 bool QGstreamerPlayerSession::isAudioAvailable() const
   262 bool QGstreamerPlayerSession::isAudioAvailable() const
   240 {
   263 {
   241     return m_audioAvailable;
   264     return m_audioAvailable;
   242 }
   265 }
   243 
   266 
       
   267 static void block_pad_cb(GstPad *pad, gboolean blocked, gpointer user_data)
       
   268 {
       
   269     Q_UNUSED(pad);
       
   270     //qDebug() << "block_pad_cb" << blocked;
       
   271 
       
   272     if (blocked && user_data) {
       
   273         QGstreamerPlayerSession *session = reinterpret_cast<QGstreamerPlayerSession*>(user_data);
       
   274         QMetaObject::invokeMethod(session, "finishVideoOutputChange", Qt::QueuedConnection);
       
   275     }
       
   276 }
       
   277 
       
   278 #ifdef DEBUG_VO_BIN_DUMP
       
   279     static int dumpNum = 0;
       
   280 #endif
       
   281 
       
   282 void QGstreamerPlayerSession::updateVideoRenderer()
       
   283 {
       
   284     if (m_videoOutput)
       
   285         setVideoRenderer(m_videoOutput);
       
   286 }
       
   287 
   244 void QGstreamerPlayerSession::setVideoRenderer(QObject *videoOutput)
   288 void QGstreamerPlayerSession::setVideoRenderer(QObject *videoOutput)
   245 {
   289 {    
   246     m_renderer = qobject_cast<QGstreamerVideoRendererInterface*>(videoOutput);
   290     if (m_videoOutput != videoOutput) {
   247     if (m_renderer)
   291         if (m_videoOutput)
   248         g_object_set(G_OBJECT(m_playbin), "video-sink", m_renderer->videoSink(), NULL);
   292             disconnect(m_videoOutput, SIGNAL(sinkChanged()),
   249     else
   293                        this, SLOT(updateVideoRenderer()));
   250         g_object_set(G_OBJECT(m_playbin), "video-sink", m_nullVideoOutput, NULL);
   294         if (videoOutput)
       
   295             connect(videoOutput, SIGNAL(sinkChanged()),
       
   296                     this, SLOT(updateVideoRenderer()));
       
   297 
       
   298         m_videoOutput = videoOutput;
       
   299     }
       
   300 
       
   301     QGstreamerVideoRendererInterface* renderer = qobject_cast<QGstreamerVideoRendererInterface*>(videoOutput);
       
   302 
       
   303     if (m_renderer == renderer) {
       
   304         //return only if video sink is still the same
       
   305         if (!m_renderer || m_renderer->videoSink() == m_videoSink)
       
   306             return;
       
   307     }
       
   308 
       
   309     m_renderer = renderer;
       
   310 
       
   311 #ifdef DEBUG_VO_BIN_DUMP
       
   312     dumpNum++;
       
   313 
       
   314     _gst_debug_bin_to_dot_file(GST_BIN(m_videoOutputBin),
       
   315                                   GstDebugGraphDetails(GST_DEBUG_GRAPH_SHOW_ALL /* GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE | GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES*/),
       
   316                                   QString("video_output_change_%1_set").arg(dumpNum).toAscii().constData());
       
   317 #endif
       
   318 
       
   319     GstElement *videoSink = m_renderer ? m_renderer->videoSink() : m_nullVideoSink;
       
   320 
       
   321     if (m_state == QMediaPlayer::StoppedState) {
       
   322         m_pendingVideoSink = 0;
       
   323         gst_element_unlink(m_videoScale, m_videoSink);
       
   324 
       
   325         gst_bin_remove(GST_BIN(m_videoOutputBin), m_videoSink);
       
   326 
       
   327         m_videoSink = videoSink;
       
   328 
       
   329         gst_bin_add(GST_BIN(m_videoOutputBin), m_videoSink);
       
   330         gst_element_link(m_videoScale, m_videoSink);
       
   331 
       
   332     } else {
       
   333         if (m_pendingVideoSink) {
       
   334             m_pendingVideoSink = videoSink;
       
   335             return;
       
   336         }
       
   337 
       
   338         m_pendingVideoSink = videoSink;
       
   339 
       
   340         //block pads, async to avoid locking in paused state
       
   341         GstPad *srcPad = gst_element_get_static_pad(m_videoIdentity, "src");
       
   342         gst_pad_set_blocked_async(srcPad, true, &block_pad_cb, this);
       
   343         gst_object_unref(GST_OBJECT(srcPad));
       
   344     }
       
   345 }
       
   346 
       
   347 void QGstreamerPlayerSession::finishVideoOutputChange()
       
   348 {
       
   349     if (!m_pendingVideoSink)
       
   350         return;
       
   351 
       
   352     GstPad *srcPad = gst_element_get_static_pad(m_videoIdentity, "src");
       
   353 
       
   354     if (!gst_pad_is_blocked(srcPad)) {
       
   355         //pad is not blocked, it's possible to swap outputs only in the null state
       
   356         GstState identityElementState = GST_STATE_NULL;
       
   357         gst_element_get_state(m_videoIdentity, &identityElementState, NULL, GST_CLOCK_TIME_NONE);
       
   358         if (identityElementState != GST_STATE_NULL) {
       
   359             gst_object_unref(GST_OBJECT(srcPad));
       
   360             return; //can't change vo yet, received async call from the previous change
       
   361         }
       
   362 
       
   363     }
       
   364 
       
   365     if (m_pendingVideoSink == m_videoSink) {
       
   366         //video output was change back to the current one,
       
   367         //no need to torment the pipeline, just unblock the pad
       
   368         if (gst_pad_is_blocked(srcPad))
       
   369             gst_pad_set_blocked_async(srcPad, false, &block_pad_cb, 0);
       
   370 
       
   371         m_pendingVideoSink = 0;
       
   372         gst_object_unref(GST_OBJECT(srcPad));
       
   373         return;
       
   374     }  
       
   375 
       
   376     gst_element_set_state(m_colorSpace, GST_STATE_NULL);
       
   377     gst_element_set_state(m_videoScale, GST_STATE_NULL);
       
   378     gst_element_set_state(m_videoSink, GST_STATE_NULL);
       
   379 
       
   380     gst_element_unlink(m_videoScale, m_videoSink);
       
   381 
       
   382     gst_bin_remove(GST_BIN(m_videoOutputBin), m_videoSink);
       
   383 
       
   384     m_videoSink = m_pendingVideoSink;
       
   385     m_pendingVideoSink = 0;
       
   386 
       
   387     gst_bin_add(GST_BIN(m_videoOutputBin), m_videoSink);
       
   388     if (!gst_element_link(m_videoScale, m_videoSink))
       
   389         qWarning() << "Linking video output element failed";
       
   390 
       
   391     GstState state;
       
   392 
       
   393     switch (m_state) {
       
   394     case QMediaPlayer::StoppedState:
       
   395         state = GST_STATE_NULL;
       
   396         break;
       
   397     case QMediaPlayer::PausedState:
       
   398         state = GST_STATE_PAUSED;
       
   399         break;
       
   400     case QMediaPlayer::PlayingState:
       
   401         state = GST_STATE_PLAYING;
       
   402         break;
       
   403     }
       
   404 
       
   405     gst_element_set_state(m_colorSpace, state);
       
   406     gst_element_set_state(m_videoScale, state);
       
   407     gst_element_set_state(m_videoSink, state);
       
   408 
       
   409     //don't have to wait here, it will unblock eventually
       
   410     if (gst_pad_is_blocked(srcPad))
       
   411         gst_pad_set_blocked_async(srcPad, false, &block_pad_cb, 0);
       
   412     gst_object_unref(GST_OBJECT(srcPad));
       
   413 
       
   414 #ifdef DEBUG_VO_BIN_DUMP
       
   415     dumpNum++;
       
   416 
       
   417     _gst_debug_bin_to_dot_file(GST_BIN(m_videoOutputBin),
       
   418                                   GstDebugGraphDetails(/*GST_DEBUG_GRAPH_SHOW_ALL */ GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE | GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES),
       
   419                                   QString("video_output_change_%1_finish").arg(dumpNum).toAscii().constData());
       
   420 #endif
       
   421 
   251 }
   422 }
   252 
   423 
   253 bool QGstreamerPlayerSession::isVideoAvailable() const
   424 bool QGstreamerPlayerSession::isVideoAvailable() const
   254 {
   425 {
   255     return m_videoAvailable;
   426     return m_videoAvailable;
   295 void QGstreamerPlayerSession::stop()
   466 void QGstreamerPlayerSession::stop()
   296 {
   467 {
   297     if (m_playbin) {
   468     if (m_playbin) {
   298         gst_element_set_state(m_playbin, GST_STATE_NULL);
   469         gst_element_set_state(m_playbin, GST_STATE_NULL);
   299 
   470 
       
   471         QMediaPlayer::State oldState = QMediaPlayer::StoppedState;
       
   472         m_state = QMediaPlayer::StoppedState;
       
   473 
       
   474         finishVideoOutputChange();
       
   475 
   300         //we have to do it here, since gstreamer will not emit bus messages any more
   476         //we have to do it here, since gstreamer will not emit bus messages any more
   301         if (m_state != QMediaPlayer::StoppedState)
   477         if (oldState != m_state)
   302             emit stateChanged(m_state = QMediaPlayer::StoppedState);
   478             emit stateChanged(m_state);
   303     }
   479     }
   304 }
   480 }
   305 
   481 
   306 bool QGstreamerPlayerSession::seek(qint64 ms)
   482 bool QGstreamerPlayerSession::seek(qint64 ms)
   307 {
   483 {
   308     if (m_playbin && m_state != QMediaPlayer::StoppedState) {
   484     //seek locks when the video output sink is changing and pad is blocked
   309         gint64  position = (gint64)ms * 1000000;
   485     if (m_playbin && !m_pendingVideoSink && m_state != QMediaPlayer::StoppedState) {
   310         return gst_element_seek_simple(m_playbin, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, position);
   486         gint64  position = qMax(ms,qint64(0)) * 1000000;
       
   487         return gst_element_seek(m_playbin,
       
   488                                 m_playbackRate,
       
   489                                 GST_FORMAT_TIME,
       
   490                                 GstSeekFlags(GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH),
       
   491                                 GST_SEEK_TYPE_SET,
       
   492                                 position,
       
   493                                 GST_SEEK_TYPE_NONE,
       
   494                                 0);
   311     }
   495     }
   312 
   496 
   313     return false;
   497     return false;
   314 }
   498 }
   315 
   499 
   469                     GstState    newState;
   653                     GstState    newState;
   470                     GstState    pending;
   654                     GstState    pending;
   471 
   655 
   472                     gst_message_parse_state_changed(gm, &oldState, &newState, &pending);
   656                     gst_message_parse_state_changed(gm, &oldState, &newState, &pending);
   473 
   657 
   474                     /*QStringList states;
   658 #ifdef DEBUG_PLAYBIN_STATES
       
   659                     QStringList states;
   475                     states << "GST_STATE_VOID_PENDING" <<  "GST_STATE_NULL" << "GST_STATE_READY" << "GST_STATE_PAUSED" << "GST_STATE_PLAYING";
   660                     states << "GST_STATE_VOID_PENDING" <<  "GST_STATE_NULL" << "GST_STATE_READY" << "GST_STATE_PAUSED" << "GST_STATE_PLAYING";
   476 
   661 
   477                     qDebug() << QString("state changed: old: %1  new: %2  pending: %3") \
   662                     qDebug() << QString("state changed: old: %1  new: %2  pending: %3") \
   478                             .arg(states[oldState]) \
   663                             .arg(states[oldState]) \
   479                             .arg(states[newState]) \
   664                             .arg(states[newState]) \
   480                             .arg(states[pending]);*/
   665                             .arg(states[pending]);
       
   666 #endif
   481 
   667 
   482                     switch (newState) {
   668                     switch (newState) {
   483                     case GST_STATE_VOID_PENDING:
   669                     case GST_STATE_VOID_PENDING:
   484                     case GST_STATE_NULL:
   670                     case GST_STATE_NULL:
   485                         setSeekable(false);
   671                         setSeekable(false);
   510                                 setSeekable(seekable);
   696                                 setSeekable(seekable);
   511                                 */
   697                                 */
   512 
   698 
   513                             setSeekable(true);
   699                             setSeekable(true);
   514 
   700 
   515                             if (!qFuzzyCompare(m_playbackRate, qreal(1.0)))
   701                             if (!qFuzzyCompare(m_playbackRate, qreal(1.0))) {
   516                                 setPlaybackRate(m_playbackRate);
   702                                 qreal rate = m_playbackRate;
       
   703                                 m_playbackRate = 1.0;
       
   704                                 setPlaybackRate(rate);
       
   705                             }
   517 
   706 
   518                             if (m_renderer)
   707                             if (m_renderer)
   519                                 m_renderer->precessNewStream();
   708                                 m_renderer->precessNewStream();
   520 
   709 
   521                         }
   710                         }
   656     for (int i=0; i<textStreamsCount; i++)
   845     for (int i=0; i<textStreamsCount; i++)
   657         m_streamTypes.append(QMediaStreamsControl::SubPictureStream);
   846         m_streamTypes.append(QMediaStreamsControl::SubPictureStream);
   658 
   847 
   659     for (int i=0; i<m_streamTypes.count(); i++) {
   848     for (int i=0; i<m_streamTypes.count(); i++) {
   660         QMediaStreamsControl::StreamType streamType = m_streamTypes[i];
   849         QMediaStreamsControl::StreamType streamType = m_streamTypes[i];
   661         QMap<QtMediaServices::MetaData, QVariant> streamProperties;
   850         QMap<QtMultimedia::MetaData, QVariant> streamProperties;
   662 
   851 
   663         int streamIndex = i - m_playbin2StreamOffset[streamType];
   852         int streamIndex = i - m_playbin2StreamOffset[streamType];
   664 
   853 
   665         GstTagList *tags = 0;
   854         GstTagList *tags = 0;
   666         switch (streamType) {
   855         switch (streamType) {
   678         }
   867         }
   679 
   868 
   680         if (tags && gst_is_tag_list(tags)) {
   869         if (tags && gst_is_tag_list(tags)) {
   681             gchar *languageCode = 0;
   870             gchar *languageCode = 0;
   682             if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &languageCode))
   871             if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &languageCode))
   683                 streamProperties[QtMediaServices::Language] = QString::fromUtf8(languageCode);
   872                 streamProperties[QtMultimedia::Language] = QString::fromUtf8(languageCode);
   684 
   873 
   685             //qDebug() << "language for setream" << i << QString::fromUtf8(languageCode);
   874             //qDebug() << "language for setream" << i << QString::fromUtf8(languageCode);
   686             g_free (languageCode);
   875             g_free (languageCode);
   687         }
   876         }
   688 
   877 
   731         default:
   920         default:
   732             streamType = QMediaStreamsControl::UnknownStream;
   921             streamType = QMediaStreamsControl::UnknownStream;
   733             break;
   922             break;
   734         }
   923         }
   735 
   924 
   736         QMap<QtMediaServices::MetaData, QVariant> streamProperties;
   925         QMap<QtMultimedia::MetaData, QVariant> streamProperties;
   737         streamProperties[QtMediaServices::Language] = QString::fromUtf8(languageCode);
   926         streamProperties[QtMultimedia::Language] = QString::fromUtf8(languageCode);
   738 
   927 
   739         m_streamProperties.append(streamProperties);
   928         m_streamProperties.append(streamProperties);
   740         m_streamTypes.append(streamType);
   929         m_streamTypes.append(streamType);
   741     }
   930     }
   742 #endif
   931 #endif