From patchwork Wed Jul 20 13:03:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 16702 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 1ED70BD1F1 for ; Wed, 20 Jul 2022 13:04:30 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 581CD63311; Wed, 20 Jul 2022 15:04:29 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1658322269; bh=sI4UlJbLvGIZhicBLEjHbefgyOesG1ClvDSiJl0g0kg=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=3vy9RYit1AJxAEK3XV9EOMTqaNG8+4pHdMD20YhA25fgSCAulOeBY6ZBvSjKhLIlu jFRMkeN7CxQivlNrwX/mQG/TZDydwPZJm2o41ofmB/M6HInbJRs6/hr0aI2DA48wpc 2kx5xvHIaNzGY7ypGAzdIxfV9QbL/5bRsfRsqaBgsjY74hYjXa6yKaswp4K992iGhs gM0f1gp7SFsmj9NOl3/ZD7cC+LGEGZE9eGeiRrGhOUjGT/wK0zpr37GwnKMUGdkudB smfz57vDdOQsHO3uEnLCUcKBKMGch8OUD+P7RncFnQCVXOjt3gRxGJ0cyX04oFMFcf KvSkGCePPWg7A== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C31A860489 for ; Wed, 20 Jul 2022 15:04:26 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="QjvvZb1Z"; dkim-atps=neutral Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 61F7488F; Wed, 20 Jul 2022 15:04:26 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1658322266; bh=sI4UlJbLvGIZhicBLEjHbefgyOesG1ClvDSiJl0g0kg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=QjvvZb1ZpIy3mus6DmhG7hyteMK+fALcj7EHo2we7GgdMsCmizKKAKGp5GsxuTrFc y3H9c2MYDgU4GKWZ4jTAacfgyNeW3+ZVO4fm0RjYSgyZwvdJgMeF2PQ+Oy0jwNdWwn qwlEwM6fC61tInM7H5HtKt76Uy+JqQz7sLhEdcrs= To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Jul 2022 16:03:47 +0300 Message-Id: <20220720130348.1337-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220720130348.1337-1-laurent.pinchart@ideasonboard.com> References: <20220720130348.1337-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 1/2] cam: sdl_sink: Use libjpeg over SDL2_image X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Laurent Pinchart via libcamera-devel From: Laurent Pinchart Reply-To: Laurent Pinchart Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Eric Curtin 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 Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- Changes since v4: - Move JpegErrorManager to sdl_texture_mjpg.cpp - Make JpegErrorManager inherit from jpeg_error_mgr - Define errorExit and outputMessage as member functions --- README.rst | 2 +- src/cam/meson.build | 8 ++--- src/cam/sdl_sink.cpp | 4 +-- src/cam/sdl_texture_mjpg.cpp | 70 ++++++++++++++++++++++++++++++++---- src/cam/sdl_texture_mjpg.h | 6 ++++ 5 files changed, 77 insertions(+), 13 deletions(-) diff --git a/README.rst b/README.rst index b9e72d81b90c..47b914f02260 100644 --- a/README.rst +++ b/README.rst @@ -92,8 +92,8 @@ for cam: [optional] tool: - libdrm-dev: Enables the KMS sink + - libjpeg-dev: Enables MJPEG on the SDL sink - libsdl2-dev: Enables the SDL sink - - libsdl2-image-dev: Supports MJPEG on the SDL sink for qcam: [optional] qtbase5-dev libqt5core5a libqt5gui5 libqt5widgets5 qttools5-dev-tools libtiff-dev diff --git a/src/cam/meson.build b/src/cam/meson.build index 5957ce140391..4dfa7b22aea9 100644 --- a/src/cam/meson.build +++ b/src/cam/meson.build @@ -24,8 +24,8 @@ cam_sources = files([ cam_cpp_args = [] libdrm = dependency('libdrm', required : false) +libjpeg = dependency('libjpeg', required : false) libsdl2 = dependency('SDL2', required : false) -libsdl2_image = dependency('SDL2_image', required : false) if libdrm.found() cam_cpp_args += [ '-DHAVE_KMS' ] @@ -43,8 +43,8 @@ if libsdl2.found() 'sdl_texture_yuyv.cpp' ]) - if libsdl2_image.found() - cam_cpp_args += ['-DHAVE_SDL_IMAGE'] + if libjpeg.found() + cam_cpp_args += ['-DHAVE_LIBJPEG'] cam_sources += files([ 'sdl_texture_mjpg.cpp' ]) @@ -57,8 +57,8 @@ cam = executable('cam', cam_sources, libcamera_public, libdrm, libevent, + libjpeg, libsdl2, - libsdl2_image, libyaml, ], cpp_args : cam_cpp_args, diff --git a/src/cam/sdl_sink.cpp b/src/cam/sdl_sink.cpp index f8e3e95dd392..19fdfd6dced5 100644 --- a/src/cam/sdl_sink.cpp +++ b/src/cam/sdl_sink.cpp @@ -21,7 +21,7 @@ #include "event_loop.h" #include "image.h" -#ifdef HAVE_SDL_IMAGE +#ifdef HAVE_LIBJPEG #include "sdl_texture_mjpg.h" #endif #include "sdl_texture_yuyv.h" @@ -62,7 +62,7 @@ int SDLSink::configure(const libcamera::CameraConfiguration &config) rect_.h = cfg.size.height; switch (cfg.pixelFormat) { -#ifdef HAVE_SDL_IMAGE +#ifdef HAVE_LIBJPEG case libcamera::formats::MJPEG: texture_ = std::make_unique(rect_); break; diff --git a/src/cam/sdl_texture_mjpg.cpp b/src/cam/sdl_texture_mjpg.cpp index 69e99ad35219..7eddc00cd210 100644 --- a/src/cam/sdl_texture_mjpg.cpp +++ b/src/cam/sdl_texture_mjpg.cpp @@ -7,19 +7,77 @@ #include "sdl_texture_mjpg.h" -#include +#include +#include +#include + +#include 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(cinfo->err); + longjmp(self->escape_, 1); + } + + static void outputMessage([[maybe_unused]] j_common_ptr cinfo) + { + } + + jmp_buf escape_; +}; + SDLTextureMJPG::SDLTextureMJPG(const SDL_Rect &rect) - : SDLTexture(rect, SDL_PIXELFORMAT_RGB24, 0) + : SDLTexture(rect, SDL_PIXELFORMAT_RGB24, rect.w * 3), + rgb_(std::make_unique(pitch_ * rect.h)) { } +int SDLTextureMJPG::decompress(const Span &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 &data) { - SDL_RWops *bufferStream = SDL_RWFromMem(data.data(), data.size()); - SDL_Surface *frame = IMG_Load_RW(bufferStream, 0); - SDL_UpdateTexture(ptr_, nullptr, frame->pixels, frame->pitch); - SDL_FreeSurface(frame); + decompress(data); + SDL_UpdateTexture(ptr_, nullptr, rgb_.get(), pitch_); } diff --git a/src/cam/sdl_texture_mjpg.h b/src/cam/sdl_texture_mjpg.h index b103f801176d..328c45a913c5 100644 --- a/src/cam/sdl_texture_mjpg.h +++ b/src/cam/sdl_texture_mjpg.h @@ -13,5 +13,11 @@ class SDLTextureMJPG : public SDLTexture { public: SDLTextureMJPG(const SDL_Rect &rect); + void update(const libcamera::Span &data) override; + +private: + int decompress(const libcamera::Span &data); + + std::unique_ptr rgb_; };