How to capture video from camera via ethernet socket - c++

I need to capture video from a live camera plugged to my PC ethernet socket. I used Phonon to capture video from a file in my system first. It works fine. Then, I created a socket to read the video. Here, I do not know how to get the buffered data and set it as a source to my Phonon video! I would thank if anyone could help me with this.
Here's the code to read a video :
void PlayVideo::rollOn()
{
media = new Phonon::MediaObject(movieLabel);
media->setCurrentSource(Phonon::MediaSource(QString("/home/saman/4.7/phonon_test/sample.mp4")));
videoPlayer = new Phonon::VideoPlayer(Phonon::VideoCategory, movieLabel);
videoPlayer->setFixedSize(QSize(400, 300));
videoPlayer->show();
connect(videoPlayer, SIGNAL(finished()), videoPlayer, SLOT(deleteLater()));
videoPlayer->play(media->currentSource());
}
and this is how I added sockets to the code:
void PlayVideo::rollOn()
{
udpSocketin = new QUdpSocket(this);
udpSocketin->bind(localPort);
connect(udpSocketin, SIGNAL(readyRead()),this, SLOT(readDatagrams()));
QDataStream out(&datagramout, QIODevice::WriteOnly);
out.setVersion (QDataStream::Qt_4_7);
timer2 = new QTimer(this);
connect(timer2, SIGNAL(timeout()), this, SLOT(playbuff()));
media = new Phonon::MediaObject(movieLabel);
media->setCurrentSource(Phonon::MediaSource(QString("/home/saman/4.7/phonon_test/sample.mp4")));
//media->setCurrentSource (Phonon::MediaSource());
videoPlayer = new Phonon::VideoPlayer(Phonon::VideoCategory, movieLabel);
videoPlayer->setFixedSize(QSize(400, 300));
videoPlayer->show();
connect(videoPlayer, SIGNAL(finished()), videoPlayer, SLOT(deleteLater()));
videoPlayer->play(media->currentSource());
}
void PlayVideo::readDatagrams()
{
if(udpSocketin->hasPendingDatagrams ())
{
datagramin.resize (udpSocketin->pendingDatagramSize ());
qint64 receiveBytes = udpSocketin->readDatagram (datagramin.data (), datagramin.size ));
if(receivedBytes <= 0)
{
qDebug("receivedBytes <= 0");
}
}
}

You can put your data into a QBuffer, which is a subclass of QIODevice. Then, there's a media source constructor that accepts a QIODevice.

Related

Qt change picture on timer

