When we create a text file with this text "ali ata bak", and we use this file as input for the program. The code is running normally. But when we enter "1111111111111111111111" this text in the textfile, Code isnt running expected. So What is the problem?
#include <QtCore/QCoreApplication>
#include <QBitArray>
#include <QByteRef>
#include <QFile>
#include <iostream>
#include <stdlib.h>
#include <QTextStream>
// Buffer Size #num of KB's
#define BUFFER_SIZE_KB 1
// Do not change !!
#define BUFFER_SIZE_BYTE BUFFER_SIZE_KB*1024
#define BUFFER_SIZE_BIT BUFFER_SIZE_BYTE*8
using namespace std;
QBitArray bytesToBits(QByteArray bytes) {
QBitArray bits(bytes.count()*8);
// Convert from QByteArray to QBitArray
for(int i=0; i<bytes.count(); ++i)
for(int b=0; b<8; ++b)
bits.setBit(i*8+b, bytes.at(i)&(1<<b));
return bits;
}
QByteArray bitsToBytes(QBitArray bits) {
QByteArray bytes;
bytes.resize(bits.count()/8);
// Convert from QBitArray to QByteArray
for(int b=0; b<bits.count(); ++b)
bytes[b/8] = ( bytes.at(b/8) | ((bits[b]?1:0)<<(b%8)));
return bytes;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString inFilename;
QString outFilename;
QTextStream qtin(stdin);
cout << "Filename : ";
qtin >> inFilename;
outFilename.append("_");
outFilename.append(inFilename);
QFile infile(inFilename);
if (!infile.open(QIODevice::ReadOnly)) {
cout << "\nFile cant opened\n";
system("pause");
return 1;
}
QFile outfile(outFilename);
if (!outfile.open(QIODevice::WriteOnly)) {
cout << "\nFile cant opened\n";
system("pause");
return 2;
}
QByteArray bytes, bytes2;
QBitArray bits;
while ((bytes = infile.read(BUFFER_SIZE_BYTE)) >0 ) {
bits = bytesToBits(bytes);
bytes2 = bitsToBytes(bits);// PROBLEM IS HERE
outfile.write(bytes2);
}
outfile.close();
infile.close();
cout << "Finished\n";
return a.exec();
}
Initialization problem.
QByteArray bitsToBytes(QBitArray bits) {
QByteArray bytes;
bytes.resize(bits.count()/8+1);
bytes.fill(0);
// Convert from QBitArray to QByteArray
for(int b=0; b<bits.count(); ++b)
bytes[b/8] = ( bytes.at(b/8) | ((bits[b]?1:0)<<(b%8)));
return bytes;
}
this produces the right answer
QByteArray bitsToBytes(const QBitArray& bits)
{
QByteArray bytes;
QDataStream stream(&bytes, QIODevice::WriteOnly);
stream << bits;
return bytes;
}
You might also want to read about endianness from the Wikipedia http://en.wikipedia.org/wiki/Endianness
QBitArray bits(8);
// The deep copy of bits
QByteArray bytes(bits.bits(), bits.count() / 8);
--------------------------------------------------------------------------
// The bits are not copied
QByteArray bytes = QByteArray::fromRawData(bits.bits(), bits.count() / 8);
Based on answers from iloahz, solve the problem of output file size grow up 1 byte.
QByteArray bitsToBytes(QBitArray bits) {
QByteArray bytes;
bytes.resize(bits.count() / 8 + ((bits.count() % 8)? 1: 0));
bytes.fill(0x00);
// Convert from QBitArray to QByteArray
for(int b = 0; b < bits.count(); ++b)
bytes[b / 8] = (bytes.at(b / 8) | ((bits[b]? 1: 0) << (b % 8)));
return bytes;
}
Related
I'm working on a voice chat and I need to compress my audio data. I record and play the audio data via the Qt Framework. If I record and play the audio data without compressing it everything is fine. If I compress,decompress and play the audio data I just hear a cracking sound.
Edit: I had a look at the demo code and I tried to use that code.
I can hear something but it is very laggy. If I increase the size of pcm_bytes to e.g 40000 it sounds better but my voice has still lags and cracking sounds.
This is the line (audioinput.cpp at the bottom):
speaker->write((const char*)pcm_bytes,3840);
codecopus.cpp:
#include "codecopus.h"
CodecOpus::CodecOpus()
{
}
void CodecOpus::initDecoder(opus_int32 samplingRate, int channels) //decoder
{
int error;
decoderState = opus_decoder_create(samplingRate,channels,&error);
if(error == OPUS_OK){
std::cout << "Created Opus Decoder struct" << std::endl;
}
}
void CodecOpus::initEncoder(opus_int32 samplingRate, int channels) // Encoder
{
int error;
encoderState = opus_encoder_create(samplingRate,channels,OPUS_APPLICATION_VOIP,&error);
error = opus_encoder_ctl(encoderState,OPUS_SET_BITRATE(64000));
if(error == OPUS_OK){
std::cout << "Created Opus Encoder struct" << std::endl;
}
}
opus_int32 CodecOpus::encodeData(const opus_int16 *pcm, int frameSize, unsigned char *data, opus_int32 maxDataBytes) //Encoder
{
opus_int32 i = opus_encode(encoderState,pcm,frameSize,data,maxDataBytes);
return i;
}
int CodecOpus::decodeData(const unsigned char *data, opus_int32 numberOfBytes,opus_int16* pcm,int frameSizeInSec) //Decoder
{
int i = opus_decode(decoderState,data,numberOfBytes,pcm,frameSizeInSec,0);
return i;
}
CodecOpus::~CodecOpus()
{
opus_decoder_destroy(this->decoderState);
opus_encoder_destroy(this->encoderState);
}
audioinput.h:
#ifndef AUDIOINPUT_H
#define AUDIOINPUT_H
#include <QAudioFormat>
#include <iostream>
#include <QAudioInput>
#include <QAudioOutput>
#include <thread>
#include "codecopus.h"
#include "QDebug"
class AudioInput : public QObject
{
Q_OBJECT
public:
AudioInput();
~AudioInput();
void startRecording();
void CreateNewAudioThread();
private:
CodecOpus opus;
unsigned char cbits[4000] = {};
opus_int16 in[960*2*sizeof(opus_int16)] = {};
opus_int16 out[5760*2] = {};
unsigned char *pcm_bytes;
int MAX_FRAME_SIZE;
QAudioFormat audioFormat;
QAudioInput *audioInput;
QIODevice *mic;
QByteArray data;
int micFrameSize;
QAudioOutput *audioOutput;
QIODevice *speaker;
QAudioFormat speakerAudioFormat;
public slots:
void OnAudioNotfiy();
};
#endif // AUDIOINPUT_H
audioinput.cpp:
#include "audioinput.h"
AudioInput::AudioInput() : audioFormat(),pcm_bytes(new unsigned char[40000])
{
audioFormat.setSampleRate(48000);
audioFormat.setChannelCount(2);
audioFormat.setSampleSize(16);
audioFormat.setSampleType(QAudioFormat::SignedInt);
audioFormat.setByteOrder(QAudioFormat::LittleEndian);
audioFormat.setCodec("audio/pcm");
speakerAudioFormat.setSampleRate(48000);
speakerAudioFormat.setChannelCount(2);
speakerAudioFormat.setSampleSize(16);
speakerAudioFormat.setSampleType(QAudioFormat::SignedInt);
speakerAudioFormat.setByteOrder(QAudioFormat::LittleEndian);
speakerAudioFormat.setCodec("audio/pcm");
QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
if(!info.isFormatSupported(audioFormat)){
std::cout << "Mic Format not supported!" << std::endl;
audioFormat = info.nearestFormat(audioFormat);
}
QAudioDeviceInfo speakerInfo = QAudioDeviceInfo::defaultOutputDevice();
if(!speakerInfo.isFormatSupported(speakerAudioFormat)){
std::cout << "Speaker Format is not supported!" << std::endl;
speakerAudioFormat = info.nearestFormat(speakerAudioFormat);
}
std::cout << speakerAudioFormat.sampleRate() << audioFormat.sampleRate() << speakerAudioFormat.channelCount() << audioFormat.channelCount() << std::endl;
audioInput = new QAudioInput(audioFormat);
audioOutput = new QAudioOutput(speakerAudioFormat);
audioInput->setNotifyInterval(20);
micFrameSize = (audioFormat.sampleRate()/1000)*20;
opus.initEncoder(audioFormat.sampleRate(),audioFormat.channelCount());
opus.initDecoder(speakerAudioFormat.sampleRate(),speakerAudioFormat.channelCount());
MAX_FRAME_SIZE = 6*960;
connect(audioInput,SIGNAL(notify()),this,SLOT(OnAudioNotfiy()));
}
AudioInput::~AudioInput()
{
}
void AudioInput::startRecording()
{
mic = audioInput->start();
speaker = audioOutput->start();
std::cout << "Recording started!" << std::endl;
}
void AudioInput::CreateNewAudioThread()
{
std::thread t1(&AudioInput::startRecording,this);
t1.detach();
}
void AudioInput::OnAudioNotfiy()
{
data = mic->readAll();
std::cout << "data size" <<data.size() << std::endl;
if(data.size() > 0){
pcm_bytes = reinterpret_cast<unsigned char*>(data.data());
//convert
for(int i=0;i<2*960;i++){ //TODO HARDCODED
in[i]=pcm_bytes[2*i+1]<<8|pcm_bytes[2*i];
}
opus_int32 compressedBytes = opus.encodeData(in,960,cbits,4000);
opus_int32 decompressedBytes = opus.decodeData(cbits,compressedBytes,out,MAX_FRAME_SIZE);
for(int i = 0; i<2*decompressedBytes;i++) //TODO HARDCODED
{
pcm_bytes[2*i]=out[i]&0xFF;
pcm_bytes[2*i+1]=(out[i]>>8)&0xFF;
}
speaker->write((const char*)pcm_bytes,3840);
}
}
1)You encode only 960 bytes, while the buffer is much larger. You must split the buffer into several equal parts and pass them to the encoder. The size of the part is 120, 240, 480, 960, 1920, and 2880.
2)Use qFromLittleEndian()/qToLittleEndian() functions or type casting when converting from char array to opus_int16 array/from opus_int16 array to char array. This will prevent cracking and poor sound quality.
Example:
void voice::slot_read_audio_input()
{
// Audio settings:
// Sample Rate=48000
// Sample Size=16
// Channel Count=1
// Byte Order=Little Endian
// Sample Type= UnSignedInt
// Encoder settings:
// Sample Rate=48000
// Channel Count=1
// OPUS_APPLICATION_VOIP
// Decoder settings:
// Sample Rate=48000
// Channel Count=1
QByteArray audio_buffer;//mic
QByteArray output_audio_buffer;//speaker
int const OPUS_INT_SIZE=2;//sizeof(opus_int16)
int const FRAME_SIZE=960;
int const MAX_FRAME_SIZE=1276;
int FRAME_COUNT=3840/FRAME_SIZE/OPUS_INT_SIZE;// 3840 is a sample size= voice_input->bytesReady;
opus_int16 input_frame[FRAME_SIZE] = {};
opus_int16 output_frame[FRAME_SIZE] = {};
unsigned char compressed_frame[MAX_FRAME_SIZE] = {};
unsigned char decompressed_frame[FRAME_SIZE*OPUS_INT_SIZE] = {};
audio_buffer.resize(voice_input->bytesReady());
output_audio_buffer.resize(FRAME_SIZE*OPUS_INT_SIZE);
input->read(audio_buffer.data(),audio_buffer.size());
for(int i=0;i<FRAME_COUNT;i++)
{
// convert from LittleEndian
for(int j=0;j<FRAME_SIZE;j++)
{
input_frame[j]=qFromLittleEndian<opus_int16>(audio_buffer.data()+j*OPUS_INT_SIZE);
// or use this:
// input_frame[j]=static_cast<short>(static_cast<unsigned char>(audio_buffer.at(OPUS_INT_SIZE*j+1))<<8|static_cast<unsigned char>(audio_buffer.at(OPUS_INT_SIZE*j)));
}
opus_int32 compressedBytes = opus_encode(enc, input_frame,FRAME_SIZE,compressed_frame,MAX_FRAME_SIZE);
opus_int32 decompressedBytes = opus_decode(dec,compressed_frame,compressedBytes,output_frame,FRAME_SIZE,0);
// conver to LittleEndian
for(int j = 0; j<decompressedBytes;j++)
{
qToLittleEndian(output_frame[j],output_audio_buffer.data()+j*OPUS_INT_SIZE);
// or use this:
// decompressed_frame[OPUS_INT_SIZE*j]=output_frame[j]&0xFF;
// decompressed_frame[OPUS_INT_SIZE*j+1]=(output_frame[j]>>8)&0xFF;
}
audio_buffer.remove(0,FRAME_SIZE*OPUS_INT_SIZE);
output->write(output_audio_buffer,FRAME_SIZE*OPUS_INT_SIZE);
// or use this:
// output->write(reinterpret_cast<char*>(decompressed_frame),FRAME_SIZE*OPUS_INT_SIZE);
}
}
I had a long answer ready about how you are misinterpreting the return value of opus.decodeData as the number of bytes, where the correct interpretation is "number of decoded samples per channel". But it still looks like you account for that in the byte conversion routine later on. So I'm not precisely sure where the bug is.
In general I think you are making the conversion from unsigned char <-> int16 more complicated than it needs to be. You should be able to just pass the audio buffer directly to / from opus and reinterpret its pointer to the needed type inline, without having to manually do bit manipulations to convert and copy between different buffers. The audio device should give you little-endian data but if there is a mismatch you can do a basic byte swapping routine
for (int c = 0; c < numSamples; c++)
{
unsigned char tmp = data[2 * c];
data[2 * c] = data[2 * c + 1];
data[2 * c + 1] = tmp;
}
I don't see it here but I assume you also have code to only consume exactly 960 samples at a time from the mic and keep the rest in the buffer for the next frame, otherwise you'll drop data.
Not that it matters much, but you can also replace 4000 in cbits with 1275, which is the maximum opus packet size.
I am trying to compress and decompress raw PCM (16-Bit) audio, using OPUS.
Here below is my code for opus_encoder.c. If I remove my decoder.c, the buffer works just fine as in the microphone is able to take in raw PCM data. However, once I have implemented my decoder class, it gave me a lot of errors such as memory allocation, heap corruption and so on. Here are some of my errors:
std::bad_alloc at memory location 0x0031D4BC
Stack overflow (parameters: 0x00000000, 0x05122000)
Access violation reading location 0x04A40000.
Based on my understanding, I think my decoder size cannot allocate the memory properly. Can you take a look at my codes and see what went wrong?
Opus_encoder.c
#include "opusencoder.h"
#include <QtConcurrent/QtConcurrent>
opusencoder::opusencoder(){
}
opusencoder::~opusencoder(){
}
OpusEncoder *enc;
int error;
unsigned char *compressedbuffer;
opus_uint32 enc_final_range;
short pcm = 0;
unsigned char *opusencoder::encodedata(const char *audiodata, const unsigned int& size) {
if (size == 0)
return false;
enc = (OpusEncoder *)malloc(opus_encoder_get_size(1));
enc = opus_encoder_create(8000, 1, OPUS_APPLICATION_VOIP, &error);
if (enc == NULL)
{
exit;
}
opus_int32 rate;
opus_encoder_ctl(enc, OPUS_GET_BANDWIDTH(&rate));
this->encoded_data_size = rate;
int len;
for (int i = 0; i < size / 2; i++)
{
//combine pairs of bytes in the original data into two-byte number
//convert const char to short
pcm= audiodata[2 * i] << 8 | audiodata[(2 * i) + 1];
}
qDebug() << "audiodata: " << pcm << endl;
compressedbuffer = new (unsigned char[this->encoded_data_size]);
len = opus_encode(enc, &pcm, 320, compressedbuffer, this->encoded_data_size);
len = opus_packet_unpad(compressedbuffer, len);
len++;
if (len < 0)
{
qDebug() << "Failure to compress";
return NULL;
}
qDebug() << "COmpressed buffer:" << compressedbuffer << endl;
qDebug() << "opus_encode() ................................ OK.\n" << endl;
}
Opus_decoder.c
##include "opusdecoder.h"
#include <QtConcurrent/QtConcurrent>
#define OPUS_CLEAR(dst, n) (memset((dst), 0, (n)*sizeof(*(dst))))
int num_channels = 1;
opusdecoder::opusdecoder(){
}
opusdecoder::~opusdecoder(){
}
opus_int16* opusdecoder::decodedata(int frame_size, const unsigned char *data)
{
dec = opus_decoder_create(8000, 1, &err);
if (dec == NULL)
{
exit;
}
opus_int32 rate;
opus_decoder_ctl(dec, OPUS_GET_BANDWIDTH(&rate));
rate = decoded_data_size;
this->num_channels = num_channels;
int decodedatanotwo;
opus_int16 *decompress = new (opus_int16[frame_size * this->num_channels]);
opus_packet_get_nb_channels(data);
decodedatanotwo= opus_decode(dec, data, this->decoded_data_size, decompress, 320, 0);
if (decodedatanotwo < 0)
{
qDebug() << "Failure to decompress";
return NULL;
}
qDebug() << "opus_decode() ................................ OK.\n" << decodedatanotwo << endl;
if (decodedatanotwo != frame_size)
{
exit;
}
}
I've been reading many suggestions on the same topic, and tried to implement many of them, but it seems that none of them is actually working in my environment.
I'm using QT 5, but I think the problem is not related to QT but to how the hexadecimal character 0x00 is interpreted by the language.
What I have to achieve is to display a stream of unsigned char as hexadecimal values, eg:
Input bytes: 0x00 0x4E 0x01 0x00 0x17 0x00
Display as: 0x00:0x4E:0x01:0x00:0x17:0x00
it seems quite easy, but all I get is an empty string...
The functions I wrote:
QString getBufferAsHexStr(const unsigned char* buf, int buffsize) {
std::string finalstring("");
char tempbuff[5];
int n=0, index=0;
for (int c = 0; c < buffsize; c++) {
if(c == buffsize-1) {
n=sprintf(tempbuff, "0x%02X", buf[c]);
} else {
n=sprintf(tempbuff, "0x%02X:", buf[c]);
}
finalstring.append(tempbuff, n);
index += n;
}
QString resultStr(finalstring.c_str());
return resultStr;
}
QString getBufferAsHexStr(const unsigned char* buf, int buffsize) {
std::stringstream ss;
for (int c = 0; c < buffsize; c++) {
if(c == buffsize-1) {
ss << std::hex << std::showbase << buf[c];
} else {
ss << std::hex << std::showbase << buf[c] << ":";
}
}
const std::string finalstring = ss.str();
QString resultStr(finalstring.c_str());
return resultStr;
}
I don't know why you started to use C++ functions with C++ types when you have a much better alternative which is QString. Using QString you might implement it as follows:
QString getBufferAsHexStr(const unsigned char* buf, int buffsize) {
QString result;
for(int i = 0; i < buffsize; ++i)
result += "0x" + QString("%1:").arg(buf[i], 2, 16, QChar('0')).toUpper();
result.chop(1);
return result;
}
Another version using a QByteArray and a joined QStringList:
QString getBufferAsHexStr(QByteArray buf) {
QStringList byteStrings;
for (int i = 0; i < buf.size(); ++i)
byteStrings += QString("0x") + QString("%1").arg(buf[i], 2, 16, QChar('0')).toUpper();
return byteStrings.join(":");
}
It would by called using
QString result = getBufferAsHexStr(QByteArray(charArr, charArrSize));
I'm trying to implement the function from listing 5.1 here
but when copying into a buffer with read from a file I just get the same character (Í) for the whole array, where string.txt is a copy and paste from the previous link content.
Here is my code:
#include <iostream>
#include <fstream>
#include <string>
#include <cinttypes>
#include <cstdio>
#include <cstring>
const int block_size = 0x4000; //16KB
int search(char* buffer, int searchLength, char* stringToSearch, int stringToSearchLength) {
char * potentialMatch;
while (searchLength) {
potentialMatch = reinterpret_cast<char *>(memchr(buffer, *stringToSearch, searchLength));
if (potentialMatch == NULL)
break;
if (stringToSearchLength == 1) {
return 1;
} else {
if (!memcmp(potentialMatch + 1, stringToSearch + 1, stringToSearchLength - 1))
return 1;
}
searchLength -= potentialMatch - buffer + 1;
buffer = potentialMatch + 1;
}
return 0;
}
int main(int argc, char* argv[]) {
char *toSearch = "Interpreting Where";
int done = 0;
int found = 0;
char *buffer;
int64_t fileSizeLeft = 0;
std::ifstream myFile("string.txt");
if (!myFile.fail()) {
buffer = new char[block_size];
myFile.seekg(0, std::ios::end); //Get file's size
fileSizeLeft = myFile.tellg();
} else {
std::cout << "Cannot open file" << std::endl;
return 1;
}
int toSearchLength = strlen(toSearch);
int stringLeft = toSearchLength - 1;
int first_time = 1;
while (!done && fileSizeLeft > toSearchLength) {
if (first_time) {
myFile.read(buffer, block_size);
found = search(buffer, block_size, toSearch, toSearchLength);
} else {
memcpy(buffer, buffer + stringLeft, stringLeft);
myFile.read(buffer+stringLeft, fileSizeLeft-stringLeft);
found = search(buffer, block_size, toSearch, toSearchLength);
}
fileSizeLeft = fileSizeLeft - block_size;
first_time = 0;
}
if (found) {
std::cout << "String found" << std::endl;
} else {
std::cout << "String not found" << std::endl;
}
myFile.close();
delete[] buffer;
return 0;
}
I hope you can help me see what I'm doing wrong, thanks!
You are setting myFile's position to ios_base::end with seekg:
myFile.seekg(0, ios::end);
Then trying to read from it:
myFile.read(buffer, block_size);
Clearly no data will be read since myFile is already at ios_base::end. And you'll be reading whatever uninitialized data that was already in buffer
What you probably intended to do was to set your myFile position back to the beginning by doing this before reading:
myFile.seekg(0, ios::beg);
I want to write a simple function to swap bytes in a QByteArray. This is what I have come up with:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString t = "abcde";
QByteArray test;
test.append(t.at(0));
test.append(t.at(1));
test.append(t.at(2));
test.append(t.at(3));
test.append(t.at(4));
qDebug() << t;
qDebug() << QString(swapBytes(test,0,3));
return a.exec();
}
QByteArray swapBytes(QByteArray in, int swapOffset, int quantity) {
if (swapOffset < 0) {
return in;
}
if(quantity>(in.length()/2)) {quantity=in.length()/2;}
if(quantity < 1) {quantity=1;}
int k;
char buf[quantity];
char buf2[quantity];
qDebug() << quantity;
for (int i = 0; i + quantity*2 + swapOffset <= in.length(); i=i+2*quantity) {
k=i;
for(int b = 0;b<i+quantity;b++){
buf[b]=in.at(k);
buf2[b]=in.at(k+swapOffset+quantity);
k++;
}
qDebug() << buf;
qDebug() << buf2;
qDebug() << in;
in.replace(0,quantity,buf2);
qDebug() << in;
in.replace(quantity+swapOffset,quantity,buf);
}
return in;
}
For some reason when I run this code I get the following output :
abcde
ab(
cd
abcde
cdcde
cdab(e
Where does the parentheses come from? As far as I know there is only one char per byte, so what is wrong?
You need to allocate one byte more than quantity to leave room for the null terminator. Try this:
char* buf = new char[quantity+1];
char* buf2 = new char[quantity+1];
memset(buf, 0, quantity+1);
memset(buf2, 0, quantity+2);
Then before your function returns, remember to deallocate:
delete [] buf;
delete [] buf2;
return in;
Alternately, you can just use a QByteArray in place of a char array:
QByteArray buf(quantity, 0x00);
QByteArray buf2(quantity, 0x00);
This allows you to skip calls to memset and to avoid worrying about deallocation.
Unrelated to all of this, note that you can initialize a QByteArray from a QString like this:
QByteArray test = t.toAscii();