diff --git a/src/jni/jpeg/Android.mk b/src/jni/jpeg/Android.mk old mode 100644 new mode 100755 index cba26b1d52..65bb7e2b2c --- a/src/jni/jpeg/Android.mk +++ b/src/jni/jpeg/Android.mk @@ -1,37 +1,79 @@ -LOCAL_PATH:= $(call my-dir) +LOCAL_PATH := $(my-dir) include $(CLEAR_VARS) LOCAL_ARM_MODE := arm +# Set ANDROID_JPEG_USE_VENUM to true to enable VeNum optimizations +ANDROID_JPEG_USE_VENUM := true + +# Disable VeNum optimizations if they are not supported on the build target +ifneq ($(ARCH_ARM_HAVE_VFP),true) +ANDROID_JPEG_USE_VENUM := false +else +ifneq ($(ARCH_ARM_HAVE_NEON),true) +ANDROID_JPEG_USE_VENUM := false +endif +endif + LOCAL_SRC_FILES := \ + de_mjpegsample_NativeJpegLib.c \ jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \ jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \ jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \ jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \ jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \ jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \ - jfdctint.c jidctflt.c jidctred.c jquant1.c \ + jfdctint.c jidctflt.c jquant1.c \ jquant2.c jutils.c jmemmgr.c \ + +# use ashmem as libjpeg decoder's backing store +#LOCAL_CFLAGS += -DUSE_ANDROID_ASHMEM +#LOCAL_SRC_FILES += \ + jmem-ashmem.c + +# the original android memory manager. +# use sdcard as libjpeg decoder's backing store +LOCAL_SRC_FILES += \ jmem-android.c + # the assembler is only for the ARM version, don't break the Linux sim ifneq ($(TARGET_ARCH),arm) ANDROID_JPEG_NO_ASSEMBLER := true endif -# temp fix until we understand why this broke cnn.com -#ANDROID_JPEG_NO_ASSEMBLER := true - ifeq ($(strip $(ANDROID_JPEG_NO_ASSEMBLER)),true) -LOCAL_SRC_FILES += jidctint.c jidctfst.c +LOCAL_SRC_FILES += jidctint.c jidctfst.c jidctred.c else -LOCAL_SRC_FILES += jidctint.c jidctfst.S +ifeq ($(ANDROID_JPEG_USE_VENUM),true) +LOCAL_SRC_FILES += jidctvenum.c +LOCAL_SRC_FILES += asm/armv7/jdcolor-armv7.S +LOCAL_SRC_FILES += asm/armv7/jdcolor-android-armv7.S +LOCAL_SRC_FILES += asm/armv7/jdidct-armv7.S +LOCAL_CFLAGS += -DANDROID_JPEG_USE_VENUM +else # ANDROID_JPEG_USE_VENUM, false +LOCAL_SRC_FILES += jidctint.c jidctred.c jidctfst.c armv6_idct.S +LOCAL_CFLAGS += -DANDROID_ARMV6_IDCT +endif # ANDROID_JPEG_USE_VENUM endif -LOCAL_CFLAGS += -DAVOID_TABLES +LOCAL_CFLAGS += -DAVOID_TABLES LOCAL_CFLAGS += -O3 -fstrict-aliasing -fprefetch-loop-arrays -#LOCAL_CFLAGS += -march=armv6j + +# enable tile based decode +LOCAL_CFLAGS += -DANDROID_TILE_BASED_DECODE + +ifdef NEEDS_ARM_ERRATA_754319_754320 +asm_flags := \ + --defsym NEEDS_ARM_ERRATA_754319_754320_ASM=1 + +LOCAL_CFLAGS+= \ + $(foreach f,$(asm_flags),-Wa,"$(f)") +endif LOCAL_MODULE:= jpeg -include $(BUILD_STATIC_LIBRARY) +LOCAL_SHARED_LIBRARIES := \ + libcutils + +include $(BUILD_SHARED_LIBRARY) diff --git a/src/jni/jpeg/CleanSpec.mk b/src/jni/jpeg/CleanSpec.mk new file mode 100644 index 0000000000..b84e1b65e7 --- /dev/null +++ b/src/jni/jpeg/CleanSpec.mk @@ -0,0 +1,49 @@ +# Copyright (C) 2007 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) + +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ diff --git a/src/jni/jpeg/README-VeNum b/src/jni/jpeg/README-VeNum new file mode 100644 index 0000000000..ee51449c7a --- /dev/null +++ b/src/jni/jpeg/README-VeNum @@ -0,0 +1,20 @@ +README-VeNum +Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum +================================================================= + +Consumers are increasingly browsing Web based photo galleries incorporating +high-resolution JPEG images with their mobile devices. These images are +decoded by the mobile device, and typically also scaled down to fit the user's +zoom selection on the device's browser. + +In order to improve both decode and download times, Qualcomm Innovation Center +has optimized the JPEG library found on many common OS platforms such as Web +OS, Android, and Chrome OS. Our team re-implemented several routines to utilize the +DSP-like SIMD capabilities of the ARM NEON instruction set. These were then +tuned and tested on Qualcomm's Snapdragon platform which implements the VeNum +implementation of these same instructions. + +The specific areas of focus cover VeNum/NEON acceleration of Inverse Discrete +Cosine Transform (iDCT) for 8x8, 4x4, 2x2, and 1x1 block sizes and YUV to RGB +color space conversion. This resulted in a range of 18-32% improvement in JPEG +decode and downscale times for images greater than 2Mpixels. diff --git a/src/jni/jpeg/ThirdPartyProject.prop b/src/jni/jpeg/ThirdPartyProject.prop new file mode 100644 index 0000000000..e88cc63552 --- /dev/null +++ b/src/jni/jpeg/ThirdPartyProject.prop @@ -0,0 +1,9 @@ +# Copyright 2010 Google Inc. All Rights Reserved. +#Fri Jul 16 10:03:09 PDT 2010 +currentVersion=8a +version=6b +isNative=true +name=jpeg +keywords=jpeg +onDevice=true +homepage=http\://www.ijg.org/ diff --git a/src/jni/jpeg/armv6_idct.S b/src/jni/jpeg/armv6_idct.S new file mode 100644 index 0000000000..18e4e8a18d --- /dev/null +++ b/src/jni/jpeg/armv6_idct.S @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This is a fast-and-accurate implementation of inverse Discrete Cosine + * Transform (IDCT) for ARMv6+. It also performs dequantization of the input + * coefficients just like other methods. + * + * This implementation is based on the scaled 1-D DCT algorithm proposed by + * Arai, Agui, and Nakajima. The following code is based on the figure 4-8 + * on page 52 of the JPEG textbook by Pennebaker and Mitchell. Coefficients + * are (almost) directly mapped into registers. + * + * The accuracy is achieved by using SMULWy and SMLAWy instructions. Both + * multiply 32 bits by 16 bits and store the top 32 bits of the result. It + * makes 32-bit fixed-point arithmetic possible without overflow. That is + * why jpeg_idct_ifast(), which is written in C, cannot be improved. + * + * More tricks are used to gain more speed. First of all, we use as many + * registers as possible. ARM processor has 16 registers including sp (r13) + * and pc (r15), so only 14 registers can be used without limitations. In + * general, we let r0 to r7 hold the coefficients; r10 and r11 hold four + * 16-bit constants; r12 and r14 hold two of the four arguments; and r8 hold + * intermediate value. In the second pass, r9 is the loop counter. In the + * first pass, r8 to r11 are used to hold quantization values, so the loop + * counter is held by sp. Yes, the stack pointer. Since it must be aligned + * to 4-byte boundary all the time, we align it to 32-byte boundary and use + * bit 3 to bit 5. As the result, we actually use 14.1 registers. :-) + * + * Second, we rearrange quantization values to access them sequentially. The + * table is first transposed, and the new columns are placed in the order of + * 7, 5, 1, 3, 0, 2, 4, 6. Thus we can use LDMDB to load four values at a + * time. Rearranging coefficients also helps, but that requires to change a + * dozen of files, which seems not worth it. In addition, we choose to scale + * up quantization values by 13 bits, so the coefficients are scaled up by + * 16 bits after both passes. Then we can pack and saturate them two at a + * time using PKHTB and USAT16 instructions. + * + * Third, we reorder the instructions to avoid bubbles in the pipeline. This + * is done by hand accroding to the cycle timings and the interlock behavior + * described in the technical reference manual of ARM1136JF-S. We also take + * advantage of dual issue processors by interleaving instructions with + * dependencies. It has been benchmarked on four devices and all the results + * showed distinguishable improvements. Note that PLD instructions actually + * slow things down, so they are removed at the last minute. In the future, + * this might be futher improved using a system profiler. + */ + +#ifdef __arm__ +#include +#endif + +#if __ARM_ARCH__ >= 6 + +// void armv6_idct(short *coefs, int *quans, unsigned char *rows, int col) + .arm + .text + .align + .global armv6_idct + .func armv6_idct + +armv6_idct: + // Push everything except sp (r13) and pc (r15). + stmdb sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, r14} + + // r12 = quans, r14 = coefs. + sub r4, sp, #236 + bic sp, r4, #31 + add r5, sp, #224 + add r12, r1, #256 + stm r5, {r2, r3, r4} + add r14, r0, #16 + +pass1_head: + // Load quantization values. (q[0, 2, 4, 6]) + ldmdb r12!, {r8, r9, r10, r11} + + // Load coefficients. (c[4, 1, 2, 3, 0, 5, 6, 7]) + ldrsh r4, [r14, #-2] ! + ldrsh r1, [r14, #16] + ldrsh r2, [r14, #32] + ldrsh r3, [r14, #48] + ldrsh r0, [r14, #64] + ldrsh r5, [r14, #80] + ldrsh r6, [r14, #96] + ldrsh r7, [r14, #112] + + // r4 = q[0] * c[0]; + mul r4, r8, r4 + + // Check if ACs are all zero. + cmp r0, #0 + orreqs r8, r1, r2 + orreqs r8, r3, r5 + orreqs r8, r6, r7 + beq pass1_zero + + // Step 1: Dequantizations. + + // r2 = q[2] * c[2]; + // r0 = q[4] * c[4] + r4; + // r6 = q[6] * c[6] + r2; + mul r2, r9, r2 + mla r0, r10, r0, r4 + mla r6, r11, r6, r2 + + // Load quantization values. (q[7, 5, 1, 3]) + ldmdb r12!, {r8, r9, r10, r11} + + // r4 = r4 * 2 - r0 = -(r0 - r4 * 2); + // r2 = r2 * 2 - r6 = -(r6 - r2 * 2); + rsb r4, r0, r4, lsl #1 + rsb r2, r6, r2, lsl #1 + + // r7 = q[7] * c[7]; + // r5 = q[5] * c[5]; + // r1 = q[1] * c[1] + r7; + // r3 = q[3] * c[3] + r5; + mul r7, r8, r7 + mul r5, r9, r5 + mla r1, r10, r1, r7 + mla r3, r11, r3, r5 + + // Load constants. + ldrd r10, constants + + // Step 2: Rotations and Butterflies. + + // r7 = r1 - r7 * 2; + // r1 = r1 - r3; + // r5 = r5 * 2 - r3 = -(r3 - r5 * 2); + // r3 = r1 + r3 * 2; + // r8 = r5 + r7; + sub r7, r1, r7, lsl #1 + sub r1, r1, r3 + rsb r5, r3, r5, lsl #1 + add r3, r1, r3, lsl #1 + add r8, r5, r7 + + // r2 = r2 * 1.41421 = r2 * 27146 / 65536 + r2; + // r8 = r8 * 1.84776 / 8 = r8 * 15137 / 65536; + // r1 = r1 * 1.41421 = r1 * 27146 / 65536 + r1; + smlawt r2, r2, r10, r2 + smulwb r8, r8, r10 + smlawt r1, r1, r10, r1 + + // r0 = r0 + r6; + // r2 = r2 - r6; + // r6 = r0 - r6 * 2; + add r0, r0, r6 + sub r2, r2, r6 + sub r6, r0, r6, lsl #1 + + // r5 = r5 * -2.61313 / 8 + r8 = r5 * -21407 / 65536 + r8; + // r8 = r7 * -1.08239 / 8 + r8 = r7 * -8867 / 65536 + r8; + smlawt r5, r5, r11, r8 + smlawb r8, r7, r11, r8 + + // r4 = r4 + r2; + // r0 = r0 + r3; + // r2 = r4 - r2 * 2; + add r4, r4, r2 + add r0, r0, r3 + sub r2, r4, r2, lsl #1 + + // r7 = r5 * 8 - r3 = -(r3 - r5 * 8); + // r3 = r0 - r3 * 2; + // r1 = r1 - r7; + // r4 = r4 + r7; + // r5 = r8 * 8 - r1 = -(r1 - r8 * 8); + // r7 = r4 - r7 * 2; + rsb r7, r3, r5, lsl #3 + sub r3, r0, r3, lsl #1 + sub r1, r1, r7 + add r4, r4, r7 + rsb r5, r1, r8, lsl #3 + sub r7, r4, r7, lsl #1 + + // r2 = r2 + r1; + // r6 = r6 + r5; + // r1 = r2 - r1 * 2; + // r5 = r6 - r5 * 2; + add r2, r2, r1 + add r6, r6, r5 + sub r1, r2, r1, lsl #1 + sub r5, r6, r5, lsl #1 + + // Step 3: Reorder and Save. + + str r0, [sp, #-4] ! + str r4, [sp, #32] + str r2, [sp, #64] + str r6, [sp, #96] + str r5, [sp, #128] + str r1, [sp, #160] + str r7, [sp, #192] + str r3, [sp, #224] + b pass1_tail + + // Precomputed 16-bit constants: 27146, 15137, -21407, -8867. + // Put them in the middle since LDRD only accepts offsets from -255 to 255. + .align 3 +constants: + .word 0x6a0a3b21 + .word 0xac61dd5d + +pass1_zero: + str r4, [sp, #-4] ! + str r4, [sp, #32] + str r4, [sp, #64] + str r4, [sp, #96] + str r4, [sp, #128] + str r4, [sp, #160] + str r4, [sp, #192] + str r4, [sp, #224] + sub r12, r12, #16 + +pass1_tail: + ands r9, sp, #31 + bne pass1_head + + // r12 = rows, r14 = col. + ldr r12, [sp, #256] + ldr r14, [sp, #260] + + // Load constants. + ldrd r10, constants + +pass2_head: + // Load coefficients. (c[0, 1, 2, 3, 4, 5, 6, 7]) + ldmia sp!, {r0, r1, r2, r3, r4, r5, r6, r7} + + // r0 = r0 + 0x00808000; + add r0, r0, #0x00800000 + add r0, r0, #0x00008000 + + // Step 1: Analog to the first pass. + + // r0 = r0 + r4; + // r6 = r6 + r2; + add r0, r0, r4 + add r6, r6, r2 + + // r4 = r0 - r4 * 2; + // r2 = r2 * 2 - r6 = -(r6 - r2 * 2); + sub r4, r0, r4, lsl #1 + rsb r2, r6, r2, lsl #1 + + // r1 = r1 + r7; + // r3 = r3 + r5; + add r1, r1, r7 + add r3, r3, r5 + + // Step 2: Rotations and Butterflies. + + // r7 = r1 - r7 * 2; + // r1 = r1 - r3; + // r5 = r5 * 2 - r3 = -(r3 - r5 * 2); + // r3 = r1 + r3 * 2; + // r8 = r5 + r7; + sub r7, r1, r7, lsl #1 + sub r1, r1, r3 + rsb r5, r3, r5, lsl #1 + add r3, r1, r3, lsl #1 + add r8, r5, r7 + + // r2 = r2 * 1.41421 = r2 * 27146 / 65536 + r2; + // r8 = r8 * 1.84776 / 8 = r8 * 15137 / 65536; + // r1 = r1 * 1.41421 = r1 * 27146 / 65536 + r1; + smlawt r2, r2, r10, r2 + smulwb r8, r8, r10 + smlawt r1, r1, r10, r1 + + // r0 = r0 + r6; + // r2 = r2 - r6; + // r6 = r0 - r6 * 2; + add r0, r0, r6 + sub r2, r2, r6 + sub r6, r0, r6, lsl #1 + + // r5 = r5 * -2.61313 / 8 + r8 = r5 * -21407 / 65536 + r8; + // r8 = r7 * -1.08239 / 8 + r8 = r7 * -8867 / 65536 + r8; + smlawt r5, r5, r11, r8 + smlawb r8, r7, r11, r8 + + // r4 = r4 + r2; + // r0 = r0 + r3; + // r2 = r4 - r2 * 2; + add r4, r4, r2 + add r0, r0, r3 + sub r2, r4, r2, lsl #1 + + // r7 = r5 * 8 - r3 = -(r3 - r5 * 8); + // r3 = r0 - r3 * 2; + // r1 = r1 - r7; + // r4 = r4 + r7; + // r5 = r8 * 8 - r1 = -(r1 - r8 * 8); + // r7 = r4 - r7 * 2; + rsb r7, r3, r5, lsl #3 + sub r3, r0, r3, lsl #1 + sub r1, r1, r7 + add r4, r4, r7 + rsb r5, r1, r8, lsl #3 + sub r7, r4, r7, lsl #1 + + // r2 = r2 + r1; + // r6 = r6 + r5; + // r1 = r2 - r1 * 2; + // r5 = r6 - r5 * 2; + add r2, r2, r1 + add r6, r6, r5 + sub r1, r2, r1, lsl #1 + sub r5, r6, r5, lsl #1 + + // Step 3: Reorder and Save. + + // Load output pointer. + ldr r8, [r12], #4 + + // For little endian: r6, r2, r4, r0, r3, r7, r1, r5. + pkhtb r6, r6, r4, asr #16 + pkhtb r2, r2, r0, asr #16 + pkhtb r3, r3, r1, asr #16 + pkhtb r7, r7, r5, asr #16 + usat16 r6, #8, r6 + usat16 r2, #8, r2 + usat16 r3, #8, r3 + usat16 r7, #8, r7 + orr r0, r2, r6, lsl #8 + orr r1, r7, r3, lsl #8 + +#ifdef __ARMEB__ + // Reverse bytes for big endian. + rev r0, r0 + rev r1, r1 +#endif + + // Use STR instead of STRD to support unaligned access. + str r0, [r8, r14] ! + str r1, [r8, #4] + +pass2_tail: + adds r9, r9, #0x10000000 + bpl pass2_head + + ldr sp, [sp, #8] + add sp, sp, #236 + + ldmia sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, r14} + bx lr + .endfunc + +#endif diff --git a/src/jni/jpeg/asm/armv7/jdcolor-android-armv7.S b/src/jni/jpeg/asm/armv7/jdcolor-android-armv7.S new file mode 100644 index 0000000000..95bd4bf782 --- /dev/null +++ b/src/jni/jpeg/asm/armv7/jdcolor-android-armv7.S @@ -0,0 +1,1223 @@ +/*------------------------------------------------------------------------ +* jdcolor-android-armv7.S +* +* Copyright (c) 2010, Code Aurora Forum. All rights reserved. +* +* 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 Code Aurora Forum, Inc. 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 "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. +*-------------------------------------------------------------------------- + +*-------------------------------------------------------------------------- +* FUNCTION LIST +*-------------------------------------------------------------------------- +* +* - yvup2rgb565_venum +* - yyvup2rgb565_venum +* - yvup2abgr8888_venum +* - yyvup2abgr8888_venum +* +*-------------------------------------------------------------------------- +*/ + + .section yvu_plain_to_rgb_android, "x" @ AREA + .text @ |.text|, CODE, READONLY + .align 2 + .code 32 @ CODE32 + +/*----------------------------------------------------------------------------- + * ARM Registers + * ---------------------------------------------------------------------------- */ +p_y .req r0 +p_cr .req r1 +p_cb .req r2 +p_rgb .req r3 +p_bgr .req r3 +length .req r12 + + .global yvup2rgb565_venum + .global yyvup2rgb565_venum + .global yvup2abgr8888_venum + .global yyvup2abgr8888_venum + +@ coefficients in color conversion matrix multiplication +.equ COEFF_Y, 256 @ contribution of Y +.equ COEFF_V_RED, 359 @ contribution of V for red +.equ COEFF_U_GREEN, -88 @ contribution of U for green +.equ COEFF_V_GREEN, -183 @ contribution of V for green +.equ COEFF_U_BLUE, 454 @ contribution of U for blue + +@ Clamping constants 0x0 and 0xFF +.equ COEFF_0, 0 +.equ COEFF_255, 255 + +@ Bias coefficients for red, green and blue +.equ COEFF_BIAS_R, -45824 @ Red bias = -359*128 + 128 +.equ COEFF_BIAS_G, 34816 @ Green bias = (88+183)*128 + 128 +.equ COEFF_BIAS_B, -57984 @ Blue bias = -454*128 + 128 + + +/*-------------------------------------------------------------------------- +* FUNCTION : yvup2rgb565_venum +*-------------------------------------------------------------------------- +* DESCRIPTION : Perform YVU planar to RGB565 conversion. +*-------------------------------------------------------------------------- +* C PROTOTYPE : void yvup2rgb565_venum(uint8_t *p_y, +* uint8_t *p_cr, +* uint8_t *p_cb, +* uint8_t *p_rgb565, +* uint32_t length) +*-------------------------------------------------------------------------- +* REG INPUT : R0: uint8_t *p_y +* pointer to the input Y Line +* R1: uint8_t *p_cr +* pointer to the input Cr Line +* R2: uint8_t *p_cb +* pointer to the input Cb Line +* R3: uint8_t *p_rgb565 +* pointer to the output RGB Line +* R12: uint32_t length +* width of Line +*-------------------------------------------------------------------------- +* STACK ARG : None +*-------------------------------------------------------------------------- +* REG OUTPUT : None +*-------------------------------------------------------------------------- +* MEM INPUT : p_y - a line of Y pixels +* p_cr - a line of Cr pixels +* p_cb - a line of Cb pixels +* length - the width of the input line +*-------------------------------------------------------------------------- +* MEM OUTPUT : p_rgb565 - the converted rgb pixels +*-------------------------------------------------------------------------- +* REG AFFECTED : ARM: R0-R4, R12 +* NEON: Q0-Q15 +*-------------------------------------------------------------------------- +* STACK USAGE : none +*-------------------------------------------------------------------------- +* CYCLES : none +* +*-------------------------------------------------------------------------- +* NOTES : +*-------------------------------------------------------------------------- +*/ +.type yvup2rgb565_venum, %function +yvup2rgb565_venum: + /*------------------------------------------------------------------------- + * Store stack registers + * ------------------------------------------------------------------------ */ + STMFD SP!, {LR} + + VPUSH {D8-D15} + + PLD [R0, R3] @ preload luma line + + ADR R12, constants + + VLD1.S16 {D6, D7}, [R12]! @ D6, D7: 359 | -88 | -183 | 454 | 256 | 0 | 255 | 0 + VLD1.S32 {D30, D31}, [R12] @ Q15 : -45824 | 34816 | -57984 | X + + /*------------------------------------------------------------------------- + * Load the 5th parameter via stack + * R0 ~ R3 are used to pass the first 4 parameters, the 5th and above + * parameters are passed via stack + * ------------------------------------------------------------------------ */ + LDR R12, [SP, #68] @ LR is pushed into the stack so SP is + @ decreased by 4, + @ D8-D15 are also pushed into the stack + @ so SP is decreased by + @ 8-byte/D-Register * 8 D-Registers = 64, + @ so SP needs to be increased by 64+4=68 + @ to get the value that was first pushed + @ into stack (the 5th parameter passed in + @ throught stack) + + /*------------------------------------------------------------------------- + * Load clamping parameters to duplicate vector elements + * ------------------------------------------------------------------------ */ + VDUP.S16 Q4, D7[1] @ Q4: 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 + VDUP.S16 Q5, D7[2] @ Q5: 255 | 255 | 255 | 255 | 255 | 255 | 255 | 255 + + /*------------------------------------------------------------------------- + * Read bias + * ------------------------------------------------------------------------ */ + VDUP.S32 Q0, D30[0] @ Q0: -45824 | -45824 | -45824 | -45824 + VDUP.S32 Q1, D30[1] @ Q1: 34816 | 34816 | 34816 | 34816 + VDUP.S32 Q2, D31[0] @ Q2: -70688 | -70688 | -70688 | -70688 + + + /*------------------------------------------------------------------------- + * The main loop + * ------------------------------------------------------------------------ */ +loop_yvup2rgb565: + + /*------------------------------------------------------------------------- + * Load input from Y, V and U + * D12 : Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 + * D14 : V0 V1 V2 V3 V4 V5 V6 V7 + * D15 : U0 U1 U2 U3 U4 U5 U6 U7 + * ------------------------------------------------------------------------ */ + VLD1.U8 {D12}, [p_y]! @ Load 8 Y elements (uint8) to D12 + VLD1.U8 {D14}, [p_cr]! @ Load 8 Cr elements (uint8) to D14 + VLD1.U8 {D15}, [p_cb]! @ Load 8 Cb elements (uint8) to D15 + + /*------------------------------------------------------------------------- + * Expand uint8 value to uint16 + * D18, D19: Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 + * D20, D21: V0 V1 V2 V3 V4 V5 V6 V7 + * D22, D23: U0 U1 U2 U3 U4 U5 U6 U7 + * ------------------------------------------------------------------------ */ + VMOVL.U8 Q9, D12 + VMOVL.U8 Q10, D14 + VMOVL.U8 Q11, D15 + + /*------------------------------------------------------------------------- + * Multiply contribution from chrominance, results are in 32-bit + * ------------------------------------------------------------------------ */ + VMULL.S16 Q12, D20, D6[0] @ Q12: 359*(V0,V1,V2,V3) Red + VMULL.S16 Q13, D22, D6[1] @ Q13: -88*(U0,U1,U2,U3) Green + VMLAL.S16 Q13, D20, D6[2] @ Q13: -88*(U0,U1,U2,U3) - 183*(V0,V1,V2,V3) + VMULL.S16 Q14, D22, D6[3] @ Q14: 454*(U0,U1,U2,U3) Blue + + /*------------------------------------------------------------------------- + * Add bias + * ------------------------------------------------------------------------ */ + VADD.S32 Q12, Q0 @ Q12 add Red bias -45824 + VADD.S32 Q13, Q1 @ Q13 add Green bias 34816 + VADD.S32 Q14, Q2 @ Q14 add Blue bias -57984 + + /*------------------------------------------------------------------------- + * Calculate Red, Green, Blue + * ------------------------------------------------------------------------ */ + VMLAL.S16 Q12, D18, D7[0] @ Q12: R0, R1, R2, R3 in 32-bit Q8 format + VMLAL.S16 Q13, D18, D7[0] @ Q13: G0, G1, G2, G3 in 32-bit Q8 format + VMLAL.S16 Q14, D18, D7[0] @ Q14: B0, B1, B2, B3 in 32-bit Q8 format + + /*------------------------------------------------------------------------- + * Right shift eight bits with rounding + * ------------------------------------------------------------------------ */ + VSHRN.S32 D18 , Q12, #8 @ D18: R0, R1, R2, R3 in 16-bit Q0 format + VSHRN.S32 D20 , Q13, #8 @ D20: G0, G1, G2, G3 in 16-bit Q0 format + VSHRN.S32 D22, Q14, #8 @ D22: B0, B1, B2, B3 in 16-bit Q0 format + + /*------------------------------------------------------------------------- + * Done with the first 4 elements, continue on the next 4 elements + * ------------------------------------------------------------------------ */ + + /*------------------------------------------------------------------------- + * Multiply contribution from chrominance, results are in 32-bit + * ------------------------------------------------------------------------ */ + VMULL.S16 Q12, D21, D6[0] @ Q12: 359*(V0,V1,V2,V3) Red + VMULL.S16 Q13, D23, D6[1] @ Q13: -88*(U0,U1,U2,U3) Green + VMLAL.S16 Q13, D21, D6[2] @ Q13: -88*(U0,U1,U2,U3) - 183*(V0,V1,V2,V3) + VMULL.S16 Q14, D23, D6[3] @ Q14: 454*(U0,U1,U2,U3) Blue + + /*------------------------------------------------------------------------- + * Add bias + * ------------------------------------------------------------------------ */ + VADD.S32 Q12, Q0 @ Q12 add Red bias -45824 + VADD.S32 Q13, Q1 @ Q13 add Green bias 34816 + VADD.S32 Q14, Q2 @ Q14 add Blue bias -57984 + + /*------------------------------------------------------------------------- + * Calculate Red, Green, Blue + * ------------------------------------------------------------------------ */ + VMLAL.S16 Q12, D19, D7[0] @ Q12: R0, R1, R2, R3 in 32-bit Q8 format + VMLAL.S16 Q13, D19, D7[0] @ Q13: G0, G1, G2, G3 in 32-bit Q8 format + VMLAL.S16 Q14, D19, D7[0] @ Q14: B0, B1, B2, B3 in 32-bit Q8 format + + /*------------------------------------------------------------------------- + * Right shift eight bits with rounding + * ------------------------------------------------------------------------ */ + VSHRN.S32 D19 , Q12, #8 @ D18: R0, R1, R2, R3 in 16-bit Q0 format + VSHRN.S32 D21 , Q13, #8 @ D20: G0, G1, G2, G3 in 16-bit Q0 format + VSHRN.S32 D23, Q14, #8 @ D22: B0, B1, B2, B3 in 16-bit Q0 format + + /*------------------------------------------------------------------------- + * Clamp the value to be within [0~255] + * ------------------------------------------------------------------------ */ + VMAX.S16 Q9, Q9, Q4 @ if Q9 < 0, Q9 = 0 + VMIN.S16 Q9, Q9, Q5 @ if Q9 > 255, Q9 = 255 + VQMOVUN.S16 D28, Q9 @ store Red to D28, narrow the value from int16 to int8 + + VMAX.S16 Q10, Q10, Q4 @ if Q10 < 0, Q10 = 0 + VMIN.S16 Q10, Q10, Q5 @ if Q10 > 255, Q10 = 255 + VQMOVUN.S16 D27, Q10 @ store Green to D27, narrow the value from int16 to int8 + + VMAX.S16 Q11, Q11, Q4 @ if Q11 < 0, Q11 = 0 + VMIN.S16 Q11, Q11, Q5 @ if Q11 > 255, Q11 = 255 + VQMOVUN.S16 D26, Q11 @ store Blue to D26, narrow the value from int16 to int8. + + /*------------------------------------------------------------------------- + * D27: 3 bits of Green + 5 bits of Blue + * D28: 5 bits of Red + 3 bits of Green + * ------------------------------------------------------------------------ */ + VSRI.8 D28, D27, #5 @ right shift G by 5 and insert to R + VSHL.U8 D27, D27, #3 @ left shift G by 3 + VSRI.8 D27, D26, #3 @ right shift B by 3 and insert to G + + SUBS length, length, #8 @ check if the length is less than 8 + + BMI trailing_yvup2rgb565 @ jump to trailing processing if remaining length is less than 8 + + VST2.U8 {D27, D28}, [p_rgb]! @ vector store Red, Green, Blue to destination + @ Blue at LSB + + BHI loop_yvup2rgb565 @ loop if more than 8 pixels left + + BEQ end_yvup2rgb565 @ done if exactly 8 pixel processed in the loop + + +trailing_yvup2rgb565: + /*------------------------------------------------------------------------- + * There are from 1 ~ 7 pixels left in the trailing part. + * First adding 7 to the length so the length would be from 0 ~ 6. + * eg: 1 pixel left in the trailing part, so 1-8+7 = 0. + * Then save 1 pixel unconditionally since at least 1 pixels left in the + * trailing part. + * ------------------------------------------------------------------------ */ + ADDS length, length, #7 @ there are 7 or less in the trailing part + + VST2.U8 {D27[0], D28[0]}, [p_rgb]! @ at least 1 pixel left in the trailing part + BEQ end_yvup2rgb565 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST2.U8 {D27[1], D28[1]}, [p_rgb]! @ store one more pixel + BEQ end_yvup2rgb565 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST2.U8 {D27[2], D28[2]}, [p_rgb]! @ store one more pixel + BEQ end_yvup2rgb565 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST2.U8 {D27[3], D28[3]}, [p_rgb]! @ store one more pixel + BEQ end_yvup2rgb565 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST2.U8 {D27[4], D28[4]}, [p_rgb]! @ store one more pixel + BEQ end_yvup2rgb565 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST2.U8 {D27[5], D28[5]}, [p_rgb]! @ store one more pixel + BEQ end_yvup2rgb565 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST2.U8 {D27[6], D28[6]}, [p_rgb]! @ store one more pixel + +end_yvup2rgb565: + VPOP {D8-D15} + LDMFD SP!, {PC} + + @ end of yvup2rgb565 + + +/*-------------------------------------------------------------------------- +* FUNCTION : yyvup2rgb565_venum +*-------------------------------------------------------------------------- +* DESCRIPTION : Perform YYVU planar to RGB565 conversion. +*-------------------------------------------------------------------------- +* C PROTOTYPE : void yyvup2rgb565_venum(uint8_t *p_y, +* uint8_t *p_cr, +* uint8_t *p_cb, +* uint8_t *p_rgb565, +* uint32_t length) +*-------------------------------------------------------------------------- +* REG INPUT : R0: uint8_t *p_y +* pointer to the input Y Line +* R1: uint8_t *p_cr +* pointer to the input Cr Line +* R2: uint8_t *p_cb +* pointer to the input Cb Line +* R3: uint8_t *p_rgb565 +* pointer to the output RGB Line +* R12: uint32_t length +* width of Line +*-------------------------------------------------------------------------- +* STACK ARG : None +*-------------------------------------------------------------------------- +* REG OUTPUT : None +*-------------------------------------------------------------------------- +* MEM INPUT : p_y - a line of Y pixels +* p_cr - a line of Cr pixels +* p_cb - a line of Cb pixels +* length - the width of the input line +*-------------------------------------------------------------------------- +* MEM OUTPUT : p_rgb565 - the converted rgb pixels +*-------------------------------------------------------------------------- +* REG AFFECTED : ARM: R0-R4, R12 +* NEON: Q0-Q15 +*-------------------------------------------------------------------------- +* STACK USAGE : none +*-------------------------------------------------------------------------- +* CYCLES : none +* +*-------------------------------------------------------------------------- +* NOTES : +*-------------------------------------------------------------------------- +*/ +.type yyvup2rgb565_venum, %function +yyvup2rgb565_venum: + /*------------------------------------------------------------------------- + * Store stack registers + * ------------------------------------------------------------------------ */ + STMFD SP!, {LR} + + VPUSH {D8-D15} + + PLD [R0, R3] @ preload luma line + + ADR R12, constants + + VLD1.S16 {D6, D7}, [R12]! @ D6, D7: 359 | -88 | -183 | 454 | 256 | 0 | 255 | 0 + VLD1.S32 {D30, D31}, [R12] @ Q15 : -45824 | 34816 | -57984 | X + + /*------------------------------------------------------------------------- + * Load the 5th parameter via stack + * R0 ~ R3 are used to pass the first 4 parameters, the 5th and above + * parameters are passed via stack + * ------------------------------------------------------------------------ */ + LDR R12, [SP, #68] @ LR is pushed into the stack so SP is + @ decreased by 4, + @ D8-D15 are also pushed into the stack + @ so SP is decreased by + @ 8-byte/D-Register * 8 D-Registers = 64, + @ so SP needs to be increased by 64+4=68 + @ to get the value that was first pushed + @ into stack (the 5th parameter passed in + @ throught stack) + + /*------------------------------------------------------------------------- + * Load clamping parameters to duplicate vector elements + * ------------------------------------------------------------------------ */ + VDUP.S16 Q4, D7[1] @ Q4: 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 + VDUP.S16 Q5, D7[2] @ Q5: 255 | 255 | 255 | 255 | 255 | 255 | 255 | 255 + + /*------------------------------------------------------------------------- + * Read bias + * ------------------------------------------------------------------------ */ + VDUP.S32 Q0, D30[0] @ Q0: -45824 | -45824 | -45824 | -45824 + VDUP.S32 Q1, D30[1] @ Q1: 34816 | 34816 | 34816 | 34816 + VDUP.S32 Q2, D31[0] @ Q2: -70688 | -70688 | -70688 | -70688 + + + /*------------------------------------------------------------------------- + * The main loop + * ------------------------------------------------------------------------ */ +loop_yyvup2rgb565: + + /*------------------------------------------------------------------------- + * Load input from Y, V and U + * D12, D13: Y0 Y2 Y4 Y6 Y8 Y10 Y12 Y14, Y1 Y3 Y5 Y7 Y9 Y11 Y13 Y15 + * D14 : V0 V1 V2 V3 V4 V5 V6 V7 + * D15 : U0 U1 U2 U3 U4 U5 U6 U7 + * ------------------------------------------------------------------------ */ + VLD2.U8 {D12,D13}, [p_y]! @ Load 16 Luma elements (uint8) to D12, D13 + VLD1.U8 {D14}, [p_cr]! @ Load 8 Cr elements (uint8) to D14 + VLD1.U8 {D15}, [p_cb]! @ Load 8 Cb elements (uint8) to D15 + + /*------------------------------------------------------------------------- + * Expand uint8 value to uint16 + * D24, D25: Y0 Y2 Y4 Y6 Y8 Y10 Y12 Y14 + * D26, D27: Y1 Y3 Y5 Y7 Y9 Y11 Y13 Y15 + * D28, D29: V0 V1 V2 V3 V4 V5 V6 V7 + * D30, D31: U0 U1 U2 U3 U4 U5 U6 U7 + * ------------------------------------------------------------------------ */ + VMOVL.U8 Q12, D12 + VMOVL.U8 Q13, D13 + VMOVL.U8 Q14, D14 + VMOVL.U8 Q15, D15 + + /*------------------------------------------------------------------------- + * Multiply contribution from chrominance, results are in 32-bit + * ------------------------------------------------------------------------ */ + VMULL.S16 Q6, D28, D6[0] @ Q6: 359*(V0,V1,V2,V3) Red + VMULL.S16 Q7, D30, D6[1] @ Q7: -88*(U0,U1,U2,U3) Green + VMLAL.S16 Q7, D28, D6[2] @ q7: -88*(U0,U1,U2,U3) - 183*(V0,V1,V2,V3) + VMULL.S16 Q8, D30, D6[3] @ q8: 454*(U0,U1,U2,U3) Blue + + /*------------------------------------------------------------------------- + * Add bias + * ------------------------------------------------------------------------ */ + VADD.S32 Q6, Q0 @ Q6 add Red bias -45824 + VADD.S32 Q7, Q1 @ Q7 add Green bias 34816 + VADD.S32 Q8, Q2 @ Q8 add Blue bias -57984 + + /*------------------------------------------------------------------------- + * Calculate Red, Green, Blue + * ------------------------------------------------------------------------ */ + VMOV.S32 Q9, Q6 + VMLAL.S16 Q6, D24, D7[0] @ Q6: R0, R2, R4, R6 in 32-bit Q8 format + VMLAL.S16 Q9, D26, D7[0] @ Q9: R1, R3, R5, R7 in 32-bit Q8 format + + VMOV.S32 Q10, Q7 + VMLAL.S16 Q7, D24, D7[0] @ Q7: G0, G2, G4, G6 in 32-bit Q8 format + VMLAL.S16 Q10, D26, D7[0] @ Q10: G1, G3, G5, G7 in 32-bit Q8 format + + VMOV.S32 Q11, Q8 + VMLAL.S16 Q8, D24, D7[0] @ Q8: B0, B2, B4, B6 in 32-bit Q8 format + VMLAL.S16 Q11, D26, D7[0] @ Q11: B1, B3, B5, B7 in 32-bit Q8 format + + /*------------------------------------------------------------------------- + * Right shift eight bits with rounding + * ------------------------------------------------------------------------ */ + VSHRN.S32 D12, Q6, #8 @ D12: R0 R2 R4 R6 in 16-bit Q0 format + VSHRN.S32 D13, Q9, #8 @ D13: R1 R3 R5 R7 in 16-bit Q0 format + VZIP.16 D12, D13 @ Q6 : R0 R1 R2 R3 R4 R5 R6 R7 + + VSHRN.S32 D18, Q7, #8 @ D18: G0 G2 G4 G6 in 16-bit Q0 format + VSHRN.S32 D19, Q10, #8 @ D19: G1 G3 G5 G7 in 16-bit Q0 format + VZIP.16 D18, D19 @ Q9 : G0 G1 G2 G3 G4 G5 G6 G7 + + VSHRN.S32 D20, Q8, #8 @ D20: B0 B2 B4 B6 in 16-bit Q0 format + VSHRN.S32 D21, Q11, #8 @ D21: B1 B3 B5 B7 in 16-bit Q0 format + VZIP.16 D20, D21 @ Q10: B0 B1 B2 B3 B4 B5 B6 B7 + + /*------------------------------------------------------------------------- + * Clamp the value to be within [0~255] + * ------------------------------------------------------------------------ */ + VMAX.S16 Q6, Q6, Q4 @ if Q6 < 0, Q6 = 0 + VMIN.S16 Q6, Q6, Q5 @ if Q6 > 255, Q6 = 255 + VQMOVUN.S16 D23, Q6 @ store Red to D23, narrow the value from int16 to int8 + + VMAX.S16 Q9, Q9, Q4 @ if Q9 < 0, Q9 = 0 + VMIN.S16 Q9, Q9, Q5 @ if Q9 > 255, Q9 = 255 + VQMOVUN.S16 D22, Q9 @ store Green to D22, narrow the value from int16 to int8 + + VMAX.S16 Q10, Q10, Q4 @ if Q10 < 0, Q10 = 0 + VMIN.S16 Q10, Q10, Q5 @ if Q10 > 255, Q10 = 255 + VQMOVUN.S16 D21, Q10 @ store Blue to D21, narrow the value from int16 to int8 + + /*------------------------------------------------------------------------- + * D22: 3 bits of Green + 5 bits of Blue + * D23: 5 bits of Red + 3 bits of Green + * ------------------------------------------------------------------------ */ + VSRI.8 D23, D22, #5 @ right shift G by 5 and insert to R + VSHL.U8 D22, D22, #3 @ left shift G by 3 + VSRI.8 D22, D21, #3 @ right shift B by 3 and insert to G + + SUBS length, length, #8 @ check if the length is less than 8 + + BMI trailing_yyvup2rgb565 @ jump to trailing processing if remaining length is less than 8 + + VST2.U8 {D22,D23}, [p_rgb]! @ vector store Red, Green, Blue to destination + @ Blue at LSB + + BEQ end_yyvup2rgb565 @ done if exactly 8 pixel processed in the loop + + + /*------------------------------------------------------------------------- + * Done with the first 8 elements, continue on the next 8 elements + * ------------------------------------------------------------------------ */ + + /*------------------------------------------------------------------------- + * Multiply contribution from chrominance, results are in 32-bit + * ------------------------------------------------------------------------ */ + VMULL.S16 Q6, D29, D6[0] @ Q6: 359*(V4,V5,V6,V7) Red + VMULL.S16 Q7, D31, D6[1] @ Q7: -88*(U4,U5,U6,U7) Green + VMLAL.S16 Q7, D29, D6[2] @ Q7: -88*(U4,U5,U6,U7) - 183*(V4,V5,V6,V7) + VMULL.S16 Q8, D31, D6[3] @ Q8: 454*(U4,U5,U6,U7) Blue + + /*------------------------------------------------------------------------- + * Add bias + * ------------------------------------------------------------------------ */ + VADD.S32 Q6, Q0 @ Q6 add Red bias -45824 + VADD.S32 Q7, Q1 @ Q7 add Green bias 34816 + VADD.S32 Q8, Q2 @ Q8 add Blue bias -57984 + + /*------------------------------------------------------------------------- + * Calculate Red, Green, Blue + * ------------------------------------------------------------------------ */ + VMOV.S32 Q9, Q6 + VMLAL.S16 Q6, D25, D7[0] @ Q6: R8 R10 R12 R14 in 32-bit Q8 format + VMLAL.S16 Q9, D27, D7[0] @ Q9: R9 R11 R13 R15 in 32-bit Q8 format + + VMOV.S32 Q10, Q7 + VMLAL.S16 Q7, D25, D7[0] @ Q7: G0, G2, G4, G6 in 32-bit Q8 format + VMLAL.S16 Q10, D27, D7[0] @ Q10 : G1, G3, G5, G7 in 32-bit Q8 format + + VMOV.S32 Q11, Q8 + VMLAL.S16 Q8, D25, D7[0] @ Q8: B0, B2, B4, B6 in 32-bit Q8 format + VMLAL.S16 Q11, D27, D7[0] @ Q11 : B1, B3, B5, B7 in 32-bit Q8 format + + /*------------------------------------------------------------------------- + * Right shift eight bits with rounding + * ------------------------------------------------------------------------ */ + VSHRN.S32 D12, Q6, #8 @ D12: R8 R10 R12 R14 in 16-bit Q0 format + VSHRN.S32 D13, Q9, #8 @ D13: R9 R11 R13 R15 in 16-bit Q0 format + VZIP.16 D12, D13 @ Q6: R8 R9 R10 R11 R12 R13 R14 R15 + + VSHRN.S32 D18, Q7, #8 @ D18: G8 G10 G12 G14 in 16-bit Q0 format + VSHRN.S32 D19, Q10, #8 @ D19: G9 G11 G13 G15 in 16-bit Q0 format + VZIP.16 D18, D19 @ Q9: G8 G9 G10 G11 G12 G13 G14 G15 + + VSHRN.S32 D20, Q8, #8 @ D20: B8 B10 B12 B14 in 16-bit Q0 format + VSHRN.S32 D21, Q11, #8 @ D21: B9 B11 B13 B15 in 16-bit Q0 format + VZIP.16 D20, D21 @ Q10: B8 B9 B10 B11 B12 B13 B14 B15 + + /*------------------------------------------------------------------------- + * Clamp the value to be within [0~255] + * ------------------------------------------------------------------------ */ + VMAX.S16 Q6, Q6, Q4 @ if Q6 < 0, Q6 = 0 + VMIN.S16 Q6, Q6, Q5 @ if Q6 > 255, Q6 = 255 + VQMOVUN.S16 D23, Q6 @ store Red to D23, narrow the value from int16 to int8 + + VMAX.S16 Q9, Q9, Q4 @ if Q9 < 0, Q9 = 0 + VMIN.S16 Q9, Q9, Q5 @ if Q9 > 255, Q9 = 255 + VQMOVUN.S16 D22, Q9 @ store Green to D22, narrow the value from int16 to int8 + + VMAX.S16 Q10, Q10, Q4 @ if Q10 < 0, Q10 = 0 + VMIN.S16 Q10, Q10, Q5 @ if Q10 > 255, Q10 = 255 + VQMOVUN.S16 D21, Q10 @ store Blue to D21, narrow the value from int16 to int8 + + /*------------------------------------------------------------------------- + * D22: 3 bits of Green + 5 bits of Blue + * D23: 5 bits of Red + 3 bits of Green + * ------------------------------------------------------------------------ */ + VSRI.8 D23, D22, #5 @ right shift G by 5 and insert to R + VSHL.U8 D22, D22, #3 @ left shift G by 3 + VSRI.8 D22, D21, #3 @ right shift B by 3 and insert to G + + SUBS length, length, #8 @ check if the length is less than 8 + + BMI trailing_yyvup2rgb565 @ jump to trailing processing if remaining length is less than 8 + + VST2.U8 {D22,D23}, [p_rgb]! @ vector store Red, Green, Blue to destination + @ Blue at LSB + + BHI loop_yyvup2rgb565 @ loop if more than 8 pixels left + + BEQ end_yyvup2rgb565 @ done if exactly 8 pixel processed in the loop + + +trailing_yyvup2rgb565: + /*------------------------------------------------------------------------- + * There are from 1 ~ 7 pixels left in the trailing part. + * First adding 7 to the length so the length would be from 0 ~ 6. + * eg: 1 pixel left in the trailing part, so 1-8+7 = 0. + * Then save 1 pixel unconditionally since at least 1 pixels left in the + * trailing part. + * ------------------------------------------------------------------------ */ + ADDS length, length, #7 @ there are 7 or less in the trailing part + + VST2.U8 {D22[0],D23[0]}, [p_rgb]! @ at least 1 pixel left in the trailing part + BEQ end_yyvup2rgb565 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST2.U8 {D22[1],D23[1]}, [p_rgb]! @ store one more pixel + BEQ end_yyvup2rgb565 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST2.U8 {D22[2],D23[2]}, [p_rgb]! @ store one more pixel + BEQ end_yyvup2rgb565 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST2.U8 {D22[3],D23[3]}, [p_rgb]! @ store one more pixel + BEQ end_yyvup2rgb565 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST2.U8 {D22[4],D23[4]}, [p_rgb]! @ store one more pixel + BEQ end_yyvup2rgb565 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST2.U8 {D22[5],D23[5]}, [p_rgb]! @ store one more pixel + BEQ end_yyvup2rgb565 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST2.U8 {D22[6],D23[6]}, [p_rgb]! @ store one more pixel + +end_yyvup2rgb565: + VPOP {D8-D15} + LDMFD SP!, {PC} + + @ end of yyvup2rgb565 + +constants: + .hword (COEFF_V_RED), (COEFF_U_GREEN), (COEFF_V_GREEN), (COEFF_U_BLUE) @ 359 | -88 | -183 | 454 + .hword (COEFF_Y), (COEFF_0), (COEFF_255) , (COEFF_0) @ 256 | 0 | 255 | 0 + .word (COEFF_BIAS_R), (COEFF_BIAS_G), (COEFF_BIAS_B) @ -45824 | 34816 | -57984 | X + +/*-------------------------------------------------------------------------- +* FUNCTION : yvup2abgr8888_venum +*-------------------------------------------------------------------------- +* DESCRIPTION : Perform YVU planar to ABGR8888 conversion. +*-------------------------------------------------------------------------- +* C PROTOTYPE : void yvup2abgr8888_venum(uint8_t *p_y, +* uint8_t *p_cr, +* uint8_t *p_cb, +* uint8_t *p_abgr8888, +* uint32_t length) +*-------------------------------------------------------------------------- +* REG INPUT : R0: uint8_t *p_y +* pointer to the input Y Line +* R1: uint8_t *p_cr +* pointer to the input Cr Line +* R2: uint8_t *p_cb +* pointer to the input Cb Line +* R3: uint8_t *p_abgr8888 +* pointer to the output ABGR Line +* R12: uint32_t length +* width of Line +*-------------------------------------------------------------------------- +* STACK ARG : None +*-------------------------------------------------------------------------- +* REG OUTPUT : None +*-------------------------------------------------------------------------- +* MEM INPUT : p_y - a line of Y pixels +* p_cr - a line of Cr pixels +* p_cb - a line of Cb pixels +* length - the width of the input line +*-------------------------------------------------------------------------- +* MEM OUTPUT : p_abgr8888 - the converted ABGR pixels +*-------------------------------------------------------------------------- +* REG AFFECTED : ARM: R0-R4, R12 +* NEON: Q0-Q15 +*-------------------------------------------------------------------------- +* STACK USAGE : none +*-------------------------------------------------------------------------- +* CYCLES : none +* +*-------------------------------------------------------------------------- +* NOTES : +*-------------------------------------------------------------------------- +*/ +.type yvup2abgr8888_venum, %function +yvup2abgr8888_venum: + /*------------------------------------------------------------------------- + * Store stack registers + * ------------------------------------------------------------------------ */ + STMFD SP!, {LR} + + VPUSH {D8-D15} + + PLD [R0, R3] @ preload luma line + + ADR R12, constants + + VLD1.S16 {D6, D7}, [R12]! @ D6, D7: 359 | -88 | -183 | 454 | 256 | 0 | 255 | 0 + VLD1.S32 {D30, D31}, [R12] @ Q15 : -45824 | 34816 | -57984 | X + + /*------------------------------------------------------------------------- + * Load the 5th parameter via stack + * R0 ~ R3 are used to pass the first 4 parameters, the 5th and above + * parameters are passed via stack + * ------------------------------------------------------------------------ */ + LDR R12, [SP, #68] @ LR is pushed into the stack so SP is + @ decreased by 4, + @ D8-D15 are also pushed into the stack + @ so SP is decreased by + @ 8-byte/D-Register * 8 D-Registers = 64, + @ so SP needs to be increased by 64+4=68 + @ to get the value that was first pushed + @ into stack (the 5th parameter passed in + @ throught stack) + + /*------------------------------------------------------------------------- + * Load clamping parameters to duplicate vector elements + * ------------------------------------------------------------------------ */ + VDUP.S16 Q4, D7[1] @ Q4: 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 + VDUP.S16 Q5, D7[2] @ Q5: 255 | 255 | 255 | 255 | 255 | 255 | 255 | 255 + + /*------------------------------------------------------------------------- + * Read bias + * ------------------------------------------------------------------------ */ + VDUP.S32 Q0, D30[0] @ Q0: -45824 | -45824 | -45824 | -45824 + VDUP.S32 Q1, D30[1] @ Q1: 34816 | 34816 | 34816 | 34816 + VDUP.S32 Q2, D31[0] @ Q2: -70688 | -70688 | -70688 | -70688 + + + /*------------------------------------------------------------------------- + * The main loop + * ------------------------------------------------------------------------ */ +loop_yvup2abgr: + + /*------------------------------------------------------------------------- + * Load input from Y, V and U + * D12 : Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 + * D14 : V0 V1 V2 V3 V4 V5 V6 V7 + * D15 : U0 U1 U2 U3 U4 U5 U6 U7 + * ------------------------------------------------------------------------ */ + VLD1.U8 {D12}, [p_y]! @ Load 8 Luma elements (uint8) to D12 + VLD1.U8 {D14}, [p_cr]! @ Load 8 Cr elements (uint8) to D14 + VLD1.U8 {D15}, [p_cb]! @ Load 8 Cb elements (uint8) to D15 + + /*------------------------------------------------------------------------- + * Expand uint8 value to uint16 + * D18, D19: Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 + * D20, D21: V0 V1 V2 V3 V4 V5 V6 V7 + * D22, D23: U0 U1 U2 U3 U4 U5 U6 U7 + * ------------------------------------------------------------------------ */ + VMOVL.U8 Q9, D12 + VMOVL.U8 Q10, D14 + VMOVL.U8 Q11, D15 + + /*------------------------------------------------------------------------- + * Multiply contribution from chrominance, results are in 32-bit + * ------------------------------------------------------------------------ */ + VMULL.S16 Q12, D20, D6[0] @ Q12: 359*(V0,V1,V2,V3) Red + VMULL.S16 Q13, D22, D6[1] @ Q13: -88*(U0,U1,U2,U3) Green + VMLAL.S16 Q13, D20, D6[2] @ Q13: -88*(U0,U1,U2,U3) - 183*(V0,V1,V2,V3) + VMULL.S16 Q14, D22, D6[3] @ Q14: 454*(U0,U1,U2,U3) Blue + + /*------------------------------------------------------------------------- + * Add bias + * ------------------------------------------------------------------------ */ + VADD.S32 Q12, Q0 @ Q12 add Red bias -45824 + VADD.S32 Q13, Q1 @ Q13 add Green bias 34816 + VADD.S32 Q14, Q2 @ Q14 add Blue bias -57984 + + /*------------------------------------------------------------------------- + * Calculate Red, Green, Blue + * ------------------------------------------------------------------------ */ + VMLAL.S16 Q12, D18, D7[0] @ Q12: R0, R1, R2, R3 in 32-bit Q8 format + VMLAL.S16 Q13, D18, D7[0] @ Q13: G0, G1, G2, G3 in 32-bit Q8 format + VMLAL.S16 Q14, D18, D7[0] @ Q14: B0, B1, B2, B3 in 32-bit Q8 format + + /*------------------------------------------------------------------------- + * Right shift eight bits with rounding + * ------------------------------------------------------------------------ */ + VSHRN.S32 D18 , Q12, #8 @ D18: R0, R1, R2, R3 in 16-bit Q0 format + VSHRN.S32 D20 , Q13, #8 @ D20: G0, G1, G2, G3 in 16-bit Q0 format + VSHRN.S32 D22, Q14, #8 @ D22: B0, B1, B2, B3 in 16-bit Q0 format + + /*------------------------------------------------------------------------- + * Done with the first 4 elements, continue on the next 4 elements + * ------------------------------------------------------------------------ */ + + /*------------------------------------------------------------------------- + * Multiply contribution from chrominance, results are in 32-bit + * ------------------------------------------------------------------------ */ + VMULL.S16 Q12, D21, D6[0] @ Q12: 359*(V0,V1,V2,V3) Red + VMULL.S16 Q13, D23, D6[1] @ Q13: -88*(U0,U1,U2,U3) Green + VMLAL.S16 Q13, D21, D6[2] @ Q13: -88*(U0,U1,U2,U3) - 183*(V0,V1,V2,V3) + VMULL.S16 Q14, D23, D6[3] @ Q14: 454*(U0,U1,U2,U3) Blue + + /*------------------------------------------------------------------------- + * Add bias + * ------------------------------------------------------------------------ */ + VADD.S32 Q12, Q0 @ Q12 add Red bias -45824 + VADD.S32 Q13, Q1 @ Q13 add Green bias 34816 + VADD.S32 Q14, Q2 @ Q14 add Blue bias -57984 + + /*------------------------------------------------------------------------- + * Calculate Red, Green, Blue + * ------------------------------------------------------------------------ */ + VMLAL.S16 Q12, D19, D7[0] @ Q12: R0, R1, R2, R3 in 32-bit Q8 format + VMLAL.S16 Q13, D19, D7[0] @ Q13: G0, G1, G2, G3 in 32-bit Q8 format + VMLAL.S16 Q14, D19, D7[0] @ Q14: B0, B1, B2, B3 in 32-bit Q8 format + + /*------------------------------------------------------------------------- + * Right shift eight bits with rounding + * ------------------------------------------------------------------------ */ + VSHRN.S32 D19 , Q12, #8 @ D18: R0, R1, R2, R3 in 16-bit Q0 format + VSHRN.S32 D21 , Q13, #8 @ D20: G0, G1, G2, G3 in 16-bit Q0 format + VSHRN.S32 D23, Q14, #8 @ D22: B0, B1, B2, B3 in 16-bit Q0 format + + /*------------------------------------------------------------------------- + * Clamp the value to be within [0~255] + * ------------------------------------------------------------------------ */ + VMAX.S16 Q11, Q11, Q4 @ if Q11 < 0, Q11 = 0 + VMIN.S16 Q11, Q11, Q5 @ if Q11 > 255, Q11 = 255 + VQMOVUN.S16 D28, Q11 @ store Blue to D28, narrow the value from int16 to int8 + + VMAX.S16 Q10, Q10, Q4 @ if Q10 < 0, Q10 = 0 + VMIN.S16 Q10, Q10, Q5 @ if Q10 > 255, Q10 = 255 + VQMOVUN.S16 D27, Q10 @ store Green to D27, narrow the value from int16 to int8 + + VMAX.S16 Q9, Q9, Q4 @ if Q9 < 0, Q9 = 0 + VMIN.S16 Q9, Q9, Q5 @ if Q9 > 255, Q9 = 255 + VQMOVUN.S16 D26, Q9 @ store Red to D26, narrow the value from int16 to int8 + + /*------------------------------------------------------------------------- + * abgr format with leading 0xFF byte + * ------------------------------------------------------------------------ */ + VMOVN.I16 D29, Q5 @ D29: 255 | 255 | 255 | 255 | 255 | 255 | 255 | 255 + + SUBS length, length, #8 @ check if the length is less than 8 + + BMI trailing_yvup2abgr @ jump to trailing processing if remaining length is less than 8 + + VST4.U8 {D26,D27,D28,D29}, [p_bgr]! @ vector store Red, Green, Blue to destination + @ Blue at LSB + + BHI loop_yvup2abgr @ loop if more than 8 pixels left + + BEQ end_yvup2abgr @ done if exactly 8 pixel processed in the loop + + +trailing_yvup2abgr: + /*------------------------------------------------------------------------- + * There are from 1 ~ 7 pixels left in the trailing part. + * First adding 7 to the length so the length would be from 0 ~ 6. + * eg: 1 pixel left in the trailing part, so 1-8+7 = 0. + * Then save 1 pixel unconditionally since at least 1 pixels left in the + * trailing part. + * ------------------------------------------------------------------------ */ + ADDS length, length, #7 @ there are 7 or less in the trailing part + + VST4.U8 {D26[0], D27[0], D28[0], D29[0]}, [p_bgr]! @ at least 1 pixel left in the trailing part + BEQ end_yvup2abgr @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST4.U8 {D26[1], D27[1], D28[1], D29[1]}, [p_bgr]! @ store one more pixel + BEQ end_yvup2abgr @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST4.U8 {D26[2], D27[2], D28[2], D29[2]}, [p_bgr]! @ store one more pixel + BEQ end_yvup2abgr @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST4.U8 {D26[3], D27[3], D28[3], D29[3]}, [p_bgr]! @ store one more pixel + BEQ end_yvup2abgr @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST4.U8 {D26[4], D27[4], D28[4], D29[4]}, [p_bgr]! @ store one more pixel + BEQ end_yvup2abgr @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST4.U8 {D26[5], D27[5], D28[5], D29[5]}, [p_bgr]! @ store one more pixel + BEQ end_yvup2abgr @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST4.U8 {D26[6], D27[6], D28[6], D29[6]}, [p_bgr]! @ store one more pixel + +end_yvup2abgr: + VPOP {D8-D15} + LDMFD SP!, {PC} + @ end of yvup2abgr + +/*-------------------------------------------------------------------------- +* FUNCTION : yyvup2abgr8888_venum +*-------------------------------------------------------------------------- +* DESCRIPTION : Perform YYVU planar to ABGR8888 conversion. +*-------------------------------------------------------------------------- +* C PROTOTYPE : void yyvup2abgr8888_venum(uint8_t *p_y, +* uint8_t *p_cr, +* uint8_t *p_cb, +* uint8_t *p_abgr8888, +* uint32_t length) +*-------------------------------------------------------------------------- +* REG INPUT : R0: uint8_t *p_y +* pointer to the input Y Line +* R1: uint8_t *p_cr +* pointer to the input Cr Line +* R2: uint8_t *p_cb +* pointer to the input Cb Line +* R3: uint8_t *p_abgr8888 +* pointer to the output ABGR Line +* R12: uint32_t length +* width of Line +*-------------------------------------------------------------------------- +* STACK ARG : None +*-------------------------------------------------------------------------- +* REG OUTPUT : None +*-------------------------------------------------------------------------- +* MEM INPUT : p_y - a line of Y pixels +* p_cr - a line of Cr pixels +* p_cb - a line of Cb pixels +* length - the width of the input line +*-------------------------------------------------------------------------- +* MEM OUTPUT : p_abgr8888 - the converted ABGR pixels +*-------------------------------------------------------------------------- +* REG AFFECTED : ARM: R0-R4, R12 +* NEON: Q0-Q15 +*-------------------------------------------------------------------------- +* STACK USAGE : none +*-------------------------------------------------------------------------- +* CYCLES : none +* +*-------------------------------------------------------------------------- +* NOTES : +*-------------------------------------------------------------------------- +*/ +.type yyvup2abgr8888_venum, %function +yyvup2abgr8888_venum: + /*------------------------------------------------------------------------- + * Store stack registers + * ------------------------------------------------------------------------ */ + STMFD SP!, {LR} + + VPUSH {D8-D15} + + PLD [R0, R3] @ preload luma line + + ADR R12, constants + + VLD1.S16 {D6, D7}, [R12]! @ D6, D7: 359 | -88 | -183 | 454 | 256 | 0 | 255 | 0 + VLD1.S32 {D30, D31}, [R12] @ Q15 : -45824 | 34816 | -57984 | X + + /*------------------------------------------------------------------------- + * Load the 5th parameter via stack + * R0 ~ R3 are used to pass the first 4 parameters, the 5th and above + * parameters are passed via stack + * ------------------------------------------------------------------------ */ + LDR R12, [SP, #68] @ LR is pushed into the stack so SP is + @ decreased by 4, + @ D8-D15 are also pushed into the stack + @ so SP is decreased by + @ 8-byte/D-Register * 8 D-Registers = 64, + @ so SP needs to be increased by 64+4=68 + @ to get the value that was first pushed + @ into stack (the 5th parameter passed in + @ throught stack) + + /*------------------------------------------------------------------------- + * Load clamping parameters to duplicate vector elements + * ------------------------------------------------------------------------ */ + VDUP.S16 Q4, D7[1] @ Q4: 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 + VDUP.S16 Q5, D7[2] @ Q5: 255 | 255 | 255 | 255 | 255 | 255 | 255 | 255 + + /*------------------------------------------------------------------------- + * Read bias + * ------------------------------------------------------------------------ */ + VDUP.S32 Q0, D30[0] @ Q0: -45824 | -45824 | -45824 | -45824 + VDUP.S32 Q1, D30[1] @ Q1: 34816 | 34816 | 34816 | 34816 + VDUP.S32 Q2, D31[0] @ Q2: -70688 | -70688 | -70688 | -70688 + + + /*------------------------------------------------------------------------- + * The main loop + * ------------------------------------------------------------------------ */ +loop_yyvup2abgr: + + /*------------------------------------------------------------------------- + * Load input from Y, V and U + * D12, D13: Y0 Y2 Y4 Y6 Y8 Y10 Y12 Y14, Y1 Y3 Y5 Y7 Y9 Y11 Y13 Y15 + * D14 : V0 V1 V2 V3 V4 V5 V6 V7 + * D15 : U0 U1 U2 U3 U4 U5 U6 U7 + * ------------------------------------------------------------------------ */ + VLD2.U8 {D12,D13}, [p_y]! @ Load 16 Luma elements (uint8) to D12, D13 + VLD1.U8 {D14}, [p_cr]! @ Load 8 Cr elements (uint8) to D14 + VLD1.U8 {D15}, [p_cb]! @ Load 8 Cb elements (uint8) to D15 + + /*------------------------------------------------------------------------- + * Expand uint8 value to uint16 + * D24, D25: Y0 Y2 Y4 Y6 Y8 Y10 Y12 Y14 + * D26, D27: Y1 Y3 Y5 Y7 Y9 Y11 Y13 Y15 + * D28, D29: V0 V1 V2 V3 V4 V5 V6 V7 + * D30, D31: U0 U1 U2 U3 U4 U5 U6 U7 + * ------------------------------------------------------------------------ */ + VMOVL.U8 Q12, D12 + VMOVL.U8 Q13, D13 + VMOVL.U8 Q14, D14 + VMOVL.U8 Q15, D15 + + /*------------------------------------------------------------------------- + * Multiply contribution from chrominance, results are in 32-bit + * ------------------------------------------------------------------------ */ + VMULL.S16 Q6, D28, D6[0] @ Q6: 359*(V0,V1,V2,V3) Red + VMULL.S16 Q7, D30, D6[1] @ Q7: -88*(U0,U1,U2,U3) Green + VMLAL.S16 Q7, D28, D6[2] @ Q7: -88*(U0,U1,U2,U3) - 183*(V0,V1,V2,V3) + VMULL.S16 Q8, D30, D6[3] @ Q8: 454*(U0,U1,U2,U3) Blue + + /*------------------------------------------------------------------------- + * Add bias + * ------------------------------------------------------------------------ */ + VADD.S32 Q6, Q0 @ Q6 add Red bias -45824 + VADD.S32 Q7, Q1 @ Q7 add Green bias 34816 + VADD.S32 Q8, Q2 @ Q8 add Blue bias -57984 + + /*------------------------------------------------------------------------- + * Calculate Red, Green, Blue + * ------------------------------------------------------------------------ */ + VMOV.S32 Q9, Q6 + VMLAL.S16 Q6, D24, D7[0] @ Q6: R0, R2, R4, R6 in 32-bit Q8 format + VMLAL.S16 Q9, D26, D7[0] @ Q9: R1, R3, R5, R7 in 32-bit Q8 format + + VMOV.S32 Q10, Q7 + VMLAL.S16 Q7, D24, D7[0] @ Q7: G0, G2, G4, G6 in 32-bit Q8 format + VMLAL.S16 Q10, D26, D7[0] @ Q10: G1, G3, G5, G7 in 32-bit Q8 format + + VMOV.S32 Q11, Q8 + VMLAL.S16 Q8, D24, D7[0] @ Q8: B0, B2, B4, B6 in 32-bit Q8 format + VMLAL.S16 Q11, D26, D7[0] @ Q11: B1, B3, B5, B7 in 32-bit Q8 format + + /*------------------------------------------------------------------------- + * Right shift eight bits with rounding + * ------------------------------------------------------------------------ */ + VSHRN.S32 D12, Q6, #8 @ D12: R0 R2 R4 R6 in 16-bit Q0 format + VSHRN.S32 D13, Q9, #8 @ D13: R1 R3 R5 R7 in 16-bit Q0 format + VZIP.16 D12, D13 @ Q6 : R0 R1 R2 R3 R4 R5 R6 R7 + + VSHRN.S32 D18, Q7, #8 @ D18: G0 G2 G4 G6 in 16-bit Q0 format + VSHRN.S32 D19, Q10, #8 @ D19: G1 G3 G5 G7 in 16-bit Q0 format + VZIP.16 D18, D19 @ Q9 : G0 G1 G2 G3 G4 G5 G6 G7 + + VSHRN.S32 D20, Q8, #8 @ D20: B0 B2 B4 B6 in 16-bit Q0 format + VSHRN.S32 D21, Q11, #8 @ D21: B1 B3 B5 B7 in 16-bit Q0 format + VZIP.16 D20, D21 @ Q10: B0 B1 B2 B3 B4 B5 B6 B7 + + /*------------------------------------------------------------------------- + * Clamp the value to be within [0~255] + * ------------------------------------------------------------------------ */ + VMAX.S16 Q10, Q10, Q4 @ if Q10 < 0, Q10 = 0 + VMIN.S16 Q10, Q10, Q5 @ if Q10 > 255, Q10 = 255 + VQMOVUN.S16 D23, Q10 @ store Blue to D23, narrow the value from int16 to int8 + + VMAX.S16 Q9, Q9, Q4 @ if Q9 < 0, Q9 = 0 + VMIN.S16 Q9, Q9, Q5 @ if Q9 > 255, Q9 = 255 + VQMOVUN.S16 D22, Q9 @ store Green to D22, narrow the value from int16 to int8 + + VMAX.S16 Q6, Q6, Q4 @ if Q6 < 0, Q6 = 0 + VMIN.S16 Q6, Q6, Q5 @ if Q6 > 255, Q6 = 255 + VQMOVUN.S16 D21, Q6 @ store Red to D21, narrow the value from int16 to int8 + + /*------------------------------------------------------------------------- + * abgr format with leading 0xFF byte + * ------------------------------------------------------------------------ */ + VMOVN.I16 D24, Q5 @ D24: 255 | 255 | 255 | 255 | 255 | 255 | 255 | 255 + + SUBS length, length, #8 @ check if the length is less than 8 + + BMI trailing_yyvup2abgr @ jump to trailing processing if remaining length is less than 8 + + VST4.U8 {D21,D22,D23,D24}, [p_bgr]! @ vector store Blue, Green, Red to destination + @ Red at LSB + + BEQ end_yyvup2abgr @ done if exactly 8 pixel processed in the loop + + + /*------------------------------------------------------------------------- + * Done with the first 8 elements, continue on the next 8 elements + * ------------------------------------------------------------------------ */ + + /*------------------------------------------------------------------------- + * Multiply contribution from chrominance, results are in 32-bit + * ------------------------------------------------------------------------ */ + VMULL.S16 Q6, D29, D6[0] @ Q6: 359*(V4,V5,V6,V7) Red + VMULL.S16 Q7, D31, D6[1] @ Q7: -88*(U4,U5,U6,U7) Green + VMLAL.S16 Q7, D29, D6[2] @ Q7: -88*(U4,U5,U6,U7) - 183*(V4,V5,V6,V7) + VMULL.S16 Q8, D31, D6[3] @ Q8: 454*(U4,U5,U6,U7) Blue + + /*------------------------------------------------------------------------- + * Add bias + * ------------------------------------------------------------------------ */ + VADD.S32 Q6, Q0 @ Q6 add Red bias -45824 + VADD.S32 Q7, Q1 @ Q7 add Green bias 34816 + VADD.S32 Q8, Q2 @ Q8 add Blue bias -57984 + + /*------------------------------------------------------------------------- + * Calculate Red, Green, Blue + * ------------------------------------------------------------------------ */ + VMOV.S32 Q9, Q6 + VMLAL.S16 Q6, D25, D7[0] @ Q6: R8 R10 R12 R14 in 32-bit Q8 format + VMLAL.S16 Q9, D27, D7[0] @ Q9: R9 R11 R13 R15 in 32-bit Q8 format + + VMOV.S32 Q10, Q7 + VMLAL.S16 Q7, D25, D7[0] @ Q7: G0, G2, G4, G6 in 32-bit Q8 format + VMLAL.S16 Q10, D27, D7[0] @ Q10 : G1, G3, G5, G7 in 32-bit Q8 format + + VMOV.S32 Q11, Q8 + VMLAL.S16 Q8, D25, D7[0] @ Q8: B0, B2, B4, B6 in 32-bit Q8 format + VMLAL.S16 Q11, D27, D7[0] @ Q11 : B1, B3, B5, B7 in 32-bit Q8 format + + /*------------------------------------------------------------------------- + * Right shift eight bits with rounding + * ------------------------------------------------------------------------ */ + VSHRN.S32 D12, Q6, #8 @ D12: R8 R10 R12 R14 in 16-bit Q0 format + VSHRN.S32 D13, Q9, #8 @ D13: R9 R11 R13 R15 in 16-bit Q0 format + VZIP.16 D12, D13 @ Q6: R8 R9 R10 R11 R12 R13 R14 R15 + + VSHRN.S32 D18, Q7, #8 @ D18: G8 G10 G12 G14 in 16-bit Q0 format + VSHRN.S32 D19, Q10, #8 @ D19: G9 G11 G13 G15 in 16-bit Q0 format + VZIP.16 D18, D19 @ Q9: G8 G9 G10 G11 G12 G13 G14 G15 + + VSHRN.S32 D20, Q8, #8 @ D20: B8 B10 B12 B14 in 16-bit Q0 format + VSHRN.S32 D21, Q11, #8 @ D21: B9 B11 B13 B15 in 16-bit Q0 format + VZIP.16 D20, D21 @ Q10: B8 B9 B10 B11 B12 B13 B14 B15 + + /*------------------------------------------------------------------------- + * Clamp the value to be within [0~255] + * ------------------------------------------------------------------------ */ + VMAX.S16 Q10, Q10, Q4 @ if Q10 < 0, Q10 = 0 + VMIN.S16 Q10, Q10, Q5 @ if Q10 > 255, Q10 = 255 + VQMOVUN.S16 D23, Q10 @ store Blue to D23, narrow the value from int16 to int8 + + VMAX.S16 Q9, Q9, Q4 @ if Q9 < 0, Q9 = 0 + VMIN.S16 Q9, Q9, Q5 @ if Q9 > 255, Q9 = 255 + VQMOVUN.S16 D22, Q9 @ store Green to D22, narrow the value from int16 to int8 + + VMAX.S16 Q6, Q6, Q4 @ if Q6 < 0, Q6 = 0 + VMIN.S16 Q6, Q6, Q5 @ if Q6 > 255, Q6 = 255 + VQMOVUN.S16 D21, Q6 @ store Red to D21, narrow the value from int16 to int8 + + /*------------------------------------------------------------------------- + * abgr format with leading 0xFF byte + * ------------------------------------------------------------------------ */ + VMOVN.I16 D24, Q5 @ D24: 255 | 255 | 255 | 255 | 255 | 255 | 255 | 255 + + SUBS length, length, #8 @ check if the length is less than 8 + + BMI trailing_yyvup2abgr @ jump to trailing processing if remaining length is less than 8 + + VST4.U8 {D21,D22,D23,D24}, [p_bgr]! @ vector store Blue, Green, Red to destination + @ Red at LSB + + BHI loop_yyvup2abgr @ loop if more than 8 pixels left + + BEQ end_yyvup2abgr @ done if exactly 8 pixel processed in the loop + + +trailing_yyvup2abgr: + /*------------------------------------------------------------------------- + * There are from 1 ~ 7 pixels left in the trailing part. + * First adding 7 to the length so the length would be from 0 ~ 6. + * eg: 1 pixel left in the trailing part, so 1-8+7 = 0. + * Then save 1 pixel unconditionally since at least 1 pixels left in the + * trailing part. + * ------------------------------------------------------------------------ */ + ADDS length, length, #7 @ there are 7 or less in the trailing part + + VST4.U8 {D21[0],D22[0],D23[0],D24[0]}, [p_bgr]! @ at least 1 pixel left in the trailing part + BEQ end_yyvup2abgr @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST4.U8 {D21[1],D22[1],D23[1],D24[1]}, [p_bgr]! @ store one more pixel + BEQ end_yyvup2abgr @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST4.U8 {D21[2],D22[2],D23[2],D24[2]}, [p_bgr]! @ store one more pixel + BEQ end_yyvup2abgr @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST4.U8 {D21[3],D22[3],D23[3],D24[3]}, [p_bgr]! @ store one more pixel + BEQ end_yyvup2abgr @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST4.U8 {D21[4],D22[4],D23[4],D24[4]}, [p_bgr]! @ store one more pixel + BEQ end_yyvup2abgr @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST4.U8 {D21[5],D22[5],D23[5],D24[5]}, [p_bgr]! @ store one more pixel + BEQ end_yyvup2abgr @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST4.U8 {D21[6],D22[6],D23[6],D24[6]}, [p_bgr]! @ store one more pixel + +end_yyvup2abgr: + VPOP {D8-D15} + LDMFD SP!, {PC} + @ end of yyvup2abgr + +.end + diff --git a/src/jni/jpeg/asm/armv7/jdcolor-armv7.S b/src/jni/jpeg/asm/armv7/jdcolor-armv7.S new file mode 100644 index 0000000000..b2da6d5d0c --- /dev/null +++ b/src/jni/jpeg/asm/armv7/jdcolor-armv7.S @@ -0,0 +1,632 @@ +/*------------------------------------------------------------------------ +* jdcolor-armv7.S +* +* Copyright (c) 2010, Code Aurora Forum. All rights reserved. +* +* 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 Code Aurora Forum, Inc. 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 "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. +*-------------------------------------------------------------------------- + +*-------------------------------------------------------------------------- +* FUNCTION LIST +*-------------------------------------------------------------------------- +* +* - yvup2bgr888_venum +* - yyvup2bgr888_venum +* +*-------------------------------------------------------------------------- +*/ + + .section yvu_plain_to_bgr, "x" @ AREA + .text @ |.text|, CODE, READONLY + .align 2 + .code 32 @ CODE32 + +/*----------------------------------------------------------------------------- + * ARM Registers + * ---------------------------------------------------------------------------- */ +p_y .req r0 +p_cr .req r1 +p_cb .req r2 +p_rgb .req r3 +p_bgr .req r3 +length .req r12 + + .global yvup2bgr888_venum + .global yyvup2bgr888_venum + +@ coefficients in color conversion matrix multiplication +.equ COEFF_Y, 256 @ contribution of Y +.equ COEFF_V_RED, 359 @ contribution of V for red +.equ COEFF_U_GREEN, -88 @ contribution of U for green +.equ COEFF_V_GREEN, -183 @ contribution of V for green +.equ COEFF_U_BLUE, 454 @ contribution of U for blue + +@ Clamping constants 0x0 and 0xFF +.equ COEFF_0, 0 +.equ COEFF_255, 255 + +@ Bias coefficients for red, green and blue +.equ COEFF_BIAS_R, -45824 @ Red bias = -359*128 + 128 +.equ COEFF_BIAS_G, 34816 @ Green bias = (88+183)*128 + 128 +.equ COEFF_BIAS_B, -57984 @ Blue bias = -454*128 + 128 + +constants: + .hword (COEFF_V_RED), (COEFF_U_GREEN), (COEFF_V_GREEN), (COEFF_U_BLUE) @ 359 | -88 | -183 | 454 + .hword (COEFF_Y), (COEFF_0), (COEFF_255) , (COEFF_0) @ 256 | 0 | 255 | 0 + .word (COEFF_BIAS_R), (COEFF_BIAS_G), (COEFF_BIAS_B) @ -45824 | 34816 | -57984 | X + +/*-------------------------------------------------------------------------- +* FUNCTION : yvup2bgr888_venum +*-------------------------------------------------------------------------- +* DESCRIPTION : Perform YVU planar to BGR888 conversion. +*-------------------------------------------------------------------------- +* C PROTOTYPE : void yvup2bgr888_venum(uint8_t *p_y, +* uint8_t *p_cr, +* uint8_t *p_cb, +* uint8_t *p_bgr888, +* uint32_t length) +*-------------------------------------------------------------------------- +* REG INPUT : R0: uint8_t *p_y +* pointer to the input Y Line +* R1: uint8_t *p_cr +* pointer to the input Cr Line +* R2: uint8_t *p_cb +* pointer to the input Cb Line +* R3: uint8_t *p_bgr888 +* pointer to the output BGR Line +* R12: uint32_t length +* width of Line +*-------------------------------------------------------------------------- +* STACK ARG : None +*-------------------------------------------------------------------------- +* REG OUTPUT : None +*-------------------------------------------------------------------------- +* MEM INPUT : p_y - a line of Y pixels +* p_cr - a line of Cr pixels +* p_cb - a line of Cb pixels +* length - the width of the input line +*-------------------------------------------------------------------------- +* MEM OUTPUT : p_bgr888 - the converted bgr pixels +*-------------------------------------------------------------------------- +* REG AFFECTED : ARM: R0-R4, R12 +* NEON: Q0-Q15 +*-------------------------------------------------------------------------- +* STACK USAGE : none +*-------------------------------------------------------------------------- +* CYCLES : none +* +*-------------------------------------------------------------------------- +* NOTES : +*-------------------------------------------------------------------------- +*/ +.type yvup2bgr888_venum, %function +yvup2bgr888_venum: + + /*------------------------------------------------------------------------- + * Store stack registers + * ------------------------------------------------------------------------ */ + STMFD SP!, {LR} + + VPUSH {D8-D15} + + PLD [R0, R3] @ preload luma line + + ADR R12, constants + + VLD1.S16 {D6, D7}, [R12]! @ D6, D7: 359 | -88 | -183 | 454 | 256 | 0 | 255 | 0 + VLD1.S32 {D30, D31}, [R12] @ Q15 : -45824 | 34816 | -57984 | X + + /*------------------------------------------------------------------------- + * Load the 5th parameter via stack + * R0 ~ R3 are used to pass the first 4 parameters, the 5th and above + * parameters are passed via stack + * ------------------------------------------------------------------------ */ + LDR R12, [SP, #68] @ LR is pushed into the stack so SP is + @ decreased by 4, + @ D8-D15 are also pushed into the stack + @ so SP is decreased by + @ 8-byte/D-Register * 8 D-Registers = 64, + @ so SP needs to be increased by 64+4=68 + @ to get the value that was first pushed + @ into stack (the 5th parameter passed in + @ throught stack) + + /*------------------------------------------------------------------------- + * Load clamping parameters to duplicate vector elements + * ------------------------------------------------------------------------ */ + VDUP.S16 Q4, D7[1] @ Q4: 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 + VDUP.S16 Q5, D7[2] @ Q5: 255 | 255 | 255 | 255 | 255 | 255 | 255 | 255 + + /*------------------------------------------------------------------------- + * Read bias + * ------------------------------------------------------------------------ */ + VDUP.S32 Q0, D30[0] @ Q0: -45824 | -45824 | -45824 | -45824 + VDUP.S32 Q1, D30[1] @ Q1: 34816 | 34816 | 34816 | 34816 + VDUP.S32 Q2, D31[0] @ Q2: -57984 | -57984 | -57984 | -57984 + + + /*------------------------------------------------------------------------- + * The main loop + * ------------------------------------------------------------------------ */ +loop_yvup2bgr888: + + /*------------------------------------------------------------------------- + * Load input from Y, V and U + * D12 : Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 + * D14 : V0 V1 V2 V3 V4 V5 V6 V7 + * D15 : U0 U1 U2 U3 U4 U5 U6 U7 + * ------------------------------------------------------------------------ */ + VLD1.U8 {D12}, [p_y]! @ Load 8 Luma elements (uint8) to D12 + VLD1.U8 {D14}, [p_cr]! @ Load 8 Cr elements (uint8) to D14 + VLD1.U8 {D15}, [p_cb]! @ Load 8 Cb elements (uint8) to D15 + + /*------------------------------------------------------------------------- + * Expand uint8 value to uint16 + * D18, D19: Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 + * D20, D21: V0 V1 V2 V3 V4 V5 V6 V7 + * D22, D23: U0 U1 U2 U3 U4 U5 U6 U7 + * ------------------------------------------------------------------------ */ + VMOVL.U8 Q9, D12 + VMOVL.U8 Q10, D14 + VMOVL.U8 Q11, D15 + + /*------------------------------------------------------------------------- + * Multiply contribution from chrominance, results are in 32-bit + * ------------------------------------------------------------------------ */ + VMULL.S16 Q12, D20, D6[0] @ Q12: 359*(V0,V1,V2,V3) Red + VMULL.S16 Q13, D22, D6[1] @ Q13: -88*(U0,U1,U2,U3) Green + VMLAL.S16 Q13, D20, D6[2] @ Q13: -88*(U0,U1,U2,U3) - 183*(V0,V1,V2,V3) + VMULL.S16 Q14, D22, D6[3] @ Q14: 454*(U0,U1,U2,U3) Blue + + /*------------------------------------------------------------------------- + * Add bias + * ------------------------------------------------------------------------ */ + VADD.S32 Q12, Q0 @ Q12 add Red bias -45824 + VADD.S32 Q13, Q1 @ Q13 add Green bias 34816 + VADD.S32 Q14, Q2 @ Q14 add Blue bias -57984 + + /*------------------------------------------------------------------------- + * Calculate Red, Green, Blue + * ------------------------------------------------------------------------ */ + VMLAL.S16 Q12, D18, D7[0] @ Q12: R0, R1, R2, R3 in 32-bit Q8 format + VMLAL.S16 Q13, D18, D7[0] @ Q13: G0, G1, G2, G3 in 32-bit Q8 format + VMLAL.S16 Q14, D18, D7[0] @ Q14: B0, B1, B2, B3 in 32-bit Q8 format + + /*------------------------------------------------------------------------- + * Right shift eight bits with rounding + * ------------------------------------------------------------------------ */ + VSHRN.S32 D18 , Q12, #8 @ D18: R0, R1, R2, R3 in 16-bit Q0 format + VSHRN.S32 D20 , Q13, #8 @ D20: G0, G1, G2, G3 in 16-bit Q0 format + VSHRN.S32 D22, Q14, #8 @ D22: B0, B1, B2, B3 in 16-bit Q0 format + + /*------------------------------------------------------------------------- + * Done with the first 4 elements, continue on the next 4 elements + * ------------------------------------------------------------------------ */ + + /*------------------------------------------------------------------------- + * Multiply contribution from chrominance, results are in 32-bit + * ------------------------------------------------------------------------ */ + VMULL.S16 Q12, D21, D6[0] @ Q12: 359*(V0,V1,V2,V3) Red + VMULL.S16 Q13, D23, D6[1] @ Q13: -88*(U0,U1,U2,U3) Green + VMLAL.S16 Q13, D21, D6[2] @ Q13: -88*(U0,U1,U2,U3) - 183*(V0,V1,V2,V3) + VMULL.S16 Q14, D23, D6[3] @ Q14: 454*(U0,U1,U2,U3) Blue + + /*------------------------------------------------------------------------- + * Add bias + * ------------------------------------------------------------------------ */ + VADD.S32 Q12, Q0 @ Q12 add Red bias -45824 + VADD.S32 Q13, Q1 @ Q13 add Green bias 34816 + VADD.S32 Q14, Q2 @ Q14 add Blue bias -57984 + + /*------------------------------------------------------------------------- + * Calculate Red, Green, Blue + * ------------------------------------------------------------------------ */ + VMLAL.S16 Q12, D19, D7[0] @ Q12: R0, R1, R2, R3 in 32-bit Q8 format + VMLAL.S16 Q13, D19, D7[0] @ Q13: G0, G1, G2, G3 in 32-bit Q8 format + VMLAL.S16 Q14, D19, D7[0] @ Q14: B0, B1, B2, B3 in 32-bit Q8 format + + /*------------------------------------------------------------------------- + * Right shift eight bits with rounding + * ------------------------------------------------------------------------ */ + VSHRN.S32 D19 , Q12, #8 @ D18: R0, R1, R2, R3 in 16-bit Q0 format + VSHRN.S32 D21 , Q13, #8 @ D20: G0, G1, G2, G3 in 16-bit Q0 format + VSHRN.S32 D23, Q14, #8 @ D22: B0, B1, B2, B3 in 16-bit Q0 format + + /*------------------------------------------------------------------------- + * Clamp the value to be within [0~255] + * ------------------------------------------------------------------------ */ + VMAX.S16 Q11, Q11, Q4 @ if Q11 < 0, Q11 = 0 + VMIN.S16 Q11, Q11, Q5 @ if Q11 > 255, Q11 = 255 + VQMOVUN.S16 D28, Q11 @ store Blue to D28, narrow the value from int16 to int8 + + VMAX.S16 Q10, Q10, Q4 @ if Q10 < 0, Q10 = 0 + VMIN.S16 Q10, Q10, Q5 @ if Q10 > 255, Q10 = 255 + VQMOVUN.S16 D27, Q10 @ store Green to D27, narrow the value from int16 to int8 + + VMAX.S16 Q9, Q9, Q4 @ if Q9 < 0, Q9 = 0 + VMIN.S16 Q9, Q9, Q5 @ if Q9 > 255, Q9 = 255 + VQMOVUN.S16 D26, Q9 @ store Red to D26, narrow the value from int16 to int8. + + SUBS length, length, #8 @ check if the length is less than 8 + + BMI trailing_yvup2bgr888 @ jump to trailing processing if remaining length is less than 8 + + VST3.U8 {D26,D27,D28}, [p_bgr]! @ vector store Red, Green, Blue to destination + @ Blue at LSB + + BHI loop_yvup2bgr888 @ loop if more than 8 pixels left + + BEQ end_yvup2bgr888 @ done if exactly 8 pixel processed in the loop + + +trailing_yvup2bgr888: + /*------------------------------------------------------------------------- + * There are from 1 ~ 7 pixels left in the trailing part. + * First adding 7 to the length so the length would be from 0 ~ 6. + * eg: 1 pixel left in the trailing part, so 1-8+7 = 0. + * Then save 1 pixel unconditionally since at least 1 pixels left in the + * trailing part. + * ------------------------------------------------------------------------ */ + ADDS length, length, #7 @ there are 7 or less in the trailing part + + VST3.U8 {D26[0], D27[0], D28[0]}, [p_bgr]! @ at least 1 pixel left in the trailing part + BEQ end_yvup2bgr888 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST3.U8 {D26[1], D27[1], D28[1]}, [p_bgr]! @ store one more pixel + BEQ end_yvup2bgr888 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST3.U8 {D26[2], D27[2], D28[2]}, [p_bgr]! @ store one more pixel + BEQ end_yvup2bgr888 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST3.U8 {D26[3], D27[3], D28[3]}, [p_bgr]! @ store one more pixel + BEQ end_yvup2bgr888 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST3.U8 {D26[4], D27[4], D28[4]}, [p_bgr]! @ store one more pixel + BEQ end_yvup2bgr888 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST3.U8 {D26[5], D27[5], D28[5]}, [p_bgr]! @ store one more pixel + BEQ end_yvup2bgr888 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST3.U8 {D26[6], D27[6], D28[6]}, [p_bgr]! @ store one more pixel + +end_yvup2bgr888: + VPOP {D8-D15} + LDMFD SP!, {PC} + + @ end of yvup2bgr888 + + +/*------------------------------------------------------------------------- +* FUNCTION : yyvup2bgr888_venum +*-------------------------------------------------------------------------- +* DESCRIPTION : Perform YYVU planar to BGR888 conversion. +*-------------------------------------------------------------------------- +* C PROTOTYPE : void yyvup2bgr888_venum(uint8_t *p_y, +* uint8_t *p_cr, +* uint8_t *p_cb, +* uint8_t *p_bgr888, +* uint32_t length) +*-------------------------------------------------------------------------- +* REG INPUT : R0: uint8_t *p_y +* pointer to the input Y Line +* R1: uint8_t *p_cr +* pointer to the input Cr Line +* R2: uint8_t *p_cb +* pointer to the input Cb Line +* R3: uint8_t *p_bgr888 +* pointer to the output BGR Line +* R12: uint32_t length +* width of Line +*-------------------------------------------------------------------------- +* STACK ARG : None +*-------------------------------------------------------------------------- +* REG OUTPUT : None +*-------------------------------------------------------------------------- +* MEM INPUT : p_y - a line of Y pixels +* p_cr - a line of Cr pixels +* p_cb - a line of Cb pixels +* length - the width of the input line +*-------------------------------------------------------------------------- +* MEM OUTPUT : p_bgr888 - the converted bgr pixels +*-------------------------------------------------------------------------- +* REG AFFECTED : ARM: R0-R4, R12 +* NEON: Q0-Q15 +*-------------------------------------------------------------------------- +* STACK USAGE : none +*-------------------------------------------------------------------------- +* CYCLES : none +* +*-------------------------------------------------------------------------- +* NOTES : +*-------------------------------------------------------------------------- +*/ +.type yyvup2bgr888_venum, %function +yyvup2bgr888_venum: + /*------------------------------------------------------------------------- + * Store stack registers + * ------------------------------------------------------------------------ */ + STMFD SP!, {LR} + + VPUSH {D8-D15} + + PLD [R0, R3] @ preload luma line + + ADR R12, constants + + VLD1.S16 {D6, D7}, [R12]! @ D6, D7: 359 | -88 | -183 | 454 | 256 | 0 | 255 | 0 + VLD1.S32 {D30, D31}, [R12] @ Q15 : -45824 | 34816 | -57984 | X + + /*------------------------------------------------------------------------- + * Load the 5th parameter via stack + * R0 ~ R3 are used to pass the first 4 parameters, the 5th and above + * parameters are passed via stack + * ------------------------------------------------------------------------ */ + LDR R12, [SP, #68] @ LR is pushed into the stack so SP is + @ decreased by 4, + @ D8-D15 are also pushed into the stack + @ so SP is decreased by + @ 8-byte/D-Register * 8 D-Registers = 64, + @ so SP needs to be increased by 64+4=68 + @ to get the value that was first pushed + @ into stack (the 5th parameter passed in + @ throught stack) + + /*------------------------------------------------------------------------- + * Load clamping parameters to duplicate vector elements + * ------------------------------------------------------------------------ */ + VDUP.S16 Q4, D7[1] @ Q4: 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 + VDUP.S16 Q5, D7[2] @ Q5: 255 | 255 | 255 | 255 | 255 | 255 | 255 | 255 + + /*------------------------------------------------------------------------- + * Read bias + * ------------------------------------------------------------------------ */ + VDUP.S32 Q0, D30[0] @ Q0: -45824 | -45824 | -45824 | -45824 + VDUP.S32 Q1, D30[1] @ Q1: 34816 | 34816 | 34816 | 34816 + VDUP.S32 Q2, D31[0] @ Q2: -70688 | -70688 | -70688 | -70688 + + + /*------------------------------------------------------------------------- + * The main loop + * ------------------------------------------------------------------------ */ +loop_yyvup2bgr888: + + /*------------------------------------------------------------------------- + * Load input from Y, V and U + * D12, D13: Y0 Y2 Y4 Y6 Y8 Y10 Y12 Y14, Y1 Y3 Y5 Y7 Y9 Y11 Y13 Y15 + * D14 : V0 V1 V2 V3 V4 V5 V6 V7 + * D15 : U0 U1 U2 U3 U4 U5 U6 U7 + * ------------------------------------------------------------------------ */ + VLD2.U8 {D12,D13}, [p_y]! @ Load 16 Luma elements (uint8) to D12, D13 + VLD1.U8 {D14}, [p_cr]! @ Load 8 Cr elements (uint8) to D14 + VLD1.U8 {D15}, [p_cb]! @ Load 8 Cb elements (uint8) to D15 + + /*------------------------------------------------------------------------- + * Expand uint8 value to uint16 + * D24, D25: Y0 Y2 Y4 Y6 Y8 Y10 Y12 Y14 + * D26, D27: Y1 Y3 Y5 Y7 Y9 Y11 Y13 Y15 + * D28, D29: V0 V1 V2 V3 V4 V5 V6 V7 + * D30, D31: U0 U1 U2 U3 U4 U5 U6 U7 + * ------------------------------------------------------------------------ */ + VMOVL.U8 Q12, D12 + VMOVL.U8 Q13, D13 + VMOVL.U8 Q14, D14 + VMOVL.U8 Q15, D15 + + /*------------------------------------------------------------------------- + * Multiply contribution from chrominance, results are in 32-bit + * ------------------------------------------------------------------------ */ + VMULL.S16 Q6, D28, D6[0] @ Q6: 359*(V0,V1,V2,V3) Red + VMULL.S16 Q7, D30, D6[1] @ Q7: -88*(U0,U1,U2,U3) Green + VMLAL.S16 Q7, D28, D6[2] @ q7: -88*(U0,U1,U2,U3) - 183*(V0,V1,V2,V3) + VMULL.S16 Q8, D30, D6[3] @ q8: 454*(U0,U1,U2,U3) Blue + + /*------------------------------------------------------------------------- + * Add bias + * ------------------------------------------------------------------------ */ + VADD.S32 Q6, Q0 @ Q6 add Red bias -45824 + VADD.S32 Q7, Q1 @ Q7 add Green bias 34816 + VADD.S32 Q8, Q2 @ Q8 add Blue bias -57984 + + /*------------------------------------------------------------------------- + * Calculate Red, Green, Blue + * ------------------------------------------------------------------------ */ + VMOV.S32 Q9, Q6 + VMLAL.S16 Q6, D24, D7[0] @ Q6: R0, R2, R4, R6 in 32-bit Q8 format + VMLAL.S16 Q9, D26, D7[0] @ Q9: R1, R3, R5, R7 in 32-bit Q8 format + + VMOV.S32 Q10, Q7 + VMLAL.S16 Q7, D24, D7[0] @ Q7: G0, G2, G4, G6 in 32-bit Q8 format + VMLAL.S16 Q10, D26, D7[0] @ Q10: G1, G3, G5, G7 in 32-bit Q8 format + + VMOV.S32 Q11, Q8 + VMLAL.S16 Q8, D24, D7[0] @ Q8: B0, B2, B4, B6 in 32-bit Q8 format + VMLAL.S16 Q11, D26, D7[0] @ Q11: B1, B3, B5, B7 in 32-bit Q8 format + + /*------------------------------------------------------------------------- + * Right shift eight bits with rounding + * ------------------------------------------------------------------------ */ + VSHRN.S32 D12, Q6, #8 @ D12: R0 R2 R4 R6 in 16-bit Q0 format + VSHRN.S32 D13, Q9, #8 @ D13: R1 R3 R5 R7 in 16-bit Q0 format + VZIP.16 D12, D13 @ Q6 : R0 R1 R2 R3 R4 R5 R6 R7 + + VSHRN.S32 D18, Q7, #8 @ D18: G0 G2 G4 G6 in 16-bit Q0 format + VSHRN.S32 D19, Q10, #8 @ D19: G1 G3 G5 G7 in 16-bit Q0 format + VZIP.16 D18, D19 @ Q9 : G0 G1 G2 G3 G4 G5 G6 G7 + + VSHRN.S32 D20, Q8, #8 @ D20: B0 B2 B4 B6 in 16-bit Q0 format + VSHRN.S32 D21, Q11, #8 @ D21: B1 B3 B5 B7 in 16-bit Q0 format + VZIP.16 D20, D21 @ Q10: B0 B1 B2 B3 B4 B5 B6 B7 + + /*------------------------------------------------------------------------- + * Clamp the value to be within [0~255] + * ------------------------------------------------------------------------ */ + VMAX.S16 Q10, Q10, Q4 @ if Q10 < 0, Q10 = 0 + VMIN.S16 Q10, Q10, Q5 @ if Q10 > 255, Q10 = 255 + VQMOVUN.S16 D23, Q10 @ store Blue to D23, narrow the value from int16 to int8 + + VMAX.S16 Q9, Q9, Q4 @ if Q9 < 0, Q9 = 0 + VMIN.S16 Q9, Q9, Q5 @ if Q9 > 255, Q9 = 255 + VQMOVUN.S16 D22, Q9 @ store Green to D22, narrow the value from int16 to int8 + + VMAX.S16 Q6, Q6, Q4 @ if Q6 < 0, Q6 = 0 + VMIN.S16 Q6, Q6, Q5 @ if Q6 > 255, Q6 = 255 + VQMOVUN.S16 D21, Q6 @ store Red to D21, narrow the value from int16 to int8 + + SUBS length, length, #8 @ check if the length is less than 8 + + BMI trailing_yyvup2bgr888 @ jump to trailing processing if remaining length is less than 8 + + VST3.U8 {D21,D22,D23}, [p_bgr]! @ vector store Blue, Green, Red to destination + @ Red at LSB + + BEQ end_yyvup2bgr888 @ done if exactly 8 pixel processed in the loop + + /*------------------------------------------------------------------------- + * Done with the first 8 elements, continue on the next 8 elements + * ------------------------------------------------------------------------ */ + + /*------------------------------------------------------------------------- + * Multiply contribution from chrominance, results are in 32-bit + * ------------------------------------------------------------------------ */ + VMULL.S16 Q6, D29, D6[0] @ Q6: 359*(V4,V5,V6,V7) Red + VMULL.S16 Q7, D31, D6[1] @ Q7: -88*(U4,U5,U6,U7) Green + VMLAL.S16 Q7, D29, D6[2] @ Q7: -88*(U4,U5,U6,U7) - 183*(V4,V5,V6,V7) + VMULL.S16 Q8, D31, D6[3] @ Q8: 454*(U4,U5,U6,U7) Blue + + /*------------------------------------------------------------------------- + * Add bias + * ------------------------------------------------------------------------ */ + VADD.S32 Q6, Q0 @ Q6 add Red bias -45824 + VADD.S32 Q7, Q1 @ Q7 add Green bias 34816 + VADD.S32 Q8, Q2 @ Q8 add Blue bias -70688 + + /*------------------------------------------------------------------------- + * Calculate Red, Green, Blue + * ------------------------------------------------------------------------ */ + VMOV.S32 Q9, Q6 + VMLAL.S16 Q6, D25, D7[0] @ Q6: R8 R10 R12 R14 in 32-bit Q8 format + VMLAL.S16 Q9, D27, D7[0] @ Q9: R9 R11 R13 R15 in 32-bit Q8 format + + VMOV.S32 Q10, Q7 + VMLAL.S16 Q7, D25, D7[0] @ Q7: G0, G2, G4, G6 in 32-bit Q8 format + VMLAL.S16 Q10, D27, D7[0] @ Q10 : G1, G3, G5, G7 in 32-bit Q8 format + + VMOV.S32 Q11, Q8 + VMLAL.S16 Q8, D25, D7[0] @ Q8: B0, B2, B4, B6 in 32-bit Q8 format + VMLAL.S16 Q11, D27, D7[0] @ Q11 : B1, B3, B5, B7 in 32-bit Q8 format + + /*------------------------------------------------------------------------- + * Right shift eight bits with rounding + * ------------------------------------------------------------------------ */ + VSHRN.S32 D12, Q6, #8 @ D12: R8 R10 R12 R14 in 16-bit Q0 format + VSHRN.S32 D13, Q9, #8 @ D13: R9 R11 R13 R15 in 16-bit Q0 format + VZIP.16 D12, D13 @ Q6: R8 R9 R10 R11 R12 R13 R14 R15 + + VSHRN.S32 D18, Q7, #8 @ D18: G8 G10 G12 G14 in 16-bit Q0 format + VSHRN.S32 D19, Q10, #8 @ D19: G9 G11 G13 G15 in 16-bit Q0 format + VZIP.16 D18, D19 @ Q9: G8 G9 G10 G11 G12 G13 G14 G15 + + VSHRN.S32 D20, Q8, #8 @ D20: B8 B10 B12 B14 in 16-bit Q0 format + VSHRN.S32 D21, Q11, #8 @ D21: B9 B11 B13 B15 in 16-bit Q0 format + VZIP.16 D20, D21 @ Q10: B8 B9 B10 B11 B12 B13 B14 B15 + + /*------------------------------------------------------------------------- + * Clamp the value to be within [0~255] + * ------------------------------------------------------------------------ */ + VMAX.S16 Q10, Q10, Q4 @ if Q10 < 0, Q10 = 0 + VMIN.S16 Q10, Q10, Q5 @ if Q10 > 255, Q10 = 255 + VQMOVUN.S16 D23, Q10 @ store Blue to D23, narrow the value from int16 to int8 + + VMAX.S16 Q9, Q9, Q4 @ if Q9 < 0, Q9 = 0 + VMIN.S16 Q9, Q9, Q5 @ if Q9 > 255, Q9 = 255 + VQMOVUN.S16 D22, Q9 @ store Green to D22, narrow the value from int16 to int8 + + VMAX.S16 Q6, Q6, Q4 @ if Q6 < 0, Q6 = 0 + VMIN.S16 Q6, Q6, Q5 @ if Q6 > 255, Q6 = 255 + VQMOVUN.S16 D21, Q6 @ store Red to D21, narrow the value from int16 to int8 + + + SUBS length, length, #8 @ check if the length is less than 8 + + BMI trailing_yyvup2bgr888 @ jump to trailing processing if remaining length is less than 8 + + VST3.U8 {D21,D22,D23}, [p_bgr]! @ vector store Blue, Green, Red to destination + @ Red at LSB + + BHI loop_yyvup2bgr888 @ loop if more than 8 pixels left + + BEQ end_yyvup2bgr888 @ done if exactly 8 pixel processed in the loop + + +trailing_yyvup2bgr888: + /*------------------------------------------------------------------------- + * There are from 1 ~ 7 pixels left in the trailing part. + * First adding 7 to the length so the length would be from 0 ~ 6. + * eg: 1 pixel left in the trailing part, so 1-8+7 = 0. + * Then save 1 pixel unconditionally since at least 1 pixels left in the + * trailing part. + * ------------------------------------------------------------------------ */ + ADDS length, length, #7 @ there are 7 or less in the trailing part + + VST3.U8 {D21[0],D22[0],D23[0]}, [p_bgr]! @ at least 1 pixel left in the trailing part + BEQ end_yyvup2bgr888 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST3.U8 {D21[1],D22[1],D23[1]}, [p_bgr]! @ store one more pixel + BEQ end_yyvup2bgr888 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST3.U8 {D21[2],D22[2],D23[2]}, [p_bgr]! @ store one more pixel + BEQ end_yyvup2bgr888 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST3.U8 {D21[3],D22[3],D23[3]}, [p_bgr]! @ store one more pixel + BEQ end_yyvup2bgr888 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST3.U8 {D21[4],D22[4],D23[4]}, [p_bgr]! @ store one more pixel + BEQ end_yyvup2bgr888 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST3.U8 {D21[5],D22[5],D23[5]}, [p_bgr]! @ store one more pixel + BEQ end_yyvup2bgr888 @ done if 0 pixel left + + SUBS length, length, #1 @ update length counter + VST3.U8 {D21[6],D22[6],D23[6]}, [p_bgr]! @ store one more pixel + +end_yyvup2bgr888: + VPOP {D8-D15} + LDMFD SP!, {PC} + + @ end of yyvup2bgr888 + +.end diff --git a/src/jni/jpeg/asm/armv7/jdidct-armv7.S b/src/jni/jpeg/asm/armv7/jdidct-armv7.S new file mode 100644 index 0000000000..d61e219f73 --- /dev/null +++ b/src/jni/jpeg/asm/armv7/jdidct-armv7.S @@ -0,0 +1,762 @@ +/*========================================================================= +* jdidct-armv7.s +* +* Copyright (c) 2010, Code Aurora Forum. All rights reserved. +* +* 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 Code Aurora Forum, Inc. 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 "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. +*========================================================================== + +*========================================================================== +* FUNCTION LIST +*-------------------------------------------------------------------------- +* - idct_1x1_venum +* - idct_2x2_venum +* - idct_4x4_venum +* - idct_8x8_venum +* +*========================================================================== +*/ + +@========================================================================== +@ MACRO DEFINITION +@========================================================================== + .macro Transpose8x8 + @================================================================== + @ Transpose an 8 x 8 x 16 bit matrix in place + @ Input: q8 to q15 + @ Output: q8 to q15 + @ Registers used: q8 to q15 + @ Assumptions: 8 x 8 x 16 bit data + @================================================================== + + vswp d17, d24 @q8, q12 + vswp d23, d30 @q11, q15 + vswp d21, d28 @q10, q14 + vswp d19, d26 @q9, q13 + + vtrn.32 q8, q10 + vtrn.32 q9, q11 + vtrn.32 q12, q14 + vtrn.32 q13, q15 + + vtrn.16 q8, q9 + vtrn.16 q10, q11 + vtrn.16 q12, q13 + vtrn.16 q14, q15 + .endm + + .macro IDCT1D + @================================================================== + @ One dimensional 64 element inverse DCT + @ Input: q8 to q15 loaded with data + @ q0 loaded with constants + @ Output: q8 to q15 + @ Registers used: q0, q4 to q15 + @ Assumptions: 16 bit data, first elements in least significant + @ halfwords + @================================================================== + + @1st stage + vqrdmulh.s16 q4, q15, d0[2] @q4 = a1*vx7 + vqrdmulh.s16 q5, q9, d0[2] @q5 = a1*vx1 + vqrdmulh.s16 q6, q13, d0[3] @q6 = a2*vx5 + vqrdmulh.s16 q7, q11, d1[1] @q7 = ma2*vx3 + vqrdmulh.s16 q2, q14, d0[1] @q6 = a0*vx6 + vqrdmulh.s16 q3, q10, d0[1] @q7 = a0*vx2 + vqadd.s16 q9, q4, q9 @q9 = t1 = a1*vx7 + vx1 + vqsub.s16 q5, q5, q15 @q5 = t8 = a1*vx1 - vx7 + vqadd.s16 q15, q6, q11 @q15 = t7 = a2*vx5 + vx3 + vqadd.s16 q11, q7, q13 @q11 = t3 = ma2*vx3 + vx5 + + @2nd stage + vqadd.s16 q13, q8, q12 @q13 = t5 = vx0 + vx4 + vqsub.s16 q8, q8, q12 @q8 = t0 = vx0 - vx4 + vqadd.s16 q10, q2, q10 @q10 = t2 = a0*vx6 + vx2 + vqsub.s16 q12, q3, q14 @q12 = t4 = a0*vx2 - vx6 + vqadd.s16 q14, q5, q11 @q14 = t6 = t8 + t3 + vqsub.s16 q11, q5, q11 @q11 = t3 = t8 - t3 + vqsub.s16 q5, q9, q15 @q5 = t8 = t1 - t7 + vqadd.s16 q9, q9, q15 @q9 = t1 = t1 + t7 + + @3rd stage + vqadd.s16 q15, q13, q10 @q15 = t7 = t5 + t2 + vqsub.s16 q10, q13, q10 @q10 = t2 = t5 - t2 + vqadd.s16 q13, q8, q12 @q13 = t5 = t0 + t4 + vqsub.s16 q7, q8, q12 @q7 = t0 = t0 - t4 + vqsub.s16 q12, q5, q11 @q12 = t4 = t8 - t3 + vqadd.s16 q11, q5, q11 @q11 = t3 = t8 + t3 + + @4th stage + vqadd.s16 q8, q15, q9 @q8 = vy0 = t7 + t1 + vqsub.s16 q15, q15, q9 @q15 = vy7 = t7 - t1 + vqrdmulh.s16 q6, q12, d0[0] @q6 = c4*t4 + vqrdmulh.s16 q4, q11, d0[0] @q4 = c4*t3 + vqsub.s16 q12, q10, q14 @q12 = vy4 = t2 - t6 + vqadd.s16 q11, q10, q14 @q11 = vy3 = t2 + t6 + vqadd.s16 q10, q7, q6 @q10 = vy2 = t0 + c4*t4 + vqsub.s16 q14, q13, q4 @q14 = vy6 = t5 - c4*t3 + vqadd.s16 q9, q13, q4 @q9 = vy1 = t5 + c4*t3 + vqsub.s16 q13, q7, q6 @q13 = vy5 = t0 - c4*t4 + .endm + + .macro PART1 + @================================================================== + @ Load input input data from memory and shift + @================================================================== + vld1.16 {d16, d17},[r0]! @q8 =row0 + vqshl.s16 q8, q8, #4 @Input data too big?!! + @Maximum MPEG input is 2047/-2048. + vld1.16 {d18, d19},[r0]! @q9 =row1 + vqshl.s16 q9, q9, #4 @Shift 1 instead of 4 + + vld1.16 {d20, d21},[r0]! @q10=row2 + vqshl.s16 q10, q10, #4 + + vld1.16 {d22, d23},[r0]! @q11=row3 + vqshl.s16 q11, q11, #4 + + vld1.16 {d24, d25},[r0]! @q12=row4 + vqshl.s16 q12, q12, #4 + + vld1.16 {d26, d27},[r0]! @q13=row5 + vqshl.s16 q13, q13, #4 + vld1.16 {d28, d29},[r0]! @q14=row6 + vqshl.s16 q14, q14, #4 + vld1.16 {d30, d31},[r0]! @q15=row7 + vqshl.s16 q15, q15, #4 + + @================================================================== + @ refresh the constants that was clobbered last time through IDCT1D + @================================================================== + vld1.16 {d4, d5},[r7] @q2 =constants[2] + vld1.16 {d6, d7},[r8] @q3 =constants[3] + vld1.16 {d8, d9},[r9] @q4 =constants[4] + .endm + + .macro PART2 + @================================================================== + @ Prescale the input + @================================================================== + vqrdmulh.s16 q12, q12, q1 @q12=row4 * constants[1] = vx4 + vqrdmulh.s16 q15, q15, q2 @q15=row7 * constants[2] = vx7 + vqrdmulh.s16 q9, q9, q2 @q9 =row1 * constants[2] = vx1 + vqrdmulh.s16 q13, q13, q4 @q13=row5 * constants[4] = vx5 + vqrdmulh.s16 q11, q11, q4 @q11=row3 * constants[4] = vx3 + vqrdmulh.s16 q14, q14, q3 @q14=row6 * constants[3] = vx6 + vqrdmulh.s16 q10, q10, q3 @q10=row2 * constants[3] = vx2 + vqrdmulh.s16 q8, q8, q1 @q8 =row0 * constants[1] = vx0 + + @================================================================== + @ At thsi point, the input 8x8 x 16 bit coefficients are + @ transposed, prescaled, and loaded in q8 to q15 + @ q0 loaded with scalar constants + @ Perform 1D IDCT + @================================================================== + IDCT1D @perform 1d idct + + @================================================================== + @ Transpose the intermediate results to get read for vertical + @ transformation + @================================================================== + vswp d17, d24 @q8, q12 + vswp d23, d30 @q11, q15 + vswp d21, d28 @q10, q14 + vswp d19, d26 @q9, q13 + + @================================================================== + @ Load the bias + @================================================================== + vdup.32 q4, d1[1] @a cycle is saved by loading + @the bias at this point + + @================================================================== + @ Finish the transposition + @================================================================== + vtrn.32 q8, q10 + vtrn.32 q9, q11 + vtrn.32 q12, q14 + vtrn.32 q13, q15 + vtrn.16 q8, q9 + vtrn.16 q10, q11 + vtrn.16 q12, q13 + vtrn.16 q14, q15 + + @================================================================== + @ Add bias + @================================================================== + vqadd.s16 q8, q8, q4 + + @================================================================== + @ IDCT 2nd half + @================================================================== + IDCT1D @perform 1d dct + + @================================================================== + @ Scale and clamp the output to correct range and save to memory + @ 1. scale to 8bits by right shift 6 + @ 2. clamp output to [0, 255] by min/max + @ 3. use multiple store. Each store will save one row of output. + @ The st queue size is 4, so do no more than 4 str in sequence. + @================================================================== + ldr r5, =constants+5*16 @constants[5], + vld1.16 d10, [r5] @load clamping parameters + vdup.s16 q6, d10[0] @q6=[0000000000000000] + vdup.s16 q7, d10[1] @q7=[FFFFFFFFFFFFFFFF] + + @Save the results + vshr.s16 q8, q8, #6 @q8 = vy0 + vmax.s16 q8, q8, q6 @clamp >0 + vmin.s16 q8, q8, q7 @clamp <255 + + vshr.s16 q9, q9, #6 @q9 = vy1 + vmax.s16 q9, q9, q6 @clamp >0 + vmin.s16 q9, q9, q7 @clamp <255 + + vshr.s16 q10, q10, #6 @q10 = vy2 + vmax.s16 q10, q10, q6 @clamp >0 + vmin.s16 q10, q10, q7 @clamp <255 + + vshr.s16 q11, q11, #6 @q11 = vy3 + vmax.s16 q11, q11, q6 @clamp >0 + vmin.s16 q11, q11, q7 @clamp <255 + + vst1.16 {d16, d17},[r1],r2 @q8 =row0 + vst1.16 {d18, d19},[r1],r2 @q9 =row1 + vst1.16 {d20, d21},[r1],r2 @q10=row2 + vst1.16 {d22, d23},[r1],r2 @q11=row3 + + vshr.s16 q12, q12, #6 @q12 = vy4 + vmax.s16 q12, q12, q6 @clamp >0 + vmin.s16 q12, q12, q7 @clamp <255 + + vshr.s16 q13, q13, #6 @q13 = vy5 + vmax.s16 q13, q13, q6 @clamp >0 + vmin.s16 q13, q13, q7 @clamp <255 + + vshr.s16 q14, q14, #6 @q14 = vy6 + vmax.s16 q14, q14, q6 @clamp >0 + vmin.s16 q14, q14, q7 @clamp <255 + + vshr.s16 q15, q15, #6 @q15 = vy7 + vmax.s16 q15, q15, q6 @clamp >0 + vmin.s16 q15, q15, q7 @clamp <255 + + vst1.16 {d24, d25},[r1],r2 @q12=row4 + vst1.16 {d26, d27},[r1],r2 @q13=row5 + vst1.16 {d28, d29},[r1],r2 @q14=row6 + vst1.16 {d30, d31},[r1] @q15=row7 + .endm + + .macro BIG_BODY_TRANSPOSE_INPUT + @================================================================== + @ Main body of idct + @================================================================== + PART1 + Transpose8x8 + PART2 + .endm + + .macro IDCT_ENTRY + @================================================================== + @ Load the locations of the constants + @================================================================== + ldr r5, =constants+0*16 @constants[0] + ldr r6, =constants+1*16 @constants[1] + ldr r7, =constants+2*16 @constants[2] + ldr r8, =constants+3*16 @constants[3] + ldr r9, =constants+4*16 @constants[4] + + @================================================================== + @ Load the coefficients + @ only some input coefficients are load due to register constrain + @================================================================== + vld1.16 {d0, d1},[r5] @q0 =constants[0] (scalars) + vld1.16 {d2, d3},[r6] @q1 =constants[1] + .endm +@========================================================================== +@ END of MACRO DEFINITION +@========================================================================== + + + .section idct_func, "x" @ ARE + .text @ idct_func, CODE, READONLY + .align 2 + .code 32 @ CODE32 + +@========================================================================== +@ Main Routine +@========================================================================== + + .global idct_1x1_venum + .global idct_2x2_venum + .global idct_4x4_venum + .global idct_8x8_venum + +@========================================================================== +@ FUNCTION : idct_1x1_venum +@-------------------------------------------------------------------------- +@ DISCRIPTION : ARM optimization of one 1x1 block iDCT +@-------------------------------------------------------------------------- +@ C PROTOTYPE : void idct_1x1_venum(int16 * input, +@ int16 * output, +@ int32 stride) +@-------------------------------------------------------------------------- +@ REG INPUT : R0 pointer to input (int16) +@ R1 pointer to output (int16) +@ R2 block stride +@-------------------------------------------------------------------------- +@ STACK ARG : None +@-------------------------------------------------------------------------- +@ MEM INPUT : None +@-------------------------------------------------------------------------- +@ REG OUTPUT : None +@-------------------------------------------------------------------------- +@ MEM OUTPUT : None +@-------------------------------------------------------------------------- +@ REG AFFECTED : R0 - R2 +@-------------------------------------------------------------------------- +@ STACK USAGE : none +@-------------------------------------------------------------------------- +@ CYCLES : 17 cycles +@-------------------------------------------------------------------------- +@ NOTES : +@ This idct_1x1_venum code was developed with ARM instruction set. +@ +@ ARM REGISTER ALLOCATION +@ ========================================================================= +@ r0 : pointer to input data +@ r1 : pointer to output area +@ r2 : stride in the output buffer +@========================================================================== +.type idct_1x1_venum, %function +idct_1x1_venum: + + ldrsh r3, [r0] @ Load signed half word (int16) + ldr r2, =1028 @ 1028 = 4 + 128 << 3 + @ 4 for rounding, 128 for offset + add r2, r3, r2 + asrs r2, r2, #3 @ Divide by 8, and set status bit + movmi r2, #0 @ Clamp to be greater than 0 + cmp r2, #255 + movgt r2, #255 @ Clamp to be less than 255 + str r2, [r1] @ Save output + bx lr @ Return to caller + + @ end of idct_1x1_venum + + +@========================================================================== +@ FUNCTION : idct_2x2_venum +@-------------------------------------------------------------------------- +@ DISCRIPTION : VeNum optimization of one 2x2 block iDCT +@-------------------------------------------------------------------------- +@ C PROTOTYPE : void idct_2x2_venum(int16 * input, +@ int16 * output, +@ int32 stride) +@-------------------------------------------------------------------------- +@ REG INPUT : R0 pointer to input (int16) +@ R1 pointer to output (int16) +@ R2 block stride +@-------------------------------------------------------------------------- +@ STACK ARG : None +@-------------------------------------------------------------------------- +@ MEM INPUT : None +@-------------------------------------------------------------------------- +@ REG OUTPUT : None +@-------------------------------------------------------------------------- +@ MEM OUTPUT : None +@-------------------------------------------------------------------------- +@ REG AFFECTED : R0 - R2 +@-------------------------------------------------------------------------- +@ STACK USAGE : none +@-------------------------------------------------------------------------- +@ CYCLES : 27 cycles +@-------------------------------------------------------------------------- +@ NOTES : Output buffer must be an 8x8 16-bit buffer +@ +@ ARM REGISTER ALLOCATION +@ ========================================== +@ r0 : pointer to input data +@ r1 : pointer to output area +@ r2 : stride in the output buffer +@ ------------------------------------------- +@ +@ VENUM REGISTER ALLOCATION +@ ================================================= +@ q0 : output x0 - x4 +@ q1 : not used +@ q2 : not used +@ q3 : not used +@ q4 : not used +@ q5 : not used +@ q6 : not used +@ q7 : not used +@ q8 : input y0 - y4 +@ q9 : intermediate value +@ q10 : intermediate value +@ q11 : offset value +@ q12 : clamp value +@ q13 : not used +@ q14 : not used +@ q15 : not used +@========================================================================== +.type idct_2x2_venum, %function +idct_2x2_venum: + + vld4.32 {d16, d17, d18, d19}, [r0] + @ d16: y0 | y1 | y2 | y3 (LSB | MSB) + + vtrn.32 d16, d17 @ d16: y0 | y1 | X | X + @ d17: y2 | y3 | X | X + + vqadd.s16 d18, d16, d17 @ d18: y0+y2 | y1+y3 | X | X q: saturated + vqsub.s16 d19, d16, d17 @ d19: y0-y2 | y1-y3 | X | X q: saturated + + vtrn.16 d18, d19 @ d18: y0+y2 | y0-y2 | X | X + @ d19: y1+y3 | y1-y3 | X | X + + vqadd.s16 d20, d18, d19 @ d20: (y0+y2)+(y1+y3) | (y0-y2)+(y1-y3) + @ x0 | x2 | X | X + vqsub.s16 d21, d18, d19 @ d21: (y0+y2)-(y1+y3) | (y0-y2)-(y1-y3) + @ x1 | x3 | X | X + + vtrn.16 d20, d21 @ d20: x0 | x1 | X | X + @ d21: x2 | x3 | X | X + + vrshr.s16 q10, q10, #3 @ Divide by 8 + + vmov.i16 q11, #128 @ q11 = 128|128|128|128|128|128|128|128 + vqadd.s16 q0, q10, q11 @ Add offset to make output in [0,255] + + vmov.i16 q12, #0 @ q12 = [0000000000000000] + vmov.i16 q13, #255 @ q13 = [FFFFFFFFFFFFFFFF] (hex) + + vmax.s16 q0, q0, q12 @ Clamp > 0 + vmin.s16 q0, q0, q13 @ Clamp < 255 + + vstr d0, [r1] @ Store x0 | x1 | X | X + @ Potential out of boundary issue + add r1, r1, r2 @ Add the offset to the output pointer + vstr d1, [r1] @ Store x2 | x3 | X | X + @ Potential out of boundary issue + bx lr @ Return to caller + + @ end of idct_2x2_venum + + +@========================================================================== +@ FUNCTION : idct_4x4_venum +@-------------------------------------------------------------------------- +@ DISCRIPTION : VeNum optimization of one 4x4 block iDCT +@-------------------------------------------------------------------------- +@ C PROTOTYPE : void idct_4x4_venum(int16 * input, +@ int16 * output, +@ int32 stride) +@-------------------------------------------------------------------------- +@ REG INPUT : R0 pointer to input (int16) +@ R1 pointer to output (int16) +@ R2 block stride +@-------------------------------------------------------------------------- +@ STACK ARG : None +@-------------------------------------------------------------------------- +@ MEM INPUT : None +@-------------------------------------------------------------------------- +@ REG OUTPUT : None +@-------------------------------------------------------------------------- +@ MEM OUTPUT : None +@-------------------------------------------------------------------------- +@ REG AFFECTED : R0 - R3, R12 +@-------------------------------------------------------------------------- +@ STACK USAGE : none +@-------------------------------------------------------------------------- +@ CYCLES : 56 cycles +@-------------------------------------------------------------------------- +@ NOTES : +@ +@ ARM REGISTER ALLOCATION +@ ========================================== +@ r0 : pointer to input data +@ r1 : pointer to output area +@ r2 : stride in the output buffer +@ r3 : pointer to the coefficient set +@ r12 : pointer to the coefficient set +@ ------------------------------------------- +@ +@ VENUM REGISTER ALLOCATION +@ ================================================= +@ q0 : coefficients[0] +@ q1 : coefficients[1] +@ q2 : coefficients[2] +@ q3 : coefficients[3] +@ q4 : not used +@ q5 : not used +@ q6 : not used +@ q7 : not used +@ q8 : input y0 - y7 +@ q9 : input y8 - y15 +@ q10 : intermediate value +@ q11 : intermediate value +@ q12 : intermediate value +@ q13 : intermediate value +@ q14 : intermediate value +@ q15 : intermediate value +@========================================================================== +.type idct_4x4_venum, %function +idct_4x4_venum: + + @ Load the locations of the first 2 sets of coefficients + ldr r3, =coefficient+0*16 @ coefficient[0] + ldr r12, =coefficient+1*16 @ coefficient[1] + + @ Load the first 2 sets of coefficients + vld1.16 {d0, d1},[r3] @ q0 = C4 | C2 | C4 | C6 | C4 | C2 | C4 | C6 + vld1.16 {d2, d3},[r12] @ q1 = C4 | C6 | C4 | C2 | C4 | C6 | C4 | C2 + + @ Load the locations of the second 2 sets of coefficients + ldr r3, =coefficient+2*16 @ coefficient[2] + ldr r12, =coefficient+3*16 @ coefficient[3] + + @ Load the second 2 sets of coefficients + vld1.16 {d4, d5},[r3] @ q2 = C4 | C4 | C4 | C4 | C2 | C2 | C2 | C2 + vld1.16 {d6, d7},[r12] @ q3 = C4 | C4 | C4 | C4 | C6 | C6 | C6 | C6 + + @ Load the input values + vld1.16 {d16}, [r0], r2 @ d16: y0 | y1 | y2 | y3 (LSB | MSB) + vld1.16 {d17}, [r0], r2 @ d17: y4 | y5 | y6 | y7 (LSB | MSB) + vld1.16 {d18}, [r0], r2 @ d18: y8 | y9 | y10 | y11 (LSB | MSB) + vld1.16 {d19}, [r0], r2 @ d19: y12 | y13 | y14 | y15 (LSB | MSB) + + @ Apply iDCT Horizonally + + @ q8: y0 |y1 |y2 |y3 |y4 |y5 |y6 |y7 + @ q9: y8 |y9 |y10|y11|y12|y13|y14|y15 + + @====================================================================== + @ vqrdmulh doubles the result and save the high 16 bits of the result, + @ this is equivalent to right shift by 15 bits. + @ since coefficients are in Q15 format, it contradicts with the right + @ shift 15 here, so the final result is in Q0 format + @ + @ vqrdmulh will also round the result + @====================================================================== + + vqrdmulh.s16 q10, q8, q0 @ q10: C4*y0 | C2*y1 | C4*y2 | C6*y3 | C4*y4 | C2*y5 | C4*y6 | C6*y7 + vqrdmulh.s16 q11, q8, q1 @ q11: C4*y0 | C6*y1 | C4*y2 | C2*y3 | C4*y4 | C6*y5 | C4*y6 | C2*y7 + + vqrdmulh.s16 q12, q9, q0 @ q12: C4*y8 | C2*y9 | C4*y10 | C6*y11 | C4*y12 | C2*y13 | C4*y14 | C6*y15 + vqrdmulh.s16 q13, q9, q1 @ q13: C4*y8 | C6*y9 | C4*y10 | C2*y11 | C4*y12 | C6*y13 | C4*y14 | C2*y15 + + vtrn.32 q10, q12 @ q10: C4*y0 | C2*y1 | C4*y8 | C2*y9 | C4*y4 | C2*y5 | C4*y12 | C2*y13 + @ q12: C4*y2 | C6*y3 | C4*y10 | C6*y11 | C4*y6 | C6*y7 | C4*y14 | C6*y15 + + vtrn.32 q11, q13 @ q11: C4*y0 | C6*y1 | C4*y8 | C6*y9 | C4*y4 | C6*y5 | C4*y12 | C6*y13 + @ q13: C4*y2 | C2*y3 | C4*y10 | C2*y11 | C4*y6 | C2*y7 | C4*y14 | C2*y15 + + vqadd.s16 q14, q10, q12 @ q14: C4*y0 + C4*y2 | C2*y1 + C6*y3 | C4*y8 + C4*y10 | C2*y9 + C6*y11 | C4*y4 + C4*y6 | C2*y5 + C6*y7 | C4*y12 + C4*y14 | C2*y13 + C6*y15 + @ S0 | S2 | S8 | S10 | S4 | S6 | S12 | S14 + + vqsub.s16 q15, q11, q13 @ q15: C4*y0 - C4*y2 | C6*y1 - C2*y3 | C4*y8 - C4*y10 | C6*y9 - C2*y11 | C4*y4 - C4*y6 | C6*y5 - C2*y7 | C4*y12 - C4*y14 | C6*y13 - C2*y15 + @ S1 | S3 | S9 | S11 | S5 | S7 | S13 | S15 + + vtrn.16 q14, q15 @ q14: S0 | S1 | S8 | S9 | S4 | S5 | S12 | S13 + @ q15: S2 | S3 | S10 | S11 | S6 | S7 | S14 | S15 + + vqadd.s16 q8, q14, q15 @ q8: Z0 | Z1 | Z8 | Z9 | Z4 | Z5 | Z12 | Z13 + vqsub.s16 q9, q14, q15 @ q9: Z3 | Z2 | Z11 | Z10 | Z7 | Z6 | Z15 | Z14 + vrev32.16 q9, q9 @ q9: Z2 | Z3 | Z10 | Z11 | Z6 | Z7 | Z14 | Z15 + + + @ Apply iDCT Vertically + + vtrn.32 q8, q9 @ q8: Z0 | Z1 | Z2 | Z3 | Z4 | Z5 | Z6 | Z7 + @ q9: Z8 | Z9 | Z10 | Z11 | Z12 | Z13 | Z14 | Z15 + + + vqrdmulh.s16 q10, q8, q2 @ q10: C4*Z0 | C4*Z1 | C4*Z2 | C4*Z3 | C2*Z4 | C2*Z5 | C2*Z6 | C2*Z7 + vqrdmulh.s16 q11, q8, q3 @ q11: C4*Z0 | C4*Z1 | C4*Z2 | C4*Z3 | C6*Z4 | C6*Z5 | C6*Z6 | C6*Z7 + + vqrdmulh.s16 q12, q9, q2 @ q12: C4*Z8 | C4*Z9 | C4*Z10 | C4*Z11 | C2*Z12 | C2*Z13 | C2*Z14 | C2*Z15 + vqrdmulh.s16 q13, q9, q3 @ q13: C4*Z8 | C4*Z9 | C4*Z10 | C4*Z11 | C6*Z12 | C6*Z13 | C6*Z14 | C6*Z15 + + vqadd.s16 q14, q10, q13 @ q14: C4*Z0+C4*Z8 | C4*Z1+C4*Z9 | C4*Z2+C4*Z10 | C4*Z3+C4*Z11 | C2*Z4+C6*Z12 | C2*Z5+C6*Z13 | C2*Z6+C6*Z14 | C2*Z7+C6*Z15 + @ s0 | s4 | s8 | s12 | s2 | s6 | s10 | s14 + + vqsub.s16 q15, q11, q12 @ q15: C4*Z0-C4*Z8 | C4*Z1-C4*Z9 | C4*Z2-C4*Z10 | C4*Z3-C4*Z11 | C6*Z4-C2*Z12 | C6*Z5-C2*Z13 | C6*Z6-C2*Z14 | C6*Z7-C2*Z15 + @ s1 | s5 | s9 | s13 | s3 | s7 | s11 | s15 + + vswp d29, d30 @ q14: s0 | s4 | s8 | s12 | s1 | s5 | s9 | s13 + @ q15: s2 | s6 | s10 | s14 | s3 | s7 | s11 | s15 + + vqadd.s16 q8, q14, q15 @ q8: x0 | x4 | x8 | x12 | x1 | x5 | x9 | x13 + vqsub.s16 q9, q14, q15 @ q9: x3 | x7 | x11 | x15 | x2 | x6 | x10 | x14 + + vmov.i16 q10, #0 @ q10=[0000000000000000] + vmov.i16 q11, #255 @ q11=[FFFFFFFFFFFFFFFF] (hex) + + vmov.i16 q0, #128 @ q0 = 128|128|128|128|128|128|128|128 + + vqadd.s16 q8, q8, q0 @ Add the offset + vqadd.s16 q9, q9, q0 @ Add the offset + + vmax.s16 q8, q8, q10 @ clamp > 0 + vmin.s16 q8, q8, q11 @ clamp < 255 + + vmax.s16 q9, q9, q10 @ clamp > 0 + vmin.s16 q9, q9, q11 @ clamp < 255 + + vst1.16 {d16}, [r1], r2 @ d16: x0 | x1 | x2 | x3 (LSB | MSB) + vst1.16 {d17}, [r1], r2 @ d17: x4 | x5 | x6 | x7 (LSB | MSB) + vst1.16 {d19}, [r1], r2 @ d18: x8 | x9 | x10 | x11 (LSB | MSB) + vst1.16 {d18}, [r1], r2 @ d19: x12| x13 | x14 | x15 (LSB | MSB) + + bx lr @ Return to caller + + @ end of idct_4x4_venum + +@========================================================================== +@ FUNCTION : idct_8x8_venum +@-------------------------------------------------------------------------- +@ DISCRIPTION : VeNum optimization of one 8x8 block iDCT +@-------------------------------------------------------------------------- +@ C PROTOTYPE : void idct_8x8_venum(int16 * input, +@ int16 * output, +@ int32 stride) +@-------------------------------------------------------------------------- +@ REG INPUT : R0 pointer to input (int16) +@ R1 pointer to output (int16) +@ R2 block stride +@-------------------------------------------------------------------------- +@ STACK ARG : None +@-------------------------------------------------------------------------- +@ MEM INPUT : None +@-------------------------------------------------------------------------- +@ REG OUTPUT : None +@-------------------------------------------------------------------------- +@ MEM OUTPUT : None +@-------------------------------------------------------------------------- +@ REG AFFECTED : R0 - R9 +@-------------------------------------------------------------------------- +@ STACK USAGE : none +@-------------------------------------------------------------------------- +@ CYCLES : 177 cycles +@-------------------------------------------------------------------------- +@ NOTES : +@ +@ It was tested to be IEEE 1180 compliant. Since IEEE 1180 compliance is more stringent +@ than MPEG-4 compliance, this version is also MPEG-4 compliant. +@ +@ CODE STRUCTURE: +@ (i) Macros for transposing an 8x8 matrix and for configuring the VFP unit are defined. +@ (ii) Macro for IDCT in one dimension is defined as four stages +@ (iii) The two dimensional code begins +@ (iv) constants are defined in the area DataArea +@ +@ PROGRAM FLOW: +@ +@ The VFP is configured +@ The parameters to IDCT are loaded +@ the coefficients are loaded +@ loop: +@ decrement loop counter +@ The first input Matrix is loaded and pre-scaled +@ The input is prescaled using the constants +@ IDCT is performed in one dimension on the 8 columns +@ The matrix is transposed +@ A bias is loaded an added to the matrix +@ IDCT is performed in one dimension on the 8 rows +@ The matrix is post-scaled +@ The matrix is saved +@ test loop counter and loop if greater than zero +@ stop +@ +@ +@ ARM REGISTER ALLOCATION +@ ========================================== +@ r0 : pointer to input data +@ r1 : pointer to output are +@ r2 : stride in the output buffer +@ r3 : +@ r4 : +@ r5 : pointer to constants[0] [5] +@ r6 : pointer to constants[1] +@ r7 : pointer to constants[2] +@ r8 : pointer to constants[3] +@ r9 : pointer to constants[4] +@ ------------------------------------------- +@ +@ VENUM REGISTER ALLOCATION +@ ================================================= +@ q0 : constants[0] +@ q1 : constants[1] +@ q2 : constants[2], IDCT1D in-place scratch +@ q3 : constants[3], IDCT1D in-place scratch +@ q4 : constants[4], IDCT1D in-place scratch, and bias compensation +@ q5 : IDCT1D in-place scratch +@ q6 : IDCT1D in-place scratch +@ q7 : IDCT1D in-place scratch +@ q8 : Matrix[0] IDCT1D in-place scratch +@ q9 : Matrix[1] IDCT1D in-place scratch +@ q10 : Matrix[2] IDCT1D in-place scratch +@ q11 : Matrix[3] IDCT1D in-place scratch +@ q12 : Matrix[4] IDCT1D in-place scratch +@ q13 : Matrix[5] IDCT1D in-place scratch +@ q14 : Matrix[6] IDCT1D in-place scratch +@ q15 : Matrix[7] IDCT1D in-place scratch +@========================================================================== +.type idct_8x8_venum, %function +idct_8x8_venum: + + push {r5-r9} + vpush {d8-d15} + IDCT_ENTRY + BIG_BODY_TRANSPOSE_INPUT + vpop {d8-d15} + pop {r5-r9} + bx lr + @ end of idct_8x8_venum + +@========================================================================== +@ Constants Definition AREA: define idct kernel, bias +@========================================================================== + .section ro_data_area @ AREA RODataArea + .data @ DATA, READONLY + .align 5 @ ALIGN=5 + +constants: + .hword 23170, 13573, 6518, 21895, -23170, -21895, 8223, 8224 + .hword 16384, 22725, 21407, 19266, 16384, 19266, 21407, 22725 + .hword 22725, 31521, 29692, 26722, 22725, 26722, 29692, 31521 + .hword 21407, 29692, 27969, 25172, 21407, 25172, 27969, 29692 + .hword 19266, 26722, 25172, 22654, 19266, 22654, 25172, 26722 + .hword 0, 255, 0, 0 + +coefficient: @ These are the coefficent used by 4x4 iDCT in Q15 format + .hword 11585, 15137, 11585, 6270, 11585, 15137, 11585, 6270 @ C4, C2, C4, C6, C4, C2, C4, C6 /2 + .hword 11585, 6270, 11585, 15137, 11585, 6270, 11585, 15137 @ C4, C6, C4, C2, C4, C6, C4, C2 /2 + .hword 11585, 11585, 11585, 11585, 15137, 15137, 15137, 15137 @ C4, C4, C4, C4, C2, C2, C2, C2 /2 + .hword 11585, 11585, 11585, 11585, 6270, 6270, 6270, 6270 @ C4, C4, C4, C4, C6, C6, C6, C6 /2 + +.end diff --git a/src/jni/jpeg/change.log b/src/jni/jpeg/change.log deleted file mode 100644 index 74102c0db5..0000000000 --- a/src/jni/jpeg/change.log +++ /dev/null @@ -1,217 +0,0 @@ -CHANGE LOG for Independent JPEG Group's JPEG software - - -Version 6b 27-Mar-1998 ------------------------ - -jpegtran has new features for lossless image transformations (rotation -and flipping) as well as "lossless" reduction to grayscale. - -jpegtran now copies comments by default; it has a -copy switch to enable -copying all APPn blocks as well, or to suppress comments. (Formerly it -always suppressed comments and APPn blocks.) jpegtran now also preserves -JFIF version and resolution information. - -New decompressor library feature: COM and APPn markers found in the input -file can be saved in memory for later use by the application. (Before, -you had to code this up yourself with a custom marker processor.) - -There is an unused field "void * client_data" now in compress and decompress -parameter structs; this may be useful in some applications. - -JFIF version number information is now saved by the decoder and accepted by -the encoder. jpegtran uses this to copy the source file's version number, -to ensure "jpegtran -copy all" won't create bogus files that contain JFXX -extensions but claim to be version 1.01. Applications that generate their -own JFXX extension markers also (finally) have a supported way to cause the -encoder to emit JFIF version number 1.02. - -djpeg's trace mode reports JFIF 1.02 thumbnail images as such, rather -than as unknown APP0 markers. - -In -verbose mode, djpeg and rdjpgcom will try to print the contents of -APP12 markers as text. Some digital cameras store useful text information -in APP12 markers. - -Handling of truncated data streams is more robust: blocks beyond the one in -which the error occurs will be output as uniform gray, or left unchanged -if decoding a progressive JPEG. The appearance no longer depends on the -Huffman tables being used. - -Huffman tables are checked for validity much more carefully than before. - -To avoid the Unisys LZW patent, djpeg's GIF output capability has been -changed to produce "uncompressed GIFs", and cjpeg's GIF input capability -has been removed altogether. We're not happy about it either, but there -seems to be no good alternative. - -The configure script now supports building libjpeg as a shared library -on many flavors of Unix (all the ones that GNU libtool knows how to -build shared libraries for). Use "./configure --enable-shared" to -try this out. - -New jconfig file and makefiles for Microsoft Visual C++ and Developer Studio. -Also, a jconfig file and a build script for Metrowerks CodeWarrior -on Apple Macintosh. makefile.dj has been updated for DJGPP v2, and there -are miscellaneous other minor improvements in the makefiles. - -jmemmac.c now knows how to create temporary files following Mac System 7 -conventions. - -djpeg's -map switch is now able to read raw-format PPM files reliably. - -cjpeg -progressive -restart no longer generates any unnecessary DRI markers. - -Multiple calls to jpeg_simple_progression for a single JPEG object -no longer leak memory. - - -Version 6a 7-Feb-96 --------------------- - -Library initialization sequence modified to detect version mismatches -and struct field packing mismatches between library and calling application. -This change requires applications to be recompiled, but does not require -any application source code change. - -All routine declarations changed to the style "GLOBAL(type) name ...", -that is, GLOBAL, LOCAL, METHODDEF, EXTERN are now macros taking the -routine's return type as an argument. This makes it possible to add -Microsoft-style linkage keywords to all the routines by changing just -these macros. Note that any application code that was using these macros -will have to be changed. - -DCT coefficient quantization tables are now stored in normal array order -rather than zigzag order. Application code that calls jpeg_add_quant_table, -or otherwise manipulates quantization tables directly, will need to be -changed. If you need to make such code work with either older or newer -versions of the library, a test like "#if JPEG_LIB_VERSION >= 61" is -recommended. - -djpeg's trace capability now dumps DQT tables in natural order, not zigzag -order. This allows the trace output to be made into a "-qtables" file -more easily. - -New system-dependent memory manager module for use on Apple Macintosh. - -Fix bug in cjpeg's -smooth option: last one or two scanlines would be -duplicates of the prior line unless the image height mod 16 was 1 or 2. - -Repair minor problems in VMS, BCC, MC6 makefiles. - -New configure script based on latest GNU Autoconf. - -Correct the list of include files needed by MetroWerks C for ccommand(). - -Numerous small documentation updates. - - -Version 6 2-Aug-95 -------------------- - -Progressive JPEG support: library can read and write full progressive JPEG -files. A "buffered image" mode supports incremental decoding for on-the-fly -display of progressive images. Simply recompiling an existing IJG-v5-based -decoder with v6 should allow it to read progressive files, though of course -without any special progressive display. - -New "jpegtran" application performs lossless transcoding between different -JPEG formats; primarily, it can be used to convert baseline to progressive -JPEG and vice versa. In support of jpegtran, the library now allows lossless -reading and writing of JPEG files as DCT coefficient arrays. This ability -may be of use in other applications. - -Notes for programmers: -* We changed jpeg_start_decompress() to be able to suspend; this makes all -decoding modes available to suspending-input applications. However, -existing applications that use suspending input will need to be changed -to check the return value from jpeg_start_decompress(). You don't need to -do anything if you don't use a suspending data source. -* We changed the interface to the virtual array routines: access_virt_array -routines now take a count of the number of rows to access this time. The -last parameter to request_virt_array routines is now interpreted as the -maximum number of rows that may be accessed at once, but not necessarily -the height of every access. - - -Version 5b 15-Mar-95 ---------------------- - -Correct bugs with grayscale images having v_samp_factor > 1. - -jpeg_write_raw_data() now supports output suspension. - -Correct bugs in "configure" script for case of compiling in -a directory other than the one containing the source files. - -Repair bug in jquant1.c: sometimes didn't use as many colors as it could. - -Borland C makefile and jconfig file work under either MS-DOS or OS/2. - -Miscellaneous improvements to documentation. - - -Version 5a 7-Dec-94 --------------------- - -Changed color conversion roundoff behavior so that grayscale values are -represented exactly. (This causes test image files to change.) - -Make ordered dither use 16x16 instead of 4x4 pattern for a small quality -improvement. - -New configure script based on latest GNU Autoconf. -Fix configure script to handle CFLAGS correctly. -Rename *.auto files to *.cfg, so that configure script still works if -file names have been truncated for DOS. - -Fix bug in rdbmp.c: didn't allow for extra data between header and image. - -Modify rdppm.c/wrppm.c to handle 2-byte raw PPM/PGM formats for 12-bit data. - -Fix several bugs in rdrle.c. - -NEED_SHORT_EXTERNAL_NAMES option was broken. - -Revise jerror.h/jerror.c for more flexibility in message table. - -Repair oversight in jmemname.c NO_MKTEMP case: file could be there -but unreadable. - - -Version 5 24-Sep-94 --------------------- - -Version 5 represents a nearly complete redesign and rewrite of the IJG -software. Major user-visible changes include: - * Automatic configuration simplifies installation for most Unix systems. - * A range of speed vs. image quality tradeoffs are supported. - This includes resizing of an image during decompression: scaling down - by a factor of 1/2, 1/4, or 1/8 is handled very efficiently. - * New programs rdjpgcom and wrjpgcom allow insertion and extraction - of text comments in a JPEG file. - -The application programmer's interface to the library has changed completely. -Notable improvements include: - * We have eliminated the use of callback routines for handling the - uncompressed image data. The application now sees the library as a - set of routines that it calls to read or write image data on a - scanline-by-scanline basis. - * The application image data is represented in a conventional interleaved- - pixel format, rather than as a separate array for each color channel. - This can save a copying step in many programs. - * The handling of compressed data has been cleaned up: the application can - supply routines to source or sink the compressed data. It is possible to - suspend processing on source/sink buffer overrun, although this is not - supported in all operating modes. - * All static state has been eliminated from the library, so that multiple - instances of compression or decompression can be active concurrently. - * JPEG abbreviated datastream formats are supported, ie, quantization and - Huffman tables can be stored separately from the image data. - * And not only that, but the documentation of the library has improved - considerably! - - -The last widely used release before the version 5 rewrite was version 4A of -18-Feb-93. Change logs before that point have been discarded, since they -are not of much interest after the rewrite. diff --git a/src/jni/jpeg/cutils/abort_socket.h b/src/jni/jpeg/cutils/abort_socket.h new file mode 100644 index 0000000000..fbb1112fae --- /dev/null +++ b/src/jni/jpeg/cutils/abort_socket.h @@ -0,0 +1,103 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Helper to perform abortable blocking operations on a socket: + * asocket_connect() + * asocket_accept() + * asocket_read() + * asocket_write() + * These calls are similar to the regular syscalls, but can be aborted with: + * asocket_abort() + * + * Calling close() on a regular POSIX socket does not abort blocked syscalls on + * that socket in other threads. + * + * After calling asocket_abort() the socket cannot be reused. + * + * Call asocket_destory() *after* all threads have finished with the socket to + * finish closing the socket and free the asocket structure. + * + * The helper is implemented by setting the socket non-blocking to initiate + * syscalls connect(), accept(), read(), write(), then using a blocking poll() + * on both the primary socket and a local pipe. This makes the poll() abortable + * by writing a byte to the local pipe in asocket_abort(). + * + * asocket_create() sets the fd to non-blocking mode. It must not be changed to + * blocking mode. + * + * Using asocket will triple the number of file descriptors required per + * socket, due to the local pipe. It may be possible to use a global pipe per + * process rather than per socket, but we have not been able to come up with a + * race-free implementation yet. + * + * All functions except asocket_init() and asocket_destroy() are thread safe. + */ + +#include +#include + +#ifndef __CUTILS_ABORT_SOCKET_H__ +#define __CUTILS_ABORT_SOCKET_H__ +#ifdef __cplusplus +extern "C" { +#endif + +struct asocket { + int fd; /* primary socket fd */ + int abort_fd[2]; /* pipe used to abort */ +}; + +/* Create an asocket from fd. + * Sets the socket to non-blocking mode. + * Returns NULL on error with errno set. + */ +struct asocket *asocket_init(int fd); + +/* Blocking socket I/O with timeout. + * Calling asocket_abort() from another thread will cause each of these + * functions to immediately return with value -1 and errno ECANCELED. + * timeout is in ms, use -1 to indicate no timeout. On timeout -1 is returned + * with errno ETIMEDOUT. + * EINTR is handled in-call. + * Other semantics are identical to the regular syscalls. + */ +int asocket_connect(struct asocket *s, const struct sockaddr *addr, + socklen_t addrlen, int timeout); + +int asocket_accept(struct asocket *s, struct sockaddr *addr, + socklen_t *addrlen, int timeout); + +int asocket_read(struct asocket *s, void *buf, size_t count, int timeout); + +int asocket_write(struct asocket *s, const void *buf, size_t count, + int timeout); + +/* Abort above calls and shutdown socket. + * Further I/O operations on this socket will immediately fail after this call. + * asocket_destroy() should be used to release resources once all threads + * have returned from blocking calls on the socket. + */ +void asocket_abort(struct asocket *s); + +/* Close socket and free asocket structure. + * Must not be called until all calls on this structure have completed. + */ +void asocket_destroy(struct asocket *s); + +#ifdef __cplusplus +} +#endif +#endif //__CUTILS_ABORT_SOCKET__H__ diff --git a/src/jni/jpeg/cutils/adb_networking.h b/src/jni/jpeg/cutils/adb_networking.h new file mode 100755 index 0000000000..409d577ecd --- /dev/null +++ b/src/jni/jpeg/cutils/adb_networking.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ADB_NETWORKING_H +#define _ADB_NETWORKING_H 1 +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern int adb_networking_connect_fd(int fd, struct sockaddr_in *p_address); +extern int adb_networking_gethostbyname(const char *name, struct in_addr *p_out_addr); + +#ifdef __cplusplus +} +#endif + +#endif /*_ADB_NETWORKING_H*/ + diff --git a/src/jni/jpeg/cutils/array.h b/src/jni/jpeg/cutils/array.h new file mode 100644 index 0000000000..c97ff34cba --- /dev/null +++ b/src/jni/jpeg/cutils/array.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A pointer array which intelligently expands its capacity ad needed. + */ + +#ifndef __ARRAY_H +#define __ARRAY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** An array. */ +typedef struct Array Array; + +/** Constructs a new array. Returns NULL if we ran out of memory. */ +Array* arrayCreate(); + +/** Frees an array. Does not free elements themselves. */ +void arrayFree(Array* array); + +/** Adds a pointer. Returns 0 is successful, < 0 otherwise. */ +int arrayAdd(Array* array, void* pointer); + +/** Gets the pointer at the specified index. */ +void* arrayGet(Array* array, int index); + +/** Removes the pointer at the given index and returns it. */ +void* arrayRemove(Array* array, int index); + +/** Sets pointer at the given index. Returns old pointer. */ +void* arraySet(Array* array, int index, void* pointer); + +/** Sets the array size. Sets new pointers to NULL. Returns 0 if successful, < 0 otherwise . */ +int arraySetSize(Array* array, int size); + +/** Returns the size of the given array. */ +int arraySize(Array* array); + +/** + * Returns a pointer to a C-style array which will be valid until this array + * changes. + */ +const void** arrayUnwrap(Array* array); + +#ifdef __cplusplus +} +#endif + +#endif /* __ARRAY_H */ diff --git a/src/jni/jpeg/cutils/ashmem.h b/src/jni/jpeg/cutils/ashmem.h new file mode 100644 index 0000000000..fd56dbef34 --- /dev/null +++ b/src/jni/jpeg/cutils/ashmem.h @@ -0,0 +1,45 @@ +/* cutils/ashmem.h + ** + ** Copyright 2008 The Android Open Source Project + ** + ** This file is dual licensed. It may be redistributed and/or modified + ** under the terms of the Apache 2.0 License OR version 2 of the GNU + ** General Public License. + */ + +#ifndef _CUTILS_ASHMEM_H +#define _CUTILS_ASHMEM_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int ashmem_create_region(const char *name, size_t size); +int ashmem_set_prot_region(int fd, int prot); +int ashmem_pin_region(int fd, size_t offset, size_t len); +int ashmem_unpin_region(int fd, size_t offset, size_t len); +int ashmem_get_size_region(int fd); + +#ifdef __cplusplus +} +#endif + +#ifndef __ASHMEMIOC /* in case someone included too */ + +#define ASHMEM_NAME_LEN 256 + +#define ASHMEM_NAME_DEF "dev/ashmem" + +/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */ +#define ASHMEM_NOT_PURGED 0 +#define ASHMEM_WAS_PURGED 1 + +/* Return values from ASHMEM_UNPIN: Is the mapping now pinned or unpinned? */ +#define ASHMEM_IS_UNPINNED 0 +#define ASHMEM_IS_PINNED 1 + +#endif /* ! __ASHMEMIOC */ + +#endif /* _CUTILS_ASHMEM_H */ diff --git a/src/jni/jpeg/cutils/atomic.h b/src/jni/jpeg/cutils/atomic.h new file mode 100644 index 0000000000..5694d66ac6 --- /dev/null +++ b/src/jni/jpeg/cutils/atomic.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_CUTILS_ATOMIC_H +#define ANDROID_CUTILS_ATOMIC_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * NOTE: memory shared between threads is synchronized by all atomic operations + * below, this means that no explicit memory barrier is required: all reads or + * writes issued before android_atomic_* operations are guaranteed to complete + * before the atomic operation takes place. + */ + +void android_atomic_write(int32_t value, volatile int32_t* addr); + +/* + * all these atomic operations return the previous value + */ + + +int32_t android_atomic_inc(volatile int32_t* addr); +int32_t android_atomic_dec(volatile int32_t* addr); + +int32_t android_atomic_add(int32_t value, volatile int32_t* addr); +int32_t android_atomic_and(int32_t value, volatile int32_t* addr); +int32_t android_atomic_or(int32_t value, volatile int32_t* addr); + +int32_t android_atomic_swap(int32_t value, volatile int32_t* addr); + +/* + * NOTE: Two "quasiatomic" operations on the exact same memory address + * are guaranteed to operate atomically with respect to each other, + * but no guarantees are made about quasiatomic operations mixed with + * non-quasiatomic operations on the same address, nor about + * quasiatomic operations that are performed on partially-overlapping + * memory. + */ + +int64_t android_quasiatomic_swap_64(int64_t value, volatile int64_t* addr); +int64_t android_quasiatomic_read_64(volatile int64_t* addr); + +/* + * cmpxchg return a non zero value if the exchange was NOT performed, + * in other words if oldvalue != *addr + */ + +int android_atomic_cmpxchg(int32_t oldvalue, int32_t newvalue, + volatile int32_t* addr); + +int android_quasiatomic_cmpxchg_64(int64_t oldvalue, int64_t newvalue, + volatile int64_t* addr); + + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // ANDROID_CUTILS_ATOMIC_H diff --git a/src/jni/jpeg/cutils/compiler.h b/src/jni/jpeg/cutils/compiler.h new file mode 100644 index 0000000000..09112d5ac6 --- /dev/null +++ b/src/jni/jpeg/cutils/compiler.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_CUTILS_COMPILER_H +#define ANDROID_CUTILS_COMPILER_H + +/* + * helps the compiler's optimizer predicting branches + */ + +#ifdef __cplusplus +# define CC_LIKELY( exp ) (__builtin_expect( !!(exp), true )) +# define CC_UNLIKELY( exp ) (__builtin_expect( !!(exp), false )) +#else +# define CC_LIKELY( exp ) (__builtin_expect( !!(exp), 1 )) +# define CC_UNLIKELY( exp ) (__builtin_expect( !!(exp), 0 )) +#endif + +#endif // ANDROID_CUTILS_COMPILER_H diff --git a/src/jni/jpeg/cutils/config_utils.h b/src/jni/jpeg/cutils/config_utils.h new file mode 100644 index 0000000000..f3fb370a8a --- /dev/null +++ b/src/jni/jpeg/cutils/config_utils.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CUTILS_CONFIG_UTILS_H +#define __CUTILS_CONFIG_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct cnode cnode; + + +struct cnode +{ + cnode *next; + cnode *first_child; + cnode *last_child; + const char *name; + const char *value; +}; + +/* parse a text string into a config node tree */ +void config_load(cnode *root, char *data); + +/* parse a file into a config node tree */ +void config_load_file(cnode *root, const char *fn); + +/* create a single config node */ +cnode* config_node(const char *name, const char *value); + +/* locate a named child of a config node */ +cnode* config_find(cnode *root, const char *name); + +/* look up a child by name and return the boolean value */ +int config_bool(cnode *root, const char *name, int _default); + +/* look up a child by name and return the string value */ +const char* config_str(cnode *root, const char *name, const char *_default); + +/* add a named child to a config node (or modify it if it already exists) */ +void config_set(cnode *root, const char *name, const char *value); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/jni/jpeg/cutils/cpu_info.h b/src/jni/jpeg/cutils/cpu_info.h new file mode 100644 index 0000000000..78c1884335 --- /dev/null +++ b/src/jni/jpeg/cutils/cpu_info.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CUTILS_CPU_INFO_H +#define __CUTILS_CPU_INFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* returns a string contiaining an ASCII representation of the CPU serial number, +** or NULL if cpu info not available. +** The string is a static variable, so don't call free() on it. +*/ +extern const char* get_cpu_serial_number(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __CUTILS_CPU_INFO_H */ diff --git a/src/jni/jpeg/cutils/dir_hash.h b/src/jni/jpeg/cutils/dir_hash.h new file mode 100644 index 0000000000..fbb4d02c8d --- /dev/null +++ b/src/jni/jpeg/cutils/dir_hash.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +typedef enum { + SHA_1, +} HashAlgorithm; + +int get_file_hash(HashAlgorithm algorithm, const char *path, + char *output_string, size_t max_output_string); + +int get_recursive_hash_manifest(HashAlgorithm algorithm, + const char *directory_path, + char **output_string); diff --git a/src/jni/jpeg/cutils/event_tag_map.h b/src/jni/jpeg/cutils/event_tag_map.h new file mode 100644 index 0000000000..1653c61e9a --- /dev/null +++ b/src/jni/jpeg/cutils/event_tag_map.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBS_CUTILS_EVENTTAGMAP_H +#define _LIBS_CUTILS_EVENTTAGMAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define EVENT_TAG_MAP_FILE "/system/etc/event-log-tags" + +struct EventTagMap; +typedef struct EventTagMap EventTagMap; + +/* + * Open the specified file as an event log tag map. + * + * Returns NULL on failure. + */ +EventTagMap* android_openEventTagMap(const char* fileName); + +/* + * Close the map. + */ +void android_closeEventTagMap(EventTagMap* map); + +/* + * Look up a tag by index. Returns the tag string, or NULL if not found. + */ +const char* android_lookupEventTag(const EventTagMap* map, int tag); + +#ifdef __cplusplus +} +#endif + +#endif /*_LIBS_CUTILS_EVENTTAGMAP_H*/ diff --git a/src/jni/jpeg/cutils/hashmap.h b/src/jni/jpeg/cutils/hashmap.h new file mode 100644 index 0000000000..5cb344c152 --- /dev/null +++ b/src/jni/jpeg/cutils/hashmap.h @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Hash map. + */ + +#ifndef __HASHMAP_H +#define __HASHMAP_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** A hash map. */ +typedef struct Hashmap Hashmap; + +/** + * Creates a new hash map. Returns NULL if memory allocation fails. + * + * @param initialCapacity number of expected entries + * @param hash function which hashes keys + * @param equals function which compares keys for equality + */ +Hashmap* hashmapCreate(size_t initialCapacity, + int (*hash)(void* key), bool (*equals)(void* keyA, void* keyB)); + +/** + * Frees the hash map. Does not free the keys or values themselves. + */ +void hashmapFree(Hashmap* map); + +/** + * Hashes the memory pointed to by key with the given size. Useful for + * implementing hash functions. + */ +int hashmapHash(void* key, size_t keySize); + +/** + * Puts value for the given key in the map. Returns pre-existing value if + * any. + * + * If memory allocation fails, this function returns NULL, the map's size + * does not increase, and errno is set to ENOMEM. + */ +void* hashmapPut(Hashmap* map, void* key, void* value); + +/** + * Gets a value from the map. Returns NULL if no entry for the given key is + * found or if the value itself is NULL. + */ +void* hashmapGet(Hashmap* map, void* key); + +/** + * Returns true if the map contains an entry for the given key. + */ +bool hashmapContainsKey(Hashmap* map, void* key); + +/** + * Gets the value for a key. If a value is not found, this function gets a + * value and creates an entry using the given callback. + * + * If memory allocation fails, the callback is not called, this function + * returns NULL, and errno is set to ENOMEM. + */ +void* hashmapMemoize(Hashmap* map, void* key, + void* (*initialValue)(void* key, void* context), void* context); + +/** + * Removes an entry from the map. Returns the removed value or NULL if no + * entry was present. + */ +void* hashmapRemove(Hashmap* map, void* key); + +/** + * Gets the number of entries in this map. + */ +size_t hashmapSize(Hashmap* map); + +/** + * Invokes the given callback on each entry in the map. Stops iterating if + * the callback returns false. + */ +void hashmapForEach(Hashmap* map, + bool (*callback)(void* key, void* value, void* context), + void* context); + +/** + * Concurrency support. + */ + +/** + * Locks the hash map so only the current thread can access it. + */ +void hashmapLock(Hashmap* map); + +/** + * Unlocks the hash map so other threads can access it. + */ +void hashmapUnlock(Hashmap* map); + +/** + * Key utilities. + */ + +/** + * Hashes int keys. 'key' is a pointer to int. + */ +int hashmapIntHash(void* key); + +/** + * Compares two int keys for equality. + */ +bool hashmapIntEquals(void* keyA, void* keyB); + +/** + * For debugging. + */ + +/** + * Gets current capacity. + */ +size_t hashmapCurrentCapacity(Hashmap* map); + +/** + * Counts the number of entry collisions. + */ +size_t hashmapCountCollisions(Hashmap* map); + +#ifdef __cplusplus +} +#endif + +#endif /* __HASHMAP_H */ diff --git a/src/jni/jpeg/cutils/jstring.h b/src/jni/jpeg/cutils/jstring.h new file mode 100644 index 0000000000..ee0018fcc7 --- /dev/null +++ b/src/jni/jpeg/cutils/jstring.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CUTILS_STRING16_H +#define __CUTILS_STRING16_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint16_t char16_t; + +extern char * strndup16to8 (const char16_t* s, size_t n); +extern size_t strnlen16to8 (const char16_t* s, size_t n); +extern char * strncpy16to8 (char *dest, const char16_t*s, size_t n); + +extern char16_t * strdup8to16 (const char* s, size_t *out_len); +extern size_t strlen8to16 (const char* utf8Str); +extern char16_t * strcpy8to16 (char16_t *dest, const char*s, size_t *out_len); +extern char16_t * strcpylen8to16 (char16_t *dest, const char*s, int length, + size_t *out_len); + +#ifdef __cplusplus +} +#endif + +#endif /* __CUTILS_STRING16_H */ diff --git a/src/jni/jpeg/cutils/log.h b/src/jni/jpeg/cutils/log.h new file mode 100644 index 0000000000..3d8b996406 --- /dev/null +++ b/src/jni/jpeg/cutils/log.h @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// C/C++ logging functions. See the logging documentation for API details. +// +// We'd like these to be available from C code (in case we import some from +// somewhere), so this has a C interface. +// +// The output will be correct when the log file is shared between multiple +// threads and/or multiple processes so long as the operating system +// supports O_APPEND. These calls have mutex-protected data structures +// and so are NOT reentrant. Do not use LOG in a signal handler. +// +#ifndef _LIBS_CUTILS_LOG_H +#define _LIBS_CUTILS_LOG_H + +#include +#include +#include +#include +#ifdef HAVE_PTHREADS +#include +#endif +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// --------------------------------------------------------------------- + +/* + * Normally we strip LOGV (VERBOSE messages) from release builds. + * You can modify this (for example with "#define LOG_NDEBUG 0" + * at the top of your source file) to change that behavior. + */ +#ifndef LOG_NDEBUG +#ifdef NDEBUG +#define LOG_NDEBUG 1 +#else +#define LOG_NDEBUG 0 +#endif +#endif + +/* + * This is the local tag used for the following simplified + * logging macros. You can change this preprocessor definition + * before using the other macros to change the tag. + */ +#ifndef LOG_TAG +#define LOG_TAG NULL +#endif + +// --------------------------------------------------------------------- + +/* + * Simplified macro to send a verbose log message using the current LOG_TAG. + */ +#ifndef LOGV +#if LOG_NDEBUG +#define LOGV(...) ((void)0) +#else +#define LOGV(...) ((void)LOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) +#endif +#endif + +#define CONDITION(cond) (__builtin_expect((cond)!=0, 0)) + +#ifndef LOGV_IF +#if LOG_NDEBUG +#define LOGV_IF(cond, ...) ((void)0) +#else +#define LOGV_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)LOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +#endif +#endif + +/* + * Simplified macro to send a debug log message using the current LOG_TAG. + */ +#ifndef LOGD +#define LOGD(...) ((void)LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) +#endif + +#ifndef LOGD_IF +#define LOGD_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +#endif + +/* + * Simplified macro to send an info log message using the current LOG_TAG. + */ +#ifndef LOGI +#define LOGI(...) ((void)LOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) +#endif + +#ifndef LOGI_IF +#define LOGI_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)LOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +#endif + +/* + * Simplified macro to send a warning log message using the current LOG_TAG. + */ +#ifndef LOGW +#define LOGW(...) ((void)LOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) +#endif + +#ifndef LOGW_IF +#define LOGW_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)LOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +#endif + +/* + * Simplified macro to send an error log message using the current LOG_TAG. + */ +#ifndef LOGE +#define LOGE(...) ((void)LOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) +#endif + +#ifndef LOGE_IF +#define LOGE_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)LOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +#endif + +// --------------------------------------------------------------------- + +/* + * Conditional based on whether the current LOG_TAG is enabled at + * verbose priority. + */ +#ifndef IF_LOGV +#if LOG_NDEBUG +#define IF_LOGV() if (false) +#else +#define IF_LOGV() IF_LOG(LOG_VERBOSE, LOG_TAG) +#endif +#endif + +/* + * Conditional based on whether the current LOG_TAG is enabled at + * debug priority. + */ +#ifndef IF_LOGD +#define IF_LOGD() IF_LOG(LOG_DEBUG, LOG_TAG) +#endif + +/* + * Conditional based on whether the current LOG_TAG is enabled at + * info priority. + */ +#ifndef IF_LOGI +#define IF_LOGI() IF_LOG(LOG_INFO, LOG_TAG) +#endif + +/* + * Conditional based on whether the current LOG_TAG is enabled at + * warn priority. + */ +#ifndef IF_LOGW +#define IF_LOGW() IF_LOG(LOG_WARN, LOG_TAG) +#endif + +/* + * Conditional based on whether the current LOG_TAG is enabled at + * error priority. + */ +#ifndef IF_LOGE +#define IF_LOGE() IF_LOG(LOG_ERROR, LOG_TAG) +#endif + +// --------------------------------------------------------------------- +#define android_printAssert(a, b, ...) printf("%s: ", a, b, __VA_ARGS__) +/* + * Log a fatal error. If the given condition fails, this stops program + * execution like a normal assertion, but also generating the given message. + * It is NOT stripped from release builds. Note that the condition test + * is -inverted- from the normal assert() semantics. + */ +#define LOG_ALWAYS_FATAL_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)android_printAssert(#cond, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) + +#define LOG_ALWAYS_FATAL(...) \ + ( ((void)android_printAssert(NULL, LOG_TAG, __VA_ARGS__)) ) + +/* + * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that + * are stripped out of release builds. + */ +#if LOG_NDEBUG + +#define LOG_FATAL_IF(cond, ...) ((void)0) +#define LOG_FATAL(...) ((void)0) + +#else + +#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, __VA_ARGS__) +#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__) + +#endif + +/* + * Assertion that generates a log message when the assertion fails. + * Stripped out of release builds. Uses the current LOG_TAG. + */ +#define LOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), __VA_ARGS__) +//#define LOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond) + +// --------------------------------------------------------------------- + +/* + * Basic log message macro. + * + * Example: + * LOG(LOG_WARN, NULL, "Failed with error %d", errno); + * + * The second argument may be NULL or "" to indicate the "global" tag. + */ +#ifndef LOG +#define LOG(priority, tag, ...) \ + printf(tag, __VA_ARGS__) +#endif + +/* + * Log macro that allows you to specify a number for the priority. + */ +#ifndef LOG_PRI +#define LOG_PRI(priority, tag, ...) \ + android_printLog(priority, tag, __VA_ARGS__) +#endif + +/* + * Log macro that allows you to pass in a varargs ("args" is a va_list). + */ +#ifndef LOG_PRI_VA +#define LOG_PRI_VA(priority, tag, fmt, args) \ + android_vprintLog(priority, NULL, tag, fmt, args) +#endif + +/* + * Conditional given a desired logging priority and tag. + */ +#ifndef IF_LOG +#define IF_LOG(priority, tag) \ + if (android_testLog(ANDROID_##priority, tag)) +#endif + +// --------------------------------------------------------------------- + +/* + * Event logging. + */ + +/* + * Event log entry types. These must match up with the declarations in + * java/android/android/util/EventLog.java. + */ +typedef enum { + EVENT_TYPE_INT = 0, + EVENT_TYPE_LONG = 1, + EVENT_TYPE_STRING = 2, + EVENT_TYPE_LIST = 3, +} AndroidEventLogType; + + +#define LOG_EVENT_INT(_tag, _value) { \ + int intBuf = _value; \ + (void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf, \ + sizeof(intBuf)); \ + } +#define LOG_EVENT_LONG(_tag, _value) { \ + long long longBuf = _value; \ + (void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf, \ + sizeof(longBuf)); \ + } +#define LOG_EVENT_STRING(_tag, _value) \ + ((void) 0) /* not implemented -- must combine len with string */ +/* TODO: something for LIST */ + +/* + * =========================================================================== + * + * The stuff in the rest of this file should not be used directly. + */ + +#define android_printLog(prio, tag, fmt...) \ + __android_log_print(prio, tag, fmt) + +#define android_vprintLog(prio, cond, tag, fmt...) \ + __android_log_vprint(prio, tag, fmt) + + +#define android_writeLog(prio, tag, text) \ + __android_log_write(prio, tag, text) + +#define android_bWriteLog(tag, payload, len) \ + __android_log_bwrite(tag, payload, len) +#define android_btWriteLog(tag, type, payload, len) \ + __android_log_btwrite(tag, type, payload, len) + +// TODO: remove these prototypes and their users +#define android_testLog(prio, tag) (1) +#define android_writevLog(vec,num) do{}while(0) +#define android_write1Log(str,len) do{}while (0) +#define android_setMinPriority(tag, prio) do{}while(0) +//#define android_logToCallback(func) do{}while(0) +#define android_logToFile(tag, file) (0) +#define android_logToFd(tag, fd) (0) + + +#ifdef __cplusplus +} +#endif + +#endif // _LIBS_CUTILS_LOG_H diff --git a/src/jni/jpeg/cutils/logd.h b/src/jni/jpeg/cutils/logd.h new file mode 100644 index 0000000000..5620c886ab --- /dev/null +++ b/src/jni/jpeg/cutils/logd.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ANDROID_CUTILS_LOGD_H +#define _ANDROID_CUTILS_LOGD_H + +/* the stable/frozen log-related definitions have been + * moved to this header, which is exposed by the NDK + */ + +/* the rest is only used internally by the system */ +#include +#include +#include +#include +#include +#ifdef HAVE_PTHREADS +#include +#endif +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* _LOGD_H */ diff --git a/src/jni/jpeg/cutils/logger.h b/src/jni/jpeg/cutils/logger.h new file mode 100644 index 0000000000..3a08019a88 --- /dev/null +++ b/src/jni/jpeg/cutils/logger.h @@ -0,0 +1,46 @@ +/* utils/logger.h +** +** Copyright 2007, The Android Open Source Project +** +** This file is dual licensed. It may be redistributed and/or modified +** under the terms of the Apache 2.0 License OR version 2 of the GNU +** General Public License. +*/ + +#ifndef _UTILS_LOGGER_H +#define _UTILS_LOGGER_H + +#include + +struct logger_entry { + uint16_t len; /* length of the payload */ + uint16_t __pad; /* no matter what, we get 2 bytes of padding */ + int32_t pid; /* generating process's pid */ + int32_t tid; /* generating process's tid */ + int32_t sec; /* seconds since Epoch */ + int32_t nsec; /* nanoseconds */ + char msg[0]; /* the entry's payload */ +}; + +#define LOGGER_LOG_MAIN "log/main" +#define LOGGER_LOG_RADIO "log/radio" +#define LOGGER_LOG_EVENTS "log/events" + +#define LOGGER_ENTRY_MAX_LEN (4*1024) +#define LOGGER_ENTRY_MAX_PAYLOAD \ + (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry)) + +#ifdef HAVE_IOCTL + +#include + +#define __LOGGERIO 0xAE + +#define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */ +#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */ +#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */ +#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */ + +#endif // HAVE_IOCTL + +#endif /* _UTILS_LOGGER_H */ diff --git a/src/jni/jpeg/cutils/logprint.h b/src/jni/jpeg/cutils/logprint.h new file mode 100644 index 0000000000..d6ec480cf7 --- /dev/null +++ b/src/jni/jpeg/cutils/logprint.h @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LOGPRINT_H +#define _LOGPRINT_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + FORMAT_OFF = 0, + FORMAT_BRIEF, + FORMAT_PROCESS, + FORMAT_TAG, + FORMAT_THREAD, + FORMAT_RAW, + FORMAT_TIME, + FORMAT_THREADTIME, + FORMAT_LONG, +} AndroidLogPrintFormat; + +typedef struct AndroidLogFormat_t AndroidLogFormat; + +typedef struct AndroidLogEntry_t { + time_t tv_sec; + long tv_nsec; + android_LogPriority priority; + pid_t pid; + pthread_t tid; + const char * tag; + size_t messageLen; + const char * message; +} AndroidLogEntry; + +AndroidLogFormat *android_log_format_new(); + +void android_log_format_free(AndroidLogFormat *p_format); + +void android_log_setPrintFormat(AndroidLogFormat *p_format, + AndroidLogPrintFormat format); + +/** + * Returns FORMAT_OFF on invalid string + */ +AndroidLogPrintFormat android_log_formatFromString(const char *s); + +/** + * filterExpression: a single filter expression + * eg "AT:d" + * + * returns 0 on success and -1 on invalid expression + * + * Assumes single threaded execution + * + */ + +int android_log_addFilterRule(AndroidLogFormat *p_format, + const char *filterExpression); + + +/** + * filterString: a whitespace-separated set of filter expressions + * eg "AT:d *:i" + * + * returns 0 on success and -1 on invalid expression + * + * Assumes single threaded execution + * + */ + +int android_log_addFilterString(AndroidLogFormat *p_format, + const char *filterString); + + +/** + * returns 1 if this log line should be printed based on its priority + * and tag, and 0 if it should not + */ +int android_log_shouldPrintLine ( + AndroidLogFormat *p_format, const char *tag, android_LogPriority pri); + + +/** + * Splits a wire-format buffer into an AndroidLogEntry + * entry allocated by caller. Pointers will point directly into buf + * + * Returns 0 on success and -1 on invalid wire format (entry will be + * in unspecified state) + */ +int android_log_processLogBuffer(struct logger_entry *buf, + AndroidLogEntry *entry); + +/** + * Like android_log_processLogBuffer, but for binary logs. + * + * If "map" is non-NULL, it will be used to convert the log tag number + * into a string. + */ +int android_log_processBinaryLogBuffer(struct logger_entry *buf, + AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf, + int messageBufLen); + + +/** + * Formats a log message into a buffer + * + * Uses defaultBuffer if it can, otherwise malloc()'s a new buffer + * If return value != defaultBuffer, caller must call free() + * Returns NULL on malloc error + */ + +char *android_log_formatLogLine ( + AndroidLogFormat *p_format, + char *defaultBuffer, + size_t defaultBufferSize, + const AndroidLogEntry *p_line, + size_t *p_outLength); + + +/** + * Either print or do not print log line, based on filter + * + * Assumes single threaded execution + * + */ +int android_log_filterAndPrintLogLine( + AndroidLogFormat *p_format, + int fd, + const AndroidLogEntry *entry); + + +#ifdef __cplusplus +} +#endif + + +#endif /*_LOGPRINT_H*/ diff --git a/src/jni/jpeg/cutils/memory.h b/src/jni/jpeg/cutils/memory.h new file mode 100644 index 0000000000..e725cdd032 --- /dev/null +++ b/src/jni/jpeg/cutils/memory.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_CUTILS_MEMORY_H +#define ANDROID_CUTILS_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* size is given in bytes and must be multiple of 2 */ +void android_memset16(uint16_t* dst, uint16_t value, size_t size); + +/* size is given in bytes and must be multiple of 4 */ +void android_memset32(uint32_t* dst, uint32_t value, size_t size); + +#if !HAVE_STRLCPY +/* Declaration of strlcpy() for platforms that don't already have it. */ +size_t strlcpy(char *dst, const char *src, size_t size); +#endif + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // ANDROID_CUTILS_MEMORY_H diff --git a/src/jni/jpeg/cutils/misc.h b/src/jni/jpeg/cutils/misc.h new file mode 100644 index 0000000000..2c48dfa830 --- /dev/null +++ b/src/jni/jpeg/cutils/misc.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CUTILS_MISC_H +#define __CUTILS_MISC_H + +#ifdef __cplusplus +extern "C" { +#endif + + /* Load an entire file into a malloc'd chunk of memory + * that is length_of_file + 1 (null terminator). If + * sz is non-zero, return the size of the file via sz. + * Returns 0 on failure. + */ +extern void *load_file(const char *fn, unsigned *sz); + + /* Connects your process to the system debugger daemon + * so that on a crash it may be logged or interactively + * debugged (depending on system settings). + */ +extern void debuggerd_connect(void); + + + /* This is the range of UIDs (and GIDs) that are reserved + * for assigning to applications. + */ +#define FIRST_APPLICATION_UID 10000 +#define LAST_APPLICATION_UID 99999 + +#ifdef __cplusplus +} +#endif + +#endif /* __CUTILS_MISC_H */ diff --git a/src/jni/jpeg/cutils/mq.h b/src/jni/jpeg/cutils/mq.h new file mode 100644 index 0000000000..b27456d4f2 --- /dev/null +++ b/src/jni/jpeg/cutils/mq.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * IPC messaging library. + */ + +#ifndef __MQ_H +#define __MQ_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** A message. */ +typedef struct MqMessage MqMessage; + +/** A destination to which messages can be sent. */ +typedef struct MqDestination MqDestination; + +/* Array of bytes. */ +typedef struct MqBytes MqBytes; + +/** + * Hears messages. + * + * @param destination to which the message was sent + * @param message the message to hear + */ +typedef void MqMessageListener(MqDestination* destination, MqMessage* message); + +/** + * Hears a destination close. + * + * @param destination that closed + */ +typedef void MqCloseListener(MqDestination* destination); + +/** Message functions. */ + +/** + * Creates a new Message. + * + * @param header as defined by user + * @param body as defined by user + * @param replyTo destination to which replies should be sent, NULL if none + */ +MqMessage* mqCreateMessage(MqBytes header, MqBytes body, + MqDestination* replyTo); + +/** Sends a message to a destination. */ +void mqSendMessage(MqMessage* message, MqDestination* destination); + +/** Destination functions. */ + +/** + * Creates a new destination. Acquires a reference implicitly. + * + * @param messageListener function to call when a message is recieved + * @param closeListener function to call when the destination closes + * @param userData user-specific data to associate with the destination. + * Retrieve using mqGetDestinationUserData(). + */ +MqDestination* mqCreateDestination(MqMessageListener* messageListener, + MqCloseListener* closeListener, void* userData); + +/** + * Gets user data which was associated with the given destination at + * construction time. + * + * It is only valid to call this function in the same process that the + * given destination was created in. + * This function returns a null pointer if you call it on a destination + * created in a remote process. + */ +void* mqGetUserData(MqDestination* destination); + +/** + * Returns 1 if the destination was created in this process, or 0 if + * the destination was created in a different process, in which case you have + * a remote stub. + */ +int mqIsDestinationLocal(MqDestination* destination); + +/** + * Increments the destination's reference count. + */ +void mqKeepDestination(MqDesintation* destination); + +/** + * Decrements the destination's reference count. + */ +void mqFreeDestination(MqDestination* desintation); + +/** Registry API. */ + +/** + * Gets the destination bound to a name. + */ +MqDestination* mqGetDestination(char* name); + +/** + * Binds a destination to a name. + */ +void mqPutDestination(char* name, MqDestination* desintation); + +#ifdef __cplusplus +} +#endif + +#endif /* __MQ_H */ diff --git a/src/jni/jpeg/cutils/mspace.h b/src/jni/jpeg/cutils/mspace.h new file mode 100644 index 0000000000..ba3d513c85 --- /dev/null +++ b/src/jni/jpeg/cutils/mspace.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* A wrapper file for dlmalloc.h that defines prototypes for the + * mspace_*() functions, which provide an interface for creating + * multiple heaps. + */ + +#ifndef MSPACE_H_ +#define MSPACE_H_ + +/* It's a pain getting the mallinfo stuff to work + * with Linux, OSX, and klibc, so just turn it off + * for now. + * TODO: make mallinfo work + */ +#define NO_MALLINFO 1 + +/* Allow setting the maximum heap footprint. + */ +#define USE_MAX_ALLOWED_FOOTPRINT 1 + +#define USE_CONTIGUOUS_MSPACES 1 +#if USE_CONTIGUOUS_MSPACES +#define HAVE_MMAP 0 +#define HAVE_MORECORE 1 +#define MORECORE_CONTIGUOUS 0 +#endif + +#define MSPACES 1 +#define ONLY_MSPACES 1 +#include "../bionic/libc/bionic/dlmalloc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + mspace_usable_size(void* p); + + Returns the number of bytes you can actually use in + an allocated chunk, which may be more than you requested (although + often not) due to alignment and minimum size constraints. + You can use this many bytes without worrying about + overwriting other allocated objects. This is not a particularly great + programming practice. mspace_usable_size can be more useful in + debugging and assertions, for example: + + p = mspace_malloc(msp, n); + assert(mspace_usable_size(msp, p) >= 256); +*/ +size_t mspace_usable_size(mspace, const void*); + +#if USE_CONTIGUOUS_MSPACES +/* + Similar to create_mspace(), but the underlying memory is + guaranteed to be contiguous. No more than max_capacity + bytes is ever allocated to the mspace. + */ +mspace create_contiguous_mspace(size_t starting_capacity, size_t max_capacity, + int locked); + +/* + Identical to create_contiguous_mspace, but labels the mapping 'mspace/name' + instead of 'mspace' +*/ +mspace create_contiguous_mspace_with_name(size_t starting_capacity, + size_t max_capacity, int locked, const char *name); + +size_t destroy_contiguous_mspace(mspace msp); +#endif + +/* + Call the handler for each block in the specified mspace. + chunkptr and chunklen refer to the heap-level chunk including + the chunk overhead, and userptr and userlen refer to the + user-usable part of the chunk. If the chunk is free, userptr + will be NULL and userlen will be 0. userlen is not guaranteed + to be the same value passed into malloc() for a given chunk; + it is >= the requested size. + */ +void mspace_walk_heap(mspace msp, + void(*handler)(const void *chunkptr, size_t chunklen, + const void *userptr, size_t userlen, void *arg), void *harg); + +/* + mspace_walk_free_pages(handler, harg) + + Calls the provided handler on each free region in the specified + mspace. The memory between start and end are guaranteed not to + contain any important data, so the handler is free to alter the + contents in any way. This can be used to advise the OS that large + free regions may be swapped out. + + The value in harg will be passed to each call of the handler. + */ +void mspace_walk_free_pages(mspace msp, + void(*handler)(void *start, void *end, void *arg), void *harg); + +#ifdef __cplusplus +}; /* end of extern "C" */ +#endif + +#endif /* MSPACE_H_ */ diff --git a/src/jni/jpeg/cutils/native_handle.h b/src/jni/jpeg/cutils/native_handle.h new file mode 100644 index 0000000000..89d6b65e24 --- /dev/null +++ b/src/jni/jpeg/cutils/native_handle.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NATIVE_HANDLE_H_ +#define NATIVE_HANDLE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + int version; /* sizeof(native_handle_t) */ + int numFds; /* number of file-descriptors at &data[0] */ + int numInts; /* number of ints at &data[numFds] */ + int data[0]; /* numFds + numInts ints */ +} native_handle_t; + + +/* keep the old definition for backward source-compatibility */ +typedef native_handle_t native_handle; + +/* + * native_handle_close + * + * closes the file descriptors contained in this native_handle_t + * + * return 0 on success, or a negative error code on failure + * + */ +int native_handle_close(const native_handle_t* h); + + +/* + * native_handle_create + * + * creates a native_handle_t and initializes it. must be destroyed with + * native_handle_delete(). + * + */ +native_handle_t* native_handle_create(int numFds, int numInts); + +/* + * native_handle_delete + * + * frees a native_handle_t allocated with native_handle_create(). + * This ONLY frees the memory allocated for the native_handle_t, but doesn't + * close the file descriptors; which can be achieved with native_handle_close(). + * + * return 0 on success, or a negative error code on failure + * + */ +int native_handle_delete(native_handle_t* h); + + +#ifdef __cplusplus +} +#endif + +#endif /* NATIVE_HANDLE_H_ */ diff --git a/src/jni/jpeg/cutils/process_name.h b/src/jni/jpeg/cutils/process_name.h new file mode 100644 index 0000000000..1e72e5c3ad --- /dev/null +++ b/src/jni/jpeg/cutils/process_name.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Gives the current process a name. + */ + +#ifndef __PROCESS_NAME_H +#define __PROCESS_NAME_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Sets the current process name. + * + * Warning: This leaks a string every time you call it. Use judiciously! + */ +void set_process_name(const char* process_name); + +/** Gets the current process name. */ +const char* get_process_name(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __PROCESS_NAME_H */ diff --git a/src/jni/jpeg/cutils/properties.h b/src/jni/jpeg/cutils/properties.h new file mode 100644 index 0000000000..25fd67ae0e --- /dev/null +++ b/src/jni/jpeg/cutils/properties.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CUTILS_PROPERTIES_H +#define __CUTILS_PROPERTIES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* System properties are *small* name value pairs managed by the +** property service. If your data doesn't fit in the provided +** space it is not appropriate for a system property. +** +** WARNING: system/bionic/include/sys/system_properties.h also defines +** these, but with different names. (TODO: fix that) +*/ +#define PROPERTY_KEY_MAX 32 +#define PROPERTY_VALUE_MAX 92 + +/* property_get: returns the length of the value which will never be +** greater than PROPERTY_VALUE_MAX - 1 and will always be zero terminated. +** (the length does not include the terminating zero). +** +** If the property read fails or returns an empty value, the default +** value is used (if nonnull). +*/ +int property_get(const char *key, char *value, const char *default_value); + +/* property_set: returns 0 on success, < 0 on failure +*/ +int property_set(const char *key, const char *value); + +int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie); + + +#ifdef HAVE_SYSTEM_PROPERTY_SERVER +/* + * We have an external property server instead of built-in libc support. + * Used by the simulator. + */ +#define SYSTEM_PROPERTY_PIPE_NAME "/tmp/android-sysprop" + +enum { + kSystemPropertyUnknown = 0, + kSystemPropertyGet, + kSystemPropertySet, + kSystemPropertyList +}; +#endif /*HAVE_SYSTEM_PROPERTY_SERVER*/ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/jni/jpeg/cutils/record_stream.h b/src/jni/jpeg/cutils/record_stream.h new file mode 100644 index 0000000000..bfac87a53c --- /dev/null +++ b/src/jni/jpeg/cutils/record_stream.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * A simple utility for reading fixed records out of a stream fd + */ + +#ifndef _CUTILS_RECORD_STREAM_H +#define _CUTILS_RECORD_STREAM_H + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct RecordStream RecordStream; + +extern RecordStream *record_stream_new(int fd, size_t maxRecordLen); +extern void record_stream_free(RecordStream *p_rs); + +extern int record_stream_get_next (RecordStream *p_rs, void ** p_outRecord, + size_t *p_outRecordLen); + +#ifdef __cplusplus +} +#endif + + +#endif /*_CUTILS_RECORD_STREAM_H*/ + diff --git a/src/jni/jpeg/cutils/sched_policy.h b/src/jni/jpeg/cutils/sched_policy.h new file mode 100644 index 0000000000..eaf39939ae --- /dev/null +++ b/src/jni/jpeg/cutils/sched_policy.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CUTILS_SCHED_POLICY_H +#define __CUTILS_SCHED_POLICY_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + SP_BACKGROUND = 0, + SP_FOREGROUND = 1, +} SchedPolicy; + +extern int set_sched_policy(int tid, SchedPolicy policy); +extern int get_sched_policy(int tid, SchedPolicy *policy); + +#ifdef __cplusplus +} +#endif + +#endif /* __CUTILS_SCHED_POLICY_H */ diff --git a/src/jni/jpeg/cutils/selector.h b/src/jni/jpeg/cutils/selector.h new file mode 100644 index 0000000000..dfc2a9d349 --- /dev/null +++ b/src/jni/jpeg/cutils/selector.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Framework for multiplexing I/O. A selector manages a set of file + * descriptors and calls out to user-provided callback functions to read and + * write data and handle errors. + */ + +#ifndef __SELECTOR_H +#define __SELECTOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * Manages SelectableFds and invokes their callbacks at appropriate times. + */ +typedef struct Selector Selector; + +/** + * A selectable descriptor. Contains callbacks which the selector can invoke + * before calling select(), when the descriptor is readable or writable, and + * when the descriptor contains out-of-band data. Simply set a callback to + * NULL if you're not interested in that particular event. + * + * A selectable descriptor can indicate that it needs to be removed from the + * selector by setting the 'remove' flag. The selector will remove the + * descriptor at a later time and invoke the onRemove() callback. + * + * SelectableFd fields should only be modified from the selector loop. + */ +typedef struct SelectableFd SelectableFd; +struct SelectableFd { + + /** The file descriptor itself. */ + int fd; + + /** Pointer to user-specific data. Can be NULL. */ + void* data; + + /** + * Set this flag when you no longer wish to be selected. The selector + * will invoke onRemove() when the descriptor is actually removed. + */ + bool remove; + + /** + * Invoked by the selector before calling select. You can set up other + * callbacks from here as necessary. + */ + void (*beforeSelect)(SelectableFd* self); + + /** + * Invoked by the selector when the descriptor has data available. Set to + * NULL to indicate that you're not interested in reading. + */ + void (*onReadable)(SelectableFd* self); + + /** + * Invoked by the selector when the descriptor can accept data. Set to + * NULL to indicate that you're not interested in writing. + */ + void (*onWritable)(SelectableFd* self); + + /** + * Invoked by the selector when out-of-band (OOB) data is available. Set to + * NULL to indicate that you're not interested in OOB data. + */ + void (*onExcept)(SelectableFd* self); + + /** + * Invoked by the selector after the descriptor is removed from the + * selector but before the selector frees the SelectableFd memory. + */ + void (*onRemove)(SelectableFd* self); + + /** + * The selector which selected this fd. Set by the selector itself. + */ + Selector* selector; +}; + +/** + * Creates a new selector. + */ +Selector* selectorCreate(void); + +/** + * Creates a new selectable fd, adds it to the given selector and returns a + * pointer. Outside of 'selector' and 'fd', all fields are set to 0 or NULL + * by default. + * + * The selectable fd should only be modified from the selector loop thread. + */ +SelectableFd* selectorAdd(Selector* selector, int fd); + +/** + * Wakes up the selector even though no I/O events occurred. Use this + * to indicate that you're ready to write to a descriptor. + */ +void selectorWakeUp(Selector* selector); + +/** + * Loops continuously selecting file descriptors and firing events. + * Does not return. + */ +void selectorLoop(Selector* selector); + +#ifdef __cplusplus +} +#endif + +#endif /* __SELECTOR_H */ diff --git a/src/jni/jpeg/cutils/sockets.h b/src/jni/jpeg/cutils/sockets.h new file mode 100644 index 0000000000..aa8682ede3 --- /dev/null +++ b/src/jni/jpeg/cutils/sockets.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CUTILS_SOCKETS_H +#define __CUTILS_SOCKETS_H + +#include +#include +#include + +#ifdef HAVE_WINSOCK +#include +typedef int socklen_t; +#elif HAVE_SYS_SOCKET_H +#include +#endif + +#define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_" +#define ANDROID_SOCKET_DIR "/dev/socket" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * android_get_control_socket - simple helper function to get the file + * descriptor of our init-managed Unix domain socket. `name' is the name of the + * socket, as given in init.rc. Returns -1 on error. + * + * This is inline and not in libcutils proper because we want to use this in + * third-party daemons with minimal modification. + */ +static inline int android_get_control_socket(const char *name) +{ + char key[64] = ANDROID_SOCKET_ENV_PREFIX; + const char *val; + int fd; + + /* build our environment variable, counting cycles like a wolf ... */ +#if HAVE_STRLCPY + strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, + name, + sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); +#else /* for the host, which may lack the almightly strncpy ... */ + strncpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, + name, + sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); + key[sizeof(key)-1] = '\0'; +#endif + + val = getenv(key); + if (!val) + return -1; + + errno = 0; + fd = strtol(val, NULL, 10); + if (errno) + return -1; + + return fd; +} + +/* + * See also android.os.LocalSocketAddress.Namespace + */ +// Linux "abstract" (non-filesystem) namespace +#define ANDROID_SOCKET_NAMESPACE_ABSTRACT 0 +// Android "reserved" (/dev/socket) namespace +#define ANDROID_SOCKET_NAMESPACE_RESERVED 1 +// Normal filesystem namespace +#define ANDROID_SOCKET_NAMESPACE_FILESYSTEM 2 + +extern int socket_loopback_client(int port, int type); +extern int socket_network_client(const char *host, int port, int type); +extern int socket_loopback_server(int port, int type); +extern int socket_local_server(const char *name, int namespaceId, int type); +extern int socket_local_server_bind(int s, const char *name, int namespaceId); +extern int socket_local_client_connect(int fd, + const char *name, int namespaceId, int type); +extern int socket_local_client(const char *name, int namespaceId, int type); +extern int socket_inaddr_any_server(int port, int type); + +#ifdef __cplusplus +} +#endif + +#endif /* __CUTILS_SOCKETS_H */ diff --git a/src/jni/jpeg/cutils/threads.h b/src/jni/jpeg/cutils/threads.h new file mode 100644 index 0000000000..a9b9236e59 --- /dev/null +++ b/src/jni/jpeg/cutils/threads.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBS_CUTILS_THREADS_H +#define _LIBS_CUTILS_THREADS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/***********************************************************************/ +/***********************************************************************/ +/***** *****/ +/***** local thread storage *****/ +/***** *****/ +/***********************************************************************/ +/***********************************************************************/ +#define HAVE_PTHREADS +#ifdef HAVE_PTHREADS + +#include + +typedef struct { + pthread_mutex_t lock; + int has_tls; + pthread_key_t tls; + +} thread_store_t; + +#define THREAD_STORE_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0 } + +#elif defined HAVE_WIN32_THREADS + +#include + +typedef struct { + int lock_init; + int has_tls; + DWORD tls; + CRITICAL_SECTION lock; + +} thread_store_t; + +#define THREAD_STORE_INITIALIZER { 0, 0, 0, {0, 0, 0, 0, 0, 0} } + +#else +# error "no thread_store_t implementation for your platform !!" +#endif + +typedef void (*thread_store_destruct_t)(void* value); + +extern void* thread_store_get(thread_store_t* store); + +extern void thread_store_set(thread_store_t* store, + void* value, + thread_store_destruct_t destroy); + +/***********************************************************************/ +/***********************************************************************/ +/***** *****/ +/***** mutexes *****/ +/***** *****/ +/***********************************************************************/ +/***********************************************************************/ + +#ifdef HAVE_PTHREADS + +typedef pthread_mutex_t mutex_t; + +#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER + +static __inline__ void mutex_lock(mutex_t* lock) +{ + pthread_mutex_lock(lock); +} +static __inline__ void mutex_unlock(mutex_t* lock) +{ + pthread_mutex_unlock(lock); +} +static __inline__ int mutex_init(mutex_t* lock) +{ + return pthread_mutex_init(lock, NULL); +} +static __inline__ void mutex_destroy(mutex_t* lock) +{ + pthread_mutex_destroy(lock); +} +#endif + +#ifdef HAVE_WIN32_THREADS +typedef struct { + int init; + CRITICAL_SECTION lock[1]; +} mutex_t; + +#define MUTEX_INITIALIZER { 0, {{ NULL, 0, 0, NULL, NULL, 0 }} } + +static __inline__ void mutex_lock(mutex_t* lock) +{ + if (!lock->init) { + lock->init = 1; + InitializeCriticalSection( lock->lock ); + lock->init = 2; + } else while (lock->init != 2) + Sleep(10); + + EnterCriticalSection(lock->lock); +} + +static __inline__ void mutex_unlock(mutex_t* lock) +{ + LeaveCriticalSection(lock->lock); +} +static __inline__ int mutex_init(mutex_t* lock) +{ + InitializeCriticalSection(lock->lock); + lock->init = 2; + return 0; +} +static __inline__ void mutex_destroy(mutex_t* lock) +{ + if (lock->init) { + lock->init = 0; + DeleteCriticalSection(lock->lock); + } +} +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBS_CUTILS_THREADS_H */ diff --git a/src/jni/jpeg/cutils/tztime.h b/src/jni/jpeg/cutils/tztime.h new file mode 100644 index 0000000000..cf103cae5e --- /dev/null +++ b/src/jni/jpeg/cutils/tztime.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CUTILS_TZTIME_H +#define _CUTILS_TZTIME_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +time_t mktime_tz(struct tm * const tmp, char const * tz); +void localtime_tz(const time_t * const timep, struct tm * tmp, const char* tz); + +#ifndef HAVE_ANDROID_OS +/* the following is defined in in Bionic */ + +struct strftime_locale { + const char *mon[12]; /* short names */ + const char *month[12]; /* long names */ + const char *standalone_month[12]; /* long standalone names */ + const char *wday[7]; /* short names */ + const char *weekday[7]; /* long names */ + const char *X_fmt; + const char *x_fmt; + const char *c_fmt; + const char *am; + const char *pm; + const char *date_fmt; +}; + +size_t strftime_tz(char *s, size_t max, const char *format, const struct tm *tm, const struct strftime_locale *locale); + +#endif /* !HAVE_ANDROID_OS */ + +#ifdef __cplusplus +} +#endif + +#endif /* __CUTILS_TZTIME_H */ + diff --git a/src/jni/jpeg/cutils/uio.h b/src/jni/jpeg/cutils/uio.h new file mode 100644 index 0000000000..52df54e92c --- /dev/null +++ b/src/jni/jpeg/cutils/uio.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// implementation of sys/uio.h for platforms that don't have it (Win32) +// +#ifndef _LIBS_CUTILS_UIO_H +#define _LIBS_CUTILS_UIO_H + +#define HAVE_SYS_UIO_H +#ifdef HAVE_SYS_UIO_H +#include +#else + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct iovec { + const void* iov_base; + size_t iov_len; +}; + +extern int readv( int fd, struct iovec* vecs, int count ); +extern int writev( int fd, const struct iovec* vecs, int count ); + +#ifdef __cplusplus +} +#endif + +#endif /* !HAVE_SYS_UIO_H */ + +#endif /* _LIBS_UTILS_UIO_H */ + diff --git a/src/jni/jpeg/cutils/zygote.h b/src/jni/jpeg/cutils/zygote.h new file mode 100644 index 0000000000..22721a6bdc --- /dev/null +++ b/src/jni/jpeg/cutils/zygote.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CUTILS_ZYGOTE_H +#define __CUTILS_ZYGOTE_H + +#ifdef __cplusplus +extern "C" { +#endif + +int zygote_run_oneshot(int sendStdio, int argc, const char **argv); +int zygote_run(int argc, const char **argv); +int zygote_run_wait(int argc, const char **argv, void (*post_run_func)(int)); + +#ifdef __cplusplus +} +#endif + +#endif /* __CUTILS_ZYGOTE_H */ diff --git a/src/jni/jpeg/de_mjpegsample_NativeJpegLib.c b/src/jni/jpeg/de_mjpegsample_NativeJpegLib.c new file mode 100644 index 0000000000..54a3b0946e --- /dev/null +++ b/src/jni/jpeg/de_mjpegsample_NativeJpegLib.c @@ -0,0 +1,210 @@ +#include "de_mjpegsample_NativeJpegLib.h" +#include +#include +#include + +#include /* low-level i/o */ +#include +#include +#include +#include +#include +#include +#include +#include + +//#include /* for videodev2.h */ +#include + +/* default size, This just the size of sample yuv */ +#define OUTPUT_BUF_SIZE 4096 + +typedef struct { + struct jpeg_destination_mgr pub; /* public fields */ + + JOCTET * buffer; /* start of buffer */ + + unsigned char *outbuffer; + int outbuffer_size; + unsigned char *outbuffer_cursor; + int *written; +}my_destmgr; + +METHODDEF(void) init_destination(j_compress_ptr cinfo) { + my_destmgr * dest = (my_destmgr*) cinfo->dest; + + /* Allocate the output buffer --- it will be released when done with + * image */ + dest->buffer = (JOCTET *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE * sizeof(JOCTET)); + + *(dest->written) = 0; + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + +/****************************************************************************** +Description.: called whenever local jpeg buffer fills up +Input Value.: +Return Value: +******************************************************************************/ +METHODDEF(boolean) empty_output_buffer(j_compress_ptr cinfo) +{ + my_destmgr *dest = (my_destmgr *) cinfo->dest; + + memcpy(dest->outbuffer_cursor, dest->buffer, OUTPUT_BUF_SIZE); + dest->outbuffer_cursor += OUTPUT_BUF_SIZE; + *(dest->written) += OUTPUT_BUF_SIZE; + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + + return TRUE; +} + + +METHODDEF(void) term_destination(j_compress_ptr cinfo) +{ + my_destmgr * dest = (my_destmgr *) cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + + /* Write any data remaining in the buffer */ + memcpy(dest->outbuffer_cursor, dest->buffer, datacount); + dest->outbuffer_cursor += datacount; + *(dest->written) += datacount; +} + +void dest_buffer(j_compress_ptr cinfo, unsigned char *buffer, int size, int *written) +{ + my_destmgr * dest; + + if (cinfo->dest == NULL) { + cinfo->dest = (struct jpeg_destination_mgr *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_destmgr)); + } + + dest = (my_destmgr*) cinfo->dest; + dest->pub.init_destination = init_destination; + dest->pub.empty_output_buffer = empty_output_buffer; + dest->pub.term_destination = term_destination; + dest->outbuffer = buffer; + dest->outbuffer_size = size; + dest->outbuffer_cursor = buffer; + dest->written = written; +} + + +static int convert_to_jpg(void *src, int src_len, + void *dst, int pwidth, int pheight, int quality) { + //Code for this function is taken from Motion + //Credit to them !!! + //Also Credit mjpg-streamer + + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + my_destmgr dest; + + memset(&cinfo , 0, sizeof(cinfo)); + + JSAMPROW y[16],cb[16],cr[16]; + JSAMPARRAY data[3]; + int i, line, width = pwidth, height = pheight; + int written; /* for count file size */ + + printf("Encoding a %dx%d frame\n", width, height); + + data[0] = y; + data[1] = cb; + data[2] = cr; + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + + //init JPEG dest mgr + dest_buffer(&cinfo, dst, src_len, &written); + + jpeg_set_quality(&cinfo, quality, TRUE); + + cinfo.input_components = 3; + cinfo.image_width = width; + cinfo.image_height = height; + + cinfo.in_color_space = JCS_YCbCr; + jpeg_set_defaults(&cinfo); + jpeg_set_colorspace(&cinfo, JCS_YCbCr); + cinfo.raw_data_in = TRUE; + + cinfo.dct_method = JDCT_FLOAT; + /* This method will faster in faster HW */ + + jpeg_start_compress( &cinfo, TRUE ); + for (line=0; lineGetByteArrayElements(env, yuv_bytes, 0); + int yuv_length = (*env)->GetArrayLength(env, yuv_bytes); + + // allocate memory to hold converted JPEG bytes + char *jpeg_buf = malloc(yuv_length); + // convert YUV420 to JPEG + int jpg_buf_size = convert_to_jpg(yuv_bytes_ptr, yuv_length, jpeg_buf, width, height, quality); + + // release all memory + (*env)->ReleaseByteArrayElements(env, yuv_bytes, yuv_bytes_ptr, (jint)0); + + // create direct buffer + jobject jbuff = (*env)->NewDirectByteBuffer(env, (void*)jpeg_buf, (jlong)jpg_buf_size); + return jbuff; +} + +/* + * Class: de_mjpegsample_NativeJpegLib + * Method: c_decompress_jpeg + * Signature: (II[B)Ljava/nio/ByteBuffer; + */ +JNIEXPORT jobject JNICALL Java_de_mjpegsample_NativeJpegLib_c_1decompress_1jpeg + (JNIEnv *env, jclass cls, jint width, jint height, jbyteArray jpeg_bytes) { + // TODO: stub + return NULL; +} + +/* + * Class: de_mjpegsample_NativeJpegLib + * Method: allocateNativeBuffer + * Signature: (I)Ljava/nio/ByteBuffer; + */ +JNIEXPORT jobject JNICALL Java_de_mjpegsample_NativeJpegLib_allocateNativeBuffer + (JNIEnv *env, jclass cls, jint size) { + void* buffer = malloc(size); + jobject directBuffer = (*env)->NewDirectByteBuffer(env, buffer, size); + return directBuffer; +} + +/* + * Class: de_mjpegsample_NativeJpegLib + * Method: freeNativeBuffer + * Signature: (Ljava/nio/ByteBuffer;)V + */ +JNIEXPORT void JNICALL Java_de_mjpegsample_NativeJpegLib_freeNativeBuffer + (JNIEnv *env, jclass cls, jobject jbyteBuf) { + void *buf = (*env)->GetDirectBufferAddress(env, jbyteBuf); + free(buf); +} diff --git a/src/jni/jpeg/de_mjpegsample_NativeJpegLib.h b/src/jni/jpeg/de_mjpegsample_NativeJpegLib.h new file mode 100644 index 0000000000..38dd9a6100 --- /dev/null +++ b/src/jni/jpeg/de_mjpegsample_NativeJpegLib.h @@ -0,0 +1,45 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class de_mjpegsample_NativeJpegLib */ + +#ifndef _Included_de_mjpegsample_NativeJpegLib +#define _Included_de_mjpegsample_NativeJpegLib +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: de_mjpegsample_NativeJpegLib + * Method: allocateNativeBuffer + * Signature: (I)Ljava/nio/ByteBuffer; + */ +JNIEXPORT jobject JNICALL Java_de_mjpegsample_NativeJpegLib_allocateNativeBuffer + (JNIEnv *, jclass, jint); + +/* + * Class: de_mjpegsample_NativeJpegLib + * Method: freeNativeBuffer + * Signature: (Ljava/nio/ByteBuffer;)V + */ +JNIEXPORT void JNICALL Java_de_mjpegsample_NativeJpegLib_freeNativeBuffer + (JNIEnv *, jclass, jobject); + +/* + * Class: de_mjpegsample_NativeJpegLib + * Method: c_compress_jpeg + * Signature: (III[B)Ljava/nio/ByteBuffer; + */ +JNIEXPORT jobject JNICALL Java_de_mjpegsample_NativeJpegLib_c_1compress_1jpeg + (JNIEnv *, jclass, jint, jint, jint, jbyteArray); + +/* + * Class: de_mjpegsample_NativeJpegLib + * Method: c_decompress_jpeg + * Signature: (II[B)Ljava/nio/ByteBuffer; + */ +JNIEXPORT jobject JNICALL Java_de_mjpegsample_NativeJpegLib_c_1decompress_1jpeg + (JNIEnv *, jclass, jint, jint, jbyteArray); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/jni/jpeg/jcparam.c b/src/jni/jpeg/jcparam.c index 6fc48f5365..a8dcf61544 100644 --- a/src/jni/jpeg/jcparam.c +++ b/src/jni/jpeg/jcparam.c @@ -605,6 +605,10 @@ jpeg_simple_progression (j_compress_ptr cinfo) scanptr = fill_dc_scans(scanptr, ncomps, 1, 0); scanptr = fill_scans(scanptr, ncomps, 1, 63, 1, 0); } +#ifdef NEEDS_ARM_ERRATA_754319_754320 + asm volatile ( "vmov s0,s0\n" ); +#endif + } #endif /* C_PROGRESSIVE_SUPPORTED */ diff --git a/src/jni/jpeg/jctrans.c b/src/jni/jpeg/jctrans.c index 0e6d70769d..f574ed14f1 100644 --- a/src/jni/jpeg/jctrans.c +++ b/src/jni/jpeg/jctrans.c @@ -338,6 +338,9 @@ compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) /* Suspension forced; update state counters and exit */ coef->MCU_vert_offset = yoffset; coef->mcu_ctr = MCU_col_num; +#ifdef NEEDS_ARM_ERRATA_754319_754320 + asm volatile ( "vmov s0,s0\n" ); +#endif return FALSE; } } @@ -347,6 +350,10 @@ compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) /* Completed the iMCU row, advance counters for next one */ coef->iMCU_row_num++; start_iMCU_row(cinfo); +#ifdef NEEDS_ARM_ERRATA_754319_754320 + asm volatile ( "vmov s0,s0\n" ); +#endif + return TRUE; } diff --git a/src/jni/jpeg/jdapimin.c b/src/jni/jpeg/jdapimin.c index cadb59fce3..5c9607ed5c 100644 --- a/src/jni/jpeg/jdapimin.c +++ b/src/jni/jpeg/jdapimin.c @@ -53,6 +53,7 @@ jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize) cinfo->client_data = client_data; } cinfo->is_decompressor = TRUE; + cinfo->tile_decode = FALSE; /* Initialize a memory manager instance for this object */ jinit_memory_mgr((j_common_ptr) cinfo); @@ -371,6 +372,9 @@ jpeg_finish_decompress (j_decompress_ptr cinfo) if ((cinfo->global_state == DSTATE_SCANNING || cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) { /* Terminate final pass of non-buffered mode */ +#ifdef ANDROID_TILE_BASED_DECODE + cinfo->output_scanline = cinfo->output_height; +#endif if (cinfo->output_scanline < cinfo->output_height) ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); (*cinfo->master->finish_output_pass) (cinfo); @@ -383,10 +387,12 @@ jpeg_finish_decompress (j_decompress_ptr cinfo) ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); } /* Read until EOI */ +#ifndef ANDROID_TILE_BASED_DECODE while (! cinfo->inputctl->eoi_reached) { if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) return FALSE; /* Suspend, come back later */ } +#endif /* Do final cleanup */ (*cinfo->src->term_source) (cinfo); /* We can use jpeg_abort to release memory and reset global_state */ diff --git a/src/jni/jpeg/jdapistd.c b/src/jni/jpeg/jdapistd.c index c8e3fa0c35..e1233df36f 100644 --- a/src/jni/jpeg/jdapistd.c +++ b/src/jni/jpeg/jdapistd.c @@ -82,6 +82,32 @@ jpeg_start_decompress (j_decompress_ptr cinfo) return output_pass_setup(cinfo); } +/* + * Tile decompression initialization. + * jpeg_read_header must be completed before calling this. + */ + +GLOBAL(boolean) +jpeg_start_tile_decompress (j_decompress_ptr cinfo) +{ + if (cinfo->global_state == DSTATE_READY) { + /* First call: initialize master control, select active modules */ + cinfo->tile_decode = TRUE; + jinit_master_decompress(cinfo); + if (cinfo->buffered_image) { + cinfo->global_state = DSTATE_BUFIMAGE; + return TRUE; + } + cinfo->global_state = DSTATE_PRELOAD; + } + if (cinfo->global_state == DSTATE_PRELOAD) { + cinfo->output_scan_number = cinfo->input_scan_number; + } else if (cinfo->global_state != DSTATE_PRESCAN) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Perform any dummy output passes, and set up for the final pass */ + return output_pass_setup(cinfo); +} + /* * Set up for an output pass, and perform any dummy pass(es) needed. @@ -174,7 +200,103 @@ jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines, cinfo->output_scanline += row_ctr; return row_ctr; } +/* + * Initialize the jpeg decoder to decompressing a rectangle with size of (width, height) + * and its upper-left corner located at (start_x, start_y). + * Align start_x and start_y to multiplies of iMCU width and height, respectively. + * Also, the new reader position and sampled image size will be returned in + * (start_x, start_y) and (width, height), respectively. + */ + +GLOBAL(void) +jpeg_init_read_tile_scanline(j_decompress_ptr cinfo, huffman_index *index, + int *start_x, int *start_y, int *width, int *height) +{ + // Calculates the boundary of iMCU + int lines_per_iMCU_row = cinfo->max_v_samp_factor * DCTSIZE; + int lines_per_iMCU_col = cinfo->max_h_samp_factor * DCTSIZE; + int row_offset = *start_y / lines_per_iMCU_row; + int col_left_boundary = ((*start_x / lines_per_iMCU_col) + / index->MCU_sample_size) * index->MCU_sample_size; + int col_right_boundary = + jdiv_round_up(*start_x + *width, lines_per_iMCU_col); + + cinfo->coef->MCU_columns_to_skip = + *start_x / lines_per_iMCU_col - col_left_boundary; + + *height = (*start_y - row_offset * lines_per_iMCU_row) + *height; + *start_x = col_left_boundary * lines_per_iMCU_col; + *start_y = row_offset * lines_per_iMCU_row; + cinfo->image_width = jmin(cinfo->original_image_width, + col_right_boundary * lines_per_iMCU_col) - + col_left_boundary * lines_per_iMCU_col; + cinfo->input_iMCU_row = row_offset; + cinfo->output_iMCU_row = row_offset; + + // Updates JPEG decoder parameter + jinit_color_deconverter(cinfo); + jpeg_calc_output_dimensions(cinfo); + jinit_upsampler(cinfo); + (*cinfo->master->prepare_for_output_pass) (cinfo); + if (cinfo->progressive_mode) + (*cinfo->entropy->start_pass) (cinfo); + else + jpeg_decompress_per_scan_setup(cinfo); + + int sample_size = DCTSIZE / cinfo->min_DCT_scaled_size; + + *height = jdiv_round_up(*height, sample_size); + *width = cinfo->output_width; + cinfo->output_scanline = lines_per_iMCU_row * row_offset / sample_size; + cinfo->inputctl->consume_input = cinfo->coef->consume_data; + cinfo->inputctl->consume_input_build_huffman_index = + cinfo->coef->consume_data_build_huffman_index; + cinfo->entropy->index = index; + cinfo->input_iMCU_row = row_offset; + cinfo->output_iMCU_row = row_offset; + cinfo->coef->MCU_column_left_boundary = col_left_boundary; + cinfo->coef->MCU_column_right_boundary = col_right_boundary; + cinfo->coef->column_left_boundary = + col_left_boundary / index->MCU_sample_size; + cinfo->coef->column_right_boundary = + jdiv_round_up(col_right_boundary, index->MCU_sample_size); +} + +/* + * Read a scanline from the current position. + * + * Return the number of lines actually read. + */ + +GLOBAL(JDIMENSION) +jpeg_read_tile_scanline (j_decompress_ptr cinfo, huffman_index *index, + JSAMPARRAY scanlines) +{ + // Calculates the boundary of iMCU + int lines_per_iMCU_row = cinfo->max_v_samp_factor * DCTSIZE; + int lines_per_iMCU_col = cinfo->max_h_samp_factor * DCTSIZE; + int sample_size = DCTSIZE / cinfo->min_DCT_scaled_size; + JDIMENSION row_ctr = 0; + + if (cinfo->progressive_mode) { + (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, 1); + } else { + if (cinfo->output_scanline % (lines_per_iMCU_row / sample_size) == 0) { + // Set the read head to the next iMCU row + int iMCU_row_offset = cinfo->output_scanline / + (lines_per_iMCU_row / sample_size); + int offset_data_col_position = cinfo->coef->MCU_column_left_boundary / + index->MCU_sample_size; + huffman_offset_data offset_data = + index->scan[0].offset[iMCU_row_offset][offset_data_col_position]; + (*cinfo->entropy->configure_huffman_decoder) (cinfo, offset_data); + } + (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, 1); + } + cinfo->output_scanline += row_ctr; + return row_ctr; +} /* * Alternate entry point to read raw data. diff --git a/src/jni/jpeg/jdcoefct.c b/src/jni/jpeg/jdcoefct.c index 4938d20fcb..e6e95062cd 100644 --- a/src/jni/jpeg/jdcoefct.c +++ b/src/jni/jpeg/jdcoefct.c @@ -156,19 +156,32 @@ decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) jpeg_component_info *compptr; inverse_DCT_method_ptr inverse_DCT; +#ifdef ANDROID_TILE_BASED_DECODE + if (cinfo->tile_decode) { + last_MCU_col = + (cinfo->coef->MCU_column_right_boundary - + cinfo->coef->MCU_column_left_boundary) - 1; + } +#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++) { /* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */ - jzero_far((void FAR *) coef->MCU_buffer[0], + if (MCU_col_num < coef->pub.MCU_columns_to_skip) { + (*cinfo->entropy->decode_mcu_discard_coef) (cinfo); + continue; + } else { + jzero_far((void FAR *) coef->MCU_buffer[0], (size_t) (cinfo->blocks_in_MCU * SIZEOF(JBLOCK))); - 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 (! (*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; + } } /* 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 @@ -195,8 +208,8 @@ decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) output_col = start_col; for (xindex = 0; xindex < useful_width; xindex++) { (*inverse_DCT) (cinfo, compptr, - (JCOEFPTR) coef->MCU_buffer[blkn+xindex], - output_ptr, output_col); + (JCOEFPTR) coef->MCU_buffer[blkn+xindex], + output_ptr, output_col); output_col += compptr->DCT_scaled_size; } } @@ -230,9 +243,7 @@ dummy_consume_data (j_decompress_ptr cinfo) return JPEG_SUSPENDED; /* Always indicate nothing was done */ } - #ifdef D_MULTISCAN_FILES_SUPPORTED - /* * Consume input data and store it in the full-image coefficient buffer. * We read as much as one fully interleaved MCU row ("iMCU" row) per call, @@ -256,30 +267,257 @@ consume_data (j_decompress_ptr cinfo) compptr = cinfo->cur_comp_info[ci]; buffer[ci] = (*cinfo->mem->access_virt_barray) ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], - cinfo->input_iMCU_row * compptr->v_samp_factor, + cinfo->tile_decode ? 0 : cinfo->input_iMCU_row * compptr->v_samp_factor, (JDIMENSION) compptr->v_samp_factor, TRUE); /* Note: entropy decoder expects buffer to be zeroed, * but this is handled automatically by the memory manager * because we requested a pre-zeroed array. */ } + unsigned int MCUs_per_row = cinfo->MCUs_per_row; +#ifdef ANDROID_TILE_BASED_DECODE + if (cinfo->tile_decode) { + int iMCU_width_To_MCU_width; + if (cinfo->comps_in_scan > 1) { + // Interleaved + iMCU_width_To_MCU_width = 1; + } else { + // Non-intervleaved + iMCU_width_To_MCU_width = cinfo->cur_comp_info[0]->h_samp_factor; + } + MCUs_per_row = jmin(MCUs_per_row, + (cinfo->coef->column_right_boundary - cinfo->coef->column_left_boundary) + * cinfo->entropy->index->MCU_sample_size * iMCU_width_To_MCU_width); + } +#endif /* Loop to process 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 < cinfo->MCUs_per_row; - MCU_col_num++) { + // configure huffman decoder +#ifdef ANDROID_TILE_BASED_DECODE + if (cinfo->tile_decode) { + huffman_scan_header scan_header = + cinfo->entropy->index->scan[cinfo->input_scan_number]; + int col_offset = cinfo->coef->column_left_boundary; + (*cinfo->entropy->configure_huffman_decoder) (cinfo, + scan_header.offset[cinfo->input_iMCU_row] + [col_offset + yoffset * scan_header.MCUs_per_row]); + } +#endif + + // zero all blocks + for (MCU_col_num = coef->MCU_ctr; MCU_col_num < MCUs_per_row; + MCU_col_num++) { /* Construct list of pointers to DCT blocks belonging to this MCU */ blkn = 0; /* index of current DCT block within MCU */ for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - start_col = MCU_col_num * compptr->MCU_width; - for (yindex = 0; yindex < compptr->MCU_height; yindex++) { - buffer_ptr = buffer[ci][yindex+yoffset] + start_col; - for (xindex = 0; xindex < compptr->MCU_width; xindex++) { - coef->MCU_buffer[blkn++] = buffer_ptr++; - } - } + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < compptr->MCU_width; xindex++) { + coef->MCU_buffer[blkn++] = buffer_ptr++; +#ifdef ANDROID_TILE_BASED_DECODE + if (cinfo->tile_decode && cinfo->input_scan_number == 0) { + // need to do pre-zero ourselves. + jzero_far((void FAR *) coef->MCU_buffer[blkn-1], + (size_t) (SIZEOF(JBLOCK))); + } +#endif + } + } + } + + + /* Try to fetch the MCU. */ + 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; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + +/* + * Consume input data and store it in the coefficient buffer. + * Read one fully interleaved MCU row ("iMCU" row) per call. + */ + +METHODDEF(int) +consume_data_multi_scan (j_decompress_ptr cinfo) +{ + huffman_index *index = cinfo->entropy->index; + int i, retcode, ci; + int mcu = cinfo->input_iMCU_row; + jinit_phuff_decoder(cinfo); + for (i = 0; i < index->scan_count; i++) { + (*cinfo->inputctl->finish_input_pass) (cinfo); + jset_input_stream_position(cinfo, index->scan[i].bitstream_offset); + cinfo->output_iMCU_row = mcu; + cinfo->unread_marker = 0; + // Consume SOS and DHT headers + retcode = (*cinfo->inputctl->consume_markers) (cinfo, index, i); + cinfo->input_iMCU_row = mcu; + cinfo->input_scan_number = i; + cinfo->entropy->index = index; + // Consume scan block data + consume_data(cinfo); + } + cinfo->input_iMCU_row = mcu + 1; + cinfo->input_scan_number = 0; + cinfo->output_scan_number = 0; + return JPEG_ROW_COMPLETED; +} + +/* + * Same as consume_data, expect for saving the Huffman decode information + * - bitstream offset and DC coefficient to index. + */ + +METHODDEF(int) +consume_data_build_huffman_index_baseline (j_decompress_ptr cinfo, + huffman_index *index, int current_scan) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + int ci, xindex, yindex, yoffset; + JDIMENSION start_col; + JBLOCKROW buffer_ptr; + + huffman_scan_header *scan_header = index->scan + current_scan; + scan_header->MCU_rows_per_iMCU_row = coef->MCU_rows_per_iMCU_row; + + size_t allocate_size = coef->MCU_rows_per_iMCU_row + * jdiv_round_up(cinfo->MCUs_per_row, index->MCU_sample_size) + * sizeof(huffman_offset_data); + scan_header->offset[cinfo->input_iMCU_row] = + (huffman_offset_data*)malloc(allocate_size); + index->mem_used += allocate_size; + + huffman_offset_data *offset_data = scan_header->offset[cinfo->input_iMCU_row]; + + /* Loop to process 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 < cinfo->MCUs_per_row; + MCU_col_num++) { + // Record huffman bit offset + if (MCU_col_num % index->MCU_sample_size == 0) { + (*cinfo->entropy->get_huffman_decoder_configuration) + (cinfo, offset_data); + ++offset_data; + } + + /* Try to fetch the MCU. */ + if (! (*cinfo->entropy->decode_mcu_discard_coef) (cinfo)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return JPEG_SUSPENDED; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + +/* + * Same as consume_data, expect for saving the Huffman decode information + * - bitstream offset and DC coefficient to index. + */ + +METHODDEF(int) +consume_data_build_huffman_index_progressive (j_decompress_ptr cinfo, + huffman_index *index, int current_scan) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + int blkn, ci, xindex, yindex, yoffset; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + + int factor = 4; // maximum factor is 4. + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + factor = jmin(factor, cinfo->cur_comp_info[ci]->h_samp_factor); + + int sample_size = index->MCU_sample_size * factor; + huffman_scan_header *scan_header = index->scan + current_scan; + scan_header->MCU_rows_per_iMCU_row = coef->MCU_rows_per_iMCU_row; + scan_header->MCUs_per_row = jdiv_round_up(cinfo->MCUs_per_row, sample_size); + scan_header->comps_in_scan = cinfo->comps_in_scan; + + size_t allocate_size = coef->MCU_rows_per_iMCU_row + * scan_header->MCUs_per_row * sizeof(huffman_offset_data); + scan_header->offset[cinfo->input_iMCU_row] = + (huffman_offset_data*)malloc(allocate_size); + index->mem_used += allocate_size; + + huffman_offset_data *offset_data = scan_header->offset[cinfo->input_iMCU_row]; + + /* Align the virtual buffers for the components used in this scan. */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + 0, // Only need one row buffer + (JDIMENSION) compptr->v_samp_factor, TRUE); + } + /* Loop to process 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 < cinfo->MCUs_per_row; + MCU_col_num++) { + /* For each MCU, we loop through different color components. + * Then, for each color component we will get a list of pointers to DCT + * blocks in the virtual buffer. + */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + /* Get the list of pointers to DCT blocks in + * the virtual buffer in a color component of the MCU. + */ + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < compptr->MCU_width; xindex++) { + coef->MCU_buffer[blkn++] = buffer_ptr++; + if (cinfo->input_scan_number == 0) { + // need to do pre-zero by ourself. + jzero_far((void FAR *) coef->MCU_buffer[blkn-1], + (size_t) (SIZEOF(JBLOCK))); + } + } + } + } + // Record huffman bit offset + if (MCU_col_num % sample_size == 0) { + (*cinfo->entropy->get_huffman_decoder_configuration) + (cinfo, offset_data); + ++offset_data; } /* Try to fetch the MCU. */ if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { @@ -292,6 +530,8 @@ consume_data (j_decompress_ptr cinfo) /* Completed an MCU row, but perhaps not an iMCU row */ coef->MCU_ctr = 0; } + (*cinfo->entropy->get_huffman_decoder_configuration) + (cinfo, &scan_header->prev_MCU_offset); /* Completed the iMCU row, advance counters for next one */ if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { start_iMCU_row(cinfo); @@ -302,7 +542,6 @@ consume_data (j_decompress_ptr cinfo) return JPEG_SCAN_COMPLETED; } - /* * Decompress and return some data in the multi-pass case. * Always attempts to emit one fully interleaved MCU row ("iMCU" row). @@ -342,7 +581,7 @@ decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) /* Align the virtual buffer for this component. */ buffer = (*cinfo->mem->access_virt_barray) ((j_common_ptr) cinfo, coef->whole_image[ci], - cinfo->output_iMCU_row * compptr->v_samp_factor, + cinfo->tile_decode ? 0 : cinfo->output_iMCU_row * compptr->v_samp_factor, (JDIMENSION) compptr->v_samp_factor, FALSE); /* Count non-dummy DCT block rows in this iMCU row. */ if (cinfo->output_iMCU_row < last_iMCU_row) @@ -354,11 +593,25 @@ decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) } inverse_DCT = cinfo->idct->inverse_DCT[ci]; output_ptr = output_buf[ci]; + int width_in_blocks = compptr->width_in_blocks; + int start_block = 0; +#if ANDROID_TILE_BASED_DECODE + if (cinfo->tile_decode) { + // width_in_blocks for a component depends on its h_samp_factor. + width_in_blocks = jmin(width_in_blocks, + (cinfo->coef->MCU_column_right_boundary - + cinfo->coef->MCU_column_left_boundary) * + compptr->h_samp_factor); + start_block = coef->pub.MCU_columns_to_skip * + compptr->h_samp_factor; + } +#endif /* Loop over all DCT blocks to be processed. */ for (block_row = 0; block_row < block_rows; block_row++) { buffer_ptr = buffer[block_row]; - output_col = 0; - for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) { + output_col = start_block * compptr->DCT_scaled_size; + buffer_ptr += start_block; + for (block_num = start_block; block_num < width_in_blocks; block_num++) { (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr, output_ptr, output_col); buffer_ptr++; @@ -683,10 +936,59 @@ jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer) cinfo->coef = (struct jpeg_d_coef_controller *) coef; coef->pub.start_input_pass = start_input_pass; coef->pub.start_output_pass = start_output_pass; + coef->pub.column_left_boundary = 0; + coef->pub.column_right_boundary = 0; + coef->pub.MCU_columns_to_skip = 0; #ifdef BLOCK_SMOOTHING_SUPPORTED coef->coef_bits_latch = NULL; #endif +#ifdef ANDROID_TILE_BASED_DECODE + if (cinfo->tile_decode) { + if (cinfo->progressive_mode) { + /* Allocate one iMCU row virtual array, coef->whole_image[ci], + * for each color component, padded to a multiple of h_samp_factor + * DCT blocks in the horizontal direction. + */ + int ci, access_rows; + jpeg_component_info *compptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + access_rows = compptr->v_samp_factor; + coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE, + (JDIMENSION) jround_up((long) compptr->width_in_blocks, + (long) compptr->h_samp_factor), + (JDIMENSION) compptr->v_samp_factor, // one iMCU row + (JDIMENSION) access_rows); + } + coef->pub.consume_data_build_huffman_index = + consume_data_build_huffman_index_progressive; + coef->pub.consume_data = consume_data_multi_scan; + coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */ + coef->pub.decompress_data = decompress_onepass; + } else { + /* We only need a single-MCU buffer. */ + JBLOCKROW buffer; + int i; + + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) { + coef->MCU_buffer[i] = buffer + i; + } + coef->pub.consume_data_build_huffman_index = + consume_data_build_huffman_index_baseline; + coef->pub.consume_data = dummy_consume_data; + coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */ + coef->pub.decompress_data = decompress_onepass; + } + return; + } +#endif + /* Create the coefficient buffer. */ if (need_full_buffer) { #ifdef D_MULTISCAN_FILES_SUPPORTED @@ -725,7 +1027,7 @@ jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer) buffer = (JBLOCKROW) (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, - D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); for (i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) { coef->MCU_buffer[i] = buffer + i; } diff --git a/src/jni/jpeg/jdcolor.c b/src/jni/jpeg/jdcolor.c index 202360c76c..9a6519e3eb 100644 --- a/src/jni/jpeg/jdcolor.c +++ b/src/jni/jpeg/jdcolor.c @@ -2,6 +2,7 @@ * jdcolor.c * * Copyright (C) 1991-1997, Thomas G. Lane. + * Copyright (c) 2010, Code Aurora Forum. All rights reserved. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -12,7 +13,6 @@ #include "jinclude.h" #include "jpeglib.h" - /* Private subobject */ typedef struct { @@ -122,6 +122,9 @@ build_ycc_rgb_table (j_decompress_ptr cinfo) /* We also add in ONE_HALF so that need not do it in inner loop */ cconvert->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF; } +#ifdef NEEDS_ARM_ERRATA_754319_754320 + asm volatile ( "vmov s0,s0\n" ); +#endif } /* @@ -139,6 +142,33 @@ METHODDEF(void) ycc_rgb_convert (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows) +#ifdef ANDROID_JPEG_USE_VENUM +/* + * Converts YCC->RGB888 using VeNum instructions. + */ +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + JSAMPROW inptr0, inptr1, inptr2; + JSAMPROW outptr; + JDIMENSION row; + + for (row = 0; row < (JDIMENSION)num_rows; row++) + { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + + input_row++; + outptr = *output_buf++; + + yvup2bgr888_venum((UINT8*) inptr0, + (UINT8*) inptr2, + (UINT8*) inptr1, + (UINT8*) outptr, + cinfo->output_width); + } +} +#else { my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; register int y, cb, cr; @@ -174,12 +204,40 @@ ycc_rgb_convert (j_decompress_ptr cinfo, } } } +#endif /* ANDROID_JPEG_USE_VENUM */ #ifdef ANDROID_RGB METHODDEF(void) ycc_rgba_8888_convert (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows) +#ifdef ANDROID_JPEG_USE_VENUM +/* + * Converts YCC->RGBA8888 using VeNum instructions. + */ +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + JSAMPROW inptr0, inptr1, inptr2; + JSAMPROW outptr; + JDIMENSION row; + + for (row = 0; row < (JDIMENSION)num_rows; row++) + { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + + yvup2abgr8888_venum((UINT8*) inptr0, + (UINT8*) inptr2, + (UINT8*) inptr1, + (UINT8*) outptr, + cinfo->output_width); + } +} + +#else { my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; register int y, cb, cr; @@ -216,11 +274,38 @@ ycc_rgba_8888_convert (j_decompress_ptr cinfo, } } } +#endif /* ANDROID_JPEG_USE_VENUM */ METHODDEF(void) ycc_rgb_565_convert (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows) +#if defined(ANDROID_JPEG_USE_VENUM) +/* + * Converts YCC->RGB565 using VeNum instructions. + */ +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + JSAMPROW inptr0, inptr1, inptr2; + JSAMPROW outptr; + JDIMENSION row; + + for (row = 0; row < (JDIMENSION)num_rows; row++) + { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + + yvup2rgb565_venum((UINT8*) inptr0, + (UINT8*) inptr2, + (UINT8*) inptr1, + (UINT8*) outptr, + cinfo->output_width); + } +} +#else { my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; register int y, cb, cr; @@ -288,6 +373,7 @@ ycc_rgb_565_convert (j_decompress_ptr cinfo, } } } +#endif /* ANDROID_JPEG_USE_VENUM */ METHODDEF(void) ycc_rgb_565D_convert (j_decompress_ptr cinfo, @@ -803,7 +889,9 @@ jinit_color_deconverter (j_decompress_ptr cinfo) cinfo->out_color_components = RGB_PIXELSIZE; if (cinfo->jpeg_color_space == JCS_YCbCr) { cconvert->pub.color_convert = ycc_rgb_convert; +#ifndef ANDROID_JPEG_USE_VENUM build_ycc_rgb_table(cinfo); +#endif } else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) { cconvert->pub.color_convert = gray_rgb_convert; } else if (cinfo->jpeg_color_space == JCS_RGB && RGB_PIXELSIZE == 3) { @@ -831,7 +919,9 @@ jinit_color_deconverter (j_decompress_ptr cinfo) if (cinfo->dither_mode == JDITHER_NONE) { if (cinfo->jpeg_color_space == JCS_YCbCr) { cconvert->pub.color_convert = ycc_rgb_565_convert; +#if !defined(ANDROID_JPEG_USE_VENUM) build_ycc_rgb_table(cinfo); +#endif /* ANDROID_JPEG_USE_VENUM */ } else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) { cconvert->pub.color_convert = gray_rgb_565_convert; } else if (cinfo->jpeg_color_space == JCS_RGB) { @@ -841,8 +931,13 @@ jinit_color_deconverter (j_decompress_ptr cinfo) } else { /* only ordered dither is supported */ if (cinfo->jpeg_color_space == JCS_YCbCr) { +#if defined(ANDROID_JPEG_USE_VENUM) + /* Use VeNum routine even if dithering option is selected. */ + cconvert->pub.color_convert = ycc_rgb_565_convert; +#else cconvert->pub.color_convert = ycc_rgb_565D_convert; build_ycc_rgb_table(cinfo); +#endif /* ANDROID_JPEG_USE_VENUM */ } else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) { cconvert->pub.color_convert = gray_rgb_565D_convert; } else if (cinfo->jpeg_color_space == JCS_RGB) { diff --git a/src/jni/jpeg/jddctmgr.c b/src/jni/jpeg/jddctmgr.c index bbf8d0e92f..674bfa75fb 100644 --- a/src/jni/jpeg/jddctmgr.c +++ b/src/jni/jpeg/jddctmgr.c @@ -2,6 +2,7 @@ * jddctmgr.c * * Copyright (C) 1994-1996, Thomas G. Lane. + * Copyright (c) 2010, Code Aurora Forum. All rights reserved. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -20,6 +21,35 @@ #include "jpeglib.h" #include "jdct.h" /* Private declarations for DCT subsystem */ +#ifdef ANDROID_ARMV6_IDCT + #undef ANDROID_ARMV6_IDCT + #ifdef __arm__ + #include + #if __ARM_ARCH__ >= 6 + #define ANDROID_ARMV6_IDCT + #else + #warning "ANDROID_ARMV6_IDCT is disabled" + #endif + #endif +#endif + +#ifdef ANDROID_ARMV6_IDCT + +/* Intentionally declare the prototype with arguments of primitive types instead + * of type-defined ones. This will at least generate some warnings if jmorecfg.h + * is changed and becomes incompatible with the assembly code. + */ +extern void armv6_idct(short *coefs, int *quans, unsigned char **rows, int col); + +void jpeg_idct_armv6 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + IFAST_MULT_TYPE *dct_table = (IFAST_MULT_TYPE *)compptr->dct_table; + armv6_idct(coef_block, dct_table, output_buf, output_col); +} + +#endif /* * The decompressor input side (jdinput.c) saves away the appropriate @@ -115,6 +145,13 @@ start_pass (j_decompress_ptr cinfo) #endif case DCTSIZE: switch (cinfo->dct_method) { +#ifdef ANDROID_ARMV6_IDCT + case JDCT_ISLOW: + case JDCT_IFAST: + method_ptr = jpeg_idct_armv6; + method = JDCT_IFAST; + break; +#else /* ANDROID_ARMV6_IDCT */ #ifdef DCT_ISLOW_SUPPORTED case JDCT_ISLOW: method_ptr = jpeg_idct_islow; @@ -123,10 +160,17 @@ start_pass (j_decompress_ptr cinfo) #endif #ifdef DCT_IFAST_SUPPORTED case JDCT_IFAST: +#ifdef ANDROID_JPEG_USE_VENUM + /* Use VeNum implementation of jpeg_idct_islow even if fast DCT option is selected */ + method_ptr = jpeg_idct_islow; + method = JDCT_ISLOW; +#else method_ptr = jpeg_idct_ifast; method = JDCT_IFAST; +#endif /* ANDROID_JPEG_USE_VENUM */ break; #endif +#endif /* ANDROID_ARMV6_IDCT */ #ifdef DCT_FLOAT_SUPPORTED case JDCT_FLOAT: method_ptr = jpeg_idct_float; @@ -181,6 +225,27 @@ start_pass (j_decompress_ptr cinfo) * IFAST_SCALE_BITS. */ IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table; +#ifdef ANDROID_ARMV6_IDCT + /* Precomputed values scaled up by 15 bits. */ + static const unsigned short scales[DCTSIZE2] = { + 32768, 45451, 42813, 38531, 32768, 25746, 17734, 9041, + 45451, 63042, 59384, 53444, 45451, 35710, 24598, 12540, + 42813, 59384, 55938, 50343, 42813, 33638, 23170, 11812, + 38531, 53444, 50343, 45308, 38531, 30274, 20853, 10631, + 32768, 45451, 42813, 38531, 32768, 25746, 17734, 9041, + 25746, 35710, 33638, 30274, 25746, 20228, 13933, 7103, + 17734, 24598, 23170, 20853, 17734, 13933, 9598, 4893, + 9041, 12540, 11812, 10631, 9041, 7103, 4893, 2494, + }; + /* Inverse map of [7, 5, 1, 3, 0, 2, 4, 6]. */ + static const char orders[DCTSIZE] = {4, 2, 5, 3, 6, 1, 7, 0}; + /* Reorder the columns after transposing. */ + for (i = 0; i < DCTSIZE2; ++i) { + int j = ((i & 7) << 3) + orders[i >> 3]; + ifmtbl[j] = (qtbl->quantval[i] * scales[i] + 2) >> 2; + } +#else /* ANDROID_ARMV6_IDCT */ + #define CONST_BITS 14 static const INT16 aanscales[DCTSIZE2] = { /* precomputed values scaled up by 14 bits */ @@ -201,6 +266,7 @@ start_pass (j_decompress_ptr cinfo) (INT32) aanscales[i]), CONST_BITS-IFAST_SCALE_BITS); } +#endif /* ANDROID_ARMV6_IDCT */ } break; #endif diff --git a/src/jni/jpeg/jdhuff.c b/src/jni/jpeg/jdhuff.c index b5ba39f736..bc5d4fdd27 100644 --- a/src/jni/jpeg/jdhuff.c +++ b/src/jni/jpeg/jdhuff.c @@ -19,6 +19,8 @@ #include "jpeglib.h" #include "jdhuff.h" /* Declarations shared with jdphuff.c */ +LOCAL(boolean) process_restart (j_decompress_ptr cinfo); + /* * Expanded entropy decoder object for Huffman decoding. @@ -77,7 +79,6 @@ typedef struct { typedef huff_entropy_decoder * huff_entropy_ptr; - /* * Initialize for a Huffman-compressed scan. */ @@ -497,6 +498,91 @@ process_restart (j_decompress_ptr cinfo) return TRUE; } +/* + * Save the current Huffman deocde position and the DC coefficients + * for each component into bitstream_offset and dc_info[], respectively. + */ +METHODDEF(void) +get_huffman_decoder_configuration(j_decompress_ptr cinfo, + huffman_offset_data *offset) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + short int *dc_info = offset->prev_dc; + int i; + jpeg_get_huffman_decoder_configuration(cinfo, offset); + for (i = 0; i < cinfo->comps_in_scan; i++) { + dc_info[i] = entropy->saved.last_dc_val[i]; + } +} + +/* + * Save the current Huffman decoder position and the bit buffer + * into bitstream_offset and get_buffer, respectively. + */ +GLOBAL(void) +jpeg_get_huffman_decoder_configuration(j_decompress_ptr cinfo, + huffman_offset_data *offset) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + + if (cinfo->restart_interval) { + // We are at the end of a data segment + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return; + } + + // Save restarts_to_go and next_restart_num + offset->restarts_to_go = (unsigned short) entropy->restarts_to_go; + offset->next_restart_num = cinfo->marker->next_restart_num; + + offset->bitstream_offset = + (jget_input_stream_position(cinfo) << LOG_TWO_BIT_BUF_SIZE) + + entropy->bitstate.bits_left; + + offset->get_buffer = entropy->bitstate.get_buffer; +} + +/* + * Configure the Huffman decoder to decode the image + * starting from the bitstream position recorded in offset. + */ +METHODDEF(void) +configure_huffman_decoder(j_decompress_ptr cinfo, huffman_offset_data offset) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + short int *dc_info = offset.prev_dc; + int i; + jpeg_configure_huffman_decoder(cinfo, offset); + for (i = 0; i < cinfo->comps_in_scan; i++) { + entropy->saved.last_dc_val[i] = dc_info[i]; + } +} + +/* + * Configure the Huffman decoder reader position and bit buffer. + */ +GLOBAL(void) +jpeg_configure_huffman_decoder(j_decompress_ptr cinfo, + huffman_offset_data offset) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + + // Restore restarts_to_go and next_restart_num + cinfo->unread_marker = 0; + entropy->restarts_to_go = offset.restarts_to_go; + cinfo->marker->next_restart_num = offset.next_restart_num; + + unsigned int bitstream_offset = offset.bitstream_offset; + int blkn, i; + + unsigned int byte_offset = bitstream_offset >> LOG_TWO_BIT_BUF_SIZE; + unsigned int bit_in_bit_buffer = + bitstream_offset & ((1 << LOG_TWO_BIT_BUF_SIZE) - 1); + + jset_input_stream_position_bit(cinfo, byte_offset, + bit_in_bit_buffer, offset.get_buffer); +} /* * Decode and return one MCU's worth of Huffman-compressed coefficients. @@ -532,7 +618,6 @@ decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) * This way, we return uniform gray for the remainder of the segment. */ if (! entropy->pub.insufficient_data) { - /* Load up working state */ BITREAD_LOAD_STATE(cinfo,entropy->bitstate); ASSIGN_STATE(state, entropy->saved); @@ -626,6 +711,87 @@ decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) return TRUE; } +/* + * Decode one MCU's worth of Huffman-compressed coefficients. + * The propose of this method is to calculate the + * data length of one MCU in Huffman-coded format. + * Therefore, all coefficients are discarded. + */ + +METHODDEF(boolean) +decode_mcu_discard_coef (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int blkn; + BITREAD_STATE_VARS; + savable_state state; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + if (! entropy->pub.insufficient_data) { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn]; + d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn]; + register int s, k, r; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + HUFF_DECODE(s, br_state, dctbl, return FALSE, label1); + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + + /* discard all coefficients */ + if (entropy->dc_needed[blkn]) { + /* Convert DC difference to actual value, update last_dc_val */ + int ci = cinfo->MCU_membership[blkn]; + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + } + for (k = 1; k < DCTSIZE2; k++) { + HUFF_DECODE(s, br_state, actbl, return FALSE, label3); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + DROP_BITS(s); + } else { + if (r != 15) + break; + k += 15; + } + } + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + /* * Module initialization routine for Huffman entropy decoding. @@ -643,9 +809,86 @@ jinit_huff_decoder (j_decompress_ptr cinfo) cinfo->entropy = (struct jpeg_entropy_decoder *) entropy; entropy->pub.start_pass = start_pass_huff_decoder; entropy->pub.decode_mcu = decode_mcu; + entropy->pub.decode_mcu_discard_coef = decode_mcu_discard_coef; + entropy->pub.configure_huffman_decoder = configure_huffman_decoder; + entropy->pub.get_huffman_decoder_configuration = + get_huffman_decoder_configuration; + entropy->pub.index = NULL; /* Mark tables unallocated */ for (i = 0; i < NUM_HUFF_TBLS; i++) { entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; } } + +/* + * Call after jpeg_read_header + */ +GLOBAL(void) +jpeg_create_huffman_index(j_decompress_ptr cinfo, huffman_index *index) +{ + int i, s; + index->scan_count = 1; + index->total_iMCU_rows = cinfo->total_iMCU_rows; + index->scan = (huffman_scan_header*)malloc(index->scan_count + * sizeof(huffman_scan_header)); + index->scan[0].offset = (huffman_offset_data**)malloc(cinfo->total_iMCU_rows + * sizeof(huffman_offset_data*)); + index->scan[0].prev_MCU_offset.bitstream_offset = 0; + index->MCU_sample_size = DEFAULT_MCU_SAMPLE_SIZE; + + index->mem_used = sizeof(huffman_scan_header) + + cinfo->total_iMCU_rows * sizeof(huffman_offset_data*); +} + +GLOBAL(void) +jpeg_destroy_huffman_index(huffman_index *index) +{ + int i, j; + for (i = 0; i < index->scan_count; i++) { + for(j = 0; j < index->total_iMCU_rows; j++) { + free(index->scan[i].offset[j]); + } + free(index->scan[i].offset); + } + free(index->scan); +} + +/* + * Set the reader byte position to offset + */ +GLOBAL(void) +jset_input_stream_position(j_decompress_ptr cinfo, int offset) +{ + if (cinfo->src->seek_input_data) { + cinfo->src->seek_input_data(cinfo, offset); + } else { + cinfo->src->bytes_in_buffer = cinfo->src->current_offset - offset; + cinfo->src->next_input_byte = cinfo->src->start_input_byte + offset; + } +} + +/* + * Set the reader byte position to offset and bit position to bit_left + * with bit buffer set to buf. + */ +GLOBAL(void) +jset_input_stream_position_bit(j_decompress_ptr cinfo, + int byte_offset, int bit_left, INT32 buf) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + + entropy->bitstate.bits_left = bit_left; + entropy->bitstate.get_buffer = buf; + + jset_input_stream_position(cinfo, byte_offset); +} + +/* + * Get the current reader byte position. + */ +GLOBAL(int) +jget_input_stream_position(j_decompress_ptr cinfo) +{ + return cinfo->src->current_offset - cinfo->src->bytes_in_buffer; +} diff --git a/src/jni/jpeg/jdhuff.h b/src/jni/jpeg/jdhuff.h index ae19b6cafd..5760a134e5 100644 --- a/src/jni/jpeg/jdhuff.h +++ b/src/jni/jpeg/jdhuff.h @@ -71,6 +71,7 @@ EXTERN(void) jpeg_make_d_derived_tbl typedef INT32 bit_buf_type; /* type of bit-extraction buffer */ #define BIT_BUF_SIZE 32 /* size of buffer in bits */ +#define LOG_TWO_BIT_BUF_SIZE 5 /* log_2(BIT_BUF_SIZE) */ /* If long is > 32 bits on your machine, and shifting/masking longs is * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE diff --git a/src/jni/jpeg/jdinput.c b/src/jni/jpeg/jdinput.c index 0c2ac8f120..4261c1a1c4 100644 --- a/src/jni/jpeg/jdinput.c +++ b/src/jni/jpeg/jdinput.c @@ -29,6 +29,8 @@ typedef my_input_controller * my_inputctl_ptr; /* Forward declarations */ METHODDEF(int) consume_markers JPP((j_decompress_ptr cinfo)); +METHODDEF(int) consume_markers_with_huffman_index JPP((j_decompress_ptr cinfo, + huffman_index *index, int current_scan)); /* @@ -114,9 +116,9 @@ initial_setup (j_decompress_ptr cinfo) cinfo->inputctl->has_multiple_scans = TRUE; else cinfo->inputctl->has_multiple_scans = FALSE; + cinfo->original_image_width = cinfo->image_width; } - LOCAL(void) per_scan_setup (j_decompress_ptr cinfo) /* Do computations that are needed before processing a JPEG scan */ @@ -179,6 +181,15 @@ per_scan_setup (j_decompress_ptr cinfo) tmp = (int) (compptr->width_in_blocks % compptr->MCU_width); if (tmp == 0) tmp = compptr->MCU_width; compptr->last_col_width = tmp; +#ifdef ANDROID_TILE_BASED_DECODE + if (cinfo->tile_decode) { + tmp = (int) (jdiv_round_up(cinfo->image_width, 8) + % compptr->MCU_width); + if (tmp == 0) tmp = compptr->MCU_width; + compptr->last_col_width = tmp; + } +#endif + tmp = (int) (compptr->height_in_blocks % compptr->MCU_height); if (tmp == 0) tmp = compptr->MCU_height; compptr->last_row_height = tmp; @@ -194,6 +205,13 @@ per_scan_setup (j_decompress_ptr cinfo) } } +GLOBAL(void) +jpeg_decompress_per_scan_setup(j_decompress_ptr cinfo) +{ + per_scan_setup(cinfo); +} + + /* * Save away a copy of the Q-table referenced by each component present @@ -258,6 +276,8 @@ start_input_pass (j_decompress_ptr cinfo) (*cinfo->entropy->start_pass) (cinfo); (*cinfo->coef->start_input_pass) (cinfo); cinfo->inputctl->consume_input = cinfo->coef->consume_data; + cinfo->inputctl->consume_input_build_huffman_index = + cinfo->coef->consume_data_build_huffman_index; } @@ -271,9 +291,17 @@ METHODDEF(void) finish_input_pass (j_decompress_ptr cinfo) { cinfo->inputctl->consume_input = consume_markers; + cinfo->inputctl->consume_input_build_huffman_index = + consume_markers_with_huffman_index; } +METHODDEF(int) +consume_markers_with_huffman_index (j_decompress_ptr cinfo, + huffman_index *index, int current_scan) +{ + return consume_markers(cinfo); +} /* * Read JPEG markers before, between, or after compressed-data scans. * Change state as necessary when a new scan is reached. @@ -341,6 +369,8 @@ reset_input_controller (j_decompress_ptr cinfo) my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; inputctl->pub.consume_input = consume_markers; + inputctl->pub.consume_input_build_huffman_index = + consume_markers_with_huffman_index; inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ inputctl->pub.eoi_reached = FALSE; inputctl->inheaders = TRUE; @@ -372,6 +402,10 @@ jinit_input_controller (j_decompress_ptr cinfo) inputctl->pub.reset_input_controller = reset_input_controller; inputctl->pub.start_input_pass = start_input_pass; inputctl->pub.finish_input_pass = finish_input_pass; + + inputctl->pub.consume_markers = consume_markers_with_huffman_index; + inputctl->pub.consume_input_build_huffman_index = + consume_markers_with_huffman_index; /* Initialize state: can't use reset_input_controller since we don't * want to try to reset other modules yet. */ diff --git a/src/jni/jpeg/jdmarker.c b/src/jni/jpeg/jdmarker.c index f4cca8cc83..7332940505 100644 --- a/src/jni/jpeg/jdmarker.c +++ b/src/jni/jpeg/jdmarker.c @@ -964,6 +964,14 @@ read_markers (j_decompress_ptr cinfo) return JPEG_SUSPENDED; } } + + /* + * Save the position of the fist marker after SOF. + */ + if (cinfo->marker->current_sos_marker_position == -1) + cinfo->marker->current_sos_marker_position = + jget_input_stream_position(cinfo) - 2; + /* At this point cinfo->unread_marker contains the marker code and the * input point is just past the marker proper, but before any parameters. * A suspension will cause us to return with this state still true. @@ -981,6 +989,7 @@ read_markers (j_decompress_ptr cinfo) break; case M_SOF2: /* Progressive, Huffman */ + cinfo->marker->current_sos_marker_position = -1; if (! get_sof(cinfo, TRUE, FALSE)) return JPEG_SUSPENDED; break; @@ -1233,6 +1242,33 @@ jpeg_resync_to_restart (j_decompress_ptr cinfo, int desired) } /* end loop */ } +/* + * Get the position for all SOS markers in the image. + */ + +METHODDEF(void) +get_sos_marker_position(j_decompress_ptr cinfo, huffman_index *index) +{ + unsigned char *head; + int count = 0; + int retcode = JPEG_REACHED_SOS; + + while (cinfo->src->bytes_in_buffer > 0) { + if (retcode == JPEG_REACHED_SOS) { + jpeg_configure_huffman_index_scan(cinfo, index, count++, + cinfo->marker->current_sos_marker_position); + // Skips scan content to the next non-RST JPEG marker. + while(next_marker(cinfo) && + cinfo->unread_marker >= M_RST0 && cinfo->unread_marker <= M_RST7) + ; + cinfo->marker->current_sos_marker_position = + jget_input_stream_position(cinfo) - 2; + retcode = read_markers(cinfo); + } else { + break; + } + } +} /* * Reset marker processing state to begin a fresh datastream. @@ -1273,6 +1309,7 @@ jinit_marker_reader (j_decompress_ptr cinfo) marker->pub.reset_marker_reader = reset_marker_reader; marker->pub.read_markers = read_markers; marker->pub.read_restart_marker = read_restart_marker; + marker->pub.get_sos_marker_position = get_sos_marker_position; /* Initialize COM/APPn processing. * By default, we examine and then discard APP0 and APP14, * but simply discard COM and all other APPn. diff --git a/src/jni/jpeg/jdmaster.c b/src/jni/jpeg/jdmaster.c index 89250133a8..e3da758b15 100644 --- a/src/jni/jpeg/jdmaster.c +++ b/src/jni/jpeg/jdmaster.c @@ -103,8 +103,12 @@ jpeg_calc_output_dimensions (j_decompress_ptr cinfo) #endif /* Prevent application from calling me at wrong times */ - if (cinfo->global_state != DSTATE_READY) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); +#if ANDROID_TILE_BASED_DECODE + // Tile based decoding may call this function several times. + if (!cinfo->tile_decode) +#endif + if (cinfo->global_state != DSTATE_READY) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); #ifdef IDCT_SCALING_SUPPORTED diff --git a/src/jni/jpeg/jdmerge.c b/src/jni/jpeg/jdmerge.c index 77f33083af..171fbd3ab9 100644 --- a/src/jni/jpeg/jdmerge.c +++ b/src/jni/jpeg/jdmerge.c @@ -2,6 +2,7 @@ * jdmerge.c * * Copyright (C) 1994-1996, Thomas G. Lane. + * Copyright (c) 2010, Code Aurora Forum. All rights reserved. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -250,6 +251,35 @@ METHODDEF(void) h2v1_merged_upsample (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf) +#ifdef ANDROID_JPEG_USE_VENUM +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPROW inptr0, inptr1, inptr2; + JSAMPROW outptr; + + inptr0 = input_buf[0][in_row_group_ctr]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr = output_buf[0]; + +#ifdef ANDROID_RGB + if (cinfo->out_color_space == JCS_RGBA_8888) { + yyvup2abgr8888_venum((UINT8*) inptr0, + (UINT8*) inptr2, + (UINT8*) inptr1, + (UINT8*) outptr, + cinfo->output_width); + } else +#endif + { + yyvup2bgr888_venum((UINT8*) inptr0, + (UINT8*) inptr2, + (UINT8*) inptr1, + (UINT8*) outptr, + cinfo->output_width); + } +} +#else { my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; register int y, cred, cgreen, cblue; @@ -263,8 +293,15 @@ h2v1_merged_upsample (j_decompress_ptr cinfo, int * Cbbtab = upsample->Cb_b_tab; INT32 * Crgtab = upsample->Cr_g_tab; INT32 * Cbgtab = upsample->Cb_g_tab; + JDIMENSION pixelWidth = RGB_PIXELSIZE; SHIFT_TEMPS +#ifdef ANDROID_RGB + if ((cinfo->out_color_components == 4) && + (cinfo->out_color_space == JCS_RGBA_8888)) + pixelWidth = 4; // RGBA pixel size +#endif /* ANDROID_RGB */ + inptr0 = input_buf[0][in_row_group_ctr]; inptr1 = input_buf[1][in_row_group_ctr]; inptr2 = input_buf[2][in_row_group_ctr]; @@ -282,12 +319,12 @@ h2v1_merged_upsample (j_decompress_ptr cinfo, outptr[RGB_RED] = range_limit[y + cred]; outptr[RGB_GREEN] = range_limit[y + cgreen]; outptr[RGB_BLUE] = range_limit[y + cblue]; - outptr += RGB_PIXELSIZE; + outptr += pixelWidth; y = GETJSAMPLE(*inptr0++); outptr[RGB_RED] = range_limit[y + cred]; outptr[RGB_GREEN] = range_limit[y + cgreen]; outptr[RGB_BLUE] = range_limit[y + cblue]; - outptr += RGB_PIXELSIZE; + outptr += pixelWidth; } /* If image width is odd, do the last output column separately */ if (cinfo->output_width & 1) { @@ -302,6 +339,7 @@ h2v1_merged_upsample (j_decompress_ptr cinfo, outptr[RGB_BLUE] = range_limit[y + cblue]; } } +#endif /* ANDROID_JPEG_USE_VENUM */ #ifdef ANDROID_RGB @@ -309,6 +347,24 @@ METHODDEF(void) h2v1_merged_upsample_565 (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf) +#if defined(ANDROID_JPEG_USE_VENUM) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPROW inptr0, inptr1, inptr2; + JSAMPROW outptr; + + inptr0 = input_buf[0][in_row_group_ctr]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr = output_buf[0]; + + yyvup2rgb565_venum((UINT8*) inptr0, + (UINT8*) inptr2, + (UINT8*) inptr1, + (UINT8*) outptr, + cinfo->output_width); +} +#else { my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; register int y, cred, cgreen, cblue; @@ -367,6 +423,7 @@ h2v1_merged_upsample_565 (j_decompress_ptr cinfo, *(INT16*)outptr = rgb; } } +#endif /* ANDROID_JPEG_USE_VENUM */ METHODDEF(void) @@ -447,6 +504,46 @@ METHODDEF(void) h2v2_merged_upsample (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf) +#ifdef ANDROID_JPEG_USE_VENUM +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPROW outptr0, outptr1; + JSAMPROW inptr00, inptr01, inptr1, inptr2; + inptr00 = input_buf[0][in_row_group_ctr*2]; + inptr01 = input_buf[0][in_row_group_ctr*2 + 1]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr0 = output_buf[0]; + outptr1 = output_buf[1]; +#ifdef ANDROID_RGB + if (cinfo->out_color_space == JCS_RGBA_8888) { + yyvup2abgr8888_venum((UINT8*) inptr00, + (UINT8*) inptr2, + (UINT8*) inptr1, + (UINT8*) outptr0, + cinfo->output_width); + yyvup2abgr8888_venum((UINT8*) inptr01, + (UINT8*) inptr2, + (UINT8*) inptr1, + (UINT8*) outptr1, + cinfo->output_width); + } else +#endif + { + yyvup2bgr888_venum((UINT8*) inptr00, + (UINT8*) inptr2, + (UINT8*) inptr1, + (UINT8*) outptr0, + cinfo->output_width); + + yyvup2bgr888_venum((UINT8*) inptr01, + (UINT8*) inptr2, + (UINT8*) inptr1, + (UINT8*) outptr1, + cinfo->output_width); + } +} +#else { my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; register int y, cred, cgreen, cblue; @@ -460,8 +557,15 @@ h2v2_merged_upsample (j_decompress_ptr cinfo, int * Cbbtab = upsample->Cb_b_tab; INT32 * Crgtab = upsample->Cr_g_tab; INT32 * Cbgtab = upsample->Cb_g_tab; + JDIMENSION pixelWidth = RGB_PIXELSIZE; SHIFT_TEMPS +#ifdef ANDROID_RGB + if ((cinfo->out_color_components == 4) && + (cinfo->out_color_space == JCS_RGBA_8888)) + pixelWidth = 4; // RGBA pixel size +#endif /* ANDROID_RGB */ + inptr00 = input_buf[0][in_row_group_ctr*2]; inptr01 = input_buf[0][in_row_group_ctr*2 + 1]; inptr1 = input_buf[1][in_row_group_ctr]; @@ -481,22 +585,22 @@ h2v2_merged_upsample (j_decompress_ptr cinfo, outptr0[RGB_RED] = range_limit[y + cred]; outptr0[RGB_GREEN] = range_limit[y + cgreen]; outptr0[RGB_BLUE] = range_limit[y + cblue]; - outptr0 += RGB_PIXELSIZE; + outptr0 += pixelWidth; y = GETJSAMPLE(*inptr00++); outptr0[RGB_RED] = range_limit[y + cred]; outptr0[RGB_GREEN] = range_limit[y + cgreen]; outptr0[RGB_BLUE] = range_limit[y + cblue]; - outptr0 += RGB_PIXELSIZE; + outptr0 += pixelWidth; y = GETJSAMPLE(*inptr01++); outptr1[RGB_RED] = range_limit[y + cred]; outptr1[RGB_GREEN] = range_limit[y + cgreen]; outptr1[RGB_BLUE] = range_limit[y + cblue]; - outptr1 += RGB_PIXELSIZE; + outptr1 += pixelWidth; y = GETJSAMPLE(*inptr01++); outptr1[RGB_RED] = range_limit[y + cred]; outptr1[RGB_GREEN] = range_limit[y + cgreen]; outptr1[RGB_BLUE] = range_limit[y + cblue]; - outptr1 += RGB_PIXELSIZE; + outptr1 += pixelWidth; } /* If image width is odd, do the last output column separately */ if (cinfo->output_width & 1) { @@ -515,6 +619,7 @@ h2v2_merged_upsample (j_decompress_ptr cinfo, outptr1[RGB_BLUE] = range_limit[y + cblue]; } } +#endif /* ANDROID_JPEG_USE_VENUM */ #ifdef ANDROID_RGB @@ -523,6 +628,31 @@ METHODDEF(void) h2v2_merged_upsample_565 (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf) +#if defined(ANDROID_JPEG_USE_VENUM) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPROW outptr0, outptr1; + JSAMPROW inptr00, inptr01, inptr1, inptr2; + inptr00 = input_buf[0][in_row_group_ctr*2]; + inptr01 = input_buf[0][in_row_group_ctr*2 + 1]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr0 = output_buf[0]; + outptr1 = output_buf[1]; + + yyvup2rgb565_venum((UINT8*) inptr00, + (UINT8*) inptr2, + (UINT8*) inptr1, + (UINT8*) outptr0, + cinfo->output_width); + + yyvup2rgb565_venum((UINT8*) inptr01, + (UINT8*) inptr2, + (UINT8*) inptr1, + (UINT8*) outptr1, + cinfo->output_width); +} +#else { my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; register int y, cred, cgreen, cblue; @@ -601,7 +731,7 @@ h2v2_merged_upsample_565 (j_decompress_ptr cinfo, *(INT16*)outptr1 = rgb; } } - +#endif /* ANDROID_JPEG_USE_VENUM */ METHODDEF(void) @@ -724,11 +854,16 @@ jinit_merged_upsampler (j_decompress_ptr cinfo) upsample->upmethod = h2v2_merged_upsample; #ifdef ANDROID_RGB if (cinfo->out_color_space == JCS_RGB_565) { - if (cinfo->dither_mode == JDITHER_NONE) { - upsample->upmethod = h2v2_merged_upsample_565; - } else { - upsample->upmethod = h2v2_merged_upsample_565D; - } +#if !defined(ANDROID_JPEG_USE_VENUM) + if (cinfo->dither_mode != JDITHER_NONE) { + upsample->upmethod = h2v2_merged_upsample_565D; + } else +#endif + { + /* If VeNum routines are enabled, use h2v2_merged_upsample_565 + * function regardless of dither mode. */ + upsample->upmethod = h2v2_merged_upsample_565; + } } #endif /* Allocate a spare row buffer */ @@ -740,18 +875,28 @@ jinit_merged_upsampler (j_decompress_ptr cinfo) upsample->upmethod = h2v1_merged_upsample; #ifdef ANDROID_RGB if (cinfo->out_color_space == JCS_RGB_565) { - if (cinfo->dither_mode == JDITHER_NONE) { - upsample->upmethod = h2v1_merged_upsample_565; - } else { - upsample->upmethod = h2v1_merged_upsample_565D; - } +#ifndef ANDROID_JPEG_USE_VENUM + if (cinfo->dither_mode != JDITHER_NONE) { + upsample->upmethod = h2v1_merged_upsample_565D; + } else +#endif + { + /* If VeNum routines are enabled, use h2v1_merged_upsample_565 + * function regardless of dither mode. */ + upsample->upmethod = h2v1_merged_upsample_565; + } } #endif /* No spare row needed */ upsample->spare_row = NULL; } - build_ycc_rgb_table(cinfo); +#if !defined(ANDROID_JPEG_USE_VENUM) + build_ycc_rgb_table(cinfo); +#endif +#ifdef NEEDS_ARM_ERRATA_754319_754320 + asm volatile ( "vmov s0,s0\n" ); +#endif } #endif /* UPSAMPLE_MERGING_SUPPORTED */ diff --git a/src/jni/jpeg/jdphuff.c b/src/jni/jpeg/jdphuff.c index 2267809945..922017ef3f 100644 --- a/src/jni/jpeg/jdphuff.c +++ b/src/jni/jpeg/jdphuff.c @@ -83,7 +83,6 @@ METHODDEF(boolean) decode_mcu_DC_refine JPP((j_decompress_ptr cinfo, METHODDEF(boolean) decode_mcu_AC_refine JPP((j_decompress_ptr cinfo, JBLOCKROW *MCU_data)); - /* * Initialize for a Huffman-compressed scan. */ @@ -632,11 +631,113 @@ decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) return FALSE; } +/* + * Save the current Huffman deocde position and the DC coefficients + * for each component into bitstream_offset and dc_info[], respectively. + */ +METHODDEF(void) +get_huffman_decoder_configuration(j_decompress_ptr cinfo, + huffman_offset_data *offset) +{ + int i; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + jpeg_get_huffman_decoder_configuration_progressive(cinfo, offset); + offset->EOBRUN = entropy->saved.EOBRUN; + for (i = 0; i < cinfo->comps_in_scan; i++) + offset->prev_dc[i] = entropy->saved.last_dc_val[i]; +} + /* - * Module initialization routine for progressive Huffman entropy decoding. + * Save the current Huffman decoder position and the bit buffer + * into bitstream_offset and get_buffer, respectively. + */ +GLOBAL(void) +jpeg_get_huffman_decoder_configuration_progressive(j_decompress_ptr cinfo, + huffman_offset_data *offset) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + + if (cinfo->restart_interval) { + // We are at the end of a data segment + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return; + } + + // Save restarts_to_go and next_restart_num. + offset->restarts_to_go = (unsigned short) entropy->restarts_to_go; + offset->next_restart_num = cinfo->marker->next_restart_num; + + offset->bitstream_offset = + (jget_input_stream_position(cinfo) << LOG_TWO_BIT_BUF_SIZE) + + entropy->bitstate.bits_left; + + offset->get_buffer = entropy->bitstate.get_buffer; +} + + +/* + * Configure the Huffman decoder to decode the image + * starting from (iMCU_row_offset, iMCU_col_offset). + */ +METHODDEF(void) +configure_huffman_decoder(j_decompress_ptr cinfo, huffman_offset_data offset) +{ + int i; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + jpeg_configure_huffman_decoder_progressive(cinfo, offset); + entropy->saved.EOBRUN = offset.EOBRUN; + for (i = 0; i < cinfo->comps_in_scan; i++) + entropy->saved.last_dc_val[i] = offset.prev_dc[i]; +} + +/* + * Configure the Huffman decoder reader position and bit buffer. */ +GLOBAL(void) +jpeg_configure_huffman_decoder_progressive(j_decompress_ptr cinfo, + huffman_offset_data offset) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + + // Restore restarts_to_go and next_restart_num + cinfo->unread_marker = 0; + entropy->restarts_to_go = offset.restarts_to_go; + cinfo->marker->next_restart_num = offset.next_restart_num; + + unsigned int bitstream_offset = offset.bitstream_offset; + int blkn, i; + unsigned int byte_offset = bitstream_offset >> LOG_TWO_BIT_BUF_SIZE; + unsigned int bit_in_bit_buffer = + bitstream_offset & ((1 << LOG_TWO_BIT_BUF_SIZE) - 1); + + jset_input_stream_position_bit(cinfo, byte_offset, + bit_in_bit_buffer, offset.get_buffer); +} + +GLOBAL(void) +jpeg_configure_huffman_index_scan(j_decompress_ptr cinfo, + huffman_index *index, int scan_no, int offset) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + if (scan_no >= index->scan_count) { + index->scan = realloc(index->scan, + (scan_no + 1) * sizeof(huffman_scan_header)); + index->mem_used += (scan_no - index->scan_count + 1) + * (sizeof(huffman_scan_header) + cinfo->total_iMCU_rows + * sizeof(huffman_offset_data*)); + index->scan_count = scan_no + 1; + } + index->scan[scan_no].offset = (huffman_offset_data**)malloc( + cinfo->total_iMCU_rows * sizeof(huffman_offset_data*)); + index->scan[scan_no].bitstream_offset = offset; +} + +/* + * Module initialization routine for progressive Huffman entropy decoding. + */ GLOBAL(void) jinit_phuff_decoder (j_decompress_ptr cinfo) { @@ -649,6 +750,9 @@ jinit_phuff_decoder (j_decompress_ptr cinfo) SIZEOF(phuff_entropy_decoder)); cinfo->entropy = (struct jpeg_entropy_decoder *) entropy; entropy->pub.start_pass = start_pass_phuff_decoder; + entropy->pub.configure_huffman_decoder = configure_huffman_decoder; + entropy->pub.get_huffman_decoder_configuration = + get_huffman_decoder_configuration; /* Mark derived tables unallocated */ for (i = 0; i < NUM_HUFF_TBLS; i++) { diff --git a/src/jni/jpeg/jdtrans.c b/src/jni/jpeg/jdtrans.c index 6c0ab715d3..586909cb6e 100644 --- a/src/jni/jpeg/jdtrans.c +++ b/src/jni/jpeg/jdtrans.c @@ -55,20 +55,20 @@ jpeg_read_coefficients (j_decompress_ptr cinfo) int retcode; /* Call progress monitor hook if present */ if (cinfo->progress != NULL) - (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); /* Absorb some more input */ retcode = (*cinfo->inputctl->consume_input) (cinfo); if (retcode == JPEG_SUSPENDED) - return NULL; + return NULL; if (retcode == JPEG_REACHED_EOI) - break; + break; /* Advance progress counter if appropriate */ if (cinfo->progress != NULL && (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { - if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { /* startup underestimated number of scans; ratchet up one scan */ - cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; - } + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } } } /* Set state so that jpeg_finish_decompress does the right thing */ @@ -87,6 +87,132 @@ jpeg_read_coefficients (j_decompress_ptr cinfo) return NULL; /* keep compiler happy */ } +LOCAL(boolean) +jpeg_build_huffman_index_progressive(j_decompress_ptr cinfo, + huffman_index *index) +{ + if (cinfo->global_state == DSTATE_READY) { + printf("Progressive Mode\n"); + /* First call: initialize active modules */ + transdecode_master_selection(cinfo); + cinfo->global_state = DSTATE_RDCOEFS; + } + if (cinfo->global_state == DSTATE_RDCOEFS) { + int mcu, i; + cinfo->marker->get_sos_marker_position(cinfo, index); + + /* Absorb whole file into the coef buffer */ + for (mcu = 0; mcu < cinfo->total_iMCU_rows; mcu++) { + int retcode = 0; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + /* Absorb some more input */ + jinit_phuff_decoder(cinfo); + for (i = 0; i < index->scan_count; i++) { + (*cinfo->inputctl->finish_input_pass) (cinfo); + jset_input_stream_position(cinfo, index->scan[i].bitstream_offset); + cinfo->unread_marker = 0; + retcode = (*cinfo->inputctl->consume_input_build_huffman_index) + (cinfo, index, i); + if (retcode == JPEG_REACHED_EOI) + break; + cinfo->input_iMCU_row = mcu; + if (mcu != 0) + (*cinfo->entropy->configure_huffman_decoder) + (cinfo, index->scan[i].prev_MCU_offset); + cinfo->input_scan_number = i; + retcode = (*cinfo->inputctl->consume_input_build_huffman_index) + (cinfo, index, i); + } + if (retcode == JPEG_SUSPENDED) + return FALSE; + if (retcode == JPEG_REACHED_EOI) + break; + /* Advance progress counter if appropriate */ + if (cinfo->progress != NULL && + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + /* startup underestimated number of scans; ratchet up one scan */ + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } + } + } + cinfo->global_state = DSTATE_STOPPING; + } + /* At this point we should be in state DSTATE_STOPPING if being used + * standalone, or in state DSTATE_BUFIMAGE if being invoked to get access + * to the coefficients during a full buffered-image-mode decompression. + */ + if ((cinfo->global_state == DSTATE_STOPPING || + cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) { + return TRUE; + } + /* Oops, improper usage */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return FALSE; /* keep compiler happy */ +} + +LOCAL(boolean) +jpeg_build_huffman_index_baseline(j_decompress_ptr cinfo, huffman_index *index) +{ + if (cinfo->global_state == DSTATE_READY) { + printf("Baseline Mode\n"); + /* First call: initialize active modules */ + transdecode_master_selection(cinfo); + cinfo->global_state = DSTATE_RDCOEFS; + } + if (cinfo->global_state == DSTATE_RDCOEFS) { + /* Absorb whole file into the coef buffer */ + for (;;) { + int retcode; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + /* Absorb some more input */ + retcode = (*cinfo->inputctl->consume_input_build_huffman_index) + (cinfo, index, 0); + if (retcode == JPEG_SUSPENDED) + return FALSE; + if (retcode == JPEG_REACHED_EOI) + break; + if (retcode == JPEG_SCAN_COMPLETED) + break; + + /* Advance progress counter if appropriate */ + if (cinfo->progress != NULL && + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + /* startup underestimated number of scans; ratchet up one scan */ + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } + } + } + /* Set state so that jpeg_finish_decompress does the right thing */ + cinfo->global_state = DSTATE_STOPPING; + } + /* At this point we should be in state DSTATE_STOPPING if being used + * standalone, or in state DSTATE_BUFIMAGE if being invoked to get access + * to the coefficients during a full buffered-image-mode decompression. + */ + if ((cinfo->global_state == DSTATE_STOPPING || + cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) { + return TRUE; + } + /* Oops, improper usage */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return FALSE; /* keep compiler happy */ +} + +GLOBAL(boolean) +jpeg_build_huffman_index(j_decompress_ptr cinfo, huffman_index *index) +{ + cinfo->tile_decode = TRUE; + if (cinfo->progressive_mode) + return jpeg_build_huffman_index_progressive(cinfo, index); + else + return jpeg_build_huffman_index_baseline(cinfo, index); +} /* * Master selection of decompression modules for transcoding. @@ -109,8 +235,9 @@ transdecode_master_selection (j_decompress_ptr cinfo) #else ERREXIT(cinfo, JERR_NOT_COMPILED); #endif - } else + } else { jinit_huff_decoder(cinfo); + } } /* Always get a full-image coefficient buffer. */ diff --git a/src/jni/jpeg/jidctfst.S b/src/jni/jpeg/jidctfst.S deleted file mode 100644 index b35f938a53..0000000000 --- a/src/jni/jpeg/jidctfst.S +++ /dev/null @@ -1,476 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - - .text - .align - - .global jpeg_idct_ifast - .func jpeg_idct_ifast - -// NOTE: sb=r9, fp=r11 ip=r12, sp=r13, lr=r14, pc=r15 - -// jpeg_idct_ifast (j_decompress_ptr cinfo, -// jpeg_component_info * compptr, -// short* coef_block, -// unsigned char* output_buf, -// int output_col) - -#define local_TMP0123 sp -#define local_TMP0 [sp, #0] -#define local_TMP1 [sp, #4] -#define local_TMP2 [sp, #8] -#define local_TMP3 [sp, #12] -#define local_RANGE_TABLE [sp, #16] -#define local_OUTPUT_COL [sp, #20] -#define local_OUTPUT_BUF [sp, #24] -#define local_UNUSED [sp, #28] -#define off_WORKSPACE 32 -#define local_WORKSPACE [sp, #offWORKSPACE] -#define local_SIZE (off_WORKSPACE + 8*8*4) - -#define off_DECOMPRESS_range_limit_base 324 -#define off_COMPINFO_quanttable 80 - -#define DCTSIZE 8 -#define VY(x) ((x)*DCTSIZE*2) -#define QY(x) ((x)*DCTSIZE*4) - -#define VX(x) ((x)*2) -#define QX(x) ((x)*4) - -#define FIX_1_414213562 #362 -#define FIX_1_082392200 #277 -#define FIX_1_847759065 #473 -#define FIX_2_613125930 #669 - -#define RANGE_MASK 1023 - - - -jpeg_idct_ifast: - PLD [r2, #0] - stmdb sp!, {r4,r5, r6,r7, r8,r9, r10,r11, r12,lr} - ldr r4, [sp, #4*10] - sub sp, #local_SIZE - - ldr r10,[r1, #off_COMPINFO_quanttable] // r10 = quanttable - str r4, local_OUTPUT_COL - str r3, local_OUTPUT_BUF - ldr r5, [r0, #off_DECOMPRESS_range_limit_base] - add r5, r5, #128 - str r5, local_RANGE_TABLE - mov fp, r2 // fp = coef_block - add ip, sp, #off_WORKSPACE - -VLoopTail: - ldrsh r0, [fp, #VY(0)] - ldrsh r1, [fp, #VY(1)] - ldrsh r2, [fp, #VY(2)] - ldrsh r3, [fp, #VY(3)] - ldrsh r4, [fp, #VY(4)] - ldrsh r5, [fp, #VY(5)] - ldrsh r6, [fp, #VY(6)] - ldrsh r7, [fp, #VY(7)] - - cmp r1, #0 - orreqs r8, r2, r3 - orreqs r8, r4, r5 - orreqs r8, r6, r7 - beq VLoopHeadZero - -VLoopHead: - // tmp0 = DEQUANTIZE(in[DCTSIZE*0], quant[DCTSIZE*0] (r0) - // tmp2 = DEQUANTIZE(in[DCTSIZE*4], quant[DCTSIZE*4] (r4) - // tmp1 = DEQUANTIZE(in[DCTSIZE*2], quant[DCTSIZE*2] (r2) - // tmp3 = DEQUANTIZE(in[DCTSIZE*6], quant[DCTSIZE*6] (r6) - // tmp10 = tmp0 + tmp2 (r0) - // tmp11 = tmp0 - tmp2 (r4) - - ldr r9, [r10, #QY(4)] - ldr r8, [r10, #QY(0)] -#if __ARM_HAVE_HALFWORD_MULTIPLY - smulbb r4, r9, r4 - smlabb r0, r8, r0, r4 -#else - mul r4, r9, r4 - mul r0, r8, r0 - add r0, r4 -#endif - ldr r9, [r10, #QY(6)] - ldr r8, [r10, #QY(2)] - sub r4, r0, r4, lsl #1 -#if __ARM_HAVE_HALFWORD_MULTIPLY - smulbb r6, r9, r6 - smlabb r2, r8, r2, r6 -#else - mul r6, r9, r6 - mul r2, r8, r2 - add r2, r6 -#endif - - // tmp13 = tmp1 + tmp3 (r2) - // tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13 (r6) - // FIX_1_4142... = 362 = 45*8 + 2 - sub r6, r2, r6, lsl #1 - mov r8, #360 - add r8, r8, #2 - mul r9, r6, r8 - - // tmp0 = tmp10 + tmp13; (r0) - // tmp3 = tmp10 - tmp13; (r8) - // tmp1 = tmp11 + tmp12; (r4) - // tmp2 = tmp11 - tmp12; (r6) - add r0, r0, r2 - rsb r6, r2, r9, asr #8 - sub r8, r0, r2, lsl #1 - add r4, r4, r6 - sub r6, r4, r6, lsl #1 - - stmia local_TMP0123, {r0, r4, r6, r8} - - // NOTE: be sure to not user r0,r4,r6,r8 soon after stm above - - // odd part - // tmp4 = DEQUANTIZE( in[DCTSIZE*1], quant[DCTSIZE*1] ) (r1) - // tmp6 = DEQUANTIZE( in[DCTSIZE*5], quant[DCTSIZE*5] ) (r5) - // tmp5 = DEQUANTIZE( in[DCTSIZE*3], quant[DCTSIZE*3] ) (r3) - // tmp7 = DEQUANTIZE( in[DCTSIZE*7], quant[DCTSIZE*7] ) (r7) - // z13 = tmp6 + tmp5; (r0) - // z10 = tmp6 - tmp5; (r2) - // z11 = tmp4 + tmp7; (r4) - // z12 = tmp4 - tmp7; (r6) - - ldr r2, [r10, #QY(1)] - ldr r9, [r10, #QY(5)] -#if __ARM_HAVE_HALFWORD_MULTIPLY - smulbb r1, r2, r1 -#else - mul r1, r2, r1 -#endif - ldr r2, [r10, #QY(3)] -#if __ARM_HAVE_HALFWORD_MULTIPLY - smulbb r5, r9, r5 -#else - mul r5, r9, r5 -#endif - ldr r9, [r10, #QY(7)] -#if __ARM_HAVE_HALFWORD_MULTIPLY - smlabb r0, r2, r3, r5 - smlabb r4, r9, r7, r1 -#else - mul r0, r2, r3 - add r0, r5 - mul r4, r9, r7 - add r4, r1 -#endif - rsb r2, r0, r5, lsl #1 - rsb r6, r4, r1, lsl #1 - - // tmp7 = z11 + z13; (r7) - // tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); (r1) - // FIX_... = 360 + 2 - add r7, r4, r0 - sub r1, r4, r0 - mov r8, #360 - add r8, r8, #2 - mul r1, r8, r1 - - // z5 = MULTIPLY(z10 + z12, FIX_1_847759065); (r8) - // tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; (r0) - // tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; (r2) - // FIX_1_8477... = 473 = 472 + 1 - // FIX_1_082... = 277 = 276 + 1 - // FIX_2_... = 669 = 668 + 1 - add r8, r2, r6 - mov r9, #472 - mla r8, r9, r8, r8 - mov r9, #276 - mla r0, r6, r9, r6 - mov r9, #668 - mla r2, r9, r2, r2 - sub r0, r0, r8 - rsb r2, r2, r8 - - // tmp6 = tmp12 - tmp7; (r6) - // tmp5 = tmp11 - tmp6; (r5) - // tmp4 = tmp10 + tmp5; (r4) - rsb r6, r7, r2, asr #8 - rsb r5, r6, r1, asr #8 - add r4, r5, r0, asr #8 - - ldmia local_TMP0123, {r0, r1, r2, r3} - - // wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7); - // wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7); - // wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6); - // wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6); - // wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5); - // wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5); - // wsptr[DCTSIZE*4] = (int) (tmp3 + tmp4); - // wsptr[DCTSIZE*3] = (int) (tmp3 - tmp4); - - add r0, r0, r7 - sub r7, r0, r7, lsl #1 - add r1, r1, r6 - sub r6, r1, r6, lsl #1 - add r2, r2, r5 - sub r5, r2, r5, lsl #1 - sub r3, r3, r4 - add r4, r3, r4, lsl #1 - - str r0, [ip, #QY(0)] - str r1, [ip, #QY(1)] - str r2, [ip, #QY(2)] - str r3, [ip, #QY(3)] - str r4, [ip, #QY(4)] - str r5, [ip, #QY(5)] - str r6, [ip, #QY(6)] - str r7, [ip, #QY(7)] - - // inptr++; /* advance pointers to next column */ - // quantptr++; - // wsptr++; - add fp, fp, #2 - add r10, r10, #4 - add ip, ip, #4 - add r0, sp, #(off_WORKSPACE + 4*8) - cmp ip, r0 - bne VLoopTail - - - -HLoopStart: - // reset pointers - PLD [sp, #off_WORKSPACE] - add ip, sp, #off_WORKSPACE - ldr r10, local_RANGE_TABLE - -HLoopTail: - // output = *output_buf++ + output_col - ldr r0, local_OUTPUT_BUF - ldr r1, local_OUTPUT_COL - ldr r2, [r0], #4 - str r0, local_OUTPUT_BUF - add fp, r2, r1 - - PLD [ip, #32] - ldmia ip!, {r0-r7} - - cmp r1, #0 - orreqs r8, r2, r3 - orreqs r8, r4, r5 - orreqs r8, r6, r7 - beq HLoopTailZero - -HLoopHead: - // tmp10 = ((DCTELEM) wsptr[0] + (DCTELEM) wsptr[4]); (r0) - // tmp11 = ((DCTELEM) wsptr[0] - (DCTELEM) wsptr[4]); (r4) - add r0, r0, r4 - sub r4, r0, r4, lsl #1 - - // tmp13 = ((DCTELEM) wsptr[2] + (DCTELEM) wsptr[6]); (r2) - // tmp12 = MULTIPLY((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6], FIX_1_414213562) - tmp13; (r6) - // FIX_... = 360 + 2 - add r2, r2, r6 - sub r6, r2, r6, lsl #1 - mov r8, #360 - add r8, r8, #2 - mul r6, r8, r6 - - // tmp0 = tmp10 + tmp13; (r0) - // tmp3 = tmp10 - tmp13; (r8) - // tmp1 = tmp11 + tmp12; (r4) - // tmp2 = tmp11 - tmp12; (r6) - add r0, r0, r2 - rsb r6, r2, r6, asr #8 - sub r8, r0, r2, lsl #1 - add r4, r4, r6 - sub r6, r4, r6, lsl #1 - - stmia local_TMP0123, {r0, r4, r6, r8} - - // Odd part - - // z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3]; (r0) - // z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3]; (r2) - // z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7]; (r4) - // z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7]; (r6) - add r0, r5, r3 - sub r2, r5, r3 - add r4, r1, r7 - sub r6, r1, r7 - - // tmp7 = z11 + z13; (r7) - // tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); (r1) - // FIX_... = 360 + 2 - add r7, r4, r0 - sub r1, r4, r0 - mov r8, #360 - add r8, r8, #2 - mul r1, r8, r1 - - // z5 = MULTIPLY(z10 + z12, FIX_1_847759065); (r8) - // tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; (r0) - // tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; (r2) - // FIX_1_8477... = 473 = 472 + 1 - // FIX_1_082... = 277 = 276 + 1 - // FIX_2_... = 669 = 668 + 1 - add r8, r2, r6 - mov r9, #472 - mla r8, r9, r8, r8 - mov r9, #276 - mla r0, r6, r9, r6 - mov r9, #668 - mla r2, r9, r2, r2 - sub r0, r0, r8 - sub r2, r8, r2 - - // tmp6 = tmp12 - tmp7; (r6) - // tmp5 = tmp11 - tmp6; (r5) - // tmp4 = tmp10 + tmp5; (r4) - rsb r6, r7, r2, asr #8 - rsb r5, r6, r1, asr #8 - add r4, r5, r0, asr #8 - - ldmia local_TMP0123, {r0, r1, r2, r3} - - // outptr[0] = range_limit[IDESCALE(tmp0 + tmp7, PASS1_BITS+3) & RANGE_MASK]; - // outptr[7] = range_limit[IDESCALE(tmp0 - tmp7, PASS1_BITS+3) & RANGE_MASK]; - // outptr[1] = range_limit[IDESCALE(tmp1 + tmp6, PASS1_BITS+3) & RANGE_MASK]; - // outptr[6] = range_limit[IDESCALE(tmp1 - tmp6, PASS1_BITS+3) & RANGE_MASK]; - // outptr[2] = range_limit[IDESCALE(tmp2 + tmp5, PASS1_BITS+3) & RANGE_MASK]; - // outptr[5] = range_limit[IDESCALE(tmp2 - tmp5, PASS1_BITS+3) & RANGE_MASK]; - // outptr[4] = range_limit[IDESCALE(tmp3 + tmp4, PASS1_BITS+3) & RANGE_MASK]; - // outptr[3] = range_limit[IDESCALE(tmp3 - tmp4, PASS1_BITS+3) & RANGE_MASK]; - - mov r8, #128 - add r0, r0, r7 - sub r7, r0, r7, lsl #1 - add r0, r8, r0, asr #5 - add r7, r8, r7, asr #5 - add r1, r1, r6 - sub r6, r1, r6, lsl #1 - add r1, r8, r1, asr #5 - add r6, r8, r6, asr #5 - add r2, r2, r5 - sub r5, r2, r5, lsl #1 - add r2, r8, r2, asr #5 - add r5, r8, r5, asr #5 - sub r3, r3, r4 - add r4, r3, r4, lsl #1 - add r3, r8, r3, asr #5 - add r4, r8, r4, asr #5 - -#if __ARM_ARCH__ >= 6 - usat r0, #8, r0 - usat r1, #8, r1 - usat r2, #8, r2 - usat r3, #8, r3 - usat r4, #8, r4 - usat r5, #8, r5 - usat r6, #8, r6 - usat r7, #8, r7 -#else - cmp r0, #255 - mvnhi r0, r0, asr #31 - andhi r0, #255 - cmp r7, #255 - mvnhi r7, r7, asr #31 - cmp r1, #255 - mvnhi r1, r1, asr #31 - andhi r1, #255 - cmp r6, #255 - mvnhi r6, r6, asr #31 - andhi r6, #255 - cmp r2, #255 - mvnhi r2, r2, asr #31 - andhi r2, #255 - cmp r5, #255 - mvnhi r5, r5, asr #31 - andhi r5, #255 - cmp r3, #255 - mvnhi r3, r3, asr #31 - cmp r4, #255 - mvnhi r4, r4, asr #31 - andhi r4, #255 -#endif - - // r3 r2 r1 r0 - orr r0, r0, r1, lsl #8 - orr r0, r0, r2, lsl #16 - orr r0, r0, r3, lsl #24 - - // r7 r6 r5 r4 - orr r1, r4, r5, lsl #8 - orr r1, r1, r6, lsl #16 - orr r1, r1, r7, lsl #24 - stmia fp, {r0, r1} - - add r0, sp, #(off_WORKSPACE + 8*8*4) - cmp ip, r0 - bne HLoopTail - -Exit: - add sp, sp, #local_SIZE - ldmia sp!, {r4,r5, r6,r7, r8,r9, r10,r11, r12,lr} - bx lr - - -VLoopHeadZero: -// ok, all AC coefficients are 0 - ldr r1, [r10, #QY(0)] - add fp, fp, #2 - add r10, r10, #4 - mul r0, r1, r0 - str r0, [ip, #QY(0)] - str r0, [ip, #QY(1)] - str r0, [ip, #QY(2)] - str r0, [ip, #QY(3)] - str r0, [ip, #QY(4)] - str r0, [ip, #QY(5)] - str r0, [ip, #QY(6)] - str r0, [ip, #QY(7)] - add ip, ip, #4 - add r0, sp, #(off_WORKSPACE + 4*8) - cmp ip, r0 - beq HLoopStart - b VLoopTail - -HLoopTailZero: - mov r0, r0, asr #5 - add r0, #128 - -#if __ARM_ARCH__ >= 6 - usat r0, #8, r0 -#else - cmp r0, #255 - mvnhi r0, r0, asr #31 - andhi r0, r0, #255 -#endif - - orr r0, r0, lsl #8 - orr r0, r0, lsl #16 - mov r1, r0 - stmia fp, {r0, r1} - - add r0, sp, #(off_WORKSPACE + 64*4) - cmp ip, r0 - beq Exit - b HLoopTail - - .endfunc diff --git a/src/jni/jpeg/jidctvenum.c b/src/jni/jpeg/jidctvenum.c new file mode 100644 index 0000000000..f458bb5652 --- /dev/null +++ b/src/jni/jpeg/jidctvenum.c @@ -0,0 +1,229 @@ +/* + * jidctvenum.c + * + * Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * 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 Code Aurora Forum, Inc. 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 "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef ANDROID_JPEG_USE_VENUM +/* + * This module is specialized to the case DCTSIZE = 8. + */ +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce an int result. In this module, both inputs and result + * are 16 bits or less, so either int or short multiply will work. + */ + +#define DEQUANTIZE(coef,quantval) ((coef) * ((INT16)quantval)) + +GLOBAL(void) +jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + ISLOW_MULT_TYPE * quantptr; + JCOEFPTR coefptr; + int ctr; + + /* idct_out temp buffer is needed because output_buf sample allocation is 8 bits, + * while IDCT output expects 16 bits. + */ + INT16 idct_out[DCTSIZE2]; /* buffers data between passes */ + JSAMPROW outptr; + INT16* idctptr; + + coefptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + + /* Dequantize the coeff buffer and write it back to the same location */ + for (ctr = DCTSIZE; ctr > 0; ctr--) { + coefptr[0] = DEQUANTIZE(coefptr[0] , quantptr[0] ); + coefptr[DCTSIZE*1] = DEQUANTIZE(coefptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + coefptr[DCTSIZE*2] = DEQUANTIZE(coefptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + coefptr[DCTSIZE*3] = DEQUANTIZE(coefptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + coefptr[DCTSIZE*4] = DEQUANTIZE(coefptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + coefptr[DCTSIZE*5] = DEQUANTIZE(coefptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + coefptr[DCTSIZE*6] = DEQUANTIZE(coefptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + coefptr[DCTSIZE*7] = DEQUANTIZE(coefptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + /* advance pointers to next column */ + quantptr++; + coefptr++; + } + + idct_8x8_venum((INT16*)coef_block, + (INT16*)idct_out, + DCTSIZE * sizeof(INT16)); + + idctptr = idct_out; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + // outptr sample size is 1 byte while idctptr sample size is 2 bytes + outptr[0] = idctptr[0]; + outptr[1] = idctptr[1]; + outptr[2] = idctptr[2]; + outptr[3] = idctptr[3]; + outptr[4] = idctptr[4]; + outptr[5] = idctptr[5]; + outptr[6] = idctptr[6]; + outptr[7] = idctptr[7]; + idctptr += DCTSIZE; /* advance pointers to next row */ + } +} + +GLOBAL(void) +jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + ISLOW_MULT_TYPE * quantptr; + JSAMPROW outptr; + + /* Note: Must allocate 8x4 even though only 4x4 is used because + * IDCT function expects stride of 8. Stride input to function is ignored. + */ + INT16 idct_out[DCTSIZE * (DCTSIZE>>1)]; /* buffers data between passes */ + INT16* idctptr; + JCOEFPTR coefptr; + int ctr; + + coefptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + + /* Dequantize the coeff buffer and write it back to the same location */ + for (ctr = (DCTSIZE>>1); ctr > 0; ctr--) { + coefptr[0] = DEQUANTIZE(coefptr[0] , quantptr[0] ); + coefptr[DCTSIZE*1] = DEQUANTIZE(coefptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + coefptr[DCTSIZE*2] = DEQUANTIZE(coefptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + coefptr[DCTSIZE*3] = DEQUANTIZE(coefptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + + /* advance pointers to next column */ + quantptr++; + coefptr++; + } + + idct_4x4_venum((INT16*)coef_block, + (INT16*)idct_out, + DCTSIZE * sizeof(INT16)); + + idctptr = idct_out; + for (ctr = 0; ctr < (DCTSIZE>>1); ctr++) { + outptr = output_buf[ctr] + output_col; + + /* outptr sample size is 1 byte while idctptr sample size is 2 bytes */ + outptr[0] = idctptr[0]; + outptr[1] = idctptr[1]; + outptr[2] = idctptr[2]; + outptr[3] = idctptr[3]; + /* IDCT function assumes stride of 8 units */ + idctptr += (DCTSIZE); /* advance pointers to next row */ + } +} + +GLOBAL(void) +jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + ISLOW_MULT_TYPE * quantptr; + JSAMPROW outptr; + + /* Note: Must allocate 8x2 even though only 2x2 is used because + * IDCT function expects stride of 8. Stride input to function is ignored. + * There is also a hw limitation requiring input size to be 8x2. + */ + INT16 idct_out[DCTSIZE * (DCTSIZE>>2)]; /* buffers data between passes */ + INT16* idctptr; + JCOEFPTR coefptr; + int ctr; + + coefptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + + /* Dequantize the coeff buffer and write it back to the same location */ + for (ctr = (DCTSIZE>>2); ctr > 0; ctr--) { + coefptr[0] = DEQUANTIZE(coefptr[0] , quantptr[0] ); + coefptr[DCTSIZE*1] = DEQUANTIZE(coefptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + /* advance pointers to next column */ + quantptr++; + coefptr++; + } + + idct_2x2_venum((INT16*)coef_block, + (INT16*)idct_out, + DCTSIZE * sizeof(INT16)); + + idctptr = idct_out; + for (ctr = 0; ctr < (DCTSIZE>>2); ctr++) { + outptr = output_buf[ctr] + output_col; + + /* outptr sample size is 1 bytes, idctptr sample size is 2 bytes */ + outptr[0] = idctptr[0]; + outptr[1] = idctptr[1]; + + /* IDCT function assumes stride of 8 units */ + idctptr += (DCTSIZE); /* advance pointers to next row */ + } +} + + +GLOBAL(void) +jpeg_idct_1x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + ISLOW_MULT_TYPE * quantptr; + JSAMPROW outptr; // 8-bit type + INT16 idct_out[DCTSIZE]; /* Required to allocate 8 samples, even though we only use one. */ + JCOEFPTR coefptr; + int ctr; + + coefptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + outptr = output_buf[0] + output_col; + + /* Dequantize the coeff buffer and write it back to the same location */ + coefptr[0] = DEQUANTIZE(coefptr[0], quantptr[0]); + + idct_1x1_venum((INT16*)coef_block, + (INT16*)idct_out, + DCTSIZE * sizeof(INT16)); + outptr[0] = idct_out[0]; +} + + +#endif /* ANDROID_JPEG_USE_VENUM */ diff --git a/src/jni/jpeg/jmem-ashmem.c b/src/jni/jpeg/jmem-ashmem.c new file mode 100644 index 0000000000..3a17b02c3a --- /dev/null +++ b/src/jni/jpeg/jmem-ashmem.c @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2007-2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#include +#include +#include + +#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ +extern void * malloc JPP((size_t size)); +extern void free JPP((void *ptr)); +#endif + +/* + * Memory allocation and freeing are controlled by the regular library + * routines malloc() and free(). + */ + +GLOBAL(void *) +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * "Large" objects are treated the same as "small" ones. + * NB: although we include FAR keywords in the routine declarations, + * this file won't actually work in 80x86 small/medium model; at least, + * you probably won't be able to process useful-size images in only 64KB. + */ + +GLOBAL(void FAR *) +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void FAR *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + free(object); +} + +/* + * This routine computes the total memory space available for allocation. + * It's impossible to do this in a portable way; our current solution is + * to make the user tell us (with a default value set at compile time). + * If you can actually get the available space, it's a good idea to subtract + * a slop factor of 5% or so. + */ + +#ifndef DEFAULT_MAX_MEM /* so can override from makefile */ +#define DEFAULT_MAX_MEM 10000000L /* default: ten megabyte */ +#endif + +GLOBAL(long) +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + return cinfo->mem->max_memory_to_use - already_allocated; +} + + +/* + * Backing store (temporary file) management. + * Backing store objects are only used when the value returned by + * jpeg_mem_available is less than the total space needed. You can dispense + * with these routines if you have plenty of virtual memory; see jmemnobs.c. + */ + +METHODDEF(void) +read_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + memmove(buffer_address, info->addr + file_offset, byte_count); +} + + +METHODDEF(void) +write_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + memmove(info->addr + file_offset, buffer_address, byte_count); +} + + +METHODDEF(void) +close_backing_store (j_common_ptr cinfo, backing_store_ptr info) +{ + munmap(info->addr, info->size); + close(info->temp_file); +} + +LOCAL(int) +get_ashmem(backing_store_ptr info, long total_bytes_needed) +{ + char path[1024]; + snprintf(path, 1023, "%d.tmp.ashmem", getpid()); + int fd = ashmem_create_region(path, total_bytes_needed); + if (fd == -1) { + return -1; + } + int err = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE); + if (err) { + return -1; + } + info->addr = mmap(NULL, total_bytes_needed, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + info->size = total_bytes_needed; + info->temp_file = fd; + return fd; +} + +/* + * Initial opening of a backing-store object. + * This version uses ashmem to get a shared memory of total-bytes_needed. + */ + +GLOBAL(void) +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + if (get_ashmem(info, total_bytes_needed) == -1) + ERREXITS(cinfo, JERR_TFILE_CREATE, ""); + info->read_backing_store = read_backing_store; + info->write_backing_store = write_backing_store; + info->close_backing_store = close_backing_store; +} + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. + */ + +GLOBAL(long) +jpeg_mem_init (j_common_ptr cinfo) +{ + return DEFAULT_MAX_MEM; /* default for max_memory_to_use */ +} + +GLOBAL(void) +jpeg_mem_term (j_common_ptr cinfo) +{ + /* no work */ +} diff --git a/src/jni/jpeg/jmemsys.h b/src/jni/jpeg/jmemsys.h index 6c3c6d348f..2ed1c63a13 100644 --- a/src/jni/jpeg/jmemsys.h +++ b/src/jni/jpeg/jmemsys.h @@ -160,12 +160,18 @@ typedef struct backing_store_struct { short temp_file; /* file reference number to temp file */ FSSpec tempSpec; /* the FSSpec for the temp file */ char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else +#ifdef USE_ANDROID_ASHMEM + short temp_file; /* file reference number to temp file */ + unsigned char* addr; /* the memory address mapped to ashmem */ + long size; /* the requested ashmem size */ #else /* For a typical implementation with temp files, we need: */ FILE * temp_file; /* stdio reference to temp file */ char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */ #endif #endif +#endif } backing_store_info; diff --git a/src/jni/jpeg/jpegint.h b/src/jni/jpeg/jpegint.h index 95b00d405c..7bf9ffe952 100644 --- a/src/jni/jpeg/jpegint.h +++ b/src/jni/jpeg/jpegint.h @@ -2,6 +2,7 @@ * jpegint.h * * Copyright (C) 1991-1997, Thomas G. Lane. + * Copyright (c) 2010, Code Aurora Forum. All rights reserved. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -145,6 +146,10 @@ struct jpeg_decomp_master { /* Input control module */ struct jpeg_input_controller { JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); + JMETHOD(int, consume_input_build_huffman_index, (j_decompress_ptr cinfo, + huffman_index *index, int scan_count)); + JMETHOD(int, consume_markers, (j_decompress_ptr cinfo, + huffman_index *index, int scan_count)); JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); @@ -166,11 +171,27 @@ struct jpeg_d_main_controller { struct jpeg_d_coef_controller { JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); + JMETHOD(int, consume_data_build_huffman_index, (j_decompress_ptr cinfo, + huffman_index* index, int scan_count)); JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); /* Pointer to array of coefficient virtual arrays, or NULL if none */ jvirt_barray_ptr *coef_arrays; + + /* column number of the first and last tile, respectively */ + int column_left_boundary; + int column_right_boundary; + + /* column number of the first and last MCU, respectively */ + int MCU_column_left_boundary; + int MCU_column_right_boundary; + + /* the number of MCU columns to skip from the indexed MCU, iM, + * to the requested MCU boundary, rM, where iM is the MCU that we sample + * into our index and is the nearest one to the left of rM. + */ + int MCU_columns_to_skip; }; /* Decompression postprocessing (color quantization buffer control) */ @@ -193,6 +214,8 @@ struct jpeg_marker_reader { * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. */ JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); + JMETHOD(void, get_sos_marker_position, (j_decompress_ptr cinfo, + huffman_index *index)); /* Read a restart marker --- exported for use by entropy decoder only */ jpeg_marker_parser_method read_restart_marker; @@ -202,6 +225,7 @@ struct jpeg_marker_reader { boolean saw_SOI; /* found SOI? */ boolean saw_SOF; /* found SOF? */ int next_restart_num; /* next restart number expected (0-7) */ + int current_sos_marker_position; unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ }; @@ -210,10 +234,17 @@ struct jpeg_entropy_decoder { JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)); + JMETHOD(boolean, decode_mcu_discard_coef, (j_decompress_ptr cinfo)); + JMETHOD(void, configure_huffman_decoder, (j_decompress_ptr cinfo, + huffman_offset_data offset)); + JMETHOD(void, get_huffman_decoder_configuration, (j_decompress_ptr cinfo, + huffman_offset_data *offset)); /* This is here to share code between baseline and progressive decoders; */ /* other modules probably should not use it */ boolean insufficient_data; /* set TRUE after emitting warning */ + + huffman_index *index; }; /* Inverse DCT (also performs dequantization) */ @@ -260,6 +291,48 @@ struct jpeg_color_quantizer { JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); }; +#ifdef ANDROID_JPEG_USE_VENUM + +/* IDCT routines */ +EXTERN (void) idct_1x1_venum (INT16 * coeffPtr, INT16 * samplePtr, INT32 stride); +EXTERN (void) idct_2x2_venum (INT16 * coeffPtr, INT16 * samplePtr, INT32 stride); +EXTERN (void) idct_4x4_venum (INT16 * coeffPtr, INT16 * samplePtr, INT32 stride); +EXTERN (void) idct_8x8_venum (INT16 * coeffPtr, INT16 * samplePtr, INT32 stride); + +#ifndef ANDROID_JPEG_DISABLE_VENUM_YCC_RGB_565 +/* Color conversion routines */ +EXTERN (void) yvup2rgb565_venum (UINT8 *pLumaLine, + UINT8 *pCrLine, + UINT8 *pCbLine, + UINT8 *pRGB565Line, + JDIMENSION nLineWidth); +EXTERN (void) yyvup2rgb565_venum (UINT8 * pLumaLine, + UINT8 *pCrLine, + UINT8 *pCbLine, + UINT8 * pRGB565Line, + JDIMENSION nLineWidth); +#endif +EXTERN (void) yvup2bgr888_venum (UINT8 * pLumaLine, + UINT8 *pCrLine, + UINT8 *pCbLine, + UINT8 * pBGR888Line, + JDIMENSION nLineWidth); +EXTERN (void) yyvup2bgr888_venum (UINT8 * pLumaLine, + UINT8 *pCrLine, + UINT8 *pCbLine, + UINT8 * pBGR888Line, + JDIMENSION nLineWidth); +EXTERN (void) yvup2abgr8888_venum (UINT8 * pLumaLine, + UINT8 *pCrLine, + UINT8 *pCbLine, + UINT8 * pABGR888Line, + JDIMENSION nLineWidth); +EXTERN (void) yyvup2abgr8888_venum (UINT8 * pLumaLine, + UINT8 *pCrLine, + UINT8 *pCbLine, + UINT8 * pABGR888Line, + JDIMENSION nLineWidth); +#endif /* Miscellaneous useful macros */ @@ -357,6 +430,7 @@ EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_huff_decoder_no_data JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); @@ -364,18 +438,27 @@ EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_decompress_per_scan_setup (j_decompress_ptr cinfo); /* Memory manager initialization */ EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); /* Utility routines in jutils.c */ EXTERN(long) jdiv_round_up JPP((long a, long b)); EXTERN(long) jround_up JPP((long a, long b)); +EXTERN(long) jmin JPP((long a, long b)); EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, JSAMPARRAY output_array, int dest_row, int num_rows, JDIMENSION num_cols)); EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, JDIMENSION num_blocks)); EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero)); + +EXTERN(void) jset_input_stream_position JPP((j_decompress_ptr cinfo, + int offset)); +EXTERN(void) jset_input_stream_position_bit JPP((j_decompress_ptr cinfo, + int byte_offset, int bit_left, INT32 buf)); + +EXTERN(int) jget_input_stream_position JPP((j_decompress_ptr cinfo)); /* Constant tables in jutils.c */ #if 0 /* This table is not actually needed in v6a */ extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ diff --git a/src/jni/jpeg/jpeglib.h b/src/jni/jpeg/jpeglib.h index 0f3a547916..07e6872943 100644 --- a/src/jni/jpeg/jpeglib.h +++ b/src/jni/jpeg/jpeglib.h @@ -421,7 +421,10 @@ struct jpeg_decompress_struct { /* Basic description of image --- filled in by jpeg_read_header(). */ /* Application may inspect these values to decide how to process image. */ - JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION original_image_width; /* nominal image width (from SOF marker) */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) + may be changed by tile decode */ JDIMENSION image_height; /* nominal image height */ int num_components; /* # of color components in JPEG image */ J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ @@ -539,6 +542,7 @@ struct jpeg_decompress_struct { jpeg_component_info * comp_info; /* comp_info[i] describes component that appears i'th in SOF */ + boolean tile_decode; /* TRUE if using tile based decoding */ boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ @@ -633,6 +637,59 @@ struct jpeg_decompress_struct { struct jpeg_color_quantizer * cquantize; }; +typedef struct { + + // |--- byte_offset ---|- bit_left -| + // \------ 27 -------/ \---- 5 ----/ + unsigned int bitstream_offset; + short prev_dc[3]; + + // remaining EOBs in EOBRUN + unsigned short EOBRUN; + + // save the decoder current bit buffer, entropy->bitstate.get_buffer. + INT32 get_buffer; + + // save the restart info. + unsigned short restarts_to_go; + unsigned char next_restart_num; +} huffman_offset_data; + +typedef struct { + + // The header starting position of this scan + unsigned int bitstream_offset; + + // Number of components in this scan + int comps_in_scan; + + // Number of MCUs in each row + int MCUs_per_row; + int MCU_rows_per_iMCU_row; + + // The last MCU position and its dc value in this scan + huffman_offset_data prev_MCU_offset; + + huffman_offset_data **offset; +} huffman_scan_header; + +#define DEFAULT_MCU_SAMPLE_SIZE 16 + +typedef struct { + + // The number of MCUs that we sample each time as an index point + int MCU_sample_size; + + // Number of scan in this image + int scan_count; + + // Number of iMCUs rows in this image + int total_iMCU_rows; + + // Memory used by scan struct + size_t mem_used; + huffman_scan_header *scan; +} huffman_index; /* "Object" declarations for JPEG modules that may be supplied or called * directly by the surrounding application. @@ -728,13 +785,16 @@ struct jpeg_destination_mgr { struct jpeg_source_mgr { const JOCTET * next_input_byte; /* => next byte to read from buffer */ + const JOCTET * start_input_byte; /* => first byte to read from input */ size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + size_t current_offset; /* current readed input offset */ JMETHOD(void, init_source, (j_decompress_ptr cinfo)); JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); JMETHOD(void, term_source, (j_decompress_ptr cinfo)); + JMETHOD(boolean, seek_input_data, (j_decompress_ptr cinfo, long byte_offset)); }; @@ -977,9 +1037,21 @@ EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, /* Main entry points for decompression */ EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_start_tile_decompress JPP((j_decompress_ptr cinfo)); EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION max_lines)); +EXTERN(JDIMENSION) jpeg_read_scanlines_from JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + int line_offset, + JDIMENSION max_lines)); +EXTERN(JDIMENSION) jpeg_read_tile_scanline JPP((j_decompress_ptr cinfo, + huffman_index *index, + JSAMPARRAY scanlines)); +EXTERN(void) jpeg_init_read_tile_scanline JPP((j_decompress_ptr cinfo, + huffman_index *index, + int *start_x, int *start_y, + int *width, int *height)); EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); /* Replaces jpeg_read_scanlines when reading raw downsampled data. */ @@ -1017,6 +1089,8 @@ EXTERN(void) jpeg_set_marker_processor /* Read or write raw DCT coefficients --- useful for lossless transcoding. */ EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_build_huffman_index + JPP((j_decompress_ptr cinfo, huffman_index *index)); EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, @@ -1041,6 +1115,16 @@ EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, int desired)); +EXTERN(void) jpeg_configure_huffman_decoder(j_decompress_ptr cinfo, + huffman_offset_data offset); +EXTERN(void) jpeg_get_huffman_decoder_configuration(j_decompress_ptr cinfo, + huffman_offset_data *offset); +EXTERN(void) jpeg_create_huffman_index(j_decompress_ptr cinfo, + huffman_index *index); +EXTERN(void) jpeg_configure_huffman_index_scan(j_decompress_ptr cinfo, + huffman_index *index, int scan_no, int offset); +EXTERN(void) jpeg_destroy_huffman_index(huffman_index *index); + /* These marker codes are exported since applications and data source modules * are likely to want to use them. diff --git a/src/jni/jpeg/jutils.c b/src/jni/jpeg/jutils.c index d18a955562..616ad05110 100644 --- a/src/jni/jpeg/jutils.c +++ b/src/jni/jpeg/jutils.c @@ -86,6 +86,12 @@ jround_up (long a, long b) return a - (a % b); } +GLOBAL(long) +jmin (long a, long b) +{ + return a < b ? a : b; +} + /* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays * and coefficient-block arrays. This won't work on 80x86 because the arrays