Added new GetQImage method to get a Qt QImage object from an openshot:Frame object. Also refactored the video playback code to use this new method.

This commit is contained in:
Jonathan Thomas
2015-03-16 13:59:11 -05:00
parent d7a43f692c
commit 891766ed29
8 changed files with 79 additions and 75 deletions

View File

@@ -40,6 +40,7 @@
#include <iomanip>
#include <sstream>
#include <queue>
#include <QtGui/QImage>
#include <tr1/memory>
#include <unistd.h>
#include "Magick++.h"
@@ -50,10 +51,23 @@
#include "Fraction.h"
#include "Sleep.h"
using namespace std;
namespace openshot
{
/**
* @brief The pixel format supported by renderers.
*
* Currently only RGB_888 is supported.
*
* @see QuantumType
*/
enum OSPixelFormat {
RGB_888,
};
/**
* @brief This class represents a single frame of video (i.e. image & audio data)
*
@@ -114,6 +128,8 @@ namespace openshot
tr1::shared_ptr<Magick::Image> image;
tr1::shared_ptr<Magick::Image> wave_image;
tr1::shared_ptr<juce::AudioSampleBuffer> audio;
tr1::shared_ptr<QImage> qimage;
unsigned char *qbuffer;
Fraction pixel_ratio;
int channels;
ChannelLayout channel_layout;
@@ -220,6 +236,9 @@ namespace openshot
/// Get pointer to Magick++ image object
tr1::shared_ptr<Magick::Image> GetImage();
/// Get pointer to QImage of frame
tr1::shared_ptr<QImage> GetQImage();
/// Set Pixel Aspect Ratio
Fraction GetPixelRatio() { return pixel_ratio; };

View File

@@ -29,7 +29,7 @@
#define OPENSHOT_VIDEO_RENDERER_WIDGET_H
#include <QtWidgets/QWidget>
#include <QImage>
#include <QtGui/QImage>
#include "../Fraction.h"
#include "VideoRenderer.h"
@@ -57,7 +57,7 @@ protected:
QRect centeredViewport(int width, int height);
private slots:
void present(const QImage & image);
void present(const QImage &image);
};

View File

@@ -30,9 +30,10 @@
#include "../RendererBase.h"
#include <QtCore/QObject>
#include <QtGui/QImage>
#include <tr1/memory>
class QImage;
class QPainter;
class VideoRenderer : public QObject, public openshot::RendererBase
@@ -47,10 +48,11 @@ public:
void OverrideWidget(long qwidget_address);
signals:
void present(const QImage & image);
void present(const QImage &image);
protected:
void render(openshot::PixelFormat format, int width, int height, int bytesPerLine, unsigned char *data);
//void render(openshot::OSPixelFormat format, int width, int height, int bytesPerLine, unsigned char *data);
void render(tr1::shared_ptr<QImage> image);
private slots:

View File

@@ -28,23 +28,14 @@
#ifndef OPENSHOT_RENDERER_BASE_H
#define OPENSHOT_RENDERER_BASE_H
#include "../include/Frame.h"
#include <stdlib.h> // for realloc
#include <tr1/memory>
namespace openshot
{
class Frame;
/**
* @brief The pixel format supported by renderers.
*
* Currently only RGB_888 is supported.
*
* @see QuantumType
*/
enum PixelFormat {
RGB_888,
};
/**
* @brief This is the base class of all Renderers in libopenshot.
*
@@ -53,8 +44,6 @@ namespace openshot
*/
class RendererBase
{
unsigned char *buffer;
public:
/// Paint(render) a video Frame.
@@ -67,7 +56,7 @@ namespace openshot
RendererBase();
virtual ~RendererBase();
virtual void render(PixelFormat format, int width, int height, int bytesPerLine, unsigned char *data) = 0;
virtual void render(tr1::shared_ptr<QImage> image) = 0;
};
}

View File

