void QGstreamerPlayerSession::setVideoRenderer(QObject *videoOutput) { QGstreamerVideoRendererInterface* renderer = qobject_cast<QGstreamerVideoRendererInterface*>(videoOutput); if (m_renderer == renderer) return; #ifdef DEBUG_VO_BIN_DUMP dumpNum++; _gst_debug_bin_to_dot_file(GST_BIN(m_videoOutputBin), GstDebugGraphDetails(GST_DEBUG_GRAPH_SHOW_ALL /* GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE | GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES*/), QString("video_output_change_%1_set").arg(dumpNum).toAscii().constData()); #endif m_renderer = renderer; GstElement *videoSink = m_renderer ? m_renderer->videoSink() : m_nullVideoSink; if (m_state == QMediaPlayer::StoppedState) { m_pendingVideoSink = 0; gst_element_unlink(m_videoScale, m_videoSink); gst_bin_remove(GST_BIN(m_videoOutputBin), m_videoSink); m_videoSink = videoSink; gst_bin_add(GST_BIN(m_videoOutputBin), m_videoSink); gst_element_link(m_videoScale, m_videoSink); } else { if (m_pendingVideoSink) { m_pendingVideoSink = videoSink; return; } m_pendingVideoSink = videoSink; //block pads, async to avoid locking in paused state GstPad *srcPad = gst_element_get_static_pad(m_videoIdentity, "src"); gst_pad_set_blocked_async(srcPad, true, &block_pad_cb, this); gst_object_unref(GST_OBJECT(srcPad)); } }
void QGstreamerPlayerSession::finishVideoOutputChange() { if (!m_pendingVideoSink) return; #ifdef DEBUG_PLAYBIN qDebug() << "finishVideoOutputChange" << m_pendingVideoSink; #endif GstPad *srcPad = gst_element_get_static_pad(m_videoIdentity, "src"); if (!gst_pad_is_blocked(srcPad)) { //pad is not blocked, it's possible to swap outputs only in the null state qWarning() << "Pad is not blocked yet, could not switch video sink"; GstState identityElementState = GST_STATE_NULL; gst_element_get_state(m_videoIdentity, &identityElementState, NULL, GST_CLOCK_TIME_NONE); if (identityElementState != GST_STATE_NULL) { gst_object_unref(GST_OBJECT(srcPad)); return; //can't change vo yet, received async call from the previous change } } if (m_pendingVideoSink == m_videoSink) { //video output was change back to the current one, //no need to torment the pipeline, just unblock the pad if (gst_pad_is_blocked(srcPad)) gst_pad_set_blocked_async(srcPad, false, &block_pad_cb, 0); m_pendingVideoSink = 0; gst_object_unref(GST_OBJECT(srcPad)); return; } gst_element_set_state(m_videoSink, GST_STATE_NULL); gst_element_unlink(m_videoIdentity, m_videoSink); gst_bin_remove(GST_BIN(m_videoOutputBin), m_videoSink); m_videoSink = m_pendingVideoSink; m_pendingVideoSink = 0; gst_bin_add(GST_BIN(m_videoOutputBin), m_videoSink); if (!gst_element_link(m_videoIdentity, m_videoSink)) qWarning() << "Linking video output element failed"; GstState state; switch (m_pendingState) { case QMediaPlayer::StoppedState: state = GST_STATE_NULL; break; case QMediaPlayer::PausedState: state = GST_STATE_PAUSED; break; case QMediaPlayer::PlayingState: state = GST_STATE_PLAYING; break; } gst_element_set_state(m_videoSink, state); //don't have to wait here, it will unblock eventually if (gst_pad_is_blocked(srcPad)) gst_pad_set_blocked_async(srcPad, false, &block_pad_cb, 0); gst_object_unref(GST_OBJECT(srcPad)); #ifdef DEBUG_VO_BIN_DUMP dumpNum++; _gst_debug_bin_to_dot_file(GST_BIN(m_playbin), GstDebugGraphDetails(/*GST_DEBUG_GRAPH_SHOW_ALL */ GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE | GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES), QString("playbin_%1_finish").arg(dumpNum).toAscii().constData()); #endif }
void QGstreamerPlayerSession::setVideoRenderer(QObject *videoOutput) { if (m_videoOutput != videoOutput) { if (m_videoOutput) { disconnect(m_videoOutput, SIGNAL(sinkChanged()), this, SLOT(updateVideoRenderer())); disconnect(m_videoOutput, SIGNAL(readyChanged(bool)), this, SLOT(updateVideoRenderer())); } if (videoOutput) { connect(videoOutput, SIGNAL(sinkChanged()), this, SLOT(updateVideoRenderer())); connect(videoOutput, SIGNAL(readyChanged(bool)), this, SLOT(updateVideoRenderer())); } m_videoOutput = videoOutput; } QGstreamerVideoRendererInterface* renderer = qobject_cast<QGstreamerVideoRendererInterface*>(videoOutput); m_renderer = renderer; #ifdef DEBUG_VO_BIN_DUMP dumpNum++; _gst_debug_bin_to_dot_file(GST_BIN(m_playbin), GstDebugGraphDetails(GST_DEBUG_GRAPH_SHOW_ALL /* GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE | GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES*/), QString("playbin_%1_set").arg(dumpNum).toAscii().constData()); #endif GstElement *videoSink = m_renderer ? m_renderer->videoSink() : m_nullVideoSink; if (!videoSink) videoSink = m_nullVideoSink; #ifdef DEBUG_PLAYBIN qDebug() << "Set video output:" << videoOutput; qDebug() << "Current sink:" << (m_videoSink ? GST_ELEMENT_NAME(m_videoSink) : "") << m_videoSink << "pending:" << (m_pendingVideoSink ? GST_ELEMENT_NAME(m_pendingVideoSink) : "") << m_pendingVideoSink << "new sink:" << (videoSink ? GST_ELEMENT_NAME(videoSink) : "") << videoSink; #endif if (m_pendingVideoSink == videoSink || (m_pendingVideoSink == 0 && m_videoSink == videoSink)) { #ifdef DEBUG_PLAYBIN qDebug() << "Video sink has not changed, skip video output reconfiguration"; #endif return; } #ifdef DEBUG_PLAYBIN qDebug() << "Reconfigure video output"; #endif if (m_state == QMediaPlayer::StoppedState) { #ifdef DEBUG_PLAYBIN qDebug() << "The pipeline has not started yet, pending state:" << m_pendingState; #endif //the pipeline has not started yet m_pendingVideoSink = 0; gst_element_set_state(m_videoSink, GST_STATE_NULL); gst_element_set_state(m_playbin, GST_STATE_NULL); gst_element_unlink(m_videoIdentity, m_videoSink); gst_bin_remove(GST_BIN(m_videoOutputBin), m_videoSink); m_videoSink = videoSink; gst_bin_add(GST_BIN(m_videoOutputBin), m_videoSink); gst_element_link(m_videoIdentity, m_videoSink); switch (m_pendingState) { case QMediaPlayer::PausedState: gst_element_set_state(m_playbin, GST_STATE_PAUSED); break; case QMediaPlayer::PlayingState: gst_element_set_state(m_playbin, GST_STATE_PLAYING); break; default: break; } } else { if (m_pendingVideoSink) { #ifdef DEBUG_PLAYBIN qDebug() << "already waiting for pad to be blocked, just change the pending sink"; #endif m_pendingVideoSink = videoSink; return; } m_pendingVideoSink = videoSink; #ifdef DEBUG_PLAYBIN qDebug() << "Blocking the video output pad..."; #endif { #ifdef DEBUG_PLAYBIN qDebug() << "send the last new segment event to the video output..."; #endif GstEvent *event = gst_event_new_new_segment(TRUE, m_segment.rate, m_segment.format, m_segment.last_stop, //start m_segment.stop, m_segment.last_stop);//position GstPad *pad = gst_element_get_static_pad(videoSink, "sink"); //gst_pad_send_event(pad, m_lastSegmentEvent); gst_pad_send_event(pad, event); gst_object_unref(GST_OBJECT(pad)); } //block pads, async to avoid locking in paused state GstPad *srcPad = gst_element_get_static_pad(m_videoIdentity, "src"); gst_pad_set_blocked_async(srcPad, true, &block_pad_cb, this); gst_object_unref(GST_OBJECT(srcPad)); } }