You've already forked libopenshot
mirror of
https://github.com/OpenShot/libopenshot.git
synced 2026-03-02 08:53:52 -08:00
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:
@@ -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; };
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user