From: Julian S. <ju...@ju...> - 2010-06-11 12:05:01
|
# HG changeset patch # User Julian Scheel <ju...@ju...> # Date 1276257869 -7200 # Node ID c4a1d0b617a1217d40ce1c9c6bfd79a5e2c54397 # Parent f542bd3430ec0fda450b60858c182a4e197889c6 rework of decoded picture buffer - the dpb is using two xine_lists now to manage reference pictures and pictures delayed for output - take VUI num_reorder_frames into account to buffer just as many frames as needed - cleanup reference counting for decoded pictures diff --git a/src/video_dec/libvdpau/dpb.c b/src/video_dec/libvdpau/dpb.c --- a/src/video_dec/libvdpau/dpb.c +++ b/src/video_dec/libvdpau/dpb.c @@ -32,7 +32,15 @@ #include "dpb.h" #include "nal.h" +#include "accel_vdpau.h" + #include <xine/video_out.h> + +/** + * ---------------------------------------------------------------------------- + * decoded picture + * ---------------------------------------------------------------------------- + */ void free_decoded_picture(struct decoded_picture *pic); @@ -42,33 +50,38 @@ struct decoded_picture *pic = calloc(1, sizeof(struct decoded_picture)); pic->coded_pic[0] = cpic; - pic->top_is_reference = cpic->slc_nal->slc.field_pic_flag - ? (cpic->slc_nal->slc.bottom_field_flag ? 0 : 1) : 1; - pic->bottom_is_reference = cpic->slc_nal->slc.field_pic_flag - ? (cpic->slc_nal->slc.bottom_field_flag ? 1 : 0) : 1; - pic->surface = surface; + + decoded_pic_check_reference(pic); pic->img = img; - pic->delayed_output = 1; pic->lock_counter = 1; return pic; } -void dpb_add_coded_picture(struct decoded_picture *pic, +void decoded_pic_check_reference(struct decoded_picture *pic) +{ + int i; + for(i = 0; i < 2; i++) { + struct coded_picture *cpic = pic->coded_pic[i]; + if(cpic && (cpic->flag_mask & REFERENCE)) { + // FIXME: this assumes Top Field First! + if(i == 0) { + pic->top_is_reference = cpic->slc_nal->slc.field_pic_flag + ? (cpic->slc_nal->slc.bottom_field_flag ? 0 : 1) : 1; + } + + pic->bottom_is_reference = cpic->slc_nal->slc.field_pic_flag + ? (cpic->slc_nal->slc.bottom_field_flag ? 1 : 0) : 1; + } + } +} + +void decoded_pic_add_field(struct decoded_picture *pic, struct coded_picture *cpic) { pic->coded_pic[1] = cpic; - if(cpic->flag_mask & REFERENCE) { - if(cpic->slc_nal->slc.field_pic_flag && - cpic->slc_nal->slc.bottom_field_flag) { - pic->bottom_is_reference = 1; - } else if(cpic->slc_nal->slc.field_pic_flag && - !cpic->slc_nal->slc.bottom_field_flag) { - pic->top_is_reference = 1; - } - - } + decoded_pic_check_reference(pic); } void release_decoded_picture(struct decoded_picture *pic) @@ -77,6 +90,7 @@ return; pic->lock_counter--; + //printf("release decoded picture: %p (%d)\n", pic, pic->lock_counter); if(pic->lock_counter <= 0) { free_decoded_picture(pic); @@ -89,10 +103,14 @@ return; pic->lock_counter++; + //printf("lock decoded picture: %p (%d)\n", pic, pic->lock_counter); } void free_decoded_picture(struct decoded_picture *pic) { + if(!pic) + return; + if(pic->img != NULL) { pic->img->free(pic->img); } @@ -104,59 +122,75 @@ free(pic); } -struct decoded_picture* dpb_get_next_ref_pic(struct dpb *dpb, - struct decoded_picture *pic) + + + +/** + * ---------------------------------------------------------------------------- + * dpb code starting here + * ---------------------------------------------------------------------------- + */ + +struct dpb* create_dpb() { - if (pic == NULL) { - pic = dpb->pictures; - } else { - pic = pic->next; - } + struct dpb *dpb = calloc(1, sizeof(struct dpb)); - while (pic != NULL) { - if (pic->used_for_reference) { - return pic; - } + dpb->output_list = xine_list_new(); + dpb->reference_list = xine_list_new(); [... 583 lines omitted ...] } int dpb_flush(struct dpb *dpb) { - struct decoded_picture *pic = dpb->pictures; + struct decoded_picture *pic = NULL; - if (pic != NULL) - do { - struct decoded_picture *next_pic = pic->next; - dpb_set_unused_ref_picture_a(dpb, pic); - pic = next_pic; - } while (pic != NULL); + xine_list_iterator_t ite = xine_list_front(dpb->reference_list); + printf("flush, list size: %d\n", xine_list_size(dpb->reference_list)); + while (ite) { + pic = xine_list_get_value(dpb->reference_list, ite); + printf("remove reference pic: %d\n", pic->coded_pic[0]->top_field_order_cnt); + dpb_unmark_reference_picture(dpb, pic); + + /* CAUTION: xine_list_next would return an item, but not the one we + * expect, as the current one was deleted + */ + ite = xine_list_front(dpb->reference_list); + } +printf("flush done, list size: %d\n", xine_list_size(dpb->reference_list)); return 0; } -void dpb_free_all( struct dpb *dpb ) +void dpb_free_all(struct dpb *dpb) { - struct decoded_picture *pic = dpb->pictures; + xine_list_iterator_t ite = xine_list_front(dpb->output_list); + while(ite) { + dpb_unmark_picture_delayed(dpb, xine_list_get_value(dpb->output_list, ite)); + /* CAUTION: xine_list_next would return an item, but not the one we + * expect, as the current one was deleted + */ + ite = xine_list_front(dpb->output_list); + } - if (pic != NULL) - do { - struct decoded_picture *next_pic = pic->next; - release_decoded_picture(pic); - --dpb->used; - pic = next_pic; - } while (pic != NULL); - - dpb->pictures = NULL; + ite = xine_list_front(dpb->reference_list); + while(ite) { + dpb_unmark_picture_delayed(dpb, xine_list_get_value(dpb->reference_list, ite)); + /* CAUTION: xine_list_next would return an item, but not the one we + * expect, as the current one was deleted + */ + ite = xine_list_front(dpb->output_list); } } -void dpb_clear_all_pts( struct dpb *dpb ) +void dpb_clear_all_pts(struct dpb *dpb) { - struct decoded_picture *pic = dpb->pictures; + xine_list_iterator_t ite = xine_list_front(dpb->output_list); + while(ite) { + struct decoded_picture *pic = xine_list_get_value(dpb->output_list, ite); + pic->img->pts = 0; - while (pic != NULL) { - pic->img->pts = 0; - pic = pic->next; + ite = xine_list_next(dpb->output_list, ite); } } int fill_vdpau_reference_list(struct dpb *dpb, VdpReferenceFrameH264 *reflist) { - struct decoded_picture *pic = dpb->pictures; - struct decoded_picture *last_pic = NULL; + struct decoded_picture *pic = NULL; int i = 0; int used_refframes = 0; - if (pic != NULL) - do { - if (pic->used_for_reference) { - reflist[i].surface = pic->surface; - reflist[i].is_long_term = pic->coded_pic[0]->used_for_long_term_ref || - (pic->coded_pic[1] != NULL && pic->coded_pic[1]->used_for_long_term_ref); + xine_list_iterator_t ite = xine_list_back(dpb->reference_list); + while (ite) { + pic = xine_list_get_value(dpb->reference_list, ite); + reflist[i].surface = ((vdpau_accel_t*)pic->img->accel_data)->surface; + reflist[i].is_long_term = pic->coded_pic[0]->used_for_long_term_ref || + (pic->coded_pic[1] != NULL && pic->coded_pic[1]->used_for_long_term_ref); - reflist[i].frame_idx = pic->coded_pic[0]->used_for_long_term_ref ? - pic->coded_pic[0]->long_term_pic_num : - pic->coded_pic[0]->slc_nal->slc.frame_num; - reflist[i].top_is_reference = pic->top_is_reference; - reflist[i].bottom_is_reference = pic->bottom_is_reference; - reflist[i].field_order_cnt[0] = pic->coded_pic[0]->top_field_order_cnt; - reflist[i].field_order_cnt[1] = pic->coded_pic[1] != NULL ? - pic->coded_pic[1]->bottom_field_order_cnt : - pic->coded_pic[0]->bottom_field_order_cnt; - i++; - } - last_pic = pic; - } while ((pic = pic->next) != NULL && i < 16); + reflist[i].frame_idx = pic->coded_pic[0]->used_for_long_term_ref ? + pic->coded_pic[0]->long_term_pic_num : + pic->coded_pic[0]->slc_nal->slc.frame_num; + reflist[i].top_is_reference = pic->top_is_reference; + reflist[i].bottom_is_reference = pic->bottom_is_reference; + reflist[i].field_order_cnt[0] = pic->coded_pic[0]->top_field_order_cnt; + reflist[i].field_order_cnt[1] = pic->coded_pic[1] != NULL ? + pic->coded_pic[1]->bottom_field_order_cnt : + pic->coded_pic[0]->bottom_field_order_cnt; + i++; + + ite = xine_list_prev(dpb->reference_list, ite); + } used_refframes = i; diff --git a/src/video_dec/libvdpau/dpb.h b/src/video_dec/libvdpau/dpb.h --- a/src/video_dec/libvdpau/dpb.h +++ b/src/video_dec/libvdpau/dpb.h @@ -23,14 +23,16 @@ #ifndef DPB_H_ #define DPB_H_ -#define MAX_DPB_SIZE 16 +#define MAX_REORDER_COUNT 16 #include "nal.h" #include "cpb.h" #include <xine/video_out.h> +#include <xine/list.h> + +#define USED_FOR_REF (top_is_reference || bottom_is_reference) struct decoded_picture { - VdpVideoSurface surface; vo_frame_t *img; /* this is the image we block, to make sure * the surface is not double-used */ @@ -43,38 +45,31 @@ int32_t frame_num_wrap; - uint8_t used_for_reference; uint8_t top_is_reference; uint8_t bottom_is_reference; - - uint8_t delayed_output; - - struct decoded_picture *next; uint32_t lock_counter; }; /* Decoded Picture Buffer */ struct dpb { - struct decoded_picture *pictures; + xine_list_t *reference_list; + xine_list_t *output_list; - uint32_t num_ref_frames; - uint32_t used; + int output_list_size; }; + +struct dpb* create_dpb(); +void release_dpb(struct dpb *dpb); struct decoded_picture* init_decoded_picture(struct coded_picture *cpic, VdpVideoSurface surface, vo_frame_t *img); void release_decoded_picture(struct decoded_picture *pic); void lock_decoded_picture(struct decoded_picture *pic); -void dpb_add_coded_picture(struct decoded_picture *pic, +void decoded_pic_check_reference(struct decoded_picture *pic); +void decoded_pic_add_field(struct decoded_picture *pic, struct coded_picture *cpic); -/** - * returns the following picture from dpb, that is used for - * reference. if pic == NULL it returns the first ref pic in dpb - */ -struct decoded_picture* dpb_get_next_ref_pic(struct dpb *dpb, - struct decoded_picture *pic); struct decoded_picture* dpb_get_next_out_picture(struct dpb *dpb, int do_flush); @@ -82,19 +77,17 @@ struct decoded_picture* dpb_get_picture_by_ltpn(struct dpb *dpb, uint32_t longterm_picnum); struct decoded_picture* dpb_get_picture_by_ltidx(struct dpb *dpb, uint32_t longterm_idx); -int dpb_set_unused_ref_picture(struct dpb *dpb, uint32_t picnum); -int dpb_set_unused_ref_picture_a(struct dpb *dpb, struct decoded_picture *refpic); int dpb_set_unused_ref_picture_byltpn(struct dpb *dpb, uint32_t longterm_picnum); int dpb_set_unused_ref_picture_bylidx(struct dpb *dpb, uint32_t longterm_idx); int dpb_set_unused_ref_picture_lidx_gt(struct dpb *dpb, int32_t longterm_idx); -int dpb_set_output_picture(struct dpb *dpb, struct decoded_picture *outpic); +int dpb_unmark_picture_delayed(struct dpb *dpb, struct decoded_picture *pic); +int dpb_unmark_reference_picture(struct dpb *dpb, struct decoded_picture *pic); -int dpb_remove_picture(struct dpb *dpb, struct decoded_picture *rempic); int dpb_add_picture(struct dpb *dpb, struct decoded_picture *pic, uint32_t num_ref_frames); int dpb_flush(struct dpb *dpb); -void dpb_free_all( struct dpb *dpb ); -void dpb_clear_all_pts( struct dpb *dpb ); +void dpb_free_all(struct dpb *dpb); +void dpb_clear_all_pts(struct dpb *dpb); int fill_vdpau_reference_list(struct dpb *dpb, VdpReferenceFrameH264 *reflist); @@ -106,10 +99,8 @@ if (decoded_pic->coded_pic[0]->slc_nal->slc.field_pic_flag == 0) { top_field_first = 1; } else { - if (decoded_pic->coded_pic[1] != NULL) { - top_field_first = (decoded_pic->coded_pic[0]->top_field_order_cnt <= decoded_pic->coded_pic[1]->bottom_field_order_cnt); - } else { - top_field_first = (decoded_pic->coded_pic[0]->top_field_order_cnt <= decoded_pic->coded_pic[0]->bottom_field_order_cnt); + if (decoded_pic->coded_pic[0]->slc_nal->slc.delta_pic_order_cnt_bottom == 1) { + top_field_first = 1; } } diff --git a/src/video_dec/libvdpau/h264_parser.c b/src/video_dec/libvdpau/h264_parser.c --- a/src/video_dec/libvdpau/h264_parser.c +++ b/src/video_dec/libvdpau/h264_parser.c @@ -1285,7 +1285,10 @@ struct decoded_picture *pic = NULL; struct slice_header *cslc = &cpic->slc_nal->slc; - while((pic = dpb_get_next_ref_pic(&parser->dpb, pic)) != NULL) { + xine_list_iterator_t ite = xine_list_front(parser->dpb->reference_list); + while (ite) { + pic = xine_list_get_value(parser->dpb->reference_list, ite); + int i; for (i=0; i<2; i++) { if(pic->coded_pic[i] == NULL) @@ -1320,6 +1323,8 @@ pic->coded_pic[i]->long_term_pic_num++; } } + + ite = xine_list_next(parser->dpb->reference_list, ite); } } @@ -1337,16 +1342,16 @@ if (!cpic->slc_nal) return; struct slice_header *slc = &cpic->slc_nal->slc; - struct dpb *dpb = &parser->dpb; + struct dpb *dpb = parser->dpb; calculate_pic_nums(parser, cpic); if (cpic->flag_mask & IDR_PIC) { if(slc->dec_ref_pic_marking[marking_nr].long_term_reference_flag) { cpic->used_for_long_term_ref = 1; - dpb_set_unused_ref_picture_lidx_gt(&parser->dpb, 0); + dpb_set_unused_ref_picture_lidx_gt(dpb, 0); } else { - dpb_set_unused_ref_picture_lidx_gt(&parser->dpb, -1); + dpb_set_unused_ref_picture_lidx_gt(dpb, -1); } return; } @@ -1360,7 +1365,7 @@ struct decoded_picture* pic = NULL; if ((pic = dpb_get_picture(dpb, pic_num_x)) != NULL) { if (cpic->slc_nal->slc.field_pic_flag == 0) { - dpb_set_unused_ref_picture_a(dpb, pic); + dpb_unmark_reference_picture(dpb, pic); } else { if (pic->coded_pic[0]->slc_nal->slc.field_pic_flag == 1) { @@ -1370,10 +1375,10 @@ pic->bottom_is_reference = 0; if(!pic->top_is_reference && !pic->bottom_is_reference) - dpb_set_unused_ref_picture_a(dpb, pic); + dpb_unmark_reference_picture(dpb, pic); } else { pic->top_is_reference = pic->bottom_is_reference = 0; - dpb_set_unused_ref_picture_a(dpb, pic); + dpb_unmark_reference_picture(dpb, pic); } } } else { @@ -1554,7 +1559,7 @@ parser->sps_buffer = create_nal_buffer(32); parser->pps_buffer = create_nal_buffer(32); parser->xine = xine; - memset(&parser->dpb, 0x00, sizeof(struct dpb)); + parser->dpb = create_dpb(); return parser; } @@ -1586,7 +1591,8 @@ void free_parser(struct h264_parser *parser) { - dpb_free_all(&parser->dpb); + dpb_free_all(parser->dpb); + release_dpb(parser->dpb); free_nal_buffer(parser->pps_buffer); free_nal_buffer(parser->sps_buffer); free(parser); diff --git a/src/video_dec/libvdpau/h264_parser.h b/src/video_dec/libvdpau/h264_parser.h --- a/src/video_dec/libvdpau/h264_parser.h +++ b/src/video_dec/libvdpau/h264_parser.h @@ -83,7 +83,7 @@ /* this is dpb used for reference frame * heading to vdpau + unordered frames */ - struct dpb dpb; + struct dpb *dpb; xine_t *xine; }; diff --git a/src/video_dec/libvdpau/vdpau_h264.c b/src/video_dec/libvdpau/vdpau_h264.c --- a/src/video_dec/libvdpau/vdpau_h264.c +++ b/src/video_dec/libvdpau/vdpau_h264.c @@ -287,7 +287,7 @@ /* set num_ref_frames to the number of actually available reference frames, * if this is not set generation 3 decoders will fail. */ /*pic->num_ref_frames =*/ - fill_vdpau_reference_list(&(this->nal_parser->dpb), pic->referenceFrames); + fill_vdpau_reference_list(this->nal_parser->dpb, pic->referenceFrames); } @@ -399,7 +399,7 @@ // FIXME: what is if this is the second field of a field coded // picture? - should we keep the first field in dpb? if(this->completed_pic->flag_mask & IDR_PIC) { - dpb_flush(&(this->nal_parser->dpb)); + dpb_flush(this->nal_parser->dpb); if(this->last_ref_pic) { release_decoded_picture(this->last_ref_pic); this->last_ref_pic = NULL; @@ -542,13 +542,14 @@ } this->last_ref_pic = decoded_pic; lock_decoded_picture(this->last_ref_pic); - decoded_pic->used_for_reference = 1; - dpb_add_picture(&(this->nal_parser->dpb), decoded_pic, sps->num_ref_frames); + + dpb_add_picture(this->nal_parser->dpb, decoded_pic, sps->num_ref_frames); this->dangling_img = NULL; } else if(slc->field_pic_flag && this->wait_for_bottom_field) { if(this->last_ref_pic) { decoded_pic = this->last_ref_pic; - dpb_add_coded_picture(decoded_pic, this->completed_pic); + lock_decoded_picture(decoded_pic); + decoded_pic_add_field(decoded_pic, this->completed_pic); this->completed_pic = NULL; } } @@ -561,20 +562,24 @@ decoded_pic = init_decoded_picture(this->completed_pic, surface, img); this->completed_pic = NULL; - dpb_add_picture(&(this->nal_parser->dpb), decoded_pic, sps->num_ref_frames); + dpb_add_picture(this->nal_parser->dpb, decoded_pic, sps->num_ref_frames); this->dangling_img = NULL; } - decoded_pic->delayed_output = 1; - this->last_img = img = NULL; + /* release the decoded picture, which was headed + * over to the dpb + */ + release_decoded_picture(decoded_pic); + decoded_pic = NULL; + /* now retrieve the next output frame */ - if ((decoded_pic = dpb_get_next_out_picture(&(this->nal_parser->dpb), 0)) != NULL) { - + if ((decoded_pic = dpb_get_next_out_picture(this->nal_parser->dpb, 0)) != NULL) { decoded_pic->img->top_field_first = dp_top_field_first(decoded_pic); decoded_pic->img->draw(decoded_pic->img, this->stream); - dpb_set_output_picture(&(this->nal_parser->dpb), decoded_pic); + dpb_unmark_picture_delayed(this->nal_parser->dpb, decoded_pic); + decoded_pic = NULL; } this->wait_for_bottom_field = 0; @@ -588,6 +593,11 @@ } this->completed_pic = NULL; } + + /* release the decoded picture as we won't use it + * in this method anymore + */ + release_decoded_picture(decoded_pic); } return 1; @@ -672,6 +682,16 @@ vdpau_decoder_init(this_gen); } + if(this->completed_pic && + this->completed_pic->sps_nal != NULL && + this->completed_pic->sps_nal->sps.vui_parameters_present_flag && + this->completed_pic->sps_nal->sps.vui_parameters.bitstream_restriction_flag) { + this->nal_parser->dpb->output_list_size = + this->completed_pic->sps_nal->sps.vui_parameters.num_reorder_frames + 1; + xprintf(this->xine, XINE_VERBOSITY_DEBUG, + "Reorder count: %d\n", this->nal_parser->dpb->output_list_size); + } + if(this->decoder != VDP_INVALID_HANDLE && vdp_buffer.bitstream_bytes > 0 && this->completed_pic->slc_nal != NULL && @@ -684,8 +704,11 @@ /* in case the last nal was detected as END_OF_SEQUENCE * we will flush the dpb, so that all pictures get drawn */ - if(this->nal_parser->last_nal_res == 3) + if(this->nal_parser->last_nal_res == 3) { + xprintf(this->xine, XINE_VERBOSITY_DEBUG, + "END_OF_SEQUENCE, flush buffers\n"); vdpau_h264_flush(this_gen); + } } } @@ -709,14 +732,14 @@ this->last_ref_pic = NULL; } - while ((decoded_pic = dpb_get_next_out_picture(&(this->nal_parser->dpb), 1)) != NULL) { + while ((decoded_pic = dpb_get_next_out_picture(this->nal_parser->dpb, 1)) != NULL) { decoded_pic->img->top_field_first = dp_top_field_first(decoded_pic); xprintf(this->xine, XINE_VERBOSITY_DEBUG, "h264 flush, draw pts: %"PRId64"\n", decoded_pic->img->pts); decoded_pic->img->draw(decoded_pic->img, this->stream); - dpb_set_output_picture(&(this->nal_parser->dpb), decoded_pic); + dpb_unmark_picture_delayed(this->nal_parser->dpb, decoded_pic); } - dpb_free_all(&this->nal_parser->dpb); + dpb_free_all(this->nal_parser->dpb); this->reset = VO_NEW_SEQUENCE_FLAG; } @@ -726,7 +749,7 @@ static void vdpau_h264_reset (video_decoder_t *this_gen) { vdpau_h264_decoder_t *this = (vdpau_h264_decoder_t *) this_gen; - dpb_free_all( &(this->nal_parser->dpb) ); + dpb_free_all(this->nal_parser->dpb); if (this->decoder != VDP_INVALID_HANDLE) { this->vdpau_accel->vdp_decoder_destroy( this->decoder ); @@ -775,7 +798,7 @@ static void vdpau_h264_discontinuity (video_decoder_t *this_gen) { vdpau_h264_decoder_t *this = (vdpau_h264_decoder_t *) this_gen; - dpb_clear_all_pts(&this->nal_parser->dpb); + dpb_clear_all_pts(this->nal_parser->dpb); this->reset = VO_NEW_SEQUENCE_FLAG; } @@ -796,7 +819,7 @@ this->dangling_img = NULL; } - dpb_free_all( &(this->nal_parser->dpb) ); + dpb_free_all(this->nal_parser->dpb); if (this->decoder != VDP_INVALID_HANDLE) { this->vdpau_accel->vdp_decoder_destroy( this->decoder ); @@ -837,6 +860,8 @@ this = (vdpau_h264_decoder_t *) calloc(1, sizeof(vdpau_h264_decoder_t)); + this->nal_parser = init_parser(stream->xine); + this->video_decoder.decode_data = vdpau_h264_decode_data; this->video_decoder.flush = vdpau_h264_flush; this->video_decoder.reset = vdpau_h264_reset; @@ -852,8 +877,6 @@ this->color_standard = VDP_COLOR_STANDARD_ITUR_BT_601; this->reset = VO_NEW_SEQUENCE_FLAG; - - this->nal_parser = init_parser(stream->xine); (this->stream->video_out->open) (this->stream->video_out, this->stream); |