To connect Gstreamer with Qt in order to play a gstreamer video in the Qt Widget - qt

I tried using phonon to play the video but could not succeed. Off-late came to know through the Qt forums that even the latest version of Qt does not support phonon. That's when I started using Gstreamer. Any suggestions as to how to connect the Gstreamer window with the Qt widget? My aim is to play a video using Gstreamer on the Qt widget. So how do I link the Gstreamer window and the Qt widget?
I am successful in getting the Id of the widget through winid().
Further with the help of Gregory Pakosz, I have added the below 2 lines of code in my application -
QApplication::syncX();
gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(sink), widget->winId());
However am not able to link the Qt widget with the gstreamer video window.
This is what my sample code would look like :-
int main(int argc, char *argv[])
{
printf("winid=%d\n", w.winId());
gst_init (NULL,NULL);
/* create a new bin to hold the elements */
bin = gst_pipeline_new ("pipeline");
/* create a disk reader */
filesrc = gst_element_factory_make ("filesrc", "disk_source");
g_assert (filesrc);
g_object_set (G_OBJECT (filesrc), "location", "PATH_TO_THE_EXECUTABLE", NULL);
demux = gst_element_factory_make ("mpegtsdemux", "demuxer");
if (!demux) {
g_print ("could not find plugin \"mpegtsmux\"");
return -1;
}
vdecoder = gst_element_factory_make ("mpeg2dec", "decode");
if (!vdecoder) {
g_print ("could not find plugin \"mpeg2dec\"");
return -1;
}
videosink = gst_element_factory_make ("xvimagesink", "play_video");
g_assert (videosink);
/* add objects to the main pipeline */
gst_bin_add_many (GST_BIN (bin), filesrc, demux, vdecoder, videosink, NULL);
/* link the elements */
gst_element_link_many (filesrc, demux, vdecoder, videosink, NULL);
gst_element_set_state(videosink, GST_STATE_READY);
QApplication::syncX();
gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(videosink), w.winId());
/* start playing */
gst_element_set_state (bin, GST_STATE_PLAYING);
}
Could you explain more in detail about the usage of gst_x_overlay_set_xwindow_id() wrt my context?
Could I get any hint as to how I can integrate gstreamer under Qt?
Please help me solve this problem.

I just did this same thing using python. What I had to do was connect to 'sync-message::element' on the bus and listen for a message called 'prepare-xwindow-id' (disregard the name as it works on all platforms, not just X11) sent after the video sink is setup. It sends you the sink inside that message, and that is where you pass it the window id.

The sample code given above will link GStreamer video window to QtWidget provided the elements are linked correctly.
filesrc should be linked to the demuxer
decoder should be linked to the filesink
Finally, the demuxer should be linked to the decoder at runtime
// link filesrc to demuxer
gst_element_link(filesrc,demux)
// link vdecoder to filesink
gst_element_link_many(vdecoder,filesink,NULL)
/*
The demuxer will be linked to the decoder dynamically.
The source pad(s) will be created at run time,
by the demuxer when it detects the amount and nature of streams.
Connect a callback function which will be executed
when the "pad-added" is emitted.
*/
g_signal_connect(demux,"pad-added",G_CALLBACK(on_pad_added),vdecoder);
// callback definition
static void on_pad_added(GstElement* element,GstPad* pad,gpointer* data)
{
GstPad* sinkpad;
GstElement * decoder = (GstElement*)data;
GstCaps* caps;
GstStructure* str;
gchar* tex;
caps = gst_pad_get_caps(pad);
str = gst_caps_get_structure(caps,0);
tex = (gchar*)gst_structure_get_name(str);
if(g_strrstr(tex,"video"))
{
sinkpad = gst_element_get_static_pad(decoder,"sink");
gst_pad_link(pad,sinkpad);
gst_object_unref(sinkpad);
}
}

http://cgit.freedesktop.org/gstreamer/gst-plugins-base/tree/tests/examples/overlay
has a minimal Qt example.
In your code, you should probably set the window ID before you do the state change to ready (I'm not 100% sure this is the problem though).
For playback, you should idally use the playbin2 element, something like this (completely untested):
GstElement *playbin, *videosink;
gchar *uri;
playbin = gst_element_factory_make ("playbin2", "myplaybin");
videosink = gst_element_factory_make ("xvimagesink", NULL);
g_object_set (playbin, "video-sink", videosink, NULL);
uri = g_filename_to_uri ("/path/to/file", NULL, NULL);
g_object_set (playbin, "uri", uri, NULL);
g_free (uri);
/* NOTE: at this point your main window needs to be realized,
* ie visible on the screen, and you might need to make sure
* that your widget w indeed has a 'native window' (just some
* things to check for if it doesn't work; there should be Qt
* API for this kind of thing if needed) */
QApplication::syncX();
 gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(videosink), w.winId());
