From 82313eaa34b02cf1a4b6f55c1b73549ec8d056f0 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 9 Mar 2013 20:37:11 +0100 Subject: h264: add a parameter to the MB_MBAFF macro. This way it does not look like a constant. --- libavcodec/h264.c | 16 ++++++++-------- libavcodec/h264.h | 4 ++-- libavcodec/h264_cabac.c | 8 ++++---- libavcodec/h264_cavlc.c | 8 ++++---- 4 files changed, 18 insertions(+), 18 deletions(-) (limited to 'libavcodec') diff --git a/libavcodec/h264.c b/libavcodec/h264.c index 086737f843..c3618a83e8 100644 --- a/libavcodec/h264.c +++ b/libavcodec/h264.c @@ -748,7 +748,7 @@ static void await_references(H264Context *h) int ref_field_picture = ref_pic->field_picture; int pic_height = 16 * h->mb_height >> ref_field_picture; - row <<= MB_MBAFF; + row <<= MB_MBAFF(h); nrefs[list]--; if (!FIELD_PICTURE && ref_field_picture) { // frame referencing two fields @@ -2050,7 +2050,7 @@ static av_always_inline void backup_mb_border(H264Context *h, uint8_t *src_y, if (!simple && FRAME_MBAFF) { if (h->mb_y & 1) { - if (!MB_MBAFF) { + if (!MB_MBAFF(h)) { top_border = h->top_borders[0][h->mb_x]; AV_COPY128(top_border, src_y + 15 * linesize); if (pixel_shift) @@ -2085,7 +2085,7 @@ static av_always_inline void backup_mb_border(H264Context *h, uint8_t *src_y, } } } - } else if (MB_MBAFF) { + } else if (MB_MBAFF(h)) { top_idx = 0; } else return; @@ -2143,10 +2143,10 @@ static av_always_inline void xchg_mb_border(H264Context *h, uint8_t *src_y, if (!simple && FRAME_MBAFF) { if (h->mb_y & 1) { - if (!MB_MBAFF) + if (!MB_MBAFF(h)) return; } else { - top_idx = MB_MBAFF ? 0 : 1; + top_idx = MB_MBAFF(h) ? 0 : 1; } } @@ -3759,7 +3759,7 @@ static av_always_inline void fill_filter_caches_inter(H264Context *h, if (USES_LIST(top_type, list)) { const int b_xy = h->mb2b_xy[top_xy] + 3 * b_stride; const int b8_xy = 4 * top_xy + 2; - int (*ref2frm)[64] = h->ref2frm[h->slice_table[top_xy] & (MAX_SLICES - 1)][0] + (MB_MBAFF ? 20 : 2); + int (*ref2frm)[64] = h->ref2frm[h->slice_table[top_xy] & (MAX_SLICES - 1)][0] + (MB_MBAFF(h) ? 20 : 2); AV_COPY128(mv_dst - 1 * 8, h->cur_pic.motion_val[list][b_xy + 0]); ref_cache[0 - 1 * 8] = ref_cache[1 - 1 * 8] = ref2frm[list][h->cur_pic.ref_index[list][b8_xy + 0]]; @@ -3774,7 +3774,7 @@ static av_always_inline void fill_filter_caches_inter(H264Context *h, if (USES_LIST(left_type[LTOP], list)) { const int b_xy = h->mb2b_xy[left_xy[LTOP]] + 3; const int b8_xy = 4 * left_xy[LTOP] + 1; - int (*ref2frm)[64] = h->ref2frm[h->slice_table[left_xy[LTOP]] & (MAX_SLICES - 1)][0] + (MB_MBAFF ? 20 : 2); + int (*ref2frm)[64] = h->ref2frm[h->slice_table[left_xy[LTOP]] & (MAX_SLICES - 1)][0] + (MB_MBAFF(h) ? 20 : 2); AV_COPY32(mv_dst - 1 + 0, h->cur_pic.motion_val[list][b_xy + b_stride * 0]); AV_COPY32(mv_dst - 1 + 8, h->cur_pic.motion_val[list][b_xy + b_stride * 1]); AV_COPY32(mv_dst - 1 + 16, h->cur_pic.motion_val[list][b_xy + b_stride * 2]); @@ -3807,7 +3807,7 @@ static av_always_inline void fill_filter_caches_inter(H264Context *h, { int8_t *ref = &h->cur_pic.ref_index[list][4 * mb_xy]; - int (*ref2frm)[64] = h->ref2frm[h->slice_num & (MAX_SLICES - 1)][0] + (MB_MBAFF ? 20 : 2); + int (*ref2frm)[64] = h->ref2frm[h->slice_num & (MAX_SLICES - 1)][0] + (MB_MBAFF(h) ? 20 : 2); uint32_t ref01 = (pack16to32(ref2frm[list][ref[0]], ref2frm[list][ref[1]]) & 0x00FF00FF) * 0x0101; uint32_t ref23 = (pack16to32(ref2frm[list][ref[2]], ref2frm[list][ref[3]]) & 0x00FF00FF) * 0x0101; AV_WN32A(&ref_cache[0 * 8], ref01); diff --git a/libavcodec/h264.h b/libavcodec/h264.h index 3482d897aa..1da1922188 100644 --- a/libavcodec/h264.h +++ b/libavcodec/h264.h @@ -59,7 +59,7 @@ #define MAX_SLICES 16 #ifdef ALLOW_INTERLACE -#define MB_MBAFF h->mb_mbaff +#define MB_MBAFF(h) h->mb_mbaff #define MB_FIELD h->mb_field_decoding_flag #define FRAME_MBAFF h->mb_aff_frame #define FIELD_PICTURE (h->picture_structure != PICT_FRAME) @@ -68,7 +68,7 @@ #define LBOT 1 #define LEFT(i) (i) #else -#define MB_MBAFF 0 +#define MB_MBAFF(h) 0 #define MB_FIELD 0 #define FRAME_MBAFF 0 #define FIELD_PICTURE 0 diff --git a/libavcodec/h264_cabac.c b/libavcodec/h264_cabac.c index 12eb2c7b22..5d793ad2b2 100644 --- a/libavcodec/h264_cabac.c +++ b/libavcodec/h264_cabac.c @@ -2088,7 +2088,7 @@ decode_intra_mb: for( i = 0; i < 4; i++ ) { if(IS_DIRECT(h->sub_mb_type[i])) continue; if(IS_DIR(h->sub_mb_type[i], 0, list)){ - int rc = h->ref_count[list] << MB_MBAFF; + int rc = h->ref_count[list] << MB_MBAFF(h); if (rc > 1) { ref[list][i] = decode_cabac_mb_ref( h, list, 4*i ); if (ref[list][i] >= (unsigned) rc) { @@ -2174,7 +2174,7 @@ decode_intra_mb: if(IS_16X16(mb_type)){ for(list=0; listlist_count; list++){ if(IS_DIR(mb_type, 0, list)){ - int ref, rc = h->ref_count[list] << MB_MBAFF; + int ref, rc = h->ref_count[list] << MB_MBAFF(h); if (rc > 1) { ref= decode_cabac_mb_ref(h, list, 0); if (ref >= (unsigned) rc) { @@ -2202,7 +2202,7 @@ decode_intra_mb: for(list=0; listlist_count; list++){ for(i=0; i<2; i++){ if(IS_DIR(mb_type, i, list)){ - int ref, rc = h->ref_count[list] << MB_MBAFF; + int ref, rc = h->ref_count[list] << MB_MBAFF(h); if (rc > 1) { ref= decode_cabac_mb_ref( h, list, 8*i ); if (ref >= (unsigned) rc) { @@ -2237,7 +2237,7 @@ decode_intra_mb: for(list=0; listlist_count; list++){ for(i=0; i<2; i++){ if(IS_DIR(mb_type, i, list)){ //FIXME optimize - int ref, rc = h->ref_count[list] << MB_MBAFF; + int ref, rc = h->ref_count[list] << MB_MBAFF(h); if (rc > 1) { ref= decode_cabac_mb_ref( h, list, 4*i ); if (ref >= (unsigned) rc) { diff --git a/libavcodec/h264_cavlc.c b/libavcodec/h264_cavlc.c index be7d2e9698..424165fece 100644 --- a/libavcodec/h264_cavlc.c +++ b/libavcodec/h264_cavlc.c @@ -856,7 +856,7 @@ decode_intra_mb: } for(list=0; listlist_count; list++){ - int ref_count = IS_REF0(mb_type) ? 1 : h->ref_count[list] << MB_MBAFF; + int ref_count = IS_REF0(mb_type) ? 1 : h->ref_count[list] << MB_MBAFF(h); for(i=0; i<4; i++){ if(IS_DIRECT(h->sub_mb_type[i])) continue; if(IS_DIR(h->sub_mb_type[i], 0, list)){ @@ -936,7 +936,7 @@ decode_intra_mb: for(list=0; listlist_count; list++){ unsigned int val; if(IS_DIR(mb_type, 0, list)){ - int rc = h->ref_count[list] << MB_MBAFF; + int rc = h->ref_count[list] << MB_MBAFF(h); if (rc == 1) { val= 0; } else if (rc == 2) { @@ -967,7 +967,7 @@ decode_intra_mb: for(i=0; i<2; i++){ unsigned int val; if(IS_DIR(mb_type, i, list)){ - int rc = h->ref_count[list] << MB_MBAFF; + int rc = h->ref_count[list] << MB_MBAFF(h); if (rc == 1) { val= 0; } else if (rc == 2) { @@ -1005,7 +1005,7 @@ decode_intra_mb: for(i=0; i<2; i++){ unsigned int val; if(IS_DIR(mb_type, i, list)){ //FIXME optimize - int rc = h->ref_count[list] << MB_MBAFF; + int rc = h->ref_count[list] << MB_MBAFF(h); if (rc == 1) { val= 0; } else if (rc == 2) { -- cgit v1.2.3 From da6be8fcec16a94d8084bda8bb8a0a411a96bcf7 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 9 Mar 2013 20:37:11 +0100 Subject: h264: add a parameter to the MB_FIELD macro. This way it does not look like a constant. --- libavcodec/h264.c | 16 ++++++++-------- libavcodec/h264.h | 4 ++-- libavcodec/h264_cabac.c | 14 +++++++------- libavcodec/h264_cavlc.c | 2 +- libavcodec/h264_loopfilter.c | 8 ++++---- libavcodec/h264_mb_template.c | 4 ++-- libavcodec/h264_mvpred.h | 12 ++++++------ 7 files changed, 30 insertions(+), 30 deletions(-) (limited to 'libavcodec') diff --git a/libavcodec/h264.c b/libavcodec/h264.c index c3618a83e8..37b3337e55 100644 --- a/libavcodec/h264.c +++ b/libavcodec/h264.c @@ -632,7 +632,7 @@ static inline void get_lowest_part_y(H264Context *h, int refs[2][48], int n, { int my; - y_offset += 16 * (h->mb_y >> MB_FIELD); + y_offset += 16 * (h->mb_y >> MB_FIELD(h)); if (list0) { int ref_n = h->ref_cache[0][scan8[n]]; @@ -799,7 +799,7 @@ static av_always_inline void mc_dir_part(H264Context *h, Picture *pic, const int full_mx = mx >> 2; const int full_my = my >> 2; const int pic_width = 16 * h->mb_width; - const int pic_height = 16 * h->mb_height >> MB_FIELD; + const int pic_height = 16 * h->mb_height >> MB_FIELD(h); int ysh; if (mx & 7) @@ -859,7 +859,7 @@ static av_always_inline void mc_dir_part(H264Context *h, Picture *pic, } ysh = 3 - (chroma_idc == 2 /* yuv422 */); - if (chroma_idc == 1 /* yuv420 */ && MB_FIELD) { + if (chroma_idc == 1 /* yuv420 */ && MB_FIELD(h)) { // chroma offset when predicting from a field of opposite parity my += 2 * ((h->mb_y & 1) - (pic->reference - 1)); emu |= (my >> 3) < 0 || (my >> 3) + 8 >= (pic_height >> 1); @@ -917,7 +917,7 @@ static av_always_inline void mc_part_std(H264Context *h, int n, int square, dest_cr += (x_offset << pixel_shift) + y_offset * h->mb_uvlinesize; } x_offset += 8 * h->mb_x; - y_offset += 8 * (h->mb_y >> MB_FIELD); + y_offset += 8 * (h->mb_y >> MB_FIELD(h)); if (list0) { Picture *ref = &h->ref_list[0][h->ref_cache[0][scan8[n]]]; @@ -970,7 +970,7 @@ static av_always_inline void mc_part_weighted(H264Context *h, int n, int square, dest_cr += (x_offset << pixel_shift) + y_offset * h->mb_uvlinesize; } x_offset += 8 * h->mb_x; - y_offset += 8 * (h->mb_y >> MB_FIELD); + y_offset += 8 * (h->mb_y >> MB_FIELD(h)); if (list0 && list1) { /* don't optimize for luma-only case, since B-frames usually @@ -2155,7 +2155,7 @@ static av_always_inline void xchg_mb_border(H264Context *h, uint8_t *src_y, deblock_top = h->top_type; } else { deblock_topleft = (h->mb_x > 0); - deblock_top = (h->mb_y > !!MB_FIELD); + deblock_top = (h->mb_y > !!MB_FIELD(h)); } src_y -= linesize + 1 + pixel_shift; @@ -3837,7 +3837,7 @@ static int fill_filter_caches(H264Context *h, int mb_type) uint8_t *nnz; uint8_t *nnz_cache; - top_xy = mb_xy - (h->mb_stride << MB_FIELD); + top_xy = mb_xy - (h->mb_stride << MB_FIELD(h)); /* Wow, what a mess, why didn't they simplify the interlacing & intra * stuff, I can't imagine that these complex rules are worth it. */ @@ -4008,7 +4008,7 @@ static void loop_filter(H264Context *h, int start_x, int end_x) mb_y * h->uvlinesize * block_h; // FIXME simplify above - if (MB_FIELD) { + if (MB_FIELD(h)) { linesize = h->mb_linesize = h->linesize * 2; uvlinesize = h->mb_uvlinesize = h->uvlinesize * 2; if (mb_y & 1) { // FIXME move out of this function? diff --git a/libavcodec/h264.h b/libavcodec/h264.h index 1da1922188..9d2a1c5756 100644 --- a/libavcodec/h264.h +++ b/libavcodec/h264.h @@ -60,7 +60,7 @@ #ifdef ALLOW_INTERLACE #define MB_MBAFF(h) h->mb_mbaff -#define MB_FIELD h->mb_field_decoding_flag +#define MB_FIELD(h) h->mb_field_decoding_flag #define FRAME_MBAFF h->mb_aff_frame #define FIELD_PICTURE (h->picture_structure != PICT_FRAME) #define LEFT_MBS 2 @@ -69,7 +69,7 @@ #define LEFT(i) (i) #else #define MB_MBAFF(h) 0 -#define MB_FIELD 0 +#define MB_FIELD(h) 0 #define FRAME_MBAFF 0 #define FIELD_PICTURE 0 #undef IS_INTERLACED diff --git a/libavcodec/h264_cabac.c b/libavcodec/h264_cabac.c index 5d793ad2b2..2d3717bec2 100644 --- a/libavcodec/h264_cabac.c +++ b/libavcodec/h264_cabac.c @@ -1328,9 +1328,9 @@ static int decode_cabac_mb_skip( H264Context *h, int mb_x, int mb_y ) { mba_xy = mb_xy - 1; if( (mb_y&1) && h->slice_table[mba_xy] == h->slice_num - && MB_FIELD == !!IS_INTERLACED( h->cur_pic.mb_type[mba_xy] ) ) + && MB_FIELD(h) == !!IS_INTERLACED( h->cur_pic.mb_type[mba_xy] ) ) mba_xy += h->mb_stride; - if( MB_FIELD ){ + if (MB_FIELD(h)) { mbb_xy = mb_xy - h->mb_stride; if( !(mb_y&1) && h->slice_table[mbb_xy] == h->slice_num @@ -1625,9 +1625,9 @@ decode_cabac_residual_internal(H264Context *h, int16_t *block, #endif significant_coeff_ctx_base = h->cabac_state - + significant_coeff_flag_offset[MB_FIELD][cat]; + + significant_coeff_flag_offset[MB_FIELD(h)][cat]; last_coeff_ctx_base = h->cabac_state - + last_coeff_flag_offset[MB_FIELD][cat]; + + last_coeff_flag_offset[MB_FIELD(h)][cat]; abs_level_m1_ctx_base = h->cabac_state + coeff_abs_level_m1_offset[cat]; @@ -1647,7 +1647,7 @@ decode_cabac_residual_internal(H264Context *h, int16_t *block, if( last == max_coeff -1 ) {\ index[coeff_count++] = last;\ } - const uint8_t *sig_off = significant_coeff_flag_offset_8x8[MB_FIELD]; + const uint8_t *sig_off = significant_coeff_flag_offset_8x8[MB_FIELD(h)]; #ifdef decode_significance coeff_count = decode_significance_8x8(CC, significant_coeff_ctx_base, index, last_coeff_ctx_base, sig_off); @@ -1917,7 +1917,7 @@ int ff_h264_decode_mb_cabac(H264Context *h) { h->prev_mb_skipped = 0; - fill_decode_neighbors(h, -(MB_FIELD)); + fill_decode_neighbors(h, -(MB_FIELD(h))); if( h->slice_type_nos == AV_PICTURE_TYPE_B ) { int ctx = 0; @@ -1981,7 +1981,7 @@ decode_intra_mb: h->intra16x16_pred_mode= i_mb_type_info[mb_type].pred_mode; mb_type= i_mb_type_info[mb_type].type; } - if(MB_FIELD) + if(MB_FIELD(h)) mb_type |= MB_TYPE_INTERLACED; h->slice_table[ mb_xy ]= h->slice_num; diff --git a/libavcodec/h264_cavlc.c b/libavcodec/h264_cavlc.c index 424165fece..b66ce9a0b1 100644 --- a/libavcodec/h264_cavlc.c +++ b/libavcodec/h264_cavlc.c @@ -755,7 +755,7 @@ decode_intra_mb: mb_type= i_mb_type_info[mb_type].type; } - if(MB_FIELD) + if(MB_FIELD(h)) mb_type |= MB_TYPE_INTERLACED; h->slice_table[ mb_xy ]= h->slice_num; diff --git a/libavcodec/h264_loopfilter.c b/libavcodec/h264_loopfilter.c index 2e4683d8e3..424c598dcf 100644 --- a/libavcodec/h264_loopfilter.c +++ b/libavcodec/h264_loopfilter.c @@ -740,9 +740,9 @@ void ff_h264_filter_mb( H264Context *h, int mb_x, int mb_y, uint8_t *img_y, uint {3+4*0, 3+4*1, 3+4*2, 3+4*3, 3+4*0, 3+4*1, 3+4*2, 3+4*3}, } }; - const uint8_t *off= offset[MB_FIELD][mb_y&1]; + const uint8_t *off= offset[MB_FIELD(h)][mb_y&1]; for( i = 0; i < 8; i++ ) { - int j= MB_FIELD ? i>>2 : i&1; + int j= MB_FIELD(h) ? i>>2 : i&1; int mbn_xy = h->left_mb_xy[LEFT(j)]; int mbn_type= h->left_type[LEFT(j)]; @@ -751,7 +751,7 @@ void ff_h264_filter_mb( H264Context *h, int mb_x, int mb_y, uint8_t *img_y, uint else{ bS[i] = 1 + !!(h->non_zero_count_cache[12+8*(i>>1)] | ((!h->pps.cabac && IS_8x8DCT(mbn_type)) ? - (h->cbp_table[mbn_xy] & (((MB_FIELD ? (i&2) : (mb_y&1)) ? 8 : 2) << 12)) + (h->cbp_table[mbn_xy] & (((MB_FIELD(h) ? (i&2) : (mb_y&1)) ? 8 : 2) << 12)) : h->non_zero_count[mbn_xy][ off[i] ])); } @@ -775,7 +775,7 @@ void ff_h264_filter_mb( H264Context *h, int mb_x, int mb_y, uint8_t *img_y, uint /* Filter edge */ tprintf(h->avctx, "filter mb:%d/%d MBAFF, QPy:%d/%d, QPb:%d/%d QPr:%d/%d ls:%d uvls:%d", mb_x, mb_y, qp[0], qp[1], bqp[0], bqp[1], rqp[0], rqp[1], linesize, uvlinesize); { int i; for (i = 0; i < 8; i++) tprintf(h->avctx, " bS[%d]:%d", i, bS[i]); tprintf(h->avctx, "\n"); } - if(MB_FIELD){ + if (MB_FIELD(h)) { filter_mb_mbaff_edgev ( h, img_y , linesize, bS , 1, qp [0], a, b, 1 ); filter_mb_mbaff_edgev ( h, img_y + 8* linesize, linesize, bS+4, 1, qp [1], a, b, 1 ); if (chroma){ diff --git a/libavcodec/h264_mb_template.c b/libavcodec/h264_mb_template.c index a39d4c9ca0..5c1121f735 100644 --- a/libavcodec/h264_mb_template.c +++ b/libavcodec/h264_mb_template.c @@ -64,7 +64,7 @@ static av_noinline void FUNC(hl_decode_mb)(H264Context *h) h->list_counts[mb_xy] = h->list_count; - if (!SIMPLE && MB_FIELD) { + if (!SIMPLE && MB_FIELD(h)) { linesize = h->mb_linesize = h->linesize * 2; uvlinesize = h->mb_uvlinesize = h->uvlinesize * 2; block_offset = &h->block_offset[48]; @@ -296,7 +296,7 @@ static av_noinline void FUNC(hl_decode_mb_444)(H264Context *h) h->list_counts[mb_xy] = h->list_count; - if (!SIMPLE && MB_FIELD) { + if (!SIMPLE && MB_FIELD(h)) { linesize = h->mb_linesize = h->mb_uvlinesize = h->linesize * 2; block_offset = &h->block_offset[48]; if (mb_y & 1) // FIXME move out of this function? diff --git a/libavcodec/h264_mvpred.h b/libavcodec/h264_mvpred.h index a61ad20f66..b0f60343f6 100644 --- a/libavcodec/h264_mvpred.h +++ b/libavcodec/h264_mvpred.h @@ -61,11 +61,11 @@ static av_always_inline int fetch_diagonal_mv(H264Context *h, const int16_t **C, AV_ZERO32(h->mv_cache[list][scan8[0] - 2]); *C = h->mv_cache[list][scan8[0] - 2]; - if (!MB_FIELD && IS_INTERLACED(h->left_type[0])) { + if (!MB_FIELD(h) && IS_INTERLACED(h->left_type[0])) { SET_DIAG_MV(* 2, >> 1, h->left_mb_xy[0] + h->mb_stride, (h->mb_y & 1) * 2 + (i >> 5)); } - if (MB_FIELD && !IS_INTERLACED(h->left_type[0])) { + if (MB_FIELD(h) && !IS_INTERLACED(h->left_type[0])) { // left shift will turn LIST_NOT_USED into PART_NOT_AVAILABLE, but that's OK. SET_DIAG_MV(/ 2, << 1, h->left_mb_xy[i >= 36], ((i >> 2)) & 3); } @@ -232,7 +232,7 @@ static av_always_inline void pred_8x16_motion(H264Context *const h, #define FIX_MV_MBAFF(type, refn, mvn, idx) \ if (FRAME_MBAFF) { \ - if (MB_FIELD) { \ + if (MB_FIELD(h)) { \ if (!IS_INTERLACED(type)) { \ refn <<= 1; \ AV_COPY32(mvbuf[idx], mvn); \ @@ -360,7 +360,7 @@ static void fill_decode_neighbors(H264Context *h, int mb_type) h->topleft_partition = -1; - top_xy = mb_xy - (h->mb_stride << MB_FIELD); + top_xy = mb_xy - (h->mb_stride << MB_FIELD(h)); /* Wow, what a mess, why didn't they simplify the interlacing & intra * stuff, I can't imagine that these complex rules are worth it. */ @@ -761,7 +761,7 @@ static void fill_decode_caches(H264Context *h, int mb_type) MAP_F2F(scan8[0] - 1 + 3 * 8, left_type[LBOT]) if (FRAME_MBAFF) { - if (MB_FIELD) { + if (MB_FIELD(h)) { #define MAP_F2F(idx, mb_type) \ if (!IS_INTERLACED(mb_type) && h->ref_cache[list][idx] >= 0) { \ @@ -801,7 +801,7 @@ static void av_unused decode_mb_skip(H264Context *h) memset(h->non_zero_count[mb_xy], 0, 48); - if (MB_FIELD) + if (MB_FIELD(h)) mb_type |= MB_TYPE_INTERLACED; if (h->slice_type_nos == AV_PICTURE_TYPE_B) { -- cgit v1.2.3