From e87d43229452f1ef001b4b97862480beb90a4b09 Mon Sep 17 00:00:00 2001 From: Jiyong Min Date: Mon, 5 Sep 2016 09:15:19 +0900 Subject: [PATCH] Add pkg config and color picker feature for product TV Change-Id: I7c28cda7b8727039c9eb5af8aee6d3e6ef8c1a8b Signed-off-by: Jiyong Min --- Makefile.am | 2 +- bmp.c | 8 +++ configure.ac | 8 ++- jconfig.h.in | 2 + jdcoefct.c | 52 ++++++++++++++ jdmarker.c | 2 +- jdmerge.c | 22 ++++++ jpeglib.h | 21 +++++- jquant2.c | 8 +++ md5/md5hl.c | 12 ++-- packaging/libjpeg-turbo.spec | 5 ++ pkgconfig/Makefile.am | 16 +++++ pkgconfig/turbojpeg.pc.in | 11 +++ rdppm.c | 9 +++ simd/jsimd.h | 10 +++ simd/jsimd_arm.c | 21 ++++++ simd/jsimd_arm_neon.S | 158 +++++++++++++++++++++++++++++++++++++++++++ tjbench.c | 8 +++ tjunittest.c | 6 ++ 19 files changed, 373 insertions(+), 8 deletions(-) create mode 100755 pkgconfig/Makefile.am create mode 100755 pkgconfig/turbojpeg.pc.in diff --git a/Makefile.am b/Makefile.am index 3a12fde..c52a89b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,7 +38,7 @@ endif SUBDIRS = java - +SUBDIRS += pkgconfig if WITH_TURBOJPEG diff --git a/bmp.c b/bmp.c index 9950a7a..8594a39 100644 --- a/bmp.c +++ b/bmp.c @@ -68,8 +68,16 @@ static void my_output_message(j_common_ptr cinfo) #define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \ retval=-1; goto bailout;} +#if _USE_PRODUCT_TV +#define _throwunix(m) { \ + char err_str[256]; \ + strerror_r(errno, err_str, 256); \ + snprintf(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, \ + err_str); retval=-1; goto bailout;} +#else #define _throwunix(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, \ strerror(errno)); retval=-1; goto bailout;} +#endif static void pixelconvert(unsigned char *srcbuf, int srcpf, int srcbottomup, diff --git a/configure.ac b/configure.ac index 6a55474..619affc 100644 --- a/configure.ac +++ b/configure.ac @@ -99,8 +99,13 @@ if test "x${SUNCC}" = "xyes"; then fi fi +AC_CHECK_DECL([_TIZEN_PRODUCT_TV], [with_pkg_config="yes"], [with_pkg_config="no"]) +if test "x${with_pkg_config}" = "xyes"; then + AC_DEFINE_UNQUOTED(COLOR_PICKER_ENABLE, [1], [tizen coloer picker enable]) +else + AC_DEFINE_UNQUOTED(COLOR_PICKER_ENABLE, [0], [tizen coloer picker disable]) +fi # Checks for libraries. - # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([stddef.h stdlib.h locale.h string.h]) @@ -582,4 +587,5 @@ AC_CONFIG_FILES([libjpeg.map]) AC_CONFIG_FILES([Makefile simd/Makefile]) AC_CONFIG_FILES([java/Makefile]) AC_CONFIG_FILES([md5/Makefile]) +AC_CONFIG_FILES([pkgconfig/Makefile pkgconfig/turbojpeg.pc]) AC_OUTPUT diff --git a/jconfig.h.in b/jconfig.h.in index b99a87e..2225577 100644 --- a/jconfig.h.in +++ b/jconfig.h.in @@ -71,3 +71,5 @@ /* The size of `size_t', as computed by sizeof. */ #undef SIZEOF_SIZE_T + +#define COLOR_PICKER_ENABLE 0 diff --git a/jdcoefct.c b/jdcoefct.c index 199a628..d304b85 100644 --- a/jdcoefct.c +++ b/jdcoefct.c @@ -158,21 +158,73 @@ decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) JDIMENSION start_col, output_col; jpeg_component_info *compptr; inverse_DCT_method_ptr inverse_DCT; +#if _USE_PRODUCT_TV + /* region decoding. this limits decode to the set of blocks +- 1 outside + * bounding blocks around the desired region to decode */ + int blk1 = 0, blk2 = 0, skip = 0; + + if ((cinfo->region_w > 0) && (cinfo->region_h > 0)) { + int bsz_w = 0, bsz_h = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + if (compptr->MCU_sample_width > bsz_w) + bsz_w = compptr->MCU_sample_width; + if ((compptr->MCU_height * 8) > bsz_h) + bsz_h = compptr->MCU_height * 8; + } + int _region_y = (int)cinfo->region_y; + _region_y = (_region_y>>1)<<1; + if (((int)cinfo->output_scanline < (_region_y - bsz_h - 1)) || + ((int)cinfo->output_scanline > (_region_y + cinfo->region_h + bsz_h))) + skip = 1; + if (bsz_w != 0) + blk1 = (cinfo->region_x / bsz_w) - 1; + if (blk1 < 0) + blk1 = 0; + if (bsz_w != 0) + blk2 = ((cinfo->region_x + cinfo->region_w + bsz_w - 1) / bsz_w) + 1; + if (blk2 < 0) + blk2 = 0; + } +#endif /* Loop to process as much as one whole iMCU row */ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; yoffset++) { for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col; MCU_col_num++) { +#if _USE_PRODUCT_TV + /* see if we need to skip this MCU or not */ + if ((cinfo->region_w > 0) && (cinfo->region_h > 0)) { + if (!((MCU_col_num < blk1) || (MCU_col_num > blk2) || skip)) + skip = 0; + } + /* if we are not skipping this MCU, zero it ready for huffman decode */ + if (!skip) + jzero_far((void FAR *) coef->MCU_buffer[0], + (size_t) (cinfo->blocks_in_MCU * sizeof(JBLOCK))); +#endif /* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */ +#if _USE_PRODUCT_TV + jzero_far((void FAR *) coef->MCU_buffer[0], + (size_t) (cinfo->blocks_in_MCU * sizeof(JBLOCK))); +#else jzero_far((void *) coef->MCU_buffer[0], (size_t) (cinfo->blocks_in_MCU * sizeof(JBLOCK))); +#endif if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { /* Suspension forced; update state counters and exit */ coef->MCU_vert_offset = yoffset; coef->MCU_ctr = MCU_col_num; return JPEG_SUSPENDED; } +#if _USE_PRODUCT_TV + /* region decoding. this limits decode to the set of blocks +- 1 outside + * bounding blocks around the desired region to decode */ + if (skip) + continue; +#endif /* Determine where data should go in output_buf and do the IDCT thing. * We skip dummy blocks at the right and bottom edges (but blkn gets * incremented past them!). Note the inner loop relies on having diff --git a/jdmarker.c b/jdmarker.c index d1357af..2d99945 100644 --- a/jdmarker.c +++ b/jdmarker.c @@ -466,7 +466,7 @@ get_dht (j_decompress_ptr cinfo) /* Here we just do minimal validation of the counts to avoid walking * off the end of our table space. jdhuff.c will check more carefully. */ - if (count > 256 || ((INT32) count) > length) + if (count < 0 || count > 256 || ((INT32) count) > length) ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); for (i = 0; i < count; i++) diff --git a/jdmerge.c b/jdmerge.c index e13adb9..a630a36 100644 --- a/jdmerge.c +++ b/jdmerge.c @@ -257,17 +257,34 @@ merged_2v_upsample (j_decompress_ptr cinfo, my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; JSAMPROW work_ptrs[2]; JDIMENSION num_rows; /* number of rows returned to caller */ +#if _USE_PRODUCT_TV + int skip = 0; +#endif if (upsample->spare_full) { /* If we have a spare row saved from a previous cycle, just return it. */ JDIMENSION size = upsample->out_row_width; if (cinfo->out_color_space == JCS_RGB565) size = cinfo->output_width * 2; +#if _USE_PRODUCT_TV + jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0, + 1, upsample->out_row_width); +#else jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0, 1, size); +#endif num_rows = 1; upsample->spare_full = FALSE; } else { +#if _USE_PRODUCT_TV + int _region_y = (int)cinfo->region_y; + _region_y = (_region_y>>1)<<1; + if ((cinfo->region_w > 0) && (cinfo->region_h > 0)) { + if (((int)cinfo->output_scanline < _region_y) || + ((int)cinfo->output_scanline >= (_region_y + (int)cinfo->region_h))) + skip = 1; + } +#endif /* Figure number of rows to return to caller. */ num_rows = 2; /* Not more than the distance to the end of the image. */ @@ -286,7 +303,12 @@ merged_2v_upsample (j_decompress_ptr cinfo, upsample->spare_full = TRUE; } /* Now do the upsampling. */ +#if _USE_PRODUCT_TV + if (!skip) + (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs); +#else (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs); +#endif } /* Adjust counts */ diff --git a/jpeglib.h b/jpeglib.h index 9615c5d..24509ef 100644 --- a/jpeglib.h +++ b/jpeglib.h @@ -35,7 +35,6 @@ extern "C" { #endif #endif - /* Various constants determining the sizes of things. * All of these are specified by the JPEG standard, so don't change them * if you want to be compatible. @@ -289,6 +288,18 @@ typedef struct jpeg_common_struct * j_common_ptr; typedef struct jpeg_compress_struct * j_compress_ptr; typedef struct jpeg_decompress_struct * j_decompress_ptr; +typedef struct _Pick_Color_ +{ + unsigned int sumR; + unsigned int sumG; + unsigned int sumB; + int enablePickColor; + int perc; + int x1; + int y1; + int x2; + int y2; +}PickColor; /* Master record for a compression instance */ @@ -490,6 +501,10 @@ struct jpeg_decompress_struct { unsigned int scale_num, scale_denom; /* fraction by which to scale image */ +#if COLOR_PICKER_ENABLE == 1 + unsigned int region_x, region_y, region_w, region_h; /* if region_w && region_h > 0, then use this region to decode. scale above is done prior to region select */ +#endif + double output_gamma; /* image gamma wanted in output */ boolean buffered_image; /* TRUE=multiple output passes */ @@ -702,6 +717,10 @@ struct jpeg_decompress_struct { struct jpeg_upsampler * upsample; struct jpeg_color_deconverter * cconvert; struct jpeg_color_quantizer * cquantize; + +#if COLOR_PICKER_ENABLE == 1 + struct _Pick_Color_ *pick_color_data; +#endif }; diff --git a/jquant2.c b/jquant2.c index 291b4f1..5114368 100644 --- a/jquant2.c +++ b/jquant2.c @@ -508,9 +508,17 @@ compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor) } } +#if _USE_PRODUCT_TV + if(total != 0) { + cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total); + cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total); + cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total); + } +#else cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total); cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total); cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total); +#endif } diff --git a/md5/md5hl.c b/md5/md5hl.c index eaa41e2..9d89e3e 100644 --- a/md5/md5hl.c +++ b/md5/md5hl.c @@ -58,14 +58,18 @@ MD5FileChunk(const char *filename, char *buf, off_t ofs, off_t len) f = open(filename, O_RDONLY); if (f < 0) return 0; - if (fstat(f, &stbuf) < 0) - return 0; + if (fstat(f, &stbuf) < 0){ + close(f); + return 0; + } if (ofs > stbuf.st_size) ofs = stbuf.st_size; if ((len == 0) || (len > stbuf.st_size - ofs)) len = stbuf.st_size - ofs; - if (lseek(f, ofs, SEEK_SET) < 0) - return 0; + if (lseek(f, ofs, SEEK_SET) < 0){ + close(f); + return 0; + } n = len; i = 0; while (n > 0) { diff --git a/packaging/libjpeg-turbo.spec b/packaging/libjpeg-turbo.spec index c9a5d75..8ac24fd 100755 --- a/packaging/libjpeg-turbo.spec +++ b/packaging/libjpeg-turbo.spec @@ -64,6 +64,10 @@ files using the libjpeg library. cp %{SOURCE1001} . %build +%if "%{?TIZEN_PRODUCT_TV}" == "1" +echo "tizen_product_tv" +export CFLAGS="$CFLAGS -D_TIZEN_PRODUCT_TV -D_USE_PRODUCT_TV" +%endif autoreconf -fiv %configure --enable-shared --disable-static --with-jpeg8 make %{?_smp_mflags} @@ -111,6 +115,7 @@ rm -rf $RPM_BUILD_ROOT %files -n libjpeg-devel %defattr(-,root,root) %{_includedir}/*.h +%{_libdir}/pkgconfig/turbojpeg.pc %{_libdir}/libturbojpeg.so %{_libdir}/libjpeg.so %doc coderules.txt jconfig.txt libjpeg.txt structure.txt example.c diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am new file mode 100755 index 0000000..fdf5f17 --- /dev/null +++ b/pkgconfig/Makefile.am @@ -0,0 +1,16 @@ +pcfiles = turbojpeg.pc + +all-local: $(pcfiles) + +%.pc: %.pc + cp $< $@ + +pkgconfigdir= $(libdir)/pkgconfig +pkgconfig_DATA= $(pcfiles) + +CLEANFILES= $(pcfiles) + +pcinfiles= turbojpeg.pc.in + +EXTRA_DIST= $(pcinfiles) + diff --git a/pkgconfig/turbojpeg.pc.in b/pkgconfig/turbojpeg.pc.in new file mode 100755 index 0000000..df77158 --- /dev/null +++ b/pkgconfig/turbojpeg.pc.in @@ -0,0 +1,11 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libturbojpeg +Description: Loads and saves jpeg +Version: @VERSION@ +Libs: -L${libdir} -lturbojpeg +Libs.private: -lz -lm +Cflags: -I${includedir} diff --git a/rdppm.c b/rdppm.c index 2e9b54d..e3aa1fd 100644 --- a/rdppm.c +++ b/rdppm.c @@ -416,10 +416,19 @@ start_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, (size_t) (((long) maxval + 1L) * sizeof(JSAMPLE))); half_maxval = maxval / 2; +#if _USE_PRODUCT_TV + if(maxval > 0) { + for (val = 0; val <= (INT32) maxval; val++) { + /* The multiplication here must be done in 32 bits to avoid overflow */ + source->rescale[val] = (JSAMPLE) ((val*MAXJSAMPLE + half_maxval)/maxval); + } + } +#else for (val = 0; val <= (INT32) maxval; val++) { /* The multiplication here must be done in 32 bits to avoid overflow */ source->rescale[val] = (JSAMPLE) ((val*MAXJSAMPLE + half_maxval)/maxval); } +#endif } } diff --git a/simd/jsimd.h b/simd/jsimd.h index c5abd45..3905c97 100644 --- a/simd/jsimd.h +++ b/simd/jsimd.h @@ -676,3 +676,13 @@ extern const int jconst_idct_float_sse2[]; EXTERN(void) jsimd_idct_float_sse2 (void * dct_table, JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col); + +/* TIZEN_PRODUCT_TV */ +EXTERN(void) jsimd_pick_color + JPP((JSAMPARRAY output_buf, + void *pickColor, + JDIMENSION out_width)); + +EXTERN(void) jsimd_h2v1_fancy_upsample_neon + JPP((int max_v_samp_factor, JDIMENSION downsampled_width, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); diff --git a/simd/jsimd_arm.c b/simd/jsimd_arm.c index 4cbcf2d..d7460a0 100644 --- a/simd/jsimd_arm.c +++ b/simd/jsimd_arm.c @@ -25,6 +25,11 @@ #include #include +#if _USE_PRODUCT_TV +//Changes for JPEG GAMMA enhancement in thumbnail +#include +#endif + static unsigned int simd_support = ~0; #if defined(__linux__) || defined(ANDROID) || defined(__ANDROID__) @@ -273,8 +278,24 @@ jsimd_ycc_rgb_convert (j_decompress_ptr cinfo, break; } +#if _USE_PRODUCT_TV + if (simd_support & JSIMD_ARM_NEON) { + neonfct(cinfo->output_width, input_buf, input_row, output_buf, num_rows); + PickColor* pickColor = cinfo->pick_color_data; + if(pickColor && pickColor->enablePickColor && output_buf) { + int w = cinfo->output_width; + unsigned char *ptr = *output_buf; + if(pickColor->perc <= 0) { + w = pickColor->x2 - pickColor->x1 + 1; + ptr = (*output_buf) + (pickColor->x1 * 3); + } + jsimd_pick_color(ptr, pickColor, w); + } + } +#else if (simd_support & JSIMD_ARM_NEON) neonfct(cinfo->output_width, input_buf, input_row, output_buf, num_rows); +#endif } GLOBAL(void) diff --git a/simd/jsimd_arm_neon.S b/simd/jsimd_arm_neon.S index 4d9685b..cf51541 100644 --- a/simd/jsimd_arm_neon.S +++ b/simd/jsimd_arm_neon.S @@ -2437,3 +2437,161 @@ asm_function jsimd_h2v1_fancy_upsample_neon .purgem upsample16 .purgem upsample32 .purgem upsample_row + +#if _USE_PRODUCT_TV +asm_function jsimd_pick_color + +@ RGB_BUFFER .req r0 +@ RGB_RET .req r1 +@ OUTPUT_WIDTH .req r2 + + push {r3, r4, r5, lr} + vpush {d8-d15} + MOV r5, #0 + VDUP.32 d0, r5 + VDUP.32 d1, r5 + VDUP.32 d2, r5 + VDUP.32 d3, r5 + VDUP.32 d4, r5 + VDUP.32 d5, r5 + VDUP.32 d6, r5 + VDUP.32 d7, r5 + VDUP.32 d8, r5 + + CMP r2,#0x8 + BCC UNDER_8 + + CMP r2,#0x10 + BCC UNDER_16 + + VLD3.8 {d0, d2, d4}, [r0]! + VLD3.8 {d1, d3, d5}, [r0]! + + SUB r2, r2, #16 + VPADDL.U8 q0,q0 + VPADDL.U8 q1,q1 + VPADDL.U8 q2,q2 + + + PROCESS_LOOP: + + CMP r2, #0x10 + BCC LOOP_BREAK + + SUB r2, r2, #16 + CMP r2, #0 + BLT LOOP_BREAK + + VLD3.8 {d6, d8, d10}, [r0]! + VLD3.8 {d7, d9, d11}, [r0]! + + VPADAL.U8 q0,q3 + VPADAL.U8 q1,q4 + VPADAL.U8 q2,q5 + + B PROCESS_LOOP + + LOOP_BREAK: + + VPADDL.U16 q0, q0 + VPADDL.U16 q1, q1 + VPADDL.U16 q2, q2 + + VPADDL.U32 q0, q0 + VPADDL.U32 q1, q1 + VPADDL.U32 q2, q2 + + VADD.I64 d0, d0, d1 + VADD.I64 d2, d2, d3 + VADD.I64 d4, d4, d5 + + PROCESS_REST: + CMP r2, #8 + BLT PROCESS_U_8 @ignore less than 8 pixels as of now + + VLD3.8 {d6, d7, d8}, [r0]! + VPADDL.U8 d6, d6 + VPADDL.U8 d7, d7 + VPADDL.U8 d8, d8 + + VPADDL.U16 d6, d6 + VPADDL.U16 d7, d7 + VPADDL.U16 d8, d8 + + VPADDL.U32 d6, d6 + VPADDL.U32 d7, d7 + VPADDL.U32 d8, d8 + + VADD.I64 d0, d0, d6 + VADD.I64 d2, d2, d7 + VADD.I64 d4, d4, d8 + + SUB r2, r2, #8 + + PROCESS_U_8: + CMP r2, #4 + BLT PROCESS_U_4 + + VLD3.8 {d6[0], d7[0], d8[0]}, [r0]! + VLD3.8 {d6[1], d7[1], d8[1]}, [r0]! + VLD3.8 {d6[2], d7[2], d8[2]}, [r0]! + VLD3.8 {d6[3], d7[3], d8[3]}, [r0]! + + VPADDL.U8 d6, d6 + VPADDL.U8 d7, d7 + VPADDL.U8 d8, d8 + + VPADDL.U16 d6, d6 + VPADDL.U16 d7, d7 + VPADDL.U16 d8, d8 + + VADD.I64 d0, d0, d6 + VADD.I64 d2, d2, d7 + VADD.I64 d4, d4, d8 + + SUB r2, r2, #4 + + PROCESS_U_4: +@ CMP r2, #2 +@ BLT PROCESS_U_2 + + B STORE + + + UNDER_16: + + VLD3.8 {d0, d2, d4}, [r0]! + VPADDL.U8 d0, d0 + VPADDL.U8 d2, d2 + VPADDL.U8 d4, d4 + + VPADDL.U16 d0, d0 + VPADDL.U16 d2, d2 + VPADDL.U16 d4, d4 + + VPADDL.U32 d0, d0 + VPADDL.U32 d2, d2 + VPADDL.U32 d4, d4 + + B STORE + + STORE: + VMOV.U32 r3, d0[0] + LDR r4, [r1] + ADD r4, r4, r3 + STR r4, [r1] + + VMOV.U32 r3, d2[0] + LDR r4, [r1, #4] + ADD r4, r4, r3 + STR r4, [r1, #4] + + VMOV.U32 r3, d4[0] + LDR r4, [r1, #8] + ADD r4, r4, r3 + STR r4, [r1, #8] + + UNDER_8: + vpop {d8-d15} + pop {r3, r4, r5, pc} +#endif \ No newline at end of file diff --git a/tjbench.c b/tjbench.c index 29ed3d0..74cea6e 100644 --- a/tjbench.c +++ b/tjbench.c @@ -41,7 +41,15 @@ #define _throw(op, err) { \ printf("ERROR in line %d while %s:\n%s\n", __LINE__, op, err); \ retval=-1; goto bailout;} +#if _USE_PRODUCT_TV +#define _throwunix(m) { \ + char err_str[256]; \ + strerror_r(errno, err_str, 256); \ + _throw(m, err_str) \ +} +#else #define _throwunix(m) _throw(m, strerror(errno)) +#endif #define _throwtj(m) _throw(m, tjGetErrorStr()) #define _throwbmp(m) _throw(m, bmpgeterr()) diff --git a/tjunittest.c b/tjunittest.c index 0c81cbe..b89d8a9 100644 --- a/tjunittest.c +++ b/tjunittest.c @@ -383,7 +383,13 @@ void writeJPEG(unsigned char *jpegBuf, unsigned long jpegSize, char *filename) FILE *file=fopen(filename, "wb"); if(!file || fwrite(jpegBuf, jpegSize, 1, file)!=1) { +#if _USE_PRODUCT_TV + char err_str[256]; + strerror_r(errno, err_str, 256); + printf("ERROR: Could not write to %s.\n%s\n", filename, err_str); +#else printf("ERROR: Could not write to %s.\n%s\n", filename, strerror(errno)); +#endif bailout(); } -- 2.7.4