gst_element_set_state (playbin, GST_STATE_PLAYING);
.. check for messages like error/statechanges/tags/eos on pipeline/playbin bus

A project wrapping gstreamer into usable C++/Qt classes including example code:
http://code.google.com/p/qbtgstreamer/
I don't know about a direct approach, as I am not familiar with gstreamer itself.

Related

Qt: Use QAudioRecorder to return buffer

I want to use QAudioRecorder to record an audio and save as a file and display the filepath to the user. I had tried using the the example from Qt but there's no feed on the buffer value when I tested it on Android. It works on my Desktop though. Below are part of my codes:
AudioRecord::AudioRecord(QWidget *parent)
{
audioRecorder = new QAudioRecorder(this);
probe = new QAudioProbe;
connect(probe, SIGNAL(audioBufferProbed(QAudioBuffer)),
this, SLOT(processBuffer(QAudioBuffer)));
probe->setSource(audioRecorder);
}
void AudioRecord::processBuffer(const QAudioBuffer& buffer)
{
qDebug()<<"Testing Successful";
}
The processBuffer function does not seems to be called. What should I do to get the buffer value work? Is there any other way around?
Thanks!

How to find video resolution and aspect ratio of QMediaPlayer video?

This seems too simple, I must be overlooking something?
How do I find the native video size or aspect ratio from a video file being displayed by a QMediaPlayer?
The video Resolution, PixelAspectRatio, etc., should be in the MetaData, but I wait for MetaData Update Signals, and wait for seconds after the video .play()s, but isMetaDataAvailable() always returns false, and .availableMetaData() and .metaData(QMediaMetaData::Resolution).toSize() always return empty.
There seems to be nowhere else to get the video resolution information, or am I missing something?
I can open the video, play the video at full screen, etc.
You can use QVideoWidget instance as video output for QMediaPlayer and retrieve native size of video from QVideoWidget::sizeHint.
QSize MyVideoPlayer::getVideoNativeSize(const QString& videoFilePath)
{
m_mediaPlayer = new QMediaPlayer(0, QMediaPlayer::VideoSurface);
m_mediaPlayer->setVideoOutput(m_videoWidget);
m_mediaPlayer->setMedia(QUrl::fromLocalFile(videoFilePath));
connect(m_mediaPlayer, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
this, SLOT(OnMediaStatusChanged(QMediaPlayer::MediaStatus)));
m_isStoppingVideo = false;
QEventLoop loop;
m_mediaPlayer->play();
while (!m_isStoppingVideo)
{
loop.processEvents();
}
disconnect(m_mediaPlayer, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
this, SLOT(OnMediaStatusChanged(QMediaPlayer::MediaStatus)));
m_mediaPlayer->stop();
return m_videoWidget->sizeHint();
}
void MyVideoPlayer::OnMediaStatusChanged(QMediaPlayer::MediaStatus mediaStatus)
{
if (mediaStatus == QMediaPlayer::BufferedMedia)
{
m_isStoppingVideo = true;
}
}
For finding the resolution without metadata, you can take a look at this question from the Qt Forums for a possible solution:
http://forum.qt.io/topic/31278/solved-get-resolution-of-a-video-file-40-qmediaplayer-41/2
I solved my problem by waiting until the user plays the video and as
soon as they do so i get the QGraphicsVideoItems class property:
nativeSize.
I also solved this problem with QGraphicsVideoItems nativeSize property. But the tricky thing is that nativeSize becomes valid only after some time since you start playing video. The trick is to connect to special QGraphicsVideoItem::nativeSizeChanged(const QSizeF &size) signal that is emitted in case of real nativeSize obtainment.

How to play QAudioBuffer by QIODevice?

