# HG changeset patch # User michael # Date 1217022375 0 # Node ID bcede7e06618e422c04e3aa598c5d49dfe4fe7c5 # Parent 535664ced6f0ed8115bc822443c617482e6e78ca Rewrite fill_default_ref_list(), the old code was obfuscated beyond repair with hacks. new code is ~60lines old was ~200 Fixes at least: FRExt/HCHP2_HHI_A.264 one sample also get decoded much better: FRExt/FRExt1_Panasonic.avc (PSNR 11 -> 80) (no i do not know why, the old code was too a big mess to figure out what it did) diff -r 535664ced6f0 -r bcede7e06618 h264.c --- a/h264.c Fri Jul 25 14:52:58 2008 +0000 +++ b/h264.c Fri Jul 25 21:46:15 2008 +0000 @@ -2770,228 +2770,100 @@ if (match) { *dest = *src; + if(parity != PICT_FRAME){ pic_as_field(dest, parity); dest->pic_id *= 2; dest->pic_id += id_add; + } } return match; } -/** - * Split one reference list into field parts, interleaving by parity - * as per H.264 spec section 8.2.4.2.5. Output fields have their data pointers - * set to look at the actual start of data for that field. - * - * @param dest output list - * @param dest_len maximum number of fields to put in dest - * @param src the source reference list containing fields and/or field pairs - * (aka short_ref/long_ref, or - * refFrameListXShortTerm/refFrameListLongTerm in spec-speak) - * @param src_len number of Picture's in source (pairs and unmatched fields) - * @param parity the parity of the picture being decoded/needing - * these ref pics (PICT_{TOP,BOTTOM}_FIELD) - * @return number of fields placed in dest - */ -static int split_field_half_ref_list(Picture *dest, int dest_len, - Picture *src, int src_len, int parity){ - int same_parity = 1; - int same_i = 0; - int opp_i = 0; - int out_i; - int field_output; - - for (out_i = 0; out_i < dest_len; out_i += field_output) { - if (same_parity && same_i < src_len) { - field_output = split_field_copy(dest + out_i, src + same_i, - parity, 1); - same_parity = !field_output; - same_i++; - - } else if (opp_i < src_len) { - field_output = split_field_copy(dest + out_i, src + opp_i, - PICT_FRAME - parity, 0); - same_parity = field_output; - opp_i++; - - } else { +static int build_def_list(Picture *def, Picture **in, int len, int is_long, int sel){ + int i[2]={0}; + int index=0; + + while(i[0]reference & sel))) + i[0]++; + while(i[1]reference & (sel^3)))) + i[1]++; + if(i[0] < len){ + in[ i[0] ]->pic_id= is_long ? i[0] : in[ i[0] ]->frame_num; + split_field_copy(&def[index++], in[ i[0]++ ], sel , 1); + } + if(i[1] < len){ + in[ i[1] ]->pic_id= is_long ? i[1] : in[ i[1] ]->frame_num; + split_field_copy(&def[index++], in[ i[1]++ ], sel^3, 0); + } + } + + return index; +} + +static int add_sorted(Picture **sorted, Picture **src, int len, int limit, int dir){ + int i, best_poc; + int out_i= 0; + + for(;;){ + best_poc= dir ? INT_MIN : INT_MAX; + + for(i=0; ipoc; + if(((poc > limit) ^ dir) && ((poc < best_poc) ^ dir)){ + best_poc= poc; + sorted[out_i]= src[i]; + } + } + if(best_poc == (dir ? INT_MIN : INT_MAX)) break; - } - } - + limit= sorted[out_i++]->poc - dir; + } return out_i; } /** - * Split the reference frame list into a reference field list. - * This implements H.264 spec 8.2.4.2.5 for a combined input list. - * The input list contains both reference field pairs and - * unmatched reference fields; it is ordered as spec describes - * RefPicListX for frames in 8.2.4.2.1 and 8.2.4.2.3, except that - * unmatched field pairs are also present. Conceptually this is equivalent - * to concatenation of refFrameListXShortTerm with refFrameListLongTerm. - * - * @param dest output reference list where ordered fields are to be placed - * @param dest_len max number of fields to place at dest - * @param src source reference list, as described above - * @param src_len number of pictures (pairs and unmatched fields) in src - * @param parity parity of field being currently decoded - * (one of PICT_{TOP,BOTTOM}_FIELD) - * @param long_i index into src array that holds first long reference picture, - * or src_len if no long refs present. - */ -static int split_field_ref_list(Picture *dest, int dest_len, - Picture *src, int src_len, - int parity, int long_i){ - - int i = split_field_half_ref_list(dest, dest_len, src, long_i, parity); - dest += i; - dest_len -= i; - - i += split_field_half_ref_list(dest, dest_len, src + long_i, - src_len - long_i, parity); - return i; -} - -/** * fills the default_ref_list. */ static int fill_default_ref_list(H264Context *h){ MpegEncContext * const s = &h->s; - int i; - int smallest_poc_greater_than_current = -1; - int structure_sel; - Picture sorted_short_ref[32]; - Picture field_entry_list[2][32]; - Picture *frame_list[2]; - - if (FIELD_PICTURE) { - structure_sel = PICT_FRAME; - frame_list[0] = field_entry_list[0]; - frame_list[1] = field_entry_list[1]; - } else { - structure_sel = 0; - frame_list[0] = h->default_ref_list[0]; - frame_list[1] = h->default_ref_list[1]; - } + int i, len; if(h->slice_type_nos==FF_B_TYPE){ - int list; - int len[2]; - int short_len[2]; - int out_i; - int limit= INT_MIN; - - /* sort frame according to POC in B slice */ - for(out_i=0; out_ishort_ref_count; out_i++){ - int best_i=INT_MIN; - int best_poc=INT_MAX; - - for(i=0; ishort_ref_count; i++){ - const int poc= h->short_ref[i]->poc; - if(poc > limit && poc < best_poc){ - best_poc= poc; - best_i= i; - } - } - - assert(best_i != INT_MIN); - - limit= best_poc; - sorted_short_ref[out_i]= *h->short_ref[best_i]; - tprintf(h->s.avctx, "sorted poc: %d->%d poc:%d fn:%d\n", best_i, out_i, sorted_short_ref[out_i].poc, sorted_short_ref[out_i].frame_num); - if (-1 == smallest_poc_greater_than_current) { - if (h->short_ref[best_i]->poc >= s->current_picture_ptr->poc) { - smallest_poc_greater_than_current = out_i; - } - } - } - - tprintf(h->s.avctx, "current poc: %d, smallest_poc_greater_than_current: %d\n", s->current_picture_ptr->poc, smallest_poc_greater_than_current); - - // find the largest POC - for(list=0; list<2; list++){ - int index = 0; - int j= -99; - int step= list ? -1 : 1; - - for(i=0; ishort_ref_count && index < h->ref_count[list]; i++, j+=step) { - int sel; - while(j<0 || j>= h->short_ref_count){ - if(j != -99 && step == (list ? -1 : 1)) - return -1; - step = -step; - j= smallest_poc_greater_than_current + (step>>1); - } - sel = sorted_short_ref[j].reference | structure_sel; - if(sel != PICT_FRAME) continue; - frame_list[list][index ]= sorted_short_ref[j]; - frame_list[list][index++].pic_id= sorted_short_ref[j].frame_num; - } - short_len[list] = index; - - for(i = 0; i < 16 && index < h->ref_count[ list ]; i++){ - int sel; - if(h->long_ref[i] == NULL) continue; - sel = h->long_ref[i]->reference | structure_sel; - if(sel != PICT_FRAME) continue; - - frame_list[ list ][index ]= *h->long_ref[i]; - frame_list[ list ][index++].pic_id= i; - } - len[list] = index; - } - - for(list=0; list<2; list++){ - if (FIELD_PICTURE) - len[list] = split_field_ref_list(h->default_ref_list[list], - h->ref_count[list], - frame_list[list], - len[list], - s->picture_structure, - short_len[list]); - - // swap the two first elements of L1 when L0 and L1 are identical - if(list && len[0] > 1 && len[0] == len[1]) - for(i=0; h->default_ref_list[0][i].data[0] == h->default_ref_list[1][i].data[0]; i++) - if(i == len[0]){ - FFSWAP(Picture, h->default_ref_list[1][0], h->default_ref_list[1][1]); - break; - } - - if(len[list] < h->ref_count[ list ]) - memset(&h->default_ref_list[list][len[list]], 0, sizeof(Picture)*(h->ref_count[ list ] - len[list])); - } - - + Picture *sorted[32]; + int cur_poc, list; + int lens[2]; + + if(FIELD_PICTURE) + cur_poc= s->current_picture_ptr->field_poc[ s->picture_structure == PICT_BOTTOM_FIELD ]; + else + cur_poc= s->current_picture_ptr->poc; + + for(list= 0; list<2; list++){ + len= add_sorted(sorted , h->short_ref, h->short_ref_count, cur_poc, 1^list); + len+=add_sorted(sorted+len, h->short_ref, h->short_ref_count, cur_poc, 0^list); + assert(len<=32); + len= build_def_list(h->default_ref_list[list] , sorted , len, 0, s->picture_structure); + len+=build_def_list(h->default_ref_list[list]+len, h->long_ref, 16 , 1, s->picture_structure); + assert(len<=32); + + if(len < h->ref_count[list]) + memset(&h->default_ref_list[list][len], 0, sizeof(Picture)*(h->ref_count[list] - len)); + lens[list]= len; + } + + if(lens[0] == lens[1] && lens[1] > 1){ + for(i=0; h->default_ref_list[0][i].data[0] == h->default_ref_list[1][i].data[0] && idefault_ref_list[1][0], h->default_ref_list[1][1]); + } }else{ - int index=0; - int short_len; - for(i=0; ishort_ref_count; i++){ - int sel; - sel = h->short_ref[i]->reference | structure_sel; - if(sel != PICT_FRAME) continue; - frame_list[0][index ]= *h->short_ref[i]; - frame_list[0][index++].pic_id= h->short_ref[i]->frame_num; - } - short_len = index; - for(i = 0; i < 16; i++){ - int sel; - if(h->long_ref[i] == NULL) continue; - sel = h->long_ref[i]->reference | structure_sel; - if(sel != PICT_FRAME) continue; - frame_list[0][index ]= *h->long_ref[i]; - frame_list[0][index++].pic_id= i; - } - - if (FIELD_PICTURE) - index = split_field_ref_list(h->default_ref_list[0], - h->ref_count[0], frame_list[0], - index, s->picture_structure, - short_len); - - if(index < h->ref_count[0]) - memset(&h->default_ref_list[0][index], 0, sizeof(Picture)*(h->ref_count[0] - index)); + len = build_def_list(h->default_ref_list[0] , h->short_ref, h->short_ref_count, 0, s->picture_structure); + len+= build_def_list(h->default_ref_list[0]+len, h-> long_ref, 16 , 1, s->picture_structure); + assert(len <= 32); + if(len < h->ref_count[0]) + memset(&h->default_ref_list[0][len], 0, sizeof(Picture)*(h->ref_count[0] - len)); } #ifdef TRACE for (i=0; iref_count[0]; i++) {