@@ -32,7 +32,7 @@ using namespace openshot;
// Constructor - blank frame (300x200 blank image, 48kHz audio silence)
Frame::Frame() : number(1), pixel_ratio(1,1), channels(2), width(1), height(1),
channel_layout(LAYOUT_STEREO), sample_rate(44100)
channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL)
{
// Init the image magic and audio buffer
image = tr1::shared_ptr<Magick::Image>(new Magick::Image(Magick::Geometry(1,1), Magick::Color("red")));
@@ -45,7 +45,7 @@ Frame::Frame() : number(1), pixel_ratio(1,1), channels(2), width(1), height(1),
// Constructor - image only (48kHz audio silence)
Frame::Frame(int number, int width, int height, string color)
: number(number), pixel_ratio(1,1), channels(2), width(width), height(height),
channel_layout(LAYOUT_STEREO), sample_rate(44100)
channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL)
{
// Init the image magic and audio buffer
image = tr1::shared_ptr<Magick::Image>(new Magick::Image(Magick::Geometry(1, 1), Magick::Color(color)));
@@ -58,7 +58,7 @@ Frame::Frame(int number, int width, int height, string color)
// Constructor - image only from pixel array (48kHz audio silence)
Frame::Frame(int number, int width, int height, const string map, const Magick::StorageType type, const void *pixels)
: number(number), pixel_ratio(1,1), channels(2), width(width), height(height),
channel_layout(LAYOUT_STEREO), sample_rate(44100)
channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL)
{
// Init the image magic and audio buffer
image = tr1::shared_ptr<Magick::Image>(new Magick::Image(width, height, map, type, pixels));
@@ -71,7 +71,7 @@ Frame::Frame(int number, int width, int height, const string map, const Magick::
// Constructor - audio only (300x200 blank image)
Frame::Frame(int number, int samples, int channels) :
number(number), pixel_ratio(1,1), channels(channels), width(1), height(1),
channel_layout(LAYOUT_STEREO), sample_rate(44100)
channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL)
{
// Init the image magic and audio buffer
image = tr1::shared_ptr<Magick::Image>(new Magick::Image(Magick::Geometry(1, 1), Magick::Color("white")));
@@ -84,7 +84,7 @@ Frame::Frame(int number, int samples, int channels) :
// Constructor - image & audio
Frame::Frame(int number, int width, int height, string color, int samples, int channels)
: number(number), pixel_ratio(1,1), channels(channels), width(width), height(height),
channel_layout(LAYOUT_STEREO), sample_rate(44100)
channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL)
{
// Init the image magic and audio buffer
image = tr1::shared_ptr<Magick::Image>(new Magick::Image(Magick::Geometry(1, 1), Magick::Color(color)));
@@ -102,18 +102,6 @@ Frame::Frame ( const Frame &other )
DeepCopy(other);
}
// Assignment operator
//Frame& Frame::operator= (const Frame& other)
//{
// if (this != &other) {
// // copy pointers and data
// DeepCopy(other);
// }
//
// // return this instance
// return *this;
// }
// Copy data and pointers from another Frame instance
void Frame::DeepCopy(const Frame& other)
{
@@ -134,6 +122,13 @@ Frame::~Frame() {
image.reset();
audio.reset();
audio.reset();
qimage.reset();
if (qbuffer)
{
delete qbuffer;
qbuffer = NULL;
}
}
// Display the frame image to the screen (primarily used for debugging reasons)
@@ -917,6 +912,33 @@ tr1::shared_ptr<Magick::Image> Frame::GetImage()
return image;
}
// Get pointer to QImage of frame
tr1::shared_ptr<QImage> Frame::GetQImage()
{
const int BPP = 3;
const std::size_t bufferSize = width * height * BPP;
/// Use realloc for fast memory allocation.
/// TODO: consider locking the buffer for mt safety
//qbuffer = reinterpret_cast<unsigned char*>(realloc(qbuffer, bufferSize));
qbuffer = new unsigned char[bufferSize]();
// Iterate through the pixel packets, and load our own buffer
// Each color needs to be scaled to 8 bit (using the ImageMagick built-in ScaleQuantumToChar function)
const Magick::PixelPacket *pixels = GetPixels();
for (int n = 0, i = 0; n < width * height; n += 1, i += 3) {
qbuffer[i+0] = MagickCore::ScaleQuantumToChar((Magick::Quantum) pixels[n].red);
qbuffer[i+1] = MagickCore::ScaleQuantumToChar((Magick::Quantum) pixels[n].green);
qbuffer[i+2] = MagickCore::ScaleQuantumToChar((Magick::Quantum) pixels[n].blue);
}
// Create QImage of frame data
qimage = tr1::shared_ptr<QImage>(new QImage(qbuffer, width, height, width * BPP, QImage::Format_RGB888));
// Return QImage
return qimage;
}
// Play audio samples for this frame
void Frame::Play()
{

View File

@@ -31,8 +31,7 @@
#include <QtGui/QPainter>
VideoRenderWidget::VideoRenderWidget(QWidget *parent)
: QWidget(parent)
, renderer(new VideoRenderer(this))
: QWidget(parent), renderer(new VideoRenderer(this))
{
QPalette p = palette();
p.setColor(QPalette::Window, Qt::black);
@@ -86,9 +85,10 @@ void VideoRenderWidget::paintEvent(QPaintEvent *event)
painter.fillRect(event->rect(), palette().window());
painter.setViewport(centeredViewport(width(), height()));
painter.drawImage(QRect(0, 0, width(), height()), image);
}
void VideoRenderWidget::present(const QImage & m)
void VideoRenderWidget::present(const QImage &m)
{
image = m;
repaint();

View File

@@ -26,10 +26,10 @@
*/
#include "../../include/Qt/VideoRenderer.h"
#include <QPainter>
#include <QImage>
#include <QtGui/QPainter>
#include <QtGui/QImage>
using openshot::PixelFormat;
using openshot::OSPixelFormat;
VideoRenderer::VideoRenderer(QObject *parent)
: QObject(parent)
@@ -48,8 +48,8 @@ void VideoRenderer::OverrideWidget(long qwidget_address)
}
void VideoRenderer::render(PixelFormat /*format*/, int width, int height, int bytesPerLine, unsigned char *data)
//void VideoRenderer::render(OSPixelFormat /*format*/, int width, int height, int bytesPerLine, unsigned char *data)
void VideoRenderer::render(tr1::shared_ptr<QImage> image)
{
QImage image(data, width, height, bytesPerLine, QImage::Format_RGB888 /* TODO: render pixels */);
emit present(image);
emit present(*image);
}

View File

@@ -26,12 +26,9 @@
*/
#include "../include/RendererBase.h"
#include "../include/Frame.h"
#include <stdlib.h> // for realloc
using namespace openshot;
RendererBase::RendererBase() : buffer(NULL)
RendererBase::RendererBase()
{
}
@@ -41,30 +38,5 @@ RendererBase::~RendererBase()
void RendererBase::paint(const std::tr1::shared_ptr<Frame> & frame)
{
const int BPP = 3;
const tr1::shared_ptr<Magick::Image> image = frame->GetImage();
const std::size_t width = image->columns();
const std::size_t height = image->rows();
const std::size_t bufferSize = width * height * BPP;
/// Use realloc for fast memory allocation.
/// TODO: consider locking the buffer for mt safety
buffer = reinterpret_cast<unsigned char*>(realloc(buffer, bufferSize));
#if false
// Not sure if this is actually faster... but it works now
image->getPixels(0,0, width, height); // load pixels into cache
image->depth( 8 ); // this is required or it crashes
image->writePixels(Magick::RGBQuantum, buffer); // write pixel data to our buffer
#else
// Iterate through the pixel packets, and load our own buffer
// Each color needs to be scaled to 8 bit (using the ImageMagick built-in ScaleQuantumToChar function)
const Magick::PixelPacket *pixels = frame->GetPixels();
for (int n = 0, i = 0; n < width * height; n += 1, i += 3) {
buffer[i+0] = MagickCore::ScaleQuantumToChar((Magick::Quantum) pixels[n].red);
buffer[i+1] = MagickCore::ScaleQuantumToChar((Magick::Quantum) pixels[n].green);
buffer[i+2] = MagickCore::ScaleQuantumToChar((Magick::Quantum) pixels[n].blue);
}
#endif
this->render(RGB_888, width, height, width * BPP, buffer);
this->render(frame->GetQImage());
}