I'm trying to change the image on QLabel in Qt.
At first, I did the basic set image as follows:
void MainWindow::setMainDisplayNew(QString imageName){
QPixmap pix7 = imageName;
QPixmap pix8 = pix7.scaled(QSize(720,480), Qt::KeepAspectRatio);
ui->mainDisplay->setStyleSheet(imageName);
ui->mainDisplay->setPixmap(pix8);
}
Now I want to change this so I can pass 2 arrays. List of images and duration they should appear for and I want the display to show them for the indicated duration.
void MainWindow::setMainDisplay(QString imageName[], int size)
{
for(unsigned int i=0; i<size; i++)
{
QTimer * timer = new QTimer(this);
timer->setSingleShot(true);
connect(timer, &QTimer::timeout, [=](){
setMainDisplayNew(imageName[i]);
timer->deleteLater(); // ensure we cleanup the timer
});
timer->start(3000);
}
}
EDIT
With the help of the responses, I reached the above code. I am sending the 3 images. It is display the final image after 3 seconds and stays as is... Any help?
while(true){
This is your problem. Qt is an event-driven framework. The while(true) prevents events from being processed. Such events include the timeout from the QTimer and updating of the GUI. You need to allow the function to exit.
In addition, you're not cleaning up your timers, so you're leaking memory every time you enter the function (although that's currently only once!). You can clean up with a call to deleteLater.
Using C++ 11, it would be something like this: -
for(int i=0; i<mySize; i++)
{
QTimer * timer = new QTimer(this);
timer->setSingleShot(true);
connect(timer, &QTimer::timeout, [=](){
setMainDisplayNew(imageName[i]);
timer->deleteLater(); // ensure we cleanup the timer
});
timer->start(duration[i]);
}

QUdpSocket doesn't emit readyRead() signal

I faced a problem with QUdpSocket. Signal readyRead() seems to be never emitted. So, I decided to create QTimer and check state of socket reading queue. That way I ensured that socket working properly (bytesAvailable() shows number of bytes) and signal/slot mechanism is working too (timeout() signal occurred). But why readyRead() doesn't emit? Thanks.
Qt 5.1
QString EthernetListener::listen()
{
udp_socket = new QUdpSocket(this);
connect(udp_socket, SIGNAL(readyRead()), this, SLOT(process_messages()));
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(dummy_slot()));
timer->start(1000);
bool res = udp_socket->bind(QHostAddress::Any, 1947, QUdpSocket::ShareAddress);
if (!res)
return QString("Не удалось подключиться к хосту").toUtf8();
return QString("Идет прослушка сети. Хост: ");
}
void EthernetListener::dummy_slot()
{
int test = udp_socket->bytesAvailable();
}
void EthernetListener::process_messages()
{
bool bp = true;
}
This problem can occur if more data becomes available while still processing the first datagram. Add this to the slot and it should work fine:
int readCount;
while (udpSock->hasPendingDatagrams())
{
readCount = udpSock->readDatagram(buffer, 4096);
cout << "readCount = " << readCount << endl;
}
You can try implementing basic receiver using this one: Udp Receiver
Probably you are not reading correctly from the slot so it looks like the signal is not emitted. Or you are calling bind after you connected the slot: probably you should call bind before connecting the slot.

QNetworkAccessManager multiple uploads fail

In my App, I have a method to upload files to the server, this works fine.
But when I call this method multiple times at once (like iterating over the result of a chooseFilesDialog) the first 7 (more or less) files are uploaded correctly, the others never get uploaded.
I think this has to be linked with the fact the server doesn't allow more than X connections from the same source maybe?
How can I make sure the upload waits for a free, established connection?
this is my method:
QString Api::FTPUpload(QString origin, QString destination)
{
qint64 timestamp = QDateTime::currentMSecsSinceEpoch();
QUrl url("ftp://ftp."+getLSPro("domain")+destination);
url.setUserName(getLSPro("user"));
url.setPassword(getLSPro("pwd"));
QFile *data = new QFile(origin, this);
if (data->open(QIODevice::ReadOnly))
{
QNetworkAccessManager *nam = new QNetworkAccessManager();
QNetworkReply *reply = nam->put(QNetworkRequest(url), data);
reply->setObjectName(QString::number(timestamp));
connect(reply, SIGNAL(uploadProgress(qint64, qint64)), SLOT(uploadProgress(qint64, qint64)));
return QString::number(timestamp);
}
else
{
qDebug() << "Could not open file to FTP";
return 0;
}
}
void Api::uploadProgress(qint64 done, qint64 total) {
QNetworkReply *reply = (QNetworkReply*)sender();
emit broadCast("uploadProgress","{\"ref\":\""+reply->objectName()+"\" , \"done\":\""+QString::number(done)+"\", \"total\":\""+QString::number(total)+"\"}");
}
First, don't create a QNetworkManager every time you start an upload.
Second, you definitely have to delete everything you new(), otherwise you are left with memory leaks. This includes the QFile, the QNetworkManager AND the QNetworkReply (!).
Third, you have to wait for the finished() signal.
Api::Api() { //in the constructor create the network access manager
nam = new QNetworkAccessManager()
QObject::connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(finished(QNetworkReply*)));
}
Api::~Api() { //in the destructor delete the allocated object
delete nam;
}
bool Api::ftpUpload(QString origin, QString destination) {
qint64 timestamp = QDateTime::currentMSecsSinceEpoch();
QUrl url("ftp://ftp."+getLSPro("domain")+destination);
url.setUserName(getLSPro("user"));
url.setPassword(getLSPro("pwd"));
//no allocation of the file object;
//will automatically be destroyed when going out of scope
//I use readAll() (see further) to fetch the data
//this is OK, as long as the files are not too big
//If they are, you should allocate the QFile object
//and destroy it when the request is finished
//So, you would need to implement some bookkeeping,
//which I left out here for simplicity
QFile file(origin);
if (file.open(QIODevice::ReadOnly)) {
QByteArray data = file.readAll(); //Okay, if your files are not too big
nam->put(QNetworkRequest(url), data);
return true;
//the finished() signal will be emitted when this request is finished
//now you can go on, and start another request
}
else {
return false;
}
}
void Api::finished(QNetworkReply *reply) {
reply->deleteLater(); //important!!!!
}

