I am working on USB WebCamera using OpenCv in Qt.The code works fine for taking images, saving images etc. But randomly it generates error "VIDIOC_QUERYCTRL: Input/output error" causing my whole qt application to shutdown.
Actually The Scenario of my application is as follow:
In MainWindow.c, I have a pushbutton, which is when pressed starts the camera:
void MainWindow::on_pushButton_continue_pressed()
{
camcapture = new CamCapture( imgResolution, defaultPath, this);
connect(camcapture, SIGNAL(imgChange(QString)), this, SLOT(changeImg(QString)));
camcapture->show();
}
and Here is piece of my CamCapture Class:
CamCapture::CamCapture( int Resolution, QString path, QWidget *parent) :
QFrame(parent),
ui(new Ui::CamCapture), timer_(this), counter_(0)
{
ui->setupUi(this);
/*----some variable initialization---*/
camInit();
timer_.start(100);
connect(&timer_,SIGNAL(timeout()), this,SLOT(captureLoop()));
}
void CamCapture::camInit()
{
capture_ = cvCaptureFromCAM(0);
if (!capture_)
{
qDebug()<<"cannot get webcam...";
ui->label_image->setText("No webcam!");
ui->label_image->setAlignment(Qt::AlignCenter);
buttonActiveStatus( false, false, false );
return;
}
cvGrabFrame(capture_); // Grabs frame from camera or file
image_ = cvRetrieveFrame(capture_); // Gets the image grabbed with cvGrabFrame
qDebug() << "image size : " << image_->width << "x" << image_->height;
qDebug() << "\n" << ui->label_image->x();
qDebug() << "\n" << ui->label_image->y();
}
QImage CamCapture::Ipl2QImage(const IplImage *newImage)
{
QImage qtemp;
if (newImage && cvGetSize(newImage).width > 0)
{
int x;
int y;
char* data = newImage->imageData;
qtemp= QImage(newImage->width, newImage->height,QImage::Format_RGB32 );
for( y = 0; y < newImage->height; y++, data +=newImage->widthStep )
for( x = 0; x < newImage->width; x++)
{
uint *p = (uint*)qtemp.scanLine (y) + x;
*p = qRgb(data[x * newImage->nChannels+2],
data[x * newImage->nChannels+1],data[x * newImage- >nChannels]);
}
}
return qtemp;
}
void CamCapture::captureLoop()
{
if ( !capture_ )
{
return;
}
cvGrabFrame(capture_);
image_ = cvRetrieveFrame(capture_);
if (image_)
{
counter_ ++;
qImage_ = Ipl2QImage(image_);
ui->label_image- >setPixmap(QPixmap::fromImage(qImage_.scaled(width(),height()),Qt::AutoColor));
}
}
void CamCapture::on_pushButton_cancel_pressed()
{
cvReleaseCapture( &capture_ );
cvDestroyAllWindows();
delay(100);
qDebug() << "nb frames :" << counter_;
CamCapture::close();
}
void CamCapture::on_pushButton_capture_pressed()
{
savePath = _imgPath;
timer_.stop();
frame = cvQueryFrame(capture_); // Gets the image grabbed with cvGrabFrame
}
void CamCapture::on_pushButton_retake_pressed()
{
timer_.start(100);
captureLoop();
}
void CamCapture::on_pushButton_save_pressed()
{
int iwidth = _imgWidth * _imgResolution * scaledFactor;
int iheight = _imgHeight * _imgResolution * scaledFactor;
QString str = savePath;
IplImage *small;
small = cvCreateImage(cvSize(iwidth,iheight), 8, 3);
cvResize(frame, small);
cvSaveImage(savePath.toUtf8().constData(),small);
delay(100);
_imgNum++;
emit imgChange(savePath);
on_pushButton_cancel_pressed();
}
The above code randomly generates error ( causing my application shutdowm ) as follow:
Debugging starts
&"warning: GDB: Failed to set controlling terminal: Invalid argument\n"
Corrupt JPEG data: bad Huffman code
image size : 640 x 480
5
10
nb frames : 11
VIDIOC_QUERYCTRL: Input/output error
Debugging has finished
Commonly, the Error is generated Either while pressing pushButton_continue from MainWindow.c or While pressing pushButton_Save from CamCapture.c
Unable to find any solution on google.
Need some suggestions/help/link to solve this issue.
Thanks in advance.
Related
I have just started using C++ for some image processing tasks. I want to integrate my RGB (OpenCV Mat) and Depth (PCL) data which I get from ros::Subscribe into colored-pointcloud data.
I use the cv::Mat acquiredImage to hold the transmitted image from ros::Subscribe and then the Mat acquiredImage is used for another processes in another threads, but I am facing segmentation fault. Or the error is shown like this:
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that. Viewtest: ../../src/xcb_io.c:260:
poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
Aborted (core dumped)
I have tried using std::mutex but it still doesn't work. Could anyone tell me how to properly manage the cv::Mat in two different threads?
typedef pcl::PointXYZRGB XYZRGB;
typedef pcl::PointCloud<XYZRGB> pclXYZRGB;
typedef pcl::PointCloud<XYZRGB>::Ptr pclXYZRGBptr;
typedef pcl::PointCloud<XYZRGB>::ConstPtr pclXYZRGBcptr;
pclXYZRGBptr acquiredCloud (new pclXYZRGB());
pclXYZRGBptr acquiredCloud2 (new pclXYZRGB());
cv::Mat acquiredImage, acquiredImageRotated;
std::thread thread_RunThread;
std::mutex mutexMutex;
bool stopThread, has_data1, has_data2;
inline float PackRGB(uint8_t r, uint8_t g, uint8_t b) {
uint32_t color_uint = ((uint32_t)r << 16 | (uint32_t) g << 8 | (uint32_t)b);
return *reinterpret_cast<float *> (&color_uint);
}
void RunThread(){
while(ros::ok()){
ros::spinOnce();
}
}
void imageReceive(const sensor_msgs::ImageConstPtr& msg){
mutexMutex.lock();
acquiredImage = cv::Mat(cv_bridge::toCvShare(msg, "bgr8")->image);
mutexMutex.unlock();
has_data1 = true;
}
void cloudReceive(const sensor_msgs::PointCloud2ConstPtr& cloudInMsg){
//mutexMutex.lock();
pcl::fromROSMsg(*cloudInMsg, *acquiredCloud);
has_data2 = true;
//mutexMutex.unlock();
}
void StartThread(){
stopThread = false;
has_data1 = has_data2 = false;
thread_RunThread = std::thread(RunThread);
while(!has_data1 && !has_data2){
std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::cout << has_data1 << "-" << has_data2 << std::endl;
}
}
void CloseThread(){
stopThread = true;
thread_RunThread.join();
}
int main(int argc, char **argv){
ros::init(argc, argv, "Viewtest");
ros::NodeHandle nh;
image_transport::ImageTransport it(nh);
cv::startWindowThread();
image_transport::Subscriber sub = it.subscribe("/rsCamera/image", 1, imageReceive);
ros::Subscriber pclsubAcquirer = nh.subscribe("/rsCamera/cloud", 1, cloudReceive);
StartThread();
while (ros::ok()){
if(!has_data1 && !has_data2){
std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::cout << has_data1 << "-" << has_data2 << std::endl;
}
else {
mutexMutex.lock();
cv::rotate(acquiredImage, acquiredImageRotated, cv::ROTATE_180);
mutexMutex.unlock();
copyPointCloud(*acquiredCloud, *acquiredCloud2);
int i = 640, j = 480, k;
for (auto& it : acquiredCloud2->points){
it.x = it.x; it.y = it.y; it.z = it.z;
it.rgb = PackRGB(
acquiredImageRotated.at<cv::Vec3b>(j,i)[2], // r
acquiredImageRotated.at<cv::Vec3b>(j,i)[1], // g
acquiredImageRotated.at<cv::Vec3b>(j,i)[0] // b
);
i--;
if(i <= 0) { i = 640; j--; }
if(j < 0) { break; }
}
}
}
CloseThread();
return 0;
}
Using QAudioOut Im trying to play data that is stored in a QByteArray in a sequence... this works when there is little data being appended, however when the data gets too much, lets say a 2~3 hour RAW PCM appending from different combinations this data to a QByteArray all at once will result in a std::bad_alloc due to the heap that's not big enough to hold all the data at the same time.
I know where the problem occurs and I think I have a possible solution, its just I have no idea on how to go about implementing it.
Below is a converted function that takes the values in the list
first one 440Hz for 1800000 msec and created RAW PCM square wave. Which works then appends it to a QByteArray then plays it.
This will work if there isn't a lot of appended data form multiple added sequences.
Im looking for a way to do one at a time from the list then create the wave, play that one for x milliseconds then move on to the next entry in the MySeq list. The list can contain large sequences of 3 minute frequencies that runs for hours.
QStringList MySeq;
MySeq << "1:440:180000";
MySeq << "1:20:180000";
MySeq << "1:2120:180000";
MySeq << "1:240:180000";
MySeq << "1:570:180000";
foreach(QString seq, MySeq)
{
QStringList Assits = seq.split(":");
qDebug() << "Now At: " << seq;
QString A = Assits.at(0);
QString B = Assits.at(1);
QString C = Assits.at(2);
qreal amplitude = A.toInt();
float frequency = B.toFloat();
int msecs = C.toInt();
qreal singleWaveTime = amplitude / frequency;
qreal samplesPerWave = qCeil(format->sampleRate() * singleWaveTime);
quint32 waveCount = qCeil(msecs / (singleWaveTime * 1000.0));
quint32 sampleSize = static_cast<quint32>(format->sampleSize() / 8.0);
QByteArray data(waveCount * samplesPerWave * sampleSize * format->channelCount(), '\0');
unsigned char* dataPointer = reinterpret_cast<unsigned char*>(data.data());
for (quint32 currentWave = 0; currentWave < waveCount; currentWave++)
{
for (int currentSample = 0; currentSample < samplesPerWave; currentSample++)
{
double nextRadStep = (currentSample / static_cast<double>(samplesPerWave)) * (2 * M_PI);
quint16 sampleValue = static_cast<quint16>((qSin(nextRadStep) > 0 ? 1 : -1) * 32767);
for (int channel = 0; channel < format->channelCount(); channel++)
{
qToLittleEndian(sampleValue, dataPointer);
dataPointer += sampleSize;
}
}
}
soundBuffer->append(data); // HERE IS THE Std::Bad_Alloc
output->start(outputBuffer);
qDebug() << data.size()
}
I wish to fill the QByteArray with only one sequence at a time then Play it with QAudioOutput then clear the ByteArray then load the next sequence repeat until all sequences are done in the QStringList.
The problem with this approach now is that QAudioOutput is asynchronous and doesn't wait for the first sequence to finish
If I loop over the list as demonstrated above they load one after the other with only the last frequency actually playing. its like the loop keep overwriting the previous sequence.
Im not sure if QEventLoop (Something I haven't used yet) is needed here or Threading. I have tried a couple of different approaches with no success. Any advice would be greatly appreciated. This is a continuation of the following question I had about wave files and data and frequency generations located here
Qt C++ Creating a square audio tone wave. Play and saving it
mainWindows.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtCore>
#include <QtMultimedia/QAudioOutput>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void playbackFinished();
private slots:
void appendSound();
void on_pushButton_Run_clicked();
void on_pushButton_Stop_clicked();
private:
Ui::MainWindow *ui;
QByteArray *soundBuffer;
QBuffer *outputBuffer;
QAudioFormat *format;
QAudioOutput *output;
};
#endif // MAINWINDOW_H
mainWindows.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
int sampleRate = 44100;
int channelCount = 2;
int sampleSize = 16;
const QString codec = "audio/pcm";
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
soundBuffer = new QByteArray();
format = new QAudioFormat();
format->setSampleRate(sampleRate);
format->setChannelCount(channelCount);
format->setSampleSize(sampleSize);
format->setCodec(codec);
format->setByteOrder(QAudioFormat::LittleEndian);
format->setSampleType(QAudioFormat::UnSignedInt);
output = new QAudioOutput(*format, this);
connect(output, SIGNAL(stateChanged(QAudio::State)), this, SLOT(playbackFinished()));
outputBuffer = new QBuffer(soundBuffer);
if (outputBuffer->open(QIODevice::ReadOnly) == false) {
qCritical() << "Invalid operation while opening QBuffer. audio/pcm";
return;
}
}
MainWindow::~MainWindow()
{
delete ui;
delete soundBuffer;
delete format;
delete output;
delete outputBuffer;
}
void MainWindow::playbackFinished()
{
if (output->state() == QAudio::IdleState)
{
qDebug() << "Playback finished";
}
}
void MainWindow::appendSound()
{
QStringList MySq;
MySq << "1:440:180000";
MySq << "1:20:180000";
MySq << "1:2120:180000";
MySq << "1:240:180000";
MySq << "1:570:180000";
MySq << "1:570:180000";
MySq << "1:570:180000";
MySq << "1:850:180000";
MySq << "1:1570:180000";
MySq << "1:200:180000";
MySq << "1:50:180000";
MySq << "1:85:180000";
MySq << "1:59:180000";
MySq << "1:20:180000";
foreach(QString seq, MySq)
{
QStringList Assits = seq.split(":");
qDebug() << "Now At: " << seq;
QString A = Assits.at(0);
QString B = Assits.at(1);
QString C = Assits.at(2);
qreal amplitude = A.toInt();
float frequency = B.toFloat();
int msecs = C.toInt();
msecs = (msecs < 50) ? 50 : msecs;
qreal singleWaveTime = amplitude / frequency;
qreal samplesPerWave = qCeil(format->sampleRate() * singleWaveTime);
quint32 waveCount = qCeil(msecs / (singleWaveTime * 1000.0));
quint32 sampleSize = static_cast<quint32>(format->sampleSize() / 8.0);
QByteArray data(waveCount * samplesPerWave * sampleSize * format->channelCount(), '\0');
unsigned char* dataPointer = reinterpret_cast<unsigned char*>(data.data());
for (quint32 currentWave = 0; currentWave < waveCount; currentWave++)
{
for (int currentSample = 0; currentSample < samplesPerWave; currentSample++)
{
double nextRadStep = (currentSample / static_cast<double>(samplesPerWave)) * (2 * M_PI);
quint16 sampleValue = static_cast<quint16>((qSin(nextRadStep) > 0 ? 1 : -1) * 32767);
for (int channel = 0; channel < format->channelCount(); channel++)
{
qToLittleEndian(sampleValue, dataPointer);
dataPointer += sampleSize;
}
}
}
soundBuffer->append(data); // <-- STD::Bad_alloc Not enough memory on heap for appending all the frequencies at once in buffer
output->start(outputBuffer);
qDebug() << data.size();
}
}
void MainWindow::on_pushButton_Run_clicked()
{
appendSound();
}
void MainWindow::on_pushButton_Stop_clicked()
{
output->stop();
soundBuffer->clear();
output->reset();
qDebug() << "Playback Stopped";
}
I came up with a solution using QThread and a Interpreter for that thread to wait for more events before continuing the next sequence in the series.
By doing this I don't need to load the full 3~4 hour PCM data into a QBufferArray all at the same time but rather break it up. Run a smaller sequence then wait on the thread to finish then load the next sequence in line and so on until all of them are done playing.
No more std::bad_alloc since the thread only uses around 80mb on the heap at any given time.
I am using FLTK with C++ to write a program to scroll through a folder of images. I have a next button with the thumbnail for the next image, and the same for the previous button. I want to be able to go through the images by clicking the previous and next buttons as well as using the left and right arrows on the keyboard.
I succeeded in doing this, however not at the same time. When I only write a callback function like so:
void buttonCallback(Fl_Widget* widget, void* viewerPtr) {
Viewer* viewer = static_cast<Viewer*>(viewerPtr);
viewer->navPressed(widget);
viewer->redraw();
}
I can click the respective buttons to go forward and backwards, however when I overload the handle function to handle the keyboard arrows like so:
int Viewer::handle(int e) {
switch(e) {
case FL_FOCUS:
case FL_UNFOCUS:
return 1;
case FL_KEYBOARD:
if ( Fl::event_key() == FL_Left) {
prev->do_callback();
return(1);
} else if (Fl::event_key() == FL_Right) {
next->do_callback();
return(1);
}
return 1;
case FL_RELEASE:
do_callback();
return 1;
}
return Fl_Widget::handle(e);
}
I can use the arrows, however I cannot figure out how to use both arrows and clicking on the buttons. I have tried passing the Fl_Widget *w through to the handle function and back up to the callback, and I was able to click on the buttons, but could no longer use the arrows.
Here is the Viewer.cpp file:
#include <iostream>
#include "Viewer.h"
using namespace std;
void buttonCallback(Fl_Widget* widget, void* viewerPtr) {
//cout << "Callback called" << endl;
Viewer* viewer = static_cast<Viewer*>(viewerPtr);
viewer->navPressed(widget);
viewer->redraw();
}
Viewer::Viewer(string imageFolder, vector<string> imageFilenames, int width = 800, int height = 600) :
Fl_Window(width, height, "Image Viewer"), imageFolder(imageFolder), imageFilenames(imageFilenames), currentIndex(0), nextIndex(1), prevIndex(imageFilenames.size()-1),
prev(nullptr), next(nullptr), imageBox(nullptr), pic(nullptr) {
prev = new NavButton(getPathFilename(imageFilenames.at(prevIndex), true), "Previous Button", borderSize, this->h() - borderSize - thumbnailSize - borderSize, thumbnailSize, imageFilenames.size() - 1);
next = new NavButton(getPathFilename(imageFilenames.at(nextIndex), true), "Next Button",
this->w() - borderSize - thumbnailSize - borderSize, this->h() - borderSize - thumbnailSize - borderSize, thumbnailSize, imageFilenames.size()-1);
imageBox = new Fl_Box(borderSize, borderSize, this->w() - (2*borderSize), this->h() - (2*borderSize) - thumbnailSize - 2*borderSize);
//imageBox->box(FL_BORDER_BOX); // useful to see where the full size of the widget holding the images
pic = new Fl_JPEG_Image(getPathFilename(imageFilenames.at(currentIndex)).c_str());
imageBox->image(pic);
this->end();
prev->callback(buttonCallback, static_cast<void*>(this));
next->callback(buttonCallback, static_cast<void*>(this));
}
string Viewer::getPathFilename(string filename, bool thumb) {
string thumbPart = "";
if (thumb) thumbPart = "t_";
return imageFolder + "/" + thumbPart+ filename;
}
void Viewer::navPressed(Fl_Widget *widget) {
NavButton* b = dynamic_cast<NavButton*>(widget);
// adds to the click counts to keep track of them
b->addClickCount(); b->addTotalClicks();
cout << b->getLabel() << " has been pressed " << b->getClickCount() << " times." << endl;
cout << "All buttons have been pressed " << b->getTotClicks() << " times." << endl;
// determines which button is pressed
if (b->getLabel() == "Next Button") {
changeAllInds(true);
// check to see if at end of list
if ((nextIndex) > imageFilenames.size()-1) {
nextIndex = 0;
} else if (currentIndex > imageFilenames.size()-1) {
currentIndex = 0;
} else if (prevIndex > imageFilenames.size()-1) {
prevIndex = 0;
}
// changes main image
pic = new Fl_JPEG_Image(getPathFilename(imageFilenames.at(currentIndex)).c_str());
imageBox->image(pic);
// changes thumbnails
prev->setImage(getPathFilename(imageFilenames.at(prevIndex), true).c_str());
next->setImage(getPathFilename(imageFilenames.at(nextIndex), true).c_str());
} else {
changeAllInds(false);
// check to see if at end of list
if ((nextIndex) < 0) {
nextIndex = imageFilenames.size()-1;
} else if (currentIndex < 0) {
currentIndex = imageFilenames.size()-1;
} else if (prevIndex < 0) {
prevIndex = imageFilenames.size()-1;
}
// changes main image
pic = new Fl_JPEG_Image(getPathFilename(imageFilenames.at(currentIndex)).c_str());
imageBox->image(pic);
// changes thumbnails
prev->setImage(getPathFilename(imageFilenames.at(prevIndex), true).c_str());
next->setImage(getPathFilename(imageFilenames.at(nextIndex), true).c_str());
}
//cout << currentIndex << endl;
cout << endl;
}
void Viewer::changeAllInds(bool increase) {
if (increase) {
currentIndex++; nextIndex++; prevIndex++;
} else {
currentIndex--; nextIndex--; prevIndex--;
}
}
int Viewer::handle(int e) {
switch(e) {
case FL_FOCUS:
case FL_UNFOCUS:
return 1;
case FL_KEYBOARD:
if ( Fl::event_key() == FL_Left) {
prev->do_callback();
return(1);
} else if (Fl::event_key() == FL_Right) {
next->do_callback();
return(1);
}
return 1;
case FL_RELEASE:
do_callback();
return 1;
}
return Fl_Widget::handle(e);
}
And here is Viewer.h:
#ifndef VIEWER_H
#define VIEWER_H
#include <vector>
#include <string>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>
#include "NavButton.h"
class Viewer : public Fl_Window {
std::vector<std::string> imageFilenames;
Fl_Box *imageBox; // Holds image being shown
Fl_JPEG_Image *pic; // Image being shown
NavButton* prev; // Button to go to previous item
// Image is thumbnail of previous image
NavButton* next; // Button to go to next item
// Image is thumbnail of next image
int currentIndex; // Index of the image currently shown
int nextIndex; // Index of next image
int prevIndex; // Index of previous image
// private helper functions
std::string imageFolder;
std::string getPathFilename(std::string filename, bool thumb=false);
public:
static const int thumbnailSize = 50; // size of NavButton
static const int borderSize = 10; // size of border between window edge and widgets
void navPressed(Fl_Widget* widget);
// constructor
Viewer(std::string, std::vector<std::string>, int, int);
virtual int handle(int e);
//int key_handle(int e, int key);
//int mouse_handle(int e);
void changeAllInds(bool increase);
};
#endif
Please let me know if you need any more info to assist me, and thank you in advance!
This may achieve what you want. Add a third routine to do the navigation
int Navigate(int key)
{
if ( key == FL_Left) {
prev->do_callback();
return(1);
} else if (key == FL_Right) {
next->do_callback();
return(1);
}
return 1;
}
Then change the other two to call it. In your handler
int Viewer::handle(int e) {
switch(e) {
...
case FL_KEYBOARD:
return Navigate(Fl::event_key());
case FL_RELEASE:
...
}
...
In navpressed,
...
if (b->getLabel() == "Next Button") {
...
Navigate(FL_Right);
}
else {
...
Navigate(FL_Left);
}
I am trying to record audio from the default microphone present in my desktop and store it in QFile.
Finally I want to play the recorded file using windows media player. The issue is that QAudioInput has a method bytesReady() which always returns 0 in my case. Even if the audio state is QAudio::ActiveState the bytesReady() shows 0 bytes implying that there are no audio bytes to read from the microphone. The system microphone works just fine. My code gets perfectly compiled, I also get a file in the specifed location with 80KB size, but the file doesn't play with windows media player even if saved as a .wav, it returns an error.
The output window shows bytesReady as 0 in my case everytime. I suspect the QAudioInput is not able to read audio data from microphone.
Could you please help me find mistakes in my code?
`class mikeDemoClass : public QWidget
{
Q_OBJECT
public:
mikeDemoClass(QWidget *parent = 0, Qt::WFlags flags = 0);
~mikeDemoClass();
public slots:
void startRecording();
void browseFiles();
void stopRecording();
void handleAudioInputState(QAudio::State);
void notified();
private:
Ui::mikeDemoWidget ui;
QAudioInput *audioInput;
QFile *recordFile;
QTimer *testTimer;
int audio_state;
};
// cpp file starts here
#include <QIODevice>
#include "mic_demo.h"
mikeDemoClass::mikeDemoClass(QWidget *parent, Qt::WFlags flags)
: QWidget(parent, flags)
{
ui.setupUi(this);
audioInput = NULL;
recordFile = NULL;
audio_state = -1;
connect(ui.browseButton,SIGNAL(clicked()),this,SLOT(browseFiles()));
connect(ui.recordingButton,SIGNAL(clicked()), this,SLOT(startRecording()));
}
mikeDemoClass::~mikeDemoClass()
{
if(recordFile)
{
delete recordFile;
recordFile = NULL;
}
}
void mikeDemoClass::browseFiles()
{
QString FileName = QFileDialog::getSaveFileName(this, tr("Browse Files"), "D:/", tr("Media Files (*.raw)"));
if(!FileName.isEmpty())
{
recordFile = new QFile(FileName);
QTextDocument *textDoc = new QTextDocument(FileName);
ui.textEdit->setDocument(textDoc);
}
}
void mikeDemoClass::startRecording()
{
bool status = recordFile->open(QIODevice::WriteOnly);
if(!status)
{
qDebug() <<"Error opening the file";
}
QString default_deviceName = "";
QAudioFormat preferred_format;
QList<QAudioDeviceInfo> device_list = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
int count = device_list.count();
if(device_list.empty())
{
qDebug() <<"The Audio Input Devices is empty";
}
else
{
foreach(QAudioDeviceInfo device_info, device_list)
{
QString device_name = device_info.deviceName();
qDebug() << "device_name:" << device_name.toLatin1();
}
QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
default_deviceName = info.deviceName();
if(!default_deviceName.isEmpty())
{
preferred_format = info.preferredFormat();
QString codec = preferred_format.codec();
int sampleRate = preferred_format.sampleRate();
int sampleSize = preferred_format.sampleSize();
int channelCount = preferred_format.channelCount();
int sampleType = preferred_format.sampleType();
int byteOrder = preferred_format.byteOrder();
qDebug() << "codec:" << codec.toLatin1() << "sampleRate :" << sampleRate << "sampleSize:" << sampleSize << "channel Count:" << channelCount << "sample type:" <<sampleType
<< "byteOrder:" << byteOrder;
}
}
QAudioFormat format;
format.setSampleRate(8000);
format.setChannels(1);
format.setSampleSize(8);
format.setCodec("audio/PCM");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::UnSignedInt);
QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
if(!info.isFormatSupported(format))
{
qDebug() <<"Default format not supported, try to use nearest format";
format = info.nearestFormat(format);
}
audioInput = new QAudioInput(info, format, this);
connect(audioInput, SIGNAL(notify()), this, SLOT(notified()));
connect(audioInput,SIGNAL(stateChanged(QAudio::State)),this, SLOT(handleAudioInputState(QAudio::State)));
QTimer::singleShot(10000, this, SLOT(stopRecording()));
//audioInput->setBufferSize(4096);
qDebug() << "platform buffer size:" << audioInput->bufferSize();
audioInput->start(recordFile);
}
void mikeDemoClass::stopRecording()
{
testTimer->stop();
audioInput->stop();
recordFile->close();
delete audioInput;
}
void mikeDemoClass::handleAudioInputState(QAudio::State state)
{
qDebug() << "Audio State:" << state;
audio_state = state;
if(state == QAudio::StoppedState)
{
qDebug() << "Error State:" << audioInput->error();
if(audioInput->error() != QAudio::NoError)
{
qDebug() << "QAudioInput error:" << audioInput->error();
}
}
}
void mikeDemoClass::notified()
{
if(audio_state == QAudio::ActiveState)
{
qDebug() << "Error State:" << audioInput->error();
qDebug() << "platform buffer size after calling QAudioInput start():" << audioInput->bufferSize();
qDebug() << "bytesReady = " << audioInput->bytesReady()
<< ", " << "elapsedUSecs = " <<audioInput->elapsedUSecs()
<< ", " << "processedUSecs = "<<audioInput->processedUSecs();
}
}`
The output displays as follows:
device_name: "Microphone (High Definition Aud"
device_name: "default"
codec: "audio/pcm" sampleRate : 11025 sampleSize: 8 channel Count: 1 sample type: 1 byteOrder: 1
Default format not supported, try to use nearest format
platform buffer size: 0
Audio State: 0
Error State: 0
platform buffer size after called QAudioInput start(): 1600
bytesReady = 0 , elapsedUSecs = 1003000 , processedUSecs = 1000000
Error State: 0
platform buffer size after called QAudioInput start(): 1600
bytesReady = 0 , elapsedUSecs = 1998000 , processedUSecs = 2000000
Error State: 0
platform buffer size after called QAudioInput start(): 1600
bytesReady = 0 , elapsedUSecs = 3003000 , processedUSecs = 3000000
Error State: 0
platform buffer size after called QAudioInput start(): 1600
bytesReady = 0 , elapsedUSecs = 4000000 , processedUSecs = 4000000
Error State: 0
platform buffer size after called QAudioInput start(): 1600
bytesReady = 0 , elapsedUSecs = 5006000 , processedUSecs = 5000000
Error State: 0
platform buffer size after called QAudioInput start(): 1600
bytesReady = 0 , elapsedUSecs = 6001000 , processedUSecs = 6000000
Error State: 0
platform buffer size after called QAudioInput start(): 1600
bytesReady = 0 , elapsedUSecs = 7005000 , processedUSecs = 7000000
Error State: 0
platform buffer size after called QAudioInput start(): 1600
bytesReady = 0 , elapsedUSecs = 8002000 , processedUSecs = 8000000
Error State: 0
platform buffer size after called QAudioInput start(): 1600
bytesReady = 0 , elapsedUSecs = 8997000 , processedUSecs = 9000000
Audio State: 2
Error State: 0
Having compared your code to the example in the Qt documentation, you're using the notified signal to handle the QAudio::ActiveState, whereas the example code connects a slot to the stateChanged signal: -
void AudioInputExample::handleStateChanged(QAudio::State newState)
{
switch (newState) {
case QAudio::StoppedState:
if (audio->error() != QAudio::NoError) {
// Error handling
} else {
// Finished recording
}
break;
case QAudio::ActiveState:
// Started recording - read from IO device
break;
default:
// ... other cases as appropriate
break;
}
}
As notify() states: -
This signal is emitted when x ms of audio data has been processed the interval set by setNotifyInterval
Could the interval be zero?
However, I recommend following the example code as shown in the documentation and use the stateChanged signal, rather than notify.
Consider PHDEBUG or PHDBG as qDebug() and see the following (I think your missing point is the QIODevice which stand as a buffer.):
Reader.cpp :
#include "PhLtcReader.h"
PhLtcReader::PhLtcReader(QObject *parent) :
QObject(parent),
_input(NULL),
_position(0),
_buffer(NULL)
{
_decoder = ltc_decoder_create(1920, 3840);
PHDEBUG << "LTC Reader created";
}
bool PhLtcReader::init(QString input)
{
QList<QAudioDeviceInfo> list = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
if(list.isEmpty())
{
PHDEBUG << "No audio input device";
return false;
}
QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
foreach(QAudioDeviceInfo device, list)
{
if(device.deviceName() == input)
info = device;
}
PHDEBUG << "LTC input device :" << info.deviceName();
QAudioFormat format;
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleRate(48000);
format.setChannelCount(1);
format.setSampleSize(8);
format.setSampleType(QAudioFormat::SignedInt);
if(!info.isFormatSupported(format))
{
PHDEBUG << "Unsupported audio format";
return false;
}
_position = 0;
_input = new QAudioInput(info, format);
connect(_input, SIGNAL(notify()), this, SLOT(onNotify()));
_buffer = _input->start();
_input->setNotifyInterval(10);
_pauseDetector.start();
return true;
}
void PhLtcReader::close()
{
if(_input)
{
_input->stop();
delete _buffer;
_buffer = NULL;
delete _input;
_input = NULL;
}
}
QList<QString> PhLtcReader::inputList()
{
QList<QString> names;
QList<QAudioDeviceInfo> list = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
foreach(QAudioDeviceInfo device, list)
names.append(device.deviceName());
return names;
}
void PhLtcReader::onNotify()
{
QByteArray array = _buffer->readAll();
char max = 0;
for(int i = 0; i < array.count(); i++)
{
if(array.at(i) > max)
max = array.at(i);
}
ltc_decoder_write(_decoder, (ltcsnd_sample_t*)array.data(), array.count(), _position);
LTCFrameExt frame;
unsigned int *hhmmssff = new unsigned int[4];
while(ltc_decoder_read(_decoder, &frame))
{
PhFrame oldFrame = _clock.frame();
hhmmssff[0] = frame.ltc.hours_tens * 10 + frame.ltc.hours_units;
hhmmssff[1] = frame.ltc.mins_tens * 10 + frame.ltc.mins_units;
hhmmssff[2] = frame.ltc.secs_tens * 10 + frame.ltc.secs_units;
hhmmssff[3] = frame.ltc.frame_tens * 10 + frame.ltc.frame_units;
}
delete hhmmssff;
_position += array.count();
}
Reader.h
class PhLtcReader : public QObject
{
Q_OBJECT
public:
explicit PhLtcReader(QObject *parent = 0);
bool init(QString _input="");
void close();
static QList<QString> inputList();
private slots:
void onNotify();
private:
QAudioInput *_input;
qint64 _position;
QIODevice * _buffer;
};
#endif // PHLTCREADER_H
The answer to your question can be found in the output.
There is a line that says
Default format not supported, try to use nearest format
Which is the problem. The format you're using isn't supported by your platform. Try a different one or install the codecs/drivers to support that format.
I am starting with SDL, and I was reading the introduction, and I am trying the drawPixel method they have. What I am doing is a ppm viewer, so far I have the rgb values in an array and are correctly stored (i checked them by printing the array and making sure they correspond to their position in the ppm file) and I want to use SDL to draw the picture. So far the code I've written is (this is the main.cpp file, if ppm.hpp and ppm.cpp are needed please tell me so to add them)
#include <iostream>
#include <SDL/SDL.h>
#include "ppm.hpp"
using namespace std;
void drawPixel (SDL_Surface*, Uint8, Uint8, Uint8, int, int);
int main (int argc, char** argv) {
PPM ppm ("res/cake.ppm");
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO) < 0) {
cerr << "Unable to init SDL: " << SDL_GetError() << endl;
exit(1);
}
atexit(SDL_Quit); // to automatically call SDL_Quit() when the program terminates
SDL_Surface* screen;
screen = SDL_SetVideoMode(ppm.width(), ppm.height(), 32, SDL_SWSURFACE);
if (screen == nullptr) {
cerr << "Unable to set " << ppm.width() << "x" << ppm.height() << " video: " << SDL_GetError() << endl;
exit(1);
}
for (int i = 0; i < ppm.width(); i++) {
for(int j = 0; j < ppm.height(); j++) {
drawPixel(screen, ppm.red(i,j), ppm.green(i,j), ppm.blue(i,j), i, j);
}
}
return 0;
}
void drawPixel (SDL_Surface* screen, Uint8 R, Uint8 G, Uint8 B, int x, int y) {
Uint32 color = SDL_MapRGB(screen->format, R, G, B);
if (SDL_MUSTLOCK(screen)) {
if (SDL_LockSurface(screen) < 0) {
return;
}
}
switch (screen->format->BytesPerPixel) {
case 1: { // Assuming 8-bpp
Uint8* bufp;
bufp = (Uint8*)screen->pixels + y * screen->pitch + x;
*bufp = color;
}
break;
case 2: { // Probably 15-bpp or 16-bpp
Uint16 *bufp;
bufp = (Uint16*)screen->pixels + y * screen->pitch / 2 + x;
*bufp = color;
}
break;
case 3: { // Slow 24-bpp mode, usually not used
Uint8* bufp;
bufp = (Uint8*)screen->pixels + y * screen->pitch + x;
*(bufp + screen->format->Rshift / 8) = R;
*(bufp + screen->format->Gshift / 8) = G;
*(bufp + screen->format->Bshift / 8) = B;
}
break;
case 4: { // Probably 32-bpp
Uint32* bufp;
bufp = (Uint32*)screen->pixels + y * screen->pitch / 4 + x;
*bufp = color;
}
break;
}
if (SDL_MUSTLOCK(screen)) {
SDL_UnlockSurface(screen);
}
SDL_UpdateRect(screen, x, y, 1, 1);
}
The drawPixel is as is provided by the introduction, now the ppm file I am trying to use is called cake.ppm and its 720x540, however when I build and run this code, I get the application is not responding. I tried it on a smaller ppm file which is 426x299 and it showed a window with colors being put on the window.
Why is it not working on the cake.ppm file and on others it works? Is it due to size?
When I try the ppm file, the second one 426x299 or other ppm files, the colors come totally different, why is that?
When I run the app, after the pixels are put, the window closes, how can I keep it?
Attempting at a file squares.ppm, here is what it should be:
But this is what I'm getting