/* * Copyright (C) 2020-2022 Artinchip Technology Co. Ltd * * author: * Desc: refrence frame function * */ #include #include #include #include "h264_decoder.h" #define REFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0) static void print_short_term(struct h264_dec_ctx *s) { int i; struct h264_picture* pic = NULL; logi("====== print short-term ref ======"); for(i=0; ishort_ref_count; i++) { pic = s->frame_info.short_ref[i]; if(pic) { logd("i: %d, frame_num: %d, poc: %d, buf_idx: %d, structure: %d", i, pic->frame_num, pic->poc, pic->buf_idx, pic->picture_structure); } } } static void print_long_term(struct h264_dec_ctx *s) { int i; struct h264_picture* pic = NULL; logi("====== print long-term ref cnt: %d======", s->long_ref_count); for(i=0; ilong_ref_count; i++) { pic = s->frame_info.long_ref[i]; if(pic) { logd("i: %d, frame_num: %d, poc: %d, buf_idx: %d, structure: %d", i, pic->frame_num, pic->poc, pic->buf_idx, pic->picture_structure); } } } /** * Extract structure information about the picture described by pic_num in * the current decoding context (frame or field). Note that pic_num is * picture number without wrapping (so, 0<=pic_numpicture_structure; if (s->picture_structure != PICT_FRAME) { if (!(pic_num & 1)) /* opposite field */ *structure ^= PICT_FRAME; pic_num >>= 1; } return pic_num; } /** * Mark a picture as no longer needed for reference. The refmask * argument allows unreferencing of individual fields or the whole frame. * If the picture becomes entirely unreferenced, but is being held for * display purposes, it is marked as such. * @param refmask mask of fields to unreference; the mask is bitwise * anded with the reference marking of pic * @return non-zero if pic becomes entirely unreferenced (except possibly * for display purposes) zero if one of the fields remains in * reference */ static int unreference_pic(struct h264_dec_ctx *s, struct h264_picture *pic, int refmask) { int i = 0; logi("unreference_pic, buf_idx: %d, refrence: %d, refmask: %d, display: %d", pic->buf_idx, pic->refrence, refmask, pic->displayed_flag); if(pic->refrence &= refmask) { //* if one field of this frame is unrefrence, do nothing return 0; } else { //* if one field of this frame is unrefrence, set DELAYED_PIC_REF to this field for(i=0; s->frame_info.delayed_pic[i]; i++) { if(pic == s->frame_info.delayed_pic[i]) { pic->refrence = DELAYED_PIC_REF; break; } } //* if this frame is unrefrence, return it if((pic->refrence == 0 || pic->refrence == 4) && pic->frame) { fm_decoder_put_frame(s->decoder.fm, pic->frame); } return 1; } } /** * Find a h264_picture in the short term reference list by frame number. * @param frame_num frame number to search for * @param idx the index into h->short_ref where returned picture is found * undefined if no picture found. * @return pointer to the found picture, or NULL if no pic with the provided * frame number is found */ static struct h264_picture *find_short(struct h264_dec_ctx *h, int frame_num, int *idx) { int i; for (i = 0; i < h->short_ref_count; i++) { struct h264_picture *pic = h->frame_info.short_ref[i]; logd("%d %d %p\n", i, pic->frame_num, pic); if (pic->frame_num == frame_num) { *idx = i; return pic; } } return NULL; } /** * Remove a picture from the short term reference list by its index in * that list. This does no checking on the provided index; it is assumed * to be valid. Other list entries are shifted down. * @param i index into h->short_ref of picture to remove. */ static void remove_short_at_index(struct h264_dec_ctx *s, int i) { assert(i >= 0 && i < s->short_ref_count); s->frame_info.short_ref[i] = NULL; if (--s->short_ref_count) memmove(&s->frame_info.short_ref[i], &s->frame_info.short_ref[i + 1], (s->short_ref_count - i) * sizeof(struct h264_picture*)); } /** * Remove a picture from the long term reference list by its index in * that list. * @return the removed picture or NULL if an error occurs */ static struct h264_picture *remove_long(struct h264_dec_ctx *s, int i, int ref_mask) { struct h264_picture *pic; pic = s->frame_info.long_ref[i]; if (pic) { if (unreference_pic(s, pic, ref_mask)) { assert(s->frame_info.long_ref[i]->long_ref == 1); s->frame_info.long_ref[i]->long_ref = 0; s->frame_info.long_ref[i] = NULL; s->long_ref_count--; } } return pic; } static int split_field_copy(struct h264_ref *dest, struct h264_picture *src, int parity, int id_add) { int match = !!(src->refrence & parity); if(match) { dest->refrence = src->refrence; dest->poc = src->poc; dest->pic_id = src->pic_id; dest->parent = src; if(parity != PICT_FRAME) { dest->refrence = parity; dest->pic_id *= 2; dest->pic_id += id_add; dest->poc = src->field_poc[parity == PICT_BOTTOM_FIELD]; logd("dest: refrence: %d, poc: %d", dest->refrence, dest->poc); } } return match; } static int h264_build_def_list(struct h264_ref *def, struct h264_picture **in, int len, int is_long, int sel) { int i[2] = {0}; int index = 0; logd("h264_build_def_list long-term: %d, structure: %d", is_long, sel); while(i[0]refrence & sel))) i[0]++; while(i[1]refrence & (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; } /* order picture by poc limit: poc of current picture dir: 0-ascending order; 1-descending order */ static int add_sorted(struct h264_picture **sorted, struct h264_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; i < len; i++) { const int poc = src[i]->poc; 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; } /* * */ static struct h264_picture* remove_short(struct h264_dec_ctx* s, int frame_num, int ref_mask) { struct h264_picture* pic = NULL; int idx; pic = find_short(s, frame_num, &idx); if(pic) { if(unreference_pic(s, pic, ref_mask)) remove_short_at_index(s, idx); } return pic; } static void generate_sliding_window_mmcos(struct h264_dec_ctx *s) { struct mmco* mmco = s->sh.mmco; int nb_mmco = 0; struct h264_sps_info* cur_sps = s->sps_buffers[s->active_sps_id]; if(s->short_ref_count && s->long_ref_count + s->short_ref_count >= cur_sps->max_num_ref_frames && !((s->picture_structure != PICT_FRAME) && !s->first_field && s->frame_info.cur_pic_ptr->refrence)) { mmco[0].opcode = MMCO_SHORT2UNUSED; mmco[0].short_pic_num = s->frame_info.short_ref[s->short_ref_count-1]->frame_num; nb_mmco = 1; if(s->picture_structure != PICT_FRAME) { mmco[0].short_pic_num *= 2; mmco[1].opcode = MMCO_SHORT2UNUSED; mmco[1].short_pic_num = mmco[0].short_pic_num + 1; nb_mmco = 2; } } s->sh.nb_mmco = nb_mmco; } int execute_ref_pic_marking(struct h264_dec_ctx *s) { int i=0, j=0; int frame_num = 0; int structure = 0; int current_ref_assigned = 0; struct h264_picture* pic = NULL; struct h264_sps_info* cur_sps = s->sps_buffers[s->active_sps_id]; struct mmco* mmco = s->sh.mmco; int mmco_cnt; print_short_term(s); print_long_term(s); if(!s->sh.explicit_ref_marking) generate_sliding_window_mmcos(s); mmco_cnt = s->sh.nb_mmco; logi("explicit_ref_marking: %d, mmco_cnt: %d", s->sh.explicit_ref_marking, mmco_cnt); for(i=0; iframe_info.long_ref[mmco[i].long_arg] || s->frame_info.long_ref[mmco[i].long_arg]->frame_num != frame_num) { loge("mmco: unref short failure"); } continue; } } switch(mmco[i].opcode) { case MMCO_SHORT2UNUSED: { remove_short(s, frame_num, structure ^ PICT_FRAME); break; } case MMCO_SHORT2LONG: { if(s->frame_info.long_ref[mmco[i].long_arg] != pic) remove_long(s, mmco[i].long_arg, 0); remove_short_at_index(s, j); s->frame_info.long_ref[ mmco[i].long_arg ] = pic; if(s->frame_info.long_ref[ mmco[i].long_arg ]) { s->frame_info.long_ref[ mmco[i].long_arg ]->long_ref = 1; s->long_ref_count++; } break; } case MMCO_LONG2UNUSED: { j = pic_num_extract(s, mmco[i].long_arg, &structure); pic = s->frame_info.long_ref[j]; if(!pic) { loge("mmco unref long failed"); } remove_long(s, j, structure ^ PICT_FRAME); break; } case MMCO_LONG: { // Comment below left from previous code as it is an interesting note. /* First field in pair is in short term list or * at a different long term index. * This is not allowed; see 7.4.3.3, notes 2 and 3. * Report the problem and keep the pair where it is, * and mark this field valid. */ if(s->frame_info.short_ref[0] == s->frame_info.cur_pic_ptr) { loge("mmco: cannot assign current picture to short and long at the same time"); remove_short_at_index(s, 0); } /* make sure the current picture is not already assigned as a long ref */ if(s->frame_info.cur_pic_ptr->long_ref) { for(j=0; j<32; j++) { if(s->frame_info.long_ref[j] == s->frame_info.cur_pic_ptr) { if(j != mmco[i].long_arg) { logw("mmco: cannot assign current picture to 2 long term references"); } remove_long(s, j, 0); } } } if(s->frame_info.long_ref[mmco[i].long_arg] != s->frame_info.cur_pic_ptr) { remove_long(s, mmco[i].long_arg, 0); s->frame_info.long_ref[mmco[i].long_arg] = s->frame_info.cur_pic_ptr; s->frame_info.long_ref[mmco[i].long_arg]->long_ref = 1; s->long_ref_count++; } s->frame_info.cur_pic_ptr->refrence |= s->picture_structure; current_ref_assigned = 1; break; } case MMCO_SET_MAX_LONG: { // remove the long term which index is greater than new max for(j=mmco[i].long_arg; j<16; j++) { remove_long(s, j, 0); } break; } case MMCO_RESET: { while(s->short_ref_count) { remove_short(s, s->frame_info.short_ref[0]->frame_num, 0); } for(j=0; j<16; j++) { remove_long(s, j, 0); } s->sh.frame_num = 0; s->frame_info.cur_pic_ptr->frame_num = 0; s->frame_info.cur_pic_ptr->mmco_reset = 1; for(j=0; jframe_info.last_pocs[j] = INT_MIN; } break; } default: loge("error mmco type(%d)", mmco[i].opcode); } } logi("current_ref_assigned: %d", current_ref_assigned); if(!current_ref_assigned) { /* Second field of complementary field pair; the first field of * which is already referenced. If short referenced, it * should be first entry in short_ref. If not, it must exist * in long_ref; trying to put it on the short list here is an * error in the encoded bit stream (ref: 7.4.3.3, NOTE 2 and 3). */ logd("s->short_ref_count: %d", s->short_ref_count); if(s->short_ref_count && s->frame_info.short_ref[0] == s->frame_info.cur_pic_ptr) { s->frame_info.cur_pic_ptr->refrence |= s->picture_structure; } else if(s->frame_info.cur_pic_ptr->long_ref) { loge("illegal short term reference assignment for second field"); return -1; } else {logd("s->frame_info.cur_pic_ptr->frame_num: %d", s->frame_info.cur_pic_ptr->frame_num); pic = remove_short(s, s->frame_info.cur_pic_ptr->frame_num, 0); if(pic) { loge("illegal short term buffer state detected"); return -1; } if(s->short_ref_count) { memmove(&s->frame_info.short_ref[1],&s->frame_info.short_ref[0], s->short_ref_count * sizeof(struct h264_picture*)); } s->frame_info.short_ref[0] = s->frame_info.cur_pic_ptr; s->short_ref_count++; s->frame_info.cur_pic_ptr->refrence |= s->picture_structure; } } logi("s->long_ref_count: %d, short_ref_count: %d, max_num_ref_frames: %d", s->long_ref_count, s->short_ref_count, cur_sps->max_num_ref_frames); if(s->long_ref_count + s->short_ref_count > cur_sps->max_num_ref_frames) { /* We have too many reference frames, probably due to corrupted * stream. Need to discard one frame. Prevents overrun of the * short_ref and long_ref buffers. */ if(s->long_ref_count && !s->short_ref_count) { for(i=0; i<16; i++) { if(s->frame_info.long_ref[i]) break; } remove_long(s, i, 0); } else { pic = s->frame_info.short_ref[s->short_ref_count-1]; remove_short(s, pic->frame_num, 0); } } print_short_term(s); print_long_term(s); return 0; } void reference_refresh(struct h264_dec_ctx *s) { int i = 0; for(i=0; ilong_ref_count; i++) { if(s->frame_info.long_ref[i]) { unreference_pic(s, s->frame_info.long_ref[i], 0); s->frame_info.long_ref[i] = NULL; } } s->long_ref_count = 0; for(i=0; ishort_ref_count; i++) { if(s->frame_info.short_ref[i]) { unreference_pic(s, s->frame_info.short_ref[i], 0); s->frame_info.short_ref[i] = NULL; } } s->short_ref_count = 0; } int init_ref_list(struct h264_dec_ctx *s) { struct h264_slice_header* sh = &s->sh; int lens[2]; int len; int i; // print_short_term(s); // print_long_term(s); if(sh->slice_type == H264_SLICE_B) { struct h264_picture* sorted[32]; int cur_poc, list; if(s->picture_structure != PICT_FRAME) { cur_poc = s->frame_info.cur_pic_ptr->field_poc[s->picture_structure == PICT_BOTTOM_FIELD]; } else { cur_poc = s->frame_info.cur_pic_ptr->poc; } for(list =0; list < 2; list++) { // sort short-term ref len = add_sorted(sorted, s->frame_info.short_ref, s->short_ref_count, cur_poc, 1^list); len += add_sorted(sorted+len, s->frame_info.short_ref, s->short_ref_count, cur_poc, 0^list); len = h264_build_def_list(s->frame_info.def_ref_list[list], sorted, len, 0, s->picture_structure); len += h264_build_def_list(s->frame_info.def_ref_list[list]+len, s->frame_info.long_ref, 16, 1, s->picture_structure); if(len < sh->num_ref_idx[list]) { memset(&s->frame_info.def_ref_list[list][len], 0, sizeof(struct h264_ref)* (sh->num_ref_idx[list]-len)); } lens[list] = len; } // why ??? from ffmpeg if (lens[0] == lens[1] && lens[1] > 1) { for (i = 0; i < lens[0] && s->frame_info.def_ref_list[0][i].parent->buf_idx == s->frame_info.def_ref_list[1][i].parent->buf_idx; i++); if (i == lens[0]) { REFSWAP(struct h264_ref,s->frame_info.def_ref_list[1][0], s->frame_info.def_ref_list[1][1]); } } } else { len = h264_build_def_list(s->frame_info.def_ref_list[0], s->frame_info.short_ref, s->short_ref_count, 0, s->picture_structure); len += h264_build_def_list(s->frame_info.def_ref_list[0]+len, s->frame_info.long_ref, 16, 1, s->picture_structure); if(len < sh->num_ref_idx[0]) { memset(&s->frame_info.def_ref_list[0][len], 0, sizeof(struct h264_ref)* (sh->num_ref_idx[0]-len)); } } /* int list = 0; struct h264_picture* pic = NULL; for(i=0; ish.num_ref_idx[0]; i++) { pic = s->frame_info.def_ref_list[0][i].parent; logd("list: %d, i: %d, buf_idx: %d, structure: %d, poc: %d", 0, i, pic->buf_idx, s->frame_info.def_ref_list[0][i].refrence, s->frame_info.def_ref_list[0][i].poc); } */ return 0; } int ref_pic_list_reordering(struct h264_dec_ctx *s) { struct h264_slice_header* sh = &s->sh; struct h264_picture* ref; int list, index, i; unsigned int abs_diff_pic_num; int pred; int frame_num; int pic_structure; logd("sh->list_count: %d", sh->list_count); for(list=0; listlist_count; list++) { memcpy(s->frame_info.ref_list[list], s->frame_info.def_ref_list[list], sizeof(struct h264_ref)*sh->num_ref_idx[list]); int flag = read_bits(&s->gb, 1); if(!flag) continue; pred = sh->cur_pic_num; for(index=0; ; index++) { unsigned int modification_of_pic_nums_idc = read_ue_golomb(&s->gb); if(modification_of_pic_nums_idc > 3) { loge("not support modification_of_pic_nums_idc: %d", modification_of_pic_nums_idc); return -1; } if(modification_of_pic_nums_idc == 3) break; if(index >= sh->num_ref_idx[list]) { loge("index(%d) out of range(%d)", index, sh->num_ref_idx[list]); return -1; } switch(modification_of_pic_nums_idc) { case 0: case 1: { abs_diff_pic_num = read_ue_golomb(&s->gb) + 1; if(abs_diff_pic_num > sh->max_pic_num) { loge("abs_diff_pic_num(%d) > sh->max_pic_num(%d)", abs_diff_pic_num, sh->max_pic_num); return -1; } if(modification_of_pic_nums_idc == 0) pred -= abs_diff_pic_num; else pred += abs_diff_pic_num; pred &= sh->max_pic_num -1; frame_num = pic_num_extract(s, pred, &pic_structure); for(i=s->short_ref_count-1; i>=0; i--) { ref = s->frame_info.short_ref[i]; if(ref->frame_num == frame_num && (ref->refrence & pic_structure)) break; } if(i >= 0) ref->pic_id = pred; break; } case 2: { unsigned int pic_id = read_ue_golomb(&s->gb); int long_idx = pic_num_extract(s, pic_id, &pic_structure); if(long_idx > 31) { loge("long_idx(%d), error", long_idx); return -1; } ref = s->frame_info.long_ref[long_idx]; if(ref && (ref->refrence & pic_structure)) { ref->pic_id = pic_id; i=0; } else { i = -1; } break; } default: loge("not support modification_of_pic_nums_idc: %d", modification_of_pic_nums_idc); return -1; } if(i < 0) { loge("i(%d) < 0", i); return -1; } for(i=index; inum_ref_idx[list]-1; i++) { if(s->frame_info.ref_list[list][i].parent && ref->long_ref == s->frame_info.ref_list[list][i].parent->long_ref && ref->pic_id == s->frame_info.ref_list[list][i].pic_id) break; } for(; i>index; i--) { s->frame_info.ref_list[list][i] = s->frame_info.ref_list[list][i-1]; } s->frame_info.ref_list[list][index].refrence = ref->refrence; s->frame_info.ref_list[list][index].pic_id = ref->pic_id; s->frame_info.ref_list[list][index].poc = ref->poc; s->frame_info.ref_list[list][index].parent = ref; if(s->picture_structure != PICT_FRAME) { s->frame_info.ref_list[list][index].refrence = pic_structure; s->frame_info.ref_list[list][index].poc = ref->field_poc[pic_structure == PICT_BOTTOM_FIELD]; } } } if(sh->slice_type == H264_SLICE_I) { s->frame_info.cur_pic_ptr->ref_count[0] = 0; } else if(sh->slice_type != H264_SLICE_B) { s->frame_info.cur_pic_ptr->ref_count[1] = 0; } for(list = 0; list < 2; list++) { s->frame_info.cur_pic_ptr->ref_count[list] = sh->num_ref_idx[list]; } return 0; } static struct h264_picture* get_one_frame_from_delayed(struct h264_dec_ctx *s) { int i; int min_poc = INT_MAX; int idx = 0; struct h264_picture* out_pic = NULL; if(s->frame_info.delay_pic_num == 0) { return NULL; } for(i=0; iframe_info.delay_pic_num; i++) { if(s->frame_info.delayed_pic[i]->poc < min_poc) { min_poc = s->frame_info.delayed_pic[i]->poc; out_pic = s->frame_info.delayed_pic[i]; idx = i; } } for(i=idx; iframe_info.delay_pic_num; i++) { s->frame_info.delayed_pic[i] = s->frame_info.delayed_pic[i+1]; } s->min_display_poc = out_pic->poc; s->frame_info.delay_pic_num--; return out_pic; } int render_all_delayed_frame(struct h264_dec_ctx *s) { struct h264_picture* out_pic = NULL; logd("delay_pic_num: %d", s->frame_info.delay_pic_num); while(s->frame_info.delay_pic_num) { out_pic = get_one_frame_from_delayed(s); if(s->frame_info.delay_pic_num == 0 && s->eos) { out_pic->frame->mpp_frame.flags |= FRAME_FLAG_EOS; } logi("render frame poc: %d, buf_idx: %d, id: %d, refrence: %d", out_pic->poc, out_pic->buf_idx, out_pic->frame->mpp_frame.id, out_pic->refrence); // send this frame to render, not call decoder_put_frame here. // decoder_put_frame will be called in reference_refresh fm_decoder_frame_to_render(s->decoder.fm, out_pic->frame, 1); // if the out_pic is not used for refrence, return it if((!out_pic->nal_ref_idc[0] && out_pic->picture_structure == PICT_FRAME) || (!out_pic->nal_ref_idc[0] && !out_pic->nal_ref_idc[1] && out_pic->picture_structure != PICT_FRAME)) fm_decoder_put_frame(s->decoder.fm, out_pic->frame); } return 0; } void select_output_frame(struct h264_dec_ctx *s) { int i; int min_poc = INT_MAX; int max_poc = -1; int idx = 0; int out_of_order = 0; struct h264_sps_info* cur_sps = s->sps_buffers[s->active_sps_id]; struct h264_picture* cur_pic = s->frame_info.cur_pic_ptr; struct h264_picture* out_pic = NULL; struct h264_picture* max_poc_pic = NULL; //* 1. order poc, start pos is 16 to 0 for(i=0; i<=MAX_DELAYED_PIC_COUNT; i++) { if(i == MAX_DELAYED_PIC_COUNT || cur_pic->poc < s->frame_info.last_pocs[i]) { if(i) s->frame_info.last_pocs[i-1] = cur_pic->poc; break; } else if(i) { s->frame_info.last_pocs[i-1] = s->frame_info.last_pocs[i]; } } out_of_order = MAX_DELAYED_PIC_COUNT - i; if(s->sh.slice_type == H264_SLICE_B || (s->frame_info.last_pocs[MAX_DELAYED_PIC_COUNT-2] > INT_MIN && s->frame_info.last_pocs[MAX_DELAYED_PIC_COUNT-1] - (int64_t)s->frame_info.last_pocs[MAX_DELAYED_PIC_COUNT-2] > 2)) { out_of_order = out_of_order > 1 ? out_of_order : 1; } if(out_of_order == MAX_DELAYED_PIC_COUNT) { loge("invalid poc %d < %d", cur_pic->poc, s->frame_info.last_pocs[0]); for(i=0; iframe_info.last_pocs[i] = INT_MIN; s->frame_info.last_pocs[0] = cur_pic->poc; cur_pic->mmco_reset = 1; } else if(s->has_b_frames < out_of_order) { s->has_b_frames = out_of_order; } if(cur_sps->max_num_ref_frames > 13) { logi("force set has_b_frames to 0"); s->has_b_frames = 0; } if(s->has_b_frames > s->b_frames_max_num) s->has_b_frames = s->b_frames_max_num; logd("s->has_b_frames: %d, b_frames_max_num: %d", s->has_b_frames, s->b_frames_max_num); //* 1. add cur_pic to delay_pic list s->frame_info.delayed_pic[s->frame_info.delay_pic_num++] = cur_pic; s->frame_info.delayed_pic[s->frame_info.delay_pic_num] = NULL; s->frame_info.cur_pic_ptr = NULL; logd("delay_pic_num: %d %p", s->frame_info.delay_pic_num, s->frame_info.delayed_pic[0]); //* 2. find the picture with min poc in delayed_pic list for(i=0; iframe_info.delay_pic_num; i++) { if(s->frame_info.delayed_pic[i]->poc < min_poc) { min_poc = s->frame_info.delayed_pic[i]->poc; out_pic = s->frame_info.delayed_pic[i]; idx = i; } if(s->frame_info.delayed_pic[i]->poc > max_poc) { max_poc = s->frame_info.delayed_pic[i]->poc; max_poc_pic = s->frame_info.delayed_pic[i]; } } logd("min_poc: %d, s->curr_packet: %p", min_poc, s->curr_packet); logd("max_poc: %d, s->curr_packet flag: %d", max_poc, s->curr_packet->flag); //* set eos flag to the frame with max poc if(s->curr_packet->flag & PACKET_FLAG_EOS) max_poc_pic->frame->mpp_frame.flags |= FRAME_FLAG_EOS; if(s->has_b_frames == 0 && (s->frame_info.delayed_pic[0]->key_frame || s->frame_info.delayed_pic[0]->mmco_reset)) s->next_output_poc = INT_MIN; out_of_order = out_pic->poc < s->next_output_poc; //* out of order, discard this frame if (out_of_order) { logw("out_of_order: %d, delay_num: %d, has_b_frame: %d", out_of_order, s->frame_info.delay_pic_num, s->has_b_frames); logw("discard this frame, poc: %d, buf_idx: %d", out_pic->poc, out_pic->buf_idx); out_pic->refrence &= ~DELAYED_PIC_REF; s->frame_info.delay_pic_num --; fm_decoder_frame_to_render(s->decoder.fm, out_pic->frame, 0); // if the out_pic is not used for refrence, return it if((!out_pic->nal_ref_idc[0] && out_pic->picture_structure == PICT_FRAME) || (!out_pic->nal_ref_idc[0] && !out_pic->nal_ref_idc[1] && out_pic->picture_structure != PICT_FRAME)) fm_decoder_put_frame(s->decoder.fm, out_pic->frame); for (i = idx; s->frame_info.delayed_pic[i]; i++) s->frame_info.delayed_pic[i] = s->frame_info.delayed_pic[i + 1]; } logi("cur poc: %d, out poc: %d, next poc: %d", cur_pic->poc, out_pic->poc, s->next_output_poc); if(!out_of_order && s->frame_info.delay_pic_num > s->has_b_frames) { if(idx == 0 && s->frame_info.delayed_pic[0] && (s->frame_info.delayed_pic[0]->key_frame || s->frame_info.delayed_pic[0]->mmco_reset)) { s->next_output_poc = INT_MIN; } else { s->next_output_poc = out_pic->poc; } out_pic->displayed_flag = 1; if(out_pic->refrence == 0 || out_pic->refrence == DELAYED_PIC_REF) { fm_decoder_frame_to_render(s->decoder.fm, out_pic->frame, 1); out_pic->refrence = 0; out_pic->displayed_flag = 0; } else { fm_decoder_frame_to_render(s->decoder.fm, out_pic->frame, 1); } logi("render frame poc: %d, buf_idx: %d, frame_id: %d, refrence: %d", out_pic->poc, out_pic->buf_idx, out_pic->frame->mpp_frame.id, out_pic->refrence); logi("nal_ref_idc: %d %d", out_pic->nal_ref_idc[0], out_pic->nal_ref_idc[1]); //* if the frame is not used for refrence, it will not be used by decoder now if(!out_pic->nal_ref_idc[0] && !out_pic->nal_ref_idc[1]) { fm_decoder_put_frame(s->decoder.fm, out_pic->frame); out_pic->refrence = 0; out_pic->displayed_flag = 0; } for(i=idx; iframe_info.delay_pic_num; i++) { s->frame_info.delayed_pic[i] = s->frame_info.delayed_pic[i+1]; } s->frame_info.delayed_pic[i] = NULL; s->frame_info.delay_pic_num--; s->min_display_poc = out_pic->poc; s->frame_info.delayed_output_pic = out_pic; } logd("====== print delay pic ======="); for(i=0; iframe_info.delay_pic_num; i++) { logd("delay pic: %d, %p", i, s->frame_info.delayed_pic[i]); if(s->frame_info.delayed_pic[i]) { logd("poc: %d, buf_idx: %d, flag: %x", s->frame_info.delayed_pic[i]->poc, s->frame_info.delayed_pic[i]->buf_idx, s->frame_info.delayed_pic[i]->frame->mpp_frame.flags); } } } void flush_all_delay_picture(struct h264_dec_ctx *s) { int i = 0; struct h264_picture* pic = NULL; for(i=0; iframe_info.delay_pic_num; i++) { pic = s->frame_info.delayed_pic[i]; if(pic->frame) { fm_decoder_frame_to_render(s->decoder.fm, pic->frame, 0); fm_decoder_put_frame(s->decoder.fm, pic->frame); } pic->refrence = 0; pic->frame = NULL; } s->frame_info.delay_pic_num = 0; }