How to use QtMultimedia to play a wav file?

My current code is:
void Sound::run() {
QFile audio_file(mResourcePath);
if(audio_file.open(QIODevice::ReadOnly)) {
audio_file.seek(44); // skip wav header
QByteArray audio_data = audio_file.readAll();
audio_file.close();
QBuffer* audio_buffer = new QBuffer(&audio_data);
qDebug() << audio_buffer->size();
QAudioFormat format;
format.setSampleSize(16);
format.setSampleRate(44100);
format.setChannelCount(2);
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::UnSignedInt);
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
if (!info.isFormatSupported(format)) {
qWarning()<<"raw audio format not supported by backend, cannot play audio.";
return;
}
qDebug() << info.deviceName();
QAudioOutput* output = new QAudioOutput(info, format);
output->start(audio_buffer);
}
}
This whole thing is started as a QRunnable in a QThreadPool and that part works fine. Problem is I never get any audio. My sound device is operational, the buffer is filled. I don't know what's wrong. I use app.exec(). Help appreciated.
The device (QBuffer) has to be open:
QBuffer audio_buffer(&audio_data);
audio_buffer.open(QIODevice::ReadOnly);
QAudioOutput needs an event loop to play anything, and that loop has to be running in the thread it belongs to. Which is the thread it was created in when you don't explicitly move it to another thread:
// Create the device and start playing...
QAudioOutput output(info, format);
output.start(&audio_buffer);
// ...then wait for the sound to finish
QEventLoop loop;
QObject::connect(&output, SIGNAL(stateChanged(QAudio::State)), &loop, SLOT(quit()));
do {
loop.exec();
} while(output.state() == QAudio::ActiveState);
Everything you allocate should be deallocated when the sound has finished playing, or you would have a memory leak, and the event loop will now run inside the function, so you can allocate everything locally.

QT C++ - Class problem wait until signal is processed and return data back

I've this code here in a program I'm making but I've a problem, How can I keep the program waiting for data on http2 before returning to the tcpserver class? And how can I get the data in the tcpserver class?
This is like a checkpoint were I need to get the data from the server and then keep running the tcpserver and use that data there.
tcpserver.cpp
#include "tcpserver.h"
#include "protocol.h"
#include "http2.h"
QTextStream in(stdin);
tcpserver::tcpserver(QObject *parent) :
QObject(parent)
{
server = new QTcpServer(this);
[ ... Other Server Stuff ... ]
http2 *h = new http2(this);
}
I've tried this with no luck:
http2.cpp
#include "http2.h"
bool httpdonne = false;
QByteArray finaldata;
http2::http2(QObject *parent, QByteArray url, QByteArray data) :
QObject(parent)
{
url.append(data);
m_manager = new QNetworkAccessManager(this);
connect(m_manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(httpdown(QNetworkReply*)));
QNetworkRequest request;
request.setUrl(QUrl(url));
request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
m_manager->get(request);
while ( httpdonne == false ) {
}
finaldata.append("HTTP: ");
qDebug() << finaldata;
}
QByteArray http2::httpdown(QNetworkReply* result)
{
QByteArray data = result->readAll();
finaldata = data;
httpdonne = true;
return data;
}
Thanks a lot! ;)
Qt makes use of signals and slots and the event loop. If you have no QEventLoop running which is normally provided by QApplication your events will not be handled.
Take a peek at this question to see how to create an event loop to simulate a blocking (synchronous) using the asynchronous programming model.
In addition I normally add a QTimer too:
QEventLoop loop;
..
QTimer timer;
timer.setInterval(2000);
timer.setSingleShot(true);
loop.connect(&timer, SIGNAL(timeout()), SLOT(handleTimeout()));
timer.start();
..
//Setup your objects / connections here...
..
loop.exec(); //Your signals and slots will be triggered / handled now!
Qt network classes are all signal-driven. That is, you create functions which handle various events (data ready etc) and connect them to the appropriate slots. Blocking isn't really the way they are to be used.
Of course I would never recommend what you are trying to achieve but if you still wanna "shoot yourself in the foot" :) then here's what you can try,
run the manager as a separate thread and make the http2 or tcpserver thread wait on
a condition variable. And when the manager is done invoke the threads
waiting the the condition variable.
You can use my WaitForSignalHelper class posted here , it does what you want: wait for a timeout OR signal to be emitted...