QDatastream太慢了?

时间:2016-01-20 13:43:29

标签: c++ image ipc qdatastream qsharedmemory

我正在尝试使用QSharedmemory在两个进程之间传递多个图像(实际上是一个视频)。目前我正在序列化QImages的QVector并将其复制到内存中。这有效,但序列化步骤大约占99%的时间。我怎样才能以独立于平台的方式更快地完成这项工作?

我的发送代码:

int main(int argc, const char* argv[])
{
QObject *parent;

QString program = "python";
QStringList arguments;
QString programPath(PYSOURCE);
arguments << "-u" << programPath+QString("/test.py");
qDebug() << arguments;

QProcess *pyProcess = new QProcess();
pyProcess->start(program, arguments);

QVector<QImage> images;
//.. fill with some images

auto start = std::chrono::system_clock::now();
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
QDataStream out(&buffer);

// this takes extremely long ~44s for 80mb
out << images;

int size = buffer.size();

QSharedMemory sharedMemory("process_example");
if (!sharedMemory.create(size)) {
    qDebug() << "Unable to create shared memory segment.";
    return 0;
}

qDebug() << "sizeof mem: " << sharedMemory.size() << "bufsize:" << buffer.size();
sharedMemory.lock();


char *to = (char*)sharedMemory.data();
const char *from = buffer.data().data();
memcpy(to, from, qMin(sharedMemory.size(), size));

sharedMemory.unlock();  

qDebug() << "image copied to shared memory";
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start);
qDebug() << "duration:" << duration.count() << "ms";

while (pyProcess->waitForReadyRead(-1)){
QByteArray newData = pyProcess->readAllStandardOutput();
QString result = QString::fromLocal8Bit(newData);
qDebug(qPrintable(QString("py:")+result));

}
sharedMemory.detach();

return 0;
}

3 个答案:

答案 0 :(得分:1)

几天前我遇到了同样的问题。我在网上找不到答案,所以我试着自己写代码。该方法是直接将图像的原始数据复制到共享内存中或从共享内存中复制。这个方法非常非常快。

图片发送功能:

//The image-file names are stored in a QStringList object
void SendImage(QStringList fileList)
{
    if (sharedMemory.isAttached())
        sharedMemory.detach();
    int count = fileList.count();
    int totalSize = 0;
    QList<QImage> images;
    
    //Load the images
    for (int i = 0; i < count; i++)
    {
        QImage image(fileList.at(i));
        images.append(image);
        totalSize += image.sizeInBytes();
    }
    //Total size needed for shared memory
    totalSize += (count * 5 + 1) * sizeof(int);
    if (!sharedMemory.create(totalSize)) {
        throw QString( "Shared memory cannot be allocated!");
        return;
    }
    sharedMemory.lock();
    
    //to points to the target space to write
    uchar *to = (uchar *)sharedMemory.data();
    //from points to the source to write
    uchar *from = (uchar *)&count;
    
    //Write the count of the images from the first byte of the shared memory
    memcpy(to, from, sizeof(int));
    //Move the pointer forward
    to += sizeof(int);
    
    //Write the images one by one
    for (int i = 0; i < count; i++) {
        //Write the total size of the image and move the pointer forward
        int sizeInBytes = images.at(i).sizeInBytes();
        from = (uchar *)&sizeInBytes;
        memcpy(to, from ,sizeof(int));
        to += sizeof(int);
        
        //Write the width of the image and move the pointer forward
        int width = images.at(i).width();
        from = (uchar *)&width;
        memcpy(to, from ,sizeof(int));
        to += sizeof(int);
        
        //Write the height of the image and move the pointer forward
        int height = images.at(i).height();
        from = (uchar *)&height;
        memcpy(to, from ,sizeof(int));
        to += sizeof(int);
        
        //Write the image format of the image and move the pointer forward
        int imageFormat =  (int)images.at(i).format() ;
        from = (uchar *)&imageFormat;
        memcpy(to, from ,sizeof(int));
        to += sizeof(int);
        
        //Write the bytes per line of the image and move the pointer forward
        int bytesPerLine = images.at(i).bytesPerLine();
        from = (uchar *)&bytesPerLine;
        memcpy(to, from ,sizeof(int));
        to += sizeof(int);
        
        //Write the raw data of the image and move the pointer forward
        from = (uchar *)images.at(i).bits();
        memcpy(to, from, sizeInBytes);
        to += sizeInBytes;
    }
    sharedMemory.unlock();
}

我接收图像的代码:

QList<QImage> * FetchImages()
{
    QList<QImage> * imageList = new QList<QImage>;
    
    if (!sharedMemory.attach())
    {
        throw QString("The shared memory cannot be attached!");
        return imageList;
    }
    
    sharedMemory.lock();
    //from points to the first byte of the shared memory
    uchar * from = (uchar *)sharedMemory.data();
    //Get the count of the images and move the pointer forward
    int count;
    count = *(int *)from;
    from += sizeof(int);
    //Get the images one by one
    for (int i = 0; i < count; i++)
    {
        //Get the size of the image and move the pointer forward
        int sizeInBytes = *(int *)from;
        from += sizeof(int);
        
        //Get the width of the image and move the pointer forward
        int width = *(int *)from;
        from += sizeof(int);
        
        //Get the height of the image and move the pointer forward
        int height  = *(int *)from;
        from += sizeof(int);
        
        //Get the image format of the image and move the pointer forward
        int imageFormat = *(int *)from;
        from += sizeof(int);
        
        ////Get the bytes per line of the image and move the pointer forward
        int bytesPerLine = *(int *)from;
        from += sizeof(int);

        //Generate an image using the raw data and move the pointer forward
        QImage image(from, width, height, bytesPerLine, (QImage::Format)imageFormat);
        from += sizeInBytes;
        
        //It is very important here and I spent much time.
        //A new image object "image1" must be deeply copied from "image" before appended to the imageList.
        //Because the raw data of "image" use the space of the shared memory, which will not be accessed after the shared memory is detached.
        //The raw data of the newly constructed "image1" use the memory of its own process.
        QImage image1 = image.copy(0, 0, width, height);
        imageList -> append(image1);
    }
    sharedMemory.unlock();
    sharedMemory.detach();

    return imageList;
}

答案 1 :(得分:0)

我认为缓冲区的主要问题是它需要多次调整大小。尝试将基本字节数组的大尺寸设置为更大的尺寸,然后再需要数据。

buffer.buffer ().resize (100000000);

在图像序列化之前调用它。

答案 2 :(得分:0)

尝试使用QImage.save将其保存到QByteArray作为&#34; PNG&#34;,然后将其中的数据复制到带有memcpy的QSharedMemory

http://doc.qt.io/qt-4.8/qimage.html#save-2