Merge branch 'master' into dev

This commit is contained in:
DRC
2020-07-28 15:09:00 -05:00
13 changed files with 339 additions and 176 deletions

View File

@@ -773,7 +773,7 @@ else()
set(MD5_PPM_3x2_IFAST fd283664b3b49127984af0a7f118fccd) set(MD5_PPM_3x2_IFAST fd283664b3b49127984af0a7f118fccd)
set(MD5_JPEG_420_ISLOW_ARI e986fb0a637a8d833d96e8a6d6d84ea1) set(MD5_JPEG_420_ISLOW_ARI e986fb0a637a8d833d96e8a6d6d84ea1)
set(MD5_JPEG_444_ISLOW_PROGARI 0a8f1c8f66e113c3cf635df0a475a617) set(MD5_JPEG_444_ISLOW_PROGARI 0a8f1c8f66e113c3cf635df0a475a617)
set(MD5_PPM_420M_IFAST_ARI 72b59a99bcf1de24c5b27d151bde2437) set(MD5_PPM_420M_IFAST_ARI 57251da28a35b46eecb7177d82d10e0e)
set(MD5_JPEG_420_ISLOW 9a68f56bc76e466aa7e52f415d0f4a5f) set(MD5_JPEG_420_ISLOW 9a68f56bc76e466aa7e52f415d0f4a5f)
set(MD5_PPM_420M_ISLOW_2_1 9f9de8c0612f8d06869b960b05abf9c9) set(MD5_PPM_420M_ISLOW_2_1 9f9de8c0612f8d06869b960b05abf9c9)
set(MD5_PPM_420M_ISLOW_15_8 b6875bc070720b899566cc06459b63b7) set(MD5_PPM_420M_ISLOW_15_8 b6875bc070720b899566cc06459b63b7)
@@ -1164,7 +1164,7 @@ foreach(libtype ${TEST_LIBTYPES})
if(WITH_ARITH_DEC) if(WITH_ARITH_DEC)
# CC: RGB->YCC SAMP: h2v2 merged IDCT: ifast ENT: arith # CC: RGB->YCC SAMP: h2v2 merged IDCT: ifast ENT: arith
add_bittest(djpeg 420m-ifast-ari "-fast;-ppm" add_bittest(djpeg 420m-ifast-ari "-fast;-skip;1,20;-ppm"
testout_420m_ifast_ari.ppm ${TESTIMAGES}/testimgari.jpg testout_420m_ifast_ari.ppm ${TESTIMAGES}/testimgari.jpg
${MD5_PPM_420M_IFAST_ARI}) ${MD5_PPM_420M_IFAST_ARI})
@@ -1300,6 +1300,11 @@ endforeach()
add_custom_target(testclean COMMAND ${CMAKE_COMMAND} -P add_custom_target(testclean COMMAND ${CMAKE_COMMAND} -P
${CMAKE_CURRENT_SOURCE_DIR}/cmakescripts/testclean.cmake) ${CMAKE_CURRENT_SOURCE_DIR}/cmakescripts/testclean.cmake)
configure_file(croptest.in croptest @ONLY)
add_custom_target(croptest
COMMAND echo croptest
COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/croptest)
if(WITH_TURBOJPEG) if(WITH_TURBOJPEG)
configure_file(tjbenchtest.in tjbenchtest @ONLY) configure_file(tjbenchtest.in tjbenchtest @ONLY)
configure_file(tjexampletest.in tjexampletest @ONLY) configure_file(tjexampletest.in tjexampletest @ONLY)

View File

@@ -80,6 +80,23 @@ limit the number of allowable scans in the input file.
- Both programs now accept a `-strict` argument, which can be used to - Both programs now accept a `-strict` argument, which can be used to
treat all warnings as fatal. treat all warnings as fatal.
10. Fixed "using JNI after critical get" errors that occurred on Android
platforms when using any of the YUV encoding/compression/decompression/decoding
methods in the TurboJPEG Java API.
11. Fixed or worked around multiple issues with `jpeg_skip_scanlines()`:
- Fixed segfaults or "Corrupt JPEG data: premature end of data segment"
errors in `jpeg_skip_scanlines()` that occurred when decompressing 4:2:2 or
4:2:0 JPEG images using merged (non-fancy) upsampling/color conversion (that
is, when setting `cinfo.do_fancy_upsampling` to `FALSE`.) 2.0.0[6] was a
similar fix, but it did not cover all cases.
- `jpeg_skip_scanlines()` now throws an error if two-pass color
quantization is enabled. Two-pass color quantization never worked properly
with `jpeg_skip_scanlines()`, and the issues could not readily be fixed.
- Fixed an issue whereby `jpeg_skip_scanlines()` always returned 0 when
skipping past the end of an image.
2.0.5 2.0.5
===== =====

View File

@@ -179,8 +179,8 @@ supported and which aren't.
NOTE: As of this writing, extensive research has been conducted into the NOTE: As of this writing, extensive research has been conducted into the
usefulness of DCT scaling as a means of data reduction and SmartScale as a usefulness of DCT scaling as a means of data reduction and SmartScale as a
means of quality improvement. The reader is invited to peruse the research at means of quality improvement. Readers are invited to peruse the research at
<http://www.libjpeg-turbo.org/About/SmartScale> and draw his/her own conclusions, <http://www.libjpeg-turbo.org/About/SmartScale> and draw their own conclusions,
but it is the general belief of our project that these features have not but it is the general belief of our project that these features have not
demonstrated sufficient usefulness to justify inclusion in libjpeg-turbo. demonstrated sufficient usefulness to justify inclusion in libjpeg-turbo.

95
croptest.in Executable file
View File

@@ -0,0 +1,95 @@
#!/bin/bash
set -u
set -e
trap onexit INT
trap onexit TERM
trap onexit EXIT
onexit()
{
if [ -d $OUTDIR ]; then
rm -rf $OUTDIR
fi
}
runme()
{
echo \*\*\* $*
$*
}
IMAGE=vgl_6548_0026a.bmp
WIDTH=128
HEIGHT=95
IMGDIR=@CMAKE_CURRENT_SOURCE_DIR@/testimages
OUTDIR=`mktemp -d /tmp/__croptest_output.XXXXXX`
EXEDIR=@CMAKE_CURRENT_BINARY_DIR@
if [ -d $OUTDIR ]; then
rm -rf $OUTDIR
fi
mkdir -p $OUTDIR
exec >$EXEDIR/croptest.log
echo "============================================================"
echo "$IMAGE ($WIDTH x $HEIGHT)"
echo "============================================================"
echo
for PROGARG in "" -progressive; do
cp $IMGDIR/$IMAGE $OUTDIR
basename=`basename $IMAGE .bmp`
echo "------------------------------------------------------------"
echo "Generating test images"
echo "------------------------------------------------------------"
echo
runme $EXEDIR/cjpeg $PROGARG -grayscale -outfile $OUTDIR/${basename}_GRAY.jpg $IMGDIR/${basename}.bmp
runme $EXEDIR/cjpeg $PROGARG -sample 2x2 -outfile $OUTDIR/${basename}_420.jpg $IMGDIR/${basename}.bmp
runme $EXEDIR/cjpeg $PROGARG -sample 2x1 -outfile $OUTDIR/${basename}_422.jpg $IMGDIR/${basename}.bmp
runme $EXEDIR/cjpeg $PROGARG -sample 1x2 -outfile $OUTDIR/${basename}_440.jpg $IMGDIR/${basename}.bmp
runme $EXEDIR/cjpeg $PROGARG -sample 1x1 -outfile $OUTDIR/${basename}_444.jpg $IMGDIR/${basename}.bmp
echo
for NSARG in "" -nosmooth; do
for COLORSARG in "" "-colors 256 -dither none -onepass"; do
for Y in {0..16}; do
for H in {1..16}; do
X=$(( (Y*16)%128 ))
W=$(( WIDTH-X-7 ))
if [ $Y -le 15 ]; then
CROPSPEC="${W}x${H}+${X}+${Y}"
else
Y2=$(( HEIGHT-H ));
CROPSPEC="${W}x${H}+${X}+${Y2}"
fi
echo "------------------------------------------------------------"
echo $PROGARG $NSARG $COLORSARG -crop $CROPSPEC
echo "------------------------------------------------------------"
echo
for samp in GRAY 420 422 440 444; do
$EXEDIR/djpeg $NSARG $COLORSARG -rgb -outfile $OUTDIR/${basename}_${samp}_full.ppm $OUTDIR/${basename}_${samp}.jpg
convert -crop $CROPSPEC $OUTDIR/${basename}_${samp}_full.ppm $OUTDIR/${basename}_${samp}_ref.ppm
runme $EXEDIR/djpeg $NSARG $COLORSARG -crop $CROPSPEC -rgb -outfile $OUTDIR/${basename}_${samp}.ppm $OUTDIR/${basename}_${samp}.jpg
runme cmp $OUTDIR/${basename}_${samp}.ppm $OUTDIR/${basename}_${samp}_ref.ppm
done
echo
done
done
done
done
done
echo SUCCESS!

24
djpeg.c
View File

@@ -5,7 +5,7 @@
* Copyright (C) 1991-1997, Thomas G. Lane. * Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 2013 by Guido Vollbeding. * Modified 2013 by Guido Vollbeding.
* libjpeg-turbo Modifications: * libjpeg-turbo Modifications:
* Copyright (C) 2010-2011, 2013-2017, 2019, D. R. Commander. * Copyright (C) 2010-2011, 2013-2017, 2019-2020, D. R. Commander.
* Copyright (C) 2015, Google, Inc. * Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg * For conditions of distribution and use, see the accompanying README.ijg
* file. * file.
@@ -730,7 +730,12 @@ main(int argc, char **argv)
dest_mgr->buffer_height); dest_mgr->buffer_height);
(*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
} }
jpeg_skip_scanlines(&cinfo, skip_end - skip_start + 1); if ((tmp = jpeg_skip_scanlines(&cinfo, skip_end - skip_start + 1)) !=
skip_end - skip_start + 1) {
fprintf(stderr, "%s: jpeg_skip_scanlines() returned %d rather than %d\n",
progname, tmp, skip_end - skip_start + 1);
exit(EXIT_FAILURE);
}
while (cinfo.output_scanline < cinfo.output_height) { while (cinfo.output_scanline < cinfo.output_height) {
num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
dest_mgr->buffer_height); dest_mgr->buffer_height);
@@ -766,13 +771,24 @@ main(int argc, char **argv)
cinfo.output_height = tmp; cinfo.output_height = tmp;
/* Process data */ /* Process data */
jpeg_skip_scanlines(&cinfo, crop_y); if ((tmp = jpeg_skip_scanlines(&cinfo, crop_y)) != crop_y) {
fprintf(stderr, "%s: jpeg_skip_scanlines() returned %d rather than %d\n",
progname, tmp, crop_y);
exit(EXIT_FAILURE);
}
while (cinfo.output_scanline < crop_y + crop_height) { while (cinfo.output_scanline < crop_y + crop_height) {
num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
dest_mgr->buffer_height); dest_mgr->buffer_height);
(*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
} }
jpeg_skip_scanlines(&cinfo, cinfo.output_height - crop_y - crop_height); if ((tmp =
jpeg_skip_scanlines(&cinfo,
cinfo.output_height - crop_y - crop_height)) !=
cinfo.output_height - crop_y - crop_height) {
fprintf(stderr, "%s: jpeg_skip_scanlines() returned %d rather than %d\n",
progname, tmp, cinfo.output_height - crop_y - crop_height);
exit(EXIT_FAILURE);
}
/* Normal full-image decompress */ /* Normal full-image decompress */
} else { } else {

View File

@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane. * Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications: * libjpeg-turbo Modifications:
* Copyright (C) 2010, 2015-2019, D. R. Commander. * Copyright (C) 2010, 2015-2020, D. R. Commander.
* Copyright (C) 2015, Google, Inc. * Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg * For conditions of distribution and use, see the accompanying README.ijg
* file. * file.
@@ -21,6 +21,8 @@
#include "jinclude.h" #include "jinclude.h"
#include "jdmainct.h" #include "jdmainct.h"
#include "jdcoefct.h" #include "jdcoefct.h"
#include "jdmaster.h"
#include "jdmerge.h"
#include "jdsample.h" #include "jdsample.h"
#include "jmemsys.h" #include "jmemsys.h"
@@ -316,6 +318,8 @@ LOCAL(void)
read_and_discard_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines) read_and_discard_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
{ {
JDIMENSION n; JDIMENSION n;
my_master_ptr master = (my_master_ptr)cinfo->master;
JSAMPARRAY scanlines = NULL;
void (*color_convert) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, void (*color_convert) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
JDIMENSION input_row, JSAMPARRAY output_buf, JDIMENSION input_row, JSAMPARRAY output_buf,
int num_rows) = NULL; int num_rows) = NULL;
@@ -332,8 +336,13 @@ read_and_discard_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
cinfo->cquantize->color_quantize = noop_quantize; cinfo->cquantize->color_quantize = noop_quantize;
} }
if (master->using_merged_upsample && cinfo->max_v_samp_factor == 2) {
my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
scanlines = &upsample->spare_row;
}
for (n = 0; n < num_lines; n++) for (n = 0; n < num_lines; n++)
jpeg_read_scanlines(cinfo, NULL, 1); jpeg_read_scanlines(cinfo, scanlines, 1);
if (color_convert) if (color_convert)
cinfo->cconvert->color_convert = color_convert; cinfo->cconvert->color_convert = color_convert;
@@ -353,6 +362,12 @@ increment_simple_rowgroup_ctr(j_decompress_ptr cinfo, JDIMENSION rows)
{ {
JDIMENSION rows_left; JDIMENSION rows_left;
my_main_ptr main_ptr = (my_main_ptr)cinfo->main; my_main_ptr main_ptr = (my_main_ptr)cinfo->main;
my_master_ptr master = (my_master_ptr)cinfo->master;
if (master->using_merged_upsample && cinfo->max_v_samp_factor == 2) {
read_and_discard_scanlines(cinfo, rows);
return;
}
/* Increment the counter to the next row group after the skipped rows. */ /* Increment the counter to the next row group after the skipped rows. */
main_ptr->rowgroup_ctr += rows / cinfo->max_v_samp_factor; main_ptr->rowgroup_ctr += rows / cinfo->max_v_samp_factor;
@@ -382,21 +397,27 @@ jpeg_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
{ {
my_main_ptr main_ptr = (my_main_ptr)cinfo->main; my_main_ptr main_ptr = (my_main_ptr)cinfo->main;
my_coef_ptr coef = (my_coef_ptr)cinfo->coef; my_coef_ptr coef = (my_coef_ptr)cinfo->coef;
my_master_ptr master = (my_master_ptr)cinfo->master;
my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample; my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
JDIMENSION i, x; JDIMENSION i, x;
int y; int y;
JDIMENSION lines_per_iMCU_row, lines_left_in_iMCU_row, lines_after_iMCU_row; JDIMENSION lines_per_iMCU_row, lines_left_in_iMCU_row, lines_after_iMCU_row;
JDIMENSION lines_to_skip, lines_to_read; JDIMENSION lines_to_skip, lines_to_read;
/* Two-pass color quantization is not supported. */
if (cinfo->quantize_colors && cinfo->two_pass_quantize)
ERREXIT(cinfo, JERR_NOTIMPL);
if (cinfo->global_state != DSTATE_SCANNING) if (cinfo->global_state != DSTATE_SCANNING)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
/* Do not skip past the bottom of the image. */ /* Do not skip past the bottom of the image. */
if (cinfo->output_scanline + num_lines >= cinfo->output_height) { if (cinfo->output_scanline + num_lines >= cinfo->output_height) {
num_lines = cinfo->output_height - cinfo->output_scanline;
cinfo->output_scanline = cinfo->output_height; cinfo->output_scanline = cinfo->output_height;
(*cinfo->inputctl->finish_input_pass) (cinfo); (*cinfo->inputctl->finish_input_pass) (cinfo);
cinfo->inputctl->eoi_reached = TRUE; cinfo->inputctl->eoi_reached = TRUE;
return cinfo->output_height - cinfo->output_scanline; return num_lines;
} }
if (num_lines == 0) if (num_lines == 0)
@@ -445,8 +466,10 @@ jpeg_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
main_ptr->buffer_full = FALSE; main_ptr->buffer_full = FALSE;
main_ptr->rowgroup_ctr = 0; main_ptr->rowgroup_ctr = 0;
main_ptr->context_state = CTX_PREPARE_FOR_IMCU; main_ptr->context_state = CTX_PREPARE_FOR_IMCU;
upsample->next_row_out = cinfo->max_v_samp_factor; if (!master->using_merged_upsample) {
upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline; upsample->next_row_out = cinfo->max_v_samp_factor;
upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
}
} }
/* Skipping is much simpler when context rows are not required. */ /* Skipping is much simpler when context rows are not required. */
@@ -458,8 +481,10 @@ jpeg_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
cinfo->output_scanline += lines_left_in_iMCU_row; cinfo->output_scanline += lines_left_in_iMCU_row;
main_ptr->buffer_full = FALSE; main_ptr->buffer_full = FALSE;
main_ptr->rowgroup_ctr = 0; main_ptr->rowgroup_ctr = 0;
upsample->next_row_out = cinfo->max_v_samp_factor; if (!master->using_merged_upsample) {
upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline; upsample->next_row_out = cinfo->max_v_samp_factor;
upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
}
} }
} }
@@ -494,7 +519,8 @@ jpeg_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
cinfo->output_iMCU_row += lines_to_skip / lines_per_iMCU_row; cinfo->output_iMCU_row += lines_to_skip / lines_per_iMCU_row;
increment_simple_rowgroup_ctr(cinfo, lines_to_read); increment_simple_rowgroup_ctr(cinfo, lines_to_read);
} }
upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline; if (!master->using_merged_upsample)
upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
return num_lines; return num_lines;
} }
@@ -537,7 +563,8 @@ jpeg_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
* bit odd, since "rows_to_go" seems to be redundantly keeping track of * bit odd, since "rows_to_go" seems to be redundantly keeping track of
* output_scanline. * output_scanline.
*/ */
upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline; if (!master->using_merged_upsample)
upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
/* Always skip the requested number of lines. */ /* Always skip the requested number of lines. */
return num_lines; return num_lines;

View File

@@ -5,7 +5,7 @@
* Copyright (C) 1994-1996, Thomas G. Lane. * Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications: * libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2009, 2011, 2014-2015, D. R. Commander. * Copyright (C) 2009, 2011, 2014-2015, 2020, D. R. Commander.
* Copyright (C) 2013, Linaro Limited. * Copyright (C) 2013, Linaro Limited.
* For conditions of distribution and use, see the accompanying README.ijg * For conditions of distribution and use, see the accompanying README.ijg
* file. * file.
@@ -40,41 +40,13 @@
#define JPEG_INTERNALS #define JPEG_INTERNALS
#include "jinclude.h" #include "jinclude.h"
#include "jpeglib.h" #include "jpeglib.h"
#include "jdmerge.h"
#include "jsimd.h" #include "jsimd.h"
#include "jconfigint.h" #include "jconfigint.h"
#ifdef UPSAMPLE_MERGING_SUPPORTED #ifdef UPSAMPLE_MERGING_SUPPORTED
/* Private subobject */
typedef struct {
struct jpeg_upsampler pub; /* public fields */
/* Pointer to routine to do actual upsampling/conversion of one row group */
void (*upmethod) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
/* Private state for YCC->RGB conversion */
int *Cr_r_tab; /* => table for Cr to R conversion */
int *Cb_b_tab; /* => table for Cb to B conversion */
JLONG *Cr_g_tab; /* => table for Cr to G conversion */
JLONG *Cb_g_tab; /* => table for Cb to G conversion */
/* For 2:1 vertical sampling, we produce two output rows at a time.
* We need a "spare" row buffer to hold the second output row if the
* application provides just a one-row buffer; we also use the spare
* to discard the dummy last row if the image height is odd.
*/
JSAMPROW spare_row;
boolean spare_full; /* T if spare buffer is occupied */
JDIMENSION out_row_width; /* samples per output row */
JDIMENSION rows_to_go; /* counts rows remaining in image */
} my_upsampler;
typedef my_upsampler *my_upsample_ptr;
#define SCALEBITS 16 /* speediest right-shift on some machines */ #define SCALEBITS 16 /* speediest right-shift on some machines */
#define ONE_HALF ((JLONG)1 << (SCALEBITS - 1)) #define ONE_HALF ((JLONG)1 << (SCALEBITS - 1))
#define FIX(x) ((JLONG)((x) * (1L << SCALEBITS) + 0.5)) #define FIX(x) ((JLONG)((x) * (1L << SCALEBITS) + 0.5))
@@ -189,7 +161,7 @@ typedef my_upsampler *my_upsample_ptr;
LOCAL(void) LOCAL(void)
build_ycc_rgb_table(j_decompress_ptr cinfo) build_ycc_rgb_table(j_decompress_ptr cinfo)
{ {
my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample; my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
int i; int i;
JLONG x; JLONG x;
SHIFT_TEMPS SHIFT_TEMPS
@@ -232,7 +204,7 @@ build_ycc_rgb_table(j_decompress_ptr cinfo)
METHODDEF(void) METHODDEF(void)
start_pass_merged_upsample(j_decompress_ptr cinfo) start_pass_merged_upsample(j_decompress_ptr cinfo)
{ {
my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample; my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
/* Mark the spare buffer empty */ /* Mark the spare buffer empty */
upsample->spare_full = FALSE; upsample->spare_full = FALSE;
@@ -254,7 +226,7 @@ merged_2v_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail) JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
/* 2:1 vertical sampling case: may need a spare row. */ /* 2:1 vertical sampling case: may need a spare row. */
{ {
my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample; my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
JSAMPROW work_ptrs[2]; JSAMPROW work_ptrs[2];
JDIMENSION num_rows; /* number of rows returned to caller */ JDIMENSION num_rows; /* number of rows returned to caller */
@@ -305,7 +277,7 @@ merged_1v_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail) JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
/* 1:1 vertical sampling case: much easier, never need a spare row. */ /* 1:1 vertical sampling case: much easier, never need a spare row. */
{ {
my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample; my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
/* Just do the upsampling. */ /* Just do the upsampling. */
(*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr,
@@ -566,11 +538,11 @@ h2v2_merged_upsample_565D(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
GLOBAL(void) GLOBAL(void)
jinit_merged_upsampler(j_decompress_ptr cinfo) jinit_merged_upsampler(j_decompress_ptr cinfo)
{ {
my_upsample_ptr upsample; my_merged_upsample_ptr upsample;
upsample = (my_upsample_ptr) upsample = (my_merged_upsample_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_upsampler)); sizeof(my_merged_upsampler));
cinfo->upsample = (struct jpeg_upsampler *)upsample; cinfo->upsample = (struct jpeg_upsampler *)upsample;
upsample->pub.start_pass = start_pass_merged_upsample; upsample->pub.start_pass = start_pass_merged_upsample;
upsample->pub.need_context_rows = FALSE; upsample->pub.need_context_rows = FALSE;

47
jdmerge.h Normal file
View File

@@ -0,0 +1,47 @@
/*
* jdmerge.h
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2020, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*/
#define JPEG_INTERNALS
#include "jpeglib.h"
#ifdef UPSAMPLE_MERGING_SUPPORTED
/* Private subobject */
typedef struct {
struct jpeg_upsampler pub; /* public fields */
/* Pointer to routine to do actual upsampling/conversion of one row group */
void (*upmethod) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
/* Private state for YCC->RGB conversion */
int *Cr_r_tab; /* => table for Cr to R conversion */
int *Cb_b_tab; /* => table for Cb to B conversion */
JLONG *Cr_g_tab; /* => table for Cr to G conversion */
JLONG *Cb_g_tab; /* => table for Cb to G conversion */
/* For 2:1 vertical sampling, we produce two output rows at a time.
* We need a "spare" row buffer to hold the second output row if the
* application provides just a one-row buffer; we also use the spare
* to discard the dummy last row if the image height is odd.
*/
JSAMPROW spare_row;
boolean spare_full; /* T if spare buffer is occupied */
JDIMENSION out_row_width; /* samples per output row */
JDIMENSION rows_to_go; /* counts rows remaining in image */
} my_merged_upsampler;
typedef my_merged_upsampler *my_merged_upsample_ptr;
#endif /* UPSAMPLE_MERGING_SUPPORTED */

View File

@@ -5,7 +5,7 @@
* Copyright (C) 1994-1996, Thomas G. Lane. * Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications: * libjpeg-turbo Modifications:
* Copyright (C) 2013, Linaro Limited. * Copyright (C) 2013, Linaro Limited.
* Copyright (C) 2014-2015, 2018, D. R. Commander. * Copyright (C) 2014-2015, 2018, 2020, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg * For conditions of distribution and use, see the accompanying README.ijg
* file. * file.
* *
@@ -19,7 +19,7 @@ h2v1_merged_upsample_565_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
JDIMENSION in_row_group_ctr, JDIMENSION in_row_group_ctr,
JSAMPARRAY output_buf) JSAMPARRAY output_buf)
{ {
my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample; my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
register int y, cred, cgreen, cblue; register int y, cred, cgreen, cblue;
int cb, cr; int cb, cr;
register JSAMPROW outptr; register JSAMPROW outptr;
@@ -90,7 +90,7 @@ h2v1_merged_upsample_565D_internal(j_decompress_ptr cinfo,
JDIMENSION in_row_group_ctr, JDIMENSION in_row_group_ctr,
JSAMPARRAY output_buf) JSAMPARRAY output_buf)
{ {
my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample; my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
register int y, cred, cgreen, cblue; register int y, cred, cgreen, cblue;
int cb, cr; int cb, cr;
register JSAMPROW outptr; register JSAMPROW outptr;
@@ -163,7 +163,7 @@ h2v2_merged_upsample_565_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
JDIMENSION in_row_group_ctr, JDIMENSION in_row_group_ctr,
JSAMPARRAY output_buf) JSAMPARRAY output_buf)
{ {
my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample; my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
register int y, cred, cgreen, cblue; register int y, cred, cgreen, cblue;
int cb, cr; int cb, cr;
register JSAMPROW outptr0, outptr1; register JSAMPROW outptr0, outptr1;
@@ -259,7 +259,7 @@ h2v2_merged_upsample_565D_internal(j_decompress_ptr cinfo,
JDIMENSION in_row_group_ctr, JDIMENSION in_row_group_ctr,
JSAMPARRAY output_buf) JSAMPARRAY output_buf)
{ {
my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample; my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
register int y, cred, cgreen, cblue; register int y, cred, cgreen, cblue;
int cb, cr; int cb, cr;
register JSAMPROW outptr0, outptr1; register JSAMPROW outptr0, outptr1;

View File

@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane. * Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications: * libjpeg-turbo Modifications:
* Copyright (C) 2011, 2015, D. R. Commander. * Copyright (C) 2011, 2015, 2020, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg * For conditions of distribution and use, see the accompanying README.ijg
* file. * file.
* *
@@ -25,7 +25,7 @@ h2v1_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
JDIMENSION in_row_group_ctr, JDIMENSION in_row_group_ctr,
JSAMPARRAY output_buf) JSAMPARRAY output_buf)
{ {
my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample; my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
register int y, cred, cgreen, cblue; register int y, cred, cgreen, cblue;
int cb, cr; int cb, cr;
register JSAMPROW outptr; register JSAMPROW outptr;
@@ -97,7 +97,7 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
JDIMENSION in_row_group_ctr, JDIMENSION in_row_group_ctr,
JSAMPARRAY output_buf) JSAMPARRAY output_buf)
{ {
my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample; my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
register int y, cred, cgreen, cblue; register int y, cred, cgreen, cblue;
int cb, cr; int cb, cr;
register JSAMPROW outptr0, outptr1; register JSAMPROW outptr0, outptr1;

View File

@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane. * Copyright (C) 1991-1996, Thomas G. Lane.
* libjpeg-turbo Modifications: * libjpeg-turbo Modifications:
* Copyright (C) 2009, 2014-2015, D. R. Commander. * Copyright (C) 2009, 2014-2015, 2020, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg * For conditions of distribution and use, see the accompanying README.ijg
* file. * file.
* *
@@ -1145,7 +1145,7 @@ start_pass_2_quant(j_decompress_ptr cinfo, boolean is_pre_scan)
int i; int i;
/* Only F-S dithering or no dithering is supported. */ /* Only F-S dithering or no dithering is supported. */
/* If user asks for ordered dither, give him F-S. */ /* If user asks for ordered dither, give them F-S. */
if (cinfo->dither_mode != JDITHER_NONE) if (cinfo->dither_mode != JDITHER_NONE)
cinfo->dither_mode = JDITHER_FS; cinfo->dither_mode = JDITHER_FS;
@@ -1263,7 +1263,7 @@ jinit_2pass_quantizer(j_decompress_ptr cinfo)
cquantize->sv_colormap = NULL; cquantize->sv_colormap = NULL;
/* Only F-S dithering or no dithering is supported. */ /* Only F-S dithering or no dithering is supported. */
/* If user asks for ordered dither, give him F-S. */ /* If user asks for ordered dither, give them F-S. */
if (cinfo->dither_mode != JDITHER_NONE) if (cinfo->dither_mode != JDITHER_NONE)
cinfo->dither_mode = JDITHER_FS; cinfo->dither_mode = JDITHER_FS;

View File

@@ -3,7 +3,7 @@ USING THE IJG JPEG LIBRARY
This file was part of the Independent JPEG Group's software: This file was part of the Independent JPEG Group's software:
Copyright (C) 1994-2013, Thomas G. Lane, Guido Vollbeding. Copyright (C) 1994-2013, Thomas G. Lane, Guido Vollbeding.
libjpeg-turbo Modifications: libjpeg-turbo Modifications:
Copyright (C) 2010, 2014-2018, D. R. Commander. Copyright (C) 2010, 2014-2018, 2020, D. R. Commander.
Copyright (C) 2015, Google, Inc. Copyright (C) 2015, Google, Inc.
For conditions of distribution and use, see the accompanying README.ijg file. For conditions of distribution and use, see the accompanying README.ijg file.
@@ -750,7 +750,9 @@ multiple rows in the JPEG image.
Suspending data sources are not supported by this function. Calling Suspending data sources are not supported by this function. Calling
jpeg_skip_scanlines() with a suspending data source will result in undefined jpeg_skip_scanlines() with a suspending data source will result in undefined
behavior. behavior. Two-pass color quantization is also not supported by this function.
Calling jpeg_skip_scanlines() with two-pass color quantization enabled will
result in an error.
jpeg_skip_scanlines() will not allow skipping past the bottom of the image. If jpeg_skip_scanlines() will not allow skipping past the bottom of the image. If
the value of num_lines is large enough to skip past the bottom of the image, the value of num_lines is large enough to skip past the bottom of the image,

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C)2011-2019 D. R. Commander. All Rights Reserved. * Copyright (C)2011-2020 D. R. Commander. All Rights Reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@@ -326,9 +326,11 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFrom
tjhandle handle = 0; tjhandle handle = 0;
unsigned long jpegSize = 0; unsigned long jpegSize = 0;
jbyteArray jSrcPlanes[3] = { NULL, NULL, NULL }; jbyteArray jSrcPlanes[3] = { NULL, NULL, NULL };
const unsigned char *srcPlanes[3]; const unsigned char *srcPlanesTmp[3] = { NULL, NULL, NULL };
const unsigned char *srcPlanes[3] = { NULL, NULL, NULL };
int *srcOffsetsTmp = NULL, srcOffsets[3] = { 0, 0, 0 };
int *srcStridesTmp = NULL, srcStrides[3] = { 0, 0, 0 };
unsigned char *jpegBuf = NULL; unsigned char *jpegBuf = NULL;
int *srcOffsets = NULL, *srcStrides = NULL;
int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i; int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i;
GET_HANDLE(); GET_HANDLE();
@@ -351,56 +353,49 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFrom
if (ProcessSystemProperties(env) < 0) goto bailout; if (ProcessSystemProperties(env) < 0) goto bailout;
#define RELEASE_ARRAYS_COMPRESSFROMYUV() { \ BAILIF0(srcOffsetsTmp =
SAFE_RELEASE(dst, jpegBuf); \ (*env)->GetPrimitiveArrayCritical(env, jSrcOffsets, 0));
for (i = 0; i < nc; i++) \ for (i = 0; i < nc; i++) srcOffsets[i] = srcOffsetsTmp[i];
SAFE_RELEASE(jSrcPlanes[i], srcPlanes[i]); \ SAFE_RELEASE(jSrcOffsets, srcOffsetsTmp);
SAFE_RELEASE(jSrcStrides, srcStrides); \
SAFE_RELEASE(jSrcOffsets, srcOffsets); \ BAILIF0(srcStridesTmp =
} (*env)->GetPrimitiveArrayCritical(env, jSrcStrides, 0));
for (i = 0; i < nc; i++) srcStrides[i] = srcStridesTmp[i];
SAFE_RELEASE(jSrcStrides, srcStridesTmp);
BAILIF0(srcOffsets = (*env)->GetPrimitiveArrayCritical(env, jSrcOffsets, 0));
BAILIF0(srcStrides = (*env)->GetPrimitiveArrayCritical(env, jSrcStrides, 0));
for (i = 0; i < nc; i++) { for (i = 0; i < nc; i++) {
int planeSize = tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp); int planeSize = tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp);
int pw = tjPlaneWidth(i, width, subsamp); int pw = tjPlaneWidth(i, width, subsamp);
if (planeSize < 0 || pw < 0) { if (planeSize < 0 || pw < 0)
RELEASE_ARRAYS_COMPRESSFROMYUV();
THROW_ARG(tjGetErrorStr()); THROW_ARG(tjGetErrorStr());
}
if (srcOffsets[i] < 0) { if (srcOffsets[i] < 0)
RELEASE_ARRAYS_COMPRESSFROMYUV();
THROW_ARG("Invalid argument in compressFromYUV()"); THROW_ARG("Invalid argument in compressFromYUV()");
} if (srcStrides[i] < 0 && srcOffsets[i] - planeSize + pw < 0)
if (srcStrides[i] < 0 && srcOffsets[i] - planeSize + pw < 0) {
RELEASE_ARRAYS_COMPRESSFROMYUV();
THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary"); THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
}
BAILIF0(jSrcPlanes[i] = (*env)->GetObjectArrayElement(env, srcobjs, i)); BAILIF0(jSrcPlanes[i] = (*env)->GetObjectArrayElement(env, srcobjs, i));
if ((*env)->GetArrayLength(env, jSrcPlanes[i]) < if ((*env)->GetArrayLength(env, jSrcPlanes[i]) <
srcOffsets[i] + planeSize) { srcOffsets[i] + planeSize)
RELEASE_ARRAYS_COMPRESSFROMYUV();
THROW_ARG("Source plane is not large enough"); THROW_ARG("Source plane is not large enough");
}
BAILIF0(srcPlanes[i] = BAILIF0(srcPlanesTmp[i] =
(*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 0)); (*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 0));
srcPlanes[i] = &srcPlanes[i][srcOffsets[i]]; srcPlanes[i] = &srcPlanesTmp[i][srcOffsets[i]];
SAFE_RELEASE(jSrcPlanes[i], srcPlanesTmp[i]);
} }
BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0)); BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
if (tjCompressFromYUVPlanes(handle, srcPlanes, width, srcStrides, height, if (tjCompressFromYUVPlanes(handle, srcPlanes, width, srcStrides, height,
subsamp, &jpegBuf, &jpegSize, jpegQual, subsamp, &jpegBuf, &jpegSize, jpegQual,
flags | TJFLAG_NOREALLOC) == -1) { flags | TJFLAG_NOREALLOC) == -1) {
RELEASE_ARRAYS_COMPRESSFROMYUV(); SAFE_RELEASE(dst, jpegBuf);
THROW_TJ(); THROW_TJ();
} }
bailout: bailout:
RELEASE_ARRAYS_COMPRESSFROMYUV(); SAFE_RELEASE(dst, jpegBuf);
return (jint)jpegSize; return (jint)jpegSize;
} }
@@ -411,9 +406,12 @@ static void TJCompressor_encodeYUV
{ {
tjhandle handle = 0; tjhandle handle = 0;
jsize arraySize = 0, actualPitch; jsize arraySize = 0, actualPitch;
unsigned char *srcBuf = NULL;
jbyteArray jDstPlanes[3] = { NULL, NULL, NULL }; jbyteArray jDstPlanes[3] = { NULL, NULL, NULL };
unsigned char *srcBuf = NULL, *dstPlanes[3]; unsigned char *dstPlanesTmp[3] = { NULL, NULL, NULL };
int *dstOffsets = NULL, *dstStrides = NULL; unsigned char *dstPlanes[3] = { NULL, NULL, NULL };
int *dstOffsetsTmp = NULL, dstOffsets[3] = { 0, 0, 0 };
int *dstStridesTmp = NULL, dstStrides[3] = { 0, 0, 0 };
int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i; int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i;
GET_HANDLE(); GET_HANDLE();
@@ -438,56 +436,49 @@ static void TJCompressor_encodeYUV
if ((*env)->GetArrayLength(env, src) * srcElementSize < arraySize) if ((*env)->GetArrayLength(env, src) * srcElementSize < arraySize)
THROW_ARG("Source buffer is not large enough"); THROW_ARG("Source buffer is not large enough");
#define RELEASE_ARRAYS_ENCODEYUV() { \ BAILIF0(dstOffsetsTmp =
SAFE_RELEASE(src, srcBuf); \ (*env)->GetPrimitiveArrayCritical(env, jDstOffsets, 0));
for (i = 0; i < nc; i++) \ for (i = 0; i < nc; i++) dstOffsets[i] = dstOffsetsTmp[i];
SAFE_RELEASE(jDstPlanes[i], dstPlanes[i]); \ SAFE_RELEASE(jDstOffsets, dstOffsetsTmp);
SAFE_RELEASE(jDstStrides, dstStrides); \
SAFE_RELEASE(jDstOffsets, dstOffsets); \ BAILIF0(dstStridesTmp =
} (*env)->GetPrimitiveArrayCritical(env, jDstStrides, 0));
for (i = 0; i < nc; i++) dstStrides[i] = dstStridesTmp[i];
SAFE_RELEASE(jDstStrides, dstStridesTmp);
BAILIF0(dstOffsets = (*env)->GetPrimitiveArrayCritical(env, jDstOffsets, 0));
BAILIF0(dstStrides = (*env)->GetPrimitiveArrayCritical(env, jDstStrides, 0));
for (i = 0; i < nc; i++) { for (i = 0; i < nc; i++) {
int planeSize = tjPlaneSizeYUV(i, width, dstStrides[i], height, subsamp); int planeSize = tjPlaneSizeYUV(i, width, dstStrides[i], height, subsamp);
int pw = tjPlaneWidth(i, width, subsamp); int pw = tjPlaneWidth(i, width, subsamp);
if (planeSize < 0 || pw < 0) { if (planeSize < 0 || pw < 0)
RELEASE_ARRAYS_ENCODEYUV();
THROW_ARG(tjGetErrorStr()); THROW_ARG(tjGetErrorStr());
}
if (dstOffsets[i] < 0) { if (dstOffsets[i] < 0)
RELEASE_ARRAYS_ENCODEYUV();
THROW_ARG("Invalid argument in encodeYUV()"); THROW_ARG("Invalid argument in encodeYUV()");
} if (dstStrides[i] < 0 && dstOffsets[i] - planeSize + pw < 0)
if (dstStrides[i] < 0 && dstOffsets[i] - planeSize + pw < 0) {
RELEASE_ARRAYS_ENCODEYUV();
THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary"); THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
}
BAILIF0(jDstPlanes[i] = (*env)->GetObjectArrayElement(env, dstobjs, i)); BAILIF0(jDstPlanes[i] = (*env)->GetObjectArrayElement(env, dstobjs, i));
if ((*env)->GetArrayLength(env, jDstPlanes[i]) < if ((*env)->GetArrayLength(env, jDstPlanes[i]) <
dstOffsets[i] + planeSize) { dstOffsets[i] + planeSize)
RELEASE_ARRAYS_ENCODEYUV();
THROW_ARG("Destination plane is not large enough"); THROW_ARG("Destination plane is not large enough");
}
BAILIF0(dstPlanes[i] = BAILIF0(dstPlanesTmp[i] =
(*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 0)); (*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 0));
dstPlanes[i] = &dstPlanes[i][dstOffsets[i]]; dstPlanes[i] = &dstPlanesTmp[i][dstOffsets[i]];
SAFE_RELEASE(jDstPlanes[i], dstPlanesTmp[i]);
} }
BAILIF0(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0)); BAILIF0(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
if (tjEncodeYUVPlanes(handle, &srcBuf[y * actualPitch + x * tjPixelSize[pf]], if (tjEncodeYUVPlanes(handle, &srcBuf[y * actualPitch + x * tjPixelSize[pf]],
width, pitch, height, pf, dstPlanes, dstStrides, width, pitch, height, pf, dstPlanes, dstStrides,
subsamp, flags) == -1) { subsamp, flags) == -1) {
RELEASE_ARRAYS_ENCODEYUV(); SAFE_RELEASE(src, srcBuf);
THROW_TJ(); THROW_TJ();
} }
bailout: bailout:
RELEASE_ARRAYS_ENCODEYUV(); SAFE_RELEASE(src, srcBuf);
} }
/* TurboJPEG 1.4.x: TJCompressor::encodeYUV() byte source */ /* TurboJPEG 1.4.x: TJCompressor::encodeYUV() byte source */
@@ -785,9 +776,12 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress
jintArray jDstStrides, jint desiredHeight, jint flags) jintArray jDstStrides, jint desiredHeight, jint flags)
{ {
tjhandle handle = 0; tjhandle handle = 0;
unsigned char *jpegBuf = NULL;
jbyteArray jDstPlanes[3] = { NULL, NULL, NULL }; jbyteArray jDstPlanes[3] = { NULL, NULL, NULL };
unsigned char *jpegBuf = NULL, *dstPlanes[3]; unsigned char *dstPlanesTmp[3] = { NULL, NULL, NULL };
int *dstOffsets = NULL, *dstStrides = NULL; unsigned char *dstPlanes[3] = { NULL, NULL, NULL };
int *dstOffsetsTmp = NULL, dstOffsets[3] = { 0, 0, 0 };
int *dstStridesTmp = NULL, dstStrides[3] = { 0, 0, 0 };
int jpegSubsamp = -1, jpegWidth = 0, jpegHeight = 0; int jpegSubsamp = -1, jpegWidth = 0, jpegHeight = 0;
int nc = 0, i, width, height, scaledWidth, scaledHeight, nsf = 0; int nc = 0, i, width, height, scaledWidth, scaledHeight, nsf = 0;
tjscalingfactor *sf; tjscalingfactor *sf;
@@ -821,57 +815,50 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress
if (i >= nsf) if (i >= nsf)
THROW_ARG("Could not scale down to desired image dimensions"); THROW_ARG("Could not scale down to desired image dimensions");
#define RELEASE_ARRAYS_DECOMPRESSTOYUV() { \ BAILIF0(dstOffsetsTmp =
SAFE_RELEASE(src, jpegBuf); \ (*env)->GetPrimitiveArrayCritical(env, jDstOffsets, 0));
for (i = 0; i < nc; i++) \ for (i = 0; i < nc; i++) dstOffsets[i] = dstOffsetsTmp[i];
SAFE_RELEASE(jDstPlanes[i], dstPlanes[i]); \ SAFE_RELEASE(jDstOffsets, dstOffsetsTmp);
SAFE_RELEASE(jDstStrides, dstStrides); \
SAFE_RELEASE(jDstOffsets, dstOffsets); \ BAILIF0(dstStridesTmp =
} (*env)->GetPrimitiveArrayCritical(env, jDstStrides, 0));
for (i = 0; i < nc; i++) dstStrides[i] = dstStridesTmp[i];
SAFE_RELEASE(jDstStrides, dstStridesTmp);
BAILIF0(dstOffsets = (*env)->GetPrimitiveArrayCritical(env, jDstOffsets, 0));
BAILIF0(dstStrides = (*env)->GetPrimitiveArrayCritical(env, jDstStrides, 0));
for (i = 0; i < nc; i++) { for (i = 0; i < nc; i++) {
int planeSize = tjPlaneSizeYUV(i, scaledWidth, dstStrides[i], scaledHeight, int planeSize = tjPlaneSizeYUV(i, scaledWidth, dstStrides[i], scaledHeight,
jpegSubsamp); jpegSubsamp);
int pw = tjPlaneWidth(i, scaledWidth, jpegSubsamp); int pw = tjPlaneWidth(i, scaledWidth, jpegSubsamp);
if (planeSize < 0 || pw < 0) { if (planeSize < 0 || pw < 0)
RELEASE_ARRAYS_DECOMPRESSTOYUV();
THROW_ARG(tjGetErrorStr()); THROW_ARG(tjGetErrorStr());
}
if (dstOffsets[i] < 0) { if (dstOffsets[i] < 0)
RELEASE_ARRAYS_DECOMPRESSTOYUV();
THROW_ARG("Invalid argument in decompressToYUV()"); THROW_ARG("Invalid argument in decompressToYUV()");
} if (dstStrides[i] < 0 && dstOffsets[i] - planeSize + pw < 0)
if (dstStrides[i] < 0 && dstOffsets[i] - planeSize + pw < 0) {
RELEASE_ARRAYS_DECOMPRESSTOYUV();
THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary"); THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
}
BAILIF0(jDstPlanes[i] = (*env)->GetObjectArrayElement(env, dstobjs, i)); BAILIF0(jDstPlanes[i] = (*env)->GetObjectArrayElement(env, dstobjs, i));
if ((*env)->GetArrayLength(env, jDstPlanes[i]) < if ((*env)->GetArrayLength(env, jDstPlanes[i]) <
dstOffsets[i] + planeSize) { dstOffsets[i] + planeSize)
RELEASE_ARRAYS_DECOMPRESSTOYUV();
THROW_ARG("Destination plane is not large enough"); THROW_ARG("Destination plane is not large enough");
}
BAILIF0(dstPlanes[i] = BAILIF0(dstPlanesTmp[i] =
(*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 0)); (*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 0));
dstPlanes[i] = &dstPlanes[i][dstOffsets[i]]; dstPlanes[i] = &dstPlanesTmp[i][dstOffsets[i]];
SAFE_RELEASE(jDstPlanes[i], dstPlanesTmp[i]);
} }
BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0)); BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
if (tjDecompressToYUVPlanes(handle, jpegBuf, (unsigned long)jpegSize, if (tjDecompressToYUVPlanes(handle, jpegBuf, (unsigned long)jpegSize,
dstPlanes, desiredWidth, dstStrides, dstPlanes, desiredWidth, dstStrides,
desiredHeight, flags) == -1) { desiredHeight, flags) == -1) {
RELEASE_ARRAYS_DECOMPRESSTOYUV(); SAFE_RELEASE(src, jpegBuf);
THROW_TJ(); THROW_TJ();
} }
bailout: bailout:
RELEASE_ARRAYS_DECOMPRESSTOYUV(); SAFE_RELEASE(src, jpegBuf);
} }
/* TurboJPEG 1.2.x: TJDecompressor::decompressToYUV() */ /* TurboJPEG 1.2.x: TJDecompressor::decompressToYUV() */
@@ -920,9 +907,11 @@ static void TJDecompressor_decodeYUV
tjhandle handle = 0; tjhandle handle = 0;
jsize arraySize = 0, actualPitch; jsize arraySize = 0, actualPitch;
jbyteArray jSrcPlanes[3] = { NULL, NULL, NULL }; jbyteArray jSrcPlanes[3] = { NULL, NULL, NULL };
const unsigned char *srcPlanes[3]; const unsigned char *srcPlanesTmp[3] = { NULL, NULL, NULL };
const unsigned char *srcPlanes[3] = { NULL, NULL, NULL };
int *srcOffsetsTmp = NULL, srcOffsets[3] = { 0, 0, 0 };
int *srcStridesTmp = NULL, srcStrides[3] = { 0, 0, 0 };
unsigned char *dstBuf = NULL; unsigned char *dstBuf = NULL;
int *srcOffsets = NULL, *srcStrides = NULL;
int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i; int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i;
GET_HANDLE(); GET_HANDLE();
@@ -946,56 +935,49 @@ static void TJDecompressor_decodeYUV
if ((*env)->GetArrayLength(env, dst) * dstElementSize < arraySize) if ((*env)->GetArrayLength(env, dst) * dstElementSize < arraySize)
THROW_ARG("Destination buffer is not large enough"); THROW_ARG("Destination buffer is not large enough");
#define RELEASE_ARRAYS_DECODEYUV() { \ BAILIF0(srcOffsetsTmp =
SAFE_RELEASE(dst, dstBuf); \ (*env)->GetPrimitiveArrayCritical(env, jSrcOffsets, 0));
for (i = 0; i < nc; i++) \ for (i = 0; i < nc; i++) srcOffsets[i] = srcOffsetsTmp[i];
SAFE_RELEASE(jSrcPlanes[i], srcPlanes[i]); \ SAFE_RELEASE(jSrcOffsets, srcOffsetsTmp);
SAFE_RELEASE(jSrcStrides, srcStrides); \
SAFE_RELEASE(jSrcOffsets, srcOffsets); \ BAILIF0(srcStridesTmp =
} (*env)->GetPrimitiveArrayCritical(env, jSrcStrides, 0));
for (i = 0; i < nc; i++) srcStrides[i] = srcStridesTmp[i];
SAFE_RELEASE(jSrcStrides, srcStridesTmp);
BAILIF0(srcOffsets = (*env)->GetPrimitiveArrayCritical(env, jSrcOffsets, 0));
BAILIF0(srcStrides = (*env)->GetPrimitiveArrayCritical(env, jSrcStrides, 0));
for (i = 0; i < nc; i++) { for (i = 0; i < nc; i++) {
int planeSize = tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp); int planeSize = tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp);
int pw = tjPlaneWidth(i, width, subsamp); int pw = tjPlaneWidth(i, width, subsamp);
if (planeSize < 0 || pw < 0) { if (planeSize < 0 || pw < 0)
RELEASE_ARRAYS_DECODEYUV();
THROW_ARG(tjGetErrorStr()); THROW_ARG(tjGetErrorStr());
}
if (srcOffsets[i] < 0) { if (srcOffsets[i] < 0)
RELEASE_ARRAYS_DECODEYUV();
THROW_ARG("Invalid argument in decodeYUV()"); THROW_ARG("Invalid argument in decodeYUV()");
} if (srcStrides[i] < 0 && srcOffsets[i] - planeSize + pw < 0)
if (srcStrides[i] < 0 && srcOffsets[i] - planeSize + pw < 0) {
RELEASE_ARRAYS_DECODEYUV();
THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary"); THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
}
BAILIF0(jSrcPlanes[i] = (*env)->GetObjectArrayElement(env, srcobjs, i)); BAILIF0(jSrcPlanes[i] = (*env)->GetObjectArrayElement(env, srcobjs, i));
if ((*env)->GetArrayLength(env, jSrcPlanes[i]) < if ((*env)->GetArrayLength(env, jSrcPlanes[i]) <
srcOffsets[i] + planeSize) { srcOffsets[i] + planeSize)
RELEASE_ARRAYS_DECODEYUV();
THROW_ARG("Source plane is not large enough"); THROW_ARG("Source plane is not large enough");
}
BAILIF0(srcPlanes[i] = BAILIF0(srcPlanesTmp[i] =
(*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 0)); (*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 0));
srcPlanes[i] = &srcPlanes[i][srcOffsets[i]]; srcPlanes[i] = &srcPlanesTmp[i][srcOffsets[i]];
SAFE_RELEASE(jSrcPlanes[i], srcPlanesTmp[i]);
} }
BAILIF0(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0)); BAILIF0(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
if (tjDecodeYUVPlanes(handle, srcPlanes, srcStrides, subsamp, if (tjDecodeYUVPlanes(handle, srcPlanes, srcStrides, subsamp,
&dstBuf[y * actualPitch + x * tjPixelSize[pf]], width, &dstBuf[y * actualPitch + x * tjPixelSize[pf]], width,
pitch, height, pf, flags) == -1) { pitch, height, pf, flags) == -1) {
RELEASE_ARRAYS_DECODEYUV(); SAFE_RELEASE(dst, dstBuf);
THROW_TJ(); THROW_TJ();
} }
bailout: bailout:
RELEASE_ARRAYS_DECODEYUV(); SAFE_RELEASE(dst, dstBuf);
} }
/* TurboJPEG 1.4.x: TJDecompressor::decodeYUV() byte destination */ /* TurboJPEG 1.4.x: TJDecompressor::decodeYUV() byte destination */