From 609f1a00c96cf5605f4614e7bb6d0487c98969c5 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Thu, 10 Dec 2009 09:44:29 -0800 Subject: Initial checkin of software AVC video decoder based on PV source code. --- media/libstagefright/Android.mk | 6 +- media/libstagefright/OMXCodec.cpp | 4 + media/libstagefright/codecs/aacdec/Android.mk | 4 - .../libstagefright/codecs/amrnb/common/Android.mk | 4 +- media/libstagefright/codecs/amrnb/dec/Android.mk | 4 - media/libstagefright/codecs/amrwb/Android.mk | 4 - media/libstagefright/codecs/avc/Android.mk | 4 + media/libstagefright/codecs/avc/common/Android.mk | 21 + .../codecs/avc/common/include/avc_types.h | 14 + .../codecs/avc/common/include/avcapi_common.h | 274 +++ .../codecs/avc/common/include/avcint_common.h | 882 ++++++++ .../codecs/avc/common/include/avclib_common.h | 555 +++++ .../codecs/avc/common/src/deblock.cpp | 1666 ++++++++++++++ media/libstagefright/codecs/avc/common/src/dpb.cpp | 724 ++++++ media/libstagefright/codecs/avc/common/src/fmo.cpp | 249 +++ .../codecs/avc/common/src/mb_access.cpp | 471 ++++ .../codecs/avc/common/src/reflist.cpp | 596 +++++ media/libstagefright/codecs/avc/dec/AVCDecoder.cpp | 439 ++++ media/libstagefright/codecs/avc/dec/Android.mk | 27 + .../codecs/avc/dec/include/avcdec_api.h | 200 ++ .../codecs/avc/dec/include/pvavcdecoder.h | 49 + .../codecs/avc/dec/include/pvavcdecoder_factory.h | 43 + .../codecs/avc/dec/include/pvavcdecoderinterface.h | 48 + .../codecs/avc/dec/src/avc_bitstream.cpp | 276 +++ .../codecs/avc/dec/src/avcdec_api.cpp | 1036 +++++++++ .../codecs/avc/dec/src/avcdec_bitstream.h | 125 ++ .../libstagefright/codecs/avc/dec/src/avcdec_int.h | 88 + .../libstagefright/codecs/avc/dec/src/avcdec_lib.h | 555 +++++ media/libstagefright/codecs/avc/dec/src/header.cpp | 1391 ++++++++++++ media/libstagefright/codecs/avc/dec/src/itrans.cpp | 307 +++ .../codecs/avc/dec/src/pred_inter.cpp | 2329 ++++++++++++++++++++ .../codecs/avc/dec/src/pred_intra.cpp | 1786 +++++++++++++++ .../libstagefright/codecs/avc/dec/src/residual.cpp | 523 +++++ media/libstagefright/codecs/avc/dec/src/slice.cpp | 772 +++++++ media/libstagefright/codecs/avc/dec/src/vlc.cpp | 815 +++++++ .../codecs/avc/patent_disclaimer.txt | 9 + media/libstagefright/codecs/mp3dec/Android.mk | 4 - media/libstagefright/include/AVCDecoder.h | 86 + 38 files changed, 16372 insertions(+), 18 deletions(-) create mode 100644 media/libstagefright/codecs/avc/Android.mk create mode 100644 media/libstagefright/codecs/avc/common/Android.mk create mode 100644 media/libstagefright/codecs/avc/common/include/avc_types.h create mode 100644 media/libstagefright/codecs/avc/common/include/avcapi_common.h create mode 100644 media/libstagefright/codecs/avc/common/include/avcint_common.h create mode 100644 media/libstagefright/codecs/avc/common/include/avclib_common.h create mode 100644 media/libstagefright/codecs/avc/common/src/deblock.cpp create mode 100644 media/libstagefright/codecs/avc/common/src/dpb.cpp create mode 100644 media/libstagefright/codecs/avc/common/src/fmo.cpp create mode 100644 media/libstagefright/codecs/avc/common/src/mb_access.cpp create mode 100644 media/libstagefright/codecs/avc/common/src/reflist.cpp create mode 100644 media/libstagefright/codecs/avc/dec/AVCDecoder.cpp create mode 100644 media/libstagefright/codecs/avc/dec/Android.mk create mode 100644 media/libstagefright/codecs/avc/dec/include/avcdec_api.h create mode 100644 media/libstagefright/codecs/avc/dec/include/pvavcdecoder.h create mode 100644 media/libstagefright/codecs/avc/dec/include/pvavcdecoder_factory.h create mode 100644 media/libstagefright/codecs/avc/dec/include/pvavcdecoderinterface.h create mode 100644 media/libstagefright/codecs/avc/dec/src/avc_bitstream.cpp create mode 100644 media/libstagefright/codecs/avc/dec/src/avcdec_api.cpp create mode 100644 media/libstagefright/codecs/avc/dec/src/avcdec_bitstream.h create mode 100644 media/libstagefright/codecs/avc/dec/src/avcdec_int.h create mode 100644 media/libstagefright/codecs/avc/dec/src/avcdec_lib.h create mode 100644 media/libstagefright/codecs/avc/dec/src/header.cpp create mode 100644 media/libstagefright/codecs/avc/dec/src/itrans.cpp create mode 100644 media/libstagefright/codecs/avc/dec/src/pred_inter.cpp create mode 100644 media/libstagefright/codecs/avc/dec/src/pred_intra.cpp create mode 100644 media/libstagefright/codecs/avc/dec/src/residual.cpp create mode 100644 media/libstagefright/codecs/avc/dec/src/slice.cpp create mode 100644 media/libstagefright/codecs/avc/dec/src/vlc.cpp create mode 100644 media/libstagefright/codecs/avc/patent_disclaimer.txt create mode 100644 media/libstagefright/include/AVCDecoder.h diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 83d492c..d4c6708 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -56,10 +56,14 @@ ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true) LOCAL_STATIC_LIBRARIES := \ libstagefright_aacdec \ libstagefright_amrnbdec \ - libstagefright_amrnb_common \ libstagefright_amrwbdec \ + libstagefright_avcdec \ libstagefright_mp3dec +LOCAL_SHARED_LIBRARIES += \ + libstagefright_amrnb_common \ + libstagefright_avc_common + endif ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true) diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 093e2e0..fc3c05b 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -22,6 +22,7 @@ #include "include/AACDecoder.h" #include "include/AMRNBDecoder.h" #include "include/AMRWBDecoder.h" +#include "include/AVCDecoder.h" #include "include/MP3Decoder.h" #endif @@ -300,6 +301,9 @@ sp OMXCodec::Create( return new AMRWBDecoder(source); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) { return new MP3Decoder(source); + } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC) + && (flags & kPreferSoftwareCodecs)) { + return new AVCDecoder(source); } #endif diff --git a/media/libstagefright/codecs/aacdec/Android.mk b/media/libstagefright/codecs/aacdec/Android.mk index 7f06095..d5d8f3e 100644 --- a/media/libstagefright/codecs/aacdec/Android.mk +++ b/media/libstagefright/codecs/aacdec/Android.mk @@ -149,10 +149,6 @@ LOCAL_CFLAGS := -DAAC_PLUS -DHQ_SBR -DPARAMETRICSTEREO -DOSCL_IMPORT_REF= -DOSCL LOCAL_C_INCLUDES := frameworks/base/media/libstagefright/include -LOCAL_SHARED_LIBRARIES := \ - libstagefright \ - libutils - LOCAL_MODULE := libstagefright_aacdec include $(BUILD_STATIC_LIBRARY) diff --git a/media/libstagefright/codecs/amrnb/common/Android.mk b/media/libstagefright/codecs/amrnb/common/Android.mk index b22be77..2657a52 100644 --- a/media/libstagefright/codecs/amrnb/common/Android.mk +++ b/media/libstagefright/codecs/amrnb/common/Android.mk @@ -69,6 +69,8 @@ LOCAL_C_INCLUDES := \ LOCAL_CFLAGS := \ -DOSCL_UNUSED_ARG= -DOSCL_IMPORT_REF= -DOSCL_EXPORT_REF= +LOCAL_PRELINK_MODULE:= false + LOCAL_MODULE := libstagefright_amrnb_common -include $(BUILD_STATIC_LIBRARY) +include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk index 0852ff3..a545762 100644 --- a/media/libstagefright/codecs/amrnb/dec/Android.mk +++ b/media/libstagefright/codecs/amrnb/dec/Android.mk @@ -49,10 +49,6 @@ LOCAL_C_INCLUDES := \ LOCAL_CFLAGS := \ -DOSCL_UNUSED_ARG= -DOSCL_IMPORT_REF= -LOCAL_SHARED_LIBRARIES := \ - libstagefright \ - libutils - LOCAL_MODULE := libstagefright_amrnbdec include $(BUILD_STATIC_LIBRARY) diff --git a/media/libstagefright/codecs/amrwb/Android.mk b/media/libstagefright/codecs/amrwb/Android.mk index 1c80f08..ab591d7 100644 --- a/media/libstagefright/codecs/amrwb/Android.mk +++ b/media/libstagefright/codecs/amrwb/Android.mk @@ -51,10 +51,6 @@ LOCAL_C_INCLUDES := \ LOCAL_CFLAGS := \ -DOSCL_UNUSED_ARG= -DOSCL_IMPORT_REF= -LOCAL_SHARED_LIBRARIES := \ - libstagefright \ - libutils - LOCAL_MODULE := libstagefright_amrwbdec include $(BUILD_STATIC_LIBRARY) diff --git a/media/libstagefright/codecs/avc/Android.mk b/media/libstagefright/codecs/avc/Android.mk new file mode 100644 index 0000000..2e43120 --- /dev/null +++ b/media/libstagefright/codecs/avc/Android.mk @@ -0,0 +1,4 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/media/libstagefright/codecs/avc/common/Android.mk b/media/libstagefright/codecs/avc/common/Android.mk new file mode 100644 index 0000000..39c6da8 --- /dev/null +++ b/media/libstagefright/codecs/avc/common/Android.mk @@ -0,0 +1,21 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + src/deblock.cpp \ + src/dpb.cpp \ + src/fmo.cpp \ + src/mb_access.cpp \ + src/reflist.cpp + +LOCAL_MODULE := libstagefright_avc_common + +LOCAL_CFLAGS := -DOSCL_EXPORT_REF= -DOSCL_IMPORT_REF= + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/src \ + $(LOCAL_PATH)/include + +LOCAL_PRELINK_MODULE:= false + +include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/avc/common/include/avc_types.h b/media/libstagefright/codecs/avc/common/include/avc_types.h new file mode 100644 index 0000000..73cad89 --- /dev/null +++ b/media/libstagefright/codecs/avc/common/include/avc_types.h @@ -0,0 +1,14 @@ +#ifndef AVC_TYPES_H_ + +#define AVC_TYPES_H_ + +#include + +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef int16_t int16; +typedef uint32_t uint32; +typedef int32_t int32; +typedef unsigned int uint; + +#endif // AVC_TYPES_H_ diff --git a/media/libstagefright/codecs/avc/common/include/avcapi_common.h b/media/libstagefright/codecs/avc/common/include/avcapi_common.h new file mode 100644 index 0000000..3331689 --- /dev/null +++ b/media/libstagefright/codecs/avc/common/include/avcapi_common.h @@ -0,0 +1,274 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 file contains common type definitions and enumerations used by AVC encoder +and decoder libraries which are exposed to the users. +@publishedAll +*/ + +#ifndef AVCAPI_COMMON_H_INCLUDED +#define AVCAPI_COMMON_H_INCLUDED + +#include "avc_types.h" + +#define PV_MEMORY_POOL +/** +This is common return status. +@publishedAll +*/ +typedef enum +{ + AVC_NO_BUFFER = -2, + AVC_MEMORY_FAIL = -1, + AVC_FAIL = 0, + AVC_SUCCESS = 1, + AVC_PICTURE_OUTPUT_READY = 2 +} AVCStatus; + +/** +This enumeration is for profiles. The value follows the profile_idc in sequence +parameter set rbsp. See Annex A. +@publishedAll +*/ +typedef enum +{ + AVC_BASELINE = 66, + AVC_MAIN = 77, + AVC_EXTENDED = 88, + AVC_HIGH = 100, + AVC_HIGH10 = 110, + AVC_HIGH422 = 122, + AVC_HIGH444 = 144 +} AVCProfile; + +/** +This enumeration is for levels. The value follows the level_idc in sequence +parameter set rbsp. See Annex A. +@published All +*/ +typedef enum +{ + AVC_LEVEL_AUTO = 0, + AVC_LEVEL1_B = 9, + AVC_LEVEL1 = 10, + AVC_LEVEL1_1 = 11, + AVC_LEVEL1_2 = 12, + AVC_LEVEL1_3 = 13, + AVC_LEVEL2 = 20, + AVC_LEVEL2_1 = 21, + AVC_LEVEL2_2 = 22, + AVC_LEVEL3 = 30, + AVC_LEVEL3_1 = 31, + AVC_LEVEL3_2 = 32, + AVC_LEVEL4 = 40, + AVC_LEVEL4_1 = 41, + AVC_LEVEL4_2 = 42, + AVC_LEVEL5 = 50, + AVC_LEVEL5_1 = 51 +} AVCLevel; + +/** +This enumeration follows Table 7-1 for NAL unit type codes. +This may go to avccommon_api.h later (external common). +@publishedAll +*/ +typedef enum +{ + AVC_NALTYPE_SLICE = 1, /* non-IDR non-data partition */ + AVC_NALTYPE_DPA = 2, /* data partition A */ + AVC_NALTYPE_DPB = 3, /* data partition B */ + AVC_NALTYPE_DPC = 4, /* data partition C */ + AVC_NALTYPE_IDR = 5, /* IDR NAL */ + AVC_NALTYPE_SEI = 6, /* supplemental enhancement info */ + AVC_NALTYPE_SPS = 7, /* sequence parameter set */ + AVC_NALTYPE_PPS = 8, /* picture parameter set */ + AVC_NALTYPE_AUD = 9, /* access unit delimiter */ + AVC_NALTYPE_EOSEQ = 10, /* end of sequence */ + AVC_NALTYPE_EOSTREAM = 11, /* end of stream */ + AVC_NALTYPE_FILL = 12 /* filler data */ +} AVCNalUnitType; + +/** +This enumeration specifies debug logging type. +This may go to avccommon_api.h later (external common). +@publishedAll +*/ +typedef enum +{ + AVC_LOGTYPE_ERROR = 0, + AVC_LOGTYPE_WARNING = 1, + AVC_LOGTYPE_INFO = 2 +} AVCLogType; + +/** +This enumerate the status of certain flags. +@publishedAll +*/ +typedef enum +{ + AVC_OFF = 0, + AVC_ON = 1 +} AVCFlag; + +/** +This structure contains input information. +Note, this structure is identical to AVCDecOutput for now. +*/ +typedef struct tagAVCFrameIO +{ + /** A unique identification number for a particular instance of this structure. + To remain unchanged by the application between the time when it is given to the + library and the time when the library returns it back. */ + uint32 id; + + /** Array of pointers to Y,Cb,Cr content in 4:2:0 format. For AVC decoding, + this memory is allocated by the AVC decoder library. For AVC encoding, only the + memory for original unencoded frame is allocated by the application. Internal + memory is also allocated by the AVC encoder library. */ + uint8 *YCbCr[3]; + + /** In/Out: Coded width of the luma component, it has to be multiple of 16. */ + int pitch; + + /** In/Out: Coded height of the luma component, must be multiple of 16. */ + int height; + + /** In/Out: Display width, less than picth */ + int clip_width; + + /** In/Out: Display height, less than height */ + int clip_height; + + /** Input: Origin of the display area [0]=>row, [1]=>column */ + int clip_origin[2]; + + /** Output: Frame number in de/encoding order (not necessary)*/ + uint32 coding_order; + + /** Output: Frame number in displaying order (this may or may not be associated with the POC at all!!!). */ + uint32 disp_order; + + /** In/Out: Flag for use for reference or not. */ + uint is_reference; + + /** In/Out: Coding timestamp in msec (not display timestamp) */ + uint32 coding_timestamp; + + /* there could be something else here such as format, DON (decoding order number) + if available thru SEI, etc. */ +} AVCFrameIO; + + +/** CALLBACK FUNCTION TO BE IMPLEMENTED BY APPLICATION */ +/** In AVCDecControls structure, userData is a pointer to an object with the following + member functions. +*/ + + +/** @brief Decoded picture buffers (DPB) must be allocated or re-allocated before an + IDR frame is decoded. If PV_MEMORY_POOL is not defined, AVC lib will allocate DPB + internally which cannot be shared with the application. In that case, this function + will not be called. + @param userData The same value of userData in AVCHandle object. + @param frame_size_in_mbs The size of each frame in number of macroblocks. + @param num_frames The number of frames in DPB. + @return 1 for success, 0 for fail (cannot allocate DPB) +*/ + +typedef int (*FunctionType_DPBAlloc)(void *userData, uint frame_size_in_mbs, uint num_buffers); + +/** @brief AVC library calls this function is reserve a memory of one frame from the DPB. + Once reserved, this frame shall not be deleted or over-written by the app. + @param userData The same value of userData in AVCHandle object. + @param indx Index of a frame in DPB (AVC library keeps track of the index). + @param yuv The address of the yuv pointer returned to the AVC lib. + @return 1 for success, 0 for fail (no frames available to bind). + */ +typedef int (*FunctionType_FrameBind)(void *userData, int indx, uint8 **yuv); + +/** @brief AVC library calls this function once a bound frame is not needed for decoding + operation (falls out of the sliding window, or marked unused for reference). + @param userData The same value of userData in AVCHandle object. + @param indx Index of frame to be unbound (AVC library keeps track of the index). + @return none. +*/ +typedef void (*FuctionType_FrameUnbind)(void *userData, int); + +/** Pointer to malloc function for general memory allocation, so that application can keep track of + memory usage. +\param "size" "Size of requested memory in bytes." +\param "attribute" "Some value specifying types, priority, etc. of the memory." +\return "The address of the allocated memory casted to int" +*/ +typedef int (*FunctionType_Malloc)(void *userData, int32 size, int attribute); + +/** Function pointer to free +\param "mem" "Pointer to the memory to be freed casted to int" +\return "void" +*/ +typedef void (*FunctionType_Free)(void *userData, int mem); + +/** Debug logging information is returned to the application thru this function. +\param "type" "Type of logging message, see definition of AVCLogType." +\param "string1" "Logging message." +\param "string2" "To be defined." +*/ +typedef void (*FunctionType_DebugLog)(uint32 *userData, AVCLogType type, char *string1, int val1, int val2); + +/** +This structure has to be allocated and maintained by the user of the library. +This structure is used as a handle to the library object. +*/ +typedef struct tagAVCHandle +{ + /** A pointer to the internal data structure. Users have to make sure that this value + is NULL at the beginning. + */ + void *AVCObject; + + /** A pointer to user object which has the following member functions used for + callback purpose. !!! */ + void *userData; + + /** Pointers to functions implemented by the users of AVC library */ + FunctionType_DPBAlloc CBAVC_DPBAlloc; + + FunctionType_FrameBind CBAVC_FrameBind; + + FuctionType_FrameUnbind CBAVC_FrameUnbind; + + FunctionType_Malloc CBAVC_Malloc; + + FunctionType_Free CBAVC_Free; + + FunctionType_DebugLog CBAVC_DebugLog; + + /** Flag to enable debugging */ + uint32 debugEnable; + +} AVCHandle; + + + +#ifdef PVDEBUGMSG_LOG +#define DEBUG_LOG(a,b,c,d,e) CBAVC_DebugLog(a,b,c,d,e) +#else +#define DEBUG_LOG(a,b,c,d,e) +#endif + +#endif /* _AVCAPI_COMMON_H_ */ diff --git a/media/libstagefright/codecs/avc/common/include/avcint_common.h b/media/libstagefright/codecs/avc/common/include/avcint_common.h new file mode 100644 index 0000000..465e604 --- /dev/null +++ b/media/libstagefright/codecs/avc/common/include/avcint_common.h @@ -0,0 +1,882 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 file contains common code shared between AVC decoder and AVC encoder for +internal use only. +@publishedAll +*/ + +#ifndef AVCINT_COMMON_H_INCLUDED +#define AVCINT_COMMON_H_INCLUDED + +#ifndef AVCAPI_COMMON_H_INCLUDED +#include "avcapi_common.h" +#endif + + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + + + +/** +Mathematic functions defined in subclause 5.7. +Can be replaced with assembly instructions for speedup. +@publishedAll +*/ +#define AVC_ABS(x) (((x)<0)? -(x) : (x)) +#define AVC_SIGN(x) (((x)<0)? -1 : 1) +#define AVC_SIGN0(x) (((x)<0)? -1 : (((x)>0) ? 1 : 0)) +#define AVC_MAX(x,y) ((x)>(y)? (x):(y)) +#define AVC_MIN(x,y) ((x)<(y)? (x):(y)) +#define AVC_MEDIAN(A,B,C) ((A) > (B) ? ((A) < (C) ? (A) : (B) > (C) ? (B) : (C)): (B) < (C) ? (B) : (C) > (A) ? (C) : (A)) +#define AVC_CLIP3(a,b,x) (AVC_MAX(a,AVC_MIN(x,b))) /* clip x between a and b */ +#define AVC_CLIP(x) AVC_CLIP3(0,255,x) +#define AVC_FLOOR(x) ((int)(x)) +#define AVC_RASTER_SCAN(x,y,n) ((x)+(y)*(n)) +#define AVC_ROUND(x) (AVC_SIGN(x)*AVC_FLOOR(AVC_ABS(x)+0.5)) +#define AVC_INVERSE_RASTER_SCAN(a,b,c,d,e) (((e)==0)? (((a)%((d)/(b)))*(b)): (((a)/((d)/(b)))*(c))) +/* a:block address, b:block width, c:block height, d:total_width, e:x or y coordinate */ + +#define DEFAULT_ATTR 0 /* default memory attribute */ +#define FAST_MEM_ATTR 1 /* fast memory attribute */ + + +/* This section is for definition of constants. */ +#define MB_SIZE 16 +#define BLOCK_SIZE 4 +#define EMULATION_PREVENTION_THREE_BYTE 0x3 +#define NUM_PIXELS_IN_MB (24*16) +#define NUM_BLKS_IN_MB 24 + +#define AVCNumI4PredMode 9 +#define AVCNumI16PredMode 4 +#define AVCNumIChromaMode 4 + +/* constants used in the structures below */ +#define MAXIMUMVALUEOFcpb_cnt 32 /* used in HRDParams */ +#define MAX_NUM_REF_FRAMES_IN_PIC_ORDER_CNT_CYCLE 255 /* used in SeqParamSet */ +#define MAX_NUM_SLICE_GROUP 8 /* used in PicParamSet */ +#define MAX_REF_PIC_LIST_REORDERING 32 /* 32 is maximum according to Annex A, SliceHeader */ +#define MAX_DEC_REF_PIC_MARKING 64 /* 64 is the maximum possible given the max num ref pictures to 31. */ +#define MAX_FS (16+1) /* pre-defined size of frame store array */ +#define MAX_LEVEL_IDX 15 /* only 15 levels defined for now */ +#define MAX_REF_PIC_LIST 33 /* max size of the RefPicList0 and RefPicList1 */ + + +/** +Architectural related macros. +@publishedAll +*/ +#ifdef USE_PRED_BLOCK +#define MB_BASED_DEBLOCK +#endif + +/** +Picture type, PV created. +@publishedAll +*/ +typedef enum +{ + AVC_FRAME = 3 +} AVCPictureType; + +/** +This slice type follows Table 7-3. The bottom 5 items may not needed. +@publishedAll +*/ +typedef enum +{ + AVC_P_SLICE = 0, + AVC_B_SLICE = 1, + AVC_I_SLICE = 2, + AVC_SP_SLICE = 3, + AVC_SI_SLICE = 4, + AVC_P_ALL_SLICE = 5, + AVC_B_ALL_SLICE = 6, + AVC_I_ALL_SLICE = 7, + AVC_SP_ALL_SLICE = 8, + AVC_SI_ALL_SLICE = 9 +} AVCSliceType; + +/** +Types of the macroblock and partition. PV Created. +@publishedAll +*/ +typedef enum +{ + /* intra */ + AVC_I4, + AVC_I16, + AVC_I_PCM, + AVC_SI4, + + /* inter for both P and B*/ + AVC_BDirect16, + AVC_P16, + AVC_P16x8, + AVC_P8x16, + AVC_P8, + AVC_P8ref0, + AVC_SKIP +} AVCMBMode; + +/** +Enumeration for sub-macroblock mode, interpreted from sub_mb_type. +@publishedAll +*/ +typedef enum +{ + /* for sub-partition mode */ + AVC_BDirect8, + AVC_8x8, + AVC_8x4, + AVC_4x8, + AVC_4x4 +} AVCSubMBMode; + +/** +Mode of prediction of partition or sub-partition. PV Created. +Do not change the order!!! Used in table look-up mode prediction in +vlc.c. +@publishedAll +*/ +typedef enum +{ + AVC_Pred_L0 = 0, + AVC_Pred_L1, + AVC_BiPred, + AVC_Direct +} AVCPredMode; + + +/** +Mode of intra 4x4 prediction. Table 8-2 +@publishedAll +*/ +typedef enum +{ + AVC_I4_Vertical = 0, + AVC_I4_Horizontal, + AVC_I4_DC, + AVC_I4_Diagonal_Down_Left, + AVC_I4_Diagonal_Down_Right, + AVC_I4_Vertical_Right, + AVC_I4_Horizontal_Down, + AVC_I4_Vertical_Left, + AVC_I4_Horizontal_Up +} AVCIntra4x4PredMode; + +/** +Mode of intra 16x16 prediction. Table 8-3 +@publishedAll +*/ +typedef enum +{ + AVC_I16_Vertical = 0, + AVC_I16_Horizontal, + AVC_I16_DC, + AVC_I16_Plane +} AVCIntra16x16PredMode; + + +/** +Mode of intra chroma prediction. Table 8-4 +@publishedAll +*/ +typedef enum +{ + AVC_IC_DC = 0, + AVC_IC_Horizontal, + AVC_IC_Vertical, + AVC_IC_Plane +} AVCIntraChromaPredMode; + +/** +Type of residual going to residual_block_cavlc function, PV created. +@publishedAll +*/ +typedef enum +{ + AVC_Luma, + AVC_Intra16DC, + AVC_Intra16AC, + AVC_ChromaDC, + AVC_ChromaAC +} AVCResidualType; + + +/** +This structure contains VUI parameters as specified in Annex E. +Some variables may be removed from the structure if they are found to be useless to store. +@publishedAll +*/ +typedef struct tagHRDParams +{ + uint cpb_cnt_minus1; /* ue(v), range 0..31 */ + uint bit_rate_scale; /* u(4) */ + uint cpb_size_scale; /* u(4) */ + uint32 bit_rate_value_minus1[MAXIMUMVALUEOFcpb_cnt];/* ue(v), range 0..2^32-2 */ + uint32 cpb_size_value_minus1[MAXIMUMVALUEOFcpb_cnt]; /* ue(v), range 0..2^32-2 */ + uint cbr_flag[MAXIMUMVALUEOFcpb_cnt]; /* u(1) */ + uint initial_cpb_removal_delay_length_minus1; /* u(5), default 23 */ + uint cpb_removal_delay_length_minus1; /* u(5), default 23 */ + uint dpb_output_delay_length_minus1; /* u(5), default 23 */ + uint time_offset_length; /* u(5), default 24 */ +} AVCHRDParams; + +/** +This structure contains VUI parameters as specified in Annex E. +Some variables may be removed from the structure if they are found to be useless to store. +@publishedAll +*/ +typedef struct tagVUIParam +{ + uint aspect_ratio_info_present_flag; /* u(1) */ + uint aspect_ratio_idc; /* u(8), table E-1 */ + uint sar_width; /* u(16) */ + uint sar_height; /* u(16) */ + uint overscan_info_present_flag; /* u(1) */ + uint overscan_appropriate_flag; /* u(1) */ + uint video_signal_type_present_flag; /* u(1) */ + uint video_format; /* u(3), Table E-2, default 5, unspecified */ + uint video_full_range_flag; /* u(1) */ + uint colour_description_present_flag; /* u(1) */ + uint colour_primaries; /* u(8), Table E-3, default 2, unspecified */ + uint transfer_characteristics; /* u(8), Table E-4, default 2, unspecified */ + uint matrix_coefficients; /* u(8), Table E-5, default 2, unspecified */ + uint chroma_location_info_present_flag; /* u(1) */ + uint chroma_sample_loc_type_top_field; /* ue(v), Fig. E-1range 0..5, default 0 */ + uint chroma_sample_loc_type_bottom_field; /* ue(v) */ + uint timing_info_present_flag; /* u(1) */ + uint num_units_in_tick; /* u(32), must be > 0 */ + uint time_scale; /* u(32), must be > 0 */ + uint fixed_frame_rate_flag; /* u(1), Eq. C-13 */ + uint nal_hrd_parameters_present_flag; /* u(1) */ + AVCHRDParams nal_hrd_parameters; /* hrd_paramters */ + uint vcl_hrd_parameters_present_flag; /* u(1) */ + AVCHRDParams vcl_hrd_parameters; /* hrd_paramters */ + /* if ((nal_hrd_parameters_present_flag || (vcl_hrd_parameters_present_flag)) */ + uint low_delay_hrd_flag; /* u(1) */ + uint pic_struct_present_flag; + uint bitstream_restriction_flag; /* u(1) */ + uint motion_vectors_over_pic_boundaries_flag; /* u(1) */ + uint max_bytes_per_pic_denom; /* ue(v), default 2 */ + uint max_bits_per_mb_denom; /* ue(v), range 0..16, default 1 */ + uint log2_max_mv_length_vertical; /* ue(v), range 0..16, default 16 */ + uint log2_max_mv_length_horizontal; /* ue(v), range 0..16, default 16 */ + uint max_dec_frame_reordering; /* ue(v) */ + uint max_dec_frame_buffering; /* ue(v) */ +} AVCVUIParams; + + +/** +This structure contains information in a sequence parameter set NAL. +Some variables may be removed from the structure if they are found to be useless to store. +@publishedAll +*/ +typedef struct tagSeqParamSet +{ + uint Valid; /* indicates the parameter set is valid */ + + uint profile_idc; /* u(8) */ + uint constrained_set0_flag; /* u(1) */ + uint constrained_set1_flag; /* u(1) */ + uint constrained_set2_flag; /* u(1) */ + uint constrained_set3_flag; /* u(1) */ + uint level_idc; /* u(8) */ + uint seq_parameter_set_id; /* ue(v), range 0..31 */ + uint log2_max_frame_num_minus4; /* ue(v), range 0..12 */ + uint pic_order_cnt_type; /* ue(v), range 0..2 */ + /* if( pic_order_cnt_type == 0 ) */ + uint log2_max_pic_order_cnt_lsb_minus4; /* ue(v), range 0..12 */ + /* else if( pic_order_cnt_type == 1 ) */ + uint delta_pic_order_always_zero_flag; /* u(1) */ + int32 offset_for_non_ref_pic; /* se(v) */ + int32 offset_for_top_to_bottom_field; /* se(v) */ + uint num_ref_frames_in_pic_order_cnt_cycle; /* ue(v) , range 0..255 */ + /* for( i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ ) */ + int32 offset_for_ref_frame[MAX_NUM_REF_FRAMES_IN_PIC_ORDER_CNT_CYCLE]; /* se(v) */ + uint num_ref_frames; /* ue(v), range 0..16 */ + uint gaps_in_frame_num_value_allowed_flag; /* u(1) */ + uint pic_width_in_mbs_minus1; /* ue(v) */ + uint pic_height_in_map_units_minus1; /* ue(v) */ + uint frame_mbs_only_flag; /* u(1) */ + /* if( !frame_mbs_only_flag ) */ + uint mb_adaptive_frame_field_flag; /* u(1) */ + uint direct_8x8_inference_flag; /* u(1), must be 1 when frame_mbs_only_flag is 0 */ + uint frame_cropping_flag; /* u(1) */ + /* if( frmae_cropping_flag) */ + uint frame_crop_left_offset; /* ue(v) */ + uint frame_crop_right_offset; /* ue(v) */ + uint frame_crop_top_offset; /* ue(v) */ + uint frame_crop_bottom_offset; /* ue(v) */ + uint vui_parameters_present_flag; /* u(1) */ +// uint nal_hrd_parameters_present_flag; +// uint vcl_hrd_parameters_present_flag; +// AVCHRDParams *nal_hrd_parameters; +// AVCHRDParams *vcl_hrd_parameters; + AVCVUIParams vui_parameters; /* AVCVUIParam */ +} AVCSeqParamSet; + +/** +This structure contains information in a picture parameter set NAL. +Some variables may be removed from the structure if they are found to be useless to store. +@publishedAll +*/ +typedef struct tagPicParamSet +{ + uint pic_parameter_set_id; /* ue(v), range 0..255 */ + uint seq_parameter_set_id; /* ue(v), range 0..31 */ + uint entropy_coding_mode_flag; /* u(1) */ + uint pic_order_present_flag; /* u(1) */ + uint num_slice_groups_minus1; /* ue(v), range in Annex A */ + /* if( num_slice_groups_minus1 > 0) */ + uint slice_group_map_type; /* ue(v), range 0..6 */ + /* if( slice_group_map_type = = 0 ) */ + /* for(0:1:num_slice_groups_minus1) */ + uint run_length_minus1[MAX_NUM_SLICE_GROUP]; /* ue(v) */ + /* else if( slice_group_map_type = = 2 ) */ + /* for(0:1:num_slice_groups_minus1-1) */ + uint top_left[MAX_NUM_SLICE_GROUP-1]; /* ue(v) */ + uint bottom_right[MAX_NUM_SLICE_GROUP-1]; /* ue(v) */ + /* else if( slice_group_map_type = = 3 || 4 || 5 */ + uint slice_group_change_direction_flag; /* u(1) */ + uint slice_group_change_rate_minus1; /* ue(v) */ + /* else if( slice_group_map_type = = 6 ) */ + uint pic_size_in_map_units_minus1; /* ue(v) */ + /* for(0:1:pic_size_in_map_units_minus1) */ + uint *slice_group_id; /* complete MBAmap u(v) */ + uint num_ref_idx_l0_active_minus1; /* ue(v), range 0..31 */ + uint num_ref_idx_l1_active_minus1; /* ue(v), range 0..31 */ + uint weighted_pred_flag; /* u(1) */ + uint weighted_bipred_idc; /* u(2), range 0..2 */ + int pic_init_qp_minus26; /* se(v), range -26..25 */ + int pic_init_qs_minus26; /* se(v), range -26..25 */ + int chroma_qp_index_offset; /* se(v), range -12..12 */ + uint deblocking_filter_control_present_flag; /* u(1) */ + uint constrained_intra_pred_flag; /* u(1) */ + uint redundant_pic_cnt_present_flag; /* u(1) */ +} AVCPicParamSet; + + +/** +This structure contains slice header information. +Some variables may be removed from the structure if they are found to be useless to store. +@publishedAll +*/ +typedef struct tagSliceHeader +{ + uint first_mb_in_slice; /* ue(v) */ + AVCSliceType slice_type; /* ue(v), Table 7-3, range 0..9 */ + uint pic_parameter_set_id; /* ue(v), range 0..255 */ + uint frame_num; /* u(v), see log2max_frame_num_minus4 */ + /* if( !frame_mbs_only_flag) */ + uint field_pic_flag; /* u(1) */ + /* if(field_pic_flag) */ + uint bottom_field_flag; /* u(1) */ + /* if(nal_unit_type == 5) */ + uint idr_pic_id; /* ue(v), range 0..65535 */ + /* if(pic_order_cnt_type==0) */ + uint pic_order_cnt_lsb; /* u(v), range 0..MaxPicOrderCntLsb-1 */ + /* if(pic_order_present_flag && !field_pic_flag) */ + int32 delta_pic_order_cnt_bottom; /* se(v) */ + /* if(pic_order_cnt_type==1 && !delta_pic_order_always_zero_flag) */ + /* if(pic_order_present_flag && !field_pic_flag) */ + int32 delta_pic_order_cnt[2]; + /* if(redundant_pic_cnt_present_flag) */ + uint redundant_pic_cnt; /* ue(v), range 0..127 */ + /* if(slice_type == B) */ + uint direct_spatial_mv_pred_flag; /* u(1) */ + /* if(slice_type == P || slice_type==SP || slice_type==B) */ + uint num_ref_idx_active_override_flag; /* u(1) */ + /* if(num_ref_idx_active_override_flag) */ + uint num_ref_idx_l0_active_minus1; /* ue(v) */ + /* if(slie_type == B) */ + uint num_ref_idx_l1_active_minus1; /* ue(v) */ + + /* ref_pic_list_reordering() */ + uint ref_pic_list_reordering_flag_l0; /* u(1) */ + uint reordering_of_pic_nums_idc_l0[MAX_REF_PIC_LIST_REORDERING]; /* ue(v), range 0..3 */ + uint abs_diff_pic_num_minus1_l0[MAX_REF_PIC_LIST_REORDERING]; /* ue(v) */ + uint long_term_pic_num_l0[MAX_REF_PIC_LIST_REORDERING]; /* ue(v) */ + uint ref_pic_list_reordering_flag_l1; /* u(1) */ + uint reordering_of_pic_nums_idc_l1[MAX_REF_PIC_LIST_REORDERING]; /* ue(v), range 0..3 */ + uint abs_diff_pic_num_minus1_l1[MAX_REF_PIC_LIST_REORDERING]; /* ue(v) */ + uint long_term_pic_num_l1[MAX_REF_PIC_LIST_REORDERING]; /* ue(v) */ + + /* end ref_pic_list_reordering() */ + /* if(nal_ref_idc!=0) */ + /* dec_ref_pic_marking() */ + uint no_output_of_prior_pics_flag; /* u(1) */ + uint long_term_reference_flag; /* u(1) */ + uint adaptive_ref_pic_marking_mode_flag; /* u(1) */ + uint memory_management_control_operation[MAX_DEC_REF_PIC_MARKING]; /* ue(v), range 0..6 */ + uint difference_of_pic_nums_minus1[MAX_DEC_REF_PIC_MARKING]; /* ue(v) */ + uint long_term_pic_num[MAX_DEC_REF_PIC_MARKING]; /* ue(v) */ + uint long_term_frame_idx[MAX_DEC_REF_PIC_MARKING]; /* ue(v) */ + uint max_long_term_frame_idx_plus1[MAX_DEC_REF_PIC_MARKING]; /* ue(v) */ + /* end dec_ref_pic_marking() */ + /* if(entropy_coding_mode_flag && slice_type!=I && slice_type!=SI) */ + uint cabac_init_idc; /* ue(v), range 0..2 */ + int slice_qp_delta; /* se(v), range 0..51 */ + /* if(slice_type==SP || slice_type==SI) */ + /* if(slice_type==SP) */ + uint sp_for_switch_flag; /* u(1) */ + int slice_qs_delta; /* se(v) */ + + /* if(deblocking_filter_control_present_flag)*/ + uint disable_deblocking_filter_idc; /* ue(v), range 0..2 */ + /* if(disable_deblocking_filter_idc!=1) */ + int slice_alpha_c0_offset_div2; /* se(v), range -6..6, default 0 */ + int slice_beta_offset_div_2; /* se(v), range -6..6, default 0 */ + /* if(num_slice_groups_minus1>0 && slice_group_map_type>=3 && slice_group_map_type<=5)*/ + uint slice_group_change_cycle; /* u(v), use ceil(log2(PicSizeInMapUnits/SliceGroupChangeRate + 1)) bits*/ + +} AVCSliceHeader; + +/** +This struct contains information about the neighboring pixel. +@publishedAll +*/ +typedef struct tagPixPos +{ + int available; + int mb_addr; /* macroblock address of the current pixel, see below */ + int x; /* x,y positions of current pixel relative to the macroblock mb_addr */ + int y; + int pos_x; /* x,y positions of current pixel relative to the picture. */ + int pos_y; +} AVCPixelPos; + +typedef struct tagNeighborAvailability +{ + int left; + int top; /* macroblock address of the current pixel, see below */ + int top_right; /* x,y positions of current pixel relative to the macroblock mb_addr */ +} AVCNeighborAvailability; + + +/** +This structure contains picture data and related information necessary to be used as +reference frame. +@publishedAll +*/ +typedef struct tagPictureData +{ + uint16 RefIdx; /* index used for reference frame */ + uint8 *Sl; /* derived from base_dpb in AVCFrameStore */ + uint8 *Scb; /* for complementary fields, YUV are interlaced */ + uint8 *Scr; /* Sl of top_field and bottom_fields will be one line apart and the + stride will be 2 times the width. */ + /* For non-complementary field, the above still applies. A special + output formatting is required. */ + + /* Then, necessary variables that need to be stored */ + AVCPictureType picType; /* frame, top-field or bot-field */ + /*bool*/ + uint isReference; + /*bool*/ + uint isLongTerm; + int PicOrderCnt; + int PicNum; + int LongTermPicNum; + + int width; /* how many pixel per line */ + int height;/* how many line */ + int pitch; /* how many pixel between the line */ + + uint padded; /* flag for being padded */ + +} AVCPictureData; + +/** +This structure contains information for frame storage. +@publishedAll +*/ +typedef struct tagFrameStore +{ + uint8 *base_dpb; /* base pointer for the YCbCr */ + + int IsReference; /* 0=not used for ref; 1=top used; 2=bottom used; 3=both fields (or frame) used */ + int IsLongTerm; /* 0=not used for ref; 1=top used; 2=bottom used; 3=both fields (or frame) used */ + /* if IsLongTerm is true, IsReference can be ignored. */ + /* if IsReference is true, IsLongterm will be checked for short-term or long-term. */ + /* IsUsed must be true to enable the validity of IsReference and IsLongTerm */ + + int IsOutputted; /* has it been outputted via AVCDecGetOutput API, then don't output it again, + wait until it is returned. */ + AVCPictureData frame; + + int FrameNum; + int FrameNumWrap; + int LongTermFrameIdx; + int PicOrderCnt; /* of the frame, smaller of the 2 fields */ + +} AVCFrameStore; + +/** +This structure maintains the actual memory for the decoded picture buffer (DPB) which is +allocated at the beginning according to profile/level. +Once decoded_picture_buffer is allocated, Sl,Scb,Scr in +AVCPictureData structure just point to the address in decoded_picture_buffer. +used_size maintains the used space. +NOTE:: In order to maintain contiguous memory space, memory equal to a single frame is +assigned at a time. Two opposite fields reside in the same frame memory. + + |-------|---|---|---|xxx|-------|xxx|---|-------| decoded_picture_buffer + frame top bot top frame bot frame + 0 1 1 2 3 4 5 + + bot 2 and top 4 do not exist, the memory is not used. + +@publishedAll +*/ +typedef struct tagDecPicBuffer +{ + uint8 *decoded_picture_buffer; /* actual memory */ + uint32 dpb_size; /* size of dpb in bytes */ + uint32 used_size; /* used size */ + struct tagFrameStore *fs[MAX_FS]; /* list of frame stored, actual buffer */ + int num_fs; /* size of fs */ + +} AVCDecPicBuffer; + + +/** +This structure contains macroblock related variables. +@publishedAll +*/ +typedef struct tagMacroblock +{ + AVCIntraChromaPredMode intra_chroma_pred_mode; /* ue(v) */ + + int32 mvL0[16]; /* motion vectors, 16 bit packed (x,y) per element */ + int32 mvL1[16]; + int16 ref_idx_L0[4]; + int16 ref_idx_L1[4]; + uint16 RefIdx[4]; /* ref index, has value of AVCPictureData->RefIdx */ + /* stored data */ + /*bool*/ + uint mb_intra; /* intra flag */ + /*bool*/ + uint mb_bottom_field; + + AVCMBMode mbMode; /* type of MB prediction */ + AVCSubMBMode subMbMode[4]; /* for each 8x8 partition */ + + uint CBP; /* CodeBlockPattern */ + AVCIntra16x16PredMode i16Mode; /* Intra16x16PredMode */ + AVCIntra4x4PredMode i4Mode[16]; /* Intra4x4PredMode, in raster scan order */ + int NumMbPart; /* number of partition */ + AVCPredMode MBPartPredMode[4][4]; /* prediction mode [MBPartIndx][subMBPartIndx] */ + int MbPartWidth; + int MbPartHeight; + int NumSubMbPart[4]; /* for each 8x8 partition */ + int SubMbPartWidth[4]; /* for each 8x8 partition */ + int SubMbPartHeight[4]; /* for each 8x8 partition */ + + uint8 nz_coeff[NUM_BLKS_IN_MB]; /* [blk_y][blk_x], Chroma is [4..5][0...3], see predict_nnz() function */ + + int QPy; /* Luma QP */ + int QPc; /* Chroma QP */ + int QSc; /* Chroma QP S-picture */ + + int slice_id; // MC slice +} AVCMacroblock; + + +/** +This structure contains common internal variables between the encoder and decoder +such that some functions can be shared among them. +@publishedAll +*/ +typedef struct tagCommonObj +{ + /* put these 2 up here to make sure they are word-aligned */ + int16 block[NUM_PIXELS_IN_MB]; /* for transformed residue coefficient */ + uint8 *pred_block; /* pointer to prediction block, could point to a frame */ +#ifdef USE_PRED_BLOCK + uint8 pred[688]; /* for prediction */ + /* Luma [0-399], Cb [400-543], Cr[544-687] */ +#endif + int pred_pitch; /* either equal to 20 or to frame pitch */ + + /* temporary buffers for intra prediction */ + /* these variables should remain inside fast RAM */ +#ifdef MB_BASED_DEBLOCK + uint8 *intra_pred_top; /* a row of pixel for intra prediction */ + uint8 intra_pred_left[17]; /* a column of pixel for intra prediction */ + uint8 *intra_pred_top_cb; + uint8 intra_pred_left_cb[9]; + uint8 *intra_pred_top_cr; + uint8 intra_pred_left_cr[9]; +#endif + /* pointer to the prediction area for intra prediction */ + uint8 *pintra_pred_top; /* pointer to the top intra prediction value */ + uint8 *pintra_pred_left; /* pointer to the left intra prediction value */ + uint8 intra_pred_topleft; /* the [-1,-1] neighboring pixel */ + uint8 *pintra_pred_top_cb; + uint8 *pintra_pred_left_cb; + uint8 intra_pred_topleft_cb; + uint8 *pintra_pred_top_cr; + uint8 *pintra_pred_left_cr; + uint8 intra_pred_topleft_cr; + + int QPy; + int QPc; + int QPy_div_6; + int QPy_mod_6; + int QPc_div_6; + int QPc_mod_6; + /**** nal_unit ******/ + /* previously in AVCNALUnit format */ + uint NumBytesInRBSP; + int forbidden_bit; + int nal_ref_idc; + AVCNalUnitType nal_unit_type; + AVCNalUnitType prev_nal_unit_type; + /*bool*/ + uint slice_data_partitioning; /* flag when nal_unit_type is between 2 and 4 */ + /**** ******** ******/ + AVCSliceType slice_type; + AVCDecPicBuffer *decPicBuf; /* decoded picture buffer */ + + AVCSeqParamSet *currSeqParams; /* the currently used one */ + + AVCPicParamSet *currPicParams; /* the currently used one */ + uint seq_parameter_set_id; + /* slice header */ + AVCSliceHeader *sliceHdr; /* slice header param syntax variables */ + + AVCPictureData *currPic; /* pointer to current picture */ + AVCFrameStore *currFS; /* pointer to current frame store */ + AVCPictureType currPicType; /* frame, top-field or bot-field */ + /*bool*/ + uint newPic; /* flag for new picture */ + uint newSlice; /* flag for new slice */ + AVCPictureData *prevRefPic; /* pointer to previous picture */ + + AVCMacroblock *mblock; /* array of macroblocks covering entire picture */ + AVCMacroblock *currMB; /* pointer to current macroblock */ + uint mbNum; /* number of current MB */ + int mb_x; /* x-coordinate of the current mbNum */ + int mb_y; /* y-coordinate of the current mbNum */ + + /* For internal operation, scratch memory for MV, prediction, transform, etc.*/ + uint32 cbp4x4; /* each bit represent nonzero 4x4 block in reverse raster scan order */ + /* starting from luma, Cb and Cr, lsb toward msb */ + int mvd_l0[4][4][2]; /* [mbPartIdx][subMbPartIdx][compIdx], se(v) */ + int mvd_l1[4][4][2]; /* [mbPartIdx][subMbPartIdx][compIdx], se(v) */ + + int mbAddrA, mbAddrB, mbAddrC, mbAddrD; /* address of neighboring MBs */ + /*bool*/ + uint mbAvailA, mbAvailB, mbAvailC, mbAvailD; /* availability */ + /*bool*/ + uint intraAvailA, intraAvailB, intraAvailC, intraAvailD; /* for intra mode */ + /***********************************************/ + /* The following variables are defined in the draft. */ + /* They may need to be stored in PictureData structure and used for reference. */ + /* In that case, just move or copy it to AVCDecPictureData structure. */ + + int padded_size; /* size of extra padding to a frame */ + + uint MaxFrameNum; /*2^(log2_max_frame_num_minus4+4), range 0.. 2^16-1 */ + uint MaxPicOrderCntLsb; /*2^(log2_max_pic_order_cnt_lsb_minus4+4), 0..2^16-1 */ + uint PicWidthInMbs; /*pic_width_in_mbs_minus1+1 */ + uint PicWidthInSamplesL; /* PicWidthInMbs*16 */ + uint PicWidthInSamplesC; /* PicWIdthInMbs*8 */ + uint PicHeightInMapUnits; /* pic_height_in_map_units_minus1+1 */ + uint PicSizeInMapUnits; /* PicWidthInMbs*PicHeightInMapUnits */ + uint FrameHeightInMbs; /*(2-frame_mbs_only_flag)*PicHeightInMapUnits */ + + uint SliceGroupChangeRate; /* slice_group_change_rate_minus1 + 1 */ + + /* access unit */ + uint primary_pic_type; /* u(3), Table 7-2, kinda informative only */ + + /* slice data partition */ + uint slice_id; /* ue(v) */ + + uint UnusedShortTermFrameNum; + uint PrevRefFrameNum; + uint MbaffFrameFlag; /* (mb_adaptive_frame_field_flag && !field_pic_flag) */ + uint PicHeightInMbs; /* FrameHeightInMbs/(1+field_pic_flag) */ + int PicHeightInSamplesL; /* PicHeightInMbs*16 */ + int PicHeightInSamplesC; /* PicHeightInMbs*8 */ + uint PicSizeInMbs; /* PicWidthInMbs*PicHeightInMbs */ + uint level_idc; + int numMBs; + uint MaxPicNum; + uint CurrPicNum; + int QSy; /* 26+pic_init_qp_minus26+slice_qs_delta */ + int FilterOffsetA; + int FilterOffsetB; + uint MapUnitsInSliceGroup0; /* Min(slie_group_change_cycle*SliceGroupChangeRate,PicSizeInMapUnits) */ + /* dec_ref_pic_marking */ + int MaxLongTermFrameIdx; + int LongTermFrameIdx; + + /* POC related variables */ + /*bool*/ + uint mem_mgr_ctrl_eq_5; /* if memory_management_control_operation equal to 5 flag */ + int PicOrderCnt; + int BottomFieldOrderCnt, TopFieldOrderCnt; + /* POC mode 0 */ + int prevPicOrderCntMsb; + uint prevPicOrderCntLsb; + int PicOrderCntMsb; + /* POC mode 1 */ + int prevFrameNumOffset, FrameNumOffset; + uint prevFrameNum; + int absFrameNum; + int picOrderCntCycleCnt, frameNumInPicOrderCntCycle; + int expectedDeltaPerPicOrderCntCycle; + int expectedPicOrderCnt; + + /* FMO */ + int *MbToSliceGroupMap; /* to be re-calculate at the beginning */ + + /* ref pic list */ + AVCPictureData *RefPicList0[MAX_REF_PIC_LIST]; /* list 0 */ + AVCPictureData *RefPicList1[MAX_REF_PIC_LIST]; /* list 1 */ + AVCFrameStore *refFrameList0ShortTerm[32]; + AVCFrameStore *refFrameList1ShortTerm[32]; + AVCFrameStore *refFrameListLongTerm[32]; + int refList0Size; + int refList1Size; + + /* slice data semantics*/ + int mb_skip_run; /* ue(v) */ + /*uint mb_skip_flag;*/ /* ae(v) */ + /* uint end_of_slice_flag;*//* ae(v) */ + /***********************************************/ + + /* function pointers */ + int (*is_short_ref)(AVCPictureData *s); + int (*is_long_ref)(AVCPictureData *s); + +} AVCCommonObj; + +/** +Commonly used constant arrays. +@publishedAll +*/ +/** +Zigzag scan from 1-D to 2-D. */ +const static uint8 ZZ_SCAN[16] = {0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15}; +/* Zigzag scan from 1-D to 2-D output to block[24][16]. */ +const static uint8 ZZ_SCAN_BLOCK[16] = {0, 1, 16, 32, 17, 2, 3, 18, 33, 48, 49, 34, 19, 35, 50, 51}; + +/** +From zigzag to raster for luma DC value */ +const static uint8 ZIGZAG2RASTERDC[16] = {0, 4, 64, 128, 68, 8, 12, 72, 132, 192, 196, 136, 76, 140, 200, 204}; + + +/** +Mapping from coding scan block indx to raster scan block index */ +const static int blkIdx2blkX[16] = {0, 1, 0, 1, 2, 3, 2, 3, 0, 1, 0, 1, 2, 3, 2, 3}; +const static int blkIdx2blkY[16] = {0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 3, 3, 2, 2, 3, 3}; +/** from [blk8indx][blk4indx] to raster scan index */ +const static int blkIdx2blkXY[4][4] = {{0, 1, 4, 5}, {2, 3, 6, 7}, {8, 9, 12, 13}, {10, 11, 14, 15}}; + +/* +Availability of the neighboring top-right block relative to the current block. */ +const static int BlkTopRight[16] = {2, 2, 2, 3, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0}; + +/** +Table 8-13 Specification of QPc as a function of qPI. */ +const static uint8 mapQPi2QPc[52] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 34, 35, 35, 36, 36, + 37, 37, 37, 38, 38, 38, 39, 39, 39, 39 + }; + +/** +See 8.5.5 equation (8-252 and 8-253) the definition of v matrix. */ +/* in zigzag scan */ +const static int dequant_coefres[6][16] = +{ + {10, 13, 13, 10, 16, 10, 13, 13, 13, 13, 16, 10, 16, 13, 13, 16}, + {11, 14, 14, 11, 18, 11, 14, 14, 14, 14, 18, 11, 18, 14, 14, 18}, + {13, 16, 16, 13, 20, 13, 16, 16, 16, 16, 20, 13, 20, 16, 16, 20}, + {14, 18, 18, 14, 23, 14, 18, 18, 18, 18, 23, 14, 23, 18, 18, 23}, + {16, 20, 20, 16, 25, 16, 20, 20, 20, 20, 25, 16, 25, 20, 20, 25}, + {18, 23, 23, 18, 29, 18, 23, 23, 23, 23, 29, 18, 29, 23, 23, 29} +}; + +/** +From jm7.6 block.c. (in zigzag scan) */ +const static int quant_coef[6][16] = +{ + {13107, 8066, 8066, 13107, 5243, 13107, 8066, 8066, 8066, 8066, 5243, 13107, 5243, 8066, 8066, 5243}, + {11916, 7490, 7490, 11916, 4660, 11916, 7490, 7490, 7490, 7490, 4660, 11916, 4660, 7490, 7490, 4660}, + {10082, 6554, 6554, 10082, 4194, 10082, 6554, 6554, 6554, 6554, 4194, 10082, 4194, 6554, 6554, 4194}, + {9362, 5825, 5825, 9362, 3647, 9362, 5825, 5825, 5825, 5825, 3647, 9362, 3647, 5825, 5825, 3647}, + {8192, 5243, 5243, 8192, 3355, 8192, 5243, 5243, 5243, 5243, 3355, 8192, 3355, 5243, 5243, 3355}, + {7282, 4559, 4559, 7282, 2893, 7282, 4559, 4559, 4559, 4559, 2893, 7282, 2893, 4559, 4559, 2893} +}; + +/** +Convert scan from raster scan order to block decoding order and +from block decoding order to raster scan order. Same table!!! +*/ +const static uint8 ras2dec[16] = {0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15}; + +/* mapping from level_idc to index map */ +const static uint8 mapLev2Idx[61] = {255, 255, 255, 255, 255, 255, 255, 255, 255, 1, + 0, 1, 2, 3, 255, 255, 255, 255, 255, 255, + 4, 5, 6, 255, 255, 255, 255, 255, 255, 255, + 7, 8, 9, 255, 255, 255, 255, 255, 255, 255, + 10, 11, 12, 255, 255, 255, 255, 255, 255, 255, + 13, 14, 255, 255, 255, 255, 255, 255, 255, 255 + }; +/* map back from index to Level IDC */ +const static uint8 mapIdx2Lev[MAX_LEVEL_IDX] = {10, 11, 12, 13, 20, 21, 22, 30, 31, 32, 40, 41, 42, 50, 51}; + +/** +from the index map to the MaxDPB value times 2 */ +const static int32 MaxDPBX2[MAX_LEVEL_IDX] = {297, 675, 1782, 1782, 1782, 3564, 6075, 6075, + 13500, 15360, 24576, 24576, 24576, 82620, 138240 + }; + +/* map index to the max frame size */ +const static int MaxFS[MAX_LEVEL_IDX] = {99, 396, 396, 396, 396, 792, 1620, 1620, 3600, 5120, + 8192, 8192, 8192, 22080, 36864 + }; + +/* map index to max MB processing rate */ +const static int32 MaxMBPS[MAX_LEVEL_IDX] = {1485, 3000, 6000, 11880, 11880, 19800, 20250, 40500, + 108000, 216000, 245760, 245760, 491520, 589824, 983040 + }; + +/* map index to max video bit rate */ +const static uint32 MaxBR[MAX_LEVEL_IDX] = {64, 192, 384, 768, 2000, 4000, 4000, 10000, 14000, 20000, + 20000, 50000, 50000, 135000, 240000 + }; + +/* map index to max CPB size */ +const static uint32 MaxCPB[MAX_LEVEL_IDX] = {175, 500, 1000, 2000, 2000, 4000, 4000, 10000, 14000, + 20000, 25000, 62500, 62500, 135000, 240000 + }; + +/* map index to max vertical MV range */ +const static int MaxVmvR[MAX_LEVEL_IDX] = {64, 128, 128, 128, 128, 256, 256, 256, 512, 512, 512, 512, 512, 512, 512}; + +#endif /* _AVCINT_COMMON_H_ */ diff --git a/media/libstagefright/codecs/avc/common/include/avclib_common.h b/media/libstagefright/codecs/avc/common/include/avclib_common.h new file mode 100644 index 0000000..e98396e --- /dev/null +++ b/media/libstagefright/codecs/avc/common/include/avclib_common.h @@ -0,0 +1,555 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 file contains declarations of internal functions for common encoder/decoder library. +@publishedAll +*/ +#ifndef AVCCOMMON_LIB_H_INCLUDED +#define AVCCOMMON_LIB_H_INCLUDED + +#ifndef AVCINT_COMMON_H_INCLUDED +#include "avcint_common.h" +#endif + +/*----------- deblock.c --------------*/ +/** +This function performs conditional deblocking on a complete picture. +\param "video" "Pointer to AVCCommonObj." +\return "AVC_SUCCESS for success and AVC_FAIL otherwise." +*/ +OSCL_IMPORT_REF AVCStatus DeblockPicture(AVCCommonObj *video); + +/** +This function performs MB-based deblocking when MB_BASED_DEBLOCK +is defined at compile time. +\param "video" "Pointer to AVCCommonObj." +\return "AVC_SUCCESS for success and AVC_FAIL otherwise." +*/ +void MBInLoopDeblock(AVCCommonObj *video); + + +/*---------- dpb.c --------------------*/ +/** +This function is called everytime a new sequence is detected. +\param "avcHandle" "Pointer to AVCHandle." +\param "video" "Pointer to AVCCommonObj." +\param "padding" "Flag specifying whether padding in luma component is needed (used for encoding)." +\return "AVC_SUCCESS or AVC_FAIL." +*/ +OSCL_IMPORT_REF AVCStatus AVCConfigureSequence(AVCHandle *avcHandle, AVCCommonObj *video, bool padding); + +/** +This function allocates and initializes the decoded picture buffer structure based on +the profile and level for the first sequence parameter set. Currently, +it does not allow changing in profile/level for subsequent SPS. +\param "avcHandle" "Pointer to AVCHandle." +\param "video" "Pointer to AVCCommonObj." +\param "FrameHeightInMbs" "Height of the frame in the unit of MBs." +\param "PicWidthInMbs" "Width of the picture in the unit of MBs." +\param "padding" "Flag specifying whether padding in luma component is needed (used for encoding)." +\return "AVC_SUCCESS or AVC_FAIL." +*/ +AVCStatus InitDPB(AVCHandle *avcHandle, AVCCommonObj *video, int FrameHeightInMbs, int PicWidthInMbs, bool padding); + +/** +This function frees the DPB memory. +\param "avcHandle" "Pointer to AVCHandle." +\param "video" "Pointer to AVCCommonObj." +\return "AVC_SUCCESS or AVC_FAIL." +*/ +OSCL_IMPORT_REF AVCStatus CleanUpDPB(AVCHandle *avcHandle, AVCCommonObj *video); + +/** +This function finds empty frame in the decoded picture buffer to be used for the +current picture, initializes the corresponding picture structure with Sl, Scb, Scr, +width, height and pitch. +\param "avcHandle" "Pointer to the main handle object." +\param "video" "Pointer to AVCCommonObj." +\return "AVC_SUCCESS or AVC_FAIL." +*/ +OSCL_IMPORT_REF AVCStatus DPBInitBuffer(AVCHandle *avcHandle, AVCCommonObj *video); +/** +This function finds empty frame in the decoded picture buffer to be used for the +current picture, initializes the corresponding picture structure with Sl, Scb, Scr, +width, height and pitch. +\param "video" "Pointer to AVCCommonObj." +\param "CurrPicNum" "Current picture number (only used in decoder)." +\return "AVC_SUCCESS or AVC_FAIL." +*/ + +OSCL_IMPORT_REF void DPBInitPic(AVCCommonObj *video, int CurrPicNum); + +/** +This function releases the current frame back to the available pool for skipped frame after encoding. +\param "avcHandle" "Pointer to the main handle object." +\param "video" "Pointer to the AVCCommonObj." +\return "void." +*/ +OSCL_IMPORT_REF void DPBReleaseCurrentFrame(AVCHandle *avcHandle, AVCCommonObj *video); + +/** +This function performs decoded reference picture marking process and store the current picture to the +corresponding frame storage in the decoded picture buffer. +\param "avcHandle" "Pointer to the main handle object." +\param "video" "Pointer to the AVCCommonObj." +\return "AVC_SUCCESS or AVC_FAIL." +*/ +OSCL_IMPORT_REF AVCStatus StorePictureInDPB(AVCHandle *avcHandle, AVCCommonObj *video); + +/** +This function perform sliding window operation on the reference picture lists, see subclause 8.2.5.3. +It removes short-term ref frames with smallest FrameNumWrap from the reference list. +\param "avcHandle" "Pointer to the main handle object." +\param "video" "Pointer to the AVCCommonObj." +\param "dpb" "Pointer to the AVCDecPicBuffer." +\return "AVC_SUCCESS or AVC_FAIL (contradicting values or scenario as in the Note in the draft)." +*/ +AVCStatus sliding_window_process(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb); + + +/** +This function perform adaptive memory marking operation on the reference picture lists, +see subclause 8.2.5.4. It calls other functions for specific operations. +\param "video" "Pointer to the AVCCommonObj." +\param "dpb" "Pointer to the AVCDecPicBuffer." +\param "sliceHdr" "Pointer to the AVCSliceHeader." +\return "AVC_SUCCESS or AVC_FAIL (contradicting values or scenario as in the Note in the draft)." +*/ +AVCStatus adaptive_memory_marking(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, AVCSliceHeader *sliceHdr); + +/** +This function performs memory management control operation 1, marking a short-term picture +as unused for reference. See subclause 8.2.5.4.1. +\param "video" "Pointer to the AVCCommonObj." +\param "dpb" "Pointer to the AVCDecPicBuffer." +\param "difference_of_pic_nums_minus1" "From the syntax in dec_ref_pic_marking()." +*/ +void MemMgrCtrlOp1(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, int difference_of_pic_nums_minus1); + +/** +This function performs memory management control operation 2, marking a long-term picture +as unused for reference. See subclause 8.2.5.4.2. +\param "dpb" "Pointer to the AVCDecPicBuffer." +\param "field_pic_flag" "Flag whether the current picture is field or not." +\param "long_term_pic_num" "From the syntax in dec_ref_pic_marking()." +*/ +void MemMgrCtrlOp2(AVCHandle *avcHandle, AVCDecPicBuffer *dpb, int long_term_pic_num); + +/** +This function performs memory management control operation 3, assigning a LongTermFrameIdx to +a short-term reference picture. See subclause 8.2.5.4.3. +\param "video" "Pointer to the AVCCommonObj." +\param "dpb" "Pointer to the AVCDecPicBuffer." +\param "difference_of_pic_nums_minus1" "From the syntax in dec_ref_pic_marking()." +\param "long_term_pic_num" "From the syntax in dec_ref_pic_marking()." +*/ +void MemMgrCtrlOp3(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, uint difference_of_pic_nums_minus1, + uint long_term_frame_idx); + +/** +This function performs memory management control operation 4, getting new MaxLongTermFrameIdx. + See subclause 8.2.5.4.4. +\param "video" "Pointer to the AVCCommonObj." +\param "dpb" "Pointer to the AVCDecPicBuffer." +\param "max_long_term_frame_idx_plus1" "From the syntax in dec_ref_pic_marking()." +*/ +void MemMgrCtrlOp4(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, uint max_long_term_frame_idx_plus1); + +/** +This function performs memory management control operation 5, marking all reference pictures +as unused for reference and set MaxLongTermFrameIdx to no long-termframe indices. + See subclause 8.2.5.4.5. +\param "video" "Pointer to the AVCCommonObj." +\param "dpb" "Pointer to the AVCDecPicBuffer." +*/ +void MemMgrCtrlOp5(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb); + +/** +This function performs memory management control operation 6, assigning a long-term frame index +to the current picture. See subclause 8.2.5.4.6. +\param "video" "Pointer to the AVCCommonObj." +\param "dpb" "Pointer to the AVCDecPicBuffer." +\param "long_term_frame_idx" "From the syntax in dec_ref_pic_marking()." +*/ +void MemMgrCtrlOp6(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, uint long_term_frame_idx); + +/** +This function mark a long-term ref frame with a specific frame index as unused for reference. +\param "dpb" "Pointer to the AVCDecPicBuffer." +\param "long_term_frame_idx" "To look for" +*/ +void unmark_long_term_frame_for_reference_by_frame_idx(AVCHandle *avcHandle, AVCDecPicBuffer *dpb, uint long_term_frame_idx); + +/** +This function mark a long-term ref field with a specific frame index as unused for reference except +a frame that contains a picture with picNumX. +\param "dpb" "Pointer to the AVCDecPicBuffer." +\param "long_term_frame_idx" "To look for." +\param "picNumX" "To look for." +*/ +void unmark_long_term_field_for_reference_by_frame_idx(AVCCommonObj *video, AVCDecPicBuffer *dpb, uint long_term_frame_indx, int picNumX); + +/** +This function mark a frame to unused for reference. +\param "fs" "Pointer to AVCFrameStore to be unmarked." +*/ +void unmark_for_reference(AVCHandle *avcHandle, AVCDecPicBuffer *dpb, uint idx); + +void update_ref_list(AVCDecPicBuffer *dpb); + + +/*---------- fmo.c --------------*/ +/** +This function initializes flexible macroblock reordering. +\param "video" "Pointer to AVCCommonObj." +\return "AVC_SUCCESS for success and AVC_FAIL otherwise." +*/ +OSCL_IMPORT_REF AVCStatus FMOInit(AVCCommonObj *video); + +/** +This function fills up an array that maps Map unit to the slice group +following the interleaved slice group map type. +\param "mapUnitToSliceGroupMap" "Array of slice group mapping." +\param "run_length_minus1" "Array of the run-length." +\param "num_slice_groups_minus_1" "Number of slice group minus 1." +\param "PicSizeInMapUnit" "Size of the picture in number Map units." +\return "Void." +*/ +void FmoGenerateType0MapUnitMap(int *mapUnitToSliceGroupMap, uint *run_length_minus1, uint num_slice_groups_minus1, uint PicSizeInMapUnits); + +/** +This function fills up an array that maps Map unit to the slice group +following the dispersed slice group map type. +\param "mapUnitToSliceGroupMap" "Array of slice group mapping." +\param "PicWidthInMbs" "Width of the luma picture in macroblock unit." +\param "num_slice_groups_minus_1" "Number of slice group minus 1." +\param "PicSizeInMapUnit" "Size of the picture in number Map units." +\return "Void." +*/ +void FmoGenerateType1MapUnitMap(int *mapUnitToSliceGroupMap, int PicWidthInMbs, uint num_slice_groups_minus1, uint PicSizeInMapUnits); + +/** +This function fills up an array that maps Map unit to the slice group +following the foreground with left-over slice group map type. +\param "pps" "Pointer to AVCPicParamSets structure." +\param "mapUnitToSliceGroupMap" "Array of slice group mapping." +\param "PicWidthInMbs" "Width of the luma picture in macroblock unit." +\param "num_slice_groups_minus_1" "Number of slice group minus 1." +\param "PicSizeInMapUnit" "Size of the picture in number Map units." +\return "Void." +*/ +void FmoGenerateType2MapUnitMap(AVCPicParamSet *pps, int *mapUnitToSliceGroupMap, int PicWidthInMbs, + uint num_slice_groups_minus1, uint PicSizeInMapUnits); + +/** +This function fills up an array that maps Map unit to the slice group +following the box-out slice group map type. +\param "pps" "Pointer to AVCPicParamSets structure." +\param "mapUnitToSliceGroupMap" "Array of slice group mapping." +\param "PicWidthInMbs" "Width of the luma picture in macroblock unit." +\return "Void." +*/ +void FmoGenerateType3MapUnitMap(AVCCommonObj *video, AVCPicParamSet* pps, int *mapUnitToSliceGroupMap, + int PicWidthInMbs); + +/** +This function fills up an array that maps Map unit to the slice group +following the raster scan slice group map type. +\param "mapUnitToSliceGroupMap" "Array of slice group mapping." +\param "MapUnitsInSliceGroup0" "Derived in subclause 7.4.3." +\param "slice_group_change_direction_flag" "A value from the slice header." +\param "PicSizeInMapUnit" "Size of the picture in number Map units." +\return "void" +*/ +void FmoGenerateType4MapUnitMap(int *mapUnitToSliceGroupMap, int MapUnitsInSliceGroup0, + int slice_group_change_direction_flag, uint PicSizeInMapUnits); + +/** +This function fills up an array that maps Map unit to the slice group +following wipe slice group map type. +\param "mapUnitToSliceGroupMap" "Array of slice group mapping." +\param "video" "Pointer to AVCCommonObj structure." +\param "slice_group_change_direction_flag" "A value from the slice header." +\param "PicSizeInMapUnit" "Size of the picture in number Map units." +\return "void" +*/ +void FmoGenerateType5MapUnitMap(int *mapUnitsToSliceGroupMap, AVCCommonObj *video, + int slice_group_change_direction_flag, uint PicSizeInMapUnits); + +/** +This function fills up an array that maps Map unit to the slice group +following wipe slice group map type. +\param "mapUnitToSliceGroupMap" "Array of slice group mapping." +\param "slice_group_id" "Array of slice_group_id from AVCPicParamSet structure." +\param "PicSizeInMapUnit" "Size of the picture in number Map units." +\return "void" +*/ +void FmoGenerateType6MapUnitMap(int *mapUnitsToSliceGroupMap, int *slice_group_id, uint PicSizeInMapUnits); + +/*------------- itrans.c --------------*/ +/** +This function performs transformation of the Intra16x16DC value according to +subclause 8.5.6. +\param "block" "Pointer to the video->block[0][0][0]." +\param "QPy" "Quantization parameter." +\return "void." +*/ +void Intra16DCTrans(int16 *block, int Qq, int Rq); + +/** +This function performs transformation of a 4x4 block according to +subclause 8.5.8. +\param "block" "Pointer to the origin of transform coefficient area." +\param "pred" "Pointer to the origin of predicted area." +\param "cur" "Pointer to the origin of the output area." +\param "width" "Pitch of cur." +\return "void." +*/ +void itrans(int16 *block, uint8 *pred, uint8 *cur, int width); + +/* +This function is the same one as itrans except for chroma. +\param "block" "Pointer to the origin of transform coefficient area." +\param "pred" "Pointer to the origin of predicted area." +\param "cur" "Pointer to the origin of the output area." +\param "width" "Pitch of cur." +\return "void." +*/ +void ictrans(int16 *block, uint8 *pred, uint8 *cur, int width); + +/** +This function performs transformation of the DCChroma value according to +subclause 8.5.7. +\param "block" "Pointer to the video->block[0][0][0]." +\param "QPc" "Quantization parameter." +\return "void." +*/ +void ChromaDCTrans(int16 *block, int Qq, int Rq); + +/** +This function copies a block from pred to cur. +\param "pred" "Pointer to prediction block." +\param "cur" "Pointer to the current YUV block." +\param "width" "Pitch of cur memory." +\param "pred_pitch" "Pitch for pred memory. +\return "void." +*/ +void copy_block(uint8 *pred, uint8 *cur, int width, int pred_pitch); + +/*--------- mb_access.c ----------------*/ +/** +This function initializes the neighboring information before start macroblock decoding. +\param "video" "Pointer to AVCCommonObj." +\param "mbNum" "The current macroblock index." +\param "currMB" "Pointer to the current AVCMacroblock structure." +\return "void" +*/ +OSCL_IMPORT_REF void InitNeighborAvailability(AVCCommonObj *video, int mbNum); + +/** +This function checks whether the requested neighboring macroblock is available. +\param "MbToSliceGroupMap" "Array containing the slice group ID mapping to MB index." +\param "PicSizeInMbs" "Size of the picture in number of MBs." +\param "mbAddr" "Neighboring macroblock index to check." +\param "currMbAddr" "Current macroblock index." +\return "TRUE if the neighboring MB is available, FALSE otherwise." +*/ +bool mb_is_available(AVCMacroblock *mblock, uint PicSizeInMbs, int mbAddr, int currMbAddr); + +/** +This function performs prediction of the nonzero coefficient for a luma block (i,j). +\param "video" "Pointer to AVCCommonObj." +\param "i" "Block index, horizontal." +\param "j" "Block index, vertical." +\return "Predicted number of nonzero coefficient." +*/ +OSCL_IMPORT_REF int predict_nnz(AVCCommonObj *video, int i, int j); + +/** +This function performs prediction of the nonzero coefficient for a chroma block (i,j). +\param "video" "Pointer to AVCCommonObj." +\param "i" "Block index, horizontal." +\param "j" "Block index, vertical." +\return "Predicted number of nonzero coefficient." +*/ +OSCL_IMPORT_REF int predict_nnz_chroma(AVCCommonObj *video, int i, int j); + +/** +This function calculates the predicted motion vectors for the current macroblock. +\param "video" "Pointer to AVCCommonObj." +\param "encFlag" "Boolean whether this function is used by encoder or decoder." +\return "void." +*/ +OSCL_IMPORT_REF void GetMotionVectorPredictor(AVCCommonObj *video, int encFlag); + +/*---------- reflist.c -----------------*/ +/** +This function initializes reference picture list used in INTER prediction +at the beginning of each slice decoding. See subclause 8.2.4. +\param "video" "Pointer to AVCCommonObj." +\return "void" +Output is video->RefPicList0, video->RefPicList1, video->refList0Size and video->refList1Size. +*/ +OSCL_IMPORT_REF void RefListInit(AVCCommonObj *video); + +/** +This function generates picture list from frame list. Used when current picture is field. +see subclause 8.2.4.2.5. +\param "video" "Pointer to AVCCommonObj." +\param "IsL1" "Is L1 list?" +\param "long_term" "Is long-term prediction?" +\return "void" +*/ +void GenPicListFromFrameList(AVCCommonObj *video, int IsL1, int long_term); + +/** +This function performs reference picture list reordering according to the +ref_pic_list_reordering() syntax. See subclause 8.2.4.3. +\param "video" "Pointer to AVCCommonObj." +\return "AVC_SUCCESS or AVC_FAIL" +Output is video->RefPicList0, video->RefPicList1, video->refList0Size and video->refList1Size. +*/ +OSCL_IMPORT_REF AVCStatus ReOrderList(AVCCommonObj *video); + +/** +This function performs reference picture list reordering according to the +ref_pic_list_reordering() syntax regardless of list 0 or list 1. See subclause 8.2.4.3. +\param "video" "Pointer to AVCCommonObj." +\param "isL1" "Is list 1 or not." +\return "AVC_SUCCESS or AVC_FAIL" +Output is video->RefPicList0 and video->refList0Size or video->RefPicList1 and video->refList1Size. +*/ +AVCStatus ReorderRefPicList(AVCCommonObj *video, int isL1); + +/** +This function performs reordering process of reference picture list for short-term pictures. +See subclause 8.2.4.3.1. +\param "video" "Pointer to AVCCommonObj." +\param "picNumLX" "picNumLX of an entry in the reference list." +\param "refIdxLX" "Pointer to the current entry index in the reference." +\param "isL1" "Is list 1 or not." +\return "AVC_SUCCESS or AVC_FAIL" +*/ +AVCStatus ReorderShortTerm(AVCCommonObj *video, int picNumLX, int *refIdxLX, int isL1); + +/** +This function performs reordering process of reference picture list for long-term pictures. +See subclause 8.2.4.3.2. +\param "video" "Pointer to AVCCommonObj." +\param "LongTermPicNum" "LongTermPicNum of an entry in the reference list." +\param "refIdxLX" "Pointer to the current entry index in the reference." +\param "isL1" "Is list 1 or not." +\return "AVC_SUCCESS or AVC_FAIL" +*/ +AVCStatus ReorderLongTerm(AVCCommonObj *video, int LongTermPicNum, int *refIdxLX, int isL1); + +/** +This function gets the pictures in DPB according to the PicNum. +\param "video" "Pointer to AVCCommonObj." +\param "picNum" "PicNum of the picture we are looking for." +\return "Pointer to the AVCPictureData or NULL if not found" +*/ +AVCPictureData* GetShortTermPic(AVCCommonObj *video, int picNum); + +/** +This function gets the pictures in DPB according to the LongtermPicNum. +\param "video" "Pointer to AVCCommonObj." +\param "LongtermPicNum" "LongtermPicNum of the picture we are looking for." +\return "Pointer to the AVCPictureData." +*/ +AVCPictureData* GetLongTermPic(AVCCommonObj *video, int LongtermPicNum); + +/** +This function indicates whether the picture is used for short-term reference or not. +\param "s" "Pointer to AVCPictureData." +\return "1 if it is used for short-term, 0 otherwise." +*/ +int is_short_ref(AVCPictureData *s); + +/** +This function indicates whether the picture is used for long-term reference or not. +\param "s" "Pointer to AVCPictureData." +\return "1 if it is used for long-term, 0 otherwise." +*/ +int is_long_ref(AVCPictureData *s); + +/** +This function sorts array of pointers to AVCPictureData in descending order of +the PicNum value. +\param "data" "Array of pointers to AVCPictureData." +\param "num" "Size of the array." +\return "void" +*/ +void SortPicByPicNum(AVCPictureData *data[], int num); + +/** +This function sorts array of pointers to AVCPictureData in ascending order of +the PicNum value. +\param "data" "Array of pointers to AVCPictureData." +\param "num" "Size of the array." +\return "void" +*/ +void SortPicByPicNumLongTerm(AVCPictureData *data[], int num); + +/** +This function sorts array of pointers to AVCFrameStore in descending order of +the FrameNumWrap value. +\param "data" "Array of pointers to AVCFrameStore." +\param "num" "Size of the array." +\return "void" +*/ +void SortFrameByFrameNumWrap(AVCFrameStore *data[], int num); + +/** +This function sorts array of pointers to AVCFrameStore in ascending order of +the LongTermFrameIdx value. +\param "data" "Array of pointers to AVCFrameStore." +\param "num" "Size of the array." +\return "void" +*/ +void SortFrameByLTFrameIdx(AVCFrameStore *data[], int num); + +/** +This function sorts array of pointers to AVCPictureData in descending order of +the PicOrderCnt value. +\param "data" "Array of pointers to AVCPictureData." +\param "num" "Size of the array." +\return "void" +*/ +void SortPicByPOC(AVCPictureData *data[], int num, int descending); + +/** +This function sorts array of pointers to AVCPictureData in ascending order of +the LongTermPicNum value. +\param "data" "Array of pointers to AVCPictureData." +\param "num" "Size of the array." +\return "void" +*/ +void SortPicByLTPicNum(AVCPictureData *data[], int num); + +/** +This function sorts array of pointers to AVCFrameStore in descending order of +the PicOrderCnt value. +\param "data" "Array of pointers to AVCFrameStore." +\param "num" "Size of the array." +\return "void" +*/ +void SortFrameByPOC(AVCFrameStore *data[], int num, int descending); + + +#endif /* _AVCCOMMON_LIB_H_ */ diff --git a/media/libstagefright/codecs/avc/common/src/deblock.cpp b/media/libstagefright/codecs/avc/common/src/deblock.cpp new file mode 100644 index 0000000..5ed4c82 --- /dev/null +++ b/media/libstagefright/codecs/avc/common/src/deblock.cpp @@ -0,0 +1,1666 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 + +#include "avclib_common.h" + +#define MAX_QP 51 +#define MB_BLOCK_SIZE 16 + +// NOTE: these 3 tables are for funtion GetStrength() only +const static int ININT_STRENGTH[4] = {0x04040404, 0x03030303, 0x03030303, 0x03030303}; + + +// NOTE: these 3 tables are for funtion EdgeLoop() only +// NOTE: to change the tables below for instance when the QP doubling is changed from 6 to 8 values + +const static int ALPHA_TABLE[52] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 5, 6, 7, 8, 9, 10, 12, 13, 15, 17, 20, 22, 25, 28, 32, 36, 40, 45, 50, 56, 63, 71, 80, 90, 101, 113, 127, 144, 162, 182, 203, 226, 255, 255} ; +const static int BETA_TABLE[52] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18} ; +const static int CLIP_TAB[52][5] = +{ + { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0}, { 0, 0, 0, 1, 1}, { 0, 0, 0, 1, 1}, { 0, 0, 0, 1, 1}, { 0, 0, 0, 1, 1}, { 0, 0, 1, 1, 1}, { 0, 0, 1, 1, 1}, { 0, 1, 1, 1, 1}, + { 0, 1, 1, 1, 1}, { 0, 1, 1, 1, 1}, { 0, 1, 1, 1, 1}, { 0, 1, 1, 2, 2}, { 0, 1, 1, 2, 2}, { 0, 1, 1, 2, 2}, { 0, 1, 1, 2, 2}, { 0, 1, 2, 3, 3}, + { 0, 1, 2, 3, 3}, { 0, 2, 2, 3, 3}, { 0, 2, 2, 4, 4}, { 0, 2, 3, 4, 4}, { 0, 2, 3, 4, 4}, { 0, 3, 3, 5, 5}, { 0, 3, 4, 6, 6}, { 0, 3, 4, 6, 6}, + { 0, 4, 5, 7, 7}, { 0, 4, 5, 8, 8}, { 0, 4, 6, 9, 9}, { 0, 5, 7, 10, 10}, { 0, 6, 8, 11, 11}, { 0, 6, 8, 13, 13}, { 0, 7, 10, 14, 14}, { 0, 8, 11, 16, 16}, + { 0, 9, 12, 18, 18}, { 0, 10, 13, 20, 20}, { 0, 11, 15, 23, 23}, { 0, 13, 17, 25, 25} +}; + +// NOTE: this table is only QP clipping, index = QP + video->FilterOffsetA/B, clipped to [0, 51] +// video->FilterOffsetA/B is in {-12, 12] +const static int QP_CLIP_TAB[76] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // [-12, 0] + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // [1, 51] + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51 // [52,63] +}; + +static void DeblockMb(AVCCommonObj *video, int mb_x, int mb_y, uint8 *SrcY, uint8 *SrcU, uint8 *SrcV); +//static void GetStrength(AVCCommonObj *video, uint8 *Strength, AVCMacroblock* MbP, AVCMacroblock* MbQ, int dir, int edge); +static void GetStrength_Edge0(uint8 *Strength, AVCMacroblock* MbP, AVCMacroblock* MbQ, int dir); +static void GetStrength_VerticalEdges(uint8 *Strength, AVCMacroblock* MbQ); +static void GetStrength_HorizontalEdges(uint8 Strength[12], AVCMacroblock* MbQ); +static void EdgeLoop_Luma_vertical(uint8* SrcPtr, uint8 *Strength, int Alpha, int Beta, int *clipTable, int pitch); +static void EdgeLoop_Luma_horizontal(uint8* SrcPtr, uint8 *Strength, int Alpha, int Beta, int *clipTable, int pitch); +static void EdgeLoop_Chroma_vertical(uint8* SrcPtr, uint8 *Strength, int Alpha, int Beta, int *clipTable, int pitch); +static void EdgeLoop_Chroma_horizontal(uint8* SrcPtr, uint8 *Strength, int Alpha, int Beta, int *clipTable, int pitch); + +/* + ***************************************************************************************** + * \brief Filter all macroblocks in order of increasing macroblock address. + ***************************************************************************************** +*/ + +OSCL_EXPORT_REF AVCStatus DeblockPicture(AVCCommonObj *video) +{ + uint i, j; + int pitch = video->currPic->pitch, pitch_c, width; + uint8 *SrcY, *SrcU, *SrcV; + + SrcY = video->currPic->Sl; // pointers to source + SrcU = video->currPic->Scb; + SrcV = video->currPic->Scr; + pitch_c = pitch >> 1; + width = video->currPic->width; + + for (i = 0; i < video->PicHeightInMbs; i++) + { + for (j = 0; j < video->PicWidthInMbs; j++) + { + DeblockMb(video, j, i, SrcY, SrcU, SrcV); + // update SrcY, SrcU, SrcV + SrcY += MB_BLOCK_SIZE; + SrcU += (MB_BLOCK_SIZE >> 1); + SrcV += (MB_BLOCK_SIZE >> 1); + } + + SrcY += ((pitch << 4) - width); + SrcU += ((pitch_c << 3) - (width >> 1)); + SrcV += ((pitch_c << 3) - (width >> 1)); + } + + return AVC_SUCCESS; +} + +#ifdef MB_BASED_DEBLOCK +/* + ***************************************************************************************** + * \brief Filter one macroblocks in a fast macroblock memory and copy it to frame + ***************************************************************************************** +*/ +void MBInLoopDeblock(AVCCommonObj *video) +{ + AVCPictureData *currPic = video->currPic; +#ifdef USE_PRED_BLOCK + uint8 *predCb, *predCr, *pred_block; + int i, j, dst_width, dst_height, dst_widthc, dst_heightc; +#endif + int pitch = currPic->pitch; + int x_pos = video->mb_x; + int y_pos = video->mb_y; + uint8 *curL, *curCb, *curCr; + int offset; + + offset = (y_pos << 4) * pitch; + + curL = currPic->Sl + offset + (x_pos << 4); + + offset >>= 2; + offset += (x_pos << 3); + + curCb = currPic->Scb + offset; + curCr = currPic->Scr + offset; + +#ifdef USE_PRED_BLOCK + pred_block = video->pred; + + /* 1. copy neighboring pixels from frame to the video->pred_block */ + if (y_pos) /* not the 0th row */ + { + /* copy to the top 4 lines of the macroblock */ + curL -= (pitch << 2); /* go back 4 lines */ + + memcpy(pred_block + 4, curL, 16); + curL += pitch; + memcpy(pred_block + 24, curL, 16); + curL += pitch; + memcpy(pred_block + 44, curL, 16); + curL += pitch; + memcpy(pred_block + 64, curL, 16); + curL += pitch; + + curCb -= (pitch << 1); /* go back 4 lines chroma */ + curCr -= (pitch << 1); + + pred_block += 400; + + memcpy(pred_block + 4, curCb, 8); + curCb += (pitch >> 1); + memcpy(pred_block + 16, curCb, 8); + curCb += (pitch >> 1); + memcpy(pred_block + 28, curCb, 8); + curCb += (pitch >> 1); + memcpy(pred_block + 40, curCb, 8); + curCb += (pitch >> 1); + + pred_block += 144; + memcpy(pred_block + 4, curCr, 8); + curCr += (pitch >> 1); + memcpy(pred_block + 16, curCr, 8); + curCr += (pitch >> 1); + memcpy(pred_block + 28, curCr, 8); + curCr += (pitch >> 1); + memcpy(pred_block + 40, curCr, 8); + curCr += (pitch >> 1); + + pred_block = video->pred; + } + + /* 2. perform deblocking. */ + DeblockMb(video, x_pos, y_pos, pred_block + 84, pred_block + 452, pred_block + 596); + + /* 3. copy it back to the frame and update pred_block */ + predCb = pred_block + 400; + predCr = predCb + 144; + + /* find the range of the block inside pred_block to be copied back */ + if (y_pos) /* the first row */ + { + curL -= (pitch << 2); + curCb -= (pitch << 1); + curCr -= (pitch << 1); + + dst_height = 20; + dst_heightc = 12; + } + else + { + pred_block += 80; + predCb += 48; + predCr += 48; + dst_height = 16; + dst_heightc = 8; + } + + if (x_pos) /* find the width */ + { + curL -= 4; + curCb -= 4; + curCr -= 4; + if (x_pos == (int)(video->PicWidthInMbs - 1)) + { + dst_width = 20; + dst_widthc = 12; + } + else + { + dst_width = 16; + dst_widthc = 8; + } + } + else + { + pred_block += 4; + predCb += 4; + predCr += 4; + dst_width = 12; + dst_widthc = 4; + } + + /* perform copy */ + for (j = 0; j < dst_height; j++) + { + memcpy(curL, pred_block, dst_width); + curL += pitch; + pred_block += 20; + } + for (j = 0; j < dst_heightc; j++) + { + memcpy(curCb, predCb, dst_widthc); + memcpy(curCr, predCr, dst_widthc); + curCb += (pitch >> 1); + curCr += (pitch >> 1); + predCb += 12; + predCr += 12; + } + + if (x_pos != (int)(video->PicWidthInMbs - 1)) /* now copy from the right-most 4 columns to the left-most 4 columns */ + { + pred_block = video->pred; + for (i = 0; i < 20; i += 4) + { + *((uint32*)pred_block) = *((uint32*)(pred_block + 16)); + pred_block += 20; + *((uint32*)pred_block) = *((uint32*)(pred_block + 16)); + pred_block += 20; + *((uint32*)pred_block) = *((uint32*)(pred_block + 16)); + pred_block += 20; + *((uint32*)pred_block) = *((uint32*)(pred_block + 16)); + pred_block += 20; + } + + for (i = 0; i < 24; i += 4) + { + *((uint32*)pred_block) = *((uint32*)(pred_block + 8)); + pred_block += 12; + *((uint32*)pred_block) = *((uint32*)(pred_block + 8)); + pred_block += 12; + *((uint32*)pred_block) = *((uint32*)(pred_block + 8)); + pred_block += 12; + *((uint32*)pred_block) = *((uint32*)(pred_block + 8)); + pred_block += 12; + } + + } +#else + DeblockMb(video, x_pos, y_pos, curL, curCb, curCr); +#endif + + return ; +} +#endif + +/* + ***************************************************************************************** + * \brief Deblocking filter for one macroblock. + ***************************************************************************************** + */ + +void DeblockMb(AVCCommonObj *video, int mb_x, int mb_y, uint8 *SrcY, uint8 *SrcU, uint8 *SrcV) +{ + AVCMacroblock *MbP, *MbQ; + int edge, QP, QPC; + int filterLeftMbEdgeFlag = (mb_x != 0); + int filterTopMbEdgeFlag = (mb_y != 0); + int pitch = video->currPic->pitch; + int indexA, indexB, tmp; + int Alpha, Beta, Alpha_c, Beta_c; + int mbNum = mb_y * video->PicWidthInMbs + mb_x; + int *clipTable, *clipTable_c, *qp_clip_tab; + uint8 Strength[16]; + void* str; + + MbQ = &(video->mblock[mbNum]); // current Mb + + + // If filter is disabled, return + if (video->sliceHdr->disable_deblocking_filter_idc == 1) return; + + if (video->sliceHdr->disable_deblocking_filter_idc == 2) + { + // don't filter at slice boundaries + filterLeftMbEdgeFlag = mb_is_available(video->mblock, video->PicSizeInMbs, mbNum - 1, mbNum); + filterTopMbEdgeFlag = mb_is_available(video->mblock, video->PicSizeInMbs, mbNum - video->PicWidthInMbs, mbNum); + } + + /* NOTE: edge=0 and edge=1~3 are separate cases because of the difference of MbP, index A and indexB calculation */ + /* for edge = 1~3, MbP, indexA and indexB remain the same, and thus there is no need to re-calculate them for each edge */ + + qp_clip_tab = (int *)QP_CLIP_TAB + 12; + + /* 1.VERTICAL EDGE + MB BOUNDARY (edge = 0) */ + if (filterLeftMbEdgeFlag) + { + MbP = MbQ - 1; + //GetStrength(video, Strength, MbP, MbQ, 0, 0); // Strength for 4 blks in 1 stripe, 0 => vertical edge + GetStrength_Edge0(Strength, MbP, MbQ, 0); + + str = (void*)Strength; //de-ref type-punned pointer fix + if (*((uint32*)str)) // only if one of the 4 Strength bytes is != 0 + { + QP = (MbP->QPy + MbQ->QPy + 1) >> 1; // Average QP of the two blocks; + indexA = QP + video->FilterOffsetA; + indexB = QP + video->FilterOffsetB; + indexA = qp_clip_tab[indexA]; // IClip(0, MAX_QP, QP+video->FilterOffsetA) + indexB = qp_clip_tab[indexB]; // IClip(0, MAX_QP, QP+video->FilterOffsetB) + + Alpha = ALPHA_TABLE[indexA]; + Beta = BETA_TABLE[indexB]; + clipTable = (int *) CLIP_TAB[indexA]; + + if (Alpha > 0 && Beta > 0) +#ifdef USE_PRED_BLOCK + EdgeLoop_Luma_vertical(SrcY, Strength, Alpha, Beta, clipTable, 20); +#else + EdgeLoop_Luma_vertical(SrcY, Strength, Alpha, Beta, clipTable, pitch); +#endif + + QPC = (MbP->QPc + MbQ->QPc + 1) >> 1; + indexA = QPC + video->FilterOffsetA; + indexB = QPC + video->FilterOffsetB; + indexA = qp_clip_tab[indexA]; // IClip(0, MAX_QP, QP+video->FilterOffsetA) + indexB = qp_clip_tab[indexB]; // IClip(0, MAX_QP, QP+video->FilterOffsetB) + + Alpha = ALPHA_TABLE[indexA]; + Beta = BETA_TABLE[indexB]; + clipTable = (int *) CLIP_TAB[indexA]; + if (Alpha > 0 && Beta > 0) + { +#ifdef USE_PRED_BLOCK + EdgeLoop_Chroma_vertical(SrcU, Strength, Alpha, Beta, clipTable, 12); + EdgeLoop_Chroma_vertical(SrcV, Strength, Alpha, Beta, clipTable, 12); +#else + EdgeLoop_Chroma_vertical(SrcU, Strength, Alpha, Beta, clipTable, pitch >> 1); + EdgeLoop_Chroma_vertical(SrcV, Strength, Alpha, Beta, clipTable, pitch >> 1); +#endif + } + } + + } /* end of: if(filterLeftMbEdgeFlag) */ + + /* 2.VERTICAL EDGE (no boundary), the edges are all inside a MB */ + /* First calculate the necesary parameters all at once, outside the loop */ + MbP = MbQ; + + indexA = MbQ->QPy + video->FilterOffsetA; + indexB = MbQ->QPy + video->FilterOffsetB; + // index + indexA = qp_clip_tab[indexA]; // IClip(0, MAX_QP, QP+video->FilterOffsetA) + indexB = qp_clip_tab[indexB]; // IClip(0, MAX_QP, QP+video->FilterOffsetB) + + Alpha = ALPHA_TABLE[indexA]; + Beta = BETA_TABLE[indexB]; + clipTable = (int *)CLIP_TAB[indexA]; + + /* Save Alpha, Beta and clipTable for future use, with the obselete variables filterLeftMbEdgeFlag, mbNum amd tmp */ + filterLeftMbEdgeFlag = Alpha; + mbNum = Beta; + tmp = (int)clipTable; + + indexA = MbQ->QPc + video->FilterOffsetA; + indexB = MbQ->QPc + video->FilterOffsetB; + indexA = qp_clip_tab[indexA]; // IClip(0, MAX_QP, QP+video->FilterOffsetA) + indexB = qp_clip_tab[indexB]; // IClip(0, MAX_QP, QP+video->FilterOffsetB) + + Alpha_c = ALPHA_TABLE[indexA]; + Beta_c = BETA_TABLE[indexB]; + clipTable_c = (int *)CLIP_TAB[indexA]; + + GetStrength_VerticalEdges(Strength + 4, MbQ); // Strength for 4 blks in 1 stripe, 0 => vertical edge + + for (edge = 1; edge < 4; edge++) // 4 vertical strips of 16 pel + { + //GetStrength_VerticalEdges(video, Strength, MbP, MbQ, 0, edge); // Strength for 4 blks in 1 stripe, 0 => vertical edge + if (*((int*)(Strength + (edge << 2)))) // only if one of the 4 Strength bytes is != 0 + { + if (Alpha > 0 && Beta > 0) +#ifdef USE_PRED_BLOCK + EdgeLoop_Luma_vertical(SrcY + (edge << 2), Strength + (edge << 2), Alpha, Beta, clipTable, 20); +#else + EdgeLoop_Luma_vertical(SrcY + (edge << 2), Strength + (edge << 2), Alpha, Beta, clipTable, pitch); +#endif + + if (!(edge & 1) && Alpha_c > 0 && Beta_c > 0) + { +#ifdef USE_PRED_BLOCK + EdgeLoop_Chroma_vertical(SrcU + (edge << 1), Strength + (edge << 2), Alpha_c, Beta_c, clipTable_c, 12); + EdgeLoop_Chroma_vertical(SrcV + (edge << 1), Strength + (edge << 2), Alpha_c, Beta_c, clipTable_c, 12); +#else + EdgeLoop_Chroma_vertical(SrcU + (edge << 1), Strength + (edge << 2), Alpha_c, Beta_c, clipTable_c, pitch >> 1); + EdgeLoop_Chroma_vertical(SrcV + (edge << 1), Strength + (edge << 2), Alpha_c, Beta_c, clipTable_c, pitch >> 1); +#endif + } + } + + } //end edge + + + + /* 3.HORIZONTAL EDGE + MB BOUNDARY (edge = 0) */ + if (filterTopMbEdgeFlag) + { + MbP = MbQ - video->PicWidthInMbs; + //GetStrength(video, Strength, MbP, MbQ, 1, 0); // Strength for 4 blks in 1 stripe, 0 => vertical edge + GetStrength_Edge0(Strength, MbP, MbQ, 1); + str = (void*)Strength; //de-ref type-punned pointer fix + if (*((uint32*)str)) // only if one of the 4 Strength bytes is != 0 + { + QP = (MbP->QPy + MbQ->QPy + 1) >> 1; // Average QP of the two blocks; + indexA = QP + video->FilterOffsetA; + indexB = QP + video->FilterOffsetB; + indexA = qp_clip_tab[indexA]; // IClip(0, MAX_QP, QP+video->FilterOffsetA) + indexB = qp_clip_tab[indexB]; // IClip(0, MAX_QP, QP+video->FilterOffsetB) + + Alpha = ALPHA_TABLE[indexA]; + Beta = BETA_TABLE[indexB]; + clipTable = (int *)CLIP_TAB[indexA]; + + if (Alpha > 0 && Beta > 0) + { +#ifdef USE_PRED_BLOCK + EdgeLoop_Luma_horizontal(SrcY, Strength, Alpha, Beta, clipTable, 20); +#else + EdgeLoop_Luma_horizontal(SrcY, Strength, Alpha, Beta, clipTable, pitch); +#endif + } + + QPC = (MbP->QPc + MbQ->QPc + 1) >> 1; + indexA = QPC + video->FilterOffsetA; + indexB = QPC + video->FilterOffsetB; + indexA = qp_clip_tab[indexA]; // IClip(0, MAX_QP, QP+video->FilterOffsetA) + indexB = qp_clip_tab[indexB]; // IClip(0, MAX_QP, QP+video->FilterOffsetB) + + Alpha = ALPHA_TABLE[indexA]; + Beta = BETA_TABLE[indexB]; + clipTable = (int *)CLIP_TAB[indexA]; + if (Alpha > 0 && Beta > 0) + { +#ifdef USE_PRED_BLOCK + EdgeLoop_Chroma_horizontal(SrcU, Strength, Alpha, Beta, clipTable, 12); + EdgeLoop_Chroma_horizontal(SrcV, Strength, Alpha, Beta, clipTable, 12); +#else + EdgeLoop_Chroma_horizontal(SrcU, Strength, Alpha, Beta, clipTable, pitch >> 1); + EdgeLoop_Chroma_horizontal(SrcV, Strength, Alpha, Beta, clipTable, pitch >> 1); +#endif + } + } + + } /* end of: if(filterTopMbEdgeFlag) */ + + + /* 4.HORIZONTAL EDGE (no boundary), the edges are inside a MB */ + MbP = MbQ; + + /* Recover Alpha, Beta and clipTable for edge!=0 with the variables filterLeftMbEdgeFlag, mbNum and tmp */ + /* Note that Alpha_c, Beta_c and clipTable_c for chroma is already calculated */ + Alpha = filterLeftMbEdgeFlag; + Beta = mbNum; + clipTable = (int *)tmp; + + GetStrength_HorizontalEdges(Strength + 4, MbQ); // Strength for 4 blks in 1 stripe, 0 => vertical edge + + for (edge = 1; edge < 4; edge++) // 4 horicontal strips of 16 pel + { + //GetStrength(video, Strength, MbP, MbQ, 1, edge); // Strength for 4 blks in 1 stripe 1 => horizontal edge + if (*((int*)(Strength + (edge << 2)))) // only if one of the 4 Strength bytes is != 0 + { + if (Alpha > 0 && Beta > 0) + { +#ifdef USE_PRED_BLOCK + EdgeLoop_Luma_horizontal(SrcY + (edge << 2)*20, Strength + (edge << 2), Alpha, Beta, clipTable, 20); +#else + EdgeLoop_Luma_horizontal(SrcY + (edge << 2)*pitch, Strength + (edge << 2), Alpha, Beta, clipTable, pitch); +#endif + } + + if (!(edge & 1) && Alpha_c > 0 && Beta_c > 0) + { +#ifdef USE_PRED_BLOCK + EdgeLoop_Chroma_horizontal(SrcU + (edge << 1)*12, Strength + (edge << 2), Alpha_c, Beta_c, clipTable_c, 12); + EdgeLoop_Chroma_horizontal(SrcV + (edge << 1)*12, Strength + (edge << 2), Alpha_c, Beta_c, clipTable_c, 12); +#else + EdgeLoop_Chroma_horizontal(SrcU + (edge << 1)*(pitch >> 1), Strength + (edge << 2), Alpha_c, Beta_c, clipTable_c, pitch >> 1); + EdgeLoop_Chroma_horizontal(SrcV + (edge << 1)*(pitch >> 1), Strength + (edge << 2), Alpha_c, Beta_c, clipTable_c, pitch >> 1); +#endif + } + } + + } //end edge + + return; +} + +/* + ***************************************************************************************************** + * \brief returns a buffer of 4 Strength values for one stripe in a mb (for different Frame types) + ***************************************************************************************************** +*/ + +void GetStrength_Edge0(uint8 *Strength, AVCMacroblock* MbP, AVCMacroblock* MbQ, int dir) +{ + int tmp; + int16 *ptrQ, *ptrP; + void* vptr; + uint8 *pStrength; + void* refIdx; + + if (MbP->mbMode == AVC_I4 || MbP->mbMode == AVC_I16 || + MbQ->mbMode == AVC_I4 || MbQ->mbMode == AVC_I16) + { + + *((int*)Strength) = ININT_STRENGTH[0]; // Start with Strength=3. or Strength=4 for Mb-edge + + } + else // if not intra or SP-frame + { + *((int*)Strength) = 0; + + if (dir == 0) // Vertical Edge 0 + { + + //1. Check the ref_frame_id + refIdx = (void*) MbQ->RefIdx; //de-ref type-punned pointer fix + ptrQ = (int16*)refIdx; + refIdx = (void*)MbP->RefIdx; //de-ref type-punned pointer fix + ptrP = (int16*)refIdx; + pStrength = Strength; + if (ptrQ[0] != ptrP[1]) pStrength[0] = 1; + if (ptrQ[2] != ptrP[3]) pStrength[2] = 1; + pStrength[1] = pStrength[0]; + pStrength[3] = pStrength[2]; + + //2. Check the non-zero coeff blocks (4x4) + if (MbQ->nz_coeff[0] != 0 || MbP->nz_coeff[3] != 0) pStrength[0] = 2; + if (MbQ->nz_coeff[4] != 0 || MbP->nz_coeff[7] != 0) pStrength[1] = 2; + if (MbQ->nz_coeff[8] != 0 || MbP->nz_coeff[11] != 0) pStrength[2] = 2; + if (MbQ->nz_coeff[12] != 0 || MbP->nz_coeff[15] != 0) pStrength[3] = 2; + + //3. Only need to check the mv difference + vptr = (void*)MbQ->mvL0; // for deref type-punned pointer + ptrQ = (int16*)vptr; + ptrP = (int16*)(MbP->mvL0 + 3); // points to 4x4 block #3 (the 4th column) + + // 1st blk + if (*pStrength == 0) + { + // check |mv difference| >= 4 + tmp = *ptrQ++ - *ptrP++; + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + + tmp = *ptrQ-- - *ptrP--; + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + } + + pStrength++; + ptrQ += 8; + ptrP += 8; + + // 2nd blk + if (*pStrength == 0) + { + // check |mv difference| >= 4 + tmp = *ptrQ++ - *ptrP++; + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + + tmp = *ptrQ-- - *ptrP--; + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + } + + pStrength++; + ptrQ += 8; + ptrP += 8; + + // 3rd blk + if (*pStrength == 0) + { + // check |mv difference| >= 4 + tmp = *ptrQ++ - *ptrP++; + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + + tmp = *ptrQ-- - *ptrP--; + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + } + + pStrength++; + ptrQ += 8; + ptrP += 8; + + // 4th blk + if (*pStrength == 0) + { + // check |mv difference| >= 4 + tmp = *ptrQ++ - *ptrP++; + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + + tmp = *ptrQ-- - *ptrP--; + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + } + } + else // Horizontal Edge 0 + { + + //1. Check the ref_frame_id + refIdx = (void*)MbQ->RefIdx; //de-ref type-punned pointer + ptrQ = (int16*)refIdx; + refIdx = (void*)MbP->RefIdx; //de-ref type-punned pointer + ptrP = (int16*)refIdx; + pStrength = Strength; + if (ptrQ[0] != ptrP[2]) pStrength[0] = 1; + if (ptrQ[1] != ptrP[3]) pStrength[2] = 1; + pStrength[1] = pStrength[0]; + pStrength[3] = pStrength[2]; + + //2. Check the non-zero coeff blocks (4x4) + if (MbQ->nz_coeff[0] != 0 || MbP->nz_coeff[12] != 0) pStrength[0] = 2; + if (MbQ->nz_coeff[1] != 0 || MbP->nz_coeff[13] != 0) pStrength[1] = 2; + if (MbQ->nz_coeff[2] != 0 || MbP->nz_coeff[14] != 0) pStrength[2] = 2; + if (MbQ->nz_coeff[3] != 0 || MbP->nz_coeff[15] != 0) pStrength[3] = 2; + + //3. Only need to check the mv difference + vptr = (void*)MbQ->mvL0; + ptrQ = (int16*)vptr; + ptrP = (int16*)(MbP->mvL0 + 12); // points to 4x4 block #12 (the 4th row) + + // 1st blk + if (*pStrength == 0) + { + // check |mv difference| >= 4 + tmp = *ptrQ++ - *ptrP++; + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + + tmp = *ptrQ-- - *ptrP--; + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + } + + pStrength++; + ptrQ += 2; + ptrP += 2; + + // 2nd blk + if (*pStrength == 0) + { + // check |mv difference| >= 4 + tmp = *ptrQ++ - *ptrP++; + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + + tmp = *ptrQ-- - *ptrP--; + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + } + + pStrength++; + ptrQ += 2; + ptrP += 2; + + // 3rd blk + if (*pStrength == 0) + { + // check |mv difference| >= 4 + tmp = *ptrQ++ - *ptrP++; + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + + tmp = *ptrQ-- - *ptrP--; + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + } + + pStrength++; + ptrQ += 2; + ptrP += 2; + + // 4th blk + if (*pStrength == 0) + { + // check |mv difference| >= 4 + tmp = *ptrQ++ - *ptrP++; + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + + tmp = *ptrQ-- - *ptrP--; + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + } + + } /* end of: else if(dir == 0) */ + + } /* end of: if( !(MbP->mbMode == AVC_I4 ...) */ +} + + +void GetStrength_VerticalEdges(uint8 *Strength, AVCMacroblock* MbQ) +{ + int idx, tmp; + int16 *ptr, *pmvx, *pmvy; + uint8 *pnz; + uint8 *pStrength, *pStr; + void* refIdx; + + if (MbQ->mbMode == AVC_I4 || MbQ->mbMode == AVC_I16) + { + *((int*)Strength) = ININT_STRENGTH[1]; // Start with Strength=3. or Strength=4 for Mb-edge + *((int*)(Strength + 4)) = ININT_STRENGTH[2]; + *((int*)(Strength + 8)) = ININT_STRENGTH[3]; + } + else // Not intra or SP-frame + { + + *((int*)Strength) = 0; // for non-intra MB, strength = 0, 1 or 2. + *((int*)(Strength + 4)) = 0; + *((int*)(Strength + 8)) = 0; + + //1. Check the ref_frame_id + refIdx = (void*)MbQ->RefIdx; //de-ref type-punned pointer fix + ptr = (int16*)refIdx; + pStrength = Strength; + if (ptr[0] != ptr[1]) pStrength[4] = 1; + if (ptr[2] != ptr[3]) pStrength[6] = 1; + pStrength[5] = pStrength[4]; + pStrength[7] = pStrength[6]; + + //2. Check the nz_coeff block and mv difference + pmvx = (int16*)(MbQ->mvL0 + 1); // points to 4x4 block #1,not #0 + pmvy = pmvx + 1; + for (idx = 0; idx < 4; idx += 2) // unroll the loop, make 4 iterations to 2 + { + // first/third row : 1,2,3 or 9,10,12 + // Strength = 2 for a whole row + pnz = MbQ->nz_coeff + (idx << 2); + if (*pnz++ != 0) *pStrength = 2; + if (*pnz++ != 0) + { + *pStrength = 2; + *(pStrength + 4) = 2; + } + if (*pnz++ != 0) + { + *(pStrength + 4) = 2; + *(pStrength + 8) = 2; + } + if (*pnz != 0) *(pStrength + 8) = 2; + + // Then Strength = 1 + if (*pStrength == 0) + { + //within the same 8x8 block, no need to check the reference id + //only need to check the |mv difference| >= 4 + tmp = *pmvx - *(pmvx - 2); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + + tmp = *pmvy - *(pmvy - 2); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + } + + pmvx += 2; + pmvy += 2; + pStr = pStrength + 4; + + if (*pStr == 0) + { + //check the |mv difference| >= 4 + tmp = *pmvx - *(pmvx - 2); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + + tmp = *pmvy - *(pmvy - 2); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + } + + pmvx += 2; + pmvy += 2; + pStr = pStrength + 8; + + if (*pStr == 0) + { + //within the same 8x8 block, no need to check the reference id + //only need to check the |mv difference| >= 4 + tmp = *pmvx - *(pmvx - 2); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + + tmp = *pmvy - *(pmvy - 2); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + } + + // Second/fourth row: 5,6,7 or 14,15,16 + // Strength = 2 for a whole row + pnz = MbQ->nz_coeff + ((idx + 1) << 2); + if (*pnz++ != 0) *(pStrength + 1) = 2; + if (*pnz++ != 0) + { + *(pStrength + 1) = 2; + *(pStrength + 5) = 2; + } + if (*pnz++ != 0) + { + *(pStrength + 5) = 2; + *(pStrength + 9) = 2; + } + if (*pnz != 0) *(pStrength + 9) = 2; + + // Then Strength = 1 + pmvx += 4; + pmvy += 4; + pStr = pStrength + 1; + if (*pStr == 0) + { + //within the same 8x8 block, no need to check the reference id + //only need to check the |mv difference| >= 4 + tmp = *pmvx - *(pmvx - 2); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + + tmp = *pmvy - *(pmvy - 2); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + } + + pmvx += 2; + pmvy += 2; + pStr = pStrength + 5; + + if (*pStr == 0) + { + //check the |mv difference| >= 4 + tmp = *pmvx - *(pmvx - 2); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + + tmp = *pmvy - *(pmvy - 2); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + } + + pmvx += 2; + pmvy += 2; + pStr = pStrength + 9; + + if (*pStr == 0) + { + //within the same 8x8 block, no need to check the reference id + //only need to check the |mv difference| >= 4 + tmp = *pmvx - *(pmvx - 2); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + + tmp = *pmvy - *(pmvy - 2); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + } + + // update some variables for the next two rows + pmvx += 4; + pmvy += 4; + pStrength += 2; + + } /* end of: for(idx=0; idx<2; idx++) */ + + } /* end of: else if( MbQ->mbMode == AVC_I4 ...) */ +} + + +void GetStrength_HorizontalEdges(uint8 Strength[12], AVCMacroblock* MbQ) +{ + int idx, tmp; + int16 *ptr, *pmvx, *pmvy; + uint8 *pStrength, *pStr; + void* refIdx; + + if (MbQ->mbMode == AVC_I4 || MbQ->mbMode == AVC_I16) + { + *((int*)Strength) = ININT_STRENGTH[1]; // Start with Strength=3. or Strength=4 for Mb-edge + *((int*)(Strength + 4)) = ININT_STRENGTH[2]; + *((int*)(Strength + 8)) = ININT_STRENGTH[3]; + } + else // Not intra or SP-frame + { + + *((int*)Strength) = 0; // for non-intra MB, strength = 0, 1 or 2. + *((int*)(Strength + 4)) = 0; // for non-intra MB, strength = 0, 1 or 2. + *((int*)(Strength + 8)) = 0; // for non-intra MB, strength = 0, 1 or 2. + + + //1. Check the ref_frame_id + refIdx = (void*) MbQ->RefIdx; // de-ref type-punned fix + ptr = (int16*) refIdx; + pStrength = Strength; + if (ptr[0] != ptr[2]) pStrength[4] = 1; + if (ptr[1] != ptr[3]) pStrength[6] = 1; + pStrength[5] = pStrength[4]; + pStrength[7] = pStrength[6]; + + //2. Check the nz_coeff block and mv difference + pmvx = (int16*)(MbQ->mvL0 + 4); // points to 4x4 block #4,not #0 + pmvy = pmvx + 1; + for (idx = 0; idx < 4; idx += 2) // unroll the loop, make 4 iterations to 2 + { + // first/third row : 1,2,3 or 9,10,12 + // Strength = 2 for a whole row + if (MbQ->nz_coeff[idx] != 0) *pStrength = 2; + if (MbQ->nz_coeff[4+idx] != 0) + { + *pStrength = 2; + *(pStrength + 4) = 2; + } + if (MbQ->nz_coeff[8+idx] != 0) + { + *(pStrength + 4) = 2; + *(pStrength + 8) = 2; + } + if (MbQ->nz_coeff[12+idx] != 0) *(pStrength + 8) = 2; + + // Then Strength = 1 + if (*pStrength == 0) + { + //within the same 8x8 block, no need to check the reference id + //only need to check the |mv difference| >= 4 + tmp = *pmvx - *(pmvx - 8); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + + tmp = *pmvy - *(pmvy - 8); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStrength = 1; + } + + pmvx += 8; + pmvy += 8; + pStr = pStrength + 4; + + if (*pStr == 0) + { + //check the |mv difference| >= 4 + tmp = *pmvx - *(pmvx - 8); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + + tmp = *pmvy - *(pmvy - 8); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + } + + pmvx += 8; + pmvy += 8; + pStr = pStrength + 8; + + if (*pStr == 0) + { + //within the same 8x8 block, no need to check the reference id + //only need to check the |mv difference| >= 4 + tmp = *pmvx - *(pmvx - 8); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + + tmp = *pmvy - *(pmvy - 8); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + } + + // Second/fourth row: 5,6,7 or 14,15,16 + // Strength = 2 for a whole row + if (MbQ->nz_coeff[idx+1] != 0) *(pStrength + 1) = 2; + if (MbQ->nz_coeff[4+idx+1] != 0) + { + *(pStrength + 1) = 2; + *(pStrength + 5) = 2; + } + if (MbQ->nz_coeff[8+idx+1] != 0) + { + *(pStrength + 5) = 2; + *(pStrength + 9) = 2; + } + if (MbQ->nz_coeff[12+idx+1] != 0) *(pStrength + 9) = 2; + + // Then Strength = 1 + pmvx -= 14; + pmvy -= 14; // -14 = -16 + 2 + pStr = pStrength + 1; + if (*pStr == 0) + { + //within the same 8x8 block, no need to check the reference id + //only need to check the |mv difference| >= 4 + tmp = *pmvx - *(pmvx - 8); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + + tmp = *pmvy - *(pmvy - 8); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + } + + pmvx += 8; + pmvy += 8; + pStr = pStrength + 5; + + if (*pStr == 0) + { + //check the |mv difference| >= 4 + tmp = *pmvx - *(pmvx - 8); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + + tmp = *pmvy - *(pmvy - 8); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + } + + pmvx += 8; + pmvy += 8; + pStr = pStrength + 9; + + if (*pStr == 0) + { + //within the same 8x8 block, no need to check the reference id + //only need to check the |mv difference| >= 4 + tmp = *pmvx - *(pmvx - 8); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + + tmp = *pmvy - *(pmvy - 8); + if (tmp < 0) tmp = -tmp; + if (tmp >= 4) *pStr = 1; + } + + // update some variables for the next two rows + pmvx -= 14; + pmvy -= 14; // -14 = -16 + 2 + pStrength += 2; + + } /* end of: for(idx=0; idx<2; idx++) */ + + } /* end of: else if( MbQ->mbMode == AVC_I4 ...) */ +} + +/* + ***************************************************************************************** + * \brief Filters one edge of 16 (luma) or 8 (chroma) pel + ***************************************************************************************** +*/ + +void EdgeLoop_Luma_horizontal(uint8* SrcPtr, uint8 *Strength, int Alpha, int Beta, int *clipTable, int pitch) +{ + int pel, ap = 0, aq = 0, Strng; + int C0, c0, dif, AbsDelta, tmp, tmp1; + int L2 = 0, L1, L0, R0, R1, R2 = 0, RL0; + + + if (Strength[0] == 4) /* INTRA strong filtering */ + { + for (pel = 0; pel < 16; pel++) + { + R0 = SrcPtr[0]; + R1 = SrcPtr[pitch]; + L0 = SrcPtr[-pitch]; + L1 = SrcPtr[-(pitch<<1)]; + + // |R0 - R1| < Beta + tmp1 = R0 - R1; + if (tmp1 < 0) tmp1 = -tmp1; + tmp = (tmp1 - Beta); + + //|L0 - L1| < Beta + tmp1 = L0 - L1; + if (tmp1 < 0) tmp1 = -tmp1; + tmp &= (tmp1 - Beta); + + //|R0 - L0| < Alpha + AbsDelta = R0 - L0; + if (AbsDelta < 0) AbsDelta = -AbsDelta; + tmp &= (AbsDelta - Alpha); + + if (tmp < 0) + { + AbsDelta -= ((Alpha >> 2) + 2); + R2 = SrcPtr[pitch<<1]; //inc2 + L2 = SrcPtr[-(pitch+(pitch<<1))]; // -inc3 + + // |R0 - R2| < Beta && |R0 - L0| < (Alpha/4 + 2) + tmp = R0 - R2; + if (tmp < 0) tmp = -tmp; + aq = AbsDelta & (tmp - Beta); + + // |L0 - L2| < Beta && |R0 - L0| < (Alpha/4 + 2) + tmp = L0 - L2; + if (tmp < 0) tmp = -tmp; + ap = AbsDelta & (tmp - Beta); + + if (aq < 0) + { + tmp = R1 + R0 + L0; + SrcPtr[0] = (L1 + (tmp << 1) + R2 + 4) >> 3; + tmp += R2; + SrcPtr[pitch] = (tmp + 2) >> 2; + SrcPtr[pitch<<1] = (((SrcPtr[(pitch+(pitch<<1))] + R2) << 1) + tmp + 4) >> 3; + } + else + SrcPtr[0] = ((R1 << 1) + R0 + L1 + 2) >> 2; + + if (ap < 0) + { + tmp = L1 + R0 + L0; + SrcPtr[-pitch] = (R1 + (tmp << 1) + L2 + 4) >> 3; + tmp += L2; + SrcPtr[-(pitch<<1)] = (tmp + 2) >> 2; + SrcPtr[-(pitch+(pitch<<1))] = (((SrcPtr[-(pitch<<2)] + L2) << 1) + tmp + 4) >> 3; + } + else + SrcPtr[-pitch] = ((L1 << 1) + L0 + R1 + 2) >> 2; + + } /* if(tmp < 0) */ + + SrcPtr ++; // Increment to next set of pixel + + } /* end of: for(pel=0; pel<16; pel++) */ + + } /* if(Strength[0] == 4) */ + + else /* Normal filtering */ + { + for (pel = 0; pel < 16; pel++) + { + Strng = Strength[pel >> 2]; + if (Strng) + { + R0 = SrcPtr[0]; + R1 = SrcPtr[pitch]; + L0 = SrcPtr[-pitch]; + L1 = SrcPtr[-(pitch<<1)]; // inc2 + + //|R0 - L0| < Alpha + tmp1 = R0 - L0; + if (tmp1 < 0) tmp1 = -tmp1; + tmp = (tmp1 - Alpha); + + // |R0 - R1| < Beta + tmp1 = R0 - R1; + if (tmp1 < 0) tmp1 = -tmp1; + tmp &= (tmp1 - Beta); + + //|L0 - L1| < Beta + tmp1 = L0 - L1; + if (tmp1 < 0) tmp1 = -tmp1; + tmp &= (tmp1 - Beta); + + if (tmp < 0) + { + R2 = SrcPtr[pitch<<1]; //inc2 + L2 = SrcPtr[-(pitch+(pitch<<1))]; // -inc3 + + // |R0 - R2| < Beta + tmp = R0 - R2; + if (tmp < 0) tmp = -tmp; + aq = tmp - Beta; + + // |L0 - L2| < Beta + tmp = L0 - L2; + if (tmp < 0) tmp = -tmp; + ap = tmp - Beta; + + + c0 = C0 = clipTable[Strng]; + if (ap < 0) c0++; + if (aq < 0) c0++; + + //dif = IClip(-c0, c0, ((Delta << 2) + (L1 - R1) + 4) >> 3); + dif = (((R0 - L0) << 2) + (L1 - R1) + 4) >> 3; + tmp = dif + c0; + if ((uint)tmp > (uint)c0 << 1) + { + tmp = ~(tmp >> 31); + dif = (tmp & (c0 << 1)) - c0; + } + + //SrcPtr[0] = (uint8)IClip(0, 255, R0 - dif); + //SrcPtr[-inc] = (uint8)IClip(0, 255, L0 + dif); + RL0 = R0 + L0; + R0 -= dif; + L0 += dif; + if ((uint)R0 > 255) + { + tmp = ~(R0 >> 31); + R0 = tmp & 255; + } + if ((uint)L0 > 255) + { + tmp = ~(L0 >> 31); + L0 = tmp & 255; + } + SrcPtr[-pitch] = L0; + SrcPtr[0] = R0; + + if (C0 != 0) /* Multiple zeros in the clip tables */ + { + if (aq < 0) // SrcPtr[inc] += IClip(-C0, C0,(R2 + ((RL0 + 1) >> 1) - (R1<<1)) >> 1); + { + R2 = (R2 + ((RL0 + 1) >> 1) - (R1 << 1)) >> 1; + tmp = R2 + C0; + if ((uint)tmp > (uint)C0 << 1) + { + tmp = ~(tmp >> 31); + R2 = (tmp & (C0 << 1)) - C0; + } + SrcPtr[pitch] += R2; + } + + if (ap < 0) //SrcPtr[-inc2] += IClip(-C0, C0,(L2 + ((RL0 + 1) >> 1) - (L1<<1)) >> 1); + { + L2 = (L2 + ((RL0 + 1) >> 1) - (L1 << 1)) >> 1; + tmp = L2 + C0; + if ((uint)tmp > (uint)C0 << 1) + { + tmp = ~(tmp >> 31); + L2 = (tmp & (C0 << 1)) - C0; + } + SrcPtr[-(pitch<<1)] += L2; + } + } + + } /* if(tmp < 0) */ + + } /* end of: if((Strng = Strength[pel >> 2])) */ + + SrcPtr ++; // Increment to next set of pixel + + } /* for(pel=0; pel<16; pel++) */ + + } /* else if(Strength[0] == 4) */ +} + +void EdgeLoop_Luma_vertical(uint8* SrcPtr, uint8 *Strength, int Alpha, int Beta, int *clipTable, int pitch) +{ + int pel, ap = 1, aq = 1; + int C0, c0, dif, AbsDelta, Strng, tmp, tmp1; + int L2 = 0, L1, L0, R0, R1, R2 = 0; + uint8 *ptr, *ptr1; + register uint R_in, L_in; + uint R_out, L_out; + + + if (Strength[0] == 4) /* INTRA strong filtering */ + { + + for (pel = 0; pel < 16; pel++) + { + + // Read 8 pels + R_in = *((uint *)SrcPtr); // R_in = {R3, R2, R1, R0} + L_in = *((uint *)(SrcPtr - 4)); // L_in = {L0, L1, L2, L3} + R1 = (R_in >> 8) & 0xff; + R0 = R_in & 0xff; + L0 = L_in >> 24; + L1 = (L_in >> 16) & 0xff; + + // |R0 - R1| < Beta + tmp1 = (R_in & 0xff) - R1; + if (tmp1 < 0) tmp1 = -tmp1; + tmp = (tmp1 - Beta); + + + //|L0 - L1| < Beta + tmp1 = (L_in >> 24) - L1; + if (tmp1 < 0) tmp1 = -tmp1; + tmp &= (tmp1 - Beta); + + //|R0 - L0| < Alpha + AbsDelta = (R_in & 0xff) - (L_in >> 24); + if (AbsDelta < 0) AbsDelta = -AbsDelta; + tmp &= (AbsDelta - Alpha); + + if (tmp < 0) + { + AbsDelta -= ((Alpha >> 2) + 2); + R2 = (R_in >> 16) & 0xff; + L2 = (L_in >> 8) & 0xff; + + // |R0 - R2| < Beta && |R0 - L0| < (Alpha/4 + 2) + tmp1 = (R_in & 0xff) - R2; + if (tmp1 < 0) tmp1 = -tmp1; + aq = AbsDelta & (tmp1 - Beta); + + // |L0 - L2| < Beta && |R0 - L0| < (Alpha/4 + 2) + tmp1 = (L_in >> 24) - L2; + if (tmp1 < 0) tmp1 = -tmp1; + ap = AbsDelta & (tmp1 - Beta); + + + ptr = SrcPtr; + if (aq < 0) + { + R_out = (R_in >> 24) << 24; // Keep R3 at the fourth byte + + tmp = R0 + L0 + R1; + R_out |= (((tmp << 1) + L1 + R2 + 4) >> 3); + tmp += R2; + R_out |= (((tmp + 2) >> 2) << 8); + tmp1 = ((R_in >> 24) + R2) << 1; + R_out |= (((tmp1 + tmp + 4) >> 3) << 16); + + *((uint *)SrcPtr) = R_out; + } + else + *ptr = ((R1 << 1) + R0 + L1 + 2) >> 2; + + + if (ap < 0) + { + L_out = (L_in << 24) >> 24; // Keep L3 at the first byte + + tmp = R0 + L0 + L1; + L_out |= ((((tmp << 1) + R1 + L2 + 4) >> 3) << 24); + tmp += L2; + L_out |= (((tmp + 2) >> 2) << 16); + tmp1 = ((L_in & 0xff) + L2) << 1; + L_out |= (((tmp1 + tmp + 4) >> 3) << 8); + + *((uint *)(SrcPtr - 4)) = L_out; + } + else + *(--ptr) = ((L1 << 1) + L0 + R1 + 2) >> 2; + + } /* if(tmp < 0) */ + + SrcPtr += pitch; // Increment to next set of pixel + + } /* end of: for(pel=0; pel<16; pel++) */ + + } /* if(Strength[0] == 4) */ + + else /* Normal filtering */ + { + + for (pel = 0; pel < 16; pel++) + { + Strng = Strength[pel >> 2]; + if (Strng) + { + // Read 8 pels + R_in = *((uint *)SrcPtr); // R_in = {R3, R2, R1, R0} + L_in = *((uint *)(SrcPtr - 4)); // L_in = {L0, L1, L2, L3} + R1 = (R_in >> 8) & 0xff; + R0 = R_in & 0xff; + L0 = L_in >> 24; + L1 = (L_in >> 16) & 0xff; + + //|R0 - L0| < Alpha + tmp = R0 - L0; + if (tmp < 0) tmp = -tmp; + tmp -= Alpha; + + // |R0 - R1| < Beta + tmp1 = R0 - R1; + if (tmp1 < 0) tmp1 = -tmp1; + tmp &= (tmp1 - Beta); + + //|L0 - L1| < Beta + tmp1 = L0 - L1; + if (tmp1 < 0) tmp1 = -tmp1; + tmp &= (tmp1 - Beta); + + if (tmp < 0) + { + L2 = SrcPtr[-3]; + R2 = SrcPtr[2]; + + // |R0 - R2| < Beta + tmp = R0 - R2; + if (tmp < 0) tmp = -tmp; + aq = tmp - Beta; + + // |L0 - L2| < Beta + tmp = L0 - L2; + if (tmp < 0) tmp = -tmp; + ap = tmp - Beta; + + + c0 = C0 = clipTable[Strng]; + if (ap < 0) c0++; + if (aq < 0) c0++; + + //dif = IClip(-c0, c0, ((Delta << 2) + (L1 - R1) + 4) >> 3); + dif = (((R0 - L0) << 2) + (L1 - R1) + 4) >> 3; + tmp = dif + c0; + if ((uint)tmp > (uint)c0 << 1) + { + tmp = ~(tmp >> 31); + dif = (tmp & (c0 << 1)) - c0; + } + + ptr = SrcPtr; + ptr1 = SrcPtr - 1; + //SrcPtr[0] = (uint8)IClip(0, 255, R0 - dif); + //SrcPtr[-inc] = (uint8)IClip(0, 255, L0 + dif); + R_in = R0 - dif; + L_in = L0 + dif; /* cannot re-use R0 and L0 here */ + if ((uint)R_in > 255) + { + tmp = ~((int)R_in >> 31); + R_in = tmp & 255; + } + if ((uint)L_in > 255) + { + tmp = ~((int)L_in >> 31); + L_in = tmp & 255; + } + *ptr1-- = L_in; + *ptr++ = R_in; + + if (C0 != 0) // Multiple zeros in the clip tables + { + if (ap < 0) //SrcPtr[-inc2] += IClip(-C0, C0,(L2 + ((RL0 + 1) >> 1) - (L1<<1)) >> 1); + { + L2 = (L2 + ((R0 + L0 + 1) >> 1) - (L1 << 1)) >> 1; + tmp = L2 + C0; + if ((uint)tmp > (uint)C0 << 1) + { + tmp = ~(tmp >> 31); + L2 = (tmp & (C0 << 1)) - C0; + } + *ptr1 += L2; + } + + if (aq < 0) // SrcPtr[inc] += IClip(-C0, C0,(R2 + ((RL0 + 1) >> 1) - (R1<<1)) >> 1); + { + R2 = (R2 + ((R0 + L0 + 1) >> 1) - (R1 << 1)) >> 1; + tmp = R2 + C0; + if ((uint)tmp > (uint)C0 << 1) + { + tmp = ~(tmp >> 31); + R2 = (tmp & (C0 << 1)) - C0; + } + *ptr += R2; + } + } + + } /* if(tmp < 0) */ + + } /* end of: if((Strng = Strength[pel >> 2])) */ + + SrcPtr += pitch; // Increment to next set of pixel + + } /* for(pel=0; pel<16; pel++) */ + + } /* else if(Strength[0] == 4) */ + +} + +void EdgeLoop_Chroma_vertical(uint8* SrcPtr, uint8 *Strength, int Alpha, int Beta, int *clipTable, int pitch) +{ + int pel, Strng; + int c0, dif; + int L1, L0, R0, R1, tmp, tmp1; + uint8 *ptr; + uint R_in, L_in; + + + for (pel = 0; pel < 16; pel++) + { + Strng = Strength[pel>>2]; + if (Strng) + { + // Read 8 pels + R_in = *((uint *)SrcPtr); // R_in = {R3, R2, R1, R0} + L_in = *((uint *)(SrcPtr - 4)); // L_in = {L0, L1, L2, L3} + R1 = (R_in >> 8) & 0xff; + R0 = R_in & 0xff; + L0 = L_in >> 24; + L1 = (L_in >> 16) & 0xff; + + // |R0 - R1| < Beta + tmp1 = R0 - R1; + if (tmp1 < 0) tmp1 = -tmp1; + tmp = (tmp1 - Beta); + + //|L0 - L1| < Beta + tmp1 = L0 - L1; + if (tmp1 < 0) tmp1 = -tmp1; + tmp &= (tmp1 - Beta); + + //|R0 - L0| < Alpha + tmp1 = R0 - L0; + if (tmp1 < 0) tmp1 = -tmp1; + tmp &= (tmp1 - Alpha); + + if (tmp < 0) + { + ptr = SrcPtr; + if (Strng == 4) /* INTRA strong filtering */ + { + *ptr-- = ((R1 << 1) + R0 + L1 + 2) >> 2; + *ptr = ((L1 << 1) + L0 + R1 + 2) >> 2; + } + else /* normal filtering */ + { + c0 = clipTable[Strng] + 1; + //dif = IClip(-c0, c0, ((Delta << 2) + (L1 - R1) + 4) >> 3); + dif = (((R0 - L0) << 2) + (L1 - R1) + 4) >> 3; + tmp = dif + c0; + if ((uint)tmp > (uint)c0 << 1) + { + tmp = ~(tmp >> 31); + dif = (tmp & (c0 << 1)) - c0; + } + + //SrcPtr[0] = (uint8)IClip(0, 255, R0 - dif); + //SrcPtr[-inc] = (uint8)IClip(0, 255, L0 + dif); + L0 += dif; + R0 -= dif; + if ((uint)L0 > 255) + { + tmp = ~(L0 >> 31); + L0 = tmp & 255; + } + if ((uint)R0 > 255) + { + tmp = ~(R0 >> 31); + R0 = tmp & 255; + } + + *ptr-- = R0; + *ptr = L0; + } + } + pel ++; + SrcPtr += pitch; // Increment to next set of pixel + + } /* end of: if((Strng = Strength[pel >> 2])) */ + else + { + pel += 3; + SrcPtr += (pitch << 1); //PtrInc << 1; + } + + } /* end of: for(pel=0; pel<16; pel++) */ +} + + +void EdgeLoop_Chroma_horizontal(uint8* SrcPtr, uint8 *Strength, int Alpha, int Beta, int *clipTable, int pitch) +{ + int pel, Strng; + int c0, dif; + int L1, L0, R0, R1, tmp, tmp1; + + for (pel = 0; pel < 16; pel++) + { + Strng = Strength[pel>>2]; + if (Strng) + { + R0 = SrcPtr[0]; + L0 = SrcPtr[-pitch]; + L1 = SrcPtr[-(pitch<<1)]; //inc2 + R1 = SrcPtr[pitch]; + + // |R0 - R1| < Beta + tmp1 = R0 - R1; + if (tmp1 < 0) tmp1 = -tmp1; + tmp = (tmp1 - Beta); + + //|L0 - L1| < Beta + tmp1 = L0 - L1; + if (tmp1 < 0) tmp1 = -tmp1; + tmp &= (tmp1 - Beta); + + //|R0 - L0| < Alpha + tmp1 = R0 - L0; + if (tmp1 < 0) tmp1 = -tmp1; + tmp &= (tmp1 - Alpha); + + if (tmp < 0) + { + if (Strng == 4) /* INTRA strong filtering */ + { + SrcPtr[0] = ((R1 << 1) + R0 + L1 + 2) >> 2; + SrcPtr[-pitch] = ((L1 << 1) + L0 + R1 + 2) >> 2; + } + else /* normal filtering */ + { + c0 = clipTable[Strng] + 1; + //dif = IClip(-c0, c0, ((Delta << 2) + (L1 - R1) + 4) >> 3); + dif = (((R0 - L0) << 2) + (L1 - R1) + 4) >> 3; + tmp = dif + c0; + if ((uint)tmp > (uint)c0 << 1) + { + tmp = ~(tmp >> 31); + dif = (tmp & (c0 << 1)) - c0; + } + + //SrcPtr[-inc] = (uint8)IClip(0, 255, L0 + dif); + //SrcPtr[0] = (uint8)IClip(0, 255, R0 - dif); + L0 += dif; + R0 -= dif; + if ((uint)L0 > 255) + { + tmp = ~(L0 >> 31); + L0 = tmp & 255; + } + if ((uint)R0 > 255) + { + tmp = ~(R0 >> 31); + R0 = tmp & 255; + } + SrcPtr[0] = R0; + SrcPtr[-pitch] = L0; + } + } + + pel ++; + SrcPtr ++; // Increment to next set of pixel + + } /* end of: if((Strng = Strength[pel >> 2])) */ + else + { + pel += 3; + SrcPtr += 2; + } + + } /* end of: for(pel=0; pel<16; pel++) */ +} + + + + diff --git a/media/libstagefright/codecs/avc/common/src/dpb.cpp b/media/libstagefright/codecs/avc/common/src/dpb.cpp new file mode 100644 index 0000000..2c4c7da --- /dev/null +++ b/media/libstagefright/codecs/avc/common/src/dpb.cpp @@ -0,0 +1,724 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 "avclib_common.h" + +#define DPB_MEM_ATTR 0 + +AVCStatus InitDPB(AVCHandle *avcHandle, AVCCommonObj *video, int FrameHeightInMbs, int PicWidthInMbs, bool padding) +{ + AVCDecPicBuffer *dpb = video->decPicBuf; + int level, framesize, num_fs; + void *userData = avcHandle->userData; +#ifndef PV_MEMORY_POOL + uint32 addr; +#endif + uint16 refIdx = 0; + level = video->currSeqParams->level_idc; + + for (num_fs = 0; num_fs < MAX_FS; num_fs++) + { + dpb->fs[num_fs] = NULL; + } + + framesize = (int)(((FrameHeightInMbs * PicWidthInMbs) << 7) * 3); + if (padding) + { + video->padded_size = (int)((((FrameHeightInMbs + 2) * (PicWidthInMbs + 2)) << 7) * 3) - framesize; + } + else + { + video->padded_size = 0; + } + +#ifndef PV_MEMORY_POOL + if (dpb->decoded_picture_buffer) + { + avcHandle->CBAVC_Free(userData, (int)dpb->decoded_picture_buffer); + dpb->decoded_picture_buffer = NULL; + } +#endif + /* need to allocate one extra frame for current frame, DPB only defines for reference frames */ + + dpb->num_fs = (uint32)(MaxDPBX2[mapLev2Idx[level]] << 2) / (3 * FrameHeightInMbs * PicWidthInMbs) + 1; + if (dpb->num_fs > MAX_FS) + { + dpb->num_fs = MAX_FS; + } + + if (video->currSeqParams->num_ref_frames + 1 > (uint32)dpb->num_fs) + { + dpb->num_fs = video->currSeqParams->num_ref_frames + 1; + } + + dpb->dpb_size = dpb->num_fs * (framesize + video->padded_size); +// dpb->dpb_size = (uint32)MaxDPBX2[mapLev2Idx[level]]*512 + framesize; + +#ifndef PV_MEMORY_POOL + dpb->decoded_picture_buffer = (uint8*) avcHandle->CBAVC_Malloc(userData, dpb->dpb_size, 100/*DPB_MEM_ATTR*/); + + if (dpb->decoded_picture_buffer == NULL || dpb->decoded_picture_buffer&0x3) // not word aligned + return AVC_MEMORY_FAIL; +#endif + dpb->used_size = 0; + num_fs = 0; + + while (num_fs < dpb->num_fs) + { + /* fs is an array pointers to AVCDecPicture */ + dpb->fs[num_fs] = (AVCFrameStore*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCFrameStore), 101/*DEFAULT_ATTR*/); + if (dpb->fs[num_fs] == NULL) + { + return AVC_MEMORY_FAIL; + } +#ifndef PV_MEMORY_POOL + /* assign the actual memory for Sl, Scb, Scr */ + dpb->fs[num_fs]->base_dpb = dpb->decoded_picture_buffer + dpb->used_size; +#endif + dpb->fs[num_fs]->IsReference = 0; + dpb->fs[num_fs]->IsLongTerm = 0; + dpb->fs[num_fs]->IsOutputted = 3; + dpb->fs[num_fs]->frame.RefIdx = refIdx++; /* this value will remain unchanged through out the encoding session */ + dpb->fs[num_fs]->frame.picType = AVC_FRAME; + dpb->fs[num_fs]->frame.isLongTerm = 0; + dpb->fs[num_fs]->frame.isReference = 0; + video->RefPicList0[num_fs] = &(dpb->fs[num_fs]->frame); + dpb->fs[num_fs]->frame.padded = 0; + dpb->used_size += (framesize + video->padded_size); + num_fs++; + } + + return AVC_SUCCESS; +} + +OSCL_EXPORT_REF AVCStatus AVCConfigureSequence(AVCHandle *avcHandle, AVCCommonObj *video, bool padding) +{ + void *userData = avcHandle->userData; + AVCDecPicBuffer *dpb = video->decPicBuf; + int framesize, ii; /* size of one frame */ + uint PicWidthInMbs, PicHeightInMapUnits, FrameHeightInMbs, PicSizeInMapUnits; + uint num_fs; + /* derived variables from SPS */ + PicWidthInMbs = video->currSeqParams->pic_width_in_mbs_minus1 + 1; + PicHeightInMapUnits = video->currSeqParams->pic_height_in_map_units_minus1 + 1 ; + FrameHeightInMbs = (2 - video->currSeqParams->frame_mbs_only_flag) * PicHeightInMapUnits ; + PicSizeInMapUnits = PicWidthInMbs * PicHeightInMapUnits ; + + if (video->PicSizeInMapUnits != PicSizeInMapUnits || video->currSeqParams->level_idc != video->level_idc) + { + /* make sure you mark all the frames as unused for reference for flushing*/ + for (ii = 0; ii < dpb->num_fs; ii++) + { + dpb->fs[ii]->IsReference = 0; + dpb->fs[ii]->IsOutputted |= 0x02; + } + + num_fs = (uint32)(MaxDPBX2[(uint32)mapLev2Idx[video->currSeqParams->level_idc]] << 2) / (3 * PicSizeInMapUnits) + 1; + if (num_fs >= MAX_FS) + { + num_fs = MAX_FS; + } +#ifdef PV_MEMORY_POOL + if (padding) + { + avcHandle->CBAVC_DPBAlloc(avcHandle->userData, + PicSizeInMapUnits + ((PicWidthInMbs + 2) << 1) + (PicHeightInMapUnits << 1), num_fs); + } + else + { + avcHandle->CBAVC_DPBAlloc(avcHandle->userData, PicSizeInMapUnits, num_fs); + } +#endif + CleanUpDPB(avcHandle, video); + if (InitDPB(avcHandle, video, FrameHeightInMbs, PicWidthInMbs, padding) != AVC_SUCCESS) + { + return AVC_FAIL; + } + /* Allocate video->mblock upto PicSizeInMbs and populate the structure such as the neighboring MB pointers. */ + framesize = (FrameHeightInMbs * PicWidthInMbs); + if (video->mblock) + { + avcHandle->CBAVC_Free(userData, (uint32)video->mblock); + video->mblock = NULL; + } + video->mblock = (AVCMacroblock*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCMacroblock) * framesize, DEFAULT_ATTR); + if (video->mblock == NULL) + { + return AVC_FAIL; + } + for (ii = 0; ii < framesize; ii++) + { + video->mblock[ii].slice_id = -1; + } + /* Allocate memory for intra prediction */ +#ifdef MB_BASED_DEBLOCK + video->intra_pred_top = (uint8*) avcHandle->CBAVC_Malloc(userData, PicWidthInMbs << 4, FAST_MEM_ATTR); + if (video->intra_pred_top == NULL) + { + return AVC_FAIL; + } + video->intra_pred_top_cb = (uint8*) avcHandle->CBAVC_Malloc(userData, PicWidthInMbs << 3, FAST_MEM_ATTR); + if (video->intra_pred_top_cb == NULL) + { + return AVC_FAIL; + } + video->intra_pred_top_cr = (uint8*) avcHandle->CBAVC_Malloc(userData, PicWidthInMbs << 3, FAST_MEM_ATTR); + if (video->intra_pred_top_cr == NULL) + { + return AVC_FAIL; + } + +#endif + /* Allocate slice group MAP map */ + + if (video->MbToSliceGroupMap) + { + avcHandle->CBAVC_Free(userData, (uint32)video->MbToSliceGroupMap); + video->MbToSliceGroupMap = NULL; + } + video->MbToSliceGroupMap = (int*) avcHandle->CBAVC_Malloc(userData, sizeof(uint) * PicSizeInMapUnits * 2, 7/*DEFAULT_ATTR*/); + if (video->MbToSliceGroupMap == NULL) + { + return AVC_FAIL; + } + video->PicSizeInMapUnits = PicSizeInMapUnits; + video->level_idc = video->currSeqParams->level_idc; + + } + return AVC_SUCCESS; +} + +OSCL_EXPORT_REF AVCStatus CleanUpDPB(AVCHandle *avcHandle, AVCCommonObj *video) +{ + AVCDecPicBuffer *dpb = video->decPicBuf; + int ii; + void *userData = avcHandle->userData; + + for (ii = 0; ii < MAX_FS; ii++) + { + if (dpb->fs[ii] != NULL) + { + avcHandle->CBAVC_Free(userData, (int)dpb->fs[ii]); + dpb->fs[ii] = NULL; + } + } +#ifndef PV_MEMORY_POOL + if (dpb->decoded_picture_buffer) + { + avcHandle->CBAVC_Free(userData, (int)dpb->decoded_picture_buffer); + dpb->decoded_picture_buffer = NULL; + } +#endif + dpb->used_size = 0; + dpb->dpb_size = 0; + + return AVC_SUCCESS; +} + +OSCL_EXPORT_REF AVCStatus DPBInitBuffer(AVCHandle *avcHandle, AVCCommonObj *video) +{ + AVCDecPicBuffer *dpb = video->decPicBuf; + int ii, status; + + /* Before doing any decoding, check if there's a frame memory available */ + /* look for next unused dpb->fs, or complementary field pair */ + /* video->currPic is assigned to this */ + + /* There's also restriction on the frame_num, see page 59 of JVT-I1010.doc. */ + + for (ii = 0; ii < dpb->num_fs; ii++) + { + /* looking for the one not used or not reference and has been outputted */ + if (dpb->fs[ii]->IsReference == 0 && dpb->fs[ii]->IsOutputted == 3) + { + video->currFS = dpb->fs[ii]; +#ifdef PV_MEMORY_POOL + status = avcHandle->CBAVC_FrameBind(avcHandle->userData, ii, &(video->currFS->base_dpb)); + if (status == AVC_FAIL) + { + return AVC_NO_BUFFER; /* this should not happen */ + } +#endif + break; + } + } + if (ii == dpb->num_fs) + { + return AVC_PICTURE_OUTPUT_READY; /* no empty frame available */ + } + return AVC_SUCCESS; +} + +OSCL_EXPORT_REF void DPBInitPic(AVCCommonObj *video, int CurrPicNum) +{ + int offset = 0; + int offsetc = 0; + int luma_framesize; + /* this part has to be set here, assuming that slice header and POC have been decoded. */ + /* used in GetOutput API */ + video->currFS->PicOrderCnt = video->PicOrderCnt; + video->currFS->FrameNum = video->sliceHdr->frame_num; + video->currFS->FrameNumWrap = CurrPicNum; // MC_FIX + /* initialize everything to zero */ + video->currFS->IsOutputted = 0; + video->currFS->IsReference = 0; + video->currFS->IsLongTerm = 0; + video->currFS->frame.isReference = FALSE; + video->currFS->frame.isLongTerm = FALSE; + + /* initialize the pixel pointer to NULL */ + video->currFS->frame.Sl = video->currFS->frame.Scb = video->currFS->frame.Scr = NULL; + + /* determine video->currPic */ + /* assign dbp->base_dpb to fs[i]->frame.Sl, Scb, Scr .*/ + /* For PicSizeInMbs, see DecodeSliceHeader() */ + + video->currPic = &(video->currFS->frame); + + video->currPic->padded = 0; // reset this flag to not-padded + + if (video->padded_size) + { + offset = ((video->PicWidthInSamplesL + 32) << 4) + 16; // offset to the origin + offsetc = (offset >> 2) + 4; + luma_framesize = (int)((((video->FrameHeightInMbs + 2) * (video->PicWidthInMbs + 2)) << 8)); + } + else + luma_framesize = video->PicSizeInMbs << 8; + + + video->currPic->Sl = video->currFS->base_dpb + offset; + video->currPic->Scb = video->currFS->base_dpb + luma_framesize + offsetc; + video->currPic->Scr = video->currPic->Scb + (luma_framesize >> 2); + video->currPic->pitch = video->PicWidthInSamplesL + (video->padded_size == 0 ? 0 : 32); + + + video->currPic->height = video->PicHeightInSamplesL; + video->currPic->width = video->PicWidthInSamplesL; + video->currPic->PicNum = CurrPicNum; +} + +/* to release skipped frame after encoding */ +OSCL_EXPORT_REF void DPBReleaseCurrentFrame(AVCHandle *avcHandle, AVCCommonObj *video) +{ + AVCDecPicBuffer *dpb = video->decPicBuf; + int ii; + + video->currFS->IsOutputted = 3; // return this buffer. + +#ifdef PV_MEMORY_POOL /* for non-memory pool, no need to do anything */ + + /* search for current frame index */ + ii = dpb->num_fs; + while (ii--) + { + if (dpb->fs[ii] == video->currFS) + { + avcHandle->CBAVC_FrameUnbind(avcHandle->userData, ii); + break; + } + } +#endif + + return ; +} + +/* see subclause 8.2.5.1 */ +OSCL_EXPORT_REF AVCStatus StorePictureInDPB(AVCHandle *avcHandle, AVCCommonObj *video) +{ + AVCStatus status; + AVCDecPicBuffer *dpb = video->decPicBuf; + AVCSliceHeader *sliceHdr = video->sliceHdr; + int ii, num_ref; + + /* number 1 of 8.2.5.1, we handle gaps in frame_num differently without using the memory */ + /* to be done!!!! */ + + /* number 3 of 8.2.5.1 */ + if (video->nal_unit_type == AVC_NALTYPE_IDR) + { + for (ii = 0; ii < dpb->num_fs; ii++) + { + if (dpb->fs[ii] != video->currFS) /* not current frame */ + { + dpb->fs[ii]->IsReference = 0; /* mark as unused for reference */ + dpb->fs[ii]->IsLongTerm = 0; /* but still used until output */ + dpb->fs[ii]->IsOutputted |= 0x02; +#ifdef PV_MEMORY_POOL + if (dpb->fs[ii]->IsOutputted == 3) + { + avcHandle->CBAVC_FrameUnbind(avcHandle->userData, ii); + } +#endif + } + } + + video->currPic->isReference = TRUE; + video->currFS->IsReference = 3; + + if (sliceHdr->long_term_reference_flag == 0) + { + video->currPic->isLongTerm = FALSE; + video->currFS->IsLongTerm = 0; + video->MaxLongTermFrameIdx = -1; + } + else + { + video->currPic->isLongTerm = TRUE; + video->currFS->IsLongTerm = 3; + video->currFS->LongTermFrameIdx = 0; + video->MaxLongTermFrameIdx = 0; + } + if (sliceHdr->no_output_of_prior_pics_flag) + { + for (ii = 0; ii < dpb->num_fs; ii++) + { + if (dpb->fs[ii] != video->currFS) /* not current frame */ + { + dpb->fs[ii]->IsOutputted = 3; +#ifdef PV_MEMORY_POOL + avcHandle->CBAVC_FrameUnbind(avcHandle->userData, ii); +#endif + } + } + } + video->mem_mgr_ctrl_eq_5 = TRUE; /* flush reference frames MC_FIX */ + } + else + { + if (video->currPic->isReference == TRUE) + { + if (sliceHdr->adaptive_ref_pic_marking_mode_flag == 0) + { + status = sliding_window_process(avcHandle, video, dpb); /* we may have to do this after adaptive_memory_marking */ + } + else + { + status = adaptive_memory_marking(avcHandle, video, dpb, sliceHdr); + } + if (status != AVC_SUCCESS) + { + return status; + } + } + } + /* number 4 of 8.2.5.1 */ + /* This basically says every frame must be at least used for short-term ref. */ + /* Need to be revisited!!! */ + /* look at insert_picture_in_dpb() */ + + + + if (video->nal_unit_type != AVC_NALTYPE_IDR && video->currPic->isLongTerm == FALSE) + { + if (video->currPic->isReference) + { + video->currFS->IsReference = 3; + } + else + { + video->currFS->IsReference = 0; + } + video->currFS->IsLongTerm = 0; + } + + /* check if number of reference frames doesn't exceed num_ref_frames */ + num_ref = 0; + for (ii = 0; ii < dpb->num_fs; ii++) + { + if (dpb->fs[ii]->IsReference) + { + num_ref++; + } + } + + if (num_ref > (int)video->currSeqParams->num_ref_frames) + { + return AVC_FAIL; /* out of range */ + } + + return AVC_SUCCESS; +} + + +AVCStatus sliding_window_process(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb) +{ + int ii, numShortTerm, numLongTerm; + int32 MinFrameNumWrap; + int MinIdx; + + + numShortTerm = 0; + numLongTerm = 0; + for (ii = 0; ii < dpb->num_fs; ii++) + { + if (dpb->fs[ii] != video->currFS) /* do not count the current frame */ + { + if (dpb->fs[ii]->IsLongTerm) + { + numLongTerm++; + } + else if (dpb->fs[ii]->IsReference) + { + numShortTerm++; + } + } + } + + while (numShortTerm + numLongTerm >= (int)video->currSeqParams->num_ref_frames) + { + /* get short-term ref frame with smallest PicOrderCnt */ + /* this doesn't work for all I-slice clip since PicOrderCnt will not be initialized */ + + MinFrameNumWrap = 0x7FFFFFFF; + MinIdx = -1; + for (ii = 0; ii < dpb->num_fs; ii++) + { + if (dpb->fs[ii]->IsReference && !dpb->fs[ii]->IsLongTerm) + { + if (dpb->fs[ii]->FrameNumWrap < MinFrameNumWrap) + { + MinFrameNumWrap = dpb->fs[ii]->FrameNumWrap; + MinIdx = ii; + } + } + } + if (MinIdx < 0) /* something wrong, impossible */ + { + return AVC_FAIL; + } + + /* mark the frame with smallest PicOrderCnt to be unused for reference */ + dpb->fs[MinIdx]->IsReference = 0; + dpb->fs[MinIdx]->IsLongTerm = 0; + dpb->fs[MinIdx]->frame.isReference = FALSE; + dpb->fs[MinIdx]->frame.isLongTerm = FALSE; + dpb->fs[MinIdx]->IsOutputted |= 0x02; +#ifdef PV_MEMORY_POOL + if (dpb->fs[MinIdx]->IsOutputted == 3) + { + avcHandle->CBAVC_FrameUnbind(avcHandle->userData, MinIdx); + } +#endif + numShortTerm--; + } + return AVC_SUCCESS; +} + +/* see subclause 8.2.5.4 */ +AVCStatus adaptive_memory_marking(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, AVCSliceHeader *sliceHdr) +{ + int ii; + + ii = 0; + while (ii < MAX_DEC_REF_PIC_MARKING && sliceHdr->memory_management_control_operation[ii] != 0) + { + switch (sliceHdr->memory_management_control_operation[ii]) + { + case 1: + MemMgrCtrlOp1(avcHandle, video, dpb, sliceHdr->difference_of_pic_nums_minus1[ii]); + // update_ref_list(dpb); + break; + case 2: + MemMgrCtrlOp2(avcHandle, dpb, sliceHdr->long_term_pic_num[ii]); + break; + case 3: + MemMgrCtrlOp3(avcHandle, video, dpb, sliceHdr->difference_of_pic_nums_minus1[ii], sliceHdr->long_term_frame_idx[ii]); + break; + case 4: + MemMgrCtrlOp4(avcHandle, video, dpb, sliceHdr->max_long_term_frame_idx_plus1[ii]); + break; + case 5: + MemMgrCtrlOp5(avcHandle, video, dpb); + video->currFS->FrameNum = 0; // + video->currFS->PicOrderCnt = 0; + break; + case 6: + MemMgrCtrlOp6(avcHandle, video, dpb, sliceHdr->long_term_frame_idx[ii]); + break; + } + ii++; + } + + if (ii == MAX_DEC_REF_PIC_MARKING) + { + return AVC_FAIL; /* exceed the limit */ + } + + return AVC_SUCCESS; +} + + +/* see subclause 8.2.5.4.1, mark short-term picture as "unused for reference" */ +void MemMgrCtrlOp1(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, int difference_of_pic_nums_minus1) +{ + int picNumX, ii; + + picNumX = video->CurrPicNum - (difference_of_pic_nums_minus1 + 1); + + for (ii = 0; ii < dpb->num_fs; ii++) + { + if (dpb->fs[ii]->IsReference == 3 && dpb->fs[ii]->IsLongTerm == 0) + { + if (dpb->fs[ii]->frame.PicNum == picNumX) + { + unmark_for_reference(avcHandle, dpb, ii); + return ; + } + } + } + + return ; +} + +/* see subclause 8.2.5.4.2 mark long-term picture as "unused for reference" */ +void MemMgrCtrlOp2(AVCHandle *avcHandle, AVCDecPicBuffer *dpb, int long_term_pic_num) +{ + int ii; + + for (ii = 0; ii < dpb->num_fs; ii++) + { + if (dpb->fs[ii]->IsLongTerm == 3) + { + if (dpb->fs[ii]->frame.LongTermPicNum == long_term_pic_num) + { + unmark_for_reference(avcHandle, dpb, ii); + } + } + } +} + +/* see subclause 8.2.5.4.3 assign LongTermFrameIdx to a short-term ref picture */ +void MemMgrCtrlOp3(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, uint difference_of_pic_nums_minus1, + uint long_term_frame_idx) +{ + int picNumX, ii; + + picNumX = video->CurrPicNum - (difference_of_pic_nums_minus1 + 1); + + /* look for fs[i] with long_term_frame_idx */ + + unmark_long_term_frame_for_reference_by_frame_idx(avcHandle, dpb, long_term_frame_idx); + + + /* now mark the picture with picNumX to long term frame idx */ + + for (ii = 0; ii < dpb->num_fs; ii++) + { + if (dpb->fs[ii]->IsReference == 3) + { + if ((dpb->fs[ii]->frame.isLongTerm == FALSE) && (dpb->fs[ii]->frame.PicNum == picNumX)) + { + dpb->fs[ii]->LongTermFrameIdx = long_term_frame_idx; + dpb->fs[ii]->frame.LongTermPicNum = long_term_frame_idx; + + dpb->fs[ii]->frame.isLongTerm = TRUE; + + dpb->fs[ii]->IsLongTerm = 3; + return; + } + } + } + +} + +/* see subclause 8.2.5.4.4, MaxLongTermFrameIdx */ +void MemMgrCtrlOp4(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, uint max_long_term_frame_idx_plus1) +{ + int ii; + + video->MaxLongTermFrameIdx = max_long_term_frame_idx_plus1 - 1; + + /* then mark long term frame with exceeding LongTermFrameIdx to unused for reference. */ + for (ii = 0; ii < dpb->num_fs; ii++) + { + if (dpb->fs[ii]->IsLongTerm && dpb->fs[ii] != video->currFS) + { + if (dpb->fs[ii]->LongTermFrameIdx > video->MaxLongTermFrameIdx) + { + unmark_for_reference(avcHandle, dpb, ii); + } + } + } +} + +/* see subclause 8.2.5.4.5 mark all reference picture as "unused for reference" and setting +MaxLongTermFrameIdx to "no long-term frame indices" */ +void MemMgrCtrlOp5(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb) +{ + int ii; + + video->MaxLongTermFrameIdx = -1; + for (ii = 0; ii < dpb->num_fs; ii++) /* including the current frame ??????*/ + { + if (dpb->fs[ii] != video->currFS) // MC_FIX + { + unmark_for_reference(avcHandle, dpb, ii); + } + } + + video->mem_mgr_ctrl_eq_5 = TRUE; +} + +/* see subclause 8.2.5.4.6 assing long-term frame index to the current picture */ +void MemMgrCtrlOp6(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, uint long_term_frame_idx) +{ + + unmark_long_term_frame_for_reference_by_frame_idx(avcHandle, dpb, long_term_frame_idx); + video->currFS->IsLongTerm = 3; + video->currFS->IsReference = 3; + + video->currPic->isLongTerm = TRUE; + video->currPic->isReference = TRUE; + video->currFS->LongTermFrameIdx = long_term_frame_idx; +} + + +void unmark_for_reference(AVCHandle *avcHandle, AVCDecPicBuffer *dpb, uint idx) +{ + + AVCFrameStore *fs = dpb->fs[idx]; + fs->frame.isReference = FALSE; + fs->frame.isLongTerm = FALSE; + + fs->IsLongTerm = 0; + fs->IsReference = 0; + fs->IsOutputted |= 0x02; +#ifdef PV_MEMORY_POOL + if (fs->IsOutputted == 3) + { + avcHandle->CBAVC_FrameUnbind(avcHandle->userData, idx); + } +#endif + return ; +} + +void unmark_long_term_frame_for_reference_by_frame_idx(AVCHandle *avcHandle, AVCDecPicBuffer *dpb, uint long_term_frame_idx) +{ + int ii; + for (ii = 0; ii < dpb->num_fs; ii++) + { + + if (dpb->fs[ii]->IsLongTerm && (dpb->fs[ii]->LongTermFrameIdx == (int)long_term_frame_idx)) + { + unmark_for_reference(avcHandle, dpb, ii); + } + + } +} + + diff --git a/media/libstagefright/codecs/avc/common/src/fmo.cpp b/media/libstagefright/codecs/avc/common/src/fmo.cpp new file mode 100644 index 0000000..d66eba3 --- /dev/null +++ b/media/libstagefright/codecs/avc/common/src/fmo.cpp @@ -0,0 +1,249 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 + +#include "avclib_common.h" + +/* see subclause 8.2.2 Decoding process for macroblock to slice group map */ +OSCL_EXPORT_REF AVCStatus FMOInit(AVCCommonObj *video) +{ + AVCPicParamSet *currPPS = video->currPicParams; + int *MbToSliceGroupMap = video->MbToSliceGroupMap; + int PicSizeInMapUnits = video->PicSizeInMapUnits; + int PicWidthInMbs = video->PicWidthInMbs; + + if (currPPS->num_slice_groups_minus1 == 0) + { + memset(video->MbToSliceGroupMap, 0, video->PicSizeInMapUnits*sizeof(uint)); + } + else + { + switch (currPPS->slice_group_map_type) + { + case 0: + FmoGenerateType0MapUnitMap(MbToSliceGroupMap, currPPS->run_length_minus1, currPPS->num_slice_groups_minus1, PicSizeInMapUnits); + break; + case 1: + FmoGenerateType1MapUnitMap(MbToSliceGroupMap, PicWidthInMbs, currPPS->num_slice_groups_minus1, PicSizeInMapUnits); + break; + case 2: + FmoGenerateType2MapUnitMap(currPPS, MbToSliceGroupMap, PicWidthInMbs, currPPS->num_slice_groups_minus1, PicSizeInMapUnits); + break; + case 3: + FmoGenerateType3MapUnitMap(video, currPPS, MbToSliceGroupMap, PicWidthInMbs); + break; + case 4: + FmoGenerateType4MapUnitMap(MbToSliceGroupMap, video->MapUnitsInSliceGroup0, currPPS->slice_group_change_direction_flag, PicSizeInMapUnits); + break; + case 5: + FmoGenerateType5MapUnitMap(MbToSliceGroupMap, video, currPPS->slice_group_change_direction_flag, PicSizeInMapUnits); + break; + case 6: + FmoGenerateType6MapUnitMap(MbToSliceGroupMap, (int*)currPPS->slice_group_id, PicSizeInMapUnits); + break; + default: + return AVC_FAIL; /* out of range, shouldn't come this far */ + } + } + + return AVC_SUCCESS; +} + +/* see subclause 8.2.2.1 interleaved slice group map type*/ +void FmoGenerateType0MapUnitMap(int *mapUnitToSliceGroupMap, uint *run_length_minus1, uint num_slice_groups_minus1, uint PicSizeInMapUnits) +{ + uint iGroup, j; + uint i = 0; + do + { + for (iGroup = 0; + (iGroup <= num_slice_groups_minus1) && (i < PicSizeInMapUnits); + i += run_length_minus1[iGroup++] + 1) + { + for (j = 0; j <= run_length_minus1[ iGroup ] && i + j < PicSizeInMapUnits; j++) + mapUnitToSliceGroupMap[i+j] = iGroup; + } + } + while (i < PicSizeInMapUnits); +} + +/* see subclause 8.2.2.2 dispersed slice group map type*/ +void FmoGenerateType1MapUnitMap(int *mapUnitToSliceGroupMap, int PicWidthInMbs, uint num_slice_groups_minus1, uint PicSizeInMapUnits) +{ + uint i; + for (i = 0; i < PicSizeInMapUnits; i++) + { + mapUnitToSliceGroupMap[i] = ((i % PicWidthInMbs) + (((i / PicWidthInMbs) * (num_slice_groups_minus1 + 1)) / 2)) + % (num_slice_groups_minus1 + 1); + } +} + +/* see subclause 8.2.2.3 foreground with left-over slice group map type */ +void FmoGenerateType2MapUnitMap(AVCPicParamSet *pps, int *mapUnitToSliceGroupMap, int PicWidthInMbs, + uint num_slice_groups_minus1, uint PicSizeInMapUnits) +{ + int iGroup; + uint i, x, y; + uint yTopLeft, xTopLeft, yBottomRight, xBottomRight; + + for (i = 0; i < PicSizeInMapUnits; i++) + { + mapUnitToSliceGroupMap[ i ] = num_slice_groups_minus1; + } + + for (iGroup = num_slice_groups_minus1 - 1 ; iGroup >= 0; iGroup--) + { + yTopLeft = pps->top_left[ iGroup ] / PicWidthInMbs; + xTopLeft = pps->top_left[ iGroup ] % PicWidthInMbs; + yBottomRight = pps->bottom_right[ iGroup ] / PicWidthInMbs; + xBottomRight = pps->bottom_right[ iGroup ] % PicWidthInMbs; + for (y = yTopLeft; y <= yBottomRight; y++) + { + for (x = xTopLeft; x <= xBottomRight; x++) + { + mapUnitToSliceGroupMap[ y * PicWidthInMbs + x ] = iGroup; + } + } + } +} + + +/* see subclause 8.2.2.4 box-out slice group map type */ +/* follow the text rather than the JM, it's quite different. */ +void FmoGenerateType3MapUnitMap(AVCCommonObj *video, AVCPicParamSet* pps, int *mapUnitToSliceGroupMap, + int PicWidthInMbs) +{ + uint i, k; + int leftBound, topBound, rightBound, bottomBound; + int x, y, xDir, yDir; + int mapUnitVacant; + uint PicSizeInMapUnits = video->PicSizeInMapUnits; + uint MapUnitsInSliceGroup0 = video->MapUnitsInSliceGroup0; + + for (i = 0; i < PicSizeInMapUnits; i++) + { + mapUnitToSliceGroupMap[ i ] = 1; + } + + x = (PicWidthInMbs - pps->slice_group_change_direction_flag) / 2; + y = (video->PicHeightInMapUnits - pps->slice_group_change_direction_flag) / 2; + + leftBound = x; + topBound = y; + rightBound = x; + bottomBound = y; + + xDir = pps->slice_group_change_direction_flag - 1; + yDir = pps->slice_group_change_direction_flag; + + for (k = 0; k < MapUnitsInSliceGroup0; k += mapUnitVacant) + { + mapUnitVacant = (mapUnitToSliceGroupMap[ y * PicWidthInMbs + x ] == 1); + if (mapUnitVacant) + { + mapUnitToSliceGroupMap[ y * PicWidthInMbs + x ] = 0; + } + + if (xDir == -1 && x == leftBound) + { + leftBound = AVC_MAX(leftBound - 1, 0); + x = leftBound; + xDir = 0; + yDir = 2 * pps->slice_group_change_direction_flag - 1; + } + else if (xDir == 1 && x == rightBound) + { + rightBound = AVC_MIN(rightBound + 1, (int)PicWidthInMbs - 1); + x = rightBound; + xDir = 0; + yDir = 1 - 2 * pps->slice_group_change_direction_flag; + } + else if (yDir == -1 && y == topBound) + { + topBound = AVC_MAX(topBound - 1, 0); + y = topBound; + xDir = 1 - 2 * pps->slice_group_change_direction_flag; + yDir = 0; + } + else if (yDir == 1 && y == bottomBound) + { + bottomBound = AVC_MIN(bottomBound + 1, (int)video->PicHeightInMapUnits - 1); + y = bottomBound; + xDir = 2 * pps->slice_group_change_direction_flag - 1; + yDir = 0; + } + else + { + x = x + xDir; + y = y + yDir; + } + } +} + +/* see subclause 8.2.2.5 raster scan slice group map types */ +void FmoGenerateType4MapUnitMap(int *mapUnitToSliceGroupMap, int MapUnitsInSliceGroup0, int slice_group_change_direction_flag, uint PicSizeInMapUnits) +{ + uint sizeOfUpperLeftGroup = slice_group_change_direction_flag ? (PicSizeInMapUnits - MapUnitsInSliceGroup0) : MapUnitsInSliceGroup0; + + uint i; + + for (i = 0; i < PicSizeInMapUnits; i++) + if (i < sizeOfUpperLeftGroup) + mapUnitToSliceGroupMap[ i ] = 1 - slice_group_change_direction_flag; + else + mapUnitToSliceGroupMap[ i ] = slice_group_change_direction_flag; + +} + +/* see subclause 8.2.2.6, wipe slice group map type. */ +void FmoGenerateType5MapUnitMap(int *mapUnitToSliceGroupMap, AVCCommonObj *video, + int slice_group_change_direction_flag, uint PicSizeInMapUnits) +{ + int PicWidthInMbs = video->PicWidthInMbs; + int PicHeightInMapUnits = video->PicHeightInMapUnits; + int MapUnitsInSliceGroup0 = video->MapUnitsInSliceGroup0; + int sizeOfUpperLeftGroup = slice_group_change_direction_flag ? (PicSizeInMapUnits - MapUnitsInSliceGroup0) : MapUnitsInSliceGroup0; + int i, j, k = 0; + + for (j = 0; j < PicWidthInMbs; j++) + { + for (i = 0; i < PicHeightInMapUnits; i++) + { + if (k++ < sizeOfUpperLeftGroup) + { + mapUnitToSliceGroupMap[ i * PicWidthInMbs + j ] = 1 - slice_group_change_direction_flag; + } + else + { + mapUnitToSliceGroupMap[ i * PicWidthInMbs + j ] = slice_group_change_direction_flag; + } + } + } +} + +/* see subclause 8.2.2.7, explicit slice group map */ +void FmoGenerateType6MapUnitMap(int *mapUnitToSliceGroupMap, int *slice_group_id, uint PicSizeInMapUnits) +{ + uint i; + for (i = 0; i < PicSizeInMapUnits; i++) + { + mapUnitToSliceGroupMap[i] = slice_group_id[i]; + } +} + + diff --git a/media/libstagefright/codecs/avc/common/src/mb_access.cpp b/media/libstagefright/codecs/avc/common/src/mb_access.cpp new file mode 100644 index 0000000..414b8f7 --- /dev/null +++ b/media/libstagefright/codecs/avc/common/src/mb_access.cpp @@ -0,0 +1,471 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 + +#include "avclib_common.h" + +OSCL_EXPORT_REF void InitNeighborAvailability(AVCCommonObj *video, int mbNum) +{ + int PicWidthInMbs = video->PicWidthInMbs; + + // do frame-only and postpone intraAvail calculattion + video->mbAddrA = mbNum - 1; + video->mbAddrB = mbNum - PicWidthInMbs; + video->mbAddrC = mbNum - PicWidthInMbs + 1; + video->mbAddrD = mbNum - PicWidthInMbs - 1; + + video->mbAvailA = video->mbAvailB = video->mbAvailC = video->mbAvailD = 0; + if (video->mb_x) + { + video->mbAvailA = (video->mblock[video->mbAddrA].slice_id == video->currMB->slice_id); + if (video->mb_y) + { + video->mbAvailD = (video->mblock[video->mbAddrD].slice_id == video->currMB->slice_id); + } + } + + if (video->mb_y) + { + video->mbAvailB = (video->mblock[video->mbAddrB].slice_id == video->currMB->slice_id); + if (video->mb_x < (PicWidthInMbs - 1)) + { + video->mbAvailC = (video->mblock[video->mbAddrC].slice_id == video->currMB->slice_id); + } + } + return ; +} + +bool mb_is_available(AVCMacroblock *mblock, uint PicSizeInMbs, int mbAddr, int currMbAddr) +{ + if (mbAddr < 0 || mbAddr >= (int)PicSizeInMbs) + { + return FALSE; + } + + if (mblock[mbAddr].slice_id != mblock[currMbAddr].slice_id) + { + return FALSE; + } + + return TRUE; +} + +OSCL_EXPORT_REF int predict_nnz(AVCCommonObj *video, int i, int j) +{ + int pred_nnz = 0; + int cnt = 1; + AVCMacroblock *tempMB; + + /* left block */ + /*getLuma4x4Neighbour(video, mb_nr, i, j, -1, 0, &pix); + leftMB = video->mblock + pix.mb_addr; */ + /* replace the above with below (won't work for field decoding), 1/19/04 */ + + if (i) + { + pred_nnz = video->currMB->nz_coeff[(j<<2)+i-1]; + } + else + { + if (video->mbAvailA) + { + tempMB = video->mblock + video->mbAddrA; + pred_nnz = tempMB->nz_coeff[(j<<2)+3]; + } + else + { + cnt = 0; + } + } + + + /* top block */ + /*getLuma4x4Neighbour(video, mb_nr, i, j, 0, -1, &pix); + topMB = video->mblock + pix.mb_addr;*/ + /* replace the above with below (won't work for field decoding), 1/19/04 */ + + if (j) + { + pred_nnz += video->currMB->nz_coeff[((j-1)<<2)+i]; + cnt++; + } + else + { + if (video->mbAvailB) + { + tempMB = video->mblock + video->mbAddrB; + pred_nnz += tempMB->nz_coeff[12+i]; + cnt++; + } + } + + + if (cnt == 2) + { + pred_nnz = (pred_nnz + 1) >> 1; + } + + return pred_nnz; + +} + + +OSCL_EXPORT_REF int predict_nnz_chroma(AVCCommonObj *video, int i, int j) +{ + int pred_nnz = 0; + int cnt = 1; + AVCMacroblock *tempMB; + + /* left block */ + /*getChroma4x4Neighbour(video, mb_nr, i%2, j-4, -1, 0, &pix); + leftMB = video->mblock + pix.mb_addr;*/ + /* replace the above with below (won't work for field decoding), 1/19/04 */ + if (i&1) + { + pred_nnz = video->currMB->nz_coeff[(j<<2)+i-1]; + + } + else + { + if (video->mbAvailA) + { + tempMB = video->mblock + video->mbAddrA; + pred_nnz = tempMB->nz_coeff[(j<<2)+i+1]; + } + else + { + cnt = 0; + } + } + + + /* top block */ + /*getChroma4x4Neighbour(video, mb_nr, i%2, j-4, 0, -1, &pix); + topMB = video->mblock + pix.mb_addr;*/ + /* replace the above with below (won't work for field decoding), 1/19/04 */ + + if (j&1) + { + pred_nnz += video->currMB->nz_coeff[((j-1)<<2)+i]; + cnt++; + } + else + { + if (video->mbAvailB) + { + tempMB = video->mblock + video->mbAddrB; + pred_nnz += tempMB->nz_coeff[20+i]; + cnt++; + } + + } + + if (cnt == 2) + { + pred_nnz = (pred_nnz + 1) >> 1; + } + + return pred_nnz; +} + +OSCL_EXPORT_REF void GetMotionVectorPredictor(AVCCommonObj *video, int encFlag) +{ + AVCMacroblock *currMB = video->currMB; + AVCMacroblock *MB_A, *MB_B, *MB_C, *MB_D; + int block_x, block_y, block_x_1, block_y_1, new_block_x; + int mbPartIdx, subMbPartIdx, offset_indx; + int16 *mv, pmv_x, pmv_y; + int nmSubMbHeight, nmSubMbWidth, mbPartIdx_X, mbPartIdx_Y; + int avail_a, avail_b, avail_c; + const static uint32 C = 0x5750; + int i, j, offset_MbPart_indx, refIdxLXA, refIdxLXB, refIdxLXC = 0, curr_ref_idx; + int pmv_A_x, pmv_B_x, pmv_C_x = 0, pmv_A_y, pmv_B_y, pmv_C_y = 0; + + /* we have to take care of Intra/skip blocks somewhere, i.e. set MV to 0 and set ref to -1! */ + /* we have to populate refIdx as well */ + + + MB_A = &video->mblock[video->mbAddrA]; + MB_B = &video->mblock[video->mbAddrB]; + + + if (currMB->mbMode == AVC_SKIP /* && !encFlag */) /* only for decoder */ + { + currMB->ref_idx_L0[0] = currMB->ref_idx_L0[1] = currMB->ref_idx_L0[2] = currMB->ref_idx_L0[3] = 0; + if (video->mbAvailA && video->mbAvailB) + { + if ((MB_A->ref_idx_L0[1] == 0 && MB_A->mvL0[3] == 0) || + (MB_B->ref_idx_L0[2] == 0 && MB_B->mvL0[12] == 0)) + { + memset(currMB->mvL0, 0, sizeof(int32)*16); + return; + } + } + else + { + memset(currMB->mvL0, 0, sizeof(int32)*16); + return; + } + video->mvd_l0[0][0][0] = 0; + video->mvd_l0[0][0][1] = 0; + } + + MB_C = &video->mblock[video->mbAddrC]; + MB_D = &video->mblock[video->mbAddrD]; + + offset_MbPart_indx = 0; + for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++) + { + offset_indx = 0; + nmSubMbHeight = currMB->SubMbPartHeight[mbPartIdx] >> 2; + nmSubMbWidth = currMB->SubMbPartWidth[mbPartIdx] >> 2; + mbPartIdx_X = ((mbPartIdx + offset_MbPart_indx) & 1) << 1; + mbPartIdx_Y = (mbPartIdx + offset_MbPart_indx) & 2; + + for (subMbPartIdx = 0; subMbPartIdx < currMB->NumSubMbPart[mbPartIdx]; subMbPartIdx++) + { + block_x = mbPartIdx_X + ((subMbPartIdx + offset_indx) & 1); + block_y = mbPartIdx_Y + (((subMbPartIdx + offset_indx) >> 1) & 1); + + block_x_1 = block_x - 1; + block_y_1 = block_y - 1; + refIdxLXA = refIdxLXB = refIdxLXC = -1; + pmv_A_x = pmv_A_y = pmv_B_x = pmv_B_y = pmv_C_x = pmv_C_y = 0; + + if (block_x) + { + avail_a = 1; + refIdxLXA = currMB->ref_idx_L0[(block_y & 2) + (block_x_1 >> 1)]; + mv = (int16*)(currMB->mvL0 + (block_y << 2) + block_x_1); + pmv_A_x = *mv++; + pmv_A_y = *mv; + } + else + { + avail_a = video->mbAvailA; + if (avail_a) + { + refIdxLXA = MB_A->ref_idx_L0[(block_y & 2) + 1]; + mv = (int16*)(MB_A->mvL0 + (block_y << 2) + 3); + pmv_A_x = *mv++; + pmv_A_y = *mv; + } + } + + if (block_y) + { + avail_b = 1; + refIdxLXB = currMB->ref_idx_L0[(block_y_1 & 2) + (block_x >> 1)]; + mv = (int16*)(currMB->mvL0 + (block_y_1 << 2) + block_x); + pmv_B_x = *mv++; + pmv_B_y = *mv; + } + + else + { + avail_b = video->mbAvailB; + if (avail_b) + { + refIdxLXB = MB_B->ref_idx_L0[2 + (block_x >> 1)]; + mv = (int16*)(MB_B->mvL0 + 12 + block_x); + pmv_B_x = *mv++; + pmv_B_y = *mv; + } + } + + new_block_x = block_x + (currMB->SubMbPartWidth[mbPartIdx] >> 2) - 1; + avail_c = (C >> ((block_y << 2) + new_block_x)) & 0x1; + + if (avail_c) + { + /* it guaranteed that block_y > 0 && new_block_x<3 ) */ + refIdxLXC = currMB->ref_idx_L0[(block_y_1 & 2) + ((new_block_x+1) >> 1)]; + mv = (int16*)(currMB->mvL0 + (block_y_1 << 2) + (new_block_x + 1)); + pmv_C_x = *mv++; + pmv_C_y = *mv; + } + else + { + if (block_y == 0 && new_block_x < 3) + { + avail_c = video->mbAvailB; + if (avail_c) + { + refIdxLXC = MB_B->ref_idx_L0[2 + ((new_block_x+1)>>1)]; + mv = (int16*)(MB_B->mvL0 + 12 + (new_block_x + 1)); + pmv_C_x = *mv++; + pmv_C_y = *mv; + } + } + else if (block_y == 0 && new_block_x == 3) + { + avail_c = video->mbAvailC; + if (avail_c) + { + refIdxLXC = MB_C->ref_idx_L0[2]; + mv = (int16*)(MB_C->mvL0 + 12); + pmv_C_x = *mv++; + pmv_C_y = *mv; + } + } + + if (avail_c == 0) + { /* check D */ + if (block_x && block_y) + { + avail_c = 1; + refIdxLXC = currMB->ref_idx_L0[(block_y_1 & 2) + (block_x_1 >> 1)]; + mv = (int16*)(currMB->mvL0 + (block_y_1 << 2) + block_x_1); + pmv_C_x = *mv++; + pmv_C_y = *mv; + } + else if (block_y) + { + avail_c = video->mbAvailA; + if (avail_c) + { + refIdxLXC = MB_A->ref_idx_L0[(block_y_1 & 2) + 1]; + mv = (int16*)(MB_A->mvL0 + (block_y_1 << 2) + 3); + pmv_C_x = *mv++; + pmv_C_y = *mv; + } + } + else if (block_x) + { + avail_c = video->mbAvailB; + if (avail_c) + { + refIdxLXC = MB_B->ref_idx_L0[2 + (block_x_1 >> 1)]; + mv = (int16*)(MB_B->mvL0 + 12 + block_x_1); + pmv_C_x = *mv++; + pmv_C_y = *mv; + } + } + else + { + avail_c = video->mbAvailD; + if (avail_c) + { + refIdxLXC = MB_D->ref_idx_L0[3]; + mv = (int16*)(MB_D->mvL0 + 15); + pmv_C_x = *mv++; + pmv_C_y = *mv; + } + } + } + } + + offset_indx = currMB->SubMbPartWidth[mbPartIdx] >> 3; + + curr_ref_idx = currMB->ref_idx_L0[(block_y & 2) + (block_x >> 1)]; + + if (avail_a && !(avail_b || avail_c)) + { + pmv_x = pmv_A_x; + pmv_y = pmv_A_y; + } + else if (((curr_ref_idx == refIdxLXA) + (curr_ref_idx == refIdxLXB) + (curr_ref_idx == refIdxLXC)) == 1) + { + if (curr_ref_idx == refIdxLXA) + { + pmv_x = pmv_A_x; + pmv_y = pmv_A_y; + } + else if (curr_ref_idx == refIdxLXB) + { + pmv_x = pmv_B_x; + pmv_y = pmv_B_y; + } + else + { + pmv_x = pmv_C_x; + pmv_y = pmv_C_y; + } + } + else + { + pmv_x = AVC_MEDIAN(pmv_A_x, pmv_B_x, pmv_C_x); + pmv_y = AVC_MEDIAN(pmv_A_y, pmv_B_y, pmv_C_y); + } + + /* overwrite if special case */ + if (currMB->NumMbPart == 2) + { + if (currMB->MbPartWidth == 16) + { + if (mbPartIdx == 0) + { + if (refIdxLXB == curr_ref_idx) + { + pmv_x = pmv_B_x; + pmv_y = pmv_B_y; + } + } + else if (refIdxLXA == curr_ref_idx) + { + pmv_x = pmv_A_x; + pmv_y = pmv_A_y; + } + } + else + { + if (mbPartIdx == 0) + { + if (refIdxLXA == curr_ref_idx) + { + pmv_x = pmv_A_x; + pmv_y = pmv_A_y; + } + } + else if (refIdxLXC == curr_ref_idx) + { + pmv_x = pmv_C_x; + pmv_y = pmv_C_y; + } + } + } + + mv = (int16*)(currMB->mvL0 + block_x + (block_y << 2)); + + if (encFlag) /* calculate residual MV video->mvd_l0 */ + { + video->mvd_l0[mbPartIdx][subMbPartIdx][0] = *mv++ - pmv_x; + video->mvd_l0[mbPartIdx][subMbPartIdx][1] = *mv++ - pmv_y; + } + else /* calculate original MV currMB->mvL0 */ + { + pmv_x += video->mvd_l0[mbPartIdx][subMbPartIdx][0]; + pmv_y += video->mvd_l0[mbPartIdx][subMbPartIdx][1]; + + for (i = 0; i < nmSubMbHeight; i++) + { + for (j = 0; j < nmSubMbWidth; j++) + { + *mv++ = pmv_x; + *mv++ = pmv_y; + } + mv += (8 - (j << 1)); + } + } + } + offset_MbPart_indx = currMB->MbPartWidth >> 4; + + } +} + + diff --git a/media/libstagefright/codecs/avc/common/src/reflist.cpp b/media/libstagefright/codecs/avc/common/src/reflist.cpp new file mode 100644 index 0000000..4ddc7dd --- /dev/null +++ b/media/libstagefright/codecs/avc/common/src/reflist.cpp @@ -0,0 +1,596 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 "avclib_common.h" + +/** see subclause 8.2.4 Decoding process for reference picture lists construction. */ +OSCL_EXPORT_REF void RefListInit(AVCCommonObj *video) +{ + AVCSliceHeader *sliceHdr = video->sliceHdr; + AVCDecPicBuffer *dpb = video->decPicBuf; + int slice_type = video->slice_type; + int i, list0idx; + + AVCPictureData *tmp_s; + + list0idx = 0; + + if (slice_type == AVC_I_SLICE) + { + video->refList0Size = 0; + video->refList1Size = 0; + + /* we still have to calculate FrameNumWrap to make sure that all I-slice clip + can perform sliding_window_operation properly. */ + + for (i = 0; i < dpb->num_fs; i++) + { + if ((dpb->fs[i]->IsReference == 3) && (!dpb->fs[i]->IsLongTerm)) + { + /* subclause 8.2.4.1 Decoding process for picture numbers. */ + if (dpb->fs[i]->FrameNum > (int)sliceHdr->frame_num) + { + dpb->fs[i]->FrameNumWrap = dpb->fs[i]->FrameNum - video->MaxFrameNum; + } + else + { + dpb->fs[i]->FrameNumWrap = dpb->fs[i]->FrameNum; + } + dpb->fs[i]->frame.PicNum = dpb->fs[i]->FrameNumWrap; + } + } + + + return ; + } + if (slice_type == AVC_P_SLICE) + { + /* Calculate FrameNumWrap and PicNum */ + + for (i = 0; i < dpb->num_fs; i++) + { + if ((dpb->fs[i]->IsReference == 3) && (!dpb->fs[i]->IsLongTerm)) + { + /* subclause 8.2.4.1 Decoding process for picture numbers. */ + if (dpb->fs[i]->FrameNum > (int)sliceHdr->frame_num) + { + dpb->fs[i]->FrameNumWrap = dpb->fs[i]->FrameNum - video->MaxFrameNum; + } + else + { + dpb->fs[i]->FrameNumWrap = dpb->fs[i]->FrameNum; + } + dpb->fs[i]->frame.PicNum = dpb->fs[i]->FrameNumWrap; + video->RefPicList0[list0idx++] = &(dpb->fs[i]->frame); + } + } + + if (list0idx == 0) + { + dpb->fs[0]->IsReference = 3; + video->RefPicList0[0] = &(dpb->fs[0]->frame); + list0idx = 1; + } + /* order list 0 by PicNum from max to min, see subclause 8.2.4.2.1 */ + SortPicByPicNum(video->RefPicList0, list0idx); + video->refList0Size = list0idx; + + /* long term handling */ + for (i = 0; i < dpb->num_fs; i++) + { + if (dpb->fs[i]->IsLongTerm == 3) + { + /* subclause 8.2.4.1 Decoding process for picture numbers. */ + dpb->fs[i]->frame.LongTermPicNum = dpb->fs[i]->LongTermFrameIdx; + video->RefPicList0[list0idx++] = &(dpb->fs[i]->frame); + } + } + + /* order PicNum from min to max, see subclause 8.2.4.2.1 */ + SortPicByPicNumLongTerm(&(video->RefPicList0[video->refList0Size]), list0idx - video->refList0Size); + video->refList0Size = list0idx; + + + video->refList1Size = 0; + } + + + if ((video->refList0Size == video->refList1Size) && (video->refList0Size > 1)) + { + /* check if lists are identical, if yes swap first two elements of listX[1] */ + /* last paragraph of subclause 8.2.4.2.4 */ + + for (i = 0; i < video->refList0Size; i++) + { + if (video->RefPicList0[i] != video->RefPicList1[i]) + { + break; + } + } + if (i == video->refList0Size) + { + tmp_s = video->RefPicList1[0]; + video->RefPicList1[0] = video->RefPicList1[1]; + video->RefPicList1[1] = tmp_s; + } + } + + /* set max size */ + video->refList0Size = AVC_MIN(video->refList0Size, (int)video->sliceHdr->num_ref_idx_l0_active_minus1 + 1); + video->refList1Size = AVC_MIN(video->refList1Size, (int)video->sliceHdr->num_ref_idx_l1_active_minus1 + 1); + + return ; +} +/* see subclause 8.2.4.3 */ +OSCL_EXPORT_REF AVCStatus ReOrderList(AVCCommonObj *video) +{ + AVCSliceHeader *sliceHdr = video->sliceHdr; + AVCStatus status = AVC_SUCCESS; + int slice_type = video->slice_type; + + if (slice_type != AVC_I_SLICE) + { + if (sliceHdr->ref_pic_list_reordering_flag_l0) + { + status = ReorderRefPicList(video, 0); + if (status != AVC_SUCCESS) + return status; + } + if (video->refList0Size == 0) + { + return AVC_FAIL; + } + } + return status; +} + +AVCStatus ReorderRefPicList(AVCCommonObj *video, int isL1) +{ + AVCSliceHeader *sliceHdr = video->sliceHdr; + AVCStatus status; + + int *list_size; + int num_ref_idx_lX_active_minus1; + uint *remapping_of_pic_nums_idc; + int *abs_diff_pic_num_minus1; + int *long_term_pic_idx; + int i; + int maxPicNum, currPicNum, picNumLXNoWrap, picNumLXPred, picNumLX; + int refIdxLX = 0; + void* tmp; + + if (!isL1) /* list 0 */ + { + list_size = &(video->refList0Size); + num_ref_idx_lX_active_minus1 = sliceHdr->num_ref_idx_l0_active_minus1; + remapping_of_pic_nums_idc = sliceHdr->reordering_of_pic_nums_idc_l0; + tmp = (void*)sliceHdr->abs_diff_pic_num_minus1_l0; + abs_diff_pic_num_minus1 = (int*) tmp; + tmp = (void*)sliceHdr->long_term_pic_num_l0; + long_term_pic_idx = (int*) tmp; + } + else + { + list_size = &(video->refList1Size); + num_ref_idx_lX_active_minus1 = sliceHdr->num_ref_idx_l1_active_minus1; + remapping_of_pic_nums_idc = sliceHdr->reordering_of_pic_nums_idc_l1; + tmp = (void*) sliceHdr->abs_diff_pic_num_minus1_l1; + abs_diff_pic_num_minus1 = (int*) tmp; + tmp = (void*) sliceHdr->long_term_pic_num_l1; + long_term_pic_idx = (int*)tmp; + } + + maxPicNum = video->MaxPicNum; + currPicNum = video->CurrPicNum; + + picNumLXPred = currPicNum; /* initial value */ + + for (i = 0; remapping_of_pic_nums_idc[i] != 3; i++) + { + if ((remapping_of_pic_nums_idc[i] > 3) || (i >= MAX_REF_PIC_LIST_REORDERING)) + { + return AVC_FAIL; /* out of range */ + } + /* see subclause 8.2.4.3.1 */ + if (remapping_of_pic_nums_idc[i] < 2) + { + if (remapping_of_pic_nums_idc[i] == 0) + { + if (picNumLXPred - (abs_diff_pic_num_minus1[i] + 1) < 0) + picNumLXNoWrap = picNumLXPred - (abs_diff_pic_num_minus1[i] + 1) + maxPicNum; + else + picNumLXNoWrap = picNumLXPred - (abs_diff_pic_num_minus1[i] + 1); + } + else /* (remapping_of_pic_nums_idc[i] == 1) */ + { + if (picNumLXPred + (abs_diff_pic_num_minus1[i] + 1) >= maxPicNum) + picNumLXNoWrap = picNumLXPred + (abs_diff_pic_num_minus1[i] + 1) - maxPicNum; + else + picNumLXNoWrap = picNumLXPred + (abs_diff_pic_num_minus1[i] + 1); + } + picNumLXPred = picNumLXNoWrap; /* prediction for the next one */ + + if (picNumLXNoWrap > currPicNum) + picNumLX = picNumLXNoWrap - maxPicNum; + else + picNumLX = picNumLXNoWrap; + + status = ReorderShortTerm(video, picNumLX, &refIdxLX, isL1); + if (status != AVC_SUCCESS) + { + return status; + } + } + else /* (remapping_of_pic_nums_idc[i] == 2), subclause 8.2.4.3.2 */ + { + status = ReorderLongTerm(video, long_term_pic_idx[i], &refIdxLX, isL1); + if (status != AVC_SUCCESS) + { + return status; + } + } + } + /* that's a definition */ + *list_size = num_ref_idx_lX_active_minus1 + 1; + + return AVC_SUCCESS; +} + +/* see subclause 8.2.4.3.1 */ +AVCStatus ReorderShortTerm(AVCCommonObj *video, int picNumLX, int *refIdxLX, int isL1) +{ + int cIdx, nIdx; + int num_ref_idx_lX_active_minus1; + AVCPictureData *picLX, **RefPicListX; + + if (!isL1) /* list 0 */ + { + RefPicListX = video->RefPicList0; + num_ref_idx_lX_active_minus1 = video->sliceHdr->num_ref_idx_l0_active_minus1; + } + else + { + RefPicListX = video->RefPicList1; + num_ref_idx_lX_active_minus1 = video->sliceHdr->num_ref_idx_l1_active_minus1; + } + + picLX = GetShortTermPic(video, picNumLX); + + if (picLX == NULL) + { + return AVC_FAIL; + } + /* Note RefPicListX has to access element number num_ref_idx_lX_active */ + /* There could be access violation here. */ + if (num_ref_idx_lX_active_minus1 + 1 >= MAX_REF_PIC_LIST) + { + return AVC_FAIL; + } + + for (cIdx = num_ref_idx_lX_active_minus1 + 1; cIdx > *refIdxLX; cIdx--) + { + RefPicListX[ cIdx ] = RefPicListX[ cIdx - 1]; + } + + RefPicListX[(*refIdxLX)++ ] = picLX; + + nIdx = *refIdxLX; + + for (cIdx = *refIdxLX; cIdx <= num_ref_idx_lX_active_minus1 + 1; cIdx++) + { + if (RefPicListX[ cIdx ]) + { + if ((RefPicListX[ cIdx ]->isLongTerm) || ((int)RefPicListX[ cIdx ]->PicNum != picNumLX)) + { + RefPicListX[ nIdx++ ] = RefPicListX[ cIdx ]; + } + } + } + return AVC_SUCCESS; +} + +/* see subclause 8.2.4.3.2 */ +AVCStatus ReorderLongTerm(AVCCommonObj *video, int LongTermPicNum, int *refIdxLX, int isL1) +{ + AVCPictureData **RefPicListX; + int num_ref_idx_lX_active_minus1; + int cIdx, nIdx; + AVCPictureData *picLX; + + if (!isL1) /* list 0 */ + { + RefPicListX = video->RefPicList0; + num_ref_idx_lX_active_minus1 = video->sliceHdr->num_ref_idx_l0_active_minus1; + } + else + { + RefPicListX = video->RefPicList1; + num_ref_idx_lX_active_minus1 = video->sliceHdr->num_ref_idx_l1_active_minus1; + } + + picLX = GetLongTermPic(video, LongTermPicNum); + if (picLX == NULL) + { + return AVC_FAIL; + } + /* Note RefPicListX has to access element number num_ref_idx_lX_active */ + /* There could be access violation here. */ + if (num_ref_idx_lX_active_minus1 + 1 >= MAX_REF_PIC_LIST) + { + return AVC_FAIL; + } + for (cIdx = num_ref_idx_lX_active_minus1 + 1; cIdx > *refIdxLX; cIdx--) + RefPicListX[ cIdx ] = RefPicListX[ cIdx - 1]; + + RefPicListX[(*refIdxLX)++ ] = picLX; + + nIdx = *refIdxLX; + + for (cIdx = *refIdxLX; cIdx <= num_ref_idx_lX_active_minus1 + 1; cIdx++) + { + if ((!RefPicListX[ cIdx ]->isLongTerm) || ((int)RefPicListX[ cIdx ]->LongTermPicNum != LongTermPicNum)) + { + RefPicListX[ nIdx++ ] = RefPicListX[ cIdx ]; + } + } + return AVC_SUCCESS; +} + + +AVCPictureData* GetShortTermPic(AVCCommonObj *video, int picNum) +{ + int i; + AVCDecPicBuffer *dpb = video->decPicBuf; + + for (i = 0; i < dpb->num_fs; i++) + { + + if (dpb->fs[i]->IsReference == 3) + { + if ((dpb->fs[i]->frame.isLongTerm == FALSE) && (dpb->fs[i]->frame.PicNum == picNum)) + { + return &(dpb->fs[i]->frame); + } + } + + } + + return NULL; +} + +AVCPictureData* GetLongTermPic(AVCCommonObj *video, int LongtermPicNum) +{ + AVCDecPicBuffer *dpb = video->decPicBuf; + int i; + + for (i = 0; i < dpb->num_fs; i++) + { + + if (dpb->fs[i]->IsReference == 3) + { + if ((dpb->fs[i]->frame.isLongTerm == TRUE) && (dpb->fs[i]->frame.LongTermPicNum == LongtermPicNum)) + { + return &(dpb->fs[i]->frame); + } + } + + } + return NULL; +} + +int is_short_ref(AVCPictureData *s) +{ + return ((s->isReference) && !(s->isLongTerm)); +} + +int is_long_ref(AVCPictureData *s) +{ + return ((s->isReference) && (s->isLongTerm)); +} + + +/* sort by PicNum, descending order */ +void SortPicByPicNum(AVCPictureData *data[], int num) +{ + int i, j; + AVCPictureData *temp; + + for (i = 0; i < num - 1; i++) + { + for (j = i + 1; j < num; j++) + { + if (data[j]->PicNum > data[i]->PicNum) + { + temp = data[j]; + data[j] = data[i]; + data[i] = temp; + } + } + } + + return ; +} + +/* sort by PicNum, ascending order */ +void SortPicByPicNumLongTerm(AVCPictureData *data[], int num) +{ + int i, j; + AVCPictureData *temp; + + for (i = 0; i < num - 1; i++) + { + for (j = i + 1; j < num; j++) + { + if (data[j]->LongTermPicNum < data[i]->LongTermPicNum) + { + temp = data[j]; + data[j] = data[i]; + data[i] = temp; + } + } + } + + return ; +} + + +/* sort by FrameNumWrap, descending order */ +void SortFrameByFrameNumWrap(AVCFrameStore *data[], int num) +{ + int i, j; + AVCFrameStore *temp; + + for (i = 0; i < num - 1; i++) + { + for (j = i + 1; j < num; j++) + { + if (data[j]->FrameNumWrap > data[i]->FrameNumWrap) + { + temp = data[j]; + data[j] = data[i]; + data[i] = temp; + } + } + } + + return ; +} + +/* sort frames by LongTermFrameIdx, ascending order */ +void SortFrameByLTFrameIdx(AVCFrameStore *data[], int num) +{ + int i, j; + AVCFrameStore *temp; + + for (i = 0; i < num - 1; i++) + { + for (j = i + 1; j < num; j++) + { + if (data[j]->LongTermFrameIdx < data[i]->LongTermFrameIdx) + { + temp = data[j]; + data[j] = data[i]; + data[i] = temp; + } + } + } + + return ; +} + +/* sort PictureData by POC in descending order */ +void SortPicByPOC(AVCPictureData *data[], int num, int descending) +{ + int i, j; + AVCPictureData *temp; + + if (descending) + { + for (i = 0; i < num - 1; i++) + { + for (j = i + 1; j < num; j++) + { + if (data[j]->PicOrderCnt > data[i]->PicOrderCnt) + { + temp = data[j]; + data[j] = data[i]; + data[i] = temp; + } + } + } + } + else + { + for (i = 0; i < num - 1; i++) + { + for (j = i + 1; j < num; j++) + { + if (data[j]->PicOrderCnt < data[i]->PicOrderCnt) + { + temp = data[j]; + data[j] = data[i]; + data[i] = temp; + } + } + } + } + return ; +} + +/* sort PictureData by LongTermPicNum in ascending order */ +void SortPicByLTPicNum(AVCPictureData *data[], int num) +{ + int i, j; + AVCPictureData *temp; + + for (i = 0; i < num - 1; i++) + { + for (j = i + 1; j < num; j++) + { + if (data[j]->LongTermPicNum < data[i]->LongTermPicNum) + { + temp = data[j]; + data[j] = data[i]; + data[i] = temp; + } + } + } + + return ; +} + +/* sort by PicOrderCnt, descending order */ +void SortFrameByPOC(AVCFrameStore *data[], int num, int descending) +{ + int i, j; + AVCFrameStore *temp; + + if (descending) + { + for (i = 0; i < num - 1; i++) + { + for (j = i + 1; j < num; j++) + { + if (data[j]->PicOrderCnt > data[i]->PicOrderCnt) + { + temp = data[j]; + data[j] = data[i]; + data[i] = temp; + } + } + } + } + else + { + for (i = 0; i < num - 1; i++) + { + for (j = i + 1; j < num; j++) + { + if (data[j]->PicOrderCnt < data[i]->PicOrderCnt) + { + temp = data[j]; + data[j] = data[i]; + data[i] = temp; + } + } + } + } + + return ; +} + + diff --git a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp new file mode 100644 index 0000000..0fc9622 --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp @@ -0,0 +1,439 @@ +/* + * 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. + */ + +#include "AVCDecoder.h" + +#include "avcdec_api.h" +#include "avcdec_int.h" + +#include + +#include +#include +#include +#include +#include +#include + +namespace android { + +static int32_t Malloc(void *userData, int32_t size, int32_t attrs) { + return reinterpret_cast(malloc(size)); +} + +static void Free(void *userData, int32_t ptr) { + free(reinterpret_cast(ptr)); +} + +AVCDecoder::AVCDecoder(const sp &source) + : mSource(source), + mStarted(false), + mHandle(new tagAVCHandle), + mInputBuffer(NULL), + mAnchorTimeUs(0), + mNumSamplesOutput(0) { + memset(mHandle, 0, sizeof(tagAVCHandle)); + mHandle->AVCObject = NULL; + mHandle->userData = this; + mHandle->CBAVC_DPBAlloc = ActivateSPSWrapper; + mHandle->CBAVC_FrameBind = BindFrameWrapper; + mHandle->CBAVC_FrameUnbind = UnbindFrame; + mHandle->CBAVC_Malloc = Malloc; + mHandle->CBAVC_Free = Free; + + mFormat = new MetaData; + mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); + int32_t width, height; + CHECK(mSource->getFormat()->findInt32(kKeyWidth, &width)); + CHECK(mSource->getFormat()->findInt32(kKeyHeight, &height)); + mFormat->setInt32(kKeyWidth, width); + mFormat->setInt32(kKeyHeight, height); + mFormat->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar); + mFormat->setCString(kKeyDecoderComponent, "AVCDecoder"); +} + +AVCDecoder::~AVCDecoder() { + if (mStarted) { + stop(); + } + + delete mHandle; + mHandle = NULL; +} + +status_t AVCDecoder::start(MetaData *) { + CHECK(!mStarted); + + uint32_t type; + const void *data; + size_t size; + if (mSource->getFormat()->findData(kKeyAVCC, &type, &data, &size)) { + // Parse the AVCDecoderConfigurationRecord + + const uint8_t *ptr = (const uint8_t *)data; + + CHECK(size >= 7); + CHECK_EQ(ptr[0], 1); // configurationVersion == 1 + uint8_t profile = ptr[1]; + uint8_t level = ptr[3]; + + // There is decodable content out there that fails the following + // assertion, let's be lenient for now... + // CHECK((ptr[4] >> 2) == 0x3f); // reserved + + size_t lengthSize = 1 + (ptr[4] & 3); + + // commented out check below as H264_QVGA_500_NO_AUDIO.3gp + // violates it... + // CHECK((ptr[5] >> 5) == 7); // reserved + + size_t numSeqParameterSets = ptr[5] & 31; + + ptr += 6; + size -= 6; + + for (size_t i = 0; i < numSeqParameterSets; ++i) { + CHECK(size >= 2); + size_t length = U16_AT(ptr); + + ptr += 2; + size -= 2; + + CHECK(size >= length); + + addCodecSpecificData(ptr, length); + + ptr += length; + size -= length; + } + + CHECK(size >= 1); + size_t numPictureParameterSets = *ptr; + ++ptr; + --size; + + for (size_t i = 0; i < numPictureParameterSets; ++i) { + CHECK(size >= 2); + size_t length = U16_AT(ptr); + + ptr += 2; + size -= 2; + + CHECK(size >= length); + + addCodecSpecificData(ptr, length); + + ptr += length; + size -= length; + } + } + + sp params = new MetaData; + params->setInt32(kKeyWantsNALFragments, true); + mSource->start(params.get()); + + mAnchorTimeUs = 0; + mNumSamplesOutput = 0; + mStarted = true; + + return OK; +} + +void AVCDecoder::addCodecSpecificData(const uint8_t *data, size_t size) { + MediaBuffer *buffer = new MediaBuffer(size); + memcpy(buffer->data(), data, size); + buffer->set_range(0, size); + + mCodecSpecificData.push(buffer); +} + +status_t AVCDecoder::stop() { + CHECK(mStarted); + + for (size_t i = 0; i < mCodecSpecificData.size(); ++i) { + (*mCodecSpecificData.editItemAt(i)).release(); + } + mCodecSpecificData.clear(); + + if (mInputBuffer) { + mInputBuffer->release(); + mInputBuffer = NULL; + } + + mSource->stop(); + + releaseFrames(); + + mStarted = false; + + return OK; +} + +sp AVCDecoder::getFormat() { + return mFormat; +} + +status_t AVCDecoder::read( + MediaBuffer **out, const ReadOptions *options) { + *out = NULL; + + if (mInputBuffer == NULL) { + LOGV("fetching new input buffer."); + + if (!mCodecSpecificData.isEmpty()) { + mInputBuffer = mCodecSpecificData.editItemAt(0); + mCodecSpecificData.removeAt(0); + } else { + for (;;) { + status_t err = mSource->read(&mInputBuffer); + if (err != OK) { + return err; + } + + if (mInputBuffer->range_length() > 0) { + break; + } + + mInputBuffer->release(); + mInputBuffer = NULL; + } + } + } + + const uint8_t *inPtr = + (const uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset(); + + int nalType; + int nalRefIdc; + AVCDec_Status res = + PVAVCDecGetNALType( + const_cast(inPtr), mInputBuffer->range_length(), + &nalType, &nalRefIdc); + + if (res != AVCDEC_SUCCESS) { + mInputBuffer->release(); + mInputBuffer = NULL; + + return UNKNOWN_ERROR; + } + + switch (nalType) { + case AVC_NALTYPE_SPS: + { + res = PVAVCDecSeqParamSet( + mHandle, const_cast(inPtr), + mInputBuffer->range_length()); + + if (res != AVCDEC_SUCCESS) { + mInputBuffer->release(); + mInputBuffer = NULL; + + return UNKNOWN_ERROR; + } + + AVCDecObject *pDecVid = (AVCDecObject *)mHandle->AVCObject; + + int32_t width = + (pDecVid->seqParams[0]->pic_width_in_mbs_minus1 + 1) * 16; + + int32_t height = + (pDecVid->seqParams[0]->pic_height_in_map_units_minus1 + 1) * 16; + + int32_t crop_left, crop_right, crop_top, crop_bottom; + if (pDecVid->seqParams[0]->frame_cropping_flag) + { + crop_left = 2 * pDecVid->seqParams[0]->frame_crop_left_offset; + crop_right = + width - (2 * pDecVid->seqParams[0]->frame_crop_right_offset + 1); + + if (pDecVid->seqParams[0]->frame_mbs_only_flag) + { + crop_top = 2 * pDecVid->seqParams[0]->frame_crop_top_offset; + crop_bottom = + height - + (2 * pDecVid->seqParams[0]->frame_crop_bottom_offset + 1); + } + else + { + crop_top = 4 * pDecVid->seqParams[0]->frame_crop_top_offset; + crop_bottom = + height - + (4 * pDecVid->seqParams[0]->frame_crop_bottom_offset + 1); + } + } else { + crop_bottom = height - 1; + crop_right = width - 1; + crop_top = crop_left = 0; + } + + mFormat->setInt32(kKeyWidth, crop_right - crop_left + 1); + mFormat->setInt32(kKeyHeight, crop_bottom - crop_top + 1); + + mInputBuffer->release(); + mInputBuffer = NULL; + + return INFO_FORMAT_CHANGED; + } + + case AVC_NALTYPE_PPS: + { + res = PVAVCDecPicParamSet( + mHandle, const_cast(inPtr), + mInputBuffer->range_length()); + + mInputBuffer->release(); + mInputBuffer = NULL; + + if (res != AVCDEC_SUCCESS) { + return UNKNOWN_ERROR; + } + + *out = new MediaBuffer(0); + + return OK; + } + + case AVC_NALTYPE_SLICE: + case AVC_NALTYPE_IDR: + { + res = PVAVCDecodeSlice( + mHandle, const_cast(inPtr), + mInputBuffer->range_length()); + + if (res == AVCDEC_PICTURE_OUTPUT_READY) { + int32_t index; + int32_t Release; + AVCFrameIO Output; + Output.YCbCr[0] = Output.YCbCr[1] = Output.YCbCr[2] = NULL; + CHECK_EQ(PVAVCDecGetOutput( + mHandle, &index, &Release, &Output), + AVCDEC_SUCCESS); + + CHECK(index >= 0); + CHECK(index < (int32_t)mFrames.size()); + + *out = mFrames.editItemAt(index); + (*out)->set_range(0, (*out)->size()); + (*out)->add_ref(); + + // Do _not_ release input buffer yet. + + return OK; + } + + mInputBuffer->release(); + mInputBuffer = NULL; + + if (res == AVCDEC_PICTURE_READY) { + *out = new MediaBuffer(0); + + return OK; + } else { + return UNKNOWN_ERROR; + } + } + + case AVC_NALTYPE_SEI: + { + res = PVAVCDecodeSlice( + mHandle, const_cast(inPtr), + mInputBuffer->range_length()); + + mInputBuffer->release(); + mInputBuffer = NULL; + + if (res != AVCDEC_SUCCESS) { + return UNKNOWN_ERROR; + } + + *out = new MediaBuffer(0); + + return OK; + } + + default: + { + LOGE("Should not be here, unknown nalType %d", nalType); + CHECK(!"Should not be here"); + break; + } + } + + mInputBuffer->release(); + mInputBuffer = NULL; + + return UNKNOWN_ERROR; +} + +// static +int32_t AVCDecoder::ActivateSPSWrapper( + void *userData, unsigned int sizeInMbs, unsigned int numBuffers) { + return static_cast(userData)->activateSPS(sizeInMbs, numBuffers); +} + +// static +int32_t AVCDecoder::BindFrameWrapper( + void *userData, int32_t index, uint8_t **yuv) { + return static_cast(userData)->bindFrame(index, yuv); +} + +// static +void AVCDecoder::UnbindFrame(void *userData, int32_t index) { +} + +int32_t AVCDecoder::activateSPS( + unsigned int sizeInMbs, unsigned int numBuffers) { + CHECK(mFrames.isEmpty()); + + size_t frameSize = (sizeInMbs << 7) * 3; + for (unsigned int i = 0; i < numBuffers; ++i) { + MediaBuffer *buffer = new MediaBuffer(frameSize); + buffer->setObserver(this); + + mFrames.push(buffer); + } + + return 1; +} + +int32_t AVCDecoder::bindFrame(int32_t index, uint8_t **yuv) { + CHECK(index >= 0); + CHECK(index < (int32_t)mFrames.size()); + + CHECK(mInputBuffer != NULL); + int64_t timeUs; + CHECK(mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)); + mFrames[index]->meta_data()->setInt64(kKeyTime, timeUs); + + *yuv = (uint8_t *)mFrames[index]->data(); + + return 1; +} + +void AVCDecoder::releaseFrames() { + for (size_t i = 0; i < mFrames.size(); ++i) { + MediaBuffer *buffer = mFrames.editItemAt(i); + + buffer->setObserver(NULL); + buffer->release(); + } + mFrames.clear(); +} + +void AVCDecoder::signalBufferReturned(MediaBuffer *buffer) { +} + +} // namespace android diff --git a/media/libstagefright/codecs/avc/dec/Android.mk b/media/libstagefright/codecs/avc/dec/Android.mk new file mode 100644 index 0000000..2a1c8e0 --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/Android.mk @@ -0,0 +1,27 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + AVCDecoder.cpp \ + src/avcdec_api.cpp \ + src/avc_bitstream.cpp \ + src/header.cpp \ + src/itrans.cpp \ + src/pred_inter.cpp \ + src/pred_intra.cpp \ + src/residual.cpp \ + src/slice.cpp \ + src/vlc.cpp + +LOCAL_MODULE := libstagefright_avcdec + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/src \ + $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/../common/include \ + $(TOP)/frameworks/base/media/libstagefright/include \ + $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include + +LOCAL_CFLAGS := -DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF= + +include $(BUILD_STATIC_LIBRARY) diff --git a/media/libstagefright/codecs/avc/dec/include/avcdec_api.h b/media/libstagefright/codecs/avc/dec/include/avcdec_api.h new file mode 100644 index 0000000..f6a14b7 --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/include/avcdec_api.h @@ -0,0 +1,200 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 file contains application function interfaces to the AVC decoder library +and necessary type defitionitions and enumerations. +@publishedAll +*/ + +#ifndef _AVCDEC_API_H_ +#define _AVCDEC_API_H_ + +#include "avcapi_common.h" + +/** + This enumeration is used for the status returned from the library interface. +*/ +typedef enum +{ + /** + The followings are fail with details. Their values are negative. + */ + AVCDEC_NO_DATA = -4, + AVCDEC_PACKET_LOSS = -3, + /** + Fail information + */ + AVCDEC_NO_BUFFER = -2, /* no output picture buffer available */ + AVCDEC_MEMORY_FAIL = -1, /* memory allocation failed */ + AVCDEC_FAIL = 0, + /** + Generic success value + */ + AVCDEC_SUCCESS = 1, + AVCDEC_PICTURE_OUTPUT_READY = 2, + AVCDEC_PICTURE_READY = 3, + + /** + The followings are success with warnings. Their values are positive integers. + */ + AVCDEC_NO_NEXT_SC = 4, + AVCDEC_REDUNDANT_FRAME = 5, + AVCDEC_CONCEALED_FRAME = 6 /* detect and conceal the error */ +} AVCDec_Status; + + +/** +This structure contains sequence parameters information. +*/ +typedef struct tagAVCDecSPSInfo +{ + int FrameWidth; + int FrameHeight; + uint frame_only_flag; + int frame_crop_left; + int frame_crop_right; + int frame_crop_top; + int frame_crop_bottom; + +} AVCDecSPSInfo; + + +#ifdef __cplusplus +extern "C" +{ +#endif + /** THE FOLLOWINGS ARE APIS */ + /** + This function parses one NAL unit from byte stream format input according to Annex B. + \param "bitstream" "Pointer to the bitstream buffer." + \param "nal_unit" "Point to pointer and the location of the start of the first NAL unit + found in bitstream." + \param "size" "As input, the pointer to the size of bitstream in bytes. As output, + the value is changed to be the size of the found NAL unit." + \return "AVCDEC_SUCCESS if success, AVCDEC_FAIL if no first start code is found, AVCDEC_NO_NEX_SC if + the first start code is found, but the second start code is missing (potential partial NAL)." + */ + OSCL_IMPORT_REF AVCDec_Status PVAVCAnnexBGetNALUnit(uint8 *bitstream, uint8 **nal_unit, int *size); + + /** + This function sniffs the nal_unit_type such that users can call corresponding APIs. + \param "bitstream" "Pointer to the beginning of a NAL unit (start with forbidden_zero_bit, etc.)." + \param "size" "size of the bitstream (NumBytesInNALunit + 1)." + \param "nal_unit_type" "Pointer to the return value of nal unit type." + \return "AVCDEC_SUCCESS if success, AVCDEC_FAIL otherwise." + */ + OSCL_IMPORT_REF AVCDec_Status PVAVCDecGetNALType(uint8 *bitstream, int size, int *nal_type, int *nal_ref_idc); + + /** + This function decodes the sequence parameters set, initializes related parameters and + allocates memory (reference frames list), must also be compliant with Annex A. + It is equivalent to decode VOL header of MPEG4. + \param "avcHandle" "Handle to the AVC decoder library object." + \param "nal_unit" "Pointer to the buffer containing single NAL unit. + The content will change due to EBSP-to-RBSP conversion." + \param "nal_size" "size of the bitstream NumBytesInNALunit." + \return "AVCDEC_SUCCESS if success, + AVCDEC_FAIL if profile and level is not supported, + AVCDEC_MEMORY_FAIL if memory allocations return null." + */ + OSCL_IMPORT_REF AVCDec_Status PVAVCDecSeqParamSet(AVCHandle *avcHandle, uint8 *nal_unit, int nal_size); + + /** + This function returns sequence parameters such as dimension and field flag of the most recently + decoded SPS. More can be added later or grouped together into a structure. This API can be called + after PVAVCInitSequence. If no sequence parameter has been decoded yet, it will return AVCDEC_FAIL. + + \param "avcHandle" "Handle to the AVC decoder library object." + \param "seqInfo" "Pointer to the AVCDecSeqParamInfo structure." + \return "AVCDEC_SUCCESS if success and AVCDEC_FAIL if fail." + \note "This API can be combined with PVAVCInitSequence if wanted to be consistent with m4vdec lib." + */ + OSCL_IMPORT_REF AVCDec_Status PVAVCDecGetSeqInfo(AVCHandle *avcHandle, AVCDecSPSInfo *seqInfo); + + /** + This function decodes the picture parameters set and initializes related parameters. Note thate + the PPS may not be present for every picture. + \param "avcHandle" "Handle to the AVC decoder library object." + \param "nal_unit" "Pointer to the buffer containing single NAL unit. + The content will change due to EBSP-to-RBSP conversion." + \param "nal_size" "size of the bitstream NumBytesInNALunit." + \return "AVCDEC_SUCCESS if success, AVCDEC_FAIL if profile and level is not supported." + */ + OSCL_IMPORT_REF AVCDec_Status PVAVCDecPicParamSet(AVCHandle *avcHandle, uint8 *nal_unit, int nal_size); + + /** + This function decodes one NAL unit of bitstream. The type of nal unit is one of the + followings, 1, 5. (for now, no data partitioning, type 2,3,4). + \param "avcHandle" "Handle to the AVC decoder library object." + \param "nal_unit" "Pointer to the buffer containing a single or partial NAL unit. + The content will change due to EBSP-to-RBSP conversion." + \param "buf_size" "Size of the buffer (less than or equal nal_size)." + \param "nal_size" "size of the current NAL unit NumBytesInNALunit." + \return "AVCDEC_PICTURE_READY for success and an output is ready, + AVCDEC_SUCCESS for success but no output is ready, + AVCDEC_PACKET_LOSS is GetData returns AVCDEC_PACKET_LOSS, + AVCDEC_FAIL if syntax error is detected, + AVCDEC_MEMORY_FAIL if memory is corrupted. + AVCDEC_NO_PICTURE if no frame memory to write to (users need to get output and/or return picture). + AVCDEC_REDUNDANT_PICTURE if error has been detected in the primary picture and redundant picture is available, + AVCDEC_CONCEALED_PICTURE if error has been detected and decoder has concealed it." + */ + OSCL_IMPORT_REF AVCDec_Status PVAVCDecSEI(AVCHandle *avcHandle, uint8 *nal_unit, int nal_size); + + OSCL_IMPORT_REF AVCDec_Status PVAVCDecodeSlice(AVCHandle *avcHandle, uint8 *buffer, int buf_size); + + /** + Check the availability of the decoded picture in decoding order (frame_num). + The AVCFrameIO also provide displaying order information such that the application + can re-order the frame for display. A picture can be retrieved only once. + \param "avcHandle" "Handle to the AVC decoder library object." + \param "output" "Pointer to the AVCOutput structure. Note that decoder library will + not re-used the pixel memory in this structure until it has been returned + thru PVAVCReleaseOutput API." + \return "AVCDEC_SUCCESS for success, AVCDEC_FAIL if no picture is available to be displayed, + AVCDEC_PICTURE_READY if there is another picture to be displayed." + */ + OSCL_IMPORT_REF AVCDec_Status PVAVCDecGetOutput(AVCHandle *avcHandle, int *indx, int *release_flag, AVCFrameIO *output); + + /** + This function resets the decoder and expects to see the next IDR slice. + \param "avcHandle" "Handle to the AVC decoder library object." + */ + OSCL_IMPORT_REF void PVAVCDecReset(AVCHandle *avcHandle); + + /** + This function performs clean up operation including memory deallocation. + \param "avcHandle" "Handle to the AVC decoder library object." + */ + OSCL_IMPORT_REF void PVAVCCleanUpDecoder(AVCHandle *avcHandle); +//AVCDec_Status EBSPtoRBSP(uint8 *nal_unit,int *size); + + + + /** CALLBACK FUNCTION TO BE IMPLEMENTED BY APPLICATION */ + /** In AVCHandle structure, userData is a pointer to an object with the following + member functions. + */ + AVCDec_Status CBAVCDec_GetData(uint32 *userData, unsigned char **buffer, unsigned int *size); + +#ifdef __cplusplus +} +#endif + +#endif /* _AVCDEC_API_H_ */ + diff --git a/media/libstagefright/codecs/avc/dec/include/pvavcdecoder.h b/media/libstagefright/codecs/avc/dec/include/pvavcdecoder.h new file mode 100644 index 0000000..6b196de --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/include/pvavcdecoder.h @@ -0,0 +1,49 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 PVAVCDECODER_H_INCLUDED +#define PVAVCDECODER_H_INCLUDED + +#ifndef PVAVCDECODERINTERFACE_H_INCLUDED +#include "pvavcdecoderinterface.h" +#endif + +// AVC video decoder +class PVAVCDecoder : public PVAVCDecoderInterface +{ + public: + virtual ~PVAVCDecoder(); + static PVAVCDecoder* New(void); + virtual bool InitAVCDecoder(FunctionType_SPS, FunctionType_Alloc, FunctionType_Unbind, + FunctionType_Malloc, FunctionType_Free, void *); + virtual void CleanUpAVCDecoder(void); + virtual void ResetAVCDecoder(void); + virtual int32 DecodeSPS(uint8 *bitstream, int32 buffer_size); + virtual int32 DecodePPS(uint8 *bitstream, int32 buffer_size); + virtual int32 DecodeAVCSlice(uint8 *bitstream, int32 *buffer_size); + virtual bool GetDecOutput(int *indx, int *release); + virtual void GetVideoDimensions(int32 *width, int32 *height, int32 *top, int32 *left, int32 *bottom, int32 *right); + int AVC_Malloc(int32 size, int attribute); + void AVC_Free(int mem); + + private: + PVAVCDecoder(); + bool Construct(void); + void *iAVCHandle; +}; + +#endif diff --git a/media/libstagefright/codecs/avc/dec/include/pvavcdecoder_factory.h b/media/libstagefright/codecs/avc/dec/include/pvavcdecoder_factory.h new file mode 100644 index 0000000..440f8ec --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/include/pvavcdecoder_factory.h @@ -0,0 +1,43 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 PVAVCDECODER_FACTORY_H_INCLUDED +#define PVAVCDECODER_FACTORY_H_INCLUDED + +class PVAVCDecoderInterface; + +class PVAVCDecoderFactory +{ + public: + /** + * Creates an instance of a PVAVCDecoder. If the creation fails, this function will leave. + * + * @returns A pointer to an instance of PVAVCDecoder as PVAVCDecoderInterface reference or leaves if instantiation fails + **/ + OSCL_IMPORT_REF static PVAVCDecoderInterface* CreatePVAVCDecoder(void); + + /** + * Deletes an instance of PVAVCDecoder and reclaims all allocated resources. + * + * @param aVideoDec The PVAVCDecoder instance to be deleted + * @returns A status code indicating success or failure of deletion + **/ + OSCL_IMPORT_REF static bool DeletePVAVCDecoder(PVAVCDecoderInterface* aVideoDec); +}; + +#endif + diff --git a/media/libstagefright/codecs/avc/dec/include/pvavcdecoderinterface.h b/media/libstagefright/codecs/avc/dec/include/pvavcdecoderinterface.h new file mode 100644 index 0000000..027212d --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/include/pvavcdecoderinterface.h @@ -0,0 +1,48 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 PVAVCDECODERINTERFACE_H_INCLUDED +#define PVAVCDECODERINTERFACE_H_INCLUDED + +typedef void (*FunctionType_Unbind)(void *, int); +typedef int (*FunctionType_Alloc)(void *, int, uint8 **); +typedef int (*FunctionType_SPS)(void *, uint, uint); +typedef int (*FunctionType_Malloc)(void *, int32, int); +typedef void(*FunctionType_Free)(void *, int); + + +// PVAVCDecoderInterface pure virtual interface class +class PVAVCDecoderInterface +{ + public: + virtual ~PVAVCDecoderInterface() {}; + virtual bool InitAVCDecoder(FunctionType_SPS, FunctionType_Alloc, FunctionType_Unbind, + FunctionType_Malloc, FunctionType_Free, void *) = 0; + virtual void CleanUpAVCDecoder(void) = 0; + virtual void ResetAVCDecoder(void) = 0; + virtual int32 DecodeSPS(uint8 *bitstream, int32 buffer_size) = 0; + virtual int32 DecodePPS(uint8 *bitstream, int32 buffer_size) = 0; + virtual int32 DecodeAVCSlice(uint8 *bitstream, int32 *buffer_size) = 0; + virtual bool GetDecOutput(int *indx, int *release) = 0; + virtual void GetVideoDimensions(int32 *width, int32 *height, int32 *top, int32 *left, int32 *bottom, int32 *right) = 0; +// virtual int AVC_Malloc(int32 size, int attribute); +// virtual void AVC_Free(int mem); +}; + +#endif // PVAVCDECODERINTERFACE_H_INCLUDED + + diff --git a/media/libstagefright/codecs/avc/dec/src/avc_bitstream.cpp b/media/libstagefright/codecs/avc/dec/src/avc_bitstream.cpp new file mode 100644 index 0000000..270b664 --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/src/avc_bitstream.cpp @@ -0,0 +1,276 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 "avcdec_bitstream.h" + +/* Swapping may not be needed anymore since we read one byte at a time and perform +EBSP to RBSP conversion in bitstream. */ +#ifdef LITTLE_ENDIAN +#if (WORD_SIZE==32) /* this can be replaced with assembly instructions */ +#define SWAP_BYTES(x) ((((x)&0xFF)<<24) | (((x)&0xFF00)<<8) | (((x)&0xFF0000)>>8) | (((x)&0xFF000000)>>24)) +#else /* for 16-bit */ +#define SWAP_BYTES(x) ((((x)&0xFF)<<8) | (((x)&0xFF00)>>8)) +#endif +#else +#define SWAP_BYTES(x) (x) +#endif + + +/* array for trailing bit pattern as function of number of bits */ +/* the first one is unused. */ +const static uint8 trailing_bits[9] = {0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80}; + +/* ======================================================================== */ +/* Function : BitstreamInit() */ +/* Date : 11/4/2003 */ +/* Purpose : Populate bitstream structure with bitstream buffer and size */ +/* it also initializes internal data */ +/* In/out : */ +/* Return : AVCDEC_SUCCESS if successed, AVCDEC_FAIL if failed. */ +/* Modified : */ +/* ======================================================================== */ +/* |--------|--------|----~~~~~-----|---------|---------|---------| + ^ ^read_pos ^data_end_pos + bitstreamBuffer <---------> + current_word + + |xxxxxxxxxxxxx----| = current_word 32 or 16 bits + <------------> + bit_left + ======================================================================== */ + + +/* ======================================================================== */ +/* Function : BitstreamNextWord() */ +/* Date : 12/4/2003 */ +/* Purpose : Read up to machine word. */ +/* In/out : */ +/* Return : Next word with emulation prevention code removed. Everything + in the bitstream structure got modified except current_word */ +/* Modified : */ +/* ======================================================================== */ + +AVCDec_Status BitstreamInit(AVCDecBitstream *stream, uint8 *buffer, int size) +{ + EBSPtoRBSP(buffer, &size); + + stream->incnt = 0; + stream->incnt_next = 0; + stream->bitcnt = 0; + stream->curr_word = stream->next_word = 0; + stream->read_pos = 0; + + stream->bitstreamBuffer = buffer; + + stream->data_end_pos = size; + + stream->nal_size = size; + + return AVCDEC_SUCCESS; +} +/* ======================================================================== */ +/* Function : AVC_BitstreamFillCache() */ +/* Date : 1/1/2005 */ +/* Purpose : Read up to machine word. */ +/* In/out : */ +/* Return : Read in 4 bytes of input data */ +/* Modified : */ +/* ======================================================================== */ + +AVCDec_Status AVC_BitstreamFillCache(AVCDecBitstream *stream) +{ + uint8 *bitstreamBuffer = stream->bitstreamBuffer; + uint8 *v; + int num_bits, i; + + stream->curr_word |= (stream->next_word >> stream->incnt); // stream->incnt cannot be 32 + stream->next_word <<= (31 - stream->incnt); + stream->next_word <<= 1; + num_bits = stream->incnt_next + stream->incnt; + if (num_bits >= 32) + { + stream->incnt_next -= (32 - stream->incnt); + stream->incnt = 32; + return AVCDEC_SUCCESS; + } + /* this check can be removed if there is additional extra 4 bytes at the end of the bitstream */ + v = bitstreamBuffer + stream->read_pos; + + if (stream->read_pos > stream->data_end_pos - 4) + { + if (stream->data_end_pos <= stream->read_pos) + { + stream->incnt = num_bits; + stream->incnt_next = 0; + return AVCDEC_SUCCESS; + } + + stream->next_word = 0; + + for (i = 0; i < stream->data_end_pos - stream->read_pos; i++) + { + stream->next_word |= (v[i] << ((3 - i) << 3)); + } + + stream->read_pos = stream->data_end_pos; + stream->curr_word |= (stream->next_word >> num_bits); // this is safe + + stream->next_word <<= (31 - num_bits); + stream->next_word <<= 1; + num_bits = i << 3; + stream->incnt += stream->incnt_next; + stream->incnt_next = num_bits - (32 - stream->incnt); + if (stream->incnt_next < 0) + { + stream->incnt += num_bits; + stream->incnt_next = 0; + } + else + { + stream->incnt = 32; + } + return AVCDEC_SUCCESS; + } + + stream->next_word = ((uint32)v[0] << 24) | (v[1] << 16) | (v[2] << 8) | v[3]; + stream->read_pos += 4; + + stream->curr_word |= (stream->next_word >> num_bits); // this is safe + stream->next_word <<= (31 - num_bits); + stream->next_word <<= 1; + stream->incnt_next += stream->incnt; + stream->incnt = 32; + return AVCDEC_SUCCESS; + +} +/* ======================================================================== */ +/* Function : BitstreamReadBits() */ +/* Date : 11/4/2003 */ +/* Purpose : Read up to machine word. */ +/* In/out : */ +/* Return : AVCDEC_SUCCESS if successed, AVCDEC_FAIL if number of bits */ +/* is greater than the word-size, AVCDEC_PACKET_LOSS or */ +/* AVCDEC_NO_DATA if callback to get data fails. */ +/* Modified : */ +/* ======================================================================== */ +AVCDec_Status BitstreamReadBits(AVCDecBitstream *stream, int nBits, uint *code) +{ + if (stream->incnt < nBits) + { + /* frame-based decoding */ + AVC_BitstreamFillCache(stream); + } + *code = stream->curr_word >> (32 - nBits); + BitstreamFlushBits(stream, nBits); + return AVCDEC_SUCCESS; +} + + + +/* ======================================================================== */ +/* Function : BitstreamShowBits() */ +/* Date : 11/4/2003 */ +/* Purpose : Show up to machine word without advancing the pointer. */ +/* In/out : */ +/* Return : AVCDEC_SUCCESS if successed, AVCDEC_FAIL if number of bits */ +/* is greater than the word-size, AVCDEC_NO_DATA if it needs */ +/* to callback to get data. */ +/* Modified : */ +/* ======================================================================== */ +AVCDec_Status BitstreamShowBits(AVCDecBitstream *stream, int nBits, uint *code) +{ + if (stream->incnt < nBits) + { + /* frame-based decoding */ + AVC_BitstreamFillCache(stream); + } + + *code = stream->curr_word >> (32 - nBits); + + return AVCDEC_SUCCESS; +} + +/* ======================================================================== */ +/* Function : BitstreamRead1Bit() */ +/* Date : 11/4/2003 */ +/* Purpose : Read 1 bit from the bitstream. */ +/* In/out : */ +/* Return : AVCDEC_SUCCESS if successed, AVCDEC_FAIL if number of bits */ +/* is greater than the word-size, AVCDEC_PACKET_LOSS or */ +/* AVCDEC_NO_DATA if callback to get data fails. */ +/* Modified : */ +/* ======================================================================== */ + +AVCDec_Status BitstreamRead1Bit(AVCDecBitstream *stream, uint *code) +{ + if (stream->incnt < 1) + { + /* frame-based decoding */ + AVC_BitstreamFillCache(stream); + } + *code = stream->curr_word >> 31; + BitstreamFlushBits(stream, 1); + return AVCDEC_SUCCESS; +} + + + +AVCDec_Status BitstreamByteAlign(AVCDecBitstream *stream) +{ + uint n_stuffed; + + n_stuffed = (8 - (stream->bitcnt & 0x7)) & 0x7; /* 07/05/01 */ + + stream->bitcnt += n_stuffed; + stream->incnt -= n_stuffed; + + if (stream->incnt < 0) + { + stream->bitcnt += stream->incnt; + stream->incnt = 0; + } + stream->curr_word <<= n_stuffed; + return AVCDEC_SUCCESS; +} + +/* check whether there are more RBSP data. */ +/* ignore the emulation prevention code, assume it has been taken out. */ +bool more_rbsp_data(AVCDecBitstream *stream) +{ + int total_bit_left; + uint code; + + if (stream->read_pos >= stream->nal_size) + { + total_bit_left = stream->incnt_next + stream->incnt; + if (total_bit_left <= 0) + { + return FALSE; + } + else if (total_bit_left <= 8) + { + BitstreamShowBits(stream, total_bit_left, &code); + if (code == trailing_bits[total_bit_left]) + { + return FALSE; + } + } + } + + return TRUE; +} + diff --git a/media/libstagefright/codecs/avc/dec/src/avcdec_api.cpp b/media/libstagefright/codecs/avc/dec/src/avcdec_api.cpp new file mode 100644 index 0000000..0a75f17 --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/src/avcdec_api.cpp @@ -0,0 +1,1036 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 file contains application function interfaces to the AVC decoder library. +@publishedAll +*/ + +#include + +#include "avcdec_api.h" +#include "avcdec_lib.h" +#include "avcdec_bitstream.h" + +/* ======================================================================== */ +/* Function : EBSPtoRBSP() */ +/* Date : 11/4/2003 */ +/* Purpose : Convert EBSP to RBSP and overwrite it. */ +/* Assuming that forbidden_zero, nal_ref_idc and nal_unit_type */ +/* (first byte), has been taken out of the nal_unit. */ +/* In/out : */ +/* Return : */ +/* Modified : */ +/* ======================================================================== */ +/** +@pseudocode " + NumBytesInRBSP = 0; + for(i=0:i< *size; i++){ + if(i+2 < *size && next_bits(24)==0x000003){ + rbsp_byte[NumBytesInRBSP++]; + rbsp_byte[NumBytesInRBSP++]; + i+=2; + emulation_prevention_three_byte (0x03) + } + else + rbsp_byte[NumBytesInRBSP++]; + }" +*/ +AVCDec_Status EBSPtoRBSP(uint8 *nal_unit, int *size) +{ + int i, j; + int count = 0; + + /* This code is based on EBSPtoRBSP of JM */ + j = 0; + + for (i = 0; i < *size; i++) + { + if (count == 2 && nal_unit[i] == 0x03) + { + i++; + count = 0; + } + nal_unit[j] = nal_unit[i]; + if (nal_unit[i] == 0x00) + count++; + else + count = 0; + j++; + } + + *size = j; + + return AVCDEC_SUCCESS; +} + +/* ======================================================================== */ +/* Function : PVAVCAnnexBGetNALUnit() */ +/* Date : 11/3/2003 */ +/* Purpose : Parse a NAL from byte stream format. */ +/* In/out : */ +/* Return : AVCDEC_SUCCESS if succeed, AVC_FAIL if fail. */ +/* Modified : */ +/* ======================================================================== */ +/** +@pseudocode " + byte_stream_nal_unit(NumBytesInNalunit){ + while(next_bits(24) != 0x000001) + zero_byte + if(more_data_in_byte_stream()){ + start_code_prefix_one_3bytes // equal 0x000001 + nal_unit(NumBytesInNALunit) + } + }" +*/ +OSCL_EXPORT_REF AVCDec_Status PVAVCAnnexBGetNALUnit(uint8 *bitstream, uint8 **nal_unit, + int *size) +{ + int i, j, FoundStartCode = 0; + int end; + + i = 0; + while (bitstream[i] == 0 && i < *size) + { + i++; + } + if (i >= *size) + { + *nal_unit = bitstream; + return AVCDEC_FAIL; /* cannot find any start_code_prefix. */ + } + else if (bitstream[i] != 0x1) + { + i = -1; /* start_code_prefix is not at the beginning, continue */ + } + + i++; + *nal_unit = bitstream + i; /* point to the beginning of the NAL unit */ + + j = end = i; + while (!FoundStartCode) + { + while ((j + 1 < *size) && (bitstream[j] != 0 || bitstream[j+1] != 0)) /* see 2 consecutive zero bytes */ + { + j++; + } + end = j; /* stop and check for start code */ + while (j + 2 < *size && bitstream[j+2] == 0) /* keep reading for zero byte */ + { + j++; + } + if (j + 2 >= *size) + { + *size -= i; + return AVCDEC_NO_NEXT_SC; /* cannot find the second start_code_prefix */ + } + if (bitstream[j+2] == 0x1) + { + FoundStartCode = 1; + } + else + { + /* could be emulation code 0x3 */ + j += 2; /* continue the search */ + } + } + + *size = end - i; + + return AVCDEC_SUCCESS; +} + +/* ======================================================================== */ +/* Function : PVAVCGetNALType() */ +/* Date : 11/4/2003 */ +/* Purpose : Sniff NAL type from the bitstream */ +/* In/out : */ +/* Return : AVCDEC_SUCCESS if succeed, AVC_FAIL if fail. */ +/* Modified : */ +/* ======================================================================== */ +OSCL_EXPORT_REF AVCDec_Status PVAVCDecGetNALType(uint8 *bitstream, int size, + int *nal_type, int *nal_ref_idc) +{ + int forbidden_zero_bit; + if (size > 0) + { + forbidden_zero_bit = bitstream[0] >> 7; + if (forbidden_zero_bit != 0) + return AVCDEC_FAIL; + *nal_ref_idc = (bitstream[0] & 0x60) >> 5; + *nal_type = bitstream[0] & 0x1F; + return AVCDEC_SUCCESS; + } + + return AVCDEC_FAIL; +} + +/* ======================================================================== */ +/* Function : PVAVCDecSeqParamSet() */ +/* Date : 11/4/2003 */ +/* Purpose : Initialize sequence, memory allocation if necessary. */ +/* In/out : */ +/* Return : AVCDEC_SUCCESS if succeed, AVC_FAIL if fail. */ +/* Modified : */ +/* ======================================================================== */ + +OSCL_EXPORT_REF AVCDec_Status PVAVCDecSeqParamSet(AVCHandle *avcHandle, uint8 *nal_unit, + int nal_size) +{ + AVCDec_Status status; + AVCDecObject *decvid; + AVCCommonObj *video; + AVCDecBitstream *bitstream; + void *userData = avcHandle->userData; + bool first_seq = FALSE; + int i; + + + DEBUG_LOG(userData, AVC_LOGTYPE_INFO, "PVAVCDecSeqParamSet", -1, -1); + + if (avcHandle->AVCObject == NULL) + { + first_seq = TRUE; + + //avcHandle->memory_usage = 0; + /* allocate AVCDecObject */ + avcHandle->AVCObject = (void*)avcHandle->CBAVC_Malloc(userData, sizeof(AVCDecObject), 0/*DEFAULT_ATTR*/); + if (avcHandle->AVCObject == NULL) + { + return AVCDEC_MEMORY_FAIL; + } + + decvid = (AVCDecObject*) avcHandle->AVCObject; + + memset(decvid, 0, sizeof(AVCDecObject)); + + decvid->common = (AVCCommonObj*)avcHandle->CBAVC_Malloc(userData, sizeof(AVCCommonObj), 0); + if (decvid->common == NULL) + { + return AVCDEC_MEMORY_FAIL; + } + + video = decvid->common; + memset(video, 0, sizeof(AVCCommonObj)); + + video->seq_parameter_set_id = 9999; /* set it to some illegal value */ + + decvid->bitstream = (AVCDecBitstream *) avcHandle->CBAVC_Malloc(userData, sizeof(AVCDecBitstream), 1/*DEFAULT_ATTR*/); + if (decvid->bitstream == NULL) + { + return AVCDEC_MEMORY_FAIL; + } + + decvid->bitstream->userData = avcHandle->userData; /* callback for more data */ + decvid->avcHandle = avcHandle; + decvid->debugEnable = avcHandle->debugEnable; + } + + decvid = (AVCDecObject*) avcHandle->AVCObject; + video = decvid->common; + bitstream = decvid->bitstream; + + /* check if we can reuse the memory without re-allocating it. */ + /* always check if(first_seq==TRUE) */ + + /* Conversion from EBSP to RBSP */ + video->forbidden_bit = nal_unit[0] >> 7; + if (video->forbidden_bit) return AVCDEC_FAIL; + video->nal_ref_idc = (nal_unit[0] & 0x60) >> 5; + video->nal_unit_type = (AVCNalUnitType)(nal_unit[0] & 0x1F); + + if (video->nal_unit_type != AVC_NALTYPE_SPS) /* not a SPS NAL */ + { + return AVCDEC_FAIL; + } + + /* Initialize bitstream structure*/ + BitstreamInit(bitstream, nal_unit + 1, nal_size - 1); + + /* if first_seq == TRUE, allocate the following memory */ + if (first_seq == TRUE) + { + video->currSeqParams = NULL; /* initialize it to NULL */ + video->currPicParams = NULL; + + /* There are 32 pointers to sequence param set, seqParams. + There are 255 pointers to picture param set, picParams.*/ + for (i = 0; i < 32; i++) + decvid->seqParams[i] = NULL; + + for (i = 0; i < 256; i++) + decvid->picParams[i] = NULL; + + video->MbToSliceGroupMap = NULL; + + video->mem_mgr_ctrl_eq_5 = FALSE; + video->newPic = TRUE; + video->newSlice = TRUE; + video->currPic = NULL; + video->currFS = NULL; + video->prevRefPic = NULL; + + video->mbNum = 0; // MC_Conceal + /* Allocate sliceHdr. */ + + video->sliceHdr = (AVCSliceHeader*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCSliceHeader), 5/*DEFAULT_ATTR*/); + if (video->sliceHdr == NULL) + { + return AVCDEC_MEMORY_FAIL; + } + + video->decPicBuf = (AVCDecPicBuffer*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCDecPicBuffer), 3/*DEFAULT_ATTR*/); + if (video->decPicBuf == NULL) + { + return AVCDEC_MEMORY_FAIL; + } + memset(video->decPicBuf, 0, sizeof(AVCDecPicBuffer)); + } + + /* Decode SPS, allocate video->seqParams[i] and assign video->currSeqParams */ + status = DecodeSPS(decvid, bitstream); + + if (status != AVCDEC_SUCCESS) + { + return status; + } + return AVCDEC_SUCCESS; +} + +/* ======================================================================== */ +/* Function : PVAVCDecGetSeqInfo() */ +/* Date : 11/4/2003 */ +/* Purpose : Get sequence parameter info. after SPS NAL is decoded. */ +/* In/out : */ +/* Return : AVCDEC_SUCCESS if succeed, AVC_FAIL if fail. */ +/* Modified : */ +/* 12/20/03: change input argument, use structure instead. */ +/* ======================================================================== */ + +OSCL_EXPORT_REF AVCDec_Status PVAVCDecGetSeqInfo(AVCHandle *avcHandle, AVCDecSPSInfo *seqInfo) +{ + AVCDecObject *decvid = (AVCDecObject*) avcHandle->AVCObject; + AVCCommonObj *video; + int PicWidthInMbs, PicHeightInMapUnits, FrameHeightInMbs; + + if (decvid == NULL || decvid->seqParams[0] == NULL) + { + return AVCDEC_FAIL; + } + + video = decvid->common; + + PicWidthInMbs = decvid->seqParams[0]->pic_width_in_mbs_minus1 + 1; + PicHeightInMapUnits = decvid->seqParams[0]->pic_height_in_map_units_minus1 + 1 ; + FrameHeightInMbs = (2 - decvid->seqParams[0]->frame_mbs_only_flag) * PicHeightInMapUnits ; + + seqInfo->FrameWidth = PicWidthInMbs << 4; + seqInfo->FrameHeight = FrameHeightInMbs << 4; + + seqInfo->frame_only_flag = decvid->seqParams[0]->frame_mbs_only_flag; + + if (decvid->seqParams[0]->frame_cropping_flag) + { + seqInfo->frame_crop_left = 2 * decvid->seqParams[0]->frame_crop_left_offset; + seqInfo->frame_crop_right = seqInfo->FrameWidth - (2 * decvid->seqParams[0]->frame_crop_right_offset + 1); + + if (seqInfo->frame_only_flag) + { + seqInfo->frame_crop_top = 2 * decvid->seqParams[0]->frame_crop_top_offset; + seqInfo->frame_crop_bottom = seqInfo->FrameHeight - (2 * decvid->seqParams[0]->frame_crop_bottom_offset + 1); + /* Note in 7.4.2.1, there is a contraint on the value of frame_crop_left and frame_crop_top + such that they have to be less than or equal to frame_crop_right/2 and frame_crop_bottom/2, respectively. */ + } + else + { + seqInfo->frame_crop_top = 4 * decvid->seqParams[0]->frame_crop_top_offset; + seqInfo->frame_crop_bottom = seqInfo->FrameHeight - (4 * decvid->seqParams[0]->frame_crop_bottom_offset + 1); + /* Note in 7.4.2.1, there is a contraint on the value of frame_crop_left and frame_crop_top + such that they have to be less than or equal to frame_crop_right/2 and frame_crop_bottom/4, respectively. */ + } + } + else /* no cropping flag, just give the first and last pixel */ + { + seqInfo->frame_crop_bottom = seqInfo->FrameHeight - 1; + seqInfo->frame_crop_right = seqInfo->FrameWidth - 1; + seqInfo->frame_crop_top = seqInfo->frame_crop_left = 0; + } + + return AVCDEC_SUCCESS; +} + +/* ======================================================================== */ +/* Function : PVAVCDecPicParamSet() */ +/* Date : 11/4/2003 */ +/* Purpose : Initialize picture */ +/* create reference picture list. */ +/* In/out : */ +/* Return : AVCDEC_SUCCESS if succeed, AVC_FAIL if fail. */ +/* Modified : */ +/* ======================================================================== */ +/** +Since PPS doesn't contain much data, most of the picture initialization will +be done after decoding the slice header in PVAVCDecodeSlice. */ +OSCL_EXPORT_REF AVCDec_Status PVAVCDecPicParamSet(AVCHandle *avcHandle, uint8 *nal_unit, + int nal_size) +{ + AVCDec_Status status; + AVCDecObject *decvid = (AVCDecObject*) avcHandle->AVCObject; + AVCCommonObj *video; + AVCDecBitstream *bitstream; + + if (decvid == NULL) + { + return AVCDEC_FAIL; + } + + video = decvid->common; + bitstream = decvid->bitstream; + /* 1. Convert EBSP to RBSP. Create bitstream structure */ + video->forbidden_bit = nal_unit[0] >> 7; + video->nal_ref_idc = (nal_unit[0] & 0x60) >> 5; + video->nal_unit_type = (AVCNalUnitType)(nal_unit[0] & 0x1F); + + if (video->nal_unit_type != AVC_NALTYPE_PPS) /* not a PPS NAL */ + { + return AVCDEC_FAIL; + } + + + /* 2. Initialize bitstream structure*/ + BitstreamInit(bitstream, nal_unit + 1, nal_size - 1); + + /* 2. Decode pic_parameter_set_rbsp syntax. Allocate video->picParams[i] and assign to currPicParams */ + status = DecodePPS(decvid, video, bitstream); + if (status != AVCDEC_SUCCESS) + { + return status; + } + + video->SliceGroupChangeRate = video->currPicParams->slice_group_change_rate_minus1 + 1 ; + + return AVCDEC_SUCCESS; +} + +OSCL_EXPORT_REF AVCDec_Status PVAVCDecSEI(AVCHandle *avcHandle, uint8 *nal_unit, + int nal_size) +{ + OSCL_UNUSED_ARG(avcHandle); + OSCL_UNUSED_ARG(nal_unit); + OSCL_UNUSED_ARG(nal_size); + + return AVCDEC_SUCCESS; +} +/* ======================================================================== */ +/* Function : PVAVCDecodeSlice() */ +/* Date : 11/4/2003 */ +/* Purpose : Decode one NAL unit. */ +/* In/out : */ +/* Return : See enum AVCDec_Status for return values. */ +/* Modified : */ +/* ======================================================================== */ +OSCL_EXPORT_REF AVCDec_Status PVAVCDecodeSlice(AVCHandle *avcHandle, uint8 *buffer, + int buf_size) +{ + AVCDecObject *decvid = (AVCDecObject*) avcHandle->AVCObject; + AVCCommonObj *video; + AVCDecBitstream *bitstream; + AVCDec_Status status; + + if (decvid == NULL) + { + return AVCDEC_FAIL; + } + + video = decvid->common; + bitstream = decvid->bitstream; + + if (video->mem_mgr_ctrl_eq_5) + { + return AVCDEC_PICTURE_OUTPUT_READY; // to flushout frame buffers + } + + if (video->newSlice) + { + /* 2. Check NAL type */ + if (buffer == NULL) + { + return AVCDEC_FAIL; + } + video->prev_nal_unit_type = video->nal_unit_type; + video->forbidden_bit = buffer[0] >> 7; + video->nal_ref_idc = (buffer[0] & 0x60) >> 5; + video->nal_unit_type = (AVCNalUnitType)(buffer[0] & 0x1F); + + + if (video->nal_unit_type == AVC_NALTYPE_AUD) + { + return AVCDEC_SUCCESS; + } + + if (video->nal_unit_type != AVC_NALTYPE_SLICE && + video->nal_unit_type != AVC_NALTYPE_IDR) + { + return AVCDEC_FAIL; /* not supported */ + } + + + + if (video->nal_unit_type >= 2 && video->nal_unit_type <= 4) + { + return AVCDEC_FAIL; /* not supported */ + } + else + { + video->slice_data_partitioning = FALSE; + } + + video->newSlice = FALSE; + /* Initialize bitstream structure*/ + BitstreamInit(bitstream, buffer + 1, buf_size - 1); + + + /* 2.1 Decode Slice Header (separate function)*/ + status = DecodeSliceHeader(decvid, video, bitstream); + if (status != AVCDEC_SUCCESS) + { + video->newSlice = TRUE; + return status; + } + + if (video->sliceHdr->frame_num != video->prevFrameNum || (video->sliceHdr->first_mb_in_slice < (uint)video->mbNum && video->currSeqParams->constrained_set1_flag == 1)) + { + video->newPic = TRUE; + if (video->numMBs > 0) + { + // Conceal missing MBs of previously decoded frame + ConcealSlice(decvid, video->PicSizeInMbs - video->numMBs, video->PicSizeInMbs); // Conceal + video->numMBs = 0; + + // DeblockPicture(video); // No need to deblock + + /* 3.2 Decoded frame reference marking. */ + /* 3.3 Put the decoded picture in output buffers */ + /* set video->mem_mge_ctrl_eq_5 */ + AVCNalUnitType temp = video->nal_unit_type; + video->nal_unit_type = video->prev_nal_unit_type; + StorePictureInDPB(avcHandle, video); + video->nal_unit_type = temp; + video->mbNum = 0; // MC_Conceal + return AVCDEC_PICTURE_OUTPUT_READY; + } + } + + if (video->nal_unit_type == AVC_NALTYPE_IDR) + { + video->prevFrameNum = 0; + video->PrevRefFrameNum = 0; + } + + if (!video->currSeqParams->gaps_in_frame_num_value_allowed_flag) + { /* no gaps allowed, frame_num has to increase by one only */ + /* if(sliceHdr->frame_num != (video->PrevRefFrameNum + 1)%video->MaxFrameNum) */ + if (video->sliceHdr->frame_num != video->PrevRefFrameNum && video->sliceHdr->frame_num != (video->PrevRefFrameNum + 1) % video->MaxFrameNum) + { + // Conceal missing MBs of previously decoded frame + video->numMBs = 0; + video->newPic = TRUE; + video->prevFrameNum++; // FIX + video->PrevRefFrameNum++; + AVCNalUnitType temp = video->nal_unit_type; + video->nal_unit_type = AVC_NALTYPE_SLICE; //video->prev_nal_unit_type; + status = (AVCDec_Status)DPBInitBuffer(avcHandle, video); + if (status != AVCDEC_SUCCESS) + { + return status; + } + video->currFS->IsOutputted = 0x01; + video->currFS->IsReference = 3; + video->currFS->IsLongTerm = 0; + + DecodePOC(video); + /* find an empty memory from DPB and assigned to currPic */ + DPBInitPic(video, video->PrevRefFrameNum % video->MaxFrameNum); + RefListInit(video); + ConcealSlice(decvid, 0, video->PicSizeInMbs); // Conceal + video->currFS->IsOutputted |= 0x02; + //conceal frame + /* 3.2 Decoded frame reference marking. */ + /* 3.3 Put the decoded picture in output buffers */ + /* set video->mem_mge_ctrl_eq_5 */ + video->mbNum = 0; // Conceal + StorePictureInDPB(avcHandle, video); + video->nal_unit_type = temp; + + return AVCDEC_PICTURE_OUTPUT_READY; + } + } + } + + if (video->newPic == TRUE) + { + status = (AVCDec_Status)DPBInitBuffer(avcHandle, video); + if (status != AVCDEC_SUCCESS) + { + return status; + } + } + + video->newSlice = TRUE; + + /* function pointer setting at slice-level */ + // OPTIMIZE + decvid->residual_block = &residual_block_cavlc; + + /* derive picture order count */ + if (video->newPic == TRUE) + { + video->numMBs = video->PicSizeInMbs; + + if (video->nal_unit_type != AVC_NALTYPE_IDR && video->currSeqParams->gaps_in_frame_num_value_allowed_flag) + { + if (video->sliceHdr->frame_num != (video->PrevRefFrameNum + 1) % video->MaxFrameNum) + { + status = fill_frame_num_gap(avcHandle, video); + if (status != AVCDEC_SUCCESS) + { + video->numMBs = 0; + return status; + } + + status = (AVCDec_Status)DPBInitBuffer(avcHandle, video); + if (status != AVCDEC_SUCCESS) + { + video->numMBs = 0; + return status; + } + + + } + } + /* if there's gap in the frame_num, we have to fill in the gap with + imaginary frames that won't get used for short-term ref. */ + /* see fill_frame_num_gap() in JM */ + + + DecodePOC(video); + /* find an empty memory from DPB and assigned to currPic */ + DPBInitPic(video, video->CurrPicNum); + + video->currPic->isReference = TRUE; // FIX + + if (video->nal_ref_idc == 0) + { + video->currPic->isReference = FALSE; + video->currFS->IsOutputted |= 0x02; /* The MASK 0x02 means not needed for reference, or returned */ + /* node need to check for freeing of this buffer */ + } + + FMOInit(video); + + if (video->currPic->isReference) + { + video->PrevRefFrameNum = video->sliceHdr->frame_num; + } + + + video->prevFrameNum = video->sliceHdr->frame_num; + } + + video->newPic = FALSE; + + + /* Initialize refListIdx for this picture */ + RefListInit(video); + + /* Re-order the reference list according to the ref_pic_list_reordering() */ + status = (AVCDec_Status)ReOrderList(video); + if (status != AVCDEC_SUCCESS) + { + return AVCDEC_FAIL; + } + + /* 2.2 Decode Slice. */ + status = (AVCDec_Status)DecodeSlice(decvid); + + video->slice_id++; // slice + + if (status == AVCDEC_PICTURE_READY) + { + /* 3. Check complete picture */ +#ifndef MB_BASED_DEBLOCK + /* 3.1 Deblock */ + DeblockPicture(video); +#endif + /* 3.2 Decoded frame reference marking. */ + /* 3.3 Put the decoded picture in output buffers */ + /* set video->mem_mge_ctrl_eq_5 */ + status = (AVCDec_Status)StorePictureInDPB(avcHandle, video); // CHECK check the retunr status + if (status != AVCDEC_SUCCESS) + { + return AVCDEC_FAIL; + } + + if (video->mem_mgr_ctrl_eq_5) + { + video->PrevRefFrameNum = 0; + video->prevFrameNum = 0; + video->prevPicOrderCntMsb = 0; + video->prevPicOrderCntLsb = video->TopFieldOrderCnt; + video->prevFrameNumOffset = 0; + } + else + { + video->prevPicOrderCntMsb = video->PicOrderCntMsb; + video->prevPicOrderCntLsb = video->sliceHdr->pic_order_cnt_lsb; + video->prevFrameNumOffset = video->FrameNumOffset; + } + + return AVCDEC_PICTURE_READY; + } + else if (status != AVCDEC_SUCCESS) + { + return AVCDEC_FAIL; + } + + return AVCDEC_SUCCESS; +} + +/* ======================================================================== */ +/* Function : PVAVCDecGetOutput() */ +/* Date : 11/3/2003 */ +/* Purpose : Get the next picture according to PicOrderCnt. */ +/* In/out : */ +/* Return : AVCFrameIO structure */ +/* Modified : */ +/* ======================================================================== */ + +OSCL_EXPORT_REF AVCDec_Status PVAVCDecGetOutput(AVCHandle *avcHandle, int *indx, int *release, AVCFrameIO *output) +{ + AVCDecObject *decvid = (AVCDecObject*) avcHandle->AVCObject; + AVCCommonObj *video; + AVCDecPicBuffer *dpb; + AVCFrameStore *oldestFrame = NULL; + int i, first = 1; + int count_frame = 0; + int index = 0; + int min_poc = 0; + + if (decvid == NULL) + { + return AVCDEC_FAIL; + } + + video = decvid->common; + dpb = video->decPicBuf; + + if (dpb->num_fs == 0) + { + return AVCDEC_FAIL; + } + + /* search for the oldest frame_num in dpb */ + /* extension to field decoding, we have to search for every top_field/bottom_field within + each frame in the dpb. This code only works for frame based.*/ + + if (video->mem_mgr_ctrl_eq_5 == FALSE) + { + for (i = 0; i < dpb->num_fs; i++) + { + if ((dpb->fs[i]->IsOutputted & 0x01) == 0) + { + count_frame++; + if (first) + { + min_poc = dpb->fs[i]->PicOrderCnt; + first = 0; + oldestFrame = dpb->fs[i]; + index = i; + } + if (dpb->fs[i]->PicOrderCnt < min_poc) + { + min_poc = dpb->fs[i]->PicOrderCnt; + oldestFrame = dpb->fs[i]; + index = i; + } + } + } + } + else + { + for (i = 0; i < dpb->num_fs; i++) + { + if ((dpb->fs[i]->IsOutputted & 0x01) == 0 && dpb->fs[i] != video->currFS) + { + count_frame++; + if (first) + { + min_poc = dpb->fs[i]->PicOrderCnt; + first = 0; + oldestFrame = dpb->fs[i]; + index = i; + } + if (dpb->fs[i]->PicOrderCnt < min_poc) + { + min_poc = dpb->fs[i]->PicOrderCnt; + oldestFrame = dpb->fs[i]; + index = i; + } + } + } + + if (count_frame < 2 && video->nal_unit_type != AVC_NALTYPE_IDR) + { + video->mem_mgr_ctrl_eq_5 = FALSE; // FIX + } + else if (count_frame < 1 && video->nal_unit_type == AVC_NALTYPE_IDR) + { + for (i = 0; i < dpb->num_fs; i++) + { + if (dpb->fs[i] == video->currFS && (dpb->fs[i]->IsOutputted & 0x01) == 0) + { + oldestFrame = dpb->fs[i]; + index = i; + break; + } + } + video->mem_mgr_ctrl_eq_5 = FALSE; + } + } + + if (oldestFrame == NULL) + { + + /* Check for Mem_mgmt_operation_5 based forced output */ + for (i = 0; i < dpb->num_fs; i++) + { + /* looking for the one not used or not reference and has been outputted */ + if (dpb->fs[i]->IsReference == 0 && dpb->fs[i]->IsOutputted == 3) + { + break; + } + } + if (i < dpb->num_fs) + { + /* there are frames available for decoding */ + return AVCDEC_FAIL; /* no frame to be outputted */ + } + + + /* no free frame available, we have to release one to continue decoding */ + int MinIdx = 0; + int32 MinFrameNumWrap = 0x7FFFFFFF; + + for (i = 0; i < dpb->num_fs; i++) + { + if (dpb->fs[i]->IsReference && !dpb->fs[i]->IsLongTerm) + { + if (dpb->fs[i]->FrameNumWrap < MinFrameNumWrap) + { + MinFrameNumWrap = dpb->fs[i]->FrameNumWrap; + MinIdx = i; + } + } + } + /* mark the frame with smallest PicOrderCnt to be unused for reference */ + dpb->fs[MinIdx]->IsReference = 0; + dpb->fs[MinIdx]->IsLongTerm = 0; + dpb->fs[MinIdx]->frame.isReference = FALSE; + dpb->fs[MinIdx]->frame.isLongTerm = FALSE; + dpb->fs[MinIdx]->IsOutputted |= 0x02; +#ifdef PV_MEMORY_POOL + if (dpb->fs[MinIdx]->IsOutputted == 3) + { + avcHandle->CBAVC_FrameUnbind(avcHandle->userData, MinIdx); + } +#endif + return AVCDEC_FAIL; + } + /* MASK 0x01 means the frame is outputted (for display). A frame gets freed when it is + outputted (0x01) and not needed for reference (0x02) */ + oldestFrame->IsOutputted |= 0x01; + + if (oldestFrame->IsOutputted == 3) + { + *release = 1; /* flag to release the buffer */ + } + else + { + *release = 0; + } + /* do not release buffer here, release it after it is sent to the sink node */ + + output->YCbCr[0] = oldestFrame->frame.Sl; + output->YCbCr[1] = oldestFrame->frame.Scb; + output->YCbCr[2] = oldestFrame->frame.Scr; + output->height = oldestFrame->frame.height; + output->pitch = oldestFrame->frame.width; + output->disp_order = oldestFrame->PicOrderCnt; + output->coding_order = oldestFrame->FrameNum; + output->id = (uint32) oldestFrame->base_dpb; /* use the pointer as the id */ + *indx = index; + + + + return AVCDEC_SUCCESS; +} + + +/* ======================================================================== */ +/* Function : PVAVCDecReset() */ +/* Date : 03/04/2004 */ +/* Purpose : Reset decoder, prepare it for a new IDR frame. */ +/* In/out : */ +/* Return : void */ +/* Modified : */ +/* ======================================================================== */ +OSCL_EXPORT_REF void PVAVCDecReset(AVCHandle *avcHandle) +{ + AVCDecObject *decvid = (AVCDecObject*) avcHandle->AVCObject; + AVCCommonObj *video; + AVCDecPicBuffer *dpb; + int i; + + if (decvid == NULL) + { + return; + } + + video = decvid->common; + dpb = video->decPicBuf; + + /* reset the DPB */ + + + for (i = 0; i < dpb->num_fs; i++) + { + dpb->fs[i]->IsLongTerm = 0; + dpb->fs[i]->IsReference = 0; + dpb->fs[i]->IsOutputted = 3; + dpb->fs[i]->frame.isReference = 0; + dpb->fs[i]->frame.isLongTerm = 0; + } + + video->mem_mgr_ctrl_eq_5 = FALSE; + video->newPic = TRUE; + video->newSlice = TRUE; + video->currPic = NULL; + video->currFS = NULL; + video->prevRefPic = NULL; + video->prevFrameNum = 0; + video->PrevRefFrameNum = 0; + video->prevFrameNumOffset = 0; + video->FrameNumOffset = 0; + video->mbNum = 0; + video->numMBs = 0; + + return ; +} + + +/* ======================================================================== */ +/* Function : PVAVCCleanUpDecoder() */ +/* Date : 11/4/2003 */ +/* Purpose : Clean up the decoder, free all memories allocated. */ +/* In/out : */ +/* Return : void */ +/* Modified : */ +/* ======================================================================== */ + +OSCL_EXPORT_REF void PVAVCCleanUpDecoder(AVCHandle *avcHandle) +{ + AVCDecObject *decvid = (AVCDecObject*) avcHandle->AVCObject; + AVCCommonObj *video; + void *userData = avcHandle->userData; + int i; + + DEBUG_LOG(userData, AVC_LOGTYPE_INFO, "PVAVCCleanUpDecoder", -1, -1); + + if (decvid != NULL) + { + video = decvid->common; + if (video != NULL) + { + if (video->MbToSliceGroupMap != NULL) + { + avcHandle->CBAVC_Free(userData, (int)video->MbToSliceGroupMap); + } + +#ifdef MB_BASED_DEBLOCK + if (video->intra_pred_top != NULL) + { + avcHandle->CBAVC_Free(userData, (int)video->intra_pred_top); + } + if (video->intra_pred_top_cb != NULL) + { + avcHandle->CBAVC_Free(userData, (int)video->intra_pred_top_cb); + } + if (video->intra_pred_top_cr != NULL) + { + avcHandle->CBAVC_Free(userData, (int)video->intra_pred_top_cr); + } +#endif + if (video->mblock != NULL) + { + avcHandle->CBAVC_Free(userData, (int)video->mblock); + } + + if (video->decPicBuf != NULL) + { + CleanUpDPB(avcHandle, video); + avcHandle->CBAVC_Free(userData, (int)video->decPicBuf); + } + + if (video->sliceHdr != NULL) + { + avcHandle->CBAVC_Free(userData, (int)video->sliceHdr); + } + + avcHandle->CBAVC_Free(userData, (int)video); /* last thing to do */ + + } + + for (i = 0; i < 256; i++) + { + if (decvid->picParams[i] != NULL) + { + if (decvid->picParams[i]->slice_group_id != NULL) + { + avcHandle->CBAVC_Free(userData, (int)decvid->picParams[i]->slice_group_id); + } + avcHandle->CBAVC_Free(userData, (int)decvid->picParams[i]); + } + } + for (i = 0; i < 32; i++) + { + if (decvid->seqParams[i] != NULL) + { + avcHandle->CBAVC_Free(userData, (int)decvid->seqParams[i]); + } + } + if (decvid->bitstream != NULL) + { + avcHandle->CBAVC_Free(userData, (int)decvid->bitstream); + } + + + avcHandle->CBAVC_Free(userData, (int)decvid); + } + + + return ; +} diff --git a/media/libstagefright/codecs/avc/dec/src/avcdec_bitstream.h b/media/libstagefright/codecs/avc/dec/src/avcdec_bitstream.h new file mode 100644 index 0000000..bd1bc59 --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/src/avcdec_bitstream.h @@ -0,0 +1,125 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 file contains bitstream related functions. +@publishedAll +*/ + +#ifndef _AVCDEC_BITSTREAM_H_ +#define _AVCDEC_BITSTREAM_H_ + +#include "avcdec_lib.h" + +#define WORD_SIZE 32 /* this can vary, default to 32 bit for now */ + +#ifndef __cplusplus + +#define AVC_GETDATA(x,y) userData->AVC_GetData(x,y) + +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif +#define BitstreamFlushBits(A,B) {(A)->bitcnt += (B); (A)->incnt -= (B); (A)->curr_word <<= (B);} + + AVCDec_Status AVC_BitstreamFillCache(AVCDecBitstream *stream); + /** + This function populates bitstream structure. + \param "stream" "Pointer to bitstream structure." + \param "buffer" "Pointer to the bitstream buffer." + \param "size" "Size of the buffer." + \param "nal_size" "Size of the NAL unit." + \param "resetall" "Flag for reset everything." + \return "AVCDEC_SUCCESS for success and AVCDEC_FAIL for fail." + */ + AVCDec_Status BitstreamInit(AVCDecBitstream *stream, uint8 *buffer, int size); + + /** + This function reads next aligned word and remove the emulation prevention code + if necessary. + \param "stream" "Pointer to bitstream structure." + \return "Next word." + */ + uint BitstreamNextWord(AVCDecBitstream *stream); + + /** + This function reads nBits bits from the current position and advance the pointer. + \param "stream" "Pointer to bitstream structure." + \param "nBits" "Number of bits to be read." + \param "code" "Point to the read value." + \return "AVCDEC_SUCCESS if successed, AVCDEC_FAIL if number of bits + is greater than the word-size, AVCDEC_PACKET_LOSS or + AVCDEC_NO_DATA if callback to get data fails." + */ + AVCDec_Status BitstreamReadBits(AVCDecBitstream *stream, int nBits, uint *code); + + /** + This function shows nBits bits from the current position without advancing the pointer. + \param "stream" "Pointer to bitstream structure." + \param "nBits" "Number of bits to be read." + \param "code" "Point to the read value." + \return "AVCDEC_SUCCESS if successed, AVCDEC_FAIL if number of bits + is greater than the word-size, AVCDEC_NO_DATA if it needs + to callback to get data." + */ + AVCDec_Status BitstreamShowBits(AVCDecBitstream *stream, int nBits, uint *code); + + + /** + This function flushes nBits bits from the current position. + \param "stream" "Pointer to bitstream structure." + \param "nBits" "Number of bits to be read." + \return "AVCDEC_SUCCESS if successed, AVCDEC_FAIL if number of bits + is greater than the word-size It will not call back to get + more data. Users should call BitstreamShowBits to determine + how much they want to flush." + */ + + /** + This function read 1 bit from the current position and advance the pointer. + \param "stream" "Pointer to bitstream structure." + \param "nBits" "Number of bits to be read." + \param "code" "Point to the read value." + \return "AVCDEC_SUCCESS if successed, AVCDEC_FAIL if number of bits + is greater than the word-size, AVCDEC_PACKET_LOSS or + AVCDEC_NO_DATA if callback to get data fails." + */ + AVCDec_Status BitstreamRead1Bit(AVCDecBitstream *stream, uint *code); + + /** + This function checks whether the current bit position is byte-aligned or not. + \param "stream" "Pointer to the bitstream structure." + \return "TRUE if byte-aligned, FALSE otherwise." + */ + bool byte_aligned(AVCDecBitstream *stream); + AVCDec_Status BitstreamByteAlign(AVCDecBitstream *stream); + /** + This function checks whether there are more RBSP data before the trailing bits. + \param "stream" "Pointer to the bitstream structure." + \return "TRUE if yes, FALSE otherwise." + */ + bool more_rbsp_data(AVCDecBitstream *stream); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _AVCDEC_BITSTREAM_H_ */ diff --git a/media/libstagefright/codecs/avc/dec/src/avcdec_int.h b/media/libstagefright/codecs/avc/dec/src/avcdec_int.h new file mode 100644 index 0000000..878f9b3 --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/src/avcdec_int.h @@ -0,0 +1,88 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 file contains application function interfaces to the AVC decoder library +and necessary type defitionitions and enumerations. +Naming convention for variables: +lower_case_with_under_line is syntax element in subclause 7.2 and 7.3 +noUnderLine or NoUnderLine is derived variables defined somewhere else in the draft + or introduced by this decoder library. +@publishedAll +*/ + +#ifndef _AVCDEC_INT_H_ +#define _AVCDEC_INT_H_ + +#include "avcint_common.h" +#include "avcdec_api.h" + + +/** +Bitstream structure contains bitstream related parameters such as the pointer +to the buffer, the current byte position and bit position. +@publishedAll +*/ +typedef struct tagDecBitstream +{ + uint8 *bitstreamBuffer; /* pointer to buffer memory */ + int nal_size; /* size of the current NAL unit */ + int data_end_pos; /* bitstreamBuffer size in bytes */ + int read_pos; /* next position to read from bitstreamBuffer */ + uint curr_word; /* byte-swapped (MSB left) current word read from buffer */ + int bit_left; /* number of bit left in current_word */ + uint next_word; /* in case for old data in previous buffer hasn't been flushed. */ + int incnt; /* bit left in the prev_word */ + int incnt_next; + int bitcnt; + void *userData; +} AVCDecBitstream; + +/** +This structure is the main object for AVC decoder library providing access to all +global variables. It is allocated at PVAVCInitDecoder and freed at PVAVCCleanUpDecoder. +@publishedAll +*/ +typedef struct tagDecObject +{ + + AVCCommonObj *common; + + AVCDecBitstream *bitstream; /* for current NAL */ + + /* sequence parameter set */ + AVCSeqParamSet *seqParams[32]; /* Array of pointers, get allocated at arrival of new seq_id */ + + /* picture parameter set */ + AVCPicParamSet *picParams[256]; /* Array of pointers to picture param set structures */ + + /* For internal operation, scratch memory for MV, prediction, transform, etc.*/ + uint ref_idx_l0[4]; /* [mbPartIdx], te(v) */ + uint ref_idx_l1[4]; + + /* function pointers */ + AVCDec_Status(*residual_block)(struct tagDecObject*, int, int, + int *, int *, int *); + /* Application control data */ + AVCHandle *avcHandle; + void (*AVC_DebugLog)(AVCLogType type, char *string1, char *string2); + /*bool*/ + uint debugEnable; + +} AVCDecObject; + +#endif /* _AVCDEC_INT_H_ */ diff --git a/media/libstagefright/codecs/avc/dec/src/avcdec_lib.h b/media/libstagefright/codecs/avc/dec/src/avcdec_lib.h new file mode 100644 index 0000000..fdead05 --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/src/avcdec_lib.h @@ -0,0 +1,555 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 file contains declarations of internal functions for AVC decoder library. +@publishedAll +*/ +#ifndef _AVCDEC_LIB_H_ +#define _AVCDEC_LIB_H_ + +#include "avclib_common.h" +#include "avcdec_int.h" + +/*----------- avcdec_api.c -------------*/ +/** +This function takes out the emulation prevention bytes from the input to creat RBSP. +The result is written over the input bitstream. +\param "nal_unit" "(I/O) Pointer to the input buffer." +\param "size" "(I/O) Pointer to the size of the input/output buffer." +\return "AVCDEC_SUCCESS for success and AVCDEC_FAIL otherwise." +*/ +AVCDec_Status EBSPtoRBSP(uint8 *nal_unit, int *size); + +/*------------- pred_intra.c ---------------*/ +/** +This function is the main entry point to intra prediction operation on a +macroblock. +\param "video" "Pointer to AVCCommonObj." +*/ +AVCStatus IntraMBPrediction(AVCCommonObj *video); + +void SaveNeighborForIntraPred(AVCCommonObj *video, int offset); + +AVCStatus Intra_4x4(AVCCommonObj *video, int component, int SubBlock_indx, uint8 *comp); +void Intra_4x4_Vertical(AVCCommonObj *video, int block_offset); +void Intra_4x4_Horizontal(AVCCommonObj *video, int pitch, int block_offset); +void Intra_4x4_DC(AVCCommonObj *video, int pitch, int block_offset, AVCNeighborAvailability *availability); +void Intra_4x4_Down_Left(AVCCommonObj *video, int block_offset, AVCNeighborAvailability *availability); +void Intra_4x4_Diagonal_Down_Right(AVCCommonObj *video, int pitch, int block_offset); +void Intra_4x4_Diagonal_Vertical_Right(AVCCommonObj *video, int pitch, int block_offset); +void Intra_4x4_Diagonal_Horizontal_Down(AVCCommonObj *video, int pitch, int block_offset); +void Intra_4x4_Vertical_Left(AVCCommonObj *video, int block_offset, AVCNeighborAvailability *availability); +void Intra_4x4_Horizontal_Up(AVCCommonObj *video, int pitch, int block_offset); +void Intra_16x16_Vertical(AVCCommonObj *video); +void Intra_16x16_Horizontal(AVCCommonObj *video, int pitch); +void Intra_16x16_DC(AVCCommonObj *video, int pitch); +void Intra_16x16_Plane(AVCCommonObj *video, int pitch); +void Intra_Chroma_DC(AVCCommonObj *video, int pitch, uint8 *predCb, uint8 *predCr); +void Intra_Chroma_Horizontal(AVCCommonObj *video, int pitch, uint8 *predCb, uint8 *predCr); +void Intra_Chroma_Vertical(AVCCommonObj *video, uint8 *predCb, uint8 *predCr); +void Intra_Chroma_Plane(AVCCommonObj *video, int pitch, uint8 *predCb, uint8 *predCr); + +/*------------ pred_inter.c ---------------*/ +/** +This function is the main entrance to inter prediction operation for +a macroblock. For decoding, this function also calls inverse transform and +compensation. +\param "video" "Pointer to AVCCommonObj." +\return "void" +*/ +void InterMBPrediction(AVCCommonObj *video); + +/** +This function is called for luma motion compensation. +\param "ref" "Pointer to the origin of a reference luma." +\param "picwidth" "Width of the picture." +\param "picheight" "Height of the picture." +\param "x_pos" "X-coordinate of the predicted block in quarter pel resolution." +\param "y_pos" "Y-coordinate of the predicted block in quarter pel resolution." +\param "pred" "Pointer to the output predicted block." +\param "pred_pitch" "Width of pred." +\param "blkwidth" "Width of the current partition." +\param "blkheight" "Height of the current partition." +\return "void" +*/ +void LumaMotionComp(uint8 *ref, int picwidth, int picheight, + int x_pos, int y_pos, + uint8 *pred, int pred_pitch, + int blkwidth, int blkheight); + +/** +Functions below are special cases for luma motion compensation. +LumaFullPelMC is for full pixel motion compensation. +LumaBorderMC is for interpolation in only one dimension. +LumaCrossMC is for interpolation in one dimension and half point in the other dimension. +LumaDiagonalMC is for interpolation in diagonal direction. + +\param "ref" "Pointer to the origin of a reference luma." +\param "picwidth" "Width of the picture." +\param "picheight" "Height of the picture." +\param "x_pos" "X-coordinate of the predicted block in full pel resolution." +\param "y_pos" "Y-coordinate of the predicted block in full pel resolution." +\param "dx" "Fraction of x_pos in quarter pel." +\param "dy" "Fraction of y_pos in quarter pel." +\param "curr" "Pointer to the current partition in the current picture." +\param "residue" "Pointer to the current partition for the residue block." +\param "blkwidth" "Width of the current partition." +\param "blkheight" "Height of the current partition." +\return "void" +*/ +void CreatePad(uint8 *ref, int picwidth, int picheight, int x_pos, int y_pos, + uint8 *out, int blkwidth, int blkheight); + +void FullPelMC(uint8 *in, int inwidth, uint8 *out, int outpitch, + int blkwidth, int blkheight); + +void HorzInterp1MC(uint8 *in, int inpitch, uint8 *out, int outpitch, + int blkwidth, int blkheight, int dx); + +void HorzInterp2MC(int *in, int inpitch, uint8 *out, int outpitch, + int blkwidth, int blkheight, int dx); + +void HorzInterp3MC(uint8 *in, int inpitch, int *out, int outpitch, + int blkwidth, int blkheight); + +void VertInterp1MC(uint8 *in, int inpitch, uint8 *out, int outpitch, + int blkwidth, int blkheight, int dy); + +void VertInterp2MC(uint8 *in, int inpitch, int *out, int outpitch, + int blkwidth, int blkheight); + +void VertInterp3MC(int *in, int inpitch, uint8 *out, int outpitch, + int blkwidth, int blkheight, int dy); + +void DiagonalInterpMC(uint8 *in1, uint8 *in2, int inpitch, + uint8 *out, int outpitch, + int blkwidth, int blkheight); + + +void ChromaMotionComp(uint8 *ref, int picwidth, int picheight, + int x_pos, int y_pos, uint8 *pred, int pred_pitch, + int blkwidth, int blkheight); + +void ChromaFullPelMC(uint8 *in, int inpitch, uint8 *out, int outpitch, + int blkwidth, int blkheight) ; +void ChromaBorderMC(uint8 *ref, int picwidth, int dx, int dy, + uint8 *pred, int pred_pitch, int blkwidth, int blkheight); +void ChromaDiagonalMC(uint8 *ref, int picwidth, int dx, int dy, + uint8 *pred, int pred_pitch, int blkwidth, int blkheight); + +void ChromaFullPelMCOutside(uint8 *ref, uint8 *pred, int pred_pitch, + int blkwidth, int blkheight, int x_inc, + int y_inc0, int y_inc1, int x_mid, int y_mid); +void ChromaBorderMCOutside(uint8 *ref, int picwidth, int dx, int dy, + uint8 *pred, int pred_pitch, int blkwidth, int blkheight, + int x_inc, int z_inc, int y_inc0, int y_inc1, int x_mid, int y_mid); +void ChromaDiagonalMCOutside(uint8 *ref, int picwidth, + int dx, int dy, uint8 *pred, int pred_pitch, + int blkwidth, int blkheight, int x_inc, int z_inc, + int y_inc0, int y_inc1, int x_mid, int y_mid); + +void ChromaDiagonalMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy, + uint8 *pOut, int predPitch, int blkwidth, int blkheight); + +void ChromaHorizontalMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy, + uint8 *pOut, int predPitch, int blkwidth, int blkheight); + +void ChromaVerticalMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy, + uint8 *pOut, int predPitch, int blkwidth, int blkheight); + +void ChromaFullMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy, + uint8 *pOut, int predPitch, int blkwidth, int blkheight); + +void ChromaVerticalMC2_SIMD(uint8 *pRef, int srcPitch, int dx, int dy, + uint8 *pOut, int predPitch, int blkwidth, int blkheight); + +void ChromaHorizontalMC2_SIMD(uint8 *pRef, int srcPitch, int dx, int dy, + uint8 *pOut, int predPitch, int blkwidth, int blkheight); + +void ChromaDiagonalMC2_SIMD(uint8 *pRef, int srcPitch, int dx, int dy, + uint8 *pOut, int predPitch, int blkwidth, int blkheight); + + +/*----------- slice.c ---------------*/ +/** +This function performs the main decoding loop for slice data including +INTRA/INTER prediction, transform and quantization and compensation. +See decode_frame_slice() in JM. +\param "video" "Pointer to AVCDecObject." +\return "AVCDEC_SUCCESS for success, AVCDEC_PICTURE_READY for end-of-picture and AVCDEC_FAIL otherwise." +*/ +AVCDec_Status DecodeSlice(AVCDecObject *video); +AVCDec_Status ConcealSlice(AVCDecObject *decvid, int mbnum_start, int mbnum_end); +/** +This function performs the decoding of one macroblock. +\param "video" "Pointer to AVCDecObject." +\param "prevMbSkipped" "A value derived in 7.3.4." +\return "AVCDEC_SUCCESS for success or AVCDEC_FAIL otherwise." +*/ +AVCDec_Status DecodeMB(AVCDecObject *video); + +/** +This function performs macroblock prediction type decoding as in subclause 7.3.5.1. +\param "video" "Pointer to AVCCommonObj." +\param "currMB" "Pointer to the current macroblock." +\param "stream" "Pointer to AVCDecBitstream." +\return "AVCDEC_SUCCESS for success or AVCDEC_FAIL otherwise." +*/ +AVCDec_Status mb_pred(AVCCommonObj *video, AVCMacroblock *currMB, AVCDecBitstream *stream); + +/** +This function performs sub-macroblock prediction type decoding as in subclause 7.3.5.2. +\param "video" "Pointer to AVCCommonObj." +\param "currMB" "Pointer to the current macroblock." +\param "stream" "Pointer to AVCDecBitstream." +\return "AVCDEC_SUCCESS for success or AVCDEC_FAIL otherwise." +*/ +AVCDec_Status sub_mb_pred(AVCCommonObj *video, AVCMacroblock *currMB, AVCDecBitstream *stream); + +/** +This function interprets the mb_type and sets necessary information +when the slice type is AVC_I_SLICE. +in the macroblock structure. +\param "mblock" "Pointer to current AVCMacroblock." +\param "mb_type" "From the syntax bitstream." +\return "void" +*/ +void InterpretMBModeI(AVCMacroblock *mblock, uint mb_type); + +/** +This function interprets the mb_type and sets necessary information +when the slice type is AVC_P_SLICE. +in the macroblock structure. +\param "mblock" "Pointer to current AVCMacroblock." +\param "mb_type" "From the syntax bitstream." +\return "void" +*/ +void InterpretMBModeP(AVCMacroblock *mblock, uint mb_type); + +/** +This function interprets the mb_type and sets necessary information +when the slice type is AVC_B_SLICE. +in the macroblock structure. +\param "mblock" "Pointer to current AVCMacroblock." +\param "mb_type" "From the syntax bitstream." +\return "void" +*/ +void InterpretMBModeB(AVCMacroblock *mblock, uint mb_type); + +/** +This function interprets the mb_type and sets necessary information +when the slice type is AVC_SI_SLICE. +in the macroblock structure. +\param "mblock" "Pointer to current AVCMacroblock." +\param "mb_type" "From the syntax bitstream." +\return "void" +*/ +void InterpretMBModeSI(AVCMacroblock *mblock, uint mb_type); + +/** +This function interprets the sub_mb_type and sets necessary information +when the slice type is AVC_P_SLICE. +in the macroblock structure. +\param "mblock" "Pointer to current AVCMacroblock." +\param "sub_mb_type" "From the syntax bitstream." +\return "void" +*/ +void InterpretSubMBModeP(AVCMacroblock *mblock, uint *sub_mb_type); + +/** +This function interprets the sub_mb_type and sets necessary information +when the slice type is AVC_B_SLICE. +in the macroblock structure. +\param "mblock" "Pointer to current AVCMacroblock." +\param "sub_mb_type" "From the syntax bitstream." +\return "void" +*/ +void InterpretSubMBModeB(AVCMacroblock *mblock, uint *sub_mb_type); + +/** +This function decodes the Intra4x4 prediction mode from neighboring information +and from the decoded syntax. +\param "video" "Pointer to AVCCommonObj." +\param "currMB" "Pointer to current macroblock." +\param "stream" "Pointer to AVCDecBitstream." +\return "AVCDEC_SUCCESS or AVCDEC_FAIL." +*/ +AVCDec_Status DecodeIntra4x4Mode(AVCCommonObj *video, AVCMacroblock *currMB, AVCDecBitstream *stream); + +/*----------- vlc.c -------------------*/ +/** +This function reads and decodes Exp-Golomb codes. +\param "bitstream" "Pointer to AVCDecBitstream." +\param "codeNum" "Pointer to the value of the codeNum." +\return "AVCDEC_SUCCESS or AVCDEC_FAIL." +*/ +AVCDec_Status ue_v(AVCDecBitstream *bitstream, uint *codeNum); + +/** +This function reads and decodes signed Exp-Golomb codes. +\param "bitstream" "Pointer to AVCDecBitstream." +\param "value" "Pointer to syntax element value." +\return "AVCDEC_SUCCESS or AVCDEC_FAIL." +*/ +AVCDec_Status se_v(AVCDecBitstream *bitstream, int *value); + +/** +This function reads and decodes signed Exp-Golomb codes for +32 bit codeword. +\param "bitstream" "Pointer to AVCDecBitstream." +\param "value" "Pointer to syntax element value." +\return "AVCDEC_SUCCESS or AVCDEC_FAIL." +*/ +AVCDec_Status se_v32bit(AVCDecBitstream *bitstream, int32 *value); + +/** +This function reads and decodes truncated Exp-Golomb codes. +\param "bitstream" "Pointer to AVCDecBitstream." +\param "value" "Pointer to syntax element value." +\param "range" "Range of the value as input to determine the algorithm." +\return "AVCDEC_SUCCESS or AVCDEC_FAIL." +*/ +AVCDec_Status te_v(AVCDecBitstream *bitstream, uint *value, uint range); + +/** +This function parse Exp-Golomb code from the bitstream. +\param "bitstream" "Pointer to AVCDecBitstream." +\param "leadingZeros" "Pointer to the number of leading zeros." +\param "infobits" "Pointer to the value after leading zeros and the first one. + The total number of bits read is 2*leadingZeros + 1." +\return "AVCDEC_SUCCESS or AVCDEC_FAIL." +*/ +AVCDec_Status GetEGBitstring(AVCDecBitstream *bitstream, int *leadingZeros, int *infobits); + +/** +This function parse Exp-Golomb code from the bitstream for 32 bit codewords. +\param "bitstream" "Pointer to AVCDecBitstream." +\param "leadingZeros" "Pointer to the number of leading zeros." +\param "infobits" "Pointer to the value after leading zeros and the first one. + The total number of bits read is 2*leadingZeros + 1." +\return "AVCDEC_SUCCESS or AVCDEC_FAIL." +*/ +AVCDec_Status GetEGBitstring32bit(AVCDecBitstream *bitstream, int *leadingZeros, uint32 *infobits); + +/** +This function performs CAVLC decoding of the CBP (coded block pattern) of a macroblock +by calling ue_v() and then mapping the codeNum to the corresponding CBP value. +\param "currMB" "Pointer to the current AVCMacroblock structure." +\param "stream" "Pointer to the AVCDecBitstream." +\return "void" +*/ +AVCDec_Status DecodeCBP(AVCMacroblock *currMB, AVCDecBitstream *stream); + +/** +This function decodes the syntax for trailing ones and total coefficient. +Subject to optimization. +\param "stream" "Pointer to the AVCDecBitstream." +\param "TrailingOnes" "Pointer to the trailing one variable output." +\param "TotalCoeff" "Pointer to the total coefficient variable output." +\param "nC" "Context for number of nonzero coefficient (prediction context)." +\return "AVCDEC_SUCCESS for success." +*/ +AVCDec_Status ce_TotalCoeffTrailingOnes(AVCDecBitstream *stream, int *TrailingOnes, int *TotalCoeff, int nC); + +/** +This function decodes the syntax for trailing ones and total coefficient for +chroma DC block. Subject to optimization. +\param "stream" "Pointer to the AVCDecBitstream." +\param "TrailingOnes" "Pointer to the trailing one variable output." +\param "TotalCoeff" "Pointer to the total coefficient variable output." +\return "AVCDEC_SUCCESS for success." +*/ +AVCDec_Status ce_TotalCoeffTrailingOnesChromaDC(AVCDecBitstream *stream, int *TrailingOnes, int *TotalCoeff); + +/** +This function decode a VLC table with 2 output. +\param "stream" "Pointer to the AVCDecBitstream." +\param "lentab" "Table for code length." +\param "codtab" "Table for code value." +\param "tabwidth" "Width of the table or alphabet size of the first output." +\param "tabheight" "Height of the table or alphabet size of the second output." +\param "code1" "Pointer to the first output." +\param "code2" "Pointer to the second output." +\return "AVCDEC_SUCCESS for success." +*/ +AVCDec_Status code_from_bitstream_2d(AVCDecBitstream *stream, int *lentab, int *codtab, int tabwidth, + int tabheight, int *code1, int *code2); + +/** +This function decodes the level_prefix VLC value as in Table 9-6. +\param "stream" "Pointer to the AVCDecBitstream." +\param "code" "Pointer to the output." +\return "AVCDEC_SUCCESS for success." +*/ +AVCDec_Status ce_LevelPrefix(AVCDecBitstream *stream, uint *code); + +/** +This function decodes total_zeros VLC syntax as in Table 9-7 and 9-8. +\param "stream" "Pointer to the AVCDecBitstream." +\param "code" "Pointer to the output." +\param "TotalCoeff" "Context parameter." +\return "AVCDEC_SUCCESS for success." +*/ +AVCDec_Status ce_TotalZeros(AVCDecBitstream *stream, int *code, int TotalCoeff); + +/** +This function decodes total_zeros VLC syntax for chroma DC as in Table 9-9. +\param "stream" "Pointer to the AVCDecBitstream." +\param "code" "Pointer to the output." +\param "TotalCoeff" "Context parameter." +\return "AVCDEC_SUCCESS for success." +*/ +AVCDec_Status ce_TotalZerosChromaDC(AVCDecBitstream *stream, int *code, int TotalCoeff); + +/** +This function decodes run_before VLC syntax as in Table 9-10. +\param "stream" "Pointer to the AVCDecBitstream." +\param "code" "Pointer to the output." +\param "zeroLeft" "Context parameter." +\return "AVCDEC_SUCCESS for success." +*/ +AVCDec_Status ce_RunBefore(AVCDecBitstream *stream, int *code, int zeroLeft); + +/*----------- header.c -------------------*/ +/** +This function parses vui_parameters. +\param "decvid" "Pointer to AVCDecObject." +\param "stream" "Pointer to AVCDecBitstream." +\return "AVCDEC_SUCCESS or AVCDEC_FAIL." +*/ +AVCDec_Status vui_parameters(AVCDecObject *decvid, AVCDecBitstream *stream, AVCSeqParamSet *currSPS); +AVCDec_Status sei_payload(AVCDecObject *decvid, AVCDecBitstream *stream, uint payloadType, uint payloadSize); + +AVCDec_Status buffering_period(AVCDecObject *decvid, AVCDecBitstream *stream); +AVCDec_Status pic_timing(AVCDecObject *decvid, AVCDecBitstream *stream); +AVCDec_Status recovery_point(AVCDecObject *decvid, AVCDecBitstream *stream); +AVCDec_Status dec_ref_pic_marking_repetition(AVCDecObject *decvid, AVCDecBitstream *stream); +AVCDec_Status motion_constrained_slice_group_set(AVCDecObject *decvid, AVCDecBitstream *stream); + + +/** +This function parses hrd_parameters. +\param "decvid" "Pointer to AVCDecObject." +\param "stream" "Pointer to AVCDecBitstream." +\return "AVCDEC_SUCCESS or AVCDEC_FAIL." +*/ +AVCDec_Status hrd_parameters(AVCDecObject *decvid, AVCDecBitstream *stream, AVCHRDParams *HRDParam); + +/** +This function decodes the syntax in sequence parameter set slice and fill up the AVCSeqParamSet +structure. +\param "decvid" "Pointer to AVCDecObject." +\param "video" "Pointer to AVCCommonObj." +\param "stream" "Pointer to AVCDecBitstream." +\return "AVCDEC_SUCCESS or AVCDEC_FAIL." +*/ +AVCDec_Status DecodeSPS(AVCDecObject *decvid, AVCDecBitstream *stream); + +/** +This function decodes the syntax in picture parameter set and fill up the AVCPicParamSet +structure. +\param "decvid" "Pointer to AVCDecObject." +\param "video" "Pointer to AVCCommonObj." +\param "stream" "Pointer to AVCDecBitstream." +\return "AVCDEC_SUCCESS or AVCDEC_FAIL." +*/ +AVCDec_Status DecodePPS(AVCDecObject *decvid, AVCCommonObj *video, AVCDecBitstream *stream); +AVCDec_Status DecodeSEI(AVCDecObject *decvid, AVCDecBitstream *stream); + +/** +This function decodes slice header, calls related functions such as +reference picture list reordering, prediction weight table, decode ref marking. +See FirstPartOfSliceHeader() and RestOfSliceHeader() in JM. +\param "decvid" "Pointer to AVCDecObject." +\param "video" "Pointer to AVCCommonObj." +\param "stream" "Pointer to AVCDecBitstream." +\return "AVCDEC_SUCCESS for success and AVCDEC_FAIL otherwise." +*/ +AVCDec_Status DecodeSliceHeader(AVCDecObject *decvid, AVCCommonObj *video, AVCDecBitstream *stream); + +/** +This function performes necessary operations to create dummy frames when +there is a gap in frame_num. +\param "video" "Pointer to AVCCommonObj." +\return "AVCDEC_SUCCESS for success and AVCDEC_FAIL otherwise." +*/ +AVCDec_Status fill_frame_num_gap(AVCHandle *avcHandle, AVCCommonObj *video); + +/** +This function decodes ref_pic_list_reordering related syntax and fill up the AVCSliceHeader +structure. +\param "video" "Pointer to AVCCommonObj." +\param "stream" "Pointer to AVCDecBitstream." +\param "sliceHdr" "Pointer to AVCSliceHdr." +\param "slice_type" "Value of slice_type - 5 if greater than 5." +\return "AVCDEC_SUCCESS for success and AVCDEC_FAIL otherwise." +*/ +AVCDec_Status ref_pic_list_reordering(AVCCommonObj *video, AVCDecBitstream *stream, AVCSliceHeader *sliceHdr, int slice_type); + +/** +This function decodes dec_ref_pic_marking related syntax and fill up the AVCSliceHeader +structure. +\param "video" "Pointer to AVCCommonObj." +\param "stream" "Pointer to AVCDecBitstream." +\param "sliceHdr" "Pointer to AVCSliceHdr." +\return "AVCDEC_SUCCESS for success and AVCDEC_FAIL otherwise." +*/ +AVCDec_Status dec_ref_pic_marking(AVCCommonObj *video, AVCDecBitstream *stream, AVCSliceHeader *sliceHdr); + +/** +This function performs POC related operation prior to decoding a picture +\param "video" "Pointer to AVCCommonObj." +\return "AVCDEC_SUCCESS for success and AVCDEC_FAIL otherwise." +See also PostPOC() for initialization of some variables. +*/ +AVCDec_Status DecodePOC(AVCCommonObj *video); + + + +/*------------ residual.c ------------------*/ +/** +This function decodes the intra pcm data and fill it in the corresponding location +on the current picture. +\param "video" "Pointer to AVCCommonObj." +\param "stream" "Pointer to AVCDecBitstream." +*/ +AVCDec_Status DecodeIntraPCM(AVCCommonObj *video, AVCDecBitstream *stream); + +/** +This function performs residual syntax decoding as well as quantization and transformation of +the decoded coefficients. See subclause 7.3.5.3. +\param "video" "Pointer to AVCDecObject." +\param "currMB" "Pointer to current macroblock." +*/ +AVCDec_Status residual(AVCDecObject *video, AVCMacroblock *currMB); + +/** +This function performs CAVLC syntax decoding to get the run and level information of the coefficients. +\param "video" "Pointer to AVCDecObject." +\param "type" "One of AVCResidualType for a particular 4x4 block." +\param "bx" "Horizontal block index." +\param "by" "Vertical block index." +\param "level" "Pointer to array of level for output." +\param "run" "Pointer to array of run for output." +\param "numcoeff" "Pointer to the total number of nonzero coefficients." +\return "AVCDEC_SUCCESS for success." +*/ +AVCDec_Status residual_block_cavlc(AVCDecObject *video, int nC, int maxNumCoeff, + int *level, int *run, int *numcoeff); + +#endif /* _AVCDEC_LIB_H_ */ diff --git a/media/libstagefright/codecs/avc/dec/src/header.cpp b/media/libstagefright/codecs/avc/dec/src/header.cpp new file mode 100644 index 0000000..8681e2b --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/src/header.cpp @@ -0,0 +1,1391 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 "avcdec_lib.h" +#include "avcdec_bitstream.h" +#include "avcdec_api.h" + +/** see subclause 7.4.2.1 */ +AVCDec_Status DecodeSPS(AVCDecObject *decvid, AVCDecBitstream *stream) +{ + AVCDec_Status status = AVCDEC_SUCCESS; + AVCSeqParamSet *seqParam; + uint temp; + int i; + uint profile_idc, constrained_set0_flag, constrained_set1_flag, constrained_set2_flag; + uint level_idc, seq_parameter_set_id; + void *userData = decvid->avcHandle->userData; + AVCHandle *avcHandle = decvid->avcHandle; + + DEBUG_LOG(userData, AVC_LOGTYPE_INFO, "DecodeSPS", -1, -1); + + BitstreamReadBits(stream, 8, &profile_idc); + BitstreamRead1Bit(stream, &constrained_set0_flag); +// if (profile_idc != 66 && constrained_set0_flag != 1) +// { +// return AVCDEC_FAIL; +// } + BitstreamRead1Bit(stream, &constrained_set1_flag); + BitstreamRead1Bit(stream, &constrained_set2_flag); + BitstreamReadBits(stream, 5, &temp); + BitstreamReadBits(stream, 8, &level_idc); + if (level_idc > 51) + { + return AVCDEC_FAIL; + } + if (mapLev2Idx[level_idc] == 255) + { + return AVCDEC_FAIL; + } + ue_v(stream, &seq_parameter_set_id); + + if (seq_parameter_set_id > 31) + { + return AVCDEC_FAIL; + } + + /* Allocate sequence param set for seqParams[seq_parameter_set_id]. */ + if (decvid->seqParams[seq_parameter_set_id] == NULL) /* allocate seqParams[id] */ + { + decvid->seqParams[seq_parameter_set_id] = + (AVCSeqParamSet*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCSeqParamSet), DEFAULT_ATTR); + + if (decvid->seqParams[seq_parameter_set_id] == NULL) + { + return AVCDEC_MEMORY_FAIL; + } + } + + DEBUG_LOG(userData, AVC_LOGTYPE_INFO, "done alloc seqParams", -1, -1); + + seqParam = decvid->seqParams[seq_parameter_set_id]; + + seqParam->profile_idc = profile_idc; + seqParam->constrained_set0_flag = constrained_set0_flag; + seqParam->constrained_set1_flag = constrained_set1_flag; + seqParam->constrained_set2_flag = constrained_set2_flag; + seqParam->level_idc = level_idc; + seqParam->seq_parameter_set_id = seq_parameter_set_id; + + /* continue decoding SPS */ + ue_v(stream, &(seqParam->log2_max_frame_num_minus4)); + + if (seqParam->log2_max_frame_num_minus4 > 12) + { + return AVCDEC_FAIL; + } + + ue_v(stream, &(seqParam->pic_order_cnt_type)); + + DEBUG_LOG(userData, AVC_LOGTYPE_INFO, "check point 1", seqParam->log2_max_frame_num_minus4, seqParam->pic_order_cnt_type); + + if (seqParam->pic_order_cnt_type == 0) + { + ue_v(stream, &(seqParam->log2_max_pic_order_cnt_lsb_minus4)); + } + else if (seqParam->pic_order_cnt_type == 1) + { // MC_CHECK + BitstreamRead1Bit(stream, (uint*)&(seqParam->delta_pic_order_always_zero_flag)); + se_v32bit(stream, &(seqParam->offset_for_non_ref_pic)); + se_v32bit(stream, &(seqParam->offset_for_top_to_bottom_field)); + ue_v(stream, &(seqParam->num_ref_frames_in_pic_order_cnt_cycle)); + + for (i = 0; i < (int)(seqParam->num_ref_frames_in_pic_order_cnt_cycle); i++) + { + se_v32bit(stream, &(seqParam->offset_for_ref_frame[i])); + } + } + + ue_v(stream, &(seqParam->num_ref_frames)); + + if (seqParam->num_ref_frames > 16) + { + return AVCDEC_FAIL; + } + + DEBUG_LOG(userData, AVC_LOGTYPE_INFO, "check point 2", seqParam->num_ref_frames, -1); + + BitstreamRead1Bit(stream, (uint*)&(seqParam->gaps_in_frame_num_value_allowed_flag)); + ue_v(stream, &(seqParam->pic_width_in_mbs_minus1)); + + DEBUG_LOG(userData, AVC_LOGTYPE_INFO, "picwidth", seqParam->pic_width_in_mbs_minus1, -1); + + ue_v(stream, &(seqParam->pic_height_in_map_units_minus1)); + + DEBUG_LOG(userData, AVC_LOGTYPE_INFO, "picwidth", seqParam->pic_height_in_map_units_minus1, -1); + + BitstreamRead1Bit(stream, (uint*)&(seqParam->frame_mbs_only_flag)); + + seqParam->mb_adaptive_frame_field_flag = 0; /* default value */ + if (!seqParam->frame_mbs_only_flag) + { + BitstreamRead1Bit(stream, (uint*)&(seqParam->mb_adaptive_frame_field_flag)); + } + + DEBUG_LOG(userData, AVC_LOGTYPE_INFO, "check point 3", seqParam->frame_mbs_only_flag, -1); + + BitstreamRead1Bit(stream, (uint*)&(seqParam->direct_8x8_inference_flag)); + + DEBUG_LOG(userData, AVC_LOGTYPE_INFO, "check point 4", seqParam->direct_8x8_inference_flag, -1); + + BitstreamRead1Bit(stream, (uint*)&(seqParam->frame_cropping_flag)); + seqParam->frame_crop_left_offset = 0; /* default value */ + seqParam->frame_crop_right_offset = 0;/* default value */ + seqParam->frame_crop_top_offset = 0;/* default value */ + seqParam->frame_crop_bottom_offset = 0;/* default value */ + if (seqParam->frame_cropping_flag) + { + ue_v(stream, &(seqParam->frame_crop_left_offset)); + ue_v(stream, &(seqParam->frame_crop_right_offset)); + ue_v(stream, &(seqParam->frame_crop_top_offset)); + ue_v(stream, &(seqParam->frame_crop_bottom_offset)); + } + + DEBUG_LOG(userData, AVC_LOGTYPE_INFO, "check point 5", seqParam->frame_cropping_flag, -1); + + BitstreamRead1Bit(stream, (uint*)&(seqParam->vui_parameters_present_flag)); + if (seqParam->vui_parameters_present_flag) + { + status = vui_parameters(decvid, stream, seqParam); + if (status != AVCDEC_SUCCESS) + { + return AVCDEC_FAIL; + } + } + + return status; +} + + +AVCDec_Status vui_parameters(AVCDecObject *decvid, AVCDecBitstream *stream, AVCSeqParamSet *currSPS) +{ + uint temp; + uint temp32; + uint aspect_ratio_idc, overscan_appopriate_flag, video_format, video_full_range_flag; + /* aspect_ratio_info_present_flag */ + BitstreamRead1Bit(stream, &temp); + if (temp) + { + BitstreamReadBits(stream, 8, &aspect_ratio_idc); + if (aspect_ratio_idc == 255) + { + /* sar_width */ + BitstreamReadBits(stream, 16, &temp); + /* sar_height */ + BitstreamReadBits(stream, 16, &temp); + } + } + /* overscan_info_present */ + BitstreamRead1Bit(stream, &temp); + if (temp) + { + BitstreamRead1Bit(stream, &overscan_appopriate_flag); + } + /* video_signal_type_present_flag */ + BitstreamRead1Bit(stream, &temp); + if (temp) + { + BitstreamReadBits(stream, 3, &video_format); + BitstreamRead1Bit(stream, &video_full_range_flag); + /* colour_description_present_flag */ + BitstreamRead1Bit(stream, &temp); + if (temp) + { + /* colour_primaries */ + BitstreamReadBits(stream, 8, &temp); + /* transfer_characteristics */ + BitstreamReadBits(stream, 8, &temp); + /* matrix coefficients */ + BitstreamReadBits(stream, 8, &temp); + } + } + /* chroma_loc_info_present_flag */ + BitstreamRead1Bit(stream, &temp); + if (temp) + { + /* chroma_sample_loc_type_top_field */ + ue_v(stream, &temp); + /* chroma_sample_loc_type_bottom_field */ + ue_v(stream, &temp); + } + + /* timing_info_present_flag*/ + BitstreamRead1Bit(stream, &temp); + if (temp) + { + /* num_unit_in_tick*/ + BitstreamReadBits(stream, 32, &temp32); + /* time_scale */ + BitstreamReadBits(stream, 32, &temp32); + /* fixed_frame_rate_flag */ + BitstreamRead1Bit(stream, &temp); + } + + /* nal_hrd_parameters_present_flag */ + BitstreamRead1Bit(stream, &temp); + currSPS->vui_parameters.nal_hrd_parameters_present_flag = temp; + if (temp) + { + hrd_parameters(decvid, stream, &(currSPS->vui_parameters.nal_hrd_parameters)); + } + /* vcl_hrd_parameters_present_flag*/ + BitstreamRead1Bit(stream, &temp); + currSPS->vui_parameters.vcl_hrd_parameters_present_flag = temp; + if (temp) + { + hrd_parameters(decvid, stream, &(currSPS->vui_parameters.vcl_hrd_parameters)); + } + if (currSPS->vui_parameters.nal_hrd_parameters_present_flag || currSPS->vui_parameters.vcl_hrd_parameters_present_flag) + { + /* low_delay_hrd_flag */ + BitstreamRead1Bit(stream, &temp); + } + /* pic_struct_present_flag */ + BitstreamRead1Bit(stream, &temp); + currSPS->vui_parameters.pic_struct_present_flag = temp; + /* bitstream_restriction_flag */ + BitstreamRead1Bit(stream, &temp); + if (temp) + { + /* motion_vectors_over_pic_boundaries_flag */ + BitstreamRead1Bit(stream, &temp); + /* max_bytes_per_pic_denom */ + ue_v(stream, &temp); + /* max_bits_per_mb_denom */ + ue_v(stream, &temp); + /* log2_max_mv_length_horizontal */ + ue_v(stream, &temp); + /* log2_max_mv_length_vertical */ + ue_v(stream, &temp); + /* num_reorder_frames */ + ue_v(stream, &temp); + /* max_dec_frame_buffering */ + ue_v(stream, &temp); + } + return AVCDEC_SUCCESS; +} +AVCDec_Status hrd_parameters(AVCDecObject *decvid, AVCDecBitstream *stream, AVCHRDParams *HRDParam) +{ + OSCL_UNUSED_ARG(decvid); + uint temp; + uint cpb_cnt_minus1; + uint i; + ue_v(stream, &cpb_cnt_minus1); + HRDParam->cpb_cnt_minus1 = cpb_cnt_minus1; + /* bit_rate_scale */ + BitstreamReadBits(stream, 4, &temp); + /* cpb_size_scale */ + BitstreamReadBits(stream, 4, &temp); + for (i = 0; i <= cpb_cnt_minus1; i++) + { + /* bit_rate_value_minus1[i] */ + ue_v(stream, &temp); + /* cpb_size_value_minus1[i] */ + ue_v(stream, &temp); + /* cbr_flag[i] */ + ue_v(stream, &temp); + } + /* initial_cpb_removal_delay_length_minus1 */ + BitstreamReadBits(stream, 5, &temp); + /* cpb_removal_delay_length_minus1 */ + BitstreamReadBits(stream, 5, &temp); + HRDParam->cpb_removal_delay_length_minus1 = temp; + /* dpb_output_delay_length_minus1 */ + BitstreamReadBits(stream, 5, &temp); + HRDParam->dpb_output_delay_length_minus1 = temp; + /* time_offset_length */ + BitstreamReadBits(stream, 5, &temp); + HRDParam->time_offset_length = temp; + return AVCDEC_SUCCESS; +} + + +/** see subclause 7.4.2.2 */ +AVCDec_Status DecodePPS(AVCDecObject *decvid, AVCCommonObj *video, AVCDecBitstream *stream) +{ + AVCPicParamSet *picParam; + AVCDec_Status status; + int i, iGroup, numBits; + int PicWidthInMbs, PicHeightInMapUnits, PicSizeInMapUnits; + uint pic_parameter_set_id, seq_parameter_set_id; + void *userData = decvid->avcHandle->userData; + AVCHandle *avcHandle = decvid->avcHandle; + + ue_v(stream, &pic_parameter_set_id); + if (pic_parameter_set_id > 255) + { + return AVCDEC_FAIL; + } + + ue_v(stream, &seq_parameter_set_id); + + if (seq_parameter_set_id > 31) + { + return AVCDEC_FAIL; + } + + /* 2.1 if picParams[pic_param_set_id] is NULL, allocate it. */ + if (decvid->picParams[pic_parameter_set_id] == NULL) + { + decvid->picParams[pic_parameter_set_id] = + (AVCPicParamSet*)avcHandle->CBAVC_Malloc(userData, sizeof(AVCPicParamSet), DEFAULT_ATTR); + if (decvid->picParams[pic_parameter_set_id] == NULL) + { + return AVCDEC_MEMORY_FAIL; + } + + decvid->picParams[pic_parameter_set_id]->slice_group_id = NULL; + } + + video->currPicParams = picParam = decvid->picParams[pic_parameter_set_id]; + picParam->seq_parameter_set_id = seq_parameter_set_id; + picParam->pic_parameter_set_id = pic_parameter_set_id; + + BitstreamRead1Bit(stream, (uint*)&(picParam->entropy_coding_mode_flag)); + if (picParam->entropy_coding_mode_flag) + { + status = AVCDEC_FAIL; + goto clean_up; + } + BitstreamRead1Bit(stream, (uint*)&(picParam->pic_order_present_flag)); + ue_v(stream, &(picParam->num_slice_groups_minus1)); + + if (picParam->num_slice_groups_minus1 > MAX_NUM_SLICE_GROUP - 1) + { + status = AVCDEC_FAIL; + goto clean_up; + } + + picParam->slice_group_change_rate_minus1 = 0; /* default value */ + if (picParam->num_slice_groups_minus1 > 0) + { + ue_v(stream, &(picParam->slice_group_map_type)); + if (picParam->slice_group_map_type == 0) + { + for (iGroup = 0; iGroup <= (int)picParam->num_slice_groups_minus1; iGroup++) + { + ue_v(stream, &(picParam->run_length_minus1[iGroup])); + } + } + else if (picParam->slice_group_map_type == 2) + { // MC_CHECK <= or < + for (iGroup = 0; iGroup < (int)picParam->num_slice_groups_minus1; iGroup++) + { + ue_v(stream, &(picParam->top_left[iGroup])); + ue_v(stream, &(picParam->bottom_right[iGroup])); + } + } + else if (picParam->slice_group_map_type == 3 || + picParam->slice_group_map_type == 4 || + picParam->slice_group_map_type == 5) + { + BitstreamRead1Bit(stream, (uint*)&(picParam->slice_group_change_direction_flag)); + ue_v(stream, &(picParam->slice_group_change_rate_minus1)); + } + else if (picParam->slice_group_map_type == 6) + { + ue_v(stream, &(picParam->pic_size_in_map_units_minus1)); + + numBits = 0;/* ceil(log2(num_slice_groups_minus1+1)) bits */ + i = picParam->num_slice_groups_minus1; + while (i > 0) + { + numBits++; + i >>= 1; + } + + i = picParam->seq_parameter_set_id; + if (decvid->seqParams[i] == NULL) + { + status = AVCDEC_FAIL; + goto clean_up; + } + + + PicWidthInMbs = decvid->seqParams[i]->pic_width_in_mbs_minus1 + 1; + PicHeightInMapUnits = decvid->seqParams[i]->pic_height_in_map_units_minus1 + 1 ; + PicSizeInMapUnits = PicWidthInMbs * PicHeightInMapUnits ; + + /* information has to be consistent with the seq_param */ + if ((int)picParam->pic_size_in_map_units_minus1 != PicSizeInMapUnits - 1) + { + status = AVCDEC_FAIL; + goto clean_up; + } + + if (picParam->slice_group_id) + { + avcHandle->CBAVC_Free(userData, (int)picParam->slice_group_id); + } + picParam->slice_group_id = (uint*)avcHandle->CBAVC_Malloc(userData, sizeof(uint) * PicSizeInMapUnits, DEFAULT_ATTR); + if (picParam->slice_group_id == NULL) + { + status = AVCDEC_MEMORY_FAIL; + goto clean_up; + } + + for (i = 0; i < PicSizeInMapUnits; i++) + { + BitstreamReadBits(stream, numBits, &(picParam->slice_group_id[i])); + } + } + + } + + ue_v(stream, &(picParam->num_ref_idx_l0_active_minus1)); + if (picParam->num_ref_idx_l0_active_minus1 > 31) + { + status = AVCDEC_FAIL; /* out of range */ + goto clean_up; + } + + ue_v(stream, &(picParam->num_ref_idx_l1_active_minus1)); + if (picParam->num_ref_idx_l1_active_minus1 > 31) + { + status = AVCDEC_FAIL; /* out of range */ + goto clean_up; + } + + BitstreamRead1Bit(stream, (uint*)&(picParam->weighted_pred_flag)); + BitstreamReadBits(stream, 2, &(picParam->weighted_bipred_idc)); + if (picParam->weighted_bipred_idc > 2) + { + status = AVCDEC_FAIL; /* out of range */ + goto clean_up; + } + + se_v(stream, &(picParam->pic_init_qp_minus26)); + if (picParam->pic_init_qp_minus26 < -26 || picParam->pic_init_qp_minus26 > 25) + { + status = AVCDEC_FAIL; /* out of range */ + goto clean_up; + } + + se_v(stream, &(picParam->pic_init_qs_minus26)); + if (picParam->pic_init_qs_minus26 < -26 || picParam->pic_init_qs_minus26 > 25) + { + status = AVCDEC_FAIL; /* out of range */ + goto clean_up; + } + + se_v(stream, &(picParam->chroma_qp_index_offset)); + if (picParam->chroma_qp_index_offset < -12 || picParam->chroma_qp_index_offset > 12) + { + status = AVCDEC_FAIL; /* out of range */ + status = AVCDEC_FAIL; /* out of range */ + goto clean_up; + } + + BitstreamReadBits(stream, 3, &pic_parameter_set_id); + picParam->deblocking_filter_control_present_flag = pic_parameter_set_id >> 2; + picParam->constrained_intra_pred_flag = (pic_parameter_set_id >> 1) & 1; + picParam->redundant_pic_cnt_present_flag = pic_parameter_set_id & 1; + + return AVCDEC_SUCCESS; +clean_up: + if (decvid->picParams[pic_parameter_set_id]) + { + if (picParam->slice_group_id) + { + avcHandle->CBAVC_Free(userData, (int)picParam->slice_group_id); + } + decvid->picParams[pic_parameter_set_id]->slice_group_id = NULL; + avcHandle->CBAVC_Free(userData, (int)decvid->picParams[pic_parameter_set_id]); + decvid->picParams[pic_parameter_set_id] = NULL; + return status; + } + return AVCDEC_SUCCESS; +} + + +/* FirstPartOfSliceHeader(); + RestOfSliceHeader() */ +/** see subclause 7.4.3 */ +AVCDec_Status DecodeSliceHeader(AVCDecObject *decvid, AVCCommonObj *video, AVCDecBitstream *stream) +{ + AVCSliceHeader *sliceHdr = video->sliceHdr; + AVCPicParamSet *currPPS; + AVCSeqParamSet *currSPS; + AVCDec_Status status; + uint idr_pic_id; + int slice_type, temp, i; + + ue_v(stream, &(sliceHdr->first_mb_in_slice)); + ue_v(stream, (uint*)&slice_type); + + if (sliceHdr->first_mb_in_slice != 0) + { + if ((int)sliceHdr->slice_type >= 5 && slice_type != (int)sliceHdr->slice_type - 5) + { + return AVCDEC_FAIL; /* slice type doesn't follow the first slice in the picture */ + } + } + sliceHdr->slice_type = (AVCSliceType) slice_type; + if (slice_type > 4) + { + slice_type -= 5; + } + + if (slice_type == 1 || slice_type > 2) + { + return AVCDEC_FAIL; + } + + video->slice_type = (AVCSliceType) slice_type; + + ue_v(stream, &(sliceHdr->pic_parameter_set_id)); + /* end FirstPartSliceHeader() */ + /* begin RestOfSliceHeader() */ + /* after getting pic_parameter_set_id, we have to load corresponding SPS and PPS */ + if (sliceHdr->pic_parameter_set_id > 255) + { + return AVCDEC_FAIL; + } + + if (decvid->picParams[sliceHdr->pic_parameter_set_id] == NULL) + return AVCDEC_FAIL; /* PPS doesn't exist */ + + currPPS = video->currPicParams = decvid->picParams[sliceHdr->pic_parameter_set_id]; + + if (decvid->seqParams[currPPS->seq_parameter_set_id] == NULL) + return AVCDEC_FAIL; /* SPS doesn't exist */ + + currSPS = video->currSeqParams = decvid->seqParams[currPPS->seq_parameter_set_id]; + + if (currPPS->seq_parameter_set_id != video->seq_parameter_set_id) + { + video->seq_parameter_set_id = currPPS->seq_parameter_set_id; + status = (AVCDec_Status)AVCConfigureSequence(decvid->avcHandle, video, false); + if (status != AVCDEC_SUCCESS) + return status; + video->level_idc = currSPS->level_idc; + } + + /* derived variables from SPS */ + video->MaxFrameNum = 1 << (currSPS->log2_max_frame_num_minus4 + 4); + // MC_OPTIMIZE + video->PicWidthInMbs = currSPS->pic_width_in_mbs_minus1 + 1; + video->PicWidthInSamplesL = video->PicWidthInMbs * 16 ; + video->PicWidthInSamplesC = video->PicWidthInMbs * 8 ; + video->PicHeightInMapUnits = currSPS->pic_height_in_map_units_minus1 + 1 ; + video->PicSizeInMapUnits = video->PicWidthInMbs * video->PicHeightInMapUnits ; + video->FrameHeightInMbs = (2 - currSPS->frame_mbs_only_flag) * video->PicHeightInMapUnits ; + + /* derived from PPS */ + video->SliceGroupChangeRate = currPPS->slice_group_change_rate_minus1 + 1; + + /* then we can continue decoding slice header */ + + BitstreamReadBits(stream, currSPS->log2_max_frame_num_minus4 + 4, &(sliceHdr->frame_num)); + + if (video->currFS == NULL && sliceHdr->frame_num != 0) + { + video->prevFrameNum = video->PrevRefFrameNum = sliceHdr->frame_num - 1; + } + + if (!currSPS->frame_mbs_only_flag) + { + BitstreamRead1Bit(stream, &(sliceHdr->field_pic_flag)); + if (sliceHdr->field_pic_flag) + { + return AVCDEC_FAIL; + } + } + + /* derived variables from slice header*/ + video->PicHeightInMbs = video->FrameHeightInMbs; + video->PicHeightInSamplesL = video->PicHeightInMbs * 16; + video->PicHeightInSamplesC = video->PicHeightInMbs * 8; + video->PicSizeInMbs = video->PicWidthInMbs * video->PicHeightInMbs; + + if (sliceHdr->first_mb_in_slice >= video->PicSizeInMbs) + { + return AVCDEC_FAIL; + } + video->MaxPicNum = video->MaxFrameNum; + video->CurrPicNum = sliceHdr->frame_num; + + + if (video->nal_unit_type == AVC_NALTYPE_IDR) + { + if (sliceHdr->frame_num != 0) + { + return AVCDEC_FAIL; + } + ue_v(stream, &idr_pic_id); + } + + sliceHdr->delta_pic_order_cnt_bottom = 0; /* default value */ + sliceHdr->delta_pic_order_cnt[0] = 0; /* default value */ + sliceHdr->delta_pic_order_cnt[1] = 0; /* default value */ + if (currSPS->pic_order_cnt_type == 0) + { + BitstreamReadBits(stream, currSPS->log2_max_pic_order_cnt_lsb_minus4 + 4, + &(sliceHdr->pic_order_cnt_lsb)); + video->MaxPicOrderCntLsb = 1 << (currSPS->log2_max_pic_order_cnt_lsb_minus4 + 4); + if (sliceHdr->pic_order_cnt_lsb > video->MaxPicOrderCntLsb - 1) + return AVCDEC_FAIL; /* out of range */ + + if (currPPS->pic_order_present_flag) + { + se_v32bit(stream, &(sliceHdr->delta_pic_order_cnt_bottom)); + } + } + if (currSPS->pic_order_cnt_type == 1 && !currSPS->delta_pic_order_always_zero_flag) + { + se_v32bit(stream, &(sliceHdr->delta_pic_order_cnt[0])); + if (currPPS->pic_order_present_flag) + { + se_v32bit(stream, &(sliceHdr->delta_pic_order_cnt[1])); + } + } + + sliceHdr->redundant_pic_cnt = 0; /* default value */ + if (currPPS->redundant_pic_cnt_present_flag) + { + // MC_CHECK + ue_v(stream, &(sliceHdr->redundant_pic_cnt)); + if (sliceHdr->redundant_pic_cnt > 127) /* out of range */ + return AVCDEC_FAIL; + + if (sliceHdr->redundant_pic_cnt > 0) /* redundant picture */ + return AVCDEC_FAIL; /* not supported */ + } + sliceHdr->num_ref_idx_l0_active_minus1 = currPPS->num_ref_idx_l0_active_minus1; + sliceHdr->num_ref_idx_l1_active_minus1 = currPPS->num_ref_idx_l1_active_minus1; + + if (slice_type == AVC_P_SLICE) + { + BitstreamRead1Bit(stream, &(sliceHdr->num_ref_idx_active_override_flag)); + if (sliceHdr->num_ref_idx_active_override_flag) + { + ue_v(stream, &(sliceHdr->num_ref_idx_l0_active_minus1)); + } + else /* the following condition is not allowed if the flag is zero */ + { + if ((slice_type == AVC_P_SLICE) && currPPS->num_ref_idx_l0_active_minus1 > 15) + { + return AVCDEC_FAIL; /* not allowed */ + } + } + } + + + if (sliceHdr->num_ref_idx_l0_active_minus1 > 15 || + sliceHdr->num_ref_idx_l1_active_minus1 > 15) + { + return AVCDEC_FAIL; /* not allowed */ + } + /* if MbaffFrameFlag =1, + max value of index is num_ref_idx_l0_active_minus1 for frame MBs and + 2*sliceHdr->num_ref_idx_l0_active_minus1 + 1 for field MBs */ + + /* ref_pic_list_reordering() */ + status = ref_pic_list_reordering(video, stream, sliceHdr, slice_type); + if (status != AVCDEC_SUCCESS) + { + return status; + } + + + if (video->nal_ref_idc != 0) + { + dec_ref_pic_marking(video, stream, sliceHdr); + } + se_v(stream, &(sliceHdr->slice_qp_delta)); + + video->QPy = 26 + currPPS->pic_init_qp_minus26 + sliceHdr->slice_qp_delta; + if (video->QPy > 51 || video->QPy < 0) + { + video->QPy = AVC_CLIP3(0, 51, video->QPy); +// return AVCDEC_FAIL; + } + video->QPc = mapQPi2QPc[AVC_CLIP3(0, 51, video->QPy + video->currPicParams->chroma_qp_index_offset)]; + + video->QPy_div_6 = (video->QPy * 43) >> 8; + video->QPy_mod_6 = video->QPy - 6 * video->QPy_div_6; + + video->QPc_div_6 = (video->QPc * 43) >> 8; + video->QPc_mod_6 = video->QPc - 6 * video->QPc_div_6; + + sliceHdr->slice_alpha_c0_offset_div2 = 0; + sliceHdr->slice_beta_offset_div_2 = 0; + sliceHdr->disable_deblocking_filter_idc = 0; + video->FilterOffsetA = video->FilterOffsetB = 0; + + if (currPPS->deblocking_filter_control_present_flag) + { + ue_v(stream, &(sliceHdr->disable_deblocking_filter_idc)); + if (sliceHdr->disable_deblocking_filter_idc > 2) + { + return AVCDEC_FAIL; /* out of range */ + } + if (sliceHdr->disable_deblocking_filter_idc != 1) + { + se_v(stream, &(sliceHdr->slice_alpha_c0_offset_div2)); + if (sliceHdr->slice_alpha_c0_offset_div2 < -6 || + sliceHdr->slice_alpha_c0_offset_div2 > 6) + { + return AVCDEC_FAIL; + } + video->FilterOffsetA = sliceHdr->slice_alpha_c0_offset_div2 << 1; + + se_v(stream, &(sliceHdr->slice_beta_offset_div_2)); + if (sliceHdr->slice_beta_offset_div_2 < -6 || + sliceHdr->slice_beta_offset_div_2 > 6) + { + return AVCDEC_FAIL; + } + video->FilterOffsetB = sliceHdr->slice_beta_offset_div_2 << 1; + } + } + + if (currPPS->num_slice_groups_minus1 > 0 && currPPS->slice_group_map_type >= 3 + && currPPS->slice_group_map_type <= 5) + { + /* Ceil(Log2(PicSizeInMapUnits/(float)SliceGroupChangeRate + 1)) */ + temp = video->PicSizeInMapUnits / video->SliceGroupChangeRate; + if (video->PicSizeInMapUnits % video->SliceGroupChangeRate) + { + temp++; + } + i = 0; + temp++; + while (temp) + { + temp >>= 1; + i++; + } + + BitstreamReadBits(stream, i, &(sliceHdr->slice_group_change_cycle)); + video->MapUnitsInSliceGroup0 = + AVC_MIN(sliceHdr->slice_group_change_cycle * video->SliceGroupChangeRate, video->PicSizeInMapUnits); + } + + return AVCDEC_SUCCESS; +} + + +AVCDec_Status fill_frame_num_gap(AVCHandle *avcHandle, AVCCommonObj *video) +{ + AVCDec_Status status; + int CurrFrameNum; + int UnusedShortTermFrameNum; + int tmp1 = video->sliceHdr->delta_pic_order_cnt[0]; + int tmp2 = video->sliceHdr->delta_pic_order_cnt[1]; + int tmp3 = video->CurrPicNum; + int tmp4 = video->sliceHdr->adaptive_ref_pic_marking_mode_flag; + UnusedShortTermFrameNum = (video->prevFrameNum + 1) % video->MaxFrameNum; + CurrFrameNum = video->sliceHdr->frame_num; + + video->sliceHdr->delta_pic_order_cnt[0] = 0; + video->sliceHdr->delta_pic_order_cnt[1] = 0; + while (CurrFrameNum != UnusedShortTermFrameNum) + { + video->CurrPicNum = UnusedShortTermFrameNum; + video->sliceHdr->frame_num = UnusedShortTermFrameNum; + + status = (AVCDec_Status)DPBInitBuffer(avcHandle, video); + if (status != AVCDEC_SUCCESS) /* no buffer available */ + { + return status; + } + DecodePOC(video); + DPBInitPic(video, UnusedShortTermFrameNum); + + + video->currFS->PicOrderCnt = video->PicOrderCnt; + video->currFS->FrameNum = video->sliceHdr->frame_num; + + /* initialize everything to zero */ + video->currFS->IsOutputted = 0x01; + video->currFS->IsReference = 3; + video->currFS->IsLongTerm = 0; + video->currFS->frame.isReference = TRUE; + video->currFS->frame.isLongTerm = FALSE; + + video->sliceHdr->adaptive_ref_pic_marking_mode_flag = 0; + + status = (AVCDec_Status)StorePictureInDPB(avcHandle, video); // MC_CHECK check the return status + if (status != AVCDEC_SUCCESS) + { + return AVCDEC_FAIL; + } + video->prevFrameNum = UnusedShortTermFrameNum; + UnusedShortTermFrameNum = (UnusedShortTermFrameNum + 1) % video->MaxFrameNum; + } + video->sliceHdr->frame_num = CurrFrameNum; + video->CurrPicNum = tmp3; + video->sliceHdr->delta_pic_order_cnt[0] = tmp1; + video->sliceHdr->delta_pic_order_cnt[1] = tmp2; + video->sliceHdr->adaptive_ref_pic_marking_mode_flag = tmp4; + return AVCDEC_SUCCESS; +} + +/** see subclause 7.4.3.1 */ +AVCDec_Status ref_pic_list_reordering(AVCCommonObj *video, AVCDecBitstream *stream, AVCSliceHeader *sliceHdr, int slice_type) +{ + int i; + + if (slice_type != AVC_I_SLICE) + { + BitstreamRead1Bit(stream, &(sliceHdr->ref_pic_list_reordering_flag_l0)); + if (sliceHdr->ref_pic_list_reordering_flag_l0) + { + i = 0; + do + { + ue_v(stream, &(sliceHdr->reordering_of_pic_nums_idc_l0[i])); + if (sliceHdr->reordering_of_pic_nums_idc_l0[i] == 0 || + sliceHdr->reordering_of_pic_nums_idc_l0[i] == 1) + { + ue_v(stream, &(sliceHdr->abs_diff_pic_num_minus1_l0[i])); + if (sliceHdr->reordering_of_pic_nums_idc_l0[i] == 0 && + sliceHdr->abs_diff_pic_num_minus1_l0[i] > video->MaxPicNum / 2 - 1) + { + return AVCDEC_FAIL; /* out of range */ + } + if (sliceHdr->reordering_of_pic_nums_idc_l0[i] == 1 && + sliceHdr->abs_diff_pic_num_minus1_l0[i] > video->MaxPicNum / 2 - 2) + { + return AVCDEC_FAIL; /* out of range */ + } + } + else if (sliceHdr->reordering_of_pic_nums_idc_l0[i] == 2) + { + ue_v(stream, &(sliceHdr->long_term_pic_num_l0[i])); + } + i++; + } + while (sliceHdr->reordering_of_pic_nums_idc_l0[i-1] != 3 + && i <= (int)sliceHdr->num_ref_idx_l0_active_minus1 + 1) ; + } + } + return AVCDEC_SUCCESS; +} + +/** see subclause 7.4.3.3 */ +AVCDec_Status dec_ref_pic_marking(AVCCommonObj *video, AVCDecBitstream *stream, AVCSliceHeader *sliceHdr) +{ + int i; + if (video->nal_unit_type == AVC_NALTYPE_IDR) + { + BitstreamRead1Bit(stream, &(sliceHdr->no_output_of_prior_pics_flag)); + BitstreamRead1Bit(stream, &(sliceHdr->long_term_reference_flag)); + if (sliceHdr->long_term_reference_flag == 0) /* used for short-term */ + { + video->MaxLongTermFrameIdx = -1; /* no long-term frame indx */ + } + else /* used for long-term */ + { + video->MaxLongTermFrameIdx = 0; + video->LongTermFrameIdx = 0; + } + } + else + { + BitstreamRead1Bit(stream, &(sliceHdr->adaptive_ref_pic_marking_mode_flag)); + if (sliceHdr->adaptive_ref_pic_marking_mode_flag) + { + i = 0; + do + { + ue_v(stream, &(sliceHdr->memory_management_control_operation[i])); + if (sliceHdr->memory_management_control_operation[i] == 1 || + sliceHdr->memory_management_control_operation[i] == 3) + { + ue_v(stream, &(sliceHdr->difference_of_pic_nums_minus1[i])); + } + if (sliceHdr->memory_management_control_operation[i] == 2) + { + ue_v(stream, &(sliceHdr->long_term_pic_num[i])); + } + if (sliceHdr->memory_management_control_operation[i] == 3 || + sliceHdr->memory_management_control_operation[i] == 6) + { + ue_v(stream, &(sliceHdr->long_term_frame_idx[i])); + } + if (sliceHdr->memory_management_control_operation[i] == 4) + { + ue_v(stream, &(sliceHdr->max_long_term_frame_idx_plus1[i])); + } + i++; + } + while (sliceHdr->memory_management_control_operation[i-1] != 0 && i < MAX_DEC_REF_PIC_MARKING); + if (i >= MAX_DEC_REF_PIC_MARKING) + { + return AVCDEC_FAIL; /* we're screwed!!, not enough memory */ + } + } + } + + return AVCDEC_SUCCESS; +} + +/* see subclause 8.2.1 Decoding process for picture order count. */ +AVCDec_Status DecodePOC(AVCCommonObj *video) +{ + AVCSeqParamSet *currSPS = video->currSeqParams; + AVCSliceHeader *sliceHdr = video->sliceHdr; + int i; + + switch (currSPS->pic_order_cnt_type) + { + case 0: /* POC MODE 0 , subclause 8.2.1.1 */ + if (video->nal_unit_type == AVC_NALTYPE_IDR) + { + video->prevPicOrderCntMsb = 0; + video->prevPicOrderCntLsb = 0; + } + + /* Calculate the MSBs of current picture */ + if (sliceHdr->pic_order_cnt_lsb < video->prevPicOrderCntLsb && + (video->prevPicOrderCntLsb - sliceHdr->pic_order_cnt_lsb) >= (video->MaxPicOrderCntLsb / 2)) + video->PicOrderCntMsb = video->prevPicOrderCntMsb + video->MaxPicOrderCntLsb; + else if (sliceHdr->pic_order_cnt_lsb > video->prevPicOrderCntLsb && + (sliceHdr->pic_order_cnt_lsb - video->prevPicOrderCntLsb) > (video->MaxPicOrderCntLsb / 2)) + video->PicOrderCntMsb = video->prevPicOrderCntMsb - video->MaxPicOrderCntLsb; + else + video->PicOrderCntMsb = video->prevPicOrderCntMsb; + + /* JVT-I010 page 81 is different from JM7.3 */ + + + video->PicOrderCnt = video->TopFieldOrderCnt = video->PicOrderCntMsb + sliceHdr->pic_order_cnt_lsb; + video->BottomFieldOrderCnt = video->TopFieldOrderCnt + sliceHdr->delta_pic_order_cnt_bottom; + + break; + + + case 1: /* POC MODE 1, subclause 8.2.1.2 */ + /* calculate FrameNumOffset */ + if (video->nal_unit_type == AVC_NALTYPE_IDR) + { + video->prevFrameNumOffset = 0; + video->FrameNumOffset = 0; + } + else if (video->prevFrameNum > sliceHdr->frame_num) + { + video->FrameNumOffset = video->prevFrameNumOffset + video->MaxFrameNum; + } + else + { + video->FrameNumOffset = video->prevFrameNumOffset; + } + /* calculate absFrameNum */ + if (currSPS->num_ref_frames_in_pic_order_cnt_cycle) + { + video->absFrameNum = video->FrameNumOffset + sliceHdr->frame_num; + } + else + { + video->absFrameNum = 0; + } + + if (video->absFrameNum > 0 && video->nal_ref_idc == 0) + { + video->absFrameNum--; + } + + /* derive picOrderCntCycleCnt and frameNumInPicOrderCntCycle */ + if (video->absFrameNum > 0) + { + video->picOrderCntCycleCnt = (video->absFrameNum - 1) / currSPS->num_ref_frames_in_pic_order_cnt_cycle; + video->frameNumInPicOrderCntCycle = (video->absFrameNum - 1) % currSPS->num_ref_frames_in_pic_order_cnt_cycle; + } + /* derive expectedDeltaPerPicOrderCntCycle */ + video->expectedDeltaPerPicOrderCntCycle = 0; + for (i = 0; i < (int)currSPS->num_ref_frames_in_pic_order_cnt_cycle; i++) + { + video->expectedDeltaPerPicOrderCntCycle += currSPS->offset_for_ref_frame[i]; + } + /* derive expectedPicOrderCnt */ + if (video->absFrameNum) + { + video->expectedPicOrderCnt = video->picOrderCntCycleCnt * video->expectedDeltaPerPicOrderCntCycle; + for (i = 0; i <= video->frameNumInPicOrderCntCycle; i++) + { + video->expectedPicOrderCnt += currSPS->offset_for_ref_frame[i]; + } + } + else + { + video->expectedPicOrderCnt = 0; + } + + if (video->nal_ref_idc == 0) + { + video->expectedPicOrderCnt += currSPS->offset_for_non_ref_pic; + } + /* derive TopFieldOrderCnt and BottomFieldOrderCnt */ + + video->TopFieldOrderCnt = video->expectedPicOrderCnt + sliceHdr->delta_pic_order_cnt[0]; + video->BottomFieldOrderCnt = video->TopFieldOrderCnt + currSPS->offset_for_top_to_bottom_field + sliceHdr->delta_pic_order_cnt[1]; + + video->PicOrderCnt = AVC_MIN(video->TopFieldOrderCnt, video->BottomFieldOrderCnt); + + + break; + + + case 2: /* POC MODE 2, subclause 8.2.1.3 */ + if (video->nal_unit_type == AVC_NALTYPE_IDR) + { + video->FrameNumOffset = 0; + } + else if (video->prevFrameNum > sliceHdr->frame_num) + { + video->FrameNumOffset = video->prevFrameNumOffset + video->MaxFrameNum; + } + else + { + video->FrameNumOffset = video->prevFrameNumOffset; + } + /* derive tempPicOrderCnt, we just use PicOrderCnt */ + if (video->nal_unit_type == AVC_NALTYPE_IDR) + { + video->PicOrderCnt = 0; + } + else if (video->nal_ref_idc == 0) + { + video->PicOrderCnt = 2 * (video->FrameNumOffset + sliceHdr->frame_num) - 1; + } + else + { + video->PicOrderCnt = 2 * (video->FrameNumOffset + sliceHdr->frame_num); + } + video->TopFieldOrderCnt = video->BottomFieldOrderCnt = video->PicOrderCnt; + break; + default: + return AVCDEC_FAIL; + } + + return AVCDEC_SUCCESS; +} + + +AVCDec_Status DecodeSEI(AVCDecObject *decvid, AVCDecBitstream *stream) +{ + OSCL_UNUSED_ARG(decvid); + OSCL_UNUSED_ARG(stream); + return AVCDEC_SUCCESS; +} + +AVCDec_Status sei_payload(AVCDecObject *decvid, AVCDecBitstream *stream, uint payloadType, uint payloadSize) +{ + AVCDec_Status status = AVCDEC_SUCCESS; + uint i; + switch (payloadType) + { + case 0: + /* buffering period SEI */ + status = buffering_period(decvid, stream); + break; + case 1: + /* picture timing SEI */ + status = pic_timing(decvid, stream); + break; + case 2: + + case 3: + + case 4: + + case 5: + + case 8: + + case 9: + + case 10: + + case 11: + + case 12: + + case 13: + + case 14: + + case 15: + + case 16: + + case 17: + for (i = 0; i < payloadSize; i++) + { + BitstreamFlushBits(stream, 8); + } + break; + case 6: + /* recovery point SEI */ + status = recovery_point(decvid, stream); + break; + case 7: + /* decoded reference picture marking repetition SEI */ + status = dec_ref_pic_marking_repetition(decvid, stream); + break; + + case 18: + /* motion-constrained slice group set SEI */ + status = motion_constrained_slice_group_set(decvid, stream); + break; + default: + /* reserved_sei_message */ + for (i = 0; i < payloadSize; i++) + { + BitstreamFlushBits(stream, 8); + } + break; + } + BitstreamByteAlign(stream); + return status; +} + +AVCDec_Status buffering_period(AVCDecObject *decvid, AVCDecBitstream *stream) +{ + AVCSeqParamSet *currSPS; + uint seq_parameter_set_id; + uint temp; + uint i; + ue_v(stream, &seq_parameter_set_id); + if (seq_parameter_set_id > 31) + { + return AVCDEC_FAIL; + } + +// decvid->common->seq_parameter_set_id = seq_parameter_set_id; + + currSPS = decvid->seqParams[seq_parameter_set_id]; + if (currSPS->vui_parameters.nal_hrd_parameters_present_flag) + { + for (i = 0; i <= currSPS->vui_parameters.nal_hrd_parameters.cpb_cnt_minus1; i++) + { + /* initial_cpb_removal_delay[i] */ + BitstreamReadBits(stream, currSPS->vui_parameters.nal_hrd_parameters.cpb_removal_delay_length_minus1 + 1, &temp); + /*initial _cpb_removal_delay_offset[i] */ + BitstreamReadBits(stream, currSPS->vui_parameters.nal_hrd_parameters.cpb_removal_delay_length_minus1 + 1, &temp); + } + } + + if (currSPS->vui_parameters.vcl_hrd_parameters_present_flag) + { + for (i = 0; i <= currSPS->vui_parameters.vcl_hrd_parameters.cpb_cnt_minus1; i++) + { + /* initial_cpb_removal_delay[i] */ + BitstreamReadBits(stream, currSPS->vui_parameters.vcl_hrd_parameters.cpb_removal_delay_length_minus1 + 1, &temp); + /*initial _cpb_removal_delay_offset[i] */ + BitstreamReadBits(stream, currSPS->vui_parameters.vcl_hrd_parameters.cpb_removal_delay_length_minus1 + 1, &temp); + } + } + + return AVCDEC_SUCCESS; +} +AVCDec_Status pic_timing(AVCDecObject *decvid, AVCDecBitstream *stream) +{ + AVCSeqParamSet *currSPS; + uint temp, NumClockTs = 0, time_offset_length = 24, full_timestamp_flag; + uint i; + + currSPS = decvid->seqParams[decvid->common->seq_parameter_set_id]; + + if (currSPS->vui_parameters.nal_hrd_parameters_present_flag) + { + BitstreamReadBits(stream, currSPS->vui_parameters.nal_hrd_parameters.cpb_removal_delay_length_minus1 + 1, &temp); + BitstreamReadBits(stream, currSPS->vui_parameters.nal_hrd_parameters.dpb_output_delay_length_minus1 + 1, &temp); + time_offset_length = currSPS->vui_parameters.nal_hrd_parameters.time_offset_length; + } + else if (currSPS->vui_parameters.vcl_hrd_parameters_present_flag) + { + BitstreamReadBits(stream, currSPS->vui_parameters.vcl_hrd_parameters.cpb_removal_delay_length_minus1 + 1, &temp); + BitstreamReadBits(stream, currSPS->vui_parameters.vcl_hrd_parameters.dpb_output_delay_length_minus1 + 1, &temp); + time_offset_length = currSPS->vui_parameters.vcl_hrd_parameters.time_offset_length; + } + + if (currSPS->vui_parameters.pic_struct_present_flag) + { + /* pic_struct */ + BitstreamReadBits(stream, 4, &temp); + + switch (temp) + { + case 0: + case 1: + case 2: + NumClockTs = 1; + break; + case 3: + case 4: + case 7: + NumClockTs = 2; + break; + case 5: + case 6: + case 8: + NumClockTs = 3; + break; + default: + NumClockTs = 0; + break; + } + + for (i = 0; i < NumClockTs; i++) + { + /* clock_timestamp_flag[i] */ + BitstreamRead1Bit(stream, &temp); + if (temp) + { + /* ct_type */ + BitstreamReadBits(stream, 2, &temp); + /* nuit_field_based_flag */ + BitstreamRead1Bit(stream, &temp); + /* counting_type */ + BitstreamReadBits(stream, 5, &temp); + /* full_timestamp_flag */ + BitstreamRead1Bit(stream, &temp); + full_timestamp_flag = temp; + /* discontinuity_flag */ + BitstreamRead1Bit(stream, &temp); + /* cnt_dropped_flag */ + BitstreamRead1Bit(stream, &temp); + /* n_frames */ + BitstreamReadBits(stream, 8, &temp); + + + if (full_timestamp_flag) + { + /* seconds_value */ + BitstreamReadBits(stream, 6, &temp); + /* minutes_value */ + BitstreamReadBits(stream, 6, &temp); + /* hours_value */ + BitstreamReadBits(stream, 5, &temp); + } + else + { + /* seconds_flag */ + BitstreamRead1Bit(stream, &temp); + if (temp) + { + /* seconds_value */ + BitstreamReadBits(stream, 6, &temp); + /* minutes_flag */ + BitstreamRead1Bit(stream, &temp); + if (temp) + { + /* minutes_value */ + BitstreamReadBits(stream, 6, &temp); + + /* hourss_flag */ + BitstreamRead1Bit(stream, &temp); + + if (temp) + { + /* hours_value */ + BitstreamReadBits(stream, 5, &temp); + } + + } + } + } + + if (time_offset_length) + { + /* time_offset */ + BitstreamReadBits(stream, time_offset_length, &temp); + } + else + { + /* time_offset */ + temp = 0; + } + } + } + } + return AVCDEC_SUCCESS; +} +AVCDec_Status recovery_point(AVCDecObject *decvid, AVCDecBitstream *stream) +{ + OSCL_UNUSED_ARG(decvid); + uint temp; + /* recover_frame_cnt */ + ue_v(stream, &temp); + /* exact_match_flag */ + BitstreamRead1Bit(stream, &temp); + /* broken_link_flag */ + BitstreamRead1Bit(stream, &temp); + /* changing slic_group_idc */ + BitstreamReadBits(stream, 2, &temp); + return AVCDEC_SUCCESS; +} +AVCDec_Status dec_ref_pic_marking_repetition(AVCDecObject *decvid, AVCDecBitstream *stream) +{ + AVCSeqParamSet *currSPS; + uint temp; + currSPS = decvid->seqParams[decvid->common->seq_parameter_set_id]; + /* original_idr_flag */ + BitstreamRead1Bit(stream, &temp); + /* original_frame_num */ + ue_v(stream, &temp); + if (currSPS->frame_mbs_only_flag == 0) + { + /* original_field_pic_flag */ + BitstreamRead1Bit(stream, &temp); + if (temp) + { + /* original_bottom_field_flag */ + BitstreamRead1Bit(stream, &temp); + } + } + + /* dec_ref_pic_marking(video,stream,sliceHdr); */ + + + return AVCDEC_SUCCESS; +} +AVCDec_Status motion_constrained_slice_group_set(AVCDecObject *decvid, AVCDecBitstream *stream) +{ + OSCL_UNUSED_ARG(decvid); + uint temp, i, numBits; + /* num_slice_groups_in_set_minus1 */ + ue_v(stream, &temp); + + numBits = 0;/* ceil(log2(num_slice_groups_minus1+1)) bits */ + i = temp; + while (i > 0) + { + numBits++; + i >>= 1; + } + for (i = 0; i <= temp; i++) + { + /* slice_group_id */ + BitstreamReadBits(stream, numBits, &temp); + } + /* exact_sample_value_match_flag */ + BitstreamRead1Bit(stream, &temp); + /* pan_scan_rect_flag */ + BitstreamRead1Bit(stream, &temp); + if (temp) + { + /* pan_scan_rect_id */ + ue_v(stream, &temp); + } + + return AVCDEC_SUCCESS; +} + diff --git a/media/libstagefright/codecs/avc/dec/src/itrans.cpp b/media/libstagefright/codecs/avc/dec/src/itrans.cpp new file mode 100644 index 0000000..02c550d --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/src/itrans.cpp @@ -0,0 +1,307 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 "avclib_common.h" + +/* input are in the first 16 elements of block, + output must be in the location specified in Figure 8-6. */ +/* subclause 8.5.6 */ +void Intra16DCTrans(int16 *block, int Qq, int Rq) +{ + int m0, m1, m2, m3; + int j, offset; + int16 *inout; + int scale = dequant_coefres[Rq][0]; + + inout = block; + for (j = 0; j < 4; j++) + { + m0 = inout[0] + inout[4]; + m1 = inout[0] - inout[4]; + m2 = inout[8] + inout[12]; + m3 = inout[8] - inout[12]; + + + inout[0] = m0 + m2; + inout[4] = m0 - m2; + inout[8] = m1 - m3; + inout[12] = m1 + m3; + inout += 64; + } + + inout = block; + + if (Qq >= 2) /* this way should be faster than JM */ + { /* they use (((m4*scale)<<(QPy/6))+2)>>2 for both cases. */ + Qq -= 2; + for (j = 0; j < 4; j++) + { + m0 = inout[0] + inout[64]; + m1 = inout[0] - inout[64]; + m2 = inout[128] + inout[192]; + m3 = inout[128] - inout[192]; + + inout[0] = ((m0 + m2) * scale) << Qq; + inout[64] = ((m0 - m2) * scale) << Qq; + inout[128] = ((m1 - m3) * scale) << Qq; + inout[192] = ((m1 + m3) * scale) << Qq; + inout += 4; + } + } + else + { + Qq = 2 - Qq; + offset = 1 << (Qq - 1); + + for (j = 0; j < 4; j++) + { + m0 = inout[0] + inout[64]; + m1 = inout[0] - inout[64]; + m2 = inout[128] + inout[192]; + m3 = inout[128] - inout[192]; + + inout[0] = (((m0 + m2) * scale + offset) >> Qq); + inout[64] = (((m0 - m2) * scale + offset) >> Qq); + inout[128] = (((m1 - m3) * scale + offset) >> Qq); + inout[192] = (((m1 + m3) * scale + offset) >> Qq); + inout += 4; + } + } + + return ; +} + +/* see subclase 8.5.8 */ +void itrans(int16 *block, uint8 *pred, uint8 *cur, int width) +{ + int e0, e1, e2, e3; /* note, at every step of the calculation, these values */ + /* shall never exceed 16bit sign value, but we don't check */ + int i; /* to save the cycles. */ + int16 *inout; + + inout = block; + + for (i = 4; i > 0; i--) + { + e0 = inout[0] + inout[2]; + e1 = inout[0] - inout[2]; + e2 = (inout[1] >> 1) - inout[3]; + e3 = inout[1] + (inout[3] >> 1); + + inout[0] = e0 + e3; + inout[1] = e1 + e2; + inout[2] = e1 - e2; + inout[3] = e0 - e3; + + inout += 16; + } + + for (i = 4; i > 0; i--) + { + e0 = block[0] + block[32]; + e1 = block[0] - block[32]; + e2 = (block[16] >> 1) - block[48]; + e3 = block[16] + (block[48] >> 1); + + e0 += e3; + e3 = (e0 - (e3 << 1)); /* e0-e3 */ + e1 += e2; + e2 = (e1 - (e2 << 1)); /* e1-e2 */ + e0 += 32; + e1 += 32; + e2 += 32; + e3 += 32; +#ifdef USE_PRED_BLOCK + e0 = pred[0] + (e0 >> 6); + if ((uint)e0 > 0xFF) e0 = 0xFF & (~(e0 >> 31)); /* clip */ + e1 = pred[20] + (e1 >> 6); + if ((uint)e1 > 0xFF) e1 = 0xFF & (~(e1 >> 31)); /* clip */ + e2 = pred[40] + (e2 >> 6); + if ((uint)e2 > 0xFF) e2 = 0xFF & (~(e2 >> 31)); /* clip */ + e3 = pred[60] + (e3 >> 6); + if ((uint)e3 > 0xFF) e3 = 0xFF & (~(e3 >> 31)); /* clip */ + *cur = e0; + *(cur += width) = e1; + *(cur += width) = e2; + cur[width] = e3; + cur -= (width << 1); + cur++; + pred++; +#else + OSCL_UNUSED_ARG(pred); + + e0 = *cur + (e0 >> 6); + if ((uint)e0 > 0xFF) e0 = 0xFF & (~(e0 >> 31)); /* clip */ + *cur = e0; + e1 = *(cur += width) + (e1 >> 6); + if ((uint)e1 > 0xFF) e1 = 0xFF & (~(e1 >> 31)); /* clip */ + *cur = e1; + e2 = *(cur += width) + (e2 >> 6); + if ((uint)e2 > 0xFF) e2 = 0xFF & (~(e2 >> 31)); /* clip */ + *cur = e2; + e3 = cur[width] + (e3 >> 6); + if ((uint)e3 > 0xFF) e3 = 0xFF & (~(e3 >> 31)); /* clip */ + cur[width] = e3; + cur -= (width << 1); + cur++; +#endif + block++; + } + + return ; +} + +/* see subclase 8.5.8 */ +void ictrans(int16 *block, uint8 *pred, uint8 *cur, int width) +{ + int e0, e1, e2, e3; /* note, at every step of the calculation, these values */ + /* shall never exceed 16bit sign value, but we don't check */ + int i; /* to save the cycles. */ + int16 *inout; + + inout = block; + + for (i = 4; i > 0; i--) + { + e0 = inout[0] + inout[2]; + e1 = inout[0] - inout[2]; + e2 = (inout[1] >> 1) - inout[3]; + e3 = inout[1] + (inout[3] >> 1); + + inout[0] = e0 + e3; + inout[1] = e1 + e2; + inout[2] = e1 - e2; + inout[3] = e0 - e3; + + inout += 16; + } + + for (i = 4; i > 0; i--) + { + e0 = block[0] + block[32]; + e1 = block[0] - block[32]; + e2 = (block[16] >> 1) - block[48]; + e3 = block[16] + (block[48] >> 1); + + e0 += e3; + e3 = (e0 - (e3 << 1)); /* e0-e3 */ + e1 += e2; + e2 = (e1 - (e2 << 1)); /* e1-e2 */ + e0 += 32; + e1 += 32; + e2 += 32; + e3 += 32; +#ifdef USE_PRED_BLOCK + e0 = pred[0] + (e0 >> 6); + if ((uint)e0 > 0xFF) e0 = 0xFF & (~(e0 >> 31)); /* clip */ + e1 = pred[12] + (e1 >> 6); + if ((uint)e1 > 0xFF) e1 = 0xFF & (~(e1 >> 31)); /* clip */ + e2 = pred[24] + (e2 >> 6); + if ((uint)e2 > 0xFF) e2 = 0xFF & (~(e2 >> 31)); /* clip */ + e3 = pred[36] + (e3 >> 6); + if ((uint)e3 > 0xFF) e3 = 0xFF & (~(e3 >> 31)); /* clip */ + *cur = e0; + *(cur += width) = e1; + *(cur += width) = e2; + cur[width] = e3; + cur -= (width << 1); + cur++; + pred++; +#else + OSCL_UNUSED_ARG(pred); + + e0 = *cur + (e0 >> 6); + if ((uint)e0 > 0xFF) e0 = 0xFF & (~(e0 >> 31)); /* clip */ + *cur = e0; + e1 = *(cur += width) + (e1 >> 6); + if ((uint)e1 > 0xFF) e1 = 0xFF & (~(e1 >> 31)); /* clip */ + *cur = e1; + e2 = *(cur += width) + (e2 >> 6); + if ((uint)e2 > 0xFF) e2 = 0xFF & (~(e2 >> 31)); /* clip */ + *cur = e2; + e3 = cur[width] + (e3 >> 6); + if ((uint)e3 > 0xFF) e3 = 0xFF & (~(e3 >> 31)); /* clip */ + cur[width] = e3; + cur -= (width << 1); + cur++; +#endif + block++; + } + + return ; +} + +/* see subclause 8.5.7 */ +void ChromaDCTrans(int16 *block, int Qq, int Rq) +{ + int c00, c01, c10, c11; + int f0, f1, f2, f3; + int scale = dequant_coefres[Rq][0]; + + c00 = block[0] + block[4]; + c01 = block[0] - block[4]; + c10 = block[64] + block[68]; + c11 = block[64] - block[68]; + + f0 = c00 + c10; + f1 = c01 + c11; + f2 = c00 - c10; + f3 = c01 - c11; + + if (Qq >= 1) + { + Qq -= 1; + block[0] = (f0 * scale) << Qq; + block[4] = (f1 * scale) << Qq; + block[64] = (f2 * scale) << Qq; + block[68] = (f3 * scale) << Qq; + } + else + { + block[0] = (f0 * scale) >> 1; + block[4] = (f1 * scale) >> 1; + block[64] = (f2 * scale) >> 1; + block[68] = (f3 * scale) >> 1; + } + + return ; +} + + +void copy_block(uint8 *pred, uint8 *cur, int width, int pred_pitch) +{ + uint32 temp; + + temp = *((uint32*)pred); + pred += pred_pitch; + *((uint32*)cur) = temp; + cur += width; + temp = *((uint32*)pred); + pred += pred_pitch; + *((uint32*)cur) = temp; + cur += width; + temp = *((uint32*)pred); + pred += pred_pitch; + *((uint32*)cur) = temp; + cur += width; + temp = *((uint32*)pred); + *((uint32*)cur) = temp; + + return ; +} + + diff --git a/media/libstagefright/codecs/avc/dec/src/pred_inter.cpp b/media/libstagefright/codecs/avc/dec/src/pred_inter.cpp new file mode 100644 index 0000000..ba36c37 --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/src/pred_inter.cpp @@ -0,0 +1,2329 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 "avcdec_lib.h" + + +#define CLIP_RESULT(x) if((uint)x > 0xFF){ \ + x = 0xFF & (~(x>>31));} + +/* (blkwidth << 2) + (dy << 1) + dx */ +static void (*const ChromaMC_SIMD[8])(uint8 *, int , int , int , uint8 *, int, int , int) = +{ + &ChromaFullMC_SIMD, + &ChromaHorizontalMC_SIMD, + &ChromaVerticalMC_SIMD, + &ChromaDiagonalMC_SIMD, + &ChromaFullMC_SIMD, + &ChromaHorizontalMC2_SIMD, + &ChromaVerticalMC2_SIMD, + &ChromaDiagonalMC2_SIMD +}; +/* Perform motion prediction and compensation with residue if exist. */ +void InterMBPrediction(AVCCommonObj *video) +{ + AVCMacroblock *currMB = video->currMB; + AVCPictureData *currPic = video->currPic; + int mbPartIdx, subMbPartIdx; + int ref_idx; + int offset_MbPart_indx = 0; + int16 *mv; + uint32 x_pos, y_pos; + uint8 *curL, *curCb, *curCr; + uint8 *ref_l, *ref_Cb, *ref_Cr; + uint8 *predBlock, *predCb, *predCr; + int block_x, block_y, offset_x, offset_y, offsetP, offset; + int x_position = (video->mb_x << 4); + int y_position = (video->mb_y << 4); + int MbHeight, MbWidth, mbPartIdx_X, mbPartIdx_Y, offset_indx; + int picWidth = currPic->pitch; + int picHeight = currPic->height; + int16 *dataBlock; + uint32 cbp4x4; + uint32 tmp_word; + + tmp_word = y_position * picWidth; + curL = currPic->Sl + tmp_word + x_position; + offset = (tmp_word >> 2) + (x_position >> 1); + curCb = currPic->Scb + offset; + curCr = currPic->Scr + offset; + +#ifdef USE_PRED_BLOCK + predBlock = video->pred + 84; + predCb = video->pred + 452; + predCr = video->pred + 596; +#else + predBlock = curL; + predCb = curCb; + predCr = curCr; +#endif + + GetMotionVectorPredictor(video, false); + + for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++) + { + MbHeight = currMB->SubMbPartHeight[mbPartIdx]; + MbWidth = currMB->SubMbPartWidth[mbPartIdx]; + mbPartIdx_X = ((mbPartIdx + offset_MbPart_indx) & 1); + mbPartIdx_Y = (mbPartIdx + offset_MbPart_indx) >> 1; + ref_idx = currMB->ref_idx_L0[(mbPartIdx_Y << 1) + mbPartIdx_X]; + offset_indx = 0; + + ref_l = video->RefPicList0[ref_idx]->Sl; + ref_Cb = video->RefPicList0[ref_idx]->Scb; + ref_Cr = video->RefPicList0[ref_idx]->Scr; + + for (subMbPartIdx = 0; subMbPartIdx < currMB->NumSubMbPart[mbPartIdx]; subMbPartIdx++) + { + block_x = (mbPartIdx_X << 1) + ((subMbPartIdx + offset_indx) & 1); // check this + block_y = (mbPartIdx_Y << 1) + (((subMbPartIdx + offset_indx) >> 1) & 1); + mv = (int16*)(currMB->mvL0 + block_x + (block_y << 2)); + offset_x = x_position + (block_x << 2); + offset_y = y_position + (block_y << 2); + x_pos = (offset_x << 2) + *mv++; /*quarter pel */ + y_pos = (offset_y << 2) + *mv; /*quarter pel */ + + //offset = offset_y * currPic->width; + //offsetC = (offset >> 2) + (offset_x >> 1); +#ifdef USE_PRED_BLOCK + offsetP = (block_y * 80) + (block_x << 2); + LumaMotionComp(ref_l, picWidth, picHeight, x_pos, y_pos, + /*comp_Sl + offset + offset_x,*/ + predBlock + offsetP, 20, MbWidth, MbHeight); +#else + offsetP = (block_y << 2) * picWidth + (block_x << 2); + LumaMotionComp(ref_l, picWidth, picHeight, x_pos, y_pos, + /*comp_Sl + offset + offset_x,*/ + predBlock + offsetP, picWidth, MbWidth, MbHeight); +#endif + +#ifdef USE_PRED_BLOCK + offsetP = (block_y * 24) + (block_x << 1); + ChromaMotionComp(ref_Cb, picWidth >> 1, picHeight >> 1, x_pos, y_pos, + /*comp_Scb + offsetC,*/ + predCb + offsetP, 12, MbWidth >> 1, MbHeight >> 1); + ChromaMotionComp(ref_Cr, picWidth >> 1, picHeight >> 1, x_pos, y_pos, + /*comp_Scr + offsetC,*/ + predCr + offsetP, 12, MbWidth >> 1, MbHeight >> 1); +#else + offsetP = (block_y * picWidth) + (block_x << 1); + ChromaMotionComp(ref_Cb, picWidth >> 1, picHeight >> 1, x_pos, y_pos, + /*comp_Scb + offsetC,*/ + predCb + offsetP, picWidth >> 1, MbWidth >> 1, MbHeight >> 1); + ChromaMotionComp(ref_Cr, picWidth >> 1, picHeight >> 1, x_pos, y_pos, + /*comp_Scr + offsetC,*/ + predCr + offsetP, picWidth >> 1, MbWidth >> 1, MbHeight >> 1); +#endif + + offset_indx = currMB->SubMbPartWidth[mbPartIdx] >> 3; + } + offset_MbPart_indx = currMB->MbPartWidth >> 4; + } + + /* used in decoder, used to be if(!encFlag) */ + + /* transform in raster scan order */ + dataBlock = video->block; + cbp4x4 = video->cbp4x4; + /* luma */ + for (block_y = 4; block_y > 0; block_y--) + { + for (block_x = 4; block_x > 0; block_x--) + { +#ifdef USE_PRED_BLOCK + if (cbp4x4&1) + { + itrans(dataBlock, predBlock, predBlock, 20); + } +#else + if (cbp4x4&1) + { + itrans(dataBlock, curL, curL, picWidth); + } +#endif + cbp4x4 >>= 1; + dataBlock += 4; +#ifdef USE_PRED_BLOCK + predBlock += 4; +#else + curL += 4; +#endif + } + dataBlock += 48; +#ifdef USE_PRED_BLOCK + predBlock += 64; +#else + curL += ((picWidth << 2) - 16); +#endif + } + + /* chroma */ + picWidth = (picWidth >> 1); + for (block_y = 2; block_y > 0; block_y--) + { + for (block_x = 2; block_x > 0; block_x--) + { +#ifdef USE_PRED_BLOCK + if (cbp4x4&1) + { + ictrans(dataBlock, predCb, predCb, 12); + } +#else + if (cbp4x4&1) + { + ictrans(dataBlock, curCb, curCb, picWidth); + } +#endif + cbp4x4 >>= 1; + dataBlock += 4; +#ifdef USE_PRED_BLOCK + predCb += 4; +#else + curCb += 4; +#endif + } + for (block_x = 2; block_x > 0; block_x--) + { +#ifdef USE_PRED_BLOCK + if (cbp4x4&1) + { + ictrans(dataBlock, predCr, predCr, 12); + } +#else + if (cbp4x4&1) + { + ictrans(dataBlock, curCr, curCr, picWidth); + } +#endif + cbp4x4 >>= 1; + dataBlock += 4; +#ifdef USE_PRED_BLOCK + predCr += 4; +#else + curCr += 4; +#endif + } + dataBlock += 48; +#ifdef USE_PRED_BLOCK + predCb += 40; + predCr += 40; +#else + curCb += ((picWidth << 2) - 8); + curCr += ((picWidth << 2) - 8); +#endif + } + +#ifdef MB_BASED_DEBLOCK + SaveNeighborForIntraPred(video, offset); +#endif + + return ; +} + + +/* preform the actual motion comp here */ +void LumaMotionComp(uint8 *ref, int picwidth, int picheight, + int x_pos, int y_pos, + uint8 *pred, int pred_pitch, + int blkwidth, int blkheight) +{ + int dx, dy; + uint8 temp[24][24]; /* for padding, make the size multiple of 4 for packing */ + int temp2[21][21]; /* for intermediate results */ + uint8 *ref2; + + dx = x_pos & 3; + dy = y_pos & 3; + x_pos = x_pos >> 2; /* round it to full-pel resolution */ + y_pos = y_pos >> 2; + + /* perform actual motion compensation */ + if (dx == 0 && dy == 0) + { /* fullpel position *//* G */ + if (x_pos >= 0 && x_pos + blkwidth <= picwidth && y_pos >= 0 && y_pos + blkheight <= picheight) + { + ref += y_pos * picwidth + x_pos; + FullPelMC(ref, picwidth, pred, pred_pitch, blkwidth, blkheight); + } + else + { + CreatePad(ref, picwidth, picheight, x_pos, y_pos, &temp[0][0], blkwidth, blkheight); + FullPelMC(&temp[0][0], 24, pred, pred_pitch, blkwidth, blkheight); + } + + } /* other positions */ + else if (dy == 0) + { /* no vertical interpolation *//* a,b,c*/ + + if (x_pos - 2 >= 0 && x_pos + 3 + blkwidth <= picwidth && y_pos >= 0 && y_pos + blkheight <= picheight) + { + ref += y_pos * picwidth + x_pos; + + HorzInterp1MC(ref, picwidth, pred, pred_pitch, blkwidth, blkheight, dx); + } + else /* need padding */ + { + CreatePad(ref, picwidth, picheight, x_pos - 2, y_pos, &temp[0][0], blkwidth + 5, blkheight); + + HorzInterp1MC(&temp[0][2], 24, pred, pred_pitch, blkwidth, blkheight, dx); + } + } + else if (dx == 0) + { /*no horizontal interpolation *//* d,h,n */ + + if (x_pos >= 0 && x_pos + blkwidth <= picwidth && y_pos - 2 >= 0 && y_pos + 3 + blkheight <= picheight) + { + ref += y_pos * picwidth + x_pos; + + VertInterp1MC(ref, picwidth, pred, pred_pitch, blkwidth, blkheight, dy); + } + else /* need padding */ + { + CreatePad(ref, picwidth, picheight, x_pos, y_pos - 2, &temp[0][0], blkwidth, blkheight + 5); + + VertInterp1MC(&temp[2][0], 24, pred, pred_pitch, blkwidth, blkheight, dy); + } + } + else if (dy == 2) + { /* horizontal cross *//* i, j, k */ + + if (x_pos - 2 >= 0 && x_pos + 3 + blkwidth <= picwidth && y_pos - 2 >= 0 && y_pos + 3 + blkheight <= picheight) + { + ref += y_pos * picwidth + x_pos - 2; /* move to the left 2 pixels */ + + VertInterp2MC(ref, picwidth, &temp2[0][0], 21, blkwidth + 5, blkheight); + + HorzInterp2MC(&temp2[0][2], 21, pred, pred_pitch, blkwidth, blkheight, dx); + } + else /* need padding */ + { + CreatePad(ref, picwidth, picheight, x_pos - 2, y_pos - 2, &temp[0][0], blkwidth + 5, blkheight + 5); + + VertInterp2MC(&temp[2][0], 24, &temp2[0][0], 21, blkwidth + 5, blkheight); + + HorzInterp2MC(&temp2[0][2], 21, pred, pred_pitch, blkwidth, blkheight, dx); + } + } + else if (dx == 2) + { /* vertical cross */ /* f,q */ + + if (x_pos - 2 >= 0 && x_pos + 3 + blkwidth <= picwidth && y_pos - 2 >= 0 && y_pos + 3 + blkheight <= picheight) + { + ref += (y_pos - 2) * picwidth + x_pos; /* move to up 2 lines */ + + HorzInterp3MC(ref, picwidth, &temp2[0][0], 21, blkwidth, blkheight + 5); + VertInterp3MC(&temp2[2][0], 21, pred, pred_pitch, blkwidth, blkheight, dy); + } + else /* need padding */ + { + CreatePad(ref, picwidth, picheight, x_pos - 2, y_pos - 2, &temp[0][0], blkwidth + 5, blkheight + 5); + HorzInterp3MC(&temp[0][2], 24, &temp2[0][0], 21, blkwidth, blkheight + 5); + VertInterp3MC(&temp2[2][0], 21, pred, pred_pitch, blkwidth, blkheight, dy); + } + } + else + { /* diagonal *//* e,g,p,r */ + + if (x_pos - 2 >= 0 && x_pos + 3 + (dx / 2) + blkwidth <= picwidth && + y_pos - 2 >= 0 && y_pos + 3 + blkheight + (dy / 2) <= picheight) + { + ref2 = ref + (y_pos + (dy / 2)) * picwidth + x_pos; + + ref += (y_pos * picwidth) + x_pos + (dx / 2); + + DiagonalInterpMC(ref2, ref, picwidth, pred, pred_pitch, blkwidth, blkheight); + } + else /* need padding */ + { + CreatePad(ref, picwidth, picheight, x_pos - 2, y_pos - 2, &temp[0][0], blkwidth + 5 + (dx / 2), blkheight + 5 + (dy / 2)); + + ref2 = &temp[2 + (dy/2)][2]; + + ref = &temp[2][2 + (dx/2)]; + + DiagonalInterpMC(ref2, ref, 24, pred, pred_pitch, blkwidth, blkheight); + } + } + + return ; +} + +void CreateAlign(uint8 *ref, int picwidth, int y_pos, + uint8 *out, int blkwidth, int blkheight) +{ + int i, j; + int offset, out_offset; + uint32 prev_pix, result, pix1, pix2, pix4; + + out_offset = 24 - blkwidth; + + //switch(x_pos&0x3){ + switch (((uint32)ref)&0x3) + { + case 1: + ref += y_pos * picwidth; + offset = picwidth - blkwidth - 3; + for (j = 0; j < blkheight; j++) + { + pix1 = *ref++; + pix2 = *((uint16*)ref); + ref += 2; + result = (pix2 << 8) | pix1; + + for (i = 3; i < blkwidth; i += 4) + { + pix4 = *((uint32*)ref); + ref += 4; + prev_pix = (pix4 << 24) & 0xFF000000; /* mask out byte belong to previous word */ + result |= prev_pix; + *((uint32*)out) = result; /* write 4 bytes */ + out += 4; + result = pix4 >> 8; /* for the next loop */ + } + ref += offset; + out += out_offset; + } + break; + case 2: + ref += y_pos * picwidth; + offset = picwidth - blkwidth - 2; + for (j = 0; j < blkheight; j++) + { + result = *((uint16*)ref); + ref += 2; + for (i = 2; i < blkwidth; i += 4) + { + pix4 = *((uint32*)ref); + ref += 4; + prev_pix = (pix4 << 16) & 0xFFFF0000; /* mask out byte belong to previous word */ + result |= prev_pix; + *((uint32*)out) = result; /* write 4 bytes */ + out += 4; + result = pix4 >> 16; /* for the next loop */ + } + ref += offset; + out += out_offset; + } + break; + case 3: + ref += y_pos * picwidth; + offset = picwidth - blkwidth - 1; + for (j = 0; j < blkheight; j++) + { + result = *ref++; + for (i = 1; i < blkwidth; i += 4) + { + pix4 = *((uint32*)ref); + ref += 4; + prev_pix = (pix4 << 8) & 0xFFFFFF00; /* mask out byte belong to previous word */ + result |= prev_pix; + *((uint32*)out) = result; /* write 4 bytes */ + out += 4; + result = pix4 >> 24; /* for the next loop */ + } + ref += offset; + out += out_offset; + } + break; + } +} + +void CreatePad(uint8 *ref, int picwidth, int picheight, int x_pos, int y_pos, + uint8 *out, int blkwidth, int blkheight) +{ + int x_inc0, x_mid; + int y_inc, y_inc0, y_inc1, y_mid; + int i, j; + int offset; + + if (x_pos < 0) + { + x_inc0 = 0; /* increment for the first part */ + x_mid = ((blkwidth + x_pos > 0) ? -x_pos : blkwidth); /* stopping point */ + x_pos = 0; + } + else if (x_pos + blkwidth > picwidth) + { + x_inc0 = 1; /* increasing */ + x_mid = ((picwidth > x_pos) ? picwidth - x_pos - 1 : 0); /* clip negative to zero, encode fool proof! */ + } + else /* normal case */ + { + x_inc0 = 1; + x_mid = blkwidth; /* just one run */ + } + + + /* boundary for y_pos, taking the result from x_pos into account */ + if (y_pos < 0) + { + y_inc0 = (x_inc0 ? - x_mid : -blkwidth + x_mid); /* offset depending on x_inc1 and x_inc0 */ + y_inc1 = picwidth + y_inc0; + y_mid = ((blkheight + y_pos > 0) ? -y_pos : blkheight); /* clip to prevent memory corruption */ + y_pos = 0; + } + else if (y_pos + blkheight > picheight) + { + y_inc1 = (x_inc0 ? - x_mid : -blkwidth + x_mid); /* saturate */ + y_inc0 = picwidth + y_inc1; /* increasing */ + y_mid = ((picheight > y_pos) ? picheight - 1 - y_pos : 0); + } + else /* normal case */ + { + y_inc1 = (x_inc0 ? - x_mid : -blkwidth + x_mid); + y_inc0 = picwidth + y_inc1; + y_mid = blkheight; + } + + /* clip y_pos and x_pos */ + if (y_pos > picheight - 1) y_pos = picheight - 1; + if (x_pos > picwidth - 1) x_pos = picwidth - 1; + + ref += y_pos * picwidth + x_pos; + + y_inc = y_inc0; /* start with top half */ + + offset = 24 - blkwidth; /* to use in offset out */ + blkwidth -= x_mid; /* to use in the loop limit */ + + if (x_inc0 == 0) + { + for (j = 0; j < blkheight; j++) + { + if (j == y_mid) /* put a check here to reduce the code size (for unrolling the loop) */ + { + y_inc = y_inc1; /* switch to lower half */ + } + for (i = x_mid; i > 0; i--) /* first or third quarter */ + { + *out++ = *ref; + } + for (i = blkwidth; i > 0; i--) /* second or fourth quarter */ + { + *out++ = *ref++; + } + out += offset; + ref += y_inc; + } + } + else + { + for (j = 0; j < blkheight; j++) + { + if (j == y_mid) /* put a check here to reduce the code size (for unrolling the loop) */ + { + y_inc = y_inc1; /* switch to lower half */ + } + for (i = x_mid; i > 0; i--) /* first or third quarter */ + { + *out++ = *ref++; + } + for (i = blkwidth; i > 0; i--) /* second or fourth quarter */ + { + *out++ = *ref; + } + out += offset; + ref += y_inc; + } + } + + return ; +} + +void HorzInterp1MC(uint8 *in, int inpitch, uint8 *out, int outpitch, + int blkwidth, int blkheight, int dx) +{ + uint8 *p_ref; + uint32 *p_cur; + uint32 tmp, pkres; + int result, curr_offset, ref_offset; + int j; + int32 r0, r1, r2, r3, r4, r5; + int32 r13, r6; + + p_cur = (uint32*)out; /* assume it's word aligned */ + curr_offset = (outpitch - blkwidth) >> 2; + p_ref = in; + ref_offset = inpitch - blkwidth; + + if (dx&1) + { + dx = ((dx >> 1) ? -3 : -4); /* use in 3/4 pel */ + p_ref -= 2; + r13 = 0; + for (j = blkheight; j > 0; j--) + { + tmp = (uint32)(p_ref + blkwidth); + r0 = p_ref[0]; + r1 = p_ref[2]; + r0 |= (r1 << 16); /* 0,c,0,a */ + r1 = p_ref[1]; + r2 = p_ref[3]; + r1 |= (r2 << 16); /* 0,d,0,b */ + while ((uint32)p_ref < tmp) + { + r2 = *(p_ref += 4); /* move pointer to e */ + r3 = p_ref[2]; + r2 |= (r3 << 16); /* 0,g,0,e */ + r3 = p_ref[1]; + r4 = p_ref[3]; + r3 |= (r4 << 16); /* 0,h,0,f */ + + r4 = r0 + r3; /* c+h, a+f */ + r5 = r0 + r1; /* c+d, a+b */ + r6 = r2 + r3; /* g+h, e+f */ + r5 >>= 16; + r5 |= (r6 << 16); /* e+f, c+d */ + r4 += r5 * 20; /* c+20*e+20*f+h, a+20*c+20*d+f */ + r4 += 0x100010; /* +16, +16 */ + r5 = r1 + r2; /* d+g, b+e */ + r4 -= r5 * 5; /* c-5*d+20*e+20*f-5*g+h, a-5*b+20*c+20*d-5*e+f */ + r4 >>= 5; + r13 |= r4; /* check clipping */ + + r5 = p_ref[dx+2]; + r6 = p_ref[dx+4]; + r5 |= (r6 << 16); + r4 += r5; + r4 += 0x10001; + r4 = (r4 >> 1) & 0xFF00FF; + + r5 = p_ref[4]; /* i */ + r6 = (r5 << 16); + r5 = r6 | (r2 >> 16);/* 0,i,0,g */ + r5 += r1; /* d+i, b+g */ /* r5 not free */ + r1 >>= 16; + r1 |= (r3 << 16); /* 0,f,0,d */ /* r1 has changed */ + r1 += r2; /* f+g, d+e */ + r5 += 20 * r1; /* d+20f+20g+i, b+20d+20e+g */ + r0 >>= 16; + r0 |= (r2 << 16); /* 0,e,0,c */ /* r0 has changed */ + r0 += r3; /* e+h, c+f */ + r5 += 0x100010; /* 16,16 */ + r5 -= r0 * 5; /* d-5e+20f+20g-5h+i, b-5c+20d+20e-5f+g */ + r5 >>= 5; + r13 |= r5; /* check clipping */ + + r0 = p_ref[dx+3]; + r1 = p_ref[dx+5]; + r0 |= (r1 << 16); + r5 += r0; + r5 += 0x10001; + r5 = (r5 >> 1) & 0xFF00FF; + + r4 |= (r5 << 8); /* pack them together */ + *p_cur++ = r4; + r1 = r3; + r0 = r2; + } + p_cur += curr_offset; /* move to the next line */ + p_ref += ref_offset; /* ref_offset = inpitch-blkwidth; */ + + if (r13&0xFF000700) /* need clipping */ + { + /* move back to the beginning of the line */ + p_ref -= (ref_offset + blkwidth); /* input */ + p_cur -= (outpitch >> 2); + + tmp = (uint32)(p_ref + blkwidth); + for (; (uint32)p_ref < tmp;) + { + + r0 = *p_ref++; + r1 = *p_ref++; + r2 = *p_ref++; + r3 = *p_ref++; + r4 = *p_ref++; + /* first pixel */ + r5 = *p_ref++; + result = (r0 + r5); + r0 = (r1 + r4); + result -= (r0 * 5);//result -= r0; result -= (r0<<2); + r0 = (r2 + r3); + result += (r0 * 20);//result += (r0<<4); result += (r0<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + /* 3/4 pel, no need to clip */ + result = (result + p_ref[dx] + 1); + pkres = (result >> 1) ; + /* second pixel */ + r0 = *p_ref++; + result = (r1 + r0); + r1 = (r2 + r5); + result -= (r1 * 5);//result -= r1; result -= (r1<<2); + r1 = (r3 + r4); + result += (r1 * 20);//result += (r1<<4); result += (r1<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + /* 3/4 pel, no need to clip */ + result = (result + p_ref[dx] + 1); + result = (result >> 1); + pkres |= (result << 8); + /* third pixel */ + r1 = *p_ref++; + result = (r2 + r1); + r2 = (r3 + r0); + result -= (r2 * 5);//result -= r2; result -= (r2<<2); + r2 = (r4 + r5); + result += (r2 * 20);//result += (r2<<4); result += (r2<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + /* 3/4 pel, no need to clip */ + result = (result + p_ref[dx] + 1); + result = (result >> 1); + pkres |= (result << 16); + /* fourth pixel */ + r2 = *p_ref++; + result = (r3 + r2); + r3 = (r4 + r1); + result -= (r3 * 5);//result -= r3; result -= (r3<<2); + r3 = (r5 + r0); + result += (r3 * 20);//result += (r3<<4); result += (r3<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + /* 3/4 pel, no need to clip */ + result = (result + p_ref[dx] + 1); + result = (result >> 1); + pkres |= (result << 24); + *p_cur++ = pkres; /* write 4 pixels */ + p_ref -= 5; /* offset back to the middle of filter */ + } + p_cur += curr_offset; /* move to the next line */ + p_ref += ref_offset; /* move to the next line */ + } + } + } + else + { + p_ref -= 2; + r13 = 0; + for (j = blkheight; j > 0; j--) + { + tmp = (uint32)(p_ref + blkwidth); + r0 = p_ref[0]; + r1 = p_ref[2]; + r0 |= (r1 << 16); /* 0,c,0,a */ + r1 = p_ref[1]; + r2 = p_ref[3]; + r1 |= (r2 << 16); /* 0,d,0,b */ + while ((uint32)p_ref < tmp) + { + r2 = *(p_ref += 4); /* move pointer to e */ + r3 = p_ref[2]; + r2 |= (r3 << 16); /* 0,g,0,e */ + r3 = p_ref[1]; + r4 = p_ref[3]; + r3 |= (r4 << 16); /* 0,h,0,f */ + + r4 = r0 + r3; /* c+h, a+f */ + r5 = r0 + r1; /* c+d, a+b */ + r6 = r2 + r3; /* g+h, e+f */ + r5 >>= 16; + r5 |= (r6 << 16); /* e+f, c+d */ + r4 += r5 * 20; /* c+20*e+20*f+h, a+20*c+20*d+f */ + r4 += 0x100010; /* +16, +16 */ + r5 = r1 + r2; /* d+g, b+e */ + r4 -= r5 * 5; /* c-5*d+20*e+20*f-5*g+h, a-5*b+20*c+20*d-5*e+f */ + r4 >>= 5; + r13 |= r4; /* check clipping */ + r4 &= 0xFF00FF; /* mask */ + + r5 = p_ref[4]; /* i */ + r6 = (r5 << 16); + r5 = r6 | (r2 >> 16);/* 0,i,0,g */ + r5 += r1; /* d+i, b+g */ /* r5 not free */ + r1 >>= 16; + r1 |= (r3 << 16); /* 0,f,0,d */ /* r1 has changed */ + r1 += r2; /* f+g, d+e */ + r5 += 20 * r1; /* d+20f+20g+i, b+20d+20e+g */ + r0 >>= 16; + r0 |= (r2 << 16); /* 0,e,0,c */ /* r0 has changed */ + r0 += r3; /* e+h, c+f */ + r5 += 0x100010; /* 16,16 */ + r5 -= r0 * 5; /* d-5e+20f+20g-5h+i, b-5c+20d+20e-5f+g */ + r5 >>= 5; + r13 |= r5; /* check clipping */ + r5 &= 0xFF00FF; /* mask */ + + r4 |= (r5 << 8); /* pack them together */ + *p_cur++ = r4; + r1 = r3; + r0 = r2; + } + p_cur += curr_offset; /* move to the next line */ + p_ref += ref_offset; /* ref_offset = inpitch-blkwidth; */ + + if (r13&0xFF000700) /* need clipping */ + { + /* move back to the beginning of the line */ + p_ref -= (ref_offset + blkwidth); /* input */ + p_cur -= (outpitch >> 2); + + tmp = (uint32)(p_ref + blkwidth); + for (; (uint32)p_ref < tmp;) + { + + r0 = *p_ref++; + r1 = *p_ref++; + r2 = *p_ref++; + r3 = *p_ref++; + r4 = *p_ref++; + /* first pixel */ + r5 = *p_ref++; + result = (r0 + r5); + r0 = (r1 + r4); + result -= (r0 * 5);//result -= r0; result -= (r0<<2); + r0 = (r2 + r3); + result += (r0 * 20);//result += (r0<<4); result += (r0<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + pkres = result; + /* second pixel */ + r0 = *p_ref++; + result = (r1 + r0); + r1 = (r2 + r5); + result -= (r1 * 5);//result -= r1; result -= (r1<<2); + r1 = (r3 + r4); + result += (r1 * 20);//result += (r1<<4); result += (r1<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + pkres |= (result << 8); + /* third pixel */ + r1 = *p_ref++; + result = (r2 + r1); + r2 = (r3 + r0); + result -= (r2 * 5);//result -= r2; result -= (r2<<2); + r2 = (r4 + r5); + result += (r2 * 20);//result += (r2<<4); result += (r2<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + pkres |= (result << 16); + /* fourth pixel */ + r2 = *p_ref++; + result = (r3 + r2); + r3 = (r4 + r1); + result -= (r3 * 5);//result -= r3; result -= (r3<<2); + r3 = (r5 + r0); + result += (r3 * 20);//result += (r3<<4); result += (r3<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + pkres |= (result << 24); + *p_cur++ = pkres; /* write 4 pixels */ + p_ref -= 5; + } + p_cur += curr_offset; /* move to the next line */ + p_ref += ref_offset; + } + } + } + + return ; +} + +void HorzInterp2MC(int *in, int inpitch, uint8 *out, int outpitch, + int blkwidth, int blkheight, int dx) +{ + int *p_ref; + uint32 *p_cur; + uint32 tmp, pkres; + int result, result2, curr_offset, ref_offset; + int j, r0, r1, r2, r3, r4, r5; + + p_cur = (uint32*)out; /* assume it's word aligned */ + curr_offset = (outpitch - blkwidth) >> 2; + p_ref = in; + ref_offset = inpitch - blkwidth; + + if (dx&1) + { + dx = ((dx >> 1) ? -3 : -4); /* use in 3/4 pel */ + + for (j = blkheight; j > 0 ; j--) + { + tmp = (uint32)(p_ref + blkwidth); + for (; (uint32)p_ref < tmp;) + { + + r0 = p_ref[-2]; + r1 = p_ref[-1]; + r2 = *p_ref++; + r3 = *p_ref++; + r4 = *p_ref++; + /* first pixel */ + r5 = *p_ref++; + result = (r0 + r5); + r0 = (r1 + r4); + result -= (r0 * 5);//result -= r0; result -= (r0<<2); + r0 = (r2 + r3); + result += (r0 * 20);//result += (r0<<4); result += (r0<<2); + result = (result + 512) >> 10; + CLIP_RESULT(result) + result2 = ((p_ref[dx] + 16) >> 5); + CLIP_RESULT(result2) + /* 3/4 pel, no need to clip */ + result = (result + result2 + 1); + pkres = (result >> 1); + /* second pixel */ + r0 = *p_ref++; + result = (r1 + r0); + r1 = (r2 + r5); + result -= (r1 * 5);//result -= r1; result -= (r1<<2); + r1 = (r3 + r4); + result += (r1 * 20);//result += (r1<<4); result += (r1<<2); + result = (result + 512) >> 10; + CLIP_RESULT(result) + result2 = ((p_ref[dx] + 16) >> 5); + CLIP_RESULT(result2) + /* 3/4 pel, no need to clip */ + result = (result + result2 + 1); + result = (result >> 1); + pkres |= (result << 8); + /* third pixel */ + r1 = *p_ref++; + result = (r2 + r1); + r2 = (r3 + r0); + result -= (r2 * 5);//result -= r2; result -= (r2<<2); + r2 = (r4 + r5); + result += (r2 * 20);//result += (r2<<4); result += (r2<<2); + result = (result + 512) >> 10; + CLIP_RESULT(result) + result2 = ((p_ref[dx] + 16) >> 5); + CLIP_RESULT(result2) + /* 3/4 pel, no need to clip */ + result = (result + result2 + 1); + result = (result >> 1); + pkres |= (result << 16); + /* fourth pixel */ + r2 = *p_ref++; + result = (r3 + r2); + r3 = (r4 + r1); + result -= (r3 * 5);//result -= r3; result -= (r3<<2); + r3 = (r5 + r0); + result += (r3 * 20);//result += (r3<<4); result += (r3<<2); + result = (result + 512) >> 10; + CLIP_RESULT(result) + result2 = ((p_ref[dx] + 16) >> 5); + CLIP_RESULT(result2) + /* 3/4 pel, no need to clip */ + result = (result + result2 + 1); + result = (result >> 1); + pkres |= (result << 24); + *p_cur++ = pkres; /* write 4 pixels */ + p_ref -= 3; /* offset back to the middle of filter */ + } + p_cur += curr_offset; /* move to the next line */ + p_ref += ref_offset; /* move to the next line */ + } + } + else + { + for (j = blkheight; j > 0 ; j--) + { + tmp = (uint32)(p_ref + blkwidth); + for (; (uint32)p_ref < tmp;) + { + + r0 = p_ref[-2]; + r1 = p_ref[-1]; + r2 = *p_ref++; + r3 = *p_ref++; + r4 = *p_ref++; + /* first pixel */ + r5 = *p_ref++; + result = (r0 + r5); + r0 = (r1 + r4); + result -= (r0 * 5);//result -= r0; result -= (r0<<2); + r0 = (r2 + r3); + result += (r0 * 20);//result += (r0<<4); result += (r0<<2); + result = (result + 512) >> 10; + CLIP_RESULT(result) + pkres = result; + /* second pixel */ + r0 = *p_ref++; + result = (r1 + r0); + r1 = (r2 + r5); + result -= (r1 * 5);//result -= r1; result -= (r1<<2); + r1 = (r3 + r4); + result += (r1 * 20);//result += (r1<<4); result += (r1<<2); + result = (result + 512) >> 10; + CLIP_RESULT(result) + pkres |= (result << 8); + /* third pixel */ + r1 = *p_ref++; + result = (r2 + r1); + r2 = (r3 + r0); + result -= (r2 * 5);//result -= r2; result -= (r2<<2); + r2 = (r4 + r5); + result += (r2 * 20);//result += (r2<<4); result += (r2<<2); + result = (result + 512) >> 10; + CLIP_RESULT(result) + pkres |= (result << 16); + /* fourth pixel */ + r2 = *p_ref++; + result = (r3 + r2); + r3 = (r4 + r1); + result -= (r3 * 5);//result -= r3; result -= (r3<<2); + r3 = (r5 + r0); + result += (r3 * 20);//result += (r3<<4); result += (r3<<2); + result = (result + 512) >> 10; + CLIP_RESULT(result) + pkres |= (result << 24); + *p_cur++ = pkres; /* write 4 pixels */ + p_ref -= 3; /* offset back to the middle of filter */ + } + p_cur += curr_offset; /* move to the next line */ + p_ref += ref_offset; /* move to the next line */ + } + } + + return ; +} + +void HorzInterp3MC(uint8 *in, int inpitch, int *out, int outpitch, + int blkwidth, int blkheight) +{ + uint8 *p_ref; + int *p_cur; + uint32 tmp; + int result, curr_offset, ref_offset; + int j, r0, r1, r2, r3, r4, r5; + + p_cur = out; + curr_offset = (outpitch - blkwidth); + p_ref = in; + ref_offset = inpitch - blkwidth; + + for (j = blkheight; j > 0 ; j--) + { + tmp = (uint32)(p_ref + blkwidth); + for (; (uint32)p_ref < tmp;) + { + + r0 = p_ref[-2]; + r1 = p_ref[-1]; + r2 = *p_ref++; + r3 = *p_ref++; + r4 = *p_ref++; + /* first pixel */ + r5 = *p_ref++; + result = (r0 + r5); + r0 = (r1 + r4); + result -= (r0 * 5);//result -= r0; result -= (r0<<2); + r0 = (r2 + r3); + result += (r0 * 20);//result += (r0<<4); result += (r0<<2); + *p_cur++ = result; + /* second pixel */ + r0 = *p_ref++; + result = (r1 + r0); + r1 = (r2 + r5); + result -= (r1 * 5);//result -= r1; result -= (r1<<2); + r1 = (r3 + r4); + result += (r1 * 20);//result += (r1<<4); result += (r1<<2); + *p_cur++ = result; + /* third pixel */ + r1 = *p_ref++; + result = (r2 + r1); + r2 = (r3 + r0); + result -= (r2 * 5);//result -= r2; result -= (r2<<2); + r2 = (r4 + r5); + result += (r2 * 20);//result += (r2<<4); result += (r2<<2); + *p_cur++ = result; + /* fourth pixel */ + r2 = *p_ref++; + result = (r3 + r2); + r3 = (r4 + r1); + result -= (r3 * 5);//result -= r3; result -= (r3<<2); + r3 = (r5 + r0); + result += (r3 * 20);//result += (r3<<4); result += (r3<<2); + *p_cur++ = result; + p_ref -= 3; /* move back to the middle of the filter */ + } + p_cur += curr_offset; /* move to the next line */ + p_ref += ref_offset; + } + + return ; +} +void VertInterp1MC(uint8 *in, int inpitch, uint8 *out, int outpitch, + int blkwidth, int blkheight, int dy) +{ + uint8 *p_cur, *p_ref; + uint32 tmp; + int result, curr_offset, ref_offset; + int j, i; + int32 r0, r1, r2, r3, r4, r5, r6, r7, r8, r13; + uint8 tmp_in[24][24]; + + /* not word-aligned */ + if (((uint32)in)&0x3) + { + CreateAlign(in, inpitch, -2, &tmp_in[0][0], blkwidth, blkheight + 5); + in = &tmp_in[2][0]; + inpitch = 24; + } + p_cur = out; + curr_offset = 1 - outpitch * (blkheight - 1); /* offset vertically back up and one pixel to right */ + ref_offset = blkheight * inpitch; /* for limit */ + + curr_offset += 3; + + if (dy&1) + { + dy = (dy >> 1) ? 0 : -inpitch; + + for (j = 0; j < blkwidth; j += 4, in += 4) + { + r13 = 0; + p_ref = in; + p_cur -= outpitch; /* compensate for the first offset */ + tmp = (uint32)(p_ref + ref_offset); /* limit */ + while ((uint32)p_ref < tmp) /* the loop un-rolled */ + { + r0 = *((uint32*)(p_ref - (inpitch << 1))); /* load 4 bytes */ + p_ref += inpitch; + r6 = (r0 >> 8) & 0xFF00FF; /* second and fourth byte */ + r0 &= 0xFF00FF; + + r1 = *((uint32*)(p_ref + (inpitch << 1))); /* r1, r7, ref[3] */ + r7 = (r1 >> 8) & 0xFF00FF; + r1 &= 0xFF00FF; + + r0 += r1; + r6 += r7; + + r2 = *((uint32*)p_ref); /* r2, r8, ref[1] */ + r8 = (r2 >> 8) & 0xFF00FF; + r2 &= 0xFF00FF; + + r1 = *((uint32*)(p_ref - inpitch)); /* r1, r7, ref[0] */ + r7 = (r1 >> 8) & 0xFF00FF; + r1 &= 0xFF00FF; + r1 += r2; + + r7 += r8; + + r0 += 20 * r1; + r6 += 20 * r7; + r0 += 0x100010; + r6 += 0x100010; + + r2 = *((uint32*)(p_ref - (inpitch << 1))); /* r2, r8, ref[-1] */ + r8 = (r2 >> 8) & 0xFF00FF; + r2 &= 0xFF00FF; + + r1 = *((uint32*)(p_ref + inpitch)); /* r1, r7, ref[2] */ + r7 = (r1 >> 8) & 0xFF00FF; + r1 &= 0xFF00FF; + r1 += r2; + + r7 += r8; + + r0 -= 5 * r1; + r6 -= 5 * r7; + + r0 >>= 5; + r6 >>= 5; + /* clip */ + r13 |= r6; + r13 |= r0; + //CLIPPACK(r6,result) + + r1 = *((uint32*)(p_ref + dy)); + r2 = (r1 >> 8) & 0xFF00FF; + r1 &= 0xFF00FF; + r0 += r1; + r6 += r2; + r0 += 0x10001; + r6 += 0x10001; + r0 = (r0 >> 1) & 0xFF00FF; + r6 = (r6 >> 1) & 0xFF00FF; + + r0 |= (r6 << 8); /* pack it back */ + *((uint32*)(p_cur += outpitch)) = r0; + } + p_cur += curr_offset; /* offset to the next pixel */ + if (r13 & 0xFF000700) /* this column need clipping */ + { + p_cur -= 4; + for (i = 0; i < 4; i++) + { + p_ref = in + i; + p_cur -= outpitch; /* compensate for the first offset */ + + tmp = (uint32)(p_ref + ref_offset); /* limit */ + while ((uint32)p_ref < tmp) + { /* loop un-rolled */ + r0 = *(p_ref - (inpitch << 1)); + r1 = *(p_ref - inpitch); + r2 = *p_ref; + r3 = *(p_ref += inpitch); /* modify pointer before loading */ + r4 = *(p_ref += inpitch); + /* first pixel */ + r5 = *(p_ref += inpitch); + result = (r0 + r5); + r0 = (r1 + r4); + result -= (r0 * 5);//result -= r0; result -= (r0<<2); + r0 = (r2 + r3); + result += (r0 * 20);//result += (r0<<4); result += (r0<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + /* 3/4 pel, no need to clip */ + result = (result + p_ref[dy-(inpitch<<1)] + 1); + result = (result >> 1); + *(p_cur += outpitch) = result; + /* second pixel */ + r0 = *(p_ref += inpitch); + result = (r1 + r0); + r1 = (r2 + r5); + result -= (r1 * 5);//result -= r1; result -= (r1<<2); + r1 = (r3 + r4); + result += (r1 * 20);//result += (r1<<4); result += (r1<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + /* 3/4 pel, no need to clip */ + result = (result + p_ref[dy-(inpitch<<1)] + 1); + result = (result >> 1); + *(p_cur += outpitch) = result; + /* third pixel */ + r1 = *(p_ref += inpitch); + result = (r2 + r1); + r2 = (r3 + r0); + result -= (r2 * 5);//result -= r2; result -= (r2<<2); + r2 = (r4 + r5); + result += (r2 * 20);//result += (r2<<4); result += (r2<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + /* 3/4 pel, no need to clip */ + result = (result + p_ref[dy-(inpitch<<1)] + 1); + result = (result >> 1); + *(p_cur += outpitch) = result; + /* fourth pixel */ + r2 = *(p_ref += inpitch); + result = (r3 + r2); + r3 = (r4 + r1); + result -= (r3 * 5);//result -= r3; result -= (r3<<2); + r3 = (r5 + r0); + result += (r3 * 20);//result += (r3<<4); result += (r3<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + /* 3/4 pel, no need to clip */ + result = (result + p_ref[dy-(inpitch<<1)] + 1); + result = (result >> 1); + *(p_cur += outpitch) = result; + p_ref -= (inpitch << 1); /* move back to center of the filter of the next one */ + } + p_cur += (curr_offset - 3); + } + } + } + } + else + { + for (j = 0; j < blkwidth; j += 4, in += 4) + { + r13 = 0; + p_ref = in; + p_cur -= outpitch; /* compensate for the first offset */ + tmp = (uint32)(p_ref + ref_offset); /* limit */ + while ((uint32)p_ref < tmp) /* the loop un-rolled */ + { + r0 = *((uint32*)(p_ref - (inpitch << 1))); /* load 4 bytes */ + p_ref += inpitch; + r6 = (r0 >> 8) & 0xFF00FF; /* second and fourth byte */ + r0 &= 0xFF00FF; + + r1 = *((uint32*)(p_ref + (inpitch << 1))); /* r1, r7, ref[3] */ + r7 = (r1 >> 8) & 0xFF00FF; + r1 &= 0xFF00FF; + + r0 += r1; + r6 += r7; + + r2 = *((uint32*)p_ref); /* r2, r8, ref[1] */ + r8 = (r2 >> 8) & 0xFF00FF; + r2 &= 0xFF00FF; + + r1 = *((uint32*)(p_ref - inpitch)); /* r1, r7, ref[0] */ + r7 = (r1 >> 8) & 0xFF00FF; + r1 &= 0xFF00FF; + r1 += r2; + + r7 += r8; + + r0 += 20 * r1; + r6 += 20 * r7; + r0 += 0x100010; + r6 += 0x100010; + + r2 = *((uint32*)(p_ref - (inpitch << 1))); /* r2, r8, ref[-1] */ + r8 = (r2 >> 8) & 0xFF00FF; + r2 &= 0xFF00FF; + + r1 = *((uint32*)(p_ref + inpitch)); /* r1, r7, ref[2] */ + r7 = (r1 >> 8) & 0xFF00FF; + r1 &= 0xFF00FF; + r1 += r2; + + r7 += r8; + + r0 -= 5 * r1; + r6 -= 5 * r7; + + r0 >>= 5; + r6 >>= 5; + /* clip */ + r13 |= r6; + r13 |= r0; + //CLIPPACK(r6,result) + r0 &= 0xFF00FF; + r6 &= 0xFF00FF; + r0 |= (r6 << 8); /* pack it back */ + *((uint32*)(p_cur += outpitch)) = r0; + } + p_cur += curr_offset; /* offset to the next pixel */ + if (r13 & 0xFF000700) /* this column need clipping */ + { + p_cur -= 4; + for (i = 0; i < 4; i++) + { + p_ref = in + i; + p_cur -= outpitch; /* compensate for the first offset */ + tmp = (uint32)(p_ref + ref_offset); /* limit */ + while ((uint32)p_ref < tmp) + { /* loop un-rolled */ + r0 = *(p_ref - (inpitch << 1)); + r1 = *(p_ref - inpitch); + r2 = *p_ref; + r3 = *(p_ref += inpitch); /* modify pointer before loading */ + r4 = *(p_ref += inpitch); + /* first pixel */ + r5 = *(p_ref += inpitch); + result = (r0 + r5); + r0 = (r1 + r4); + result -= (r0 * 5);//result -= r0; result -= (r0<<2); + r0 = (r2 + r3); + result += (r0 * 20);//result += (r0<<4); result += (r0<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + *(p_cur += outpitch) = result; + /* second pixel */ + r0 = *(p_ref += inpitch); + result = (r1 + r0); + r1 = (r2 + r5); + result -= (r1 * 5);//result -= r1; result -= (r1<<2); + r1 = (r3 + r4); + result += (r1 * 20);//result += (r1<<4); result += (r1<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + *(p_cur += outpitch) = result; + /* third pixel */ + r1 = *(p_ref += inpitch); + result = (r2 + r1); + r2 = (r3 + r0); + result -= (r2 * 5);//result -= r2; result -= (r2<<2); + r2 = (r4 + r5); + result += (r2 * 20);//result += (r2<<4); result += (r2<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + *(p_cur += outpitch) = result; + /* fourth pixel */ + r2 = *(p_ref += inpitch); + result = (r3 + r2); + r3 = (r4 + r1); + result -= (r3 * 5);//result -= r3; result -= (r3<<2); + r3 = (r5 + r0); + result += (r3 * 20);//result += (r3<<4); result += (r3<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + *(p_cur += outpitch) = result; + p_ref -= (inpitch << 1); /* move back to center of the filter of the next one */ + } + p_cur += (curr_offset - 3); + } + } + } + } + + return ; +} + +void VertInterp2MC(uint8 *in, int inpitch, int *out, int outpitch, + int blkwidth, int blkheight) +{ + int *p_cur; + uint8 *p_ref; + uint32 tmp; + int result, curr_offset, ref_offset; + int j, r0, r1, r2, r3, r4, r5; + + p_cur = out; + curr_offset = 1 - outpitch * (blkheight - 1); /* offset vertically back up and one pixel to right */ + ref_offset = blkheight * inpitch; /* for limit */ + + for (j = 0; j < blkwidth; j++) + { + p_cur -= outpitch; /* compensate for the first offset */ + p_ref = in++; + + tmp = (uint32)(p_ref + ref_offset); /* limit */ + while ((uint32)p_ref < tmp) + { /* loop un-rolled */ + r0 = *(p_ref - (inpitch << 1)); + r1 = *(p_ref - inpitch); + r2 = *p_ref; + r3 = *(p_ref += inpitch); /* modify pointer before loading */ + r4 = *(p_ref += inpitch); + /* first pixel */ + r5 = *(p_ref += inpitch); + result = (r0 + r5); + r0 = (r1 + r4); + result -= (r0 * 5);//result -= r0; result -= (r0<<2); + r0 = (r2 + r3); + result += (r0 * 20);//result += (r0<<4); result += (r0<<2); + *(p_cur += outpitch) = result; + /* second pixel */ + r0 = *(p_ref += inpitch); + result = (r1 + r0); + r1 = (r2 + r5); + result -= (r1 * 5);//result -= r1; result -= (r1<<2); + r1 = (r3 + r4); + result += (r1 * 20);//result += (r1<<4); result += (r1<<2); + *(p_cur += outpitch) = result; + /* third pixel */ + r1 = *(p_ref += inpitch); + result = (r2 + r1); + r2 = (r3 + r0); + result -= (r2 * 5);//result -= r2; result -= (r2<<2); + r2 = (r4 + r5); + result += (r2 * 20);//result += (r2<<4); result += (r2<<2); + *(p_cur += outpitch) = result; + /* fourth pixel */ + r2 = *(p_ref += inpitch); + result = (r3 + r2); + r3 = (r4 + r1); + result -= (r3 * 5);//result -= r3; result -= (r3<<2); + r3 = (r5 + r0); + result += (r3 * 20);//result += (r3<<4); result += (r3<<2); + *(p_cur += outpitch) = result; + p_ref -= (inpitch << 1); /* move back to center of the filter of the next one */ + } + p_cur += curr_offset; + } + + return ; +} + +void VertInterp3MC(int *in, int inpitch, uint8 *out, int outpitch, + int blkwidth, int blkheight, int dy) +{ + uint8 *p_cur; + int *p_ref; + uint32 tmp; + int result, result2, curr_offset, ref_offset; + int j, r0, r1, r2, r3, r4, r5; + + p_cur = out; + curr_offset = 1 - outpitch * (blkheight - 1); /* offset vertically back up and one pixel to right */ + ref_offset = blkheight * inpitch; /* for limit */ + + if (dy&1) + { + dy = (dy >> 1) ? -(inpitch << 1) : -(inpitch << 1) - inpitch; + + for (j = 0; j < blkwidth; j++) + { + p_cur -= outpitch; /* compensate for the first offset */ + p_ref = in++; + + tmp = (uint32)(p_ref + ref_offset); /* limit */ + while ((uint32)p_ref < tmp) + { /* loop un-rolled */ + r0 = *(p_ref - (inpitch << 1)); + r1 = *(p_ref - inpitch); + r2 = *p_ref; + r3 = *(p_ref += inpitch); /* modify pointer before loading */ + r4 = *(p_ref += inpitch); + /* first pixel */ + r5 = *(p_ref += inpitch); + result = (r0 + r5); + r0 = (r1 + r4); + result -= (r0 * 5);//result -= r0; result -= (r0<<2); + r0 = (r2 + r3); + result += (r0 * 20);//result += (r0<<4); result += (r0<<2); + result = (result + 512) >> 10; + CLIP_RESULT(result) + result2 = ((p_ref[dy] + 16) >> 5); + CLIP_RESULT(result2) + /* 3/4 pel, no need to clip */ + result = (result + result2 + 1); + result = (result >> 1); + *(p_cur += outpitch) = result; + /* second pixel */ + r0 = *(p_ref += inpitch); + result = (r1 + r0); + r1 = (r2 + r5); + result -= (r1 * 5);//result -= r1; result -= (r1<<2); + r1 = (r3 + r4); + result += (r1 * 20);//result += (r1<<4); result += (r1<<2); + result = (result + 512) >> 10; + CLIP_RESULT(result) + result2 = ((p_ref[dy] + 16) >> 5); + CLIP_RESULT(result2) + /* 3/4 pel, no need to clip */ + result = (result + result2 + 1); + result = (result >> 1); + *(p_cur += outpitch) = result; + /* third pixel */ + r1 = *(p_ref += inpitch); + result = (r2 + r1); + r2 = (r3 + r0); + result -= (r2 * 5);//result -= r2; result -= (r2<<2); + r2 = (r4 + r5); + result += (r2 * 20);//result += (r2<<4); result += (r2<<2); + result = (result + 512) >> 10; + CLIP_RESULT(result) + result2 = ((p_ref[dy] + 16) >> 5); + CLIP_RESULT(result2) + /* 3/4 pel, no need to clip */ + result = (result + result2 + 1); + result = (result >> 1); + *(p_cur += outpitch) = result; + /* fourth pixel */ + r2 = *(p_ref += inpitch); + result = (r3 + r2); + r3 = (r4 + r1); + result -= (r3 * 5);//result -= r3; result -= (r3<<2); + r3 = (r5 + r0); + result += (r3 * 20);//result += (r3<<4); result += (r3<<2); + result = (result + 512) >> 10; + CLIP_RESULT(result) + result2 = ((p_ref[dy] + 16) >> 5); + CLIP_RESULT(result2) + /* 3/4 pel, no need to clip */ + result = (result + result2 + 1); + result = (result >> 1); + *(p_cur += outpitch) = result; + p_ref -= (inpitch << 1); /* move back to center of the filter of the next one */ + } + p_cur += curr_offset; + } + } + else + { + for (j = 0; j < blkwidth; j++) + { + p_cur -= outpitch; /* compensate for the first offset */ + p_ref = in++; + + tmp = (uint32)(p_ref + ref_offset); /* limit */ + while ((uint32)p_ref < tmp) + { /* loop un-rolled */ + r0 = *(p_ref - (inpitch << 1)); + r1 = *(p_ref - inpitch); + r2 = *p_ref; + r3 = *(p_ref += inpitch); /* modify pointer before loading */ + r4 = *(p_ref += inpitch); + /* first pixel */ + r5 = *(p_ref += inpitch); + result = (r0 + r5); + r0 = (r1 + r4); + result -= (r0 * 5);//result -= r0; result -= (r0<<2); + r0 = (r2 + r3); + result += (r0 * 20);//result += (r0<<4); result += (r0<<2); + result = (result + 512) >> 10; + CLIP_RESULT(result) + *(p_cur += outpitch) = result; + /* second pixel */ + r0 = *(p_ref += inpitch); + result = (r1 + r0); + r1 = (r2 + r5); + result -= (r1 * 5);//result -= r1; result -= (r1<<2); + r1 = (r3 + r4); + result += (r1 * 20);//result += (r1<<4); result += (r1<<2); + result = (result + 512) >> 10; + CLIP_RESULT(result) + *(p_cur += outpitch) = result; + /* third pixel */ + r1 = *(p_ref += inpitch); + result = (r2 + r1); + r2 = (r3 + r0); + result -= (r2 * 5);//result -= r2; result -= (r2<<2); + r2 = (r4 + r5); + result += (r2 * 20);//result += (r2<<4); result += (r2<<2); + result = (result + 512) >> 10; + CLIP_RESULT(result) + *(p_cur += outpitch) = result; + /* fourth pixel */ + r2 = *(p_ref += inpitch); + result = (r3 + r2); + r3 = (r4 + r1); + result -= (r3 * 5);//result -= r3; result -= (r3<<2); + r3 = (r5 + r0); + result += (r3 * 20);//result += (r3<<4); result += (r3<<2); + result = (result + 512) >> 10; + CLIP_RESULT(result) + *(p_cur += outpitch) = result; + p_ref -= (inpitch << 1); /* move back to center of the filter of the next one */ + } + p_cur += curr_offset; + } + } + + return ; +} + +void DiagonalInterpMC(uint8 *in1, uint8 *in2, int inpitch, + uint8 *out, int outpitch, + int blkwidth, int blkheight) +{ + int j, i; + int result; + uint8 *p_cur, *p_ref, *p_tmp8; + int curr_offset, ref_offset; + uint8 tmp_res[24][24], tmp_in[24][24]; + uint32 *p_tmp; + uint32 tmp, pkres, tmp_result; + int32 r0, r1, r2, r3, r4, r5; + int32 r6, r7, r8, r9, r10, r13; + + ref_offset = inpitch - blkwidth; + p_ref = in1 - 2; + /* perform horizontal interpolation */ + /* not word-aligned */ + /* It is faster to read 1 byte at time to avoid calling CreateAlign */ + /* if(((uint32)p_ref)&0x3) + { + CreateAlign(p_ref,inpitch,0,&tmp_in[0][0],blkwidth+8,blkheight); + p_ref = &tmp_in[0][0]; + ref_offset = 24-blkwidth; + }*/ + + p_tmp = (uint32*) & (tmp_res[0][0]); + for (j = blkheight; j > 0; j--) + { + r13 = 0; + tmp = (uint32)(p_ref + blkwidth); + + //r0 = *((uint32*)p_ref); /* d,c,b,a */ + //r1 = (r0>>8)&0xFF00FF; /* 0,d,0,b */ + //r0 &= 0xFF00FF; /* 0,c,0,a */ + /* It is faster to read 1 byte at a time, */ + r0 = p_ref[0]; + r1 = p_ref[2]; + r0 |= (r1 << 16); /* 0,c,0,a */ + r1 = p_ref[1]; + r2 = p_ref[3]; + r1 |= (r2 << 16); /* 0,d,0,b */ + + while ((uint32)p_ref < tmp) + { + //r2 = *((uint32*)(p_ref+=4));/* h,g,f,e */ + //r3 = (r2>>8)&0xFF00FF; /* 0,h,0,f */ + //r2 &= 0xFF00FF; /* 0,g,0,e */ + /* It is faster to read 1 byte at a time, */ + r2 = *(p_ref += 4); + r3 = p_ref[2]; + r2 |= (r3 << 16); /* 0,g,0,e */ + r3 = p_ref[1]; + r4 = p_ref[3]; + r3 |= (r4 << 16); /* 0,h,0,f */ + + r4 = r0 + r3; /* c+h, a+f */ + r5 = r0 + r1; /* c+d, a+b */ + r6 = r2 + r3; /* g+h, e+f */ + r5 >>= 16; + r5 |= (r6 << 16); /* e+f, c+d */ + r4 += r5 * 20; /* c+20*e+20*f+h, a+20*c+20*d+f */ + r4 += 0x100010; /* +16, +16 */ + r5 = r1 + r2; /* d+g, b+e */ + r4 -= r5 * 5; /* c-5*d+20*e+20*f-5*g+h, a-5*b+20*c+20*d-5*e+f */ + r4 >>= 5; + r13 |= r4; /* check clipping */ + r4 &= 0xFF00FF; /* mask */ + + r5 = p_ref[4]; /* i */ + r6 = (r5 << 16); + r5 = r6 | (r2 >> 16);/* 0,i,0,g */ + r5 += r1; /* d+i, b+g */ /* r5 not free */ + r1 >>= 16; + r1 |= (r3 << 16); /* 0,f,0,d */ /* r1 has changed */ + r1 += r2; /* f+g, d+e */ + r5 += 20 * r1; /* d+20f+20g+i, b+20d+20e+g */ + r0 >>= 16; + r0 |= (r2 << 16); /* 0,e,0,c */ /* r0 has changed */ + r0 += r3; /* e+h, c+f */ + r5 += 0x100010; /* 16,16 */ + r5 -= r0 * 5; /* d-5e+20f+20g-5h+i, b-5c+20d+20e-5f+g */ + r5 >>= 5; + r13 |= r5; /* check clipping */ + r5 &= 0xFF00FF; /* mask */ + + r4 |= (r5 << 8); /* pack them together */ + *p_tmp++ = r4; + r1 = r3; + r0 = r2; + } + p_tmp += ((24 - blkwidth) >> 2); /* move to the next line */ + p_ref += ref_offset; /* ref_offset = inpitch-blkwidth; */ + + if (r13&0xFF000700) /* need clipping */ + { + /* move back to the beginning of the line */ + p_ref -= (ref_offset + blkwidth); /* input */ + p_tmp -= 6; /* intermediate output */ + tmp = (uint32)(p_ref + blkwidth); + while ((uint32)p_ref < tmp) + { + r0 = *p_ref++; + r1 = *p_ref++; + r2 = *p_ref++; + r3 = *p_ref++; + r4 = *p_ref++; + /* first pixel */ + r5 = *p_ref++; + result = (r0 + r5); + r0 = (r1 + r4); + result -= (r0 * 5);//result -= r0; result -= (r0<<2); + r0 = (r2 + r3); + result += (r0 * 20);//result += (r0<<4); result += (r0<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + pkres = result; + /* second pixel */ + r0 = *p_ref++; + result = (r1 + r0); + r1 = (r2 + r5); + result -= (r1 * 5);//result -= r1; result -= (r1<<2); + r1 = (r3 + r4); + result += (r1 * 20);//result += (r1<<4); result += (r1<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + pkres |= (result << 8); + /* third pixel */ + r1 = *p_ref++; + result = (r2 + r1); + r2 = (r3 + r0); + result -= (r2 * 5);//result -= r2; result -= (r2<<2); + r2 = (r4 + r5); + result += (r2 * 20);//result += (r2<<4); result += (r2<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + pkres |= (result << 16); + /* fourth pixel */ + r2 = *p_ref++; + result = (r3 + r2); + r3 = (r4 + r1); + result -= (r3 * 5);//result -= r3; result -= (r3<<2); + r3 = (r5 + r0); + result += (r3 * 20);//result += (r3<<4); result += (r3<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + pkres |= (result << 24); + + *p_tmp++ = pkres; /* write 4 pixel */ + p_ref -= 5; + } + p_tmp += ((24 - blkwidth) >> 2); /* move to the next line */ + p_ref += ref_offset; /* ref_offset = inpitch-blkwidth; */ + } + } + + /* perform vertical interpolation */ + /* not word-aligned */ + if (((uint32)in2)&0x3) + { + CreateAlign(in2, inpitch, -2, &tmp_in[0][0], blkwidth, blkheight + 5); + in2 = &tmp_in[2][0]; + inpitch = 24; + } + + p_cur = out; + curr_offset = 1 - outpitch * (blkheight - 1); /* offset vertically up and one pixel right */ + pkres = blkheight * inpitch; /* reuse it for limit */ + + curr_offset += 3; + + for (j = 0; j < blkwidth; j += 4, in2 += 4) + { + r13 = 0; + p_ref = in2; + p_tmp8 = &(tmp_res[0][j]); /* intermediate result */ + p_tmp8 -= 24; /* compensate for the first offset */ + p_cur -= outpitch; /* compensate for the first offset */ + tmp = (uint32)(p_ref + pkres); /* limit */ + while ((uint32)p_ref < tmp) /* the loop un-rolled */ + { + /* Read 1 byte at a time is too slow, too many read and pack ops, need to call CreateAlign, */ + /*p_ref8 = p_ref-(inpitch<<1); r0 = p_ref8[0]; r1 = p_ref8[2]; + r0 |= (r1<<16); r6 = p_ref8[1]; r1 = p_ref8[3]; + r6 |= (r1<<16); p_ref+=inpitch; */ + r0 = *((uint32*)(p_ref - (inpitch << 1))); /* load 4 bytes */ + p_ref += inpitch; + r6 = (r0 >> 8) & 0xFF00FF; /* second and fourth byte */ + r0 &= 0xFF00FF; + + /*p_ref8 = p_ref+(inpitch<<1); + r1 = p_ref8[0]; r7 = p_ref8[2]; r1 |= (r7<<16); + r7 = p_ref8[1]; r2 = p_ref8[3]; r7 |= (r2<<16);*/ + r1 = *((uint32*)(p_ref + (inpitch << 1))); /* r1, r7, ref[3] */ + r7 = (r1 >> 8) & 0xFF00FF; + r1 &= 0xFF00FF; + + r0 += r1; + r6 += r7; + + /*r2 = p_ref[0]; r8 = p_ref[2]; r2 |= (r8<<16); + r8 = p_ref[1]; r1 = p_ref[3]; r8 |= (r1<<16);*/ + r2 = *((uint32*)p_ref); /* r2, r8, ref[1] */ + r8 = (r2 >> 8) & 0xFF00FF; + r2 &= 0xFF00FF; + + /*p_ref8 = p_ref-inpitch; r1 = p_ref8[0]; r7 = p_ref8[2]; + r1 |= (r7<<16); r1 += r2; r7 = p_ref8[1]; + r2 = p_ref8[3]; r7 |= (r2<<16);*/ + r1 = *((uint32*)(p_ref - inpitch)); /* r1, r7, ref[0] */ + r7 = (r1 >> 8) & 0xFF00FF; + r1 &= 0xFF00FF; + r1 += r2; + + r7 += r8; + + r0 += 20 * r1; + r6 += 20 * r7; + r0 += 0x100010; + r6 += 0x100010; + + /*p_ref8 = p_ref-(inpitch<<1); r2 = p_ref8[0]; r8 = p_ref8[2]; + r2 |= (r8<<16); r8 = p_ref8[1]; r1 = p_ref8[3]; r8 |= (r1<<16);*/ + r2 = *((uint32*)(p_ref - (inpitch << 1))); /* r2, r8, ref[-1] */ + r8 = (r2 >> 8) & 0xFF00FF; + r2 &= 0xFF00FF; + + /*p_ref8 = p_ref+inpitch; r1 = p_ref8[0]; r7 = p_ref8[2]; + r1 |= (r7<<16); r1 += r2; r7 = p_ref8[1]; + r2 = p_ref8[3]; r7 |= (r2<<16);*/ + r1 = *((uint32*)(p_ref + inpitch)); /* r1, r7, ref[2] */ + r7 = (r1 >> 8) & 0xFF00FF; + r1 &= 0xFF00FF; + r1 += r2; + + r7 += r8; + + r0 -= 5 * r1; + r6 -= 5 * r7; + + r0 >>= 5; + r6 >>= 5; + /* clip */ + r13 |= r6; + r13 |= r0; + //CLIPPACK(r6,result) + /* add with horizontal results */ + r10 = *((uint32*)(p_tmp8 += 24)); + r9 = (r10 >> 8) & 0xFF00FF; + r10 &= 0xFF00FF; + + r0 += r10; + r0 += 0x10001; + r0 = (r0 >> 1) & 0xFF00FF; /* mask to 8 bytes */ + + r6 += r9; + r6 += 0x10001; + r6 = (r6 >> 1) & 0xFF00FF; /* mask to 8 bytes */ + + r0 |= (r6 << 8); /* pack it back */ + *((uint32*)(p_cur += outpitch)) = r0; + } + p_cur += curr_offset; /* offset to the next pixel */ + if (r13 & 0xFF000700) /* this column need clipping */ + { + p_cur -= 4; + for (i = 0; i < 4; i++) + { + p_ref = in2 + i; + p_tmp8 = &(tmp_res[0][j+i]); /* intermediate result */ + p_tmp8 -= 24; /* compensate for the first offset */ + p_cur -= outpitch; /* compensate for the first offset */ + tmp = (uint32)(p_ref + pkres); /* limit */ + while ((uint32)p_ref < tmp) /* the loop un-rolled */ + { + r0 = *(p_ref - (inpitch << 1)); + r1 = *(p_ref - inpitch); + r2 = *p_ref; + r3 = *(p_ref += inpitch); /* modify pointer before loading */ + r4 = *(p_ref += inpitch); + /* first pixel */ + r5 = *(p_ref += inpitch); + result = (r0 + r5); + r0 = (r1 + r4); + result -= (r0 * 5);//result -= r0; result -= (r0<<2); + r0 = (r2 + r3); + result += (r0 * 20);//result += (r0<<4); result += (r0<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + tmp_result = *(p_tmp8 += 24); /* modify pointer before loading */ + result = (result + tmp_result + 1); /* no clip */ + result = (result >> 1); + *(p_cur += outpitch) = result; + /* second pixel */ + r0 = *(p_ref += inpitch); + result = (r1 + r0); + r1 = (r2 + r5); + result -= (r1 * 5);//result -= r1; result -= (r1<<2); + r1 = (r3 + r4); + result += (r1 * 20);//result += (r1<<4); result += (r1<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + tmp_result = *(p_tmp8 += 24); /* intermediate result */ + result = (result + tmp_result + 1); /* no clip */ + result = (result >> 1); + *(p_cur += outpitch) = result; + /* third pixel */ + r1 = *(p_ref += inpitch); + result = (r2 + r1); + r2 = (r3 + r0); + result -= (r2 * 5);//result -= r2; result -= (r2<<2); + r2 = (r4 + r5); + result += (r2 * 20);//result += (r2<<4); result += (r2<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + tmp_result = *(p_tmp8 += 24); /* intermediate result */ + result = (result + tmp_result + 1); /* no clip */ + result = (result >> 1); + *(p_cur += outpitch) = result; + /* fourth pixel */ + r2 = *(p_ref += inpitch); + result = (r3 + r2); + r3 = (r4 + r1); + result -= (r3 * 5);//result -= r3; result -= (r3<<2); + r3 = (r5 + r0); + result += (r3 * 20);//result += (r3<<4); result += (r3<<2); + result = (result + 16) >> 5; + CLIP_RESULT(result) + tmp_result = *(p_tmp8 += 24); /* intermediate result */ + result = (result + tmp_result + 1); /* no clip */ + result = (result >> 1); + *(p_cur += outpitch) = result; + p_ref -= (inpitch << 1); /* move back to center of the filter of the next one */ + } + p_cur += (curr_offset - 3); + } + } + } + + return ; +} + +/* position G */ +void FullPelMC(uint8 *in, int inpitch, uint8 *out, int outpitch, + int blkwidth, int blkheight) +{ + int i, j; + int offset_in = inpitch - blkwidth; + int offset_out = outpitch - blkwidth; + uint32 temp; + uint8 byte; + + if (((uint32)in)&3) + { + for (j = blkheight; j > 0; j--) + { + for (i = blkwidth; i > 0; i -= 4) + { + temp = *in++; + byte = *in++; + temp |= (byte << 8); + byte = *in++; + temp |= (byte << 16); + byte = *in++; + temp |= (byte << 24); + + *((uint32*)out) = temp; /* write 4 bytes */ + out += 4; + } + out += offset_out; + in += offset_in; + } + } + else + { + for (j = blkheight; j > 0; j--) + { + for (i = blkwidth; i > 0; i -= 4) + { + temp = *((uint32*)in); + *((uint32*)out) = temp; + in += 4; + out += 4; + } + out += offset_out; + in += offset_in; + } + } + return ; +} + +void ChromaMotionComp(uint8 *ref, int picwidth, int picheight, + int x_pos, int y_pos, + uint8 *pred, int pred_pitch, + int blkwidth, int blkheight) +{ + int dx, dy; + int offset_dx, offset_dy; + int index; + uint8 temp[24][24]; + + dx = x_pos & 7; + dy = y_pos & 7; + offset_dx = (dx + 7) >> 3; + offset_dy = (dy + 7) >> 3; + x_pos = x_pos >> 3; /* round it to full-pel resolution */ + y_pos = y_pos >> 3; + + if ((x_pos >= 0 && x_pos + blkwidth + offset_dx <= picwidth) && (y_pos >= 0 && y_pos + blkheight + offset_dy <= picheight)) + { + ref += y_pos * picwidth + x_pos; + } + else + { + CreatePad(ref, picwidth, picheight, x_pos, y_pos, &temp[0][0], blkwidth + offset_dx, blkheight + offset_dy); + ref = &temp[0][0]; + picwidth = 24; + } + + index = offset_dx + (offset_dy << 1) + ((blkwidth << 1) & 0x7); + + (*(ChromaMC_SIMD[index]))(ref, picwidth , dx, dy, pred, pred_pitch, blkwidth, blkheight); + return ; +} + + +/* SIMD routines, unroll the loops in vertical direction, decreasing loops (things to be done) */ +void ChromaDiagonalMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy, + uint8 *pOut, int predPitch, int blkwidth, int blkheight) +{ + int32 r0, r1, r2, r3, result0, result1; + uint8 temp[288]; + uint8 *ref, *out; + int i, j; + int dx_8 = 8 - dx; + int dy_8 = 8 - dy; + + /* horizontal first */ + out = temp; + for (i = 0; i < blkheight + 1; i++) + { + ref = pRef; + r0 = ref[0]; + for (j = 0; j < blkwidth; j += 4) + { + r0 |= (ref[2] << 16); + result0 = dx_8 * r0; + + r1 = ref[1] | (ref[3] << 16); + result0 += dx * r1; + *(int32 *)out = result0; + + result0 = dx_8 * r1; + + r2 = ref[4]; + r0 = r0 >> 16; + r1 = r0 | (r2 << 16); + result0 += dx * r1; + *(int32 *)(out + 16) = result0; + + ref += 4; + out += 4; + r0 = r2; + } + pRef += srcPitch; + out += (32 - blkwidth); + } + +// pRef -= srcPitch*(blkheight+1); + ref = temp; + + for (j = 0; j < blkwidth; j += 4) + { + r0 = *(int32 *)ref; + r1 = *(int32 *)(ref + 16); + ref += 32; + out = pOut; + for (i = 0; i < (blkheight >> 1); i++) + { + result0 = dy_8 * r0 + 0x00200020; + r2 = *(int32 *)ref; + result0 += dy * r2; + result0 >>= 6; + result0 &= 0x00FF00FF; + r0 = r2; + + result1 = dy_8 * r1 + 0x00200020; + r3 = *(int32 *)(ref + 16); + result1 += dy * r3; + result1 >>= 6; + result1 &= 0x00FF00FF; + r1 = r3; + *(int32 *)out = result0 | (result1 << 8); + out += predPitch; + ref += 32; + + result0 = dy_8 * r0 + 0x00200020; + r2 = *(int32 *)ref; + result0 += dy * r2; + result0 >>= 6; + result0 &= 0x00FF00FF; + r0 = r2; + + result1 = dy_8 * r1 + 0x00200020; + r3 = *(int32 *)(ref + 16); + result1 += dy * r3; + result1 >>= 6; + result1 &= 0x00FF00FF; + r1 = r3; + *(int32 *)out = result0 | (result1 << 8); + out += predPitch; + ref += 32; + } + pOut += 4; + ref = temp + 4; /* since it can only iterate twice max */ + } + return; +} + +void ChromaHorizontalMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy, + uint8 *pOut, int predPitch, int blkwidth, int blkheight) +{ + OSCL_UNUSED_ARG(dy); + int32 r0, r1, r2, result0, result1; + uint8 *ref, *out; + int i, j; + int dx_8 = 8 - dx; + + /* horizontal first */ + for (i = 0; i < blkheight; i++) + { + ref = pRef; + out = pOut; + + r0 = ref[0]; + for (j = 0; j < blkwidth; j += 4) + { + r0 |= (ref[2] << 16); + result0 = dx_8 * r0 + 0x00040004; + + r1 = ref[1] | (ref[3] << 16); + result0 += dx * r1; + result0 >>= 3; + result0 &= 0x00FF00FF; + + result1 = dx_8 * r1 + 0x00040004; + + r2 = ref[4]; + r0 = r0 >> 16; + r1 = r0 | (r2 << 16); + result1 += dx * r1; + result1 >>= 3; + result1 &= 0x00FF00FF; + + *(int32 *)out = result0 | (result1 << 8); + + ref += 4; + out += 4; + r0 = r2; + } + + pRef += srcPitch; + pOut += predPitch; + } + return; +} + +void ChromaVerticalMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy, + uint8 *pOut, int predPitch, int blkwidth, int blkheight) +{ + OSCL_UNUSED_ARG(dx); + int32 r0, r1, r2, r3, result0, result1; + int i, j; + uint8 *ref, *out; + int dy_8 = 8 - dy; + /* vertical first */ + for (i = 0; i < blkwidth; i += 4) + { + ref = pRef; + out = pOut; + + r0 = ref[0] | (ref[2] << 16); + r1 = ref[1] | (ref[3] << 16); + ref += srcPitch; + for (j = 0; j < blkheight; j++) + { + result0 = dy_8 * r0 + 0x00040004; + r2 = ref[0] | (ref[2] << 16); + result0 += dy * r2; + result0 >>= 3; + result0 &= 0x00FF00FF; + r0 = r2; + + result1 = dy_8 * r1 + 0x00040004; + r3 = ref[1] | (ref[3] << 16); + result1 += dy * r3; + result1 >>= 3; + result1 &= 0x00FF00FF; + r1 = r3; + *(int32 *)out = result0 | (result1 << 8); + ref += srcPitch; + out += predPitch; + } + pOut += 4; + pRef += 4; + } + return; +} + +void ChromaDiagonalMC2_SIMD(uint8 *pRef, int srcPitch, int dx, int dy, + uint8 *pOut, int predPitch, int blkwidth, int blkheight) +{ + OSCL_UNUSED_ARG(blkwidth); + int32 r0, r1, temp0, temp1, result; + int32 temp[9]; + int32 *out; + int i, r_temp; + int dy_8 = 8 - dy; + + /* horizontal first */ + out = temp; + for (i = 0; i < blkheight + 1; i++) + { + r_temp = pRef[1]; + temp0 = (pRef[0] << 3) + dx * (r_temp - pRef[0]); + temp1 = (r_temp << 3) + dx * (pRef[2] - r_temp); + r0 = temp0 | (temp1 << 16); + *out++ = r0; + pRef += srcPitch; + } + + pRef -= srcPitch * (blkheight + 1); + + out = temp; + + r0 = *out++; + + for (i = 0; i < blkheight; i++) + { + result = dy_8 * r0 + 0x00200020; + r1 = *out++; + result += dy * r1; + result >>= 6; + result &= 0x00FF00FF; + *(int16 *)pOut = (result >> 8) | (result & 0xFF); + r0 = r1; + pOut += predPitch; + } + return; +} + +void ChromaHorizontalMC2_SIMD(uint8 *pRef, int srcPitch, int dx, int dy, + uint8 *pOut, int predPitch, int blkwidth, int blkheight) +{ + OSCL_UNUSED_ARG(dy); + OSCL_UNUSED_ARG(blkwidth); + int i, temp, temp0, temp1; + + /* horizontal first */ + for (i = 0; i < blkheight; i++) + { + temp = pRef[1]; + temp0 = ((pRef[0] << 3) + dx * (temp - pRef[0]) + 4) >> 3; + temp1 = ((temp << 3) + dx * (pRef[2] - temp) + 4) >> 3; + + *(int16 *)pOut = temp0 | (temp1 << 8); + pRef += srcPitch; + pOut += predPitch; + + } + return; +} +void ChromaVerticalMC2_SIMD(uint8 *pRef, int srcPitch, int dx, int dy, + uint8 *pOut, int predPitch, int blkwidth, int blkheight) +{ + OSCL_UNUSED_ARG(dx); + OSCL_UNUSED_ARG(blkwidth); + int32 r0, r1, result; + int i; + int dy_8 = 8 - dy; + r0 = pRef[0] | (pRef[1] << 16); + pRef += srcPitch; + for (i = 0; i < blkheight; i++) + { + result = dy_8 * r0 + 0x00040004; + r1 = pRef[0] | (pRef[1] << 16); + result += dy * r1; + result >>= 3; + result &= 0x00FF00FF; + *(int16 *)pOut = (result >> 8) | (result & 0xFF); + r0 = r1; + pRef += srcPitch; + pOut += predPitch; + } + return; +} + +void ChromaFullMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy, + uint8 *pOut, int predPitch, int blkwidth, int blkheight) +{ + OSCL_UNUSED_ARG(dx); + OSCL_UNUSED_ARG(dy); + int i, j; + int offset_in = srcPitch - blkwidth; + int offset_out = predPitch - blkwidth; + uint16 temp; + uint8 byte; + + if (((uint32)pRef)&1) + { + for (j = blkheight; j > 0; j--) + { + for (i = blkwidth; i > 0; i -= 2) + { + temp = *pRef++; + byte = *pRef++; + temp |= (byte << 8); + *((uint16*)pOut) = temp; /* write 2 bytes */ + pOut += 2; + } + pOut += offset_out; + pRef += offset_in; + } + } + else + { + for (j = blkheight; j > 0; j--) + { + for (i = blkwidth; i > 0; i -= 2) + { + temp = *((uint16*)pRef); + *((uint16*)pOut) = temp; + pRef += 2; + pOut += 2; + } + pOut += offset_out; + pRef += offset_in; + } + } + return ; +} diff --git a/media/libstagefright/codecs/avc/dec/src/pred_intra.cpp b/media/libstagefright/codecs/avc/dec/src/pred_intra.cpp new file mode 100644 index 0000000..0b613a4 --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/src/pred_intra.cpp @@ -0,0 +1,1786 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 "avcdec_lib.h" + +#define CLIP_COMP *comp++ = (uint8)(((uint)temp>0xFF)? 0xFF&(~(temp>>31)): temp) +#define CLIP_RESULT(x) if((uint)x > 0xFF){ \ + x = 0xFF & (~(x>>31));} + + +/* We should combine the Intra4x4 functions with residual decoding and compensation */ +AVCStatus IntraMBPrediction(AVCCommonObj *video) +{ + int component, SubBlock_indx, temp; + AVCStatus status; + AVCMacroblock *currMB = video->currMB; + AVCPictureData *currPic = video->currPic; + uint8 *curL, *curCb, *curCr; + uint8 *comp; + int block_x, block_y, offset; + int16 *dataBlock = video->block; + uint8 *predCb, *predCr; +#ifdef USE_PRED_BLOCK + uint8 *pred; +#endif + int pitch = currPic->pitch; + uint32 cbp4x4 = video->cbp4x4; + + offset = (video->mb_y << 4) * pitch + (video->mb_x << 4); + curL = currPic->Sl + offset; + +#ifdef USE_PRED_BLOCK + video->pred_block = video->pred + 84; /* point to separate prediction memory */ + pred = video->pred_block; + video->pred_pitch = 20; +#else + video->pred_block = curL; /* point directly to the frame buffer */ + video->pred_pitch = pitch; +#endif + + if (currMB->mbMode == AVC_I4) + { + /* luminance first */ + block_x = block_y = 0; + for (component = 0; component < 4; component++) + { + block_x = ((component & 1) << 1); + block_y = ((component >> 1) << 1); + comp = curL;// + (block_x<<2) + (block_y<<2)*currPic->pitch; + + for (SubBlock_indx = 0; SubBlock_indx < 4; SubBlock_indx++) + { + status = Intra_4x4(video, block_x, block_y, comp); + if (status != AVC_SUCCESS) + { + return status; + } + /* transform following the 4x4 prediction, can't be SIMD + with other blocks. */ +#ifdef USE_PRED_BLOCK + if (cbp4x4&(1 << ((block_y << 2) + block_x))) + { + itrans(dataBlock, pred, pred, 20); + } +#else + if (cbp4x4&(1 << ((block_y << 2) + block_x))) + { + itrans(dataBlock, comp, comp, pitch); + } +#endif + temp = SubBlock_indx & 1; + if (temp) + { + block_y++; + block_x--; + dataBlock += 60; +#ifdef USE_PRED_BLOCK + pred += 76; +#else + comp += ((pitch << 2) - 4); +#endif + } + else + { + block_x++; + dataBlock += 4; +#ifdef USE_PRED_BLOCK + pred += 4; +#else + comp += 4; +#endif + } + } + if (component&1) + { +#ifdef USE_PRED_BLOCK + pred -= 8; +#else + curL += (pitch << 3) - 8; +#endif + dataBlock -= 8; + } + else + { +#ifdef USE_PRED_BLOCK + pred -= 152; +#else + curL += 8; +#endif + dataBlock -= 120; + } + } + cbp4x4 >>= 16; + } + else /* AVC_I16 */ + { +#ifdef MB_BASED_DEBLOCK + video->pintra_pred_top = video->intra_pred_top + (video->mb_x << 4); + video->pintra_pred_left = video->intra_pred_left + 1; + video->intra_pred_topleft = video->intra_pred_left[0]; + pitch = 1; +#else + video->pintra_pred_top = curL - pitch; + video->pintra_pred_left = curL - 1; + if (video->mb_y) + { + video->intra_pred_topleft = *(curL - pitch - 1); + } +#endif + switch (currMB->i16Mode) + { + case AVC_I16_Vertical: /* Intra_16x16_Vertical */ + /* check availability of top */ + if (video->intraAvailB) + { + Intra_16x16_Vertical(video); + } + else + { + return AVC_FAIL; + } + break; + case AVC_I16_Horizontal: /* Intra_16x16_Horizontal */ + /* check availability of left */ + if (video->intraAvailA) + { + Intra_16x16_Horizontal(video, pitch); + } + else + { + return AVC_FAIL; + } + break; + case AVC_I16_DC: /* Intra_16x16_DC */ + Intra_16x16_DC(video, pitch); + break; + case AVC_I16_Plane: /* Intra_16x16_Plane */ + if (video->intraAvailA && video->intraAvailB && video->intraAvailD) + { + Intra_16x16_Plane(video, pitch); + } + else + { + return AVC_FAIL; + } + break; + default: + break; + } + + pitch = currPic->pitch; + + /* transform */ + /* can go in raster scan order now */ + /* can be done in SIMD, */ + for (block_y = 4; block_y > 0; block_y--) + { + for (block_x = 4; block_x > 0; block_x--) + { +#ifdef USE_PRED_BLOCK + if (cbp4x4&1) + { + itrans(dataBlock, pred, pred, 20); + } +#else + if (cbp4x4&1) + { + itrans(dataBlock, curL, curL, pitch); + } +#endif + cbp4x4 >>= 1; + dataBlock += 4; +#ifdef USE_PRED_BLOCK + pred += 4; +#else + curL += 4; +#endif + } + dataBlock += 48; +#ifdef USE_PRED_BLOCK + pred += 64; +#else + curL += ((pitch << 2) - 16); +#endif + } + } + + offset = (offset >> 2) + (video->mb_x << 2); //((video->mb_y << 3)* pitch + (video->mb_x << 3)); + curCb = currPic->Scb + offset; + curCr = currPic->Scr + offset; + +#ifdef MB_BASED_DEBLOCK + video->pintra_pred_top_cb = video->intra_pred_top_cb + (video->mb_x << 3); + video->pintra_pred_left_cb = video->intra_pred_left_cb + 1; + video->intra_pred_topleft_cb = video->intra_pred_left_cb[0]; + video->pintra_pred_top_cr = video->intra_pred_top_cr + (video->mb_x << 3); + video->pintra_pred_left_cr = video->intra_pred_left_cr + 1; + video->intra_pred_topleft_cr = video->intra_pred_left_cr[0]; + pitch = 1; +#else + pitch >>= 1; + video->pintra_pred_top_cb = curCb - pitch; + video->pintra_pred_left_cb = curCb - 1; + video->pintra_pred_top_cr = curCr - pitch; + video->pintra_pred_left_cr = curCr - 1; + + if (video->mb_y) + { + video->intra_pred_topleft_cb = *(curCb - pitch - 1); + video->intra_pred_topleft_cr = *(curCr - pitch - 1); + } +#endif + +#ifdef USE_PRED_BLOCK + predCb = video->pred + 452; + predCr = predCb + 144; + video->pred_pitch = 12; +#else + predCb = curCb; + predCr = curCr; + video->pred_pitch = currPic->pitch >> 1; +#endif + /* chrominance */ + switch (currMB->intra_chroma_pred_mode) + { + case AVC_IC_DC: /* Intra_Chroma_DC */ + Intra_Chroma_DC(video, pitch, predCb, predCr); + break; + case AVC_IC_Horizontal: /* Intra_Chroma_Horizontal */ + if (video->intraAvailA) + { + /* check availability of left */ + Intra_Chroma_Horizontal(video, pitch, predCb, predCr); + } + else + { + return AVC_FAIL; + } + break; + case AVC_IC_Vertical: /* Intra_Chroma_Vertical */ + if (video->intraAvailB) + { + /* check availability of top */ + Intra_Chroma_Vertical(video, predCb, predCr); + } + else + { + return AVC_FAIL; + } + break; + case AVC_IC_Plane: /* Intra_Chroma_Plane */ + if (video->intraAvailA && video->intraAvailB && video->intraAvailD) + { + /* check availability of top and left */ + Intra_Chroma_Plane(video, pitch, predCb, predCr); + } + else + { + return AVC_FAIL; + } + break; + default: + break; + } + + /* transform, done in raster scan manner */ + pitch = currPic->pitch >> 1; + + for (block_y = 2; block_y > 0; block_y--) + { + for (block_x = 2; block_x > 0; block_x--) + { +#ifdef USE_PRED_BLOCK + if (cbp4x4&1) + { + ictrans(dataBlock, predCb, predCb, 12); + } +#else + if (cbp4x4&1) + { + ictrans(dataBlock, curCb, curCb, pitch); + } +#endif + cbp4x4 >>= 1; + dataBlock += 4; +#ifdef USE_PRED_BLOCK + predCb += 4; +#else + curCb += 4; +#endif + } + for (block_x = 2; block_x > 0; block_x--) + { +#ifdef USE_PRED_BLOCK + if (cbp4x4&1) + { + ictrans(dataBlock, predCr, predCr, 12); + } +#else + if (cbp4x4&1) + { + ictrans(dataBlock, curCr, curCr, pitch); + } +#endif + cbp4x4 >>= 1; + dataBlock += 4; +#ifdef USE_PRED_BLOCK + predCr += 4; +#else + curCr += 4; +#endif + } + dataBlock += 48; +#ifdef USE_PRED_BLOCK + predCb += 40; + predCr += 40; +#else + curCb += ((pitch << 2) - 8); + curCr += ((pitch << 2) - 8); +#endif + } + +#ifdef MB_BASED_DEBLOCK + SaveNeighborForIntraPred(video, offset); +#endif + return AVC_SUCCESS; +} + +#ifdef MB_BASED_DEBLOCK +void SaveNeighborForIntraPred(AVCCommonObj *video, int offset) +{ + AVCPictureData *currPic = video->currPic; + int pitch; + uint8 *pred, *predCb, *predCr; + uint8 *tmp_ptr, tmp_byte; + uint32 tmp_word; + int mb_x = video->mb_x; + + /* save the value for intra prediction */ +#ifdef USE_PRED_BLOCK + pitch = 20; + pred = video->pred + 384; /* bottom line for Y */ + predCb = pred + 152; /* bottom line for Cb */ + predCr = predCb + 144; /* bottom line for Cr */ +#else + pitch = currPic->pitch; + tmp_word = offset + (pitch << 2) - (pitch >> 1); + predCb = currPic->Scb + tmp_word;/* bottom line for Cb */ + predCr = currPic->Scr + tmp_word;/* bottom line for Cr */ + + offset = (offset << 2) - (mb_x << 4); + pred = currPic->Sl + offset + (pitch << 4) - pitch;/* bottom line for Y */ + +#endif + + video->intra_pred_topleft = video->intra_pred_top[(mb_x<<4)+15]; + video->intra_pred_topleft_cb = video->intra_pred_top_cb[(mb_x<<3)+7]; + video->intra_pred_topleft_cr = video->intra_pred_top_cr[(mb_x<<3)+7]; + + /* then copy to video->intra_pred_top, intra_pred_top_cb, intra_pred_top_cr */ + /*memcpy(video->intra_pred_top + (mb_x<<4), pred, 16); + memcpy(video->intra_pred_top_cb + (mb_x<<3), predCb, 8); + memcpy(video->intra_pred_top_cr + (mb_x<<3), predCr, 8);*/ + tmp_ptr = video->intra_pred_top + (mb_x << 4); + *((uint32*)tmp_ptr) = *((uint32*)pred); + *((uint32*)(tmp_ptr + 4)) = *((uint32*)(pred + 4)); + *((uint32*)(tmp_ptr + 8)) = *((uint32*)(pred + 8)); + *((uint32*)(tmp_ptr + 12)) = *((uint32*)(pred + 12)); + tmp_ptr = video->intra_pred_top_cb + (mb_x << 3); + *((uint32*)tmp_ptr) = *((uint32*)predCb); + *((uint32*)(tmp_ptr + 4)) = *((uint32*)(predCb + 4)); + tmp_ptr = video->intra_pred_top_cr + (mb_x << 3); + *((uint32*)tmp_ptr) = *((uint32*)predCr); + *((uint32*)(tmp_ptr + 4)) = *((uint32*)(predCr + 4)); + + + /* now save last column */ +#ifdef USE_PRED_BLOCK + pred = video->pred + 99; /* last column*/ +#else + pred -= ((pitch << 4) - pitch - 15); /* last column */ +#endif + tmp_ptr = video->intra_pred_left; + tmp_word = video->intra_pred_topleft; + tmp_byte = *(pred); + tmp_word |= (tmp_byte << 8); + tmp_byte = *(pred += pitch); + tmp_word |= (tmp_byte << 16); + tmp_byte = *(pred += pitch); + tmp_word |= (tmp_byte << 24); + *((uint32*)tmp_ptr) = tmp_word; + tmp_word = *(pred += pitch); + tmp_byte = *(pred += pitch); + tmp_word |= (tmp_byte << 8); + tmp_byte = *(pred += pitch); + tmp_word |= (tmp_byte << 16); + tmp_byte = *(pred += pitch); + tmp_word |= (tmp_byte << 24); + *((uint32*)(tmp_ptr += 4)) = tmp_word; + tmp_word = *(pred += pitch); + tmp_byte = *(pred += pitch); + tmp_word |= (tmp_byte << 8); + tmp_byte = *(pred += pitch); + tmp_word |= (tmp_byte << 16); + tmp_byte = *(pred += pitch); + tmp_word |= (tmp_byte << 24); + *((uint32*)(tmp_ptr += 4)) = tmp_word; + tmp_word = *(pred += pitch); + tmp_byte = *(pred += pitch); + tmp_word |= (tmp_byte << 8); + tmp_byte = *(pred += pitch); + tmp_word |= (tmp_byte << 16); + tmp_byte = *(pred += pitch); + tmp_word |= (tmp_byte << 24); + *((uint32*)(tmp_ptr += 4)) = tmp_word; + *(tmp_ptr += 4) = *(pred += pitch); + + /* now for Cb */ +#ifdef USE_PRED_BLOCK + predCb = video->pred + 459; + pitch = 12; +#else + pitch >>= 1; + predCb -= (7 * pitch - 7); +#endif + tmp_ptr = video->intra_pred_left_cb; + tmp_word = video->intra_pred_topleft_cb; + tmp_byte = *(predCb); + tmp_word |= (tmp_byte << 8); + tmp_byte = *(predCb += pitch); + tmp_word |= (tmp_byte << 16); + tmp_byte = *(predCb += pitch); + tmp_word |= (tmp_byte << 24); + *((uint32*)tmp_ptr) = tmp_word; + tmp_word = *(predCb += pitch); + tmp_byte = *(predCb += pitch); + tmp_word |= (tmp_byte << 8); + tmp_byte = *(predCb += pitch); + tmp_word |= (tmp_byte << 16); + tmp_byte = *(predCb += pitch); + tmp_word |= (tmp_byte << 24); + *((uint32*)(tmp_ptr += 4)) = tmp_word; + *(tmp_ptr += 4) = *(predCb += pitch); + + /* now for Cr */ +#ifdef USE_PRED_BLOCK + predCr = video->pred + 603; +#else + predCr -= (7 * pitch - 7); +#endif + tmp_ptr = video->intra_pred_left_cr; + tmp_word = video->intra_pred_topleft_cr; + tmp_byte = *(predCr); + tmp_word |= (tmp_byte << 8); + tmp_byte = *(predCr += pitch); + tmp_word |= (tmp_byte << 16); + tmp_byte = *(predCr += pitch); + tmp_word |= (tmp_byte << 24); + *((uint32*)tmp_ptr) = tmp_word; + tmp_word = *(predCr += pitch); + tmp_byte = *(predCr += pitch); + tmp_word |= (tmp_byte << 8); + tmp_byte = *(predCr += pitch); + tmp_word |= (tmp_byte << 16); + tmp_byte = *(predCr += pitch); + tmp_word |= (tmp_byte << 24); + *((uint32*)(tmp_ptr += 4)) = tmp_word; + *(tmp_ptr += 4) = *(predCr += pitch); + + return ; +} +#endif /* MB_BASED_DEBLOCK */ + +AVCStatus Intra_4x4(AVCCommonObj *video, int block_x, int block_y, uint8 *comp) +{ + AVCMacroblock *currMB = video->currMB; + int block_offset; + AVCNeighborAvailability availability; + int pitch = video->currPic->pitch; + +#ifdef USE_PRED_BLOCK + block_offset = (block_y * 80) + (block_x << 2); +#else + block_offset = (block_y << 2) * pitch + (block_x << 2); +#endif + +#ifdef MB_BASED_DEBLOCK + /* boundary blocks use video->pred_intra_top, pred_intra_left, pred_intra_topleft */ + if (!block_x) + { + video->pintra_pred_left = video->intra_pred_left + 1 + (block_y << 2); + pitch = 1; + } + else + { + video->pintra_pred_left = video->pred_block + block_offset - 1; + pitch = video->pred_pitch; + } + + if (!block_y) + { + video->pintra_pred_top = video->intra_pred_top + (block_x << 2) + (video->mb_x << 4); + } + else + { + video->pintra_pred_top = video->pred_block + block_offset - video->pred_pitch; + } + + if (!block_x) + { + video->intra_pred_topleft = video->intra_pred_left[block_y<<2]; + } + else if (!block_y) + { + video->intra_pred_topleft = video->intra_pred_top[(video->mb_x<<4)+(block_x<<2)-1]; + } + else + { + video->intra_pred_topleft = video->pred_block[block_offset - video->pred_pitch - 1]; + } + +#else + /* normal case */ + video->pintra_pred_top = comp - pitch; + video->pintra_pred_left = comp - 1; + if (video->mb_y || block_y) + { + video->intra_pred_topleft = *(comp - pitch - 1); + } +#endif + + switch (currMB->i4Mode[(block_y << 2) + block_x]) + { + case AVC_I4_Vertical: /* Intra_4x4_Vertical */ + if (block_y > 0 || video->intraAvailB)/* to prevent out-of-bound access*/ + { + Intra_4x4_Vertical(video, block_offset); + } + else + { + return AVC_FAIL; + } + break; + + case AVC_I4_Horizontal: /* Intra_4x4_Horizontal */ + if (block_x || video->intraAvailA) /* to prevent out-of-bound access */ + { + Intra_4x4_Horizontal(video, pitch, block_offset); + } + else + { + return AVC_FAIL; + } + break; + + case AVC_I4_DC: /* Intra_4x4_DC */ + availability.left = TRUE; + availability.top = TRUE; + if (!block_y) + { /* check availability up */ + availability.top = video->intraAvailB ; + } + if (!block_x) + { /* check availability left */ + availability.left = video->intraAvailA ; + } + Intra_4x4_DC(video, pitch, block_offset, &availability); + break; + + case AVC_I4_Diagonal_Down_Left: /* Intra_4x4_Diagonal_Down_Left */ + /* lookup table will be more appropriate for this case */ + if (block_y == 0 && !video->intraAvailB) + { + return AVC_FAIL; + } + + availability.top_right = BlkTopRight[(block_y<<2) + block_x]; + + if (availability.top_right == 2) + { + availability.top_right = video->intraAvailB; + } + else if (availability.top_right == 3) + { + availability.top_right = video->intraAvailC; + } + + Intra_4x4_Down_Left(video, block_offset, &availability); + break; + + case AVC_I4_Diagonal_Down_Right: /* Intra_4x4_Diagonal_Down_Right */ + if ((block_y && block_x) /* to prevent out-of-bound access */ + || (block_y && video->intraAvailA) + || (block_x && video->intraAvailB) + || (video->intraAvailA && video->intraAvailD && video->intraAvailB)) + { + Intra_4x4_Diagonal_Down_Right(video, pitch, block_offset); + } + else + { + return AVC_FAIL; + } + break; + + case AVC_I4_Vertical_Right: /* Intra_4x4_Vertical_Right */ + if ((block_y && block_x) /* to prevent out-of-bound access */ + || (block_y && video->intraAvailA) + || (block_x && video->intraAvailB) + || (video->intraAvailA && video->intraAvailD && video->intraAvailB)) + { + Intra_4x4_Diagonal_Vertical_Right(video, pitch, block_offset); + } + else + { + return AVC_FAIL; + } + break; + + case AVC_I4_Horizontal_Down: /* Intra_4x4_Horizontal_Down */ + if ((block_y && block_x) /* to prevent out-of-bound access */ + || (block_y && video->intraAvailA) + || (block_x && video->intraAvailB) + || (video->intraAvailA && video->intraAvailD && video->intraAvailB)) + { + Intra_4x4_Diagonal_Horizontal_Down(video, pitch, block_offset); + } + else + { + return AVC_FAIL; + } + break; + + case AVC_I4_Vertical_Left: /* Intra_4x4_Vertical_Left */ + /* lookup table may be more appropriate for this case */ + if (block_y == 0 && !video->intraAvailB) + { + return AVC_FAIL; + } + + availability.top_right = BlkTopRight[(block_y<<2) + block_x]; + + if (availability.top_right == 2) + { + availability.top_right = video->intraAvailB; + } + else if (availability.top_right == 3) + { + availability.top_right = video->intraAvailC; + } + + Intra_4x4_Vertical_Left(video, block_offset, &availability); + break; + + case AVC_I4_Horizontal_Up: /* Intra_4x4_Horizontal_Up */ + if (block_x || video->intraAvailA) + { + Intra_4x4_Horizontal_Up(video, pitch, block_offset); + } + else + { + return AVC_FAIL; + } + break; + + + default: + + break; + } + + return AVC_SUCCESS; +} + + +/* =============================== BEGIN 4x4 +MODES======================================*/ +void Intra_4x4_Vertical(AVCCommonObj *video, int block_offset) +{ + uint8 *comp_ref = video->pintra_pred_top; + uint32 temp; + uint8 *pred = video->pred_block + block_offset; + int pred_pitch = video->pred_pitch; + + /*P = (int) *comp_ref++; + Q = (int) *comp_ref++; + R = (int) *comp_ref++; + S = (int) *comp_ref++; + temp = S|(R<<8)|(Q<<16)|(P<<24);*/ + temp = *((uint32*)comp_ref); + + *((uint32*)pred) = temp; /* write 4 at a time */ + pred += pred_pitch; + *((uint32*)pred) = temp; + pred += pred_pitch; + *((uint32*)pred) = temp; + pred += pred_pitch; + *((uint32*)pred) = temp; + + return ; +} + +void Intra_4x4_Horizontal(AVCCommonObj *video, int pitch, int block_offset) +{ + uint8 *comp_ref = video->pintra_pred_left; + uint32 temp; + int P; + uint8 *pred = video->pred_block + block_offset; + int pred_pitch = video->pred_pitch; + + P = *comp_ref; + temp = P | (P << 8); + temp = temp | (temp << 16); + *((uint32*)pred) = temp; + pred += pred_pitch; + comp_ref += pitch; + P = *comp_ref; + temp = P | (P << 8); + temp = temp | (temp << 16); + *((uint32*)pred) = temp; + pred += pred_pitch; + comp_ref += pitch; + P = *comp_ref; + temp = P | (P << 8); + temp = temp | (temp << 16); + *((uint32*)pred) = temp; + pred += pred_pitch; + comp_ref += pitch; + P = *comp_ref; + temp = P | (P << 8); + temp = temp | (temp << 16); + *((uint32*)pred) = temp; + + return ; +} + +void Intra_4x4_DC(AVCCommonObj *video, int pitch, int block_offset, + AVCNeighborAvailability *availability) +{ + uint8 *comp_ref = video->pintra_pred_left; + uint32 temp; + int DC; + uint8 *pred = video->pred_block + block_offset; + int pred_pitch = video->pred_pitch; + + if (availability->left) + { + DC = *comp_ref; + comp_ref += pitch; + DC += *comp_ref; + comp_ref += pitch; + DC += *comp_ref; + comp_ref += pitch; + DC += *comp_ref; + comp_ref = video->pintra_pred_top; + + if (availability->top) + { + DC = (comp_ref[0] + comp_ref[1] + comp_ref[2] + comp_ref[3] + DC + 4) >> 3; + } + else + { + DC = (DC + 2) >> 2; + + } + } + else if (availability->top) + { + comp_ref = video->pintra_pred_top; + DC = (comp_ref[0] + comp_ref[1] + comp_ref[2] + comp_ref[3] + 2) >> 2; + + } + else + { + DC = 128; + } + + temp = DC | (DC << 8); + temp = temp | (temp << 16); + *((uint32*)pred) = temp; + pred += pred_pitch; + *((uint32*)pred) = temp; + pred += pred_pitch; + *((uint32*)pred) = temp; + pred += pred_pitch; + *((uint32*)pred) = temp; + + return ; +} + +void Intra_4x4_Down_Left(AVCCommonObj *video, int block_offset, + AVCNeighborAvailability *availability) +{ + uint8 *comp_refx = video->pintra_pred_top; + uint32 temp; + int r0, r1, r2, r3, r4, r5, r6, r7; + uint8 *pred = video->pred_block + block_offset; + int pred_pitch = video->pred_pitch; + + r0 = *comp_refx++; + r1 = *comp_refx++; + r2 = *comp_refx++; + r3 = *comp_refx++; + if (availability->top_right) + { + r4 = *comp_refx++; + r5 = *comp_refx++; + r6 = *comp_refx++; + r7 = *comp_refx++; + } + else + { + r4 = r3; + r5 = r3; + r6 = r3; + r7 = r3; + } + + r0 += (r1 << 1); + r0 += r2; + r0 += 2; + r0 >>= 2; + r1 += (r2 << 1); + r1 += r3; + r1 += 2; + r1 >>= 2; + r2 += (r3 << 1); + r2 += r4; + r2 += 2; + r2 >>= 2; + r3 += (r4 << 1); + r3 += r5; + r3 += 2; + r3 >>= 2; + r4 += (r5 << 1); + r4 += r6; + r4 += 2; + r4 >>= 2; + r5 += (r6 << 1); + r5 += r7; + r5 += 2; + r5 >>= 2; + r6 += (3 * r7); + r6 += 2; + r6 >>= 2; + + temp = r0 | (r1 << 8); + temp |= (r2 << 16); + temp |= (r3 << 24); + *((uint32*)pred) = temp; + pred += pred_pitch; + + temp = (temp >> 8) | (r4 << 24); + *((uint32*)pred) = temp; + pred += pred_pitch; + + temp = (temp >> 8) | (r5 << 24); + *((uint32*)pred) = temp; + pred += pred_pitch; + + temp = (temp >> 8) | (r6 << 24); + *((uint32*)pred) = temp; + + return ; +} + +void Intra_4x4_Diagonal_Down_Right(AVCCommonObj *video, int pitch, int + block_offset) +{ + uint8 *comp_refx = video->pintra_pred_top; + uint8 *comp_refy = video->pintra_pred_left; + uint32 temp; + int P_x, Q_x, R_x, P_y, Q_y, R_y, D; + int x0, x1, x2; + uint8 *pred = video->pred_block + block_offset; + int pred_pitch = video->pred_pitch; + + temp = *((uint32*)comp_refx); /* read 4 bytes */ + x0 = temp & 0xFF; + x1 = (temp >> 8) & 0xFF; + x2 = (temp >> 16) & 0xFF; + + Q_x = (x0 + 2 * x1 + x2 + 2) >> 2; + R_x = (x1 + 2 * x2 + (temp >> 24) + 2) >> 2; + + x2 = video->intra_pred_topleft; /* re-use x2 instead of y0 */ + P_x = (x2 + 2 * x0 + x1 + 2) >> 2; + + x1 = *comp_refy; + comp_refy += pitch; /* re-use x1 instead of y1 */ + D = (x0 + 2 * x2 + x1 + 2) >> 2; + + x0 = *comp_refy; + comp_refy += pitch; /* re-use x0 instead of y2 */ + P_y = (x2 + 2 * x1 + x0 + 2) >> 2; + + x2 = *comp_refy; + comp_refy += pitch; /* re-use x2 instead of y3 */ + Q_y = (x1 + 2 * x0 + x2 + 2) >> 2; + + x1 = *comp_refy; /* re-use x1 instead of y4 */ + R_y = (x0 + 2 * x2 + x1 + 2) >> 2; + + /* we can pack these */ + temp = D | (P_x << 8); //[D P_x Q_x R_x] + //[P_y D P_x Q_x] + temp |= (Q_x << 16); //[Q_y P_y D P_x] + temp |= (R_x << 24); //[R_y Q_y P_y D ] + *((uint32*)pred) = temp; + pred += pred_pitch; + + temp = P_y | (D << 8); + temp |= (P_x << 16); + temp |= (Q_x << 24); + *((uint32*)pred) = temp; + pred += pred_pitch; + + temp = Q_y | (P_y << 8); + temp |= (D << 16); + temp |= (P_x << 24); + *((uint32*)pred) = temp; + pred += pred_pitch; + + temp = R_y | (Q_y << 8); + temp |= (P_y << 16); + temp |= (D << 24); + *((uint32*)pred) = temp; + + return ; +} + +void Intra_4x4_Diagonal_Vertical_Right(AVCCommonObj *video, int pitch, int block_offset) +{ + uint8 *comp_refx = video->pintra_pred_top; + uint8 *comp_refy = video->pintra_pred_left; + uint32 temp; + int P0, Q0, R0, S0, P1, Q1, R1, P2, Q2, D; + int x0, x1, x2; + uint8 *pred = video->pred_block + block_offset; + int pred_pitch = video->pred_pitch; + + x0 = *comp_refx++; + x1 = *comp_refx++; + Q0 = x0 + x1 + 1; + + x2 = *comp_refx++; + R0 = x1 + x2 + 1; + + x1 = *comp_refx++; /* reuse x1 instead of x3 */ + S0 = x2 + x1 + 1; + + x1 = video->intra_pred_topleft; /* reuse x1 instead of y0 */ + P0 = x1 + x0 + 1; + + x2 = *comp_refy; + comp_refy += pitch; /* reuse x2 instead of y1 */ + D = (x2 + 2 * x1 + x0 + 2) >> 2; + + P1 = (P0 + Q0) >> 2; + Q1 = (Q0 + R0) >> 2; + R1 = (R0 + S0) >> 2; + + P0 >>= 1; + Q0 >>= 1; + R0 >>= 1; + S0 >>= 1; + + x0 = *comp_refy; + comp_refy += pitch; /* reuse x0 instead of y2 */ + P2 = (x1 + 2 * x2 + x0 + 2) >> 2; + x1 = *comp_refy; + comp_refy += pitch; /* reuse x1 instead of y3 */ + Q2 = (x2 + 2 * x0 + x1 + 2) >> 2; + + temp = P0 | (Q0 << 8); //[P0 Q0 R0 S0] + //[D P1 Q1 R1] + temp |= (R0 << 16); //[P2 P0 Q0 R0] + temp |= (S0 << 24); //[Q2 D P1 Q1] + *((uint32*)pred) = temp; + pred += pred_pitch; + + temp = D | (P1 << 8); + temp |= (Q1 << 16); + temp |= (R1 << 24); + *((uint32*)pred) = temp; + pred += pred_pitch; + + temp = P2 | (P0 << 8); + temp |= (Q0 << 16); + temp |= (R0 << 24); + *((uint32*)pred) = temp; + pred += pred_pitch; + + temp = Q2 | (D << 8); + temp |= (P1 << 16); + temp |= (Q1 << 24); + *((uint32*)pred) = temp; + + return ; +} + +void Intra_4x4_Diagonal_Horizontal_Down(AVCCommonObj *video, int pitch, + int block_offset) +{ + uint8 *comp_refx = video->pintra_pred_top; + uint8 *comp_refy = video->pintra_pred_left; + uint32 temp; + int P0, Q0, R0, S0, P1, Q1, R1, P2, Q2, D; + int x0, x1, x2; + uint8 *pred = video->pred_block + block_offset; + int pred_pitch = video->pred_pitch; + + x0 = *comp_refx++; + x1 = *comp_refx++; + x2 = *comp_refx++; + Q2 = (x0 + 2 * x1 + x2 + 2) >> 2; + + x2 = video->intra_pred_topleft; /* reuse x2 instead of y0 */ + P2 = (x2 + 2 * x0 + x1 + 2) >> 2; + + x1 = *comp_refy; + comp_refy += pitch; /* reuse x1 instead of y1 */ + D = (x1 + 2 * x2 + x0 + 2) >> 2; + P0 = x2 + x1 + 1; + + x0 = *comp_refy; + comp_refy += pitch; /* reuse x0 instead of y2 */ + Q0 = x1 + x0 + 1; + + x1 = *comp_refy; + comp_refy += pitch; /* reuse x1 instead of y3 */ + R0 = x0 + x1 + 1; + + x2 = *comp_refy; /* reuse x2 instead of y4 */ + S0 = x1 + x2 + 1; + + P1 = (P0 + Q0) >> 2; + Q1 = (Q0 + R0) >> 2; + R1 = (R0 + S0) >> 2; + + P0 >>= 1; + Q0 >>= 1; + R0 >>= 1; + S0 >>= 1; + + + /* we can pack these */ + temp = P0 | (D << 8); //[P0 D P2 Q2] + //[Q0 P1 P0 D ] + temp |= (P2 << 16); //[R0 Q1 Q0 P1] + temp |= (Q2 << 24); //[S0 R1 R0 Q1] + *((uint32*)pred) = temp; + pred += pred_pitch; + + temp = Q0 | (P1 << 8); + temp |= (P0 << 16); + temp |= (D << 24); + *((uint32*)pred) = temp; + pred += pred_pitch; + + temp = R0 | (Q1 << 8); + temp |= (Q0 << 16); + temp |= (P1 << 24); + *((uint32*)pred) = temp; + pred += pred_pitch; + + temp = S0 | (R1 << 8); + temp |= (R0 << 16); + temp |= (Q1 << 24); + *((uint32*)pred) = temp; + + return ; +} + +void Intra_4x4_Vertical_Left(AVCCommonObj *video, int block_offset, AVCNeighborAvailability *availability) +{ + uint8 *comp_refx = video->pintra_pred_top; + uint32 temp1, temp2; + int x0, x1, x2, x3, x4, x5, x6; + uint8 *pred = video->pred_block + block_offset; + int pred_pitch = video->pred_pitch; + + x0 = *comp_refx++; + x1 = *comp_refx++; + x2 = *comp_refx++; + x3 = *comp_refx++; + if (availability->top_right) + { + x4 = *comp_refx++; + x5 = *comp_refx++; + x6 = *comp_refx++; + } + else + { + x4 = x3; + x5 = x3; + x6 = x3; + } + + x0 += x1 + 1; + x1 += x2 + 1; + x2 += x3 + 1; + x3 += x4 + 1; + x4 += x5 + 1; + x5 += x6 + 1; + + temp1 = (x0 >> 1); + temp1 |= ((x1 >> 1) << 8); + temp1 |= ((x2 >> 1) << 16); + temp1 |= ((x3 >> 1) << 24); + + *((uint32*)pred) = temp1; + pred += pred_pitch; + + temp2 = ((x0 + x1) >> 2); + temp2 |= (((x1 + x2) >> 2) << 8); + temp2 |= (((x2 + x3) >> 2) << 16); + temp2 |= (((x3 + x4) >> 2) << 24); + + *((uint32*)pred) = temp2; + pred += pred_pitch; + + temp1 = (temp1 >> 8) | ((x4 >> 1) << 24); /* rotate out old value */ + *((uint32*)pred) = temp1; + pred += pred_pitch; + + temp2 = (temp2 >> 8) | (((x4 + x5) >> 2) << 24); /* rotate out old value */ + *((uint32*)pred) = temp2; + pred += pred_pitch; + + return ; +} + +void Intra_4x4_Horizontal_Up(AVCCommonObj *video, int pitch, int block_offset) +{ + uint8 *comp_refy = video->pintra_pred_left; + uint32 temp; + int Q0, R0, Q1, D0, D1, P0, P1; + int y0, y1, y2, y3; + uint8 *pred = video->pred_block + block_offset; + int pred_pitch = video->pred_pitch; + + y0 = *comp_refy; + comp_refy += pitch; + y1 = *comp_refy; + comp_refy += pitch; + y2 = *comp_refy; + comp_refy += pitch; + y3 = *comp_refy; + + Q0 = (y1 + y2 + 1) >> 1; + Q1 = (y1 + (y2 << 1) + y3 + 2) >> 2; + P0 = ((y0 + y1 + 1) >> 1); + P1 = ((y0 + (y1 << 1) + y2 + 2) >> 2); + + temp = P0 | (P1 << 8); // [P0 P1 Q0 Q1] + temp |= (Q0 << 16); // [Q0 Q1 R0 DO] + temp |= (Q1 << 24); // [R0 D0 D1 D1] + *((uint32*)pred) = temp; // [D1 D1 D1 D1] + pred += pred_pitch; + + D0 = (y2 + 3 * y3 + 2) >> 2; + R0 = (y2 + y3 + 1) >> 1; + + temp = Q0 | (Q1 << 8); + temp |= (R0 << 16); + temp |= (D0 << 24); + *((uint32*)pred) = temp; + pred += pred_pitch; + + D1 = y3; + + temp = R0 | (D0 << 8); + temp |= (D1 << 16); + temp |= (D1 << 24); + *((uint32*)pred) = temp; + pred += pred_pitch; + + temp = D1 | (D1 << 8); + temp |= (temp << 16); + *((uint32*)pred) = temp; + + return ; +} +/* =============================== END 4x4 MODES======================================*/ +void Intra_16x16_Vertical(AVCCommonObj *video) +{ + int i; + uint32 temp1, temp2, temp3, temp4; + uint8 *comp_ref = video->pintra_pred_top; + uint8 *pred = video->pred_block; + int pred_pitch = video->pred_pitch; + + temp1 = *((uint32*)comp_ref); + comp_ref += 4; + + temp2 = *((uint32*)comp_ref); + comp_ref += 4; + + temp3 = *((uint32*)comp_ref); + comp_ref += 4; + + temp4 = *((uint32*)comp_ref); + comp_ref += 4; + + i = 16; + while (i > 0) + { + *((uint32*)pred) = temp1; + *((uint32*)(pred + 4)) = temp2; + *((uint32*)(pred + 8)) = temp3; + *((uint32*)(pred + 12)) = temp4; + pred += pred_pitch; + i--; + } + + return ; +} + +void Intra_16x16_Horizontal(AVCCommonObj *video, int pitch) +{ + int i; + uint32 temp; + uint8 *comp_ref = video->pintra_pred_left; + uint8 *pred = video->pred_block; + int pred_pitch = video->pred_pitch; + + for (i = 0; i < 16; i++) + { + temp = *comp_ref; + temp |= (temp << 8); + temp |= (temp << 16); + *((uint32*)pred) = temp; + *((uint32*)(pred + 4)) = temp; + *((uint32*)(pred + 8)) = temp; + *((uint32*)(pred + 12)) = temp; + pred += pred_pitch; + comp_ref += pitch; + } +} + + +void Intra_16x16_DC(AVCCommonObj *video, int pitch) +{ + int i; + uint32 temp, temp2; + uint8 *comp_ref_x = video->pintra_pred_top; + uint8 *comp_ref_y = video->pintra_pred_left; + int sum = 0; + uint8 *pred = video->pred_block; + int pred_pitch = video->pred_pitch; + + if (video->intraAvailB) + { + temp = *((uint32*)comp_ref_x); + comp_ref_x += 4; + temp2 = (temp >> 8) & 0xFF00FF; + temp &= 0xFF00FF; + temp += temp2; + sum = temp + (temp >> 16); + temp = *((uint32*)comp_ref_x); + comp_ref_x += 4; + temp2 = (temp >> 8) & 0xFF00FF; + temp &= 0xFF00FF; + temp += temp2; + sum += temp + (temp >> 16); + temp = *((uint32*)comp_ref_x); + comp_ref_x += 4; + temp2 = (temp >> 8) & 0xFF00FF; + temp &= 0xFF00FF; + temp += temp2; + sum += temp + (temp >> 16); + temp = *((uint32*)comp_ref_x); + comp_ref_x += 4; + temp2 = (temp >> 8) & 0xFF00FF; + temp &= 0xFF00FF; + temp += temp2; + sum += temp + (temp >> 16); + sum &= 0xFFFF; + + if (video->intraAvailA) + { + for (i = 0; i < 16; i++) + { + sum += (*comp_ref_y); + comp_ref_y += pitch; + } + sum = (sum + 16) >> 5; + } + else + { + sum = (sum + 8) >> 4; + } + } + else if (video->intraAvailA) + { + for (i = 0; i < 16; i++) + { + sum += *comp_ref_y; + comp_ref_y += pitch; + } + sum = (sum + 8) >> 4; + } + else + { + sum = 128; + } + + temp = sum | (sum << 8); + temp |= (temp << 16); + + for (i = 0; i < 16; i++) + { + *((uint32*)pred) = temp; + *((uint32*)(pred + 4)) = temp; + *((uint32*)(pred + 8)) = temp; + *((uint32*)(pred + 12)) = temp; + pred += pred_pitch; + } + +} + +void Intra_16x16_Plane(AVCCommonObj *video, int pitch) +{ + int i, a_16, b, c, factor_c; + uint8 *comp_ref_x = video->pintra_pred_top; + uint8 *comp_ref_y = video->pintra_pred_left; + uint8 *comp_ref_x0, *comp_ref_x1, *comp_ref_y0, *comp_ref_y1; + int H = 0, V = 0 , tmp; + uint8 *pred = video->pred_block; + uint32 temp; + uint8 byte1, byte2, byte3; + int value; + int pred_pitch = video->pred_pitch; + + comp_ref_x0 = comp_ref_x + 8; + comp_ref_x1 = comp_ref_x + 6; + comp_ref_y0 = comp_ref_y + (pitch << 3); + comp_ref_y1 = comp_ref_y + 6 * pitch; + + for (i = 1; i < 8; i++) + { + H += i * (*comp_ref_x0++ - *comp_ref_x1--); + V += i * (*comp_ref_y0 - *comp_ref_y1); + comp_ref_y0 += pitch; + comp_ref_y1 -= pitch; + } + + H += i * (*comp_ref_x0++ - video->intra_pred_topleft); + V += i * (*comp_ref_y0 - *comp_ref_y1); + + + a_16 = ((*(comp_ref_x + 15) + *(comp_ref_y + 15 * pitch)) << 4) + 16;; + b = (5 * H + 32) >> 6; + c = (5 * V + 32) >> 6; + + tmp = 0; + + for (i = 0; i < 16; i++) + { + factor_c = a_16 + c * (tmp++ - 7); + + factor_c -= 7 * b; + + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + byte1 = value; + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + byte2 = value; + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + byte3 = value; + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + temp = byte1 | (byte2 << 8); + temp |= (byte3 << 16); + temp |= (value << 24); + *((uint32*)pred) = temp; + + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + byte1 = value; + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + byte2 = value; + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + byte3 = value; + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + temp = byte1 | (byte2 << 8); + temp |= (byte3 << 16); + temp |= (value << 24); + *((uint32*)(pred + 4)) = temp; + + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + byte1 = value; + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + byte2 = value; + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + byte3 = value; + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + temp = byte1 | (byte2 << 8); + temp |= (byte3 << 16); + temp |= (value << 24); + *((uint32*)(pred + 8)) = temp; + + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + byte1 = value; + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + byte2 = value; + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + byte3 = value; + value = factor_c >> 5; + CLIP_RESULT(value) + temp = byte1 | (byte2 << 8); + temp |= (byte3 << 16); + temp |= (value << 24); + *((uint32*)(pred + 12)) = temp; + pred += pred_pitch; + } +} + +/************** Chroma intra prediction *********************/ + +void Intra_Chroma_DC(AVCCommonObj *video, int pitch, uint8 *predCb, uint8 *predCr) +{ + int i; + uint32 temp, temp2, pred_a, pred_b; + uint8 *comp_ref_x, *comp_ref_y; + uint8 *comp_ref_cb_x = video->pintra_pred_top_cb; + uint8 *comp_ref_cb_y = video->pintra_pred_left_cb; + uint8 *comp_ref_cr_x = video->pintra_pred_top_cr; + uint8 *comp_ref_cr_y = video->pintra_pred_left_cr; + int component, j; + int sum_x0, sum_x1, sum_y0, sum_y1; + int pred_0[2], pred_1[2], pred_2[2], pred_3[2]; + int pred_pitch = video->pred_pitch; + uint8 *pred; + + if (video->intraAvailB & video->intraAvailA) + { + comp_ref_x = comp_ref_cb_x; + comp_ref_y = comp_ref_cb_y; + for (i = 0; i < 2; i++) + { + temp = *((uint32*)comp_ref_x); + comp_ref_x += 4; + temp2 = (temp >> 8) & 0xFF00FF; + temp &= 0xFF00FF; + temp += temp2; + temp += (temp >> 16); + sum_x0 = temp & 0xFFFF; + + temp = *((uint32*)comp_ref_x); + temp2 = (temp >> 8) & 0xFF00FF; + temp &= 0xFF00FF; + temp += temp2; + temp += (temp >> 16); + sum_x1 = temp & 0xFFFF; + + pred_1[i] = (sum_x1 + 2) >> 2; + + sum_y0 = *comp_ref_y; + sum_y0 += *(comp_ref_y += pitch); + sum_y0 += *(comp_ref_y += pitch); + sum_y0 += *(comp_ref_y += pitch); + + sum_y1 = *(comp_ref_y += pitch); + sum_y1 += *(comp_ref_y += pitch); + sum_y1 += *(comp_ref_y += pitch); + sum_y1 += *(comp_ref_y += pitch); + + pred_2[i] = (sum_y1 + 2) >> 2; + + pred_0[i] = (sum_y0 + sum_x0 + 4) >> 3; + pred_3[i] = (sum_y1 + sum_x1 + 4) >> 3; + + comp_ref_x = comp_ref_cr_x; + comp_ref_y = comp_ref_cr_y; + } + } + + else if (video->intraAvailA) + { + comp_ref_y = comp_ref_cb_y; + for (i = 0; i < 2; i++) + { + sum_y0 = *comp_ref_y; + sum_y0 += *(comp_ref_y += pitch); + sum_y0 += *(comp_ref_y += pitch); + sum_y0 += *(comp_ref_y += pitch); + + sum_y1 = *(comp_ref_y += pitch); + sum_y1 += *(comp_ref_y += pitch); + sum_y1 += *(comp_ref_y += pitch); + sum_y1 += *(comp_ref_y += pitch); + + pred_0[i] = pred_1[i] = (sum_y0 + 2) >> 2; + pred_2[i] = pred_3[i] = (sum_y1 + 2) >> 2; + comp_ref_y = comp_ref_cr_y; + } + } + else if (video->intraAvailB) + { + comp_ref_x = comp_ref_cb_x; + for (i = 0; i < 2; i++) + { + temp = *((uint32*)comp_ref_x); + comp_ref_x += 4; + temp2 = (temp >> 8) & 0xFF00FF; + temp &= 0xFF00FF; + temp += temp2; + temp += (temp >> 16); + sum_x0 = temp & 0xFFFF; + + temp = *((uint32*)comp_ref_x); + temp2 = (temp >> 8) & 0xFF00FF; + temp &= 0xFF00FF; + temp += temp2; + temp += (temp >> 16); + sum_x1 = temp & 0xFFFF; + + pred_0[i] = pred_2[i] = (sum_x0 + 2) >> 2; + pred_1[i] = pred_3[i] = (sum_x1 + 2) >> 2; + comp_ref_x = comp_ref_cr_x; + } + } + else + { + pred_0[0] = pred_0[1] = pred_1[0] = pred_1[1] = + pred_2[0] = pred_2[1] = pred_3[0] = pred_3[1] = 128; + } + + pred = predCb; + for (component = 0; component < 2; component++) + { + pred_a = pred_0[component]; + pred_b = pred_1[component]; + pred_a |= (pred_a << 8); + pred_a |= (pred_a << 16); + pred_b |= (pred_b << 8); + pred_b |= (pred_b << 16); + + for (i = 4; i < 6; i++) + { + for (j = 0; j < 4; j++) /* 4 lines */ + { + *((uint32*)pred) = pred_a; + *((uint32*)(pred + 4)) = pred_b; + pred += pred_pitch; /* move to the next line */ + } + pred_a = pred_2[component]; + pred_b = pred_3[component]; + pred_a |= (pred_a << 8); + pred_a |= (pred_a << 16); + pred_b |= (pred_b << 8); + pred_b |= (pred_b << 16); + } + pred = predCr; /* point to cr */ + } +} + +void Intra_Chroma_Horizontal(AVCCommonObj *video, int pitch, uint8 *predCb, uint8 *predCr) +{ + int i; + uint32 temp; + uint8 *comp_ref_cb_y = video->pintra_pred_left_cb; + uint8 *comp_ref_cr_y = video->pintra_pred_left_cr; + uint8 *comp; + int component, j; + int pred_pitch = video->pred_pitch; + uint8 *pred; + + comp = comp_ref_cb_y; + pred = predCb; + for (component = 0; component < 2; component++) + { + for (i = 4; i < 6; i++) + { + for (j = 0; j < 4; j++) + { + temp = *comp; + comp += pitch; + temp |= (temp << 8); + temp |= (temp << 16); + *((uint32*)pred) = temp; + *((uint32*)(pred + 4)) = temp; + pred += pred_pitch; + } + } + comp = comp_ref_cr_y; + pred = predCr; /* point to cr */ + } + +} + +void Intra_Chroma_Vertical(AVCCommonObj *video, uint8 *predCb, uint8 *predCr) +{ + uint32 temp1, temp2; + uint8 *comp_ref_cb_x = video->pintra_pred_top_cb; + uint8 *comp_ref_cr_x = video->pintra_pred_top_cr; + uint8 *comp_ref; + int component, j; + int pred_pitch = video->pred_pitch; + uint8 *pred; + + comp_ref = comp_ref_cb_x; + pred = predCb; + for (component = 0; component < 2; component++) + { + temp1 = *((uint32*)comp_ref); + temp2 = *((uint32*)(comp_ref + 4)); + for (j = 0; j < 8; j++) + { + *((uint32*)pred) = temp1; + *((uint32*)(pred + 4)) = temp2; + pred += pred_pitch; + } + comp_ref = comp_ref_cr_x; + pred = predCr; /* point to cr */ + } + +} + +void Intra_Chroma_Plane(AVCCommonObj *video, int pitch, uint8 *predCb, uint8 *predCr) +{ + int i; + int a_16_C[2], b_C[2], c_C[2], a_16, b, c, factor_c; + uint8 *comp_ref_x, *comp_ref_y, *comp_ref_x0, *comp_ref_x1, *comp_ref_y0, *comp_ref_y1; + int component, j; + int H, V, tmp; + uint32 temp; + uint8 byte1, byte2, byte3; + int value; + uint8 topleft; + int pred_pitch = video->pred_pitch; + uint8 *pred; + + comp_ref_x = video->pintra_pred_top_cb; + comp_ref_y = video->pintra_pred_left_cb; + topleft = video->intra_pred_topleft_cb; + + for (component = 0; component < 2; component++) + { + H = V = 0; + comp_ref_x0 = comp_ref_x + 4; + comp_ref_x1 = comp_ref_x + 2; + comp_ref_y0 = comp_ref_y + (pitch << 2); + comp_ref_y1 = comp_ref_y + (pitch << 1); + for (i = 1; i < 4; i++) + { + H += i * (*comp_ref_x0++ - *comp_ref_x1--); + V += i * (*comp_ref_y0 - *comp_ref_y1); + comp_ref_y0 += pitch; + comp_ref_y1 -= pitch; + } + H += i * (*comp_ref_x0++ - topleft); + V += i * (*comp_ref_y0 - *comp_ref_y1); + + a_16_C[component] = ((*(comp_ref_x + 7) + *(comp_ref_y + 7 * pitch)) << 4) + 16; + b_C[component] = (17 * H + 16) >> 5; + c_C[component] = (17 * V + 16) >> 5; + + comp_ref_x = video->pintra_pred_top_cr; + comp_ref_y = video->pintra_pred_left_cr; + topleft = video->intra_pred_topleft_cr; + } + + pred = predCb; + for (component = 0; component < 2; component++) + { + a_16 = a_16_C[component]; + b = b_C[component]; + c = c_C[component]; + tmp = 0; + for (i = 4; i < 6; i++) + { + for (j = 0; j < 4; j++) + { + factor_c = a_16 + c * (tmp++ - 3); + + factor_c -= 3 * b; + + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + byte1 = value; + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + byte2 = value; + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + byte3 = value; + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + temp = byte1 | (byte2 << 8); + temp |= (byte3 << 16); + temp |= (value << 24); + *((uint32*)pred) = temp; + + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + byte1 = value; + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + byte2 = value; + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + byte3 = value; + value = factor_c >> 5; + factor_c += b; + CLIP_RESULT(value) + temp = byte1 | (byte2 << 8); + temp |= (byte3 << 16); + temp |= (value << 24); + *((uint32*)(pred + 4)) = temp; + pred += pred_pitch; + } + } + pred = predCr; /* point to cr */ + } +} + diff --git a/media/libstagefright/codecs/avc/dec/src/residual.cpp b/media/libstagefright/codecs/avc/dec/src/residual.cpp new file mode 100644 index 0000000..c68550d --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/src/residual.cpp @@ -0,0 +1,523 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 + +#include "avcdec_lib.h" +#include "avcdec_bitstream.h" + +AVCDec_Status DecodeIntraPCM(AVCCommonObj *video, AVCDecBitstream *stream) +{ + AVCDec_Status status; + int j; + int mb_x, mb_y, offset1; + uint8 *pDst; + uint32 byte0, byte1; + int pitch; + + mb_x = video->mb_x; + mb_y = video->mb_y; + +#ifdef USE_PRED_BLOCK + pDst = video->pred_block + 84; + pitch = 20; +#else + offset1 = (mb_x << 4) + (mb_y << 4) * video->PicWidthInSamplesL; + pDst = video->currPic->Sl + offset1; + pitch = video->currPic->pitch; +#endif + + /* at this point bitstream is byte-aligned */ + j = 16; + while (j > 0) + { + status = BitstreamReadBits(stream, 8, (uint*) & byte0); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 8); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 16); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 24); + *((uint32*)pDst) = byte0; + + status = BitstreamReadBits(stream, 8, (uint*) & byte0); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 8); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 16); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 24); + *((uint32*)(pDst + 4)) = byte0; + + status = BitstreamReadBits(stream, 8, (uint*) & byte0); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 8); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 16); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 24); + *((uint32*)(pDst + 8)) = byte0; + + status = BitstreamReadBits(stream, 8, (uint*) & byte0); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 8); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 16); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 24); + *((uint32*)(pDst + 12)) = byte0; + j--; + pDst += pitch; + + if (status != AVCDEC_SUCCESS) /* check only once per line */ + return status; + } + +#ifdef USE_PRED_BLOCK + pDst = video->pred_block + 452; + pitch = 12; +#else + offset1 = (offset1 >> 2) + (mb_x << 2); + pDst = video->currPic->Scb + offset1; + pitch >>= 1; +#endif + + j = 8; + while (j > 0) + { + status = BitstreamReadBits(stream, 8, (uint*) & byte0); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 8); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 16); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 24); + *((uint32*)pDst) = byte0; + + status = BitstreamReadBits(stream, 8, (uint*) & byte0); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 8); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 16); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 24); + *((uint32*)(pDst + 4)) = byte0; + + j--; + pDst += pitch; + + if (status != AVCDEC_SUCCESS) /* check only once per line */ + return status; + } + +#ifdef USE_PRED_BLOCK + pDst = video->pred_block + 596; + pitch = 12; +#else + pDst = video->currPic->Scr + offset1; +#endif + j = 8; + while (j > 0) + { + status = BitstreamReadBits(stream, 8, (uint*) & byte0); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 8); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 16); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 24); + *((uint32*)pDst) = byte0; + + status = BitstreamReadBits(stream, 8, (uint*) & byte0); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 8); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 16); + status = BitstreamReadBits(stream, 8, (uint*) & byte1); + byte0 |= (byte1 << 24); + *((uint32*)(pDst + 4)) = byte0; + + j--; + pDst += pitch; + + if (status != AVCDEC_SUCCESS) /* check only once per line */ + return status; + } + +#ifdef MB_BASED_DEBLOCK + SaveNeighborForIntraPred(video, offset1); +#endif + + return AVCDEC_SUCCESS; +} + + + +/* see subclause 7.3.5.3 and readCBPandCoeffsFromNAL() in JM*/ +AVCDec_Status residual(AVCDecObject *decvid, AVCMacroblock *currMB) +{ + AVCCommonObj *video = decvid->common; + int16 *block; + int level[16], run[16], numcoeff; /* output from residual_block_cavlc */ + int block_x, i, j, k, idx, iCbCr; + int mbPartIdx, subMbPartIdx, mbPartIdx_X, mbPartIdx_Y; + int nC, maxNumCoeff = 16; + int coeffNum, start_scan = 0; + uint8 *zz_scan; + int Rq, Qq; + uint32 cbp4x4 = 0; + + /* in 8.5.4, it only says if it's field macroblock. */ + + zz_scan = (uint8*) ZZ_SCAN_BLOCK; + + + /* see 8.5.8 for the initialization of these values */ + Qq = video->QPy_div_6; + Rq = video->QPy_mod_6; + + memset(video->block, 0, sizeof(int16)*NUM_PIXELS_IN_MB); + + if (currMB->mbMode == AVC_I16) + { + nC = predict_nnz(video, 0, 0); + decvid->residual_block(decvid, nC, 16, level, run, &numcoeff); + /* then performs zigzag and transform */ + block = video->block; + coeffNum = -1; + for (i = numcoeff - 1; i >= 0; i--) + { + coeffNum += run[i] + 1; + if (coeffNum > 15) + { + return AVCDEC_FAIL; + } + idx = zz_scan[coeffNum] << 2; + /* idx = ((idx>>2)<<6) + ((idx&3)<<2); */ + block[idx] = level[i]; + } + + /* inverse transform on Intra16x16DCLevel */ + if (numcoeff) + { + Intra16DCTrans(block, Qq, Rq); + cbp4x4 = 0xFFFF; + } + maxNumCoeff = 15; + start_scan = 1; + } + + memset(currMB->nz_coeff, 0, sizeof(uint8)*24); + + for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++) + { + mbPartIdx_X = (mbPartIdx & 1) << 1; + mbPartIdx_Y = mbPartIdx & -2; + + if (currMB->CBP&(1 << mbPartIdx)) + { + for (subMbPartIdx = 0; subMbPartIdx < 4; subMbPartIdx++) + { + i = mbPartIdx_X + (subMbPartIdx & 1); // check this + j = mbPartIdx_Y + (subMbPartIdx >> 1); + block = video->block + (j << 6) + (i << 2); // + nC = predict_nnz(video, i, j); + decvid->residual_block(decvid, nC, maxNumCoeff, level, run, &numcoeff); + + /* convert to raster scan and quantize*/ + /* Note: for P mb in SP slice and SI mb in SI slice, + the quantization cannot be done here. + block[idx] should be assigned with level[k]. + itrans will be done after the prediction. + There will be transformation on the predicted value, + then addition with block[idx], then this quantization + and transform.*/ + + coeffNum = -1 + start_scan; + for (k = numcoeff - 1; k >= 0; k--) + { + coeffNum += run[k] + 1; + if (coeffNum > 15) + { + return AVCDEC_FAIL; + } + idx = zz_scan[coeffNum]; + block[idx] = (level[k] * dequant_coefres[Rq][coeffNum]) << Qq ; + } + + currMB->nz_coeff[(j<<2)+i] = numcoeff; + if (numcoeff) + { + cbp4x4 |= (1 << ((j << 2) + i)); + } + } + } + } + + Qq = video->QPc_div_6; + Rq = video->QPc_mod_6; + + if (currMB->CBP & (3 << 4)) /* chroma DC residual present */ + { + for (iCbCr = 0; iCbCr < 2; iCbCr++) + { + decvid->residual_block(decvid, -1, 4, level, run, &numcoeff); + block = video->block + 256 + (iCbCr << 3); + coeffNum = -1; + for (i = numcoeff - 1; i >= 0; i--) + { + coeffNum += run[i] + 1; + if (coeffNum > 3) + { + return AVCDEC_FAIL; + } + block[(coeffNum>>1)*64 + (coeffNum&1)*4] = level[i]; + } + /* inverse transform on chroma DC */ + /* for P in SP and SI in SI, this function can't be done here, + must do prediction transform/quant first. */ + if (numcoeff) + { + ChromaDCTrans(block, Qq, Rq); + cbp4x4 |= (iCbCr ? 0xcc0000 : 0x330000); + } + } + } + + if (currMB->CBP & (2 << 4)) + { + for (block_x = 0; block_x < 4; block_x += 2) /* for iCbCr */ + { + for (j = 4; j < 6; j++) /* for each block inside Cb or Cr */ + { + for (i = block_x; i < block_x + 2; i++) + { + + block = video->block + (j << 6) + (i << 2); + + nC = predict_nnz_chroma(video, i, j); + decvid->residual_block(decvid, nC, 15, level, run, &numcoeff); + + /* convert to raster scan and quantize */ + /* for P MB in SP slice and SI MB in SI slice, + the dequant and transform cannot be done here. + It needs the prediction values. */ + coeffNum = 0; + for (k = numcoeff - 1; k >= 0; k--) + { + coeffNum += run[k] + 1; + if (coeffNum > 15) + { + return AVCDEC_FAIL; + } + idx = zz_scan[coeffNum]; + block[idx] = (level[k] * dequant_coefres[Rq][coeffNum]) << Qq; + } + + + /* then transform */ + // itrans(block); /* transform */ + currMB->nz_coeff[(j<<2)+i] = numcoeff; // + if (numcoeff) + { + cbp4x4 |= (1 << ((j << 2) + i)); + } + } + + } + } + } + + video->cbp4x4 = cbp4x4; + + return AVCDEC_SUCCESS; +} + +/* see subclause 7.3.5.3.1 and 9.2 and readCoeff4x4_CAVLC() in JM */ +AVCDec_Status residual_block_cavlc(AVCDecObject *decvid, int nC, int maxNumCoeff, + int *level, int *run, int *numcoeff) +{ + int i, j; + int TrailingOnes, TotalCoeff; + AVCDecBitstream *stream = decvid->bitstream; + int suffixLength; + uint trailing_ones_sign_flag, level_prefix, level_suffix; + int levelCode, levelSuffixSize, zerosLeft; + int run_before; + + + if (nC >= 0) + { + ce_TotalCoeffTrailingOnes(stream, &TrailingOnes, &TotalCoeff, nC); + } + else + { + ce_TotalCoeffTrailingOnesChromaDC(stream, &TrailingOnes, &TotalCoeff); + } + + *numcoeff = TotalCoeff; + + /* This part is done quite differently in ReadCoef4x4_CAVLC() */ + if (TotalCoeff == 0) + { + return AVCDEC_SUCCESS; + } + + if (TrailingOnes) /* keep reading the sign of those trailing ones */ + { + /* instead of reading one bit at a time, read the whole thing at once */ + BitstreamReadBits(stream, TrailingOnes, &trailing_ones_sign_flag); + trailing_ones_sign_flag <<= 1; + for (i = 0; i < TrailingOnes; i++) + { + level[i] = 1 - ((trailing_ones_sign_flag >> (TrailingOnes - i - 1)) & 2); + } + } + + i = TrailingOnes; + suffixLength = 1; + if (TotalCoeff > TrailingOnes) + { + ce_LevelPrefix(stream, &level_prefix); + if (TotalCoeff < 11 || TrailingOnes == 3) + { + if (level_prefix < 14) + { +// levelSuffixSize = 0; + levelCode = level_prefix; + } + else if (level_prefix == 14) + { +// levelSuffixSize = 4; + BitstreamReadBits(stream, 4, &level_suffix); + levelCode = 14 + level_suffix; + } + else /* if (level_prefix == 15) */ + { +// levelSuffixSize = 12; + BitstreamReadBits(stream, 12, &level_suffix); + levelCode = 30 + level_suffix; + } + } + else + { + /* suffixLength = 1; */ + if (level_prefix < 15) + { + levelSuffixSize = suffixLength; + } + else + { + levelSuffixSize = 12; + } + BitstreamReadBits(stream, levelSuffixSize, &level_suffix); + + levelCode = (level_prefix << 1) + level_suffix; + } + + if (TrailingOnes < 3) + { + levelCode += 2; + } + + level[i] = (levelCode + 2) >> 1; + if (level[i] > 3) + { + suffixLength = 2; + } + + if (levelCode & 1) + { + level[i] = -level[i]; + } + i++; + + } + + for (j = TotalCoeff - i; j > 0 ; j--) + { + ce_LevelPrefix(stream, &level_prefix); + if (level_prefix < 15) + { + levelSuffixSize = suffixLength; + } + else + { + levelSuffixSize = 12; + } + BitstreamReadBits(stream, levelSuffixSize, &level_suffix); + + levelCode = (level_prefix << suffixLength) + level_suffix; + level[i] = (levelCode >> 1) + 1; + if (level[i] > (3 << (suffixLength - 1)) && suffixLength < 6) + { + suffixLength++; + } + if (levelCode & 1) + { + level[i] = -level[i]; + } + i++; + } + + + if (TotalCoeff < maxNumCoeff) + { + if (nC >= 0) + { + ce_TotalZeros(stream, &zerosLeft, TotalCoeff); + } + else + { + ce_TotalZerosChromaDC(stream, &zerosLeft, TotalCoeff); + } + } + else + { + zerosLeft = 0; + } + + for (i = 0; i < TotalCoeff - 1; i++) + { + if (zerosLeft > 0) + { + ce_RunBefore(stream, &run_before, zerosLeft); + run[i] = run_before; + } + else + { + run[i] = 0; + zerosLeft = 0; // could be negative under error conditions + } + + zerosLeft = zerosLeft - run[i]; + } + + if (zerosLeft < 0) + { + zerosLeft = 0; +// return AVCDEC_FAIL; + } + + run[TotalCoeff-1] = zerosLeft; + + /* leave the inverse zigzag scan part for the caller */ + + + return AVCDEC_SUCCESS; +} diff --git a/media/libstagefright/codecs/avc/dec/src/slice.cpp b/media/libstagefright/codecs/avc/dec/src/slice.cpp new file mode 100644 index 0000000..7a2ef3d --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/src/slice.cpp @@ -0,0 +1,772 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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. + * ------------------------------------------------------------------- + */ +/* Note for optimization: syntax decoding or operations related to B_SLICE should be +commented out by macro definition or function pointers. */ + +#include + +#include "avcdec_lib.h" +#include "avcdec_bitstream.h" + +const static int mbPart2raster[3][4] = {{0, 0, 0, 0}, {1, 1, 0, 0}, {1, 0, 1, 0}}; +/* decode_frame_slice() */ +/* decode_one_slice() */ +AVCDec_Status DecodeSlice(AVCDecObject *decvid) +{ + AVCDec_Status status; + AVCCommonObj *video = decvid->common; + AVCSliceHeader *sliceHdr = video->sliceHdr; + AVCMacroblock *currMB ; + AVCDecBitstream *stream = decvid->bitstream; + uint slice_group_id; + uint CurrMbAddr, moreDataFlag; + + /* set the first mb in slice */ + CurrMbAddr = sliceHdr->first_mb_in_slice; + slice_group_id = video->MbToSliceGroupMap[CurrMbAddr]; + + if ((CurrMbAddr && (CurrMbAddr != (uint)(video->mbNum + 1))) && video->currSeqParams->constrained_set1_flag == 1) + { + ConcealSlice(decvid, video->mbNum, CurrMbAddr); + } + + moreDataFlag = 1; + video->mb_skip_run = -1; + + + /* while loop , see subclause 7.3.4 */ + do + { + if (CurrMbAddr >= video->PicSizeInMbs) + { + return AVCDEC_FAIL; + } + + currMB = video->currMB = &(video->mblock[CurrMbAddr]); + video->mbNum = CurrMbAddr; + currMB->slice_id = video->slice_id; // slice + + /* we can remove this check if we don't support Mbaff. */ + /* we can wrap below into an initMB() function which will also + do necessary reset of macroblock related parameters. */ + + video->mb_x = CurrMbAddr % video->PicWidthInMbs; + video->mb_y = CurrMbAddr / video->PicWidthInMbs; + + /* check the availability of neighboring macroblocks */ + InitNeighborAvailability(video, CurrMbAddr); + + /* read_macroblock and decode_one_macroblock() */ + status = DecodeMB(decvid); + if (status != AVCDEC_SUCCESS) + { + return status; + } +#ifdef MB_BASED_DEBLOCK + if (video->currPicParams->num_slice_groups_minus1 == 0) + { + MBInLoopDeblock(video); /* MB-based deblocking */ + } + else /* this mode cannot be used if the number of slice group is not one. */ + { + return AVCDEC_FAIL; + } +#endif + video->numMBs--; + + moreDataFlag = more_rbsp_data(stream); + + + /* go to next MB */ + while (++CurrMbAddr < video->PicSizeInMbs && video->MbToSliceGroupMap[CurrMbAddr] != (int)slice_group_id) + { + } + + } + while ((moreDataFlag && video->numMBs > 0) || video->mb_skip_run > 0); /* even if no more data, but last few MBs are skipped */ + + if (video->numMBs == 0) + { + video->newPic = TRUE; + video->mbNum = 0; // _Conceal + return AVCDEC_PICTURE_READY; + } + + return AVCDEC_SUCCESS; +} + +/* read MB mode and motion vectors */ +/* perform Intra/Inter prediction and residue */ +/* update video->mb_skip_run */ +AVCDec_Status DecodeMB(AVCDecObject *decvid) +{ + AVCDec_Status status; + AVCCommonObj *video = decvid->common; + AVCDecBitstream *stream = decvid->bitstream; + AVCMacroblock *currMB = video->currMB; + uint mb_type; + int slice_type = video->slice_type; + int temp; + + currMB->QPy = video->QPy; + currMB->QPc = video->QPc; + + if (slice_type == AVC_P_SLICE) + { + if (video->mb_skip_run < 0) + { + ue_v(stream, (uint *)&(video->mb_skip_run)); + } + + if (video->mb_skip_run == 0) + { + /* this will not handle the case where the slice ends with a mb_skip_run == 0 and no following MB data */ + ue_v(stream, &mb_type); + if (mb_type > 30) + { + return AVCDEC_FAIL; + } + InterpretMBModeP(currMB, mb_type); + video->mb_skip_run = -1; + } + else + { + /* see subclause 7.4.4 for more details on how + mb_field_decoding_flag is derived in case of skipped MB */ + + currMB->mb_intra = FALSE; + + currMB->mbMode = AVC_SKIP; + currMB->MbPartWidth = currMB->MbPartHeight = 16; + currMB->NumMbPart = 1; + currMB->NumSubMbPart[0] = currMB->NumSubMbPart[1] = + currMB->NumSubMbPart[2] = currMB->NumSubMbPart[3] = 1; // + currMB->SubMbPartWidth[0] = currMB->SubMbPartWidth[1] = + currMB->SubMbPartWidth[2] = currMB->SubMbPartWidth[3] = currMB->MbPartWidth; + currMB->SubMbPartHeight[0] = currMB->SubMbPartHeight[1] = + currMB->SubMbPartHeight[2] = currMB->SubMbPartHeight[3] = currMB->MbPartHeight; + + memset(currMB->nz_coeff, 0, sizeof(uint8)*NUM_BLKS_IN_MB); + + currMB->CBP = 0; + video->cbp4x4 = 0; + /* for skipped MB, always look at the first entry in RefPicList */ + currMB->RefIdx[0] = currMB->RefIdx[1] = + currMB->RefIdx[2] = currMB->RefIdx[3] = video->RefPicList0[0]->RefIdx; + InterMBPrediction(video); + video->mb_skip_run--; + return AVCDEC_SUCCESS; + } + + } + else + { + /* Then decode mode and MV */ + ue_v(stream, &mb_type); + if (mb_type > 25) + { + return AVCDEC_FAIL; + } + InterpretMBModeI(currMB, mb_type); + } + + + if (currMB->mbMode != AVC_I_PCM) + { + + if (currMB->mbMode == AVC_P8 || currMB->mbMode == AVC_P8ref0) + { + status = sub_mb_pred(video, currMB, stream); + } + else + { + status = mb_pred(video, currMB, stream) ; + } + + if (status != AVCDEC_SUCCESS) + { + return status; + } + + if (currMB->mbMode != AVC_I16) + { + /* decode coded_block_pattern */ + status = DecodeCBP(currMB, stream); + if (status != AVCDEC_SUCCESS) + { + return status; + } + } + + if (currMB->CBP > 0 || currMB->mbMode == AVC_I16) + { + se_v(stream, &temp); + if (temp) + { + temp += (video->QPy + 52); + currMB->QPy = video->QPy = temp - 52 * (temp * 79 >> 12); + if (currMB->QPy > 51 || currMB->QPy < 0) + { + video->QPy = AVC_CLIP3(0, 51, video->QPy); +// return AVCDEC_FAIL; + } + video->QPy_div_6 = (video->QPy * 43) >> 8; + video->QPy_mod_6 = video->QPy - 6 * video->QPy_div_6; + currMB->QPc = video->QPc = mapQPi2QPc[AVC_CLIP3(0, 51, video->QPy + video->currPicParams->chroma_qp_index_offset)]; + video->QPc_div_6 = (video->QPc * 43) >> 8; + video->QPc_mod_6 = video->QPc - 6 * video->QPc_div_6; + } + } + /* decode residue and inverse transform */ + status = residual(decvid, currMB); + if (status != AVCDEC_SUCCESS) + { + return status; + } + } + else + { + if (stream->bitcnt & 7) + { + BitstreamByteAlign(stream); + } + /* decode pcm_byte[i] */ + DecodeIntraPCM(video, stream); + + currMB->QPy = 0; /* necessary for deblocking */ // _OPTIMIZE + currMB->QPc = mapQPi2QPc[AVC_CLIP3(0, 51, video->currPicParams->chroma_qp_index_offset)]; + + /* default values, don't know if really needed */ + currMB->CBP = 0x3F; + video->cbp4x4 = 0xFFFF; + currMB->mb_intra = TRUE; + memset(currMB->nz_coeff, 16, sizeof(uint8)*NUM_BLKS_IN_MB); + return AVCDEC_SUCCESS; + } + + + /* do Intra/Inter prediction, together with the residue compensation */ + /* This part should be common between the skip and no-skip */ + if (currMB->mbMode == AVC_I4 || currMB->mbMode == AVC_I16) + { + IntraMBPrediction(video); + } + else + { + InterMBPrediction(video); + } + + + + return AVCDEC_SUCCESS; +} + +/* see subclause 7.3.5.1 */ +AVCDec_Status mb_pred(AVCCommonObj *video, AVCMacroblock *currMB, AVCDecBitstream *stream) +{ + int mbPartIdx; + AVCSliceHeader *sliceHdr = video->sliceHdr; + uint max_ref_idx; + const int *temp_0; + int16 *temp_1; + uint code; + + if (currMB->mbMode == AVC_I4 || currMB->mbMode == AVC_I16) + { + + video->intraAvailA = video->intraAvailB = video->intraAvailC = video->intraAvailD = 0; + + if (!video->currPicParams->constrained_intra_pred_flag) + { + video->intraAvailA = video->mbAvailA; + video->intraAvailB = video->mbAvailB; + video->intraAvailC = video->mbAvailC; + video->intraAvailD = video->mbAvailD; + } + else + { + if (video->mbAvailA) + { + video->intraAvailA = video->mblock[video->mbAddrA].mb_intra; + } + if (video->mbAvailB) + { + video->intraAvailB = video->mblock[video->mbAddrB].mb_intra ; + } + if (video->mbAvailC) + { + video->intraAvailC = video->mblock[video->mbAddrC].mb_intra; + } + if (video->mbAvailD) + { + video->intraAvailD = video->mblock[video->mbAddrD].mb_intra; + } + } + + + if (currMB->mbMode == AVC_I4) + { + /* perform prediction to get the actual intra 4x4 pred mode */ + DecodeIntra4x4Mode(video, currMB, stream); + /* output will be in currMB->i4Mode[4][4] */ + } + + ue_v(stream, &code); + + if (code > 3) + { + return AVCDEC_FAIL; /* out of range */ + } + currMB->intra_chroma_pred_mode = (AVCIntraChromaPredMode)code; + } + else + { + + memset(currMB->ref_idx_L0, 0, sizeof(int16)*4); + + /* see subclause 7.4.5.1 for the range of ref_idx_lX */ +// max_ref_idx = sliceHdr->num_ref_idx_l0_active_minus1; + max_ref_idx = video->refList0Size - 1; + + /* decode ref index for L0 */ + if (sliceHdr->num_ref_idx_l0_active_minus1 > 0) + { + for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++) + { + te_v(stream, &code, max_ref_idx); + if (code > (uint)max_ref_idx) + { + return AVCDEC_FAIL; + } + currMB->ref_idx_L0[mbPartIdx] = code; + } + } + + /* populate ref_idx_L0 */ + temp_0 = &mbPart2raster[currMB->mbMode-AVC_P16][0]; + temp_1 = &currMB->ref_idx_L0[3]; + + *temp_1-- = currMB->ref_idx_L0[*temp_0++]; + *temp_1-- = currMB->ref_idx_L0[*temp_0++]; + *temp_1-- = currMB->ref_idx_L0[*temp_0++]; + *temp_1-- = currMB->ref_idx_L0[*temp_0++]; + + /* Global reference index, these values are used in deblock */ + currMB->RefIdx[0] = video->RefPicList0[currMB->ref_idx_L0[0]]->RefIdx; + currMB->RefIdx[1] = video->RefPicList0[currMB->ref_idx_L0[1]]->RefIdx; + currMB->RefIdx[2] = video->RefPicList0[currMB->ref_idx_L0[2]]->RefIdx; + currMB->RefIdx[3] = video->RefPicList0[currMB->ref_idx_L0[3]]->RefIdx; + + /* see subclause 7.4.5.1 for the range of ref_idx_lX */ + max_ref_idx = sliceHdr->num_ref_idx_l1_active_minus1; + /* decode mvd_l0 */ + for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++) + { + se_v(stream, &(video->mvd_l0[mbPartIdx][0][0])); + se_v(stream, &(video->mvd_l0[mbPartIdx][0][1])); + } + } + + return AVCDEC_SUCCESS; +} + +/* see subclause 7.3.5.2 */ +AVCDec_Status sub_mb_pred(AVCCommonObj *video, AVCMacroblock *currMB, AVCDecBitstream *stream) +{ + int mbPartIdx, subMbPartIdx; + AVCSliceHeader *sliceHdr = video->sliceHdr; + uint max_ref_idx; + uint sub_mb_type[4]; + uint code; + + memset(currMB->ref_idx_L0, 0, sizeof(int16)*4); + + for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++) + { + ue_v(stream, &(sub_mb_type[mbPartIdx])); + if (sub_mb_type[mbPartIdx] > 3) + { + return AVCDEC_FAIL; + } + + } + /* we have to check the values to make sure they are valid */ + /* assign values to currMB->sub_mb_type[], currMB->MBPartPredMode[][x] */ + + InterpretSubMBModeP(currMB, sub_mb_type); + + + /* see subclause 7.4.5.1 for the range of ref_idx_lX */ +// max_ref_idx = sliceHdr->num_ref_idx_l0_active_minus1; + max_ref_idx = video->refList0Size - 1; + + if (sliceHdr->num_ref_idx_l0_active_minus1 > 0 && currMB->mbMode != AVC_P8ref0) + { + for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++) + { + te_v(stream, (uint*)&code, max_ref_idx); + if (code > max_ref_idx) + { + return AVCDEC_FAIL; + } + currMB->ref_idx_L0[mbPartIdx] = code; + } + } + /* see subclause 7.4.5.1 for the range of ref_idx_lX */ + + max_ref_idx = sliceHdr->num_ref_idx_l1_active_minus1; + /* if(video->MbaffFrameFlag && currMB->mb_field_decoding_flag) + max_ref_idx = 2*sliceHdr->num_ref_idx_l1_active_minus1 + 1;*/ + for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++) + { + for (subMbPartIdx = 0; subMbPartIdx < currMB->NumSubMbPart[mbPartIdx]; subMbPartIdx++) + { + se_v(stream, &(video->mvd_l0[mbPartIdx][subMbPartIdx][0])); + se_v(stream, &(video->mvd_l0[mbPartIdx][subMbPartIdx][1])); + } + /* used in deblocking */ + currMB->RefIdx[mbPartIdx] = video->RefPicList0[currMB->ref_idx_L0[mbPartIdx]]->RefIdx; + } + return AVCDEC_SUCCESS; +} + +void InterpretMBModeI(AVCMacroblock *mblock, uint mb_type) +{ + mblock->NumMbPart = 1; + + mblock->mb_intra = TRUE; + + if (mb_type == 0) /* I_4x4 */ + { + mblock->mbMode = AVC_I4; + } + else if (mb_type < 25) /* I_PCM */ + { + mblock->mbMode = AVC_I16; + mblock->i16Mode = (AVCIntra16x16PredMode)((mb_type - 1) & 0x3); + if (mb_type > 12) + { + mblock->CBP = (((mb_type - 13) >> 2) << 4) + 0x0F; + } + else + { + mblock->CBP = ((mb_type - 1) >> 2) << 4; + } + } + else + { + mblock->mbMode = AVC_I_PCM; + } + + return ; +} + +void InterpretMBModeP(AVCMacroblock *mblock, uint mb_type) +{ + const static int map2PartWidth[5] = {16, 16, 8, 8, 8}; + const static int map2PartHeight[5] = {16, 8, 16, 8, 8}; + const static int map2NumPart[5] = {1, 2, 2, 4, 4}; + const static AVCMBMode map2mbMode[5] = {AVC_P16, AVC_P16x8, AVC_P8x16, AVC_P8, AVC_P8ref0}; + + mblock->mb_intra = FALSE; + if (mb_type < 5) + { + mblock->mbMode = map2mbMode[mb_type]; + mblock->MbPartWidth = map2PartWidth[mb_type]; + mblock->MbPartHeight = map2PartHeight[mb_type]; + mblock->NumMbPart = map2NumPart[mb_type]; + mblock->NumSubMbPart[0] = mblock->NumSubMbPart[1] = + mblock->NumSubMbPart[2] = mblock->NumSubMbPart[3] = 1; + mblock->SubMbPartWidth[0] = mblock->SubMbPartWidth[1] = + mblock->SubMbPartWidth[2] = mblock->SubMbPartWidth[3] = mblock->MbPartWidth; + mblock->SubMbPartHeight[0] = mblock->SubMbPartHeight[1] = + mblock->SubMbPartHeight[2] = mblock->SubMbPartHeight[3] = mblock->MbPartHeight; + } + else + { + InterpretMBModeI(mblock, mb_type - 5); + /* set MV and Ref_Idx codes of Intra blocks in P-slices */ + memset(mblock->mvL0, 0, sizeof(int32)*16); + mblock->ref_idx_L0[0] = mblock->ref_idx_L0[1] = mblock->ref_idx_L0[2] = mblock->ref_idx_L0[3] = -1; + } + return ; +} + +void InterpretMBModeB(AVCMacroblock *mblock, uint mb_type) +{ + const static int map2PartWidth[23] = {8, 16, 16, 16, 16, 8, 16, 8, 16, 8, + 16, 8, 16, 8, 16, 8, 16, 8, 16, 8, 16, 8, 8 + }; + const static int map2PartHeight[23] = {8, 16, 16, 16, 8, 16, 8, 16, 8, + 16, 8, 16, 8, 16, 8, 16, 8, 16, 8, 16, 8, 16, 8 + }; + /* see enum AVCMBType declaration */ + const static AVCMBMode map2mbMode[23] = {AVC_BDirect16, AVC_P16, AVC_P16, AVC_P16, + AVC_P16x8, AVC_P8x16, AVC_P16x8, AVC_P8x16, AVC_P16x8, AVC_P8x16, + AVC_P16x8, AVC_P8x16, AVC_P16x8, AVC_P8x16, AVC_P16x8, AVC_P8x16, + AVC_P16x8, AVC_P8x16, AVC_P16x8, AVC_P8x16, AVC_P16x8, AVC_P8x16, AVC_P8 + }; + const static int map2PredMode1[23] = {3, 0, 1, 2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 2, 2, 2, 2, -1}; + const static int map2PredMode2[23] = { -1, -1, -1, -1, 0, 0, 1, 1, 1, 1, 0, 0, 2, 2, 2, 2, 0, 0, 1, 1, 2, 2, -1}; + const static int map2NumPart[23] = { -1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4}; + + mblock->mb_intra = FALSE; + + if (mb_type < 23) + { + mblock->mbMode = map2mbMode[mb_type]; + mblock->NumMbPart = map2NumPart[mb_type]; + mblock->MBPartPredMode[0][0] = (AVCPredMode)map2PredMode1[mb_type]; + if (mblock->NumMbPart > 1) + { + mblock->MBPartPredMode[1][0] = (AVCPredMode)map2PredMode2[mb_type]; + } + mblock->MbPartWidth = map2PartWidth[mb_type]; + mblock->MbPartHeight = map2PartHeight[mb_type]; + } + else + { + InterpretMBModeI(mblock, mb_type - 23); + } + + return ; +} + +void InterpretMBModeSI(AVCMacroblock *mblock, uint mb_type) +{ + mblock->mb_intra = TRUE; + + if (mb_type == 0) + { + mblock->mbMode = AVC_SI4; + /* other values are N/A */ + } + else + { + InterpretMBModeI(mblock, mb_type - 1); + } + return ; +} + +/* input is mblock->sub_mb_type[] */ +void InterpretSubMBModeP(AVCMacroblock *mblock, uint *sub_mb_type) +{ + int i, sub_type; + /* see enum AVCMBType declaration */ +// const static AVCSubMBMode map2subMbMode[4] = {AVC_8x8,AVC_8x4,AVC_4x8,AVC_4x4}; + const static int map2subPartWidth[4] = {8, 8, 4, 4}; + const static int map2subPartHeight[4] = {8, 4, 8, 4}; + const static int map2numSubPart[4] = {1, 2, 2, 4}; + + for (i = 0; i < 4 ; i++) + { + sub_type = (int) sub_mb_type[i]; + // mblock->subMbMode[i] = map2subMbMode[sub_type]; + mblock->NumSubMbPart[i] = map2numSubPart[sub_type]; + mblock->SubMbPartWidth[i] = map2subPartWidth[sub_type]; + mblock->SubMbPartHeight[i] = map2subPartHeight[sub_type]; + } + + return ; +} + +void InterpretSubMBModeB(AVCMacroblock *mblock, uint *sub_mb_type) +{ + int i, j, sub_type; + /* see enum AVCMBType declaration */ + const static AVCSubMBMode map2subMbMode[13] = {AVC_BDirect8, AVC_8x8, AVC_8x8, + AVC_8x8, AVC_8x4, AVC_4x8, AVC_8x4, AVC_4x8, AVC_8x4, AVC_4x8, AVC_4x4, AVC_4x4, AVC_4x4 + }; + const static int map2subPartWidth[13] = {4, 8, 8, 8, 8, 4, 8, 4, 8, 4, 4, 4, 4}; + const static int map2subPartHeight[13] = {4, 8, 8, 8, 4, 8, 4, 8, 4, 8, 4, 4, 4}; + const static int map2numSubPart[13] = {1, 1, 1, 2, 2, 2, 2, 2, 2, 4, 4, 4}; + const static int map2predMode[13] = {3, 0, 1, 2, 0, 0, 1, 1, 2, 2, 0, 1, 2}; + + for (i = 0; i < 4 ; i++) + { + sub_type = (int) sub_mb_type[i]; + mblock->subMbMode[i] = map2subMbMode[sub_type]; + mblock->NumSubMbPart[i] = map2numSubPart[sub_type]; + mblock->SubMbPartWidth[i] = map2subPartWidth[sub_type]; + mblock->SubMbPartHeight[i] = map2subPartHeight[sub_type]; + for (j = 0; j < 4; j++) + { + mblock->MBPartPredMode[i][j] = (AVCPredMode)map2predMode[sub_type]; + } + } + + return ; +} + +/* see subclause 8.3.1 */ +AVCDec_Status DecodeIntra4x4Mode(AVCCommonObj *video, AVCMacroblock *currMB, AVCDecBitstream *stream) +{ + int intra4x4PredModeA = 0, intra4x4PredModeB = 0, predIntra4x4PredMode = 0; + int component, SubBlock_indx, block_x, block_y; + int dcOnlyPredictionFlag; + uint prev_intra4x4_pred_mode_flag[16]; + int rem_intra4x4_pred_mode[16]; + int bindx = 0; + + for (component = 0; component < 4; component++) /* partition index */ + { + block_x = ((component & 1) << 1); + block_y = ((component >> 1) << 1); + + for (SubBlock_indx = 0; SubBlock_indx < 4; SubBlock_indx++) /* sub-partition index */ + { + BitstreamRead1Bit(stream, &(prev_intra4x4_pred_mode_flag[bindx])); + + if (!prev_intra4x4_pred_mode_flag[bindx]) + { + BitstreamReadBits(stream, 3, (uint*)&(rem_intra4x4_pred_mode[bindx])); + } + + dcOnlyPredictionFlag = 0; + if (block_x > 0) + { + intra4x4PredModeA = currMB->i4Mode[(block_y << 2) + block_x - 1 ]; + } + else + { + if (video->intraAvailA) + { + if (video->mblock[video->mbAddrA].mbMode == AVC_I4) + { + intra4x4PredModeA = video->mblock[video->mbAddrA].i4Mode[(block_y << 2) + 3]; + } + else + { + intra4x4PredModeA = AVC_I4_DC; + } + } + else + { + dcOnlyPredictionFlag = 1; + } + } + + if (block_y > 0) + { + intra4x4PredModeB = currMB->i4Mode[((block_y-1) << 2) + block_x]; + } + else + { + if (video->intraAvailB) + { + if (video->mblock[video->mbAddrB].mbMode == AVC_I4) + { + intra4x4PredModeB = video->mblock[video->mbAddrB].i4Mode[(3 << 2) + block_x]; + } + else + { + intra4x4PredModeB = AVC_I4_DC; + } + } + else + { + dcOnlyPredictionFlag = 1; + } + } + + if (dcOnlyPredictionFlag) + { + intra4x4PredModeA = intra4x4PredModeB = AVC_I4_DC; + } + + predIntra4x4PredMode = AVC_MIN(intra4x4PredModeA, intra4x4PredModeB); + if (prev_intra4x4_pred_mode_flag[bindx]) + { + currMB->i4Mode[(block_y<<2)+block_x] = (AVCIntra4x4PredMode)predIntra4x4PredMode; + } + else + { + if (rem_intra4x4_pred_mode[bindx] < predIntra4x4PredMode) + { + currMB->i4Mode[(block_y<<2)+block_x] = (AVCIntra4x4PredMode)rem_intra4x4_pred_mode[bindx]; + } + else + { + currMB->i4Mode[(block_y<<2)+block_x] = (AVCIntra4x4PredMode)(rem_intra4x4_pred_mode[bindx] + 1); + } + } + bindx++; + block_y += (SubBlock_indx & 1) ; + block_x += (1 - 2 * (SubBlock_indx & 1)) ; + } + } + return AVCDEC_SUCCESS; +} +AVCDec_Status ConcealSlice(AVCDecObject *decvid, int mbnum_start, int mbnum_end) +{ + AVCCommonObj *video = decvid->common; + AVCMacroblock *currMB ; + + int CurrMbAddr; + + if (video->RefPicList0[0] == NULL) + { + return AVCDEC_FAIL; + } + + for (CurrMbAddr = mbnum_start; CurrMbAddr < mbnum_end; CurrMbAddr++) + { + currMB = video->currMB = &(video->mblock[CurrMbAddr]); + video->mbNum = CurrMbAddr; + currMB->slice_id = video->slice_id++; // slice + + /* we can remove this check if we don't support Mbaff. */ + /* we can wrap below into an initMB() function which will also + do necessary reset of macroblock related parameters. */ + + video->mb_x = CurrMbAddr % video->PicWidthInMbs; + video->mb_y = CurrMbAddr / video->PicWidthInMbs; + + /* check the availability of neighboring macroblocks */ + InitNeighborAvailability(video, CurrMbAddr); + + currMB->mb_intra = FALSE; + + currMB->mbMode = AVC_SKIP; + currMB->MbPartWidth = currMB->MbPartHeight = 16; + + currMB->NumMbPart = 1; + currMB->NumSubMbPart[0] = currMB->NumSubMbPart[1] = + currMB->NumSubMbPart[2] = currMB->NumSubMbPart[3] = 1; + currMB->SubMbPartWidth[0] = currMB->SubMbPartWidth[1] = + currMB->SubMbPartWidth[2] = currMB->SubMbPartWidth[3] = currMB->MbPartWidth; + currMB->SubMbPartHeight[0] = currMB->SubMbPartHeight[1] = + currMB->SubMbPartHeight[2] = currMB->SubMbPartHeight[3] = currMB->MbPartHeight; + currMB->QPy = 26; + currMB->QPc = 26; + memset(currMB->nz_coeff, 0, sizeof(uint8)*NUM_BLKS_IN_MB); + + currMB->CBP = 0; + video->cbp4x4 = 0; + /* for skipped MB, always look at the first entry in RefPicList */ + currMB->RefIdx[0] = currMB->RefIdx[1] = + currMB->RefIdx[2] = currMB->RefIdx[3] = video->RefPicList0[0]->RefIdx; + InterMBPrediction(video); + + video->numMBs--; + + } + + return AVCDEC_SUCCESS; +} + diff --git a/media/libstagefright/codecs/avc/dec/src/vlc.cpp b/media/libstagefright/codecs/avc/dec/src/vlc.cpp new file mode 100644 index 0000000..f531249 --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/src/vlc.cpp @@ -0,0 +1,815 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * 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 "avcdec_lib.h" +#include "avcdec_bitstream.h" + +//#define PV_ARM_V5 +#ifdef PV_ARM_V5 +#define PV_CLZ(A,B) __asm{CLZ (A),(B)} \ + A -= 16; +#else +#define PV_CLZ(A,B) while (((B) & 0x8000) == 0) {(B) <<=1; A++;} +#endif + + +#define PV_NO_CLZ + +#ifndef PV_NO_CLZ +typedef struct tagVLCNumCoeffTrail +{ + int trailing; + int total_coeff; + int length; +} VLCNumCoeffTrail; + +typedef struct tagShiftOffset +{ + int shift; + int offset; +} ShiftOffset; + +const VLCNumCoeffTrail NumCoeffTrailOnes[3][67] = +{ + {{0, 0, 1}, {1, 1, 2}, {2, 2, 3}, {1, 2, 6}, {0, 1, 6}, {3, 3, 5}, {3, 3, 5}, {3, 5, 7}, + {2, 3, 7}, {3, 4, 6}, {3, 4, 6}, {3, 6, 8}, {2, 4, 8}, {1, 3, 8}, {0, 2, 8}, {3, 7, 9}, + {2, 5, 9}, {1, 4, 9}, {0, 3, 9}, {3, 8, 10}, {2, 6, 10}, {1, 5, 10}, {0, 4, 10}, {3, 9, 11}, + {2, 7, 11}, {1, 6, 11}, {0, 5, 11}, {0, 8, 13}, {2, 9, 13}, {1, 8, 13}, {0, 7, 13}, {3, 10, 13}, + {2, 8, 13}, {1, 7, 13}, {0, 6, 13}, {3, 12, 14}, {2, 11, 14}, {1, 10, 14}, {0, 10, 14}, {3, 11, 14}, + {2, 10, 14}, {1, 9, 14}, {0, 9, 14}, {3, 14, 15}, {2, 13, 15}, {1, 12, 15}, {0, 12, 15}, {3, 13, 15}, + {2, 12, 15}, {1, 11, 15}, {0, 11, 15}, {3, 16, 16}, {2, 15, 16}, {1, 15, 16}, {0, 14, 16}, {3, 15, 16}, + {2, 14, 16}, {1, 14, 16}, {0, 13, 16}, {0, 16, 16}, {2, 16, 16}, {1, 16, 16}, {0, 15, 16}, {1, 13, 15}, + { -1, -1, -1}, { -1, -1, -1}, { -1, -1, -1}}, + + {{1, 1, 2}, {0, 0, 2}, {3, 4, 4}, {3, 3, 4}, {2, 2, 3}, {2, 2, 3}, {3, 6, 6}, {2, 3, 6}, + {1, 3, 6}, {0, 1, 6}, {3, 5, 5}, {3, 5, 5}, {1, 2, 5}, {1, 2, 5}, {3, 7, 6}, {2, 4, 6}, + {1, 4, 6}, {0, 2, 6}, {3, 8, 7}, {2, 5, 7}, {1, 5, 7}, {0, 3, 7}, {0, 5, 8}, {2, 6, 8}, + {1, 6, 8}, {0, 4, 8}, {3, 9, 9}, {2, 7, 9}, {1, 7, 9}, {0, 6, 9}, {3, 11, 11}, {2, 9, 11}, + {1, 9, 11}, {0, 8, 11}, {3, 10, 11}, {2, 8, 11}, {1, 8, 11}, {0, 7, 11}, {0, 11, 12}, {2, 11, 12}, + {1, 11, 12}, {0, 10, 12}, {3, 12, 12}, {2, 10, 12}, {1, 10, 12}, {0, 9, 12}, {3, 14, 13}, {2, 13, 13}, + {1, 13, 13}, {0, 13, 13}, {3, 13, 13}, {2, 12, 13}, {1, 12, 13}, {0, 12, 13}, {1, 15, 14}, {0, 15, 14}, + {2, 15, 14}, {1, 14, 14}, {2, 14, 13}, {2, 14, 13}, {0, 14, 13}, {0, 14, 13}, {3, 16, 14}, {2, 16, 14}, + {1, 16, 14}, {0, 16, 14}, {3, 15, 13}}, + + {{3, 7, 4}, {3, 6, 4}, {3, 5, 4}, {3, 4, 4}, {3, 3, 4}, {2, 2, 4}, {1, 1, 4}, {0, 0, 4}, + {1, 5, 5}, {2, 5, 5}, {1, 4, 5}, {2, 4, 5}, {1, 3, 5}, {3, 8, 5}, {2, 3, 5}, {1, 2, 5}, + {0, 3, 6}, {2, 7, 6}, {1, 7, 6}, {0, 2, 6}, {3, 9, 6}, {2, 6, 6}, {1, 6, 6}, {0, 1, 6}, + {0, 7, 7}, {0, 6, 7}, {2, 9, 7}, {0, 5, 7}, {3, 10, 7}, {2, 8, 7}, {1, 8, 7}, {0, 4, 7}, + {3, 12, 8}, {2, 11, 8}, {1, 10, 8}, {0, 9, 8}, {3, 11, 8}, {2, 10, 8}, {1, 9, 8}, {0, 8, 8}, + {0, 12, 9}, {2, 13, 9}, {1, 12, 9}, {0, 11, 9}, {3, 13, 9}, {2, 12, 9}, {1, 11, 9}, {0, 10, 9}, + {1, 15, 10}, {0, 14, 10}, {3, 14, 10}, {2, 14, 10}, {1, 14, 10}, {0, 13, 10}, {1, 13, 9}, {1, 13, 9}, + {1, 16, 10}, {0, 15, 10}, {3, 15, 10}, {2, 15, 10}, {3, 16, 10}, {2, 16, 10}, {0, 16, 10}, { -1, -1, -1}, + { -1, -1, -1}, { -1, -1, -1}, { -1, -1, -1}} +}; + + +const ShiftOffset NumCoeffTrailOnes_indx[3][15] = +{ + {{15, -1}, {14, 0}, {13, 1}, {10, -1}, {9, 3}, {8, 7}, {7, 11}, {6, 15}, + {5, 19}, {3, 19}, {2, 27}, {1, 35}, {0, 43}, {0, 55}, {1, 62}}, + + {{14, -2}, {12, -2}, {10, -2}, {10, 10}, {9, 14}, {8, 18}, {7, 22}, {5, 22}, + {4, 30}, {3, 38}, {2, 46}, {2, 58}, {3, 65}, {16, 0}, {16, 0}}, + + {{12, -8}, {11, 0}, {10, 8}, {9, 16}, {8, 24}, {7, 32}, {6, 40}, {6, 52}, + {6, 58}, {6, 61}, {16, 0}, {16, 0}, {16, 0}, {16, 0}, {16, 0}} +}; + +const static int nC_table[8] = {0, 0, 1, 1, 2, 2, 2, 2}; + +#endif +/** +See algorithm in subclause 9.1, Table 9-1, Table 9-2. */ +AVCDec_Status ue_v(AVCDecBitstream *bitstream, uint *codeNum) +{ + uint temp, tmp_cnt; + int leading_zeros = 0; + BitstreamShowBits(bitstream, 16, &temp); + tmp_cnt = temp | 0x1; + + PV_CLZ(leading_zeros, tmp_cnt) + + if (leading_zeros < 8) + { + *codeNum = (temp >> (15 - (leading_zeros << 1))) - 1; + BitstreamFlushBits(bitstream, (leading_zeros << 1) + 1); + } + else + { + BitstreamReadBits(bitstream, (leading_zeros << 1) + 1, &temp); + *codeNum = temp - 1; + } + + return AVCDEC_SUCCESS; +} + +/** +See subclause 9.1.1, Table 9-3 */ +AVCDec_Status se_v(AVCDecBitstream *bitstream, int *value) +{ + uint temp, tmp_cnt; + int leading_zeros = 0; + BitstreamShowBits(bitstream, 16, &temp); + tmp_cnt = temp | 0x1; + + PV_CLZ(leading_zeros, tmp_cnt) + + if (leading_zeros < 8) + { + temp >>= (15 - (leading_zeros << 1)); + BitstreamFlushBits(bitstream, (leading_zeros << 1) + 1); + } + else + { + BitstreamReadBits(bitstream, (leading_zeros << 1) + 1, &temp); + } + + *value = temp >> 1; + + if (temp & 0x01) // lsb is signed bit + *value = -(*value); + +// leading_zeros = temp >> 1; +// *value = leading_zeros - (leading_zeros*2*(temp&1)); + + return AVCDEC_SUCCESS; +} + +AVCDec_Status se_v32bit(AVCDecBitstream *bitstream, int32 *value) +{ + int leadingZeros; + uint32 infobits; + uint32 codeNum; + + if (AVCDEC_SUCCESS != GetEGBitstring32bit(bitstream, &leadingZeros, &infobits)) + return AVCDEC_FAIL; + + codeNum = (1 << leadingZeros) - 1 + infobits; + + *value = (codeNum + 1) / 2; + + if ((codeNum & 0x01) == 0) // lsb is signed bit + *value = -(*value); + + return AVCDEC_SUCCESS; +} + + +AVCDec_Status te_v(AVCDecBitstream *bitstream, uint *value, uint range) +{ + if (range > 1) + { + ue_v(bitstream, value); + } + else + { + BitstreamRead1Bit(bitstream, value); + *value = 1 - (*value); + } + return AVCDEC_SUCCESS; +} + + + +/* This function is only used for syntax with range from -2^31 to 2^31-1 */ +/* only a few of them in the SPS and PPS */ +AVCDec_Status GetEGBitstring32bit(AVCDecBitstream *bitstream, int *leadingZeros, uint32 *infobits) +{ + int bit_value; + uint info_temp; + + *leadingZeros = 0; + + BitstreamRead1Bit(bitstream, (uint*)&bit_value); + + while (!bit_value) + { + (*leadingZeros)++; + BitstreamRead1Bit(bitstream, (uint*)&bit_value); + } + + if (*leadingZeros > 0) + { + if (sizeof(uint) == 4) /* 32 bit machine */ + { + BitstreamReadBits(bitstream, *leadingZeros, (uint*)&info_temp); + *infobits = (uint32)info_temp; + } + else if (sizeof(uint) == 2) /* 16 bit machine */ + { + *infobits = 0; + if (*leadingZeros > 16) + { + BitstreamReadBits(bitstream, 16, (uint*)&info_temp); + (*leadingZeros) -= 16; + *infobits = ((uint32)info_temp) << (*leadingZeros); + } + + BitstreamReadBits(bitstream, *leadingZeros, (uint*)&info_temp); + *infobits |= (uint32)info_temp ; + } + } + else + *infobits = 0; + + return AVCDEC_SUCCESS; +} + +/* see Table 9-4 assignment of codeNum to values of coded_block_pattern. */ +const static uint8 MapCBP[48][2] = +{ + {47, 0}, {31, 16}, {15, 1}, { 0, 2}, {23, 4}, {27, 8}, {29, 32}, {30, 3}, { 7, 5}, {11, 10}, {13, 12}, {14, 15}, + {39, 47}, {43, 7}, {45, 11}, {46, 13}, {16, 14}, { 3, 6}, { 5, 9}, {10, 31}, {12, 35}, {19, 37}, {21, 42}, {26, 44}, + {28, 33}, {35, 34}, {37, 36}, {42, 40}, {44, 39}, { 1, 43}, { 2, 45}, { 4, 46}, { 8, 17}, {17, 18}, {18, 20}, {20, 24}, + {24, 19}, { 6, 21}, { 9, 26}, {22, 28}, {25, 23}, {32, 27}, {33, 29}, {34, 30}, {36, 22}, {40, 25}, {38, 38}, {41, 41}, +}; + +AVCDec_Status DecodeCBP(AVCMacroblock *currMB, AVCDecBitstream *stream) +{ + uint codeNum; + uint coded_block_pattern; + + ue_v(stream, &codeNum); + + if (codeNum > 47) + { + return AVCDEC_FAIL; + } + + /* can get rid of the if _OPTIMIZE */ + if (currMB->mbMode == AVC_I4) + { + coded_block_pattern = MapCBP[codeNum][0]; + } + else + { + coded_block_pattern = MapCBP[codeNum][1]; + } + +// currMB->cbpL = coded_block_pattern&0xF; /* modulo 16 */ +// currMB->cbpC = coded_block_pattern>>4; /* divide 16 */ + currMB->CBP = coded_block_pattern; + + return AVCDEC_SUCCESS; +} + + +/* TO BE OPTIMIZED !!!!! */ +AVCDec_Status ce_TotalCoeffTrailingOnes(AVCDecBitstream *stream, int *TrailingOnes, int *TotalCoeff, int nC) +{ +#ifdef PV_NO_CLZ + const static uint8 TotCofNTrail1[75][3] = {{0, 0, 16}/*error */, {0, 0, 16}/*error */, {1, 13, 15}, {1, 13, 15}, {0, 16, 16}, {2, 16, 16}, {1, 16, 16}, {0, 15, 16}, + {3, 16, 16}, {2, 15, 16}, {1, 15, 16}, {0, 14, 16}, {3, 15, 16}, {2, 14, 16}, {1, 14, 16}, {0, 13, 16}, + {3, 14, 15}, {2, 13, 15}, {1, 12, 15}, {0, 12, 15}, {3, 13, 15}, {2, 12, 15}, {1, 11, 15}, {0, 11, 15}, + {3, 12, 14}, {2, 11, 14}, {1, 10, 14}, {0, 10, 14}, {3, 11, 14}, {2, 10, 14}, {1, 9, 14}, {0, 9, 14}, + {0, 8, 13}, {2, 9, 13}, {1, 8, 13}, {0, 7, 13}, {3, 10, 13}, {2, 8, 13}, {1, 7, 13}, {0, 6, 13}, + {3, 9, 11}, {2, 7, 11}, {1, 6, 11}, {0, 5, 11}, {3, 8, 10}, + {2, 6, 10}, {1, 5, 10}, {0, 4, 10}, {3, 7, 9}, {2, 5, 9}, {1, 4, 9}, {0, 3, 9}, {3, 6, 8}, + {2, 4, 8}, {1, 3, 8}, {0, 2, 8}, {3, 5, 7}, {2, 3, 7}, {3, 4, 6}, {3, 4, 6}, {1, 2, 6}, + {1, 2, 6}, {0, 1, 6}, {0, 1, 6}, {3, 3, 5}, {3, 3, 5}, {3, 3, 5}, {3, 3, 5}, {2, 2, 3}, + {1, 1, 2}, {1, 1, 2}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1} + }; + + const static uint8 TotCofNTrail2[84][3] = {{0, 0, 14 /* error */}, {0, 0, 14/*error */}, {3, 15, 13}, {3, 15, 13}, {3, 16, 14}, {2, 16, 14}, {1, 16, 14}, {0, 16, 14}, + {1, 15, 14}, {0, 15, 14}, {2, 15, 14}, {1, 14, 14}, {2, 14, 13}, {2, 14, 13}, {0, 14, 13}, {0, 14, 13}, + {3, 14, 13}, {2, 13, 13}, {1, 13, 13}, {0, 13, 13}, {3, 13, 13}, {2, 12, 13}, {1, 12, 13}, {0, 12, 13}, + {0, 11, 12}, {2, 11, 12}, {1, 11, 12}, {0, 10, 12}, {3, 12, 12}, {2, 10, 12}, {1, 10, 12}, {0, 9, 12}, + {3, 11, 11}, {2, 9, 11}, {1, 9, 11}, {0, 8, 11}, {3, 10, 11}, {2, 8, 11}, {1, 8, 11}, {0, 7, 11}, + {3, 9, 9}, {2, 7, 9}, {1, 7, 9}, {0, 6, 9}, {0, 5, 8}, {0, 5, 8}, {2, 6, 8}, {2, 6, 8}, + {1, 6, 8}, {1, 6, 8}, {0, 4, 8}, {0, 4, 8}, {3, 8, 7}, {2, 5, 7}, {1, 5, 7}, {0, 3, 7}, + {3, 7, 6}, {3, 7, 6}, {2, 4, 6}, {2, 4, 6}, {1, 4, 6}, {1, 4, 6}, {0, 2, 6}, {0, 2, 6}, + {3, 6, 6}, {2, 3, 6}, {1, 3, 6}, {0, 1, 6}, {3, 5, 5}, {3, 5, 5}, {1, 2, 5}, {1, 2, 5}, + {3, 4, 4}, {3, 3, 4}, {2, 2, 3}, {2, 2, 3}, {1, 1, 2}, {1, 1, 2}, {1, 1, 2}, {1, 1, 2}, + {0, 0, 2}, {0, 0, 2}, {0, 0, 2}, {0, 0, 2} + }; + + const static uint8 TotCofNTrail3[64][3] = {{0, 0, 10/*error*/}, {0, 16, 10}, {3, 16, 10}, {2, 16, 10}, {1, 16, 10}, {0, 15, 10}, {3, 15, 10}, + {2, 15, 10}, {1, 15, 10}, {0, 14, 10}, {3, 14, 10}, {2, 14, 10}, {1, 14, 10}, {0, 13, 10}, {1, 13, 9}, + {1, 13, 9}, {0, 12, 9}, {2, 13, 9}, {1, 12, 9}, {0, 11, 9}, {3, 13, 9}, {2, 12, 9}, {1, 11, 9}, + {0, 10, 9}, {3, 12, 8}, {2, 11, 8}, {1, 10, 8}, {0, 9, 8}, {3, 11, 8}, {2, 10, 8}, {1, 9, 8}, + {0, 8, 8}, {0, 7, 7}, {0, 6, 7}, {2, 9, 7}, {0, 5, 7}, {3, 10, 7}, {2, 8, 7}, {1, 8, 7}, + {0, 4, 7}, {0, 3, 6}, {2, 7, 6}, {1, 7, 6}, {0, 2, 6}, {3, 9, 6}, {2, 6, 6}, {1, 6, 6}, + {0, 1, 6}, {1, 5, 5}, {2, 5, 5}, {1, 4, 5}, {2, 4, 5}, {1, 3, 5}, {3, 8, 5}, {2, 3, 5}, + {1, 2, 5}, {3, 7, 4}, {3, 6, 4}, {3, 5, 4}, {3, 4, 4}, {3, 3, 4}, {2, 2, 4}, {1, 1, 4}, + {0, 0, 4} + }; +#endif + uint code; + +#ifdef PV_NO_CLZ + uint8 *pcode; + if (nC < 2) + { + BitstreamShowBits(stream, 16, &code); + + if (code >= 8192) + { + pcode = (uint8*) & (TotCofNTrail1[(code>>13)+65+2][0]); + } + else if (code >= 2048) + { + pcode = (uint8*) & (TotCofNTrail1[(code>>9)+50+2][0]); + } + else if (code >= 1024) + { + pcode = (uint8*) & (TotCofNTrail1[(code>>8)+46+2][0]); + } + else if (code >= 512) + { + pcode = (uint8*) & (TotCofNTrail1[(code>>7)+42+2][0]); + } + else if (code >= 256) + { + pcode = (uint8*) & (TotCofNTrail1[(code>>6)+38+2][0]); + } + else if (code >= 128) + { + pcode = (uint8*) & (TotCofNTrail1[(code>>5)+34+2][0]); + } + else if (code >= 64) + { + pcode = (uint8*) & (TotCofNTrail1[(code>>3)+22+2][0]); + } + else if (code >= 32) + { + pcode = (uint8*) & (TotCofNTrail1[(code>>2)+14+2][0]); + } + else if (code >= 16) + { + pcode = (uint8*) & (TotCofNTrail1[(code>>1)+6+2][0]); + } + else + { + pcode = (uint8*) & (TotCofNTrail1[(code-2)+2][0]); + } + + *TrailingOnes = pcode[0]; + *TotalCoeff = pcode[1]; + + BitstreamFlushBits(stream, pcode[2]); + } + else if (nC < 4) + { + BitstreamShowBits(stream, 14, &code); + + if (code >= 4096) + { + pcode = (uint8*) & (TotCofNTrail2[(code>>10)+66+2][0]); + } + else if (code >= 2048) + { + pcode = (uint8*) & (TotCofNTrail2[(code>>8)+54+2][0]); + } + else if (code >= 512) + { + pcode = (uint8*) & (TotCofNTrail2[(code>>7)+46+2][0]); + } + else if (code >= 128) + { + pcode = (uint8*) & (TotCofNTrail2[(code>>5)+34+2][0]); + } + else if (code >= 64) + { + pcode = (uint8*) & (TotCofNTrail2[(code>>3)+22+2][0]); + } + else if (code >= 32) + { + pcode = (uint8*) & (TotCofNTrail2[(code>>2)+14+2][0]); + } + else if (code >= 16) + { + pcode = (uint8*) & (TotCofNTrail2[(code>>1)+6+2][0]); + } + else + { + pcode = (uint8*) & (TotCofNTrail2[code-2+2][0]); + } + *TrailingOnes = pcode[0]; + *TotalCoeff = pcode[1]; + + BitstreamFlushBits(stream, pcode[2]); + } + else if (nC < 8) + { + BitstreamShowBits(stream, 10, &code); + + if (code >= 512) + { + pcode = (uint8*) & (TotCofNTrail3[(code>>6)+47+1][0]); + } + else if (code >= 256) + { + pcode = (uint8*) & (TotCofNTrail3[(code>>5)+39+1][0]); + } + else if (code >= 128) + { + pcode = (uint8*) & (TotCofNTrail3[(code>>4)+31+1][0]); + } + else if (code >= 64) + { + pcode = (uint8*) & (TotCofNTrail3[(code>>3)+23+1][0]); + } + else if (code >= 32) + { + pcode = (uint8*) & (TotCofNTrail3[(code>>2)+15+1][0]); + } + else if (code >= 16) + { + pcode = (uint8*) & (TotCofNTrail3[(code>>1)+7+1][0]); + } + else + { + pcode = (uint8*) & (TotCofNTrail3[code-1+1][0]); + } + *TrailingOnes = pcode[0]; + *TotalCoeff = pcode[1]; + + BitstreamFlushBits(stream, pcode[2]); + } + else + { + /* read 6 bit FLC */ + BitstreamReadBits(stream, 6, &code); + + + *TrailingOnes = code & 3; + *TotalCoeff = (code >> 2) + 1; + + if (*TotalCoeff > 16) + { + *TotalCoeff = 16; // _ERROR + } + + if (code == 3) + { + *TrailingOnes = 0; + (*TotalCoeff)--; + } + } +#else + const VLCNumCoeffTrail *ptr; + const ShiftOffset *ptr_indx; + uint temp, leading_zeros = 0; + + if (nC < 8) + { + + BitstreamShowBits(stream, 16, &code); + temp = code | 1; + + PV_CLZ(leading_zeros, temp) + + temp = nC_table[nC]; + ptr_indx = &NumCoeffTrailOnes_indx[temp][leading_zeros]; + ptr = &NumCoeffTrailOnes[temp][(code >> ptr_indx->shift) + ptr_indx->offset]; + *TrailingOnes = ptr->trailing; + *TotalCoeff = ptr->total_coeff; + BitstreamFlushBits(stream, ptr->length); + } + else + { + /* read 6 bit FLC */ + BitstreamReadBits(stream, 6, &code); + + + *TrailingOnes = code & 3; + *TotalCoeff = (code >> 2) + 1; + + if (*TotalCoeff > 16) + { + *TotalCoeff = 16; // _ERROR + } + + if (code == 3) + { + *TrailingOnes = 0; + (*TotalCoeff)--; + } + } +#endif + return AVCDEC_SUCCESS; +} + +/* TO BE OPTIMIZED !!!!! */ +AVCDec_Status ce_TotalCoeffTrailingOnesChromaDC(AVCDecBitstream *stream, int *TrailingOnes, int *TotalCoeff) +{ + AVCDec_Status status; + + const static uint8 TotCofNTrail5[21][3] = + { + {3, 4, 7}, {3, 4, 7}, {2, 4, 8}, {1, 4, 8}, {2, 3, 7}, {2, 3, 7}, {1, 3, 7}, + {1, 3, 7}, {0, 4, 6}, {0, 3, 6}, {0, 2, 6}, {3, 3, 6}, {1, 2, 6}, {0, 1, 6}, + {2, 2, 3}, {0, 0, 2}, {0, 0, 2}, {1, 1, 1}, {1, 1, 1}, {1, 1, 1}, {1, 1, 1} + }; + + uint code; + uint8 *pcode; + + status = BitstreamShowBits(stream, 8, &code); + + if (code >= 32) + { + pcode = (uint8*) & (TotCofNTrail5[(code>>5)+13][0]); + } + else if (code >= 8) + { + pcode = (uint8*) & (TotCofNTrail5[(code>>2)+6][0]); + } + else + { + pcode = (uint8*) & (TotCofNTrail5[code][0]); + } + + *TrailingOnes = pcode[0]; + *TotalCoeff = pcode[1]; + + BitstreamFlushBits(stream, pcode[2]); + + return status; +} + +/* see Table 9-6 */ +AVCDec_Status ce_LevelPrefix(AVCDecBitstream *stream, uint *code) +{ + uint temp; + uint leading_zeros = 0; + BitstreamShowBits(stream, 16, &temp); + temp |= 1 ; + + PV_CLZ(leading_zeros, temp) + + BitstreamFlushBits(stream, leading_zeros + 1); + *code = leading_zeros; + return AVCDEC_SUCCESS; +} + +/* see Table 9-7 and 9-8 */ +AVCDec_Status ce_TotalZeros(AVCDecBitstream *stream, int *code, int TotalCoeff) +{ + const static uint8 TotZero1[28][2] = {{15, 9}, {14, 9}, {13, 9}, {12, 8}, + {12, 8}, {11, 8}, {11, 8}, {10, 7}, {9, 7}, {8, 6}, {8, 6}, {7, 6}, {7, 6}, {6, 5}, {6, 5}, + {6, 5}, {6, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {4, 4}, {3, 4}, + {2, 3}, {2, 3}, {1, 3}, {1, 3}, {0, 1} + }; + + const static uint8 TotZero2n3[2][18][2] = {{{14, 6}, {13, 6}, {12, 6}, {11, 6}, + {10, 5}, {10, 5}, {9, 5}, {9, 5}, {8, 4}, {7, 4}, {6, 4}, {5, 4}, {4, 3}, {4, 3}, + {3, 3}, {2, 3}, {1, 3}, {0, 3}}, + + /*const static uint8 TotZero3[18][2]=*/{{13, 6}, {11, 6}, {12, 5}, {12, 5}, {10, 5}, + {10, 5}, {9, 5}, {9, 5}, {8, 4}, {5, 4}, {4, 4}, {0, 4}, {7, 3}, {7, 3}, {6, 3}, {3, 3}, + {2, 3}, {1, 3}} + }; + + const static uint8 TotZero4[17][2] = {{12, 5}, {11, 5}, {10, 5}, {0, 5}, {9, 4}, + {9, 4}, {7, 4}, {7, 4}, {3, 4}, {3, 4}, {2, 4}, {2, 4}, {8, 3}, {6, 3}, {5, 3}, {4, 3}, {1, 3} + }; + + const static uint8 TotZero5[13][2] = {{11, 5}, {9, 5}, {10, 4}, {8, 4}, {2, 4}, + {1, 4}, {0, 4}, {7, 3}, {7, 3}, {6, 3}, {5, 3}, {4, 3}, {3, 3} + }; + + const static uint8 TotZero6to10[5][15][2] = {{{10, 6}, {0, 6}, {1, 5}, {1, 5}, {8, 4}, + {8, 4}, {8, 4}, {8, 4}, {9, 3}, {7, 3}, {6, 3}, {5, 3}, {4, 3}, {3, 3}, {2, 3}}, + + /*const static uint8 TotZero7[15][2]=*/{{9, 6}, {0, 6}, {1, 5}, {1, 5}, {7, 4}, + {7, 4}, {7, 4}, {7, 4}, {8, 3}, {6, 3}, {4, 3}, {3, 3}, {2, 3}, {5, 2}, {5, 2}}, + + /*const static uint8 TotZero8[15][2]=*/{{8, 6}, {0, 6}, {2, 5}, {2, 5}, {1, 4}, + {1, 4}, {1, 4}, {1, 4}, {7, 3}, {6, 3}, {3, 3}, {5, 2}, {5, 2}, {4, 2}, {4, 2}}, + + /*const static uint8 TotZero9[15][2]=*/{{1, 6}, {0, 6}, {7, 5}, {7, 5}, {2, 4}, + {2, 4}, {2, 4}, {2, 4}, {5, 3}, {6, 2}, {6, 2}, {4, 2}, {4, 2}, {3, 2}, {3, 2}}, + + /*const static uint8 TotZero10[11][2]=*/{{1, 5}, {0, 5}, {6, 4}, {6, 4}, {2, 3}, + {2, 3}, {2, 3}, {2, 3}, {5, 2}, {4, 2}, {3, 2}, {0, 0}, {0, 0}, {0, 0}, {0, 0}} + }; + + const static uint8 TotZero11[7][2] = {{0, 4}, {1, 4}, {2, 3}, {2, 3}, {3, 3}, {5, 3}, {4, 1}}; + + const static uint8 TotZero12to15[4][5][2] = + { + {{3, 1}, {2, 2}, {4, 3}, {1, 4}, {0, 4}}, + {{2, 1}, {3, 2}, {1, 3}, {0, 3}, {0, 0}}, + {{2, 1}, {1, 2}, {0, 2}, {0, 0}, {0, 0}}, + {{1, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}} + }; + + uint temp, mask; + int indx; + uint8 *pcode; + + if (TotalCoeff == 1) + { + BitstreamShowBits(stream, 9, &temp); + + if (temp >= 256) + { + pcode = (uint8*) & (TotZero1[27][0]); + } + else if (temp >= 64) + { + pcode = (uint8*) & (TotZero1[(temp>>5)+19][0]); + } + else if (temp >= 8) + { + pcode = (uint8*) & (TotZero1[(temp>>2)+5][0]); + } + else + { + pcode = (uint8*) & (TotZero1[temp-1][0]); + } + + } + else if (TotalCoeff == 2 || TotalCoeff == 3) + { + BitstreamShowBits(stream, 6, &temp); + + if (temp >= 32) + { + pcode = (uint8*) & (TotZero2n3[TotalCoeff-2][(temp>>3)+10][0]); + } + else if (temp >= 8) + { + pcode = (uint8*) & (TotZero2n3[TotalCoeff-2][(temp>>2)+6][0]); + } + else + { + pcode = (uint8*) & (TotZero2n3[TotalCoeff-2][temp][0]); + } + } + else if (TotalCoeff == 4) + { + BitstreamShowBits(stream, 5, &temp); + + if (temp >= 12) + { + pcode = (uint8*) & (TotZero4[(temp>>2)+9][0]); + } + else + { + pcode = (uint8*) & (TotZero4[temp][0]); + } + } + else if (TotalCoeff == 5) + { + BitstreamShowBits(stream, 5, &temp); + + if (temp >= 16) + { + pcode = (uint8*) & (TotZero5[(temp>>2)+5][0]); + } + else if (temp >= 2) + { + pcode = (uint8*) & (TotZero5[(temp>>1)+1][0]); + } + else + { + pcode = (uint8*) & (TotZero5[temp][0]); + } + } + else if (TotalCoeff >= 6 && TotalCoeff <= 10) + { + if (TotalCoeff == 10) + { + BitstreamShowBits(stream, 5, &temp); + } + else + { + BitstreamShowBits(stream, 6, &temp); + } + + + if (temp >= 8) + { + pcode = (uint8*) & (TotZero6to10[TotalCoeff-6][(temp>>3)+7][0]); + } + else + { + pcode = (uint8*) & (TotZero6to10[TotalCoeff-6][temp][0]); + } + } + else if (TotalCoeff == 11) + { + BitstreamShowBits(stream, 4, &temp); + + + if (temp >= 8) + { + pcode = (uint8*) & (TotZero11[6][0]); + } + else if (temp >= 4) + { + pcode = (uint8*) & (TotZero11[(temp>>1)+2][0]); + } + else + { + pcode = (uint8*) & (TotZero11[temp][0]); + } + } + else + { + BitstreamShowBits(stream, (16 - TotalCoeff), &temp); + mask = 1 << (15 - TotalCoeff); + indx = 0; + while ((temp&mask) == 0 && indx < (16 - TotalCoeff)) /* search location of 1 bit */ + { + mask >>= 1; + indx++; + } + + pcode = (uint8*) & (TotZero12to15[TotalCoeff-12][indx]); + } + + *code = pcode[0]; + BitstreamFlushBits(stream, pcode[1]); + + return AVCDEC_SUCCESS; +} + +/* see Table 9-9 */ +AVCDec_Status ce_TotalZerosChromaDC(AVCDecBitstream *stream, int *code, int TotalCoeff) +{ + const static uint8 TotZeroChrom1to3[3][8][2] = + { + {{3, 3}, {2, 3}, {1, 2}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}}, + {{2, 2}, {2, 2}, {1, 2}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}}, + {{1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}}, + }; + + + uint temp; + uint8 *pcode; + + BitstreamShowBits(stream, 3, &temp); + pcode = (uint8*) & (TotZeroChrom1to3[TotalCoeff-1][temp]); + + *code = pcode[0]; + + BitstreamFlushBits(stream, pcode[1]); + + return AVCDEC_SUCCESS; +} + +/* see Table 9-10 */ +AVCDec_Status ce_RunBefore(AVCDecBitstream *stream, int *code, int zerosLeft) +{ + const static int codlen[6] = {1, 2, 2, 3, 3, 3}; /* num bits to read */ + const static uint8 RunBeforeTab[6][8][2] = {{{1, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, + /*const static int RunBefore2[4][2]=*/{{2, 2}, {1, 2}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, + /*const static int RunBefore3[4][2]=*/{{3, 2}, {2, 2}, {1, 2}, {0, 2}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, + /*const static int RunBefore4[7][2]=*/{{4, 3}, {3, 3}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {0, 2}, {0, 2}}, + /*const static int RunBefore5[7][2]=*/{{5, 3}, {4, 3}, {3, 3}, {2, 3}, {1, 2}, {1, 2}, {0, 2}, {0, 2}}, + /*const static int RunBefore6[7][2]=*/{{1, 3}, {2, 3}, {4, 3}, {3, 3}, {6, 3}, {5, 3}, {0, 2}, {0, 2}} + }; + + uint temp; + uint8 *pcode; + int indx; + + if (zerosLeft <= 6) + { + BitstreamShowBits(stream, codlen[zerosLeft-1], &temp); + + pcode = (uint8*) & (RunBeforeTab[zerosLeft-1][temp][0]); + + *code = pcode[0]; + + BitstreamFlushBits(stream, pcode[1]); + } + else + { + BitstreamReadBits(stream, 3, &temp); + if (temp) + { + *code = 7 - temp; + } + else + { + BitstreamShowBits(stream, 9, &temp); + temp <<= 7; + temp |= 1; + indx = 0; + PV_CLZ(indx, temp) + *code = 7 + indx; + BitstreamFlushBits(stream, indx + 1); + } + } + + + return AVCDEC_SUCCESS; +} diff --git a/media/libstagefright/codecs/avc/patent_disclaimer.txt b/media/libstagefright/codecs/avc/patent_disclaimer.txt new file mode 100644 index 0000000..b4bf11d --- /dev/null +++ b/media/libstagefright/codecs/avc/patent_disclaimer.txt @@ -0,0 +1,9 @@ + +THIS IS NOT A GRANT OF PATENT RIGHTS. + +Google makes no representation or warranty that the codecs for which +source code is made available hereunder are unencumbered by +third-party patents. Those intending to use this source code in +hardware or software products are advised that implementations of +these codecs, including in open source software or shareware, may +require patent licenses from the relevant patent holders. diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk index cb2788c..fb56a93 100644 --- a/media/libstagefright/codecs/mp3dec/Android.mk +++ b/media/libstagefright/codecs/mp3dec/Android.mk @@ -51,10 +51,6 @@ LOCAL_C_INCLUDES := \ LOCAL_CFLAGS := \ -DOSCL_UNUSED_ARG= -LOCAL_SHARED_LIBRARIES := \ - libstagefright \ - libutils - LOCAL_MODULE := libstagefright_mp3dec include $(BUILD_STATIC_LIBRARY) diff --git a/media/libstagefright/include/AVCDecoder.h b/media/libstagefright/include/AVCDecoder.h new file mode 100644 index 0000000..0146f77 --- /dev/null +++ b/media/libstagefright/include/AVCDecoder.h @@ -0,0 +1,86 @@ +/* + * 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 AVC_DECODER_H_ + +#define AVC_DECODER_H_ + +#include +#include +#include + +struct tagAVCHandle; + +namespace android { + +struct MediaBufferGroup; + +struct AVCDecoder : public MediaSource, + public MediaBufferObserver { + AVCDecoder(const sp &source); + + virtual status_t start(MetaData *params); + virtual status_t stop(); + + virtual sp getFormat(); + + virtual status_t read( + MediaBuffer **buffer, const ReadOptions *options); + + virtual void signalBufferReturned(MediaBuffer *buffer); + +protected: + virtual ~AVCDecoder(); + +private: + sp mSource; + bool mStarted; + + sp mFormat; + + Vector mCodecSpecificData; + + tagAVCHandle *mHandle; + Vector mFrames; + MediaBuffer *mInputBuffer; + + int64_t mAnchorTimeUs; + int64_t mNumSamplesOutput; + + void addCodecSpecificData(const uint8_t *data, size_t size); + + static int32_t ActivateSPSWrapper( + void *userData, unsigned int sizeInMbs, unsigned int numBuffers); + + static int32_t BindFrameWrapper( + void *userData, int32_t index, uint8_t **yuv); + + static void UnbindFrame(void *userData, int32_t index); + + int32_t activateSPS( + unsigned int sizeInMbs, unsigned int numBuffers); + + int32_t bindFrame(int32_t index, uint8_t **yuv); + + void releaseFrames(); + + AVCDecoder(const AVCDecoder &); + AVCDecoder &operator=(const AVCDecoder &); +}; + +} // namespace android + +#endif // AVC_DECODER_H_ -- cgit v1.1