/***************************************************************************** # # # uStreamer - Lightweight and fast MJPG-HTTP streamer. # # # # Copyright (C) 2018-2021 Maxim Devaev # # # # This program is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation, either version 3 of the License, or # # (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program. If not, see . # # # *****************************************************************************/ #include "unjpeg.h" typedef struct { struct jpeg_error_mgr mgr; // Default manager jmp_buf jmp; const frame_s *frame; } _jpeg_error_manager_s; static void _jpeg_error_handler(j_common_ptr jpeg); int unjpeg(const frame_s *src, frame_s *dest, bool decode) { assert(is_jpeg(src->format)); volatile int retval = 0; struct jpeg_decompress_struct jpeg; jpeg_create_decompress(&jpeg); // https://stackoverflow.com/questions/19857766/error-handling-in-libjpeg _jpeg_error_manager_s jpeg_error; jpeg.err = jpeg_std_error((struct jpeg_error_mgr *)&jpeg_error); jpeg_error.mgr.error_exit = _jpeg_error_handler; jpeg_error.frame = src; if (setjmp(jpeg_error.jmp) < 0) { retval = -1; goto done; } jpeg_mem_src(&jpeg, src->data, src->used); jpeg_read_header(&jpeg, TRUE); jpeg.out_color_space = JCS_RGB; jpeg_start_decompress(&jpeg); frame_copy_meta(src, dest); dest->format = V4L2_PIX_FMT_RGB24; dest->width = jpeg.output_width; dest->height = jpeg.output_height; dest->stride = jpeg.output_width * jpeg.output_components; // Row stride dest->used = 0; if (decode) { JSAMPARRAY scanlines; scanlines = (*jpeg.mem->alloc_sarray)((j_common_ptr) &jpeg, JPOOL_IMAGE, dest->stride, 1); frame_realloc_data(dest, ((dest->width * dest->height) << 1) * 2); while (jpeg.output_scanline < jpeg.output_height) { jpeg_read_scanlines(&jpeg, scanlines, 1); frame_append_data(dest, scanlines[0], dest->stride); } jpeg_finish_decompress(&jpeg); } done: jpeg_destroy_decompress(&jpeg); return retval; } static void _jpeg_error_handler(j_common_ptr jpeg) { _jpeg_error_manager_s *jpeg_error = (_jpeg_error_manager_s *)jpeg->err; char msg[JMSG_LENGTH_MAX]; (*jpeg_error->mgr.format_message)(jpeg, msg); LOG_ERROR("Can't decompress %s JPEG: %s", jpeg_error->frame->name, msg); longjmp(jpeg_error->jmp, -1); }