/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2022, Ideas on Board Oy * * sdl_texture_mjpg.cpp - SDL Texture MJPG */ #include "sdl_texture_mjpg.h" #include <iostream> #include <setjmp.h> #include <stdio.h> #include <jpeglib.h> 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) : SDLTexture(rect, SDL_PIXELFORMAT_RGB24, rect.w * 3), rgb_(std::make_unique<unsigned char[]>(stride_ * rect.h)) { } int SDLTextureMJPG::decompress(Span<const 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 * stride_; jpeg_read_scanlines(&cinfo, &rowptr, 1); } jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); return 0; } void SDLTextureMJPG::update(const std::vector<libcamera::Span<const uint8_t>> &data) { decompress(data[0]); SDL_UpdateTexture(ptr_, nullptr, rgb_.get(), stride_); }