I want to make an audio streaming program (like phone) using the QMediaPlayer, QAudioProbe and QAudioOutput classes in Qt 5.3.0 MSVC2012 OpenGL 32bit.
This is my code:
musicPlayer = new QMediaPlayer();
musicProbe = new QAudioProbe();
musicProbe->setSource(musicPlayer);
connect(musicProbe, SIGNAL(audioBufferProbed(QAudioBuffer)),
this, SLOT(slotGetMusicData(QAudioBuffer)));
If audio data probed, the slot is actived.
void MusicPlayer::slotGetMusicData(QAudioBuffer musicBuffer)
{
/*QAudioBuffer to QByteArray*/
*musicDataBuffer = musicDataBuffer->fromRawData((char *)musicBuffer.data(),
,musicBuffer.byteCount());
/*Send Music Data*/
musicSocket->sendMudicData(*musicDataBuffer);
qDebug("send complete");
}
Using a socket, I send the data to another program.
The other program plays the music received.
QAudioOutput *audioOutput = new QAudioOutput(format, this);
QIoDevice *audioDevice = audioOutput->start();
and then, data received this slot is actived.
void BgmSocket::slotPlayBgm(QByteArray data)
{
audioDevice->write(data.data(), data.size());
}
The audio is playing well, but the sounds have a lot of static (pause sound).
How can I solve this problem?
The problem was a different frequency between the network and the playback buffer.
I solved this problem by creating a buffer with double buffering.

to paint image in standard NPAPI plugin with QT

I need to create a NPAPI browser plugin to show a picture.
Till now, I have create that and draw a picture in plugin with GDK successfully, I catch the event in "NPP_HandleEvent()" function and get a GdkDrawable object with method "gdk_pixmap_lookup", just like the following codes:
int16_t NPP_HandleEvent(NPP instance, void* event) {
XGraphicsExposeEvent *expose = &nativeEvent->xgraphicsexpose;
instanceData->window.window = (void*)(expose->drawable);
GdkNativeWindow nativeWinId = (XID)(instanceData->window.window);
GdkDrawable* gdkWindow = GDK_DRAWABLE(gdk_pixmap_lookup(xid));
NPSetWindowCallbackStruct *ws_info = (NPSetWindowCallbackStruct*)(instanceData->window.ws_info);
GdkVisual* gdkVisual = gdkx_visual_get(ws_info->visual ? XVisualIDFromVisual(ws_info->visual) : 0);
GdkColormap* gdkColormap = gdk_x11_colormap_foreign_new(gdkVisual, ws_info->colormap);
gdk_drawable_set_colormap(gdkWindow, gdkColormap);
// another method, to use GdkWindow to draw picture.
drawWindow(instanceData, gdkWindow);
}
so now, I'm wondering how to use QT methods draw a picture in this plugin ? any ways just use QT and X11 releated stubs to implement this ?

How can I get a video meta data using Qt phonon?

I want to get the bitrate of a video. And I use Qt Phonon to achieve this goal.
Since there is a class called Phonon::MediaObject and provide a method called metaData(),I use that method but the result shows zero. Here is my code, I wonder why and how can I get the metadata such as bitrate in qt with Phonon
QString source="E:\\sh.mp4";
Phonon::MediaObject media;
media.setCurrentSource(Phonon::MediaSource(source));
QMap <QString, QString> metaData = media.metaData();
int trackBitrate = metaData.value("bitrate").toInt();
qDebug()<<trackBitrate;
The result is 0 all the time
I just figured this out myself.
Meta data in video files do not contain bitrate. It only contains extra information about the media that don't have any effect on playback. So even if Phonon::MediaObject::metaData() worked without loading the video, it will not help you.
I ended up using libformat, part of ffmpeg library to get the bitrate. Here's the code.
If you copy and paste this, it should work.
Download FFMpeg here: http://dranger.com/ffmpeg/tutorial01.html
This first tutorial will tell you how to link: http://dranger.com/ffmpeg/tutorial01.html
#include <QString>
#include <QMultiMap>
#include <stdio.h>
#include <libavformat/avformat.h>
#include <libavutil/dict.h>
void processMedia(const char* mediaFile)
{
AVFormatContext *pFormatCtx = NULL;
AVDictionaryEntry *tag = NULL;
// Register all formats and codecs
av_register_all();
// Open video file
if(avformat_open_input(&pFormatCtx, mediaFile, NULL, NULL)!=0)
return;
// Retrieve stream information
if(av_find_stream_info(pFormatCtx)<0)
return;
//Get Bitrate
float bitRate = pFormatCtx->bit_rate;
//Get Meta
QMultiMap<QString, QString> metaData;
while ((tag = av_dict_get(pFormatCtx->metadata, "", tag,
AV_DICT_IGNORE_SUFFIX)))
{
QString keyString(tag->key);
QString valueString(tag->value);
metaData.insert(keyString, valueString);
printf("%s=%s\n", tag->key, tag->value);
}
// Close the video file
av_close_input_file(pFormatCtx);
}
When you set the data source, the MediaObject enters the LoadingState. At that point, metadata might not yet be available.
The object emits a metaDataChanged signal when the metadata is ready. You should react to that signal and only attempt accessing the metadata once it has been emitted.

Resources