cam: sdl_sink: Use libjpeg over SDL2_image

We were using the libjpeg functionality of SDL2_image only, instead just
use libjpeg directly to reduce our dependancy count, it is a more
commonly available library.

Signed-off-by: Eric Curtin <ecurtin@redhat.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
This commit is contained in:
Eric Curtin 2022-07-19 10:17:46 +01:00 committed by Laurent Pinchart
parent c13f86704b
commit dc1f4a91df
5 changed files with 77 additions and 13 deletions

View file

@ -86,8 +86,8 @@ for cam: [optional]
tool: tool:
- libdrm-dev: Enables the KMS sink - libdrm-dev: Enables the KMS sink
- libjpeg-dev: Enables MJPEG on the SDL sink
- libsdl2-dev: Enables the SDL sink - libsdl2-dev: Enables the SDL sink
- libsdl2-image-dev: Supports MJPEG on the SDL sink
for qcam: [optional] for qcam: [optional]
qtbase5-dev libqt5core5a libqt5gui5 libqt5widgets5 qttools5-dev-tools libtiff-dev qtbase5-dev libqt5core5a libqt5gui5 libqt5widgets5 qttools5-dev-tools libtiff-dev

View file

@ -24,8 +24,8 @@ cam_sources = files([
cam_cpp_args = [] cam_cpp_args = []
libdrm = dependency('libdrm', required : false) libdrm = dependency('libdrm', required : false)
libjpeg = dependency('libjpeg', required : false)
libsdl2 = dependency('SDL2', required : false) libsdl2 = dependency('SDL2', required : false)
libsdl2_image = dependency('SDL2_image', required : false)
if libdrm.found() if libdrm.found()
cam_cpp_args += [ '-DHAVE_KMS' ] cam_cpp_args += [ '-DHAVE_KMS' ]
@ -43,8 +43,8 @@ if libsdl2.found()
'sdl_texture_yuyv.cpp' 'sdl_texture_yuyv.cpp'
]) ])
if libsdl2_image.found() if libjpeg.found()
cam_cpp_args += ['-DHAVE_SDL_IMAGE'] cam_cpp_args += ['-DHAVE_LIBJPEG']
cam_sources += files([ cam_sources += files([
'sdl_texture_mjpg.cpp' 'sdl_texture_mjpg.cpp'
]) ])
@ -57,8 +57,8 @@ cam = executable('cam', cam_sources,
libcamera_public, libcamera_public,
libdrm, libdrm,
libevent, libevent,
libjpeg,
libsdl2, libsdl2,
libsdl2_image,
libyaml, libyaml,
], ],
cpp_args : cam_cpp_args, cpp_args : cam_cpp_args,

View file

@ -21,7 +21,7 @@
#include "event_loop.h" #include "event_loop.h"
#include "image.h" #include "image.h"
#ifdef HAVE_SDL_IMAGE #ifdef HAVE_LIBJPEG
#include "sdl_texture_mjpg.h" #include "sdl_texture_mjpg.h"
#endif #endif
#include "sdl_texture_yuyv.h" #include "sdl_texture_yuyv.h"
@ -62,7 +62,7 @@ int SDLSink::configure(const libcamera::CameraConfiguration &config)
rect_.h = cfg.size.height; rect_.h = cfg.size.height;
switch (cfg.pixelFormat) { switch (cfg.pixelFormat) {
#ifdef HAVE_SDL_IMAGE #ifdef HAVE_LIBJPEG
case libcamera::formats::MJPEG: case libcamera::formats::MJPEG:
texture_ = std::make_unique<SDLTextureMJPG>(rect_); texture_ = std::make_unique<SDLTextureMJPG>(rect_);
break; break;

View file

@ -7,19 +7,77 @@
#include "sdl_texture_mjpg.h" #include "sdl_texture_mjpg.h"
#include <SDL2/SDL_image.h> #include <iostream>
#include <setjmp.h>
#include <stdio.h>
#include <jpeglib.h>
using namespace libcamera; using namespace libcamera;
struct JpegErrorManager : public jpeg_error_mgr {
JpegErrorManager()
{
jpeg_std_error(this);
error_exit = errorExit;
output_message = outputMessage;
}
static void errorExit(j_common_ptr cinfo)
{
JpegErrorManager *self =
static_cast<JpegErrorManager *>(cinfo->err);
longjmp(self->escape_, 1);
}
static void outputMessage([[maybe_unused]] j_common_ptr cinfo)
{
}
jmp_buf escape_;
};
SDLTextureMJPG::SDLTextureMJPG(const SDL_Rect &rect) SDLTextureMJPG::SDLTextureMJPG(const SDL_Rect &rect)
: SDLTexture(rect, SDL_PIXELFORMAT_RGB24, 0) : SDLTexture(rect, SDL_PIXELFORMAT_RGB24, rect.w * 3),
rgb_(std::make_unique<unsigned char[]>(pitch_ * rect.h))
{ {
} }
int SDLTextureMJPG::decompress(const Span<uint8_t> &data)
{
struct jpeg_decompress_struct cinfo;
JpegErrorManager errorManager;
if (setjmp(errorManager.escape_)) {
/* libjpeg found an error */
jpeg_destroy_decompress(&cinfo);
std::cerr << "JPEG decompression error" << std::endl;
return -EINVAL;
}
cinfo.err = &errorManager;
jpeg_create_decompress(&cinfo);
jpeg_mem_src(&cinfo, data.data(), data.size());
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
for (int i = 0; cinfo.output_scanline < cinfo.output_height; ++i) {
JSAMPROW rowptr = rgb_.get() + i * pitch_;
jpeg_read_scanlines(&cinfo, &rowptr, 1);
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
return 0;
}
void SDLTextureMJPG::update(const Span<uint8_t> &data) void SDLTextureMJPG::update(const Span<uint8_t> &data)
{ {
SDL_RWops *bufferStream = SDL_RWFromMem(data.data(), data.size()); decompress(data);
SDL_Surface *frame = IMG_Load_RW(bufferStream, 0); SDL_UpdateTexture(ptr_, nullptr, rgb_.get(), pitch_);
SDL_UpdateTexture(ptr_, nullptr, frame->pixels, frame->pitch);
SDL_FreeSurface(frame);
} }

View file

@ -13,5 +13,11 @@ class SDLTextureMJPG : public SDLTexture
{ {
public: public:
SDLTextureMJPG(const SDL_Rect &rect); SDLTextureMJPG(const SDL_Rect &rect);
void update(const libcamera::Span<uint8_t> &data) override; void update(const libcamera::Span<uint8_t> &data) override;
private:
int decompress(const libcamera::Span<uint8_t> &data);
std::unique_ptr<unsigned char[]> rgb_;
}; };