nengel@2: /* nengel@2: * H.26L/H.264/AVC/JVT/14496-10/... reference picture handling nengel@2: * Copyright (c) 2003 Michael Niedermayer nengel@2: * nengel@2: * This file is part of FFmpeg. nengel@2: * nengel@2: * FFmpeg is free software; you can redistribute it and/or nengel@2: * modify it under the terms of the GNU Lesser General Public nengel@2: * License as published by the Free Software Foundation; either nengel@2: * version 2.1 of the License, or (at your option) any later version. nengel@2: * nengel@2: * FFmpeg is distributed in the hope that it will be useful, nengel@2: * but WITHOUT ANY WARRANTY; without even the implied warranty of nengel@2: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU nengel@2: * Lesser General Public License for more details. nengel@2: * nengel@2: * You should have received a copy of the GNU Lesser General Public nengel@2: * License along with FFmpeg; if not, write to the Free Software nengel@2: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA nengel@2: */ nengel@2: nengel@2: /** nengel@2: * @file nengel@2: * H.264 / AVC / MPEG4 part10 reference picture handling. nengel@2: * @author Michael Niedermayer nengel@2: */ nengel@2: nengel@2: #include "dsputil.h" nengel@2: #include "h264_types.h" nengel@2: #include "golomb.h" nengel@2: nengel@2: //#undef NDEBUG nengel@2: #include nengel@2: nengel@2: static int build_def_list(PictureInfo **def, PictureInfo **in, int len, int is_long){ nengel@2: int i[2]={0}; nengel@2: int index=0; nengel@2: nengel@2: while(i[0]reference))) nengel@2: i[0]++; nengel@2: while(i[1]reference & 0))) nengel@2: i[1]++; nengel@2: if(i[0] < len){ nengel@2: in[ i[0] ]->pic_id= is_long ? i[0] : in[ i[0] ]->frame_num; nengel@2: def[index++]= in[ i[0]++ ]; nengel@2: } nengel@2: if(i[1] < len){ nengel@2: in[ i[1] ]->pic_id= is_long ? i[1] : in[ i[1] ]->frame_num; nengel@2: def[index++]= in[ i[1]++ ]; nengel@2: } nengel@2: } nengel@2: nengel@2: return index; nengel@2: } nengel@2: nengel@2: static int add_sorted(PictureInfo **sorted, PictureInfo **src, int len, int limit, int dir){ nengel@2: int i, best_poc; nengel@2: int out_i= 0; nengel@2: nengel@2: for(;;){ nengel@2: best_poc= dir ? INT_MIN : INT_MAX; nengel@2: nengel@2: for(i=0; ipoc; nengel@2: if(((poc > limit) ^ dir) && ((poc < best_poc) ^ dir)){ nengel@2: best_poc= poc; nengel@2: sorted[out_i]= src[i]; nengel@2: } nengel@2: } nengel@2: if(best_poc == (dir ? INT_MIN : INT_MAX)) nengel@2: break; nengel@2: limit= sorted[out_i++]->poc - dir; nengel@2: } nengel@2: return out_i; nengel@2: } nengel@2: nengel@2: int ff_h264_fill_default_ref_list(NalContext *n, H264Slice *s){ nengel@2: int i,len; nengel@2: nengel@2: if(s->slice_type_nos==FF_B_TYPE){ nengel@2: PictureInfo *sorted[32]; nengel@2: int cur_poc, list; nengel@2: int lens[2]; nengel@2: nengel@2: cur_poc= s->poc; nengel@2: nengel@2: for(list= 0; list<2; list++){ nengel@2: len= add_sorted(sorted, n->short_ref, n->short_ref_count, cur_poc, !list); nengel@2: len+=add_sorted(sorted+len, n->short_ref, n->short_ref_count, cur_poc, list); nengel@2: assert(len<=32); nengel@2: len= build_def_list(s->ref_list[list], sorted, len, 0); nengel@2: len+=build_def_list(s->ref_list[list] +len, n->long_ref, 16 , 1); nengel@2: assert(len<=32); nengel@2: nengel@2: for(int i=len; iref_count[list]; i++) nengel@2: s->ref_list[list][i] = NULL; nengel@2: nengel@2: lens[list]= len; nengel@2: } nengel@2: nengel@2: if(lens[0] == lens[1] && lens[1] > 1){ nengel@2: for(i=0; s->ref_list[0][i]->poc == s->ref_list[1][i]->poc && iref_list[1][0], s->ref_list[1][1]); nengel@2: } nengel@2: }else{ nengel@2: len = build_def_list(s->ref_list[0], n->short_ref, n->short_ref_count, 0); nengel@2: len+= build_def_list(s->ref_list[0] +len, n->long_ref, 16, 1); nengel@2: assert(len <= 32); nengel@2: for(i=len; iref_count[0]; i++) nengel@2: s->ref_list[0][i] = NULL; nengel@2: } nengel@2: nengel@2: return 0; nengel@2: } nengel@2: nengel@2: /** nengel@2: * print short term list nengel@2: */ nengel@2: static void print_short_term(NalContext *n) { nengel@2: av_log(AV_LOG_DEBUG, "short term list:\n"); nengel@2: for(int i=0; ishort_ref_count; i++){ nengel@2: PictureInfo *pic= n->short_ref[i]; nengel@2: av_log(AV_LOG_DEBUG, "%d fn:%d poc:%d ref:%d \n", i, pic->frame_num, pic->poc, pic->reference); nengel@2: } nengel@2: } nengel@2: nengel@2: /** nengel@2: * print long term list nengel@2: */ nengel@2: static void print_long_term(NalContext *n) { nengel@2: uint32_t i; nengel@2: nengel@2: av_log(AV_LOG_DEBUG, "long term list:\n"); nengel@2: for(i = 0; i < 16; i++){ nengel@2: PictureInfo *pic= n->long_ref[i]; nengel@2: if (pic) { nengel@2: av_log(AV_LOG_DEBUG, "%d fn:%d poc:%d\n", i, pic->frame_num, pic->poc); nengel@2: } nengel@2: } nengel@2: } nengel@2: nengel@2: int ff_h264_decode_ref_pic_list_reordering(NalContext *n, H264Slice *s, GetBitContext *gb){ nengel@2: int list, index; nengel@2: nengel@2: print_short_term(n); nengel@2: print_long_term(n); nengel@2: nengel@2: for(list=0; listlist_count; list++){ nengel@2: nengel@2: if(get_bits1(gb)){ nengel@2: int frame_num = n->frame_num; nengel@2: unsigned int abs_diff_pic_num; nengel@2: for(index=0; ; index++){ nengel@2: unsigned int reordering_of_pic_nums_idc= get_ue_golomb_31(gb); nengel@2: int i=0; nengel@2: PictureInfo *ref = NULL; nengel@2: nengel@2: if(reordering_of_pic_nums_idc==3){ nengel@2: break; nengel@2: } nengel@2: if(index >= s->ref_count[list]){ nengel@2: av_log(AV_LOG_ERROR, "reference count overflow\n"); nengel@2: return -1; nengel@2: } nengel@2: nengel@2: if (reordering_of_pic_nums_idc>2){ nengel@2: av_log(AV_LOG_ERROR, "illegal reordering_of_pic_nums_idc\n"); nengel@2: return -1; nengel@2: } nengel@2: nengel@2: if (reordering_of_pic_nums_idc<2){ nengel@2: //av_log(AV_LOG_ERROR, "long term pic not supported\n"); nengel@2: nengel@2: abs_diff_pic_num= get_ue_golomb(gb) + 1; nengel@2: if(abs_diff_pic_num > (unsigned) n->max_pic_num){ nengel@2: av_log(AV_LOG_ERROR, "abs_diff_pic_num overflow\n"); nengel@2: return -1; nengel@2: } nengel@2: nengel@2: if(reordering_of_pic_nums_idc == 0) nengel@2: frame_num-= abs_diff_pic_num; nengel@2: else nengel@2: frame_num+= abs_diff_pic_num; nengel@2: frame_num &= n->max_pic_num - 1; nengel@2: nengel@2: for(i= 0 ; ishort_ref_count; i++){ nengel@2: ref = n->short_ref[i]; nengel@2: if(ref->frame_num == frame_num && ref->reference){ nengel@2: break; nengel@2: } nengel@2: } nengel@2: ref->pic_id= frame_num; nengel@2: }else{ nengel@2: int long_idx; nengel@2: long_idx= get_ue_golomb(gb); //long_term_pic_idx nengel@2: nengel@2: if(long_idx>31){ nengel@2: av_log(AV_LOG_ERROR, "long_term_pic_idx overflow\n"); nengel@2: return -1; nengel@2: } nengel@2: ref = n->long_ref[long_idx]; nengel@2: assert(!(ref && !ref->reference)); nengel@2: if(ref && (ref->reference)){ nengel@2: ref->pic_id= long_idx; nengel@2: assert(ref->long_ref); nengel@2: }else{ nengel@2: av_log(AV_LOG_ERROR, "reference picture missing during reorder\n"); nengel@2: } nengel@2: } nengel@2: nengel@2: if (i >= n->short_ref_count) { nengel@2: av_log(AV_LOG_ERROR, "reference picture missing during reorder\n"); nengel@2: return -1; nengel@2: } else { nengel@2: for(i=index; i+1 ref_count[list]; i++){ nengel@2: nengel@2: // if(ref->frame_num == s->ref_list[list][i]->frame_num) nengel@2: // break; nengel@2: ///there is probably no need for a separate pic_id and frame_num nengel@2: if (s->ref_list[list][i]){ nengel@2: nengel@2: if(ref->long_ref == s->ref_list[list][i]->long_ref && ref->pic_id == s->ref_list[list][i]->pic_id) nengel@2: break; nengel@2: } nengel@2: } nengel@2: for(; i > index; i--){ nengel@2: s->ref_list[list][i]= s->ref_list[list][i-1]; nengel@2: } nengel@2: s->ref_list[list][index]= ref; nengel@2: } nengel@2: } nengel@2: } nengel@2: } nengel@2: nengel@2: // //Check if everything went well nengel@2: // for(list=0; listlist_count; list++){ nengel@2: // //printf("ref_count %d list %d\n", s->ref_count[list], list); nengel@2: // for(index= 0; index < s->ref_count[list]; index++){ nengel@2: // //printf("%d\n", s->ref_list[list][index]->pic_id); nengel@2: // if(!s->ref_list[list][index]->data[0]){ nengel@2: // av_log(AV_LOG_ERROR, "Missing reference picture\n"); nengel@2: // return -1; nengel@2: // } nengel@2: // } nengel@2: // } nengel@2: nengel@2: return 0; nengel@2: } nengel@2: nengel@2: static PictureInfo *find_short(NalContext *n, int frame_num){ nengel@2: int i; nengel@2: for(i=0; ishort_ref_count; i++){ nengel@2: if(n->short_ref[i]->frame_num == frame_num) { nengel@2: return n->short_ref[i]; nengel@2: } nengel@2: } nengel@2: return NULL; nengel@2: } nengel@2: nengel@2: static int remove_short(NalContext *n, H264Slice *s, int frame_num, int release){ nengel@2: int i; nengel@2: nengel@2: for (i=0; ishort_ref_count; i++){ nengel@2: if (n->short_ref[i]->frame_num == frame_num){ nengel@2: if (release){ nengel@2: s->release_ref_cpn[s->release_cnt++] = n->short_ref[i]->cpn; nengel@2: n->short_ref[i]->reference &= ~2; nengel@2: } nengel@2: n->short_ref[i] = NULL; nengel@2: if (--n->short_ref_count) nengel@2: memmove(&n->short_ref[i], &n->short_ref[i+1], (n->short_ref_count - i)*sizeof(PictureInfo *)); nengel@2: return 0; nengel@2: } nengel@2: } nengel@2: return -1; nengel@2: } nengel@2: nengel@2: static void remove_long(NalContext *n, H264Slice *s, int i){ nengel@2: nengel@2: if (n->long_ref[i]){ nengel@2: s->release_ref_cpn[s->release_cnt++] = n->long_ref[i]->cpn; nengel@2: n->long_ref[i]->reference &= ~2; nengel@2: n->long_ref[i]->long_ref = 0; nengel@2: n->long_ref_count--; nengel@2: n->long_ref[i] = NULL; nengel@2: } nengel@2: } nengel@2: nengel@2: void ff_h264_remove_all_refs(NalContext *n, H264Slice *s){ nengel@2: int i; nengel@2: nengel@2: while (n->short_ref[0]) nengel@2: remove_short(n, s, n->short_ref[0]->frame_num, 1); nengel@2: nengel@2: for(i=0; i<16; i++){ nengel@2: remove_long(n, s, i); nengel@2: } nengel@2: assert(n->short_ref_count==0); nengel@2: assert(n->long_ref_count==0); nengel@2: } nengel@2: nengel@2: int ff_h264_ref_pic_marking(NalContext *n, H264Slice *s, GetBitContext *gb){ nengel@2: nengel@2: if(s->nal_unit_type == NAL_IDR_SLICE){ //FIXME fields nengel@2: get_bits1(gb); //get_bits1(gb) -1; //broken link nengel@2: if(get_bits1(gb)){ nengel@2: av_log(AV_LOG_ERROR, "MMCO_LONG reference management not supported\n"); nengel@2: } nengel@2: }else{ nengel@2: if(get_bits1(gb)){ // adaptive_ref_pic_marking_mode_flag nengel@2: int i,j; nengel@2: for(i= 0; iframe_num - get_ue_golomb(gb) - 1) & (n->max_pic_num - 1); nengel@2: } nengel@2: if(opcode==MMCO_SHORT2LONG || opcode==MMCO_LONG2UNUSED || opcode==MMCO_LONG || opcode==MMCO_SET_MAX_LONG){ nengel@2: long_arg= get_ue_golomb_31(gb); nengel@2: if(long_arg >= 16){ nengel@2: av_log(AV_LOG_ERROR, "illegal long ref in memory management control operation %d\n", opcode); nengel@2: return -1; nengel@2: } nengel@2: } nengel@2: nengel@2: if(opcode > (unsigned)MMCO_LONG){ nengel@2: av_log(AV_LOG_ERROR, "illegal memory management control operation %d\n", opcode); nengel@2: return -1; nengel@2: } nengel@2: if(opcode == MMCO_END) nengel@2: break; nengel@2: nengel@2: switch (opcode){ nengel@2: case MMCO_SHORT2UNUSED: nengel@2: remove_short(n, s, short_pic_num, 1); nengel@2: break; nengel@2: case MMCO_SHORT2LONG: nengel@2: pic = find_short(n, short_pic_num); nengel@2: if (n->long_ref[long_arg] != pic) nengel@2: remove_long(n, s, long_arg); nengel@2: remove_short(n, s, short_pic_num, 0); nengel@2: n->long_ref[long_arg]= pic; nengel@2: if (pic){ nengel@2: pic->long_ref=1; nengel@2: n->long_ref[long_arg]= pic; nengel@2: n->long_ref_count++; nengel@2: } nengel@2: break; nengel@2: case MMCO_LONG2UNUSED: nengel@2: assert(n->long_ref[long_arg]); nengel@2: remove_long(n, s, long_arg); nengel@2: break; nengel@2: case MMCO_SET_MAX_LONG: nengel@2: for(j=long_arg; j<16; j++) nengel@2: remove_long(n, s, j); nengel@2: break; nengel@2: case MMCO_RESET: nengel@2: while(n->short_ref_count) nengel@2: remove_short(n, s, n->short_ref[0]->frame_num, 1); nengel@2: nengel@2: for(j=0; j < 16; j++) nengel@2: remove_long(n, s, j); nengel@2: nengel@2: s->current_picture_info->poc= nengel@2: s->poc = nengel@2: n->poc_lsb= nengel@2: n->poc_msb= nengel@2: n->frame_num= nengel@2: s->current_picture_info->frame_num= 0; nengel@2: break; nengel@2: case MMCO_END: nengel@2: case MMCO_LONG: nengel@2: break; nengel@2: } nengel@2: } nengel@2: }else{// sliding window ref picture marking nengel@2: if(n->short_ref_count == n->sps.ref_frame_count) { nengel@2: s->release_ref_cpn[s->release_cnt++] = n->short_ref[n->short_ref_count - 1]->cpn; nengel@2: n->short_ref[n->short_ref_count - 1]->reference &= ~2; nengel@2: n->short_ref[ n->short_ref_count - 1 ] =NULL; nengel@2: n->short_ref_count--; nengel@2: } nengel@2: } nengel@2: } nengel@2: nengel@2: if(n->short_ref_count) nengel@2: memmove(&n->short_ref[1], &n->short_ref[0], n->short_ref_count*sizeof(PictureInfo *)); nengel@2: nengel@2: n->short_ref[0]= s->current_picture_info; nengel@2: n->short_ref_count++; nengel@2: nengel@2: return 0; nengel@2: } nengel@2: nengel@2: static int get_scale_factor(H264Slice *s, int poc, int poc1, int i){ nengel@2: int poc0 = s->ref_list[0][i]->poc; nengel@2: int td = av_clip(poc1 - poc0, -128, 127); nengel@2: if(td == 0 || s->ref_list[0][i]->long_ref){ nengel@2: return 256; nengel@2: }else{ nengel@2: int tb = av_clip(poc - poc0, -128, 127); nengel@2: int tx = (16384 + (FFABS(td) >> 1)) / td; nengel@2: return av_clip((tb*tx + 32) >> 6, -1024, 1023); nengel@2: } nengel@2: } nengel@2: nengel@2: void ff_h264_direct_dist_scale_factor(H264Slice *s){ nengel@2: const int poc = s->current_picture_info->poc; nengel@2: const int poc1 = s->ref_list[1][0]->poc; nengel@2: nengel@2: for(int i=0; iref_count[0]; i++){ nengel@2: s->dist_scale_factor[i] = get_scale_factor(s, poc, poc1, i); nengel@2: } nengel@2: } nengel@2: nengel@2: static void fill_colmap(H264Slice *s, int map[2][16], int list){ nengel@2: PictureInfo * const ref1 = s->ref_list[1][0]; nengel@2: int old_ref, rfield; nengel@2: nengel@2: /* bogus; fills in for missing frames */ nengel@2: memset(map[list], 0, sizeof(map[list])); nengel@2: nengel@2: for(rfield=0; rfield<2; rfield++){ nengel@2: for(old_ref=0; old_ref < ref1->ref_count[list]; old_ref++){ nengel@2: int poc = ref1->ref_poc[list][old_ref]; nengel@2: nengel@2: for(int j=0; jref_count[0]; j++){ nengel@2: if(s->ref_list[0][j]->poc == poc){ nengel@2: map[list][old_ref] = j; nengel@2: break; nengel@2: } nengel@2: } nengel@2: } nengel@2: } nengel@2: } nengel@2: nengel@2: void ff_h264_direct_ref_list_init(H264Slice *s){ nengel@2: PictureInfo * const cur = s->current_picture_info; nengel@2: int list; nengel@2: nengel@2: for(list=0; list<2; list++){ nengel@2: cur->ref_count[list] = s->ref_count[list]; nengel@2: for(int j=0; jref_count[list]; j++){ nengel@2: cur->ref_poc[list][j] = s->ref_list[list][j] ? s->ref_list[list][j]->poc : 0; nengel@2: } nengel@2: } nengel@2: nengel@2: if(s->slice_type_nos != FF_B_TYPE || s->direct_spatial_mv_pred) nengel@2: return; nengel@2: nengel@2: for(list=0; list<2; list++){ nengel@2: fill_colmap(s, s->map_col_to_list0, list); nengel@2: } nengel@2: } nengel@2: