Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c7449c461 | ||
|
|
2906cbf6ed | ||
|
|
7b66e2fa25 | ||
|
|
5d332e6447 | ||
|
|
8d2a67c7dd | ||
|
|
a4871a16c6 | ||
|
|
e59db4fad5 | ||
|
|
d12ca848a2 | ||
|
|
030a805b5b | ||
|
|
0c48e5367b | ||
|
|
7448ab4e82 |
@@ -485,7 +485,7 @@ add_custom_target(installer
|
||||
makensis -nocd ${INST_DEFS} libmozjpeg.nsi
|
||||
DEPENDS jpeg jpeg-static turbojpeg turbojpeg-static rdjpgcom wrjpgcom
|
||||
cjpeg djpeg jpegtran tjbench ${JAVA_DEPEND}
|
||||
SOURCES libjpeg-turbo.nsi)
|
||||
SOURCES libmozjpeg.nsi)
|
||||
|
||||
install(TARGETS jpeg-static turbojpeg turbojpeg-static rdjpgcom wrjpgcom tjbench
|
||||
ARCHIVE DESTINATION lib
|
||||
|
||||
7
LICENSE.txt
Normal file
7
LICENSE.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the libmozjpeg Project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
10
Makefile.am
10
Makefile.am
@@ -84,7 +84,7 @@ endif
|
||||
|
||||
|
||||
bin_PROGRAMS = cjpeg djpeg jpegtran rdjpgcom wrjpgcom
|
||||
noinst_PROGRAMS = jcstest
|
||||
noinst_PROGRAMS = jcstest jpegyuv yuvjpeg
|
||||
|
||||
|
||||
if WITH_TURBOJPEG
|
||||
@@ -139,6 +139,14 @@ jcstest_SOURCES = jcstest.c
|
||||
|
||||
jcstest_LDADD = libjpeg.la
|
||||
|
||||
jpegyuv_SOURCES = jpegyuv.c
|
||||
|
||||
jpegyuv_LDADD = libjpeg.la
|
||||
|
||||
yuvjpeg_SOURCES = yuvjpeg.c
|
||||
|
||||
yuvjpeg_LDADD = libjpeg.la
|
||||
|
||||
dist_man1_MANS = cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 wrjpgcom.1
|
||||
|
||||
DOCS= coderules.txt jconfig.txt change.log rdrle.c wrrle.c BUILDING.txt \
|
||||
|
||||
13
README.md
13
README.md
@@ -1 +1,12 @@
|
||||
Mozilla JPEG encoder/decoder project.
|
||||
Mozilla JPEG Encoder Project
|
||||
============================
|
||||
|
||||
This project's goal is to reduce the size of JPEG files without reducing quality or compatibility with the vast majority of the world's deployed decoders.
|
||||
|
||||
The idea is to reduce transfer times for JPEGs on the Web, thus reducing page load times.
|
||||
|
||||
'mozjpeg' is not intended to be a general JPEG library replacement. It makes tradeoffs that are intended to benefit Web use cases and focuses solely on improving encoding. It is best used as part of a Web encoding workflow. For a general JPEG library (e.g. your system libjpeg), especially if you care about decoding, we recommend libjpeg-turbo.
|
||||
|
||||
For more information, see the project announcement:
|
||||
|
||||
https://blog.mozilla.org/research/2014/03/05/introducing-the-mozjpeg-project/
|
||||
|
||||
@@ -741,20 +741,21 @@ jpeg_search_progression (j_compress_ptr cinfo)
|
||||
GLOBAL(void)
|
||||
jpeg_simple_progression (j_compress_ptr cinfo)
|
||||
{
|
||||
int ncomps;
|
||||
int nscans;
|
||||
jpeg_scan_info * scanptr;
|
||||
|
||||
if (cinfo->optimize_scans) {
|
||||
if (jpeg_search_progression(cinfo) == TRUE)
|
||||
return;
|
||||
}
|
||||
|
||||
int ncomps = cinfo->num_components;
|
||||
int nscans;
|
||||
jpeg_scan_info * scanptr;
|
||||
|
||||
/* Safety check to ensure start_compress not called yet. */
|
||||
if (cinfo->global_state != CSTATE_START)
|
||||
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
|
||||
|
||||
/* Figure space needed for script. Calculation must match code below! */
|
||||
ncomps = cinfo->num_components;
|
||||
if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
|
||||
/* Custom script for YCbCr color images. */
|
||||
nscans = 10;
|
||||
|
||||
@@ -38,6 +38,10 @@ LOCAL(void) transencode_coef_controller
|
||||
GLOBAL(void)
|
||||
jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)
|
||||
{
|
||||
/* setting up scan optimisation pattern failed, disable scan optimisation */
|
||||
if (cinfo->num_scans_luma == 0)
|
||||
cinfo->optimize_scans = FALSE;
|
||||
|
||||
if (cinfo->global_state != CSTATE_START)
|
||||
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
|
||||
/* Mark all tables to be written */
|
||||
|
||||
138
jpegyuv.c
Normal file
138
jpegyuv.c
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Written by Josh Aas and Tim Terriberry
|
||||
* Copyright (c) 2013, Mozilla Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Mozilla Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Input: JPEG YUV 4:2:0 */
|
||||
/* Output: YUV 4:2:0 */
|
||||
|
||||
/* gcc -std=c99 jpegyuv.c -I/opt/local/include/ -L/opt/local/lib/ -ljpeg -o jpegyuv */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "jpeglib.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *jpg_path;
|
||||
const char *yuv_path;
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
FILE *jpg_fd;
|
||||
int width;
|
||||
int height;
|
||||
int yuv_size;
|
||||
JSAMPLE *image_buffer;
|
||||
JSAMPROW yrow_pointer[16];
|
||||
JSAMPROW cbrow_pointer[8];
|
||||
JSAMPROW crrow_pointer[8];
|
||||
JSAMPROW *plane_pointer[3];
|
||||
int y;
|
||||
FILE *yuv_fd;
|
||||
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Required arguments:\n");
|
||||
fprintf(stderr, "1. Path to JPG input file\n");
|
||||
fprintf(stderr, "2. Path to YUV output file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
|
||||
/* Will check these for validity when opening via 'fopen'. */
|
||||
jpg_path = argv[1];
|
||||
yuv_path = argv[2];
|
||||
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
jpeg_create_decompress(&cinfo);
|
||||
|
||||
jpg_fd = fopen(jpg_path, "rb");
|
||||
if (!jpg_fd) {
|
||||
fprintf(stderr, "Invalid path to JPEG file!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
jpeg_stdio_src(&cinfo, jpg_fd);
|
||||
|
||||
jpeg_read_header(&cinfo, TRUE);
|
||||
|
||||
cinfo.raw_data_out = TRUE;
|
||||
cinfo.do_fancy_upsampling = FALSE;
|
||||
|
||||
jpeg_start_decompress(&cinfo);
|
||||
|
||||
width = cinfo.output_width;
|
||||
height = cinfo.output_height;
|
||||
/* Right now we only support dimensions that are multiples of 16. */
|
||||
if ((width % 16) != 0 || (height % 16) != 0) {
|
||||
fprintf(stderr, "Image dimensions must be multiples of 16!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
yuv_size = (width * height) + (((width >> 1) * (height >> 1)) * 2);
|
||||
image_buffer = malloc(yuv_size);
|
||||
|
||||
plane_pointer[0] = yrow_pointer;
|
||||
plane_pointer[1] = cbrow_pointer;
|
||||
plane_pointer[2] = crrow_pointer;
|
||||
while (cinfo.output_scanline < cinfo.output_height) {
|
||||
for (y = 0; y < 16; y++) {
|
||||
yrow_pointer[y] = image_buffer + cinfo.image_width * (cinfo.output_scanline + y);
|
||||
}
|
||||
for (y = 0; y < 8; y++) {
|
||||
cbrow_pointer[y] = image_buffer + width * height +
|
||||
((width + 1) >> 1) * ((cinfo.output_scanline >> 1) + y);
|
||||
crrow_pointer[y] = image_buffer + width * height +
|
||||
((width + 1) >> 1) * ((height + 1) >> 1) +
|
||||
((width + 1) >> 1) * ((cinfo.output_scanline >> 1) + y);
|
||||
}
|
||||
jpeg_read_raw_data(&cinfo, plane_pointer, 16);
|
||||
}
|
||||
|
||||
jpeg_finish_decompress(&cinfo);
|
||||
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
|
||||
fclose(jpg_fd);
|
||||
|
||||
yuv_fd = fopen(yuv_path, "wb");
|
||||
if (!yuv_fd) {
|
||||
fprintf(stderr, "Invalid path to YUV file!");
|
||||
return 1;
|
||||
}
|
||||
if (fwrite(image_buffer, yuv_size, 1, yuv_fd)!=1) {
|
||||
fprintf(stderr, "Error writing yuv file\n");
|
||||
}
|
||||
fclose(yuv_fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
15
rd_average.sh
Executable file
15
rd_average.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [ $# == 0 ]; then
|
||||
echo "usage: OUTPUT=<label> $0 *.out"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TOTAL=total.out
|
||||
|
||||
if [ -n "$OUTPUT" ]; then
|
||||
TOTAL="$OUTPUT.out"
|
||||
fi
|
||||
|
||||
awk '{size[FNR]+=$2;bytes[FNR]+=$3;psnr[FNR]+=$2*$4;psnrhvs[FNR]+=$2*$5;ssim[FNR]+=$2*$6;fastssim[FNR]+=$2*$7;}END{for(i=1;i<=FNR;i++)print i-1,size[i],bytes[i],psnr[i]/size[i],psnrhvs[i]/size[i],ssim[i]/size[i],fastssim[i]/size[i];}' $@ > $TOTAL
|
||||
106
rd_collect.sh
Executable file
106
rd_collect.sh
Executable file
@@ -0,0 +1,106 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [ $# == 0 ]; then
|
||||
echo "usage: DAALA_ROOT=<daala_root> MOZJPEG_ROOT=<mozjpeg_root> $0 *.y4m"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z $MOZJPEG_ROOT ]; then
|
||||
MOZJPEG_ROOT=.
|
||||
fi
|
||||
|
||||
if [ -z $DAALA_ROOT ]; then
|
||||
echo "DAALA_ROOT not set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$PLANE" ]; then
|
||||
export PLANE=0
|
||||
fi
|
||||
|
||||
if [ $PLANE != 0 ] && [ $PLANE != 1 ] && [ $PLANE != 2 ]; then
|
||||
echo "Invalid plane $PLANE. Must be 0, 1 or 2."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$YUVJPEG" ]; then
|
||||
export YUVJPEG=$MOZJPEG_ROOT/yuvjpeg
|
||||
fi
|
||||
|
||||
if [ -z "$JPEGYUV" ]; then
|
||||
export JPEGYUV=$MOZJPEG_ROOT/jpegyuv
|
||||
fi
|
||||
|
||||
if [ ! -x "$YUVJPEG" ]; then
|
||||
echo "Executable not found YUVJPEG=$YUVJPEG"
|
||||
echo "Do you have the right MOZJPEG_ROOT=$MOZJPEG_ROOT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -x "$JPEGYUV" ]; then
|
||||
echo "Executable not found JPEGYUV=$JPEGYUV"
|
||||
echo "Do you have the right MOZJPEG_ROOT=$MOZJPEG_ROOT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# TODO refactor these out of the daala project into a metrics project
|
||||
|
||||
if [ -z "$YUV2YUV4MPEG" ]; then
|
||||
export YUV2YUV4MPEG=$DAALA_ROOT/tools/yuv2yuv4mpeg
|
||||
fi
|
||||
|
||||
if [ -z "$DUMP_PSNR" ]; then
|
||||
export DUMP_PSNR=$DAALA_ROOT/tools/dump_psnr
|
||||
fi
|
||||
|
||||
if [ -z "$DUMP_PSNRHVS" ]; then
|
||||
export DUMP_PSNRHVS=$DAALA_ROOT/tools/dump_psnrhvs
|
||||
fi
|
||||
|
||||
if [ -z "$DUMP_SSIM" ]; then
|
||||
export DUMP_SSIM=$DAALA_ROOT/tools/dump_ssim
|
||||
fi
|
||||
|
||||
if [ -z "$DUMP_FASTSSIM" ]; then
|
||||
export DUMP_FASTSSIM=$DAALA_ROOT/tools/dump_fastssim
|
||||
fi
|
||||
|
||||
if [ ! -x "$YUV2YUV4MPEG" ]; then
|
||||
echo "Executable not found YUV2YUV4MPEG=$YUV2YUV4MPEG"
|
||||
echo "Do you have the right DAALA_ROOT=$DAALA_ROOT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -x "$DUMP_PSNR" ]; then
|
||||
echo "Executable not found DUMP_PSNR=$DUMP_PSNR"
|
||||
echo "Do you have the right DAALA_ROOT=$DAALA_ROOT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -x "$DUMP_PSNRHVS" ]; then
|
||||
echo "Executable not found DUMP_PSNRHVS=$DUMP_PSNRHVS"
|
||||
echo "Do you have the right DAALA_ROOT=$DAALA_ROOT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -x "$DUMP_SSIM" ]; then
|
||||
echo "Executable not found DUMP_SSIM=$DUMP_SSIM"
|
||||
echo "Do you have the right DAALA_ROOT=$DAALA_ROOT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -x "$DUMP_FASTSSIM" ]; then
|
||||
echo "Executable not found DUMP_FASTSSIM=$DUMP_FASTSSIM"
|
||||
echo "Do you have the right DAALA_ROOT=$DAALA_ROOT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RD_COLLECT_SUB=$(dirname "$0")/rd_collect_sub.sh
|
||||
|
||||
if [ -z "$CORES" ]; then
|
||||
CORES=`grep -i processor /proc/cpuinfo | wc -l`
|
||||
#echo "CORES not set, using $CORES"
|
||||
fi
|
||||
|
||||
find $@ -type f -name "*.y4m" -print0 | xargs -0 -n1 -P$CORES $RD_COLLECT_SUB
|
||||
28
rd_collect_sub.sh
Executable file
28
rd_collect_sub.sh
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
FILE=$1
|
||||
|
||||
BASENAME=$(basename $FILE)
|
||||
rm $BASENAME.out 2> /dev/null || true
|
||||
echo $BASENAME
|
||||
tail -n+3 $FILE > $BASENAME-in.yuv
|
||||
WIDTH=$(head -1 $FILE | cut -d\ -f 2 | tr -d 'W')
|
||||
HEIGHT=$(head -1 $FILE | cut -d\ -f 3 | tr -d 'H')
|
||||
|
||||
for x in {0..100}; do
|
||||
$YUVJPEG $x "$WIDTH"x$HEIGHT $BASENAME-in.yuv $BASENAME.jpeg
|
||||
$JPEGYUV $BASENAME.jpeg $BASENAME.yuv
|
||||
$YUV2YUV4MPEG $BASENAME -w$WIDTH -h$HEIGHT -an0 -ad0 -c420mpeg2
|
||||
PIXELS=$(($WIDTH*$HEIGHT))
|
||||
SIZE=$(wc -c $BASENAME.jpeg | awk '{ print $1 }')
|
||||
PSNR=$($DUMP_PSNR $FILE $BASENAME.y4m 2> /dev/null | grep Total | tr -s ' ' | cut -d\ -f $((4+$PLANE*2)))
|
||||
PSNRHVS=$($DUMP_PSNRHVS $FILE $BASENAME.y4m 2> /dev/null | grep Total | tr -s ' ' | cut -d\ -f $((4+$PLANE*2)))
|
||||
SSIM=$($DUMP_SSIM $FILE $BASENAME.y4m 2> /dev/null | grep Total | tr -s ' ' | cut -d\ -f $((4+$PLANE*2)))
|
||||
FASTSSIM=$($DUMP_FASTSSIM -c $FILE $BASENAME.y4m 2> /dev/null | grep Total | tr -s ' ' | cut -d\ -f $((4+$PLANE*2)))
|
||||
rm $BASENAME.jpeg $BASENAME.yuv $BASENAME.y4m
|
||||
echo $x $PIXELS $SIZE $PSNR $PSNRHVS $SSIM $FASTSSIM >> $BASENAME.out
|
||||
#tail -1 $BASENAME.out
|
||||
done
|
||||
|
||||
rm $BASENAME-in.yuv
|
||||
47
rd_plot.sh
Executable file
47
rd_plot.sh
Executable file
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Use this to average data from multiple runs
|
||||
#awk '{size[FNR]+=$2;bytes[FNR]+=$3;psnr[FNR]+=$2*$4;psnrhvs[FNR]+=$2*$5;ssim[FNR]+=$2*$6;fastssim[FNR]+=$2*$7;}END{for(i=1;i<=FNR;i++)print i+1,size[i],bytes[i],psnr[i]/size[i],psnrhvs[i]/size[i],ssim[i]/size[i],fastssim[i]/size[i];}' *.out > total.out
|
||||
|
||||
if [ -n "$IMAGE" ]; then
|
||||
IMAGE="$IMAGE-"
|
||||
fi
|
||||
|
||||
if [ $# == 0 ]; then
|
||||
echo "usage: IMAGE=<prefix> $0 *.out"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$GNUPLOT" -a -n "`type -p gnuplot`" ]; then
|
||||
GNUPLOT=`type -p gnuplot`
|
||||
fi
|
||||
if [ ! -x "$GNUPLOT" ]; then
|
||||
echo "Executable not found GNUPLOT=$GNUPLOT"
|
||||
echo "Please install it or set GNUPLOT to point to an installed copy"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CMDS="$CMDS set term pngcairo dashed size 1024,768;"
|
||||
CMDS="$CMDS set log x;"
|
||||
CMDS="$CMDS set xlabel 'Bits/Pixel';"
|
||||
CMDS="$CMDS set ylabel 'dB';"
|
||||
CMDS="$CMDS set key bot right;"
|
||||
|
||||
for FILE in "$@"; do
|
||||
BASENAME=$(basename $FILE)
|
||||
PSNR="$PSNR $PREFIX '$FILE' using (\$3*8/\$2):4 with lines title '${BASENAME%.*} (PSNR)'"
|
||||
PSNRHVS="$PSNRHVS $PREFIX '$FILE' using (\$3*8/\$2):5 with lines title '${BASENAME%.*} (PSNR-HVS)'"
|
||||
SSIM="$SSIM $PREFIX '$FILE' using (\$3*8/\$2):6 with lines title '${BASENAME%.*} (SSIM)'"
|
||||
FASTSSIM="$FASTSSIM $PREFIX '$FILE' using (\$3*8/\$2):7 with lines title '${BASENAME%.*} (FAST SSIM)'"
|
||||
PREFIX=","
|
||||
done
|
||||
|
||||
SUFFIX="psnr.png"
|
||||
$GNUPLOT -e "$CMDS set output \"$IMAGE$SUFFIX\"; plot $PSNR;" 2> /dev/null
|
||||
SUFFIX="psnrhvs.png"
|
||||
$GNUPLOT -e "$CMDS set output \"$IMAGE$SUFFIX\"; plot $PSNRHVS;" 2> /dev/null
|
||||
SUFFIX="ssim.png"
|
||||
$GNUPLOT -e "$CMDS set output \"$IMAGE$SUFFIX\"; plot $SSIM;" 2> /dev/null
|
||||
SUFFIX="fastssim.png"
|
||||
$GNUPLOT -e "$CMDS set output \"$IMAGE$SUFFIX\"; plot $FASTSSIM;" 2> /dev/null
|
||||
@@ -208,6 +208,10 @@ static int setCompDefaults(struct jpeg_compress_struct *cinfo,
|
||||
jpeg_set_colorspace(cinfo, JCS_YCCK);
|
||||
else jpeg_set_colorspace(cinfo, JCS_YCbCr);
|
||||
|
||||
/* Set scan pattern again as colorspace might have changed */
|
||||
if (cinfo->use_moz_defaults)
|
||||
jpeg_simple_progression(cinfo);
|
||||
|
||||
cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
|
||||
cinfo->comp_info[1].h_samp_factor=1;
|
||||
cinfo->comp_info[2].h_samp_factor=1;
|
||||
|
||||
196
yuvjpeg.c
Normal file
196
yuvjpeg.c
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Written by Josh Aas and Tim Terriberry
|
||||
* Copyright (c) 2013, Mozilla Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Mozilla Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Expects 4:2:0 YCbCr */
|
||||
|
||||
/* gcc -std=c99 yuvjpeg.c -I/opt/local/include/ -L/opt/local/lib/ -ljpeg -o yuvjpeg */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "jpeglib.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
long quality;
|
||||
const char *size;
|
||||
char *x;
|
||||
long width;
|
||||
long height;
|
||||
const char *yuv_path;
|
||||
const char *jpg_path;
|
||||
FILE *yuv_fd;
|
||||
size_t yuv_size;
|
||||
JSAMPLE *image_buffer;
|
||||
struct jpeg_compress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
FILE *jpg_fd;
|
||||
JSAMPROW yrow_pointer[16];
|
||||
JSAMPROW cbrow_pointer[8];
|
||||
JSAMPROW crrow_pointer[8];
|
||||
JSAMPROW *plane_pointer[3];
|
||||
int y;
|
||||
|
||||
if (argc != 5) {
|
||||
fprintf(stderr, "Required arguments:\n");
|
||||
fprintf(stderr, "1. JPEG quality value, 0-100\n");
|
||||
fprintf(stderr, "2. Image size (e.g. '512x512'\n");
|
||||
fprintf(stderr, "3. Path to YUV input file\n");
|
||||
fprintf(stderr, "4. Path to JPG output file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
|
||||
quality = strtol(argv[1], NULL, 10);
|
||||
if (errno != 0 || quality < 0 || quality > 100) {
|
||||
fprintf(stderr, "Invalid JPEG quality value!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
size = argv[2];
|
||||
x = strchr(size, 'x');
|
||||
if (!x && x != size && x != (x + strlen(x) - 1)) {
|
||||
fprintf(stderr, "Invalid image size input!\n");
|
||||
return 1;
|
||||
}
|
||||
width = strtol(size, NULL, 10);
|
||||
if (errno != 0) {
|
||||
fprintf(stderr, "Invalid image size input!\n");
|
||||
return 1;
|
||||
}
|
||||
height = strtol(x + 1, NULL, 10);
|
||||
if (errno != 0) {
|
||||
fprintf(stderr, "Invalid image size input!\n");
|
||||
return 1;
|
||||
}
|
||||
/* Right now we only support dimensions that are multiples of 16. */
|
||||
if ((width % 16) != 0 || (height % 16) != 0) {
|
||||
fprintf(stderr, "Image dimensions must be multiples of 16!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Will check these for validity when opening via 'fopen'. */
|
||||
yuv_path = argv[3];
|
||||
jpg_path = argv[4];
|
||||
|
||||
yuv_fd = fopen(yuv_path, "r");
|
||||
if (!yuv_fd) {
|
||||
fprintf(stderr, "Invalid path to YUV file!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fseek(yuv_fd, 0, SEEK_END);
|
||||
yuv_size = ftell(yuv_fd);
|
||||
fseek(yuv_fd, 0, SEEK_SET);
|
||||
image_buffer = malloc(yuv_size);
|
||||
if (fread(image_buffer, yuv_size, 1, yuv_fd)!=1) {
|
||||
fprintf(stderr, "Error reading yuv file\n");
|
||||
};
|
||||
|
||||
fclose(yuv_fd);
|
||||
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
jpeg_create_compress(&cinfo);
|
||||
|
||||
jpg_fd = fopen(jpg_path, "wb");
|
||||
if (!jpg_fd) {
|
||||
fprintf(stderr, "Invalid path to JPEG file!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
jpeg_stdio_dest(&cinfo, jpg_fd);
|
||||
|
||||
cinfo.image_width = width;
|
||||
cinfo.image_height = height;
|
||||
cinfo.input_components = 3;
|
||||
|
||||
cinfo.in_color_space = JCS_YCbCr;
|
||||
cinfo.use_moz_defaults = TRUE;
|
||||
jpeg_set_defaults(&cinfo);
|
||||
|
||||
cinfo.raw_data_in = TRUE;
|
||||
#if JPEG_LIB_VERSION >= 70
|
||||
cinfo.do_fancy_downsampling = FALSE;
|
||||
#endif
|
||||
|
||||
cinfo.comp_info[0].h_samp_factor = 2;
|
||||
cinfo.comp_info[0].v_samp_factor = 2;
|
||||
cinfo.comp_info[0].dc_tbl_no = 0;
|
||||
cinfo.comp_info[0].ac_tbl_no = 0;
|
||||
cinfo.comp_info[0].quant_tbl_no = 0;
|
||||
|
||||
cinfo.comp_info[1].h_samp_factor = 1;
|
||||
cinfo.comp_info[1].v_samp_factor = 1;
|
||||
cinfo.comp_info[1].dc_tbl_no = 1;
|
||||
cinfo.comp_info[1].ac_tbl_no = 1;
|
||||
cinfo.comp_info[1].quant_tbl_no = 1;
|
||||
|
||||
cinfo.comp_info[2].h_samp_factor = 1;
|
||||
cinfo.comp_info[2].v_samp_factor = 1;
|
||||
cinfo.comp_info[2].dc_tbl_no = 1;
|
||||
cinfo.comp_info[2].ac_tbl_no = 1;
|
||||
cinfo.comp_info[2].quant_tbl_no = 1;
|
||||
|
||||
jpeg_set_quality(&cinfo, quality, TRUE);
|
||||
cinfo.optimize_coding = TRUE;
|
||||
|
||||
jpeg_start_compress(&cinfo, TRUE);
|
||||
|
||||
plane_pointer[0] = yrow_pointer;
|
||||
plane_pointer[1] = cbrow_pointer;
|
||||
plane_pointer[2] = crrow_pointer;
|
||||
while (cinfo.next_scanline < cinfo.image_height) {
|
||||
for (y = 0; y < 16; y++) {
|
||||
yrow_pointer[y] = image_buffer + cinfo.image_width * (cinfo.next_scanline + y);
|
||||
}
|
||||
for (y = 0; y < 8; y++) {
|
||||
cbrow_pointer[y] = image_buffer + width * height +
|
||||
((width + 1) >> 1) * ((cinfo.next_scanline >> 1) + y);
|
||||
crrow_pointer[y] = image_buffer + width * height +
|
||||
((width + 1) >> 1) * ((height + 1) >> 1) +
|
||||
((width + 1) >> 1) * ((cinfo.next_scanline >> 1) + y);
|
||||
}
|
||||
jpeg_write_raw_data(&cinfo, plane_pointer, 16);
|
||||
}
|
||||
|
||||
jpeg_finish_compress(&cinfo);
|
||||
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
|
||||
free(image_buffer);
|
||||
|
||||
fclose(jpg_fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user