diff options
author | Julian Scheel <julian@jusst.de> | 2010-06-11 14:04:29 +0200 |
---|---|---|
committer | Julian Scheel <julian@jusst.de> | 2010-06-11 14:04:29 +0200 |
commit | 65c389b2851e978cd3c86bff53b1749081b2bd46 (patch) | |
tree | c4e57e4f891ca23a9be424bbd0493dafeecc529c | |
parent | fe09ed17c1a83b5576834e6eaa2e241b1c4f6328 (diff) | |
download | xine-lib-65c389b2851e978cd3c86bff53b1749081b2bd46.tar.gz xine-lib-65c389b2851e978cd3c86bff53b1749081b2bd46.tar.bz2 |
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
-rw-r--r-- | src/video_dec/libvdpau/dpb.c | 671 | ||||
-rw-r--r-- | src/video_dec/libvdpau/dpb.h | 45 | ||||
-rw-r--r-- | src/video_dec/libvdpau/h264_parser.c | 24 | ||||
-rw-r--r-- | src/video_dec/libvdpau/h264_parser.h | 2 | ||||
-rw-r--r-- | src/video_dec/libvdpau/vdpau_h264.c | 63 |
5 files changed, 409 insertions, 396 deletions
diff --git a/src/video_dec/libvdpau/dpb.c b/src/video_dec/libvdpau/dpb.c index 79cd35db3..aecbf7d77 100644 --- a/src/video_dec/libvdpau/dpb.c +++ b/src/video_dec/libvdpau/dpb.c @@ -32,8 +32,16 @@ #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); struct decoded_picture* init_decoded_picture(struct coded_picture *cpic, @@ -42,41 +50,47 @@ struct decoded_picture* init_decoded_picture(struct coded_picture *cpic, 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, - struct coded_picture *cpic) +void decoded_pic_check_reference(struct decoded_picture *pic) { - pic->coded_pic[1] = cpic; + 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; + } - 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; + 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; + + decoded_pic_check_reference(pic); +} + void release_decoded_picture(struct decoded_picture *pic) { if(!pic) 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 @@ void lock_decoded_picture(struct decoded_picture *pic) 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 @@ void free_decoded_picture(struct decoded_picture *pic) 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(); - pic = pic->next; - } + dpb->output_list_size = MAX_REORDER_COUNT; - return NULL; + return dpb; +} + +void release_dpb(struct dpb *dpb) +{ + if(!dpb) + return; + + dpb_free_all(dpb); + + xine_list_delete(dpb->output_list); + xine_list_delete(dpb->reference_list); + + free(dpb); } struct decoded_picture* dpb_get_next_out_picture(struct dpb *dpb, int do_flush) { - struct decoded_picture *pic = dpb->pictures; + struct decoded_picture *pic = NULL;; struct decoded_picture *outpic = NULL; - if(!do_flush && dpb->used < MAX_DPB_SIZE) + if(!do_flush && xine_list_size(dpb->output_list) < dpb->output_list_size) { return NULL; + } - if (pic != NULL) { - do { - if (pic->delayed_output) { - int32_t out_top_field_order_cnt = outpic != NULL ? - outpic->coded_pic[0]->top_field_order_cnt : 0; - int32_t top_field_order_cnt = pic->coded_pic[0]->top_field_order_cnt; - - int32_t out_bottom_field_order_cnt = outpic != NULL ? - (outpic->coded_pic[1] != NULL ? - outpic->coded_pic[1]->bottom_field_order_cnt : - outpic->coded_pic[0]->top_field_order_cnt) : 0; - int32_t bottom_field_order_cnt = pic->coded_pic[1] != NULL ? - pic->coded_pic[1]->bottom_field_order_cnt : - pic->coded_pic[0]->top_field_order_cnt; - - if (outpic == NULL || - (top_field_order_cnt <= out_top_field_order_cnt && - bottom_field_order_cnt <= out_bottom_field_order_cnt) || - (out_top_field_order_cnt <= 0 && top_field_order_cnt > 0 && - out_bottom_field_order_cnt <= 0 && bottom_field_order_cnt > 0) || - outpic->coded_pic[0]->flag_mask & IDR_PIC) { - outpic = pic; - } - } - } while ((pic = pic->next) != NULL); + xine_list_iterator_t ite = xine_list_back(dpb->output_list); + while (ite) { + pic = xine_list_get_value(dpb->output_list, ite); + + int32_t out_top_field_order_cnt = outpic != NULL ? + outpic->coded_pic[0]->top_field_order_cnt : 0; + int32_t top_field_order_cnt = pic->coded_pic[0]->top_field_order_cnt; + + int32_t out_bottom_field_order_cnt = outpic != NULL ? + (outpic->coded_pic[1] != NULL ? + outpic->coded_pic[1]->bottom_field_order_cnt : + outpic->coded_pic[0]->top_field_order_cnt) : 0; + int32_t bottom_field_order_cnt = pic->coded_pic[1] != NULL ? + pic->coded_pic[1]->bottom_field_order_cnt : + pic->coded_pic[0]->top_field_order_cnt; + + if (outpic == NULL || + (top_field_order_cnt <= out_top_field_order_cnt && + bottom_field_order_cnt <= out_bottom_field_order_cnt) || + (out_top_field_order_cnt <= 0 && top_field_order_cnt > 0 && + out_bottom_field_order_cnt <= 0 && bottom_field_order_cnt > 0) || + outpic->coded_pic[0]->flag_mask & IDR_PIC) { + outpic = pic; + } + + ite = xine_list_prev(dpb->output_list, ite); } return outpic; @@ -164,17 +198,20 @@ struct decoded_picture* dpb_get_next_out_picture(struct dpb *dpb, int do_flush) struct decoded_picture* dpb_get_picture(struct dpb *dpb, uint32_t picnum) { - struct decoded_picture *pic = dpb->pictures; - - if (pic != NULL) - do { - if (pic->used_for_reference && - (pic->coded_pic[0]->pic_num == picnum || - (pic->coded_pic[1] != NULL && - pic->coded_pic[1]->pic_num == picnum))) { - return pic; - } - } while ((pic = pic->next) != NULL); + struct decoded_picture *pic = NULL; + + xine_list_iterator_t ite = xine_list_front(dpb->reference_list); + while (ite) { + pic = xine_list_get_value(dpb->reference_list, ite); + + if ((pic->coded_pic[0]->pic_num == picnum || + (pic->coded_pic[1] != NULL && + pic->coded_pic[1]->pic_num == picnum))) { + return pic; + } + + ite = xine_list_next(dpb->reference_list, ite); + } return NULL; } @@ -182,16 +219,20 @@ struct decoded_picture* dpb_get_picture(struct dpb *dpb, uint32_t picnum) struct decoded_picture* dpb_get_picture_by_ltpn(struct dpb *dpb, uint32_t longterm_picnum) { - struct decoded_picture *pic = dpb->pictures; - - if (pic != NULL) - do { - if (pic->coded_pic[0]->long_term_pic_num == longterm_picnum || - (pic->coded_pic[1] != NULL && - pic->coded_pic[1]->long_term_pic_num == longterm_picnum)) { - return pic; - } - } while ((pic = pic->next) != NULL); + struct decoded_picture *pic = NULL; + + xine_list_iterator_t ite = xine_list_front(dpb->reference_list); + while (ite) { + pic = xine_list_get_value(dpb->reference_list, ite); + + if (pic->coded_pic[0]->long_term_pic_num == longterm_picnum || + (pic->coded_pic[1] != NULL && + pic->coded_pic[1]->long_term_pic_num == longterm_picnum)) { + return pic; + } + + ite = xine_list_next(dpb->reference_list, ite); + } return NULL; } @@ -199,356 +240,308 @@ struct decoded_picture* dpb_get_picture_by_ltpn(struct dpb *dpb, struct decoded_picture* dpb_get_picture_by_ltidx(struct dpb *dpb, uint32_t longterm_idx) { - struct decoded_picture *pic = dpb->pictures; - - if (pic != NULL) - do { - if (pic->coded_pic[0]->long_term_frame_idx == longterm_idx || - (pic->coded_pic[1] != NULL && - pic->coded_pic[1]->long_term_frame_idx == longterm_idx)) { - return pic; - } - } while ((pic = pic->next) != NULL); + struct decoded_picture *pic = NULL; - return NULL; -} + xine_list_iterator_t ite = xine_list_front(dpb->reference_list); + while (ite) { + pic = xine_list_get_value(dpb->reference_list, ite); -int dpb_set_unused_ref_picture_a(struct dpb *dpb, struct decoded_picture *refpic) -{ - struct decoded_picture *pic = dpb->pictures; - if (pic != NULL) - do { - if (pic == refpic) { - pic->used_for_reference = 0; - if(!pic->delayed_output) - dpb_remove_picture(dpb, pic); - return 0; - } - } while ((pic = pic->next) != NULL); - - return -1; -} + if (pic->coded_pic[0]->long_term_frame_idx == longterm_idx || + (pic->coded_pic[1] != NULL && + pic->coded_pic[1]->long_term_frame_idx == longterm_idx)) { + return pic; + } -int dpb_set_unused_ref_picture(struct dpb *dpb, uint32_t picnum) -{ - struct decoded_picture *pic = dpb->pictures; - if (pic != NULL) - do { - if (pic->coded_pic[0]->pic_num == picnum || - (pic->coded_pic[1] != NULL && - pic->coded_pic[1]->pic_num == picnum)) { - pic->used_for_reference = 0; - if(!pic->delayed_output) - dpb_remove_picture(dpb, pic); - return 0; - } - } while ((pic = pic->next) != NULL); + ite = xine_list_next(dpb->reference_list, ite); + } - return -1; + return NULL; } int dpb_set_unused_ref_picture_byltpn(struct dpb *dpb, uint32_t longterm_picnum) { - struct decoded_picture *pic = dpb->pictures; - if (pic != NULL) - do { - uint8_t found = 0; - - if (pic->coded_pic[0]->long_term_pic_num == longterm_picnum) { - pic->coded_pic[0]->used_for_long_term_ref = 0; - found = 1; - } + struct decoded_picture *pic = NULL; - if ((pic->coded_pic[1] != NULL && - pic->coded_pic[1]->long_term_pic_num == longterm_picnum)) { - pic->coded_pic[1]->used_for_long_term_ref = 0; - found = 1; - } + xine_list_iterator_t ite = xine_list_front(dpb->reference_list); + while (ite) { + pic = xine_list_get_value(dpb->reference_list, ite); - if(found && !pic->coded_pic[0]->used_for_long_term_ref && - (pic->coded_pic[1] == NULL || - !pic->coded_pic[1]->used_for_long_term_ref)) { - pic->used_for_reference = 0; - if(!pic->delayed_output) - dpb_remove_picture(dpb, pic); - } + uint8_t found = 0; - if (found) - return 0; + if (pic->coded_pic[0]->long_term_pic_num == longterm_picnum) { + pic->coded_pic[0]->used_for_long_term_ref = 0; + found = 1; + } - } while ((pic = pic->next) != NULL); + if ((pic->coded_pic[1] != NULL && + pic->coded_pic[1]->long_term_pic_num == longterm_picnum)) { + pic->coded_pic[1]->used_for_long_term_ref = 0; + found = 1; + } + + if(found && !pic->coded_pic[0]->used_for_long_term_ref && + (pic->coded_pic[1] == NULL || + !pic->coded_pic[1]->used_for_long_term_ref)) { + dpb_unmark_reference_picture(dpb, pic); + } + + if (found) + return 0; + + ite = xine_list_next(dpb->reference_list, ite); + } return -1; } int dpb_set_unused_ref_picture_bylidx(struct dpb *dpb, uint32_t longterm_idx) { - struct decoded_picture *pic = dpb->pictures; - if (pic != NULL) - do { - uint8_t found = 0; - - if (pic->coded_pic[0]->long_term_frame_idx == longterm_idx) { - pic->coded_pic[0]->used_for_long_term_ref = 0; - found = 1; - } + struct decoded_picture *pic = NULL; - if ((pic->coded_pic[1] != NULL && - pic->coded_pic[1]->long_term_frame_idx == longterm_idx)) { - pic->coded_pic[1]->used_for_long_term_ref = 0; - found = 1; - } + xine_list_iterator_t ite = xine_list_front(dpb->reference_list); + while (ite) { + pic = xine_list_get_value(dpb->reference_list, ite); - if(found && !pic->coded_pic[0]->used_for_long_term_ref && - (pic->coded_pic[1] == NULL || - !pic->coded_pic[1]->used_for_long_term_ref)) { - pic->used_for_reference = 0; - if(!pic->delayed_output) - dpb_remove_picture(dpb, pic); - } + uint8_t found = 0; + + if (pic->coded_pic[0]->long_term_frame_idx == longterm_idx) { + pic->coded_pic[0]->used_for_long_term_ref = 0; + found = 1; + } + + if ((pic->coded_pic[1] != NULL && + pic->coded_pic[1]->long_term_frame_idx == longterm_idx)) { + pic->coded_pic[1]->used_for_long_term_ref = 0; + found = 1; + } - if (found) - return 0; + if(found && !pic->coded_pic[0]->used_for_long_term_ref && + (pic->coded_pic[1] == NULL || + !pic->coded_pic[1]->used_for_long_term_ref)) { + dpb_unmark_reference_picture(dpb, pic); + } - } while ((pic = pic->next) != NULL); + if (found) + return 0; + + ite = xine_list_next(dpb->reference_list, ite); + } return -1; } int dpb_set_unused_ref_picture_lidx_gt(struct dpb *dpb, int32_t longterm_idx) { - struct decoded_picture *pic = dpb->pictures; - if (pic != NULL) - do { - uint8_t found = 0; - - if (pic->coded_pic[0]->long_term_frame_idx >= longterm_idx) { - pic->coded_pic[0]->used_for_long_term_ref = 0; - found = 1; - } + struct decoded_picture *pic = NULL; - if ((pic->coded_pic[1] != NULL && - pic->coded_pic[1]->long_term_frame_idx >= longterm_idx)) { - pic->coded_pic[1]->used_for_long_term_ref = 0; - found = 1; - } + xine_list_iterator_t ite = xine_list_front(dpb->reference_list); + while (ite) { + pic = xine_list_get_value(dpb->reference_list, ite); - if(found && !pic->coded_pic[0]->used_for_long_term_ref && - (pic->coded_pic[1] == NULL || - !pic->coded_pic[1]->used_for_long_term_ref)) { - pic->used_for_reference = 0; - if(!pic->delayed_output) { - struct decoded_picture *next_pic = pic->next; - dpb_remove_picture(dpb, pic); - pic = next_pic; - continue; - } - } - } while ((pic = pic->next) != NULL); + uint8_t found = 0; + + if (pic->coded_pic[0]->long_term_frame_idx >= longterm_idx) { + pic->coded_pic[0]->used_for_long_term_ref = 0; + found = 1; + } + + if ((pic->coded_pic[1] != NULL && + pic->coded_pic[1]->long_term_frame_idx >= longterm_idx)) { + pic->coded_pic[1]->used_for_long_term_ref = 0; + found = 1; + } + + if(found && !pic->coded_pic[0]->used_for_long_term_ref && + (pic->coded_pic[1] == NULL || + !pic->coded_pic[1]->used_for_long_term_ref)) { + dpb_unmark_reference_picture(dpb, pic); + } + + ite = xine_list_next(dpb->reference_list, ite); + } return -1; } -int dpb_set_output_picture(struct dpb *dpb, struct decoded_picture *outpic) +int dpb_unmark_picture_delayed(struct dpb *dpb, struct decoded_picture *pic) { - /*struct decoded_picture *pic = dpb->pictures; - if (pic != NULL) - do { - if (pic == outpic) { - pic->delayed_output = 0; - if(!pic->used_for_reference) - dpb_remove_picture(dpb, pic); - return 0; - } - } while ((pic = pic->next) != NULL);*/ - if(!outpic) + if(!pic) return -1; - outpic->delayed_output = 0; - if(outpic->img != NULL) { - outpic->img->free(outpic->img); - outpic->img = NULL; - } + xine_list_iterator_t ite = xine_list_find(dpb->output_list, pic); + if (ite) { + xine_list_remove(dpb->output_list, ite); + release_decoded_picture(pic); - if(!outpic->used_for_reference) - dpb_remove_picture(dpb, outpic); + return 0; + } - return 0; + return -1; } -int dpb_remove_picture(struct dpb *dpb, struct decoded_picture *rempic) +int dpb_unmark_reference_picture(struct dpb *dpb, struct decoded_picture *pic) { - struct decoded_picture *pic = dpb->pictures; - struct decoded_picture *last_pic = NULL; - - if (pic != NULL) - do { - if (pic == rempic) { - if (last_pic != NULL) - last_pic->next = pic->next; - else - dpb->pictures = pic->next; - release_decoded_picture(pic); - dpb->used--; - return 0; - } + if(!pic) + return -1; - last_pic = pic; - } while ((pic = pic->next) != NULL); + xine_list_iterator_t ite = xine_list_find(dpb->reference_list, pic); + if (ite) { + xine_list_remove(dpb->reference_list, ite); + release_decoded_picture(pic); + + return 0; + } return -1; } -static int dpb_remove_picture_by_img(struct dpb *dpb, vo_frame_t *remimg) +/*static int dpb_remove_picture_by_img(struct dpb *dpb, vo_frame_t *remimg) { - struct decoded_picture *pic = dpb->pictures; - struct decoded_picture *last_pic = NULL; - - if (pic != NULL) - do { - if (pic->img == remimg) { - if (last_pic != NULL) - last_pic->next = pic->next; - else - dpb->pictures = pic->next; - release_decoded_picture(pic); - dpb->used--; - return 0; - } + int retval = -1; + struct decoded_picture *pic = NULL; - last_pic = pic; - } while ((pic = pic->next) != NULL); + xine_list_iterator_t ite = xine_list_front(dpb->output_list); + while (ite) { + pic = xine_list_get_value(dpb->output_list, ite); - return -1; -} + if (pic->img == remimg) { + dpb_unmark_picture_delayed(dpb, pic); + dpb->used--; + retval = 0; + } + + ite = xine_list_next(dpb->output_list, ite); + } + + return retval; +}*/ int dpb_add_picture(struct dpb *dpb, struct decoded_picture *pic, uint32_t num_ref_frames) { +#if 0 + /* this should never happen */ pic->img->lock(pic->img); if (0 == dpb_remove_picture_by_img(dpb, pic->img)) - lprintf("broken stream: current img was already in dpb -- freed it\n"); + lprintf("H264/DPB broken stream: current img was already in dpb -- freed it\n"); else pic->img->free(pic->img); +#endif - int i = 0; - struct decoded_picture *last_pic = dpb->pictures; - - struct decoded_picture *discard_ref = NULL; - - pic->next = dpb->pictures; - dpb->pictures = pic; - dpb->num_ref_frames = num_ref_frames; - dpb->used++; - - if(pic != NULL && dpb->used > num_ref_frames) { - do { - if(pic->used_for_reference) { - i++; - if(i>num_ref_frames) { - pic->used_for_reference = 0; - if(pic == dpb->pictures) - last_pic = pic->next; - - if(!pic->delayed_output) { - if(discard_ref == NULL || - discard_ref->frame_num_wrap > pic->frame_num_wrap) { - discard_ref = pic; - } - } else { - num_ref_frames++; - } - pic = last_pic; - if(pic == dpb->pictures) - continue; - } - last_pic = pic; - } - } while (pic != NULL && (pic = pic->next) != NULL); - - /* if all pictures in dpb are marked as delayed for output - * we need to drop a not yet drawn image. take the oldest one + /* add the pic to the output picture list, as no + * pic would be immediately drawn. + * acquire a lock for this list + */ + lock_decoded_picture(pic); + xine_list_push_back(dpb->output_list, pic); + + + /* check if the pic is a reference pic, + * if it is it should be added to the reference + * list. another lock has to be acquired in that case + */ + if (pic->coded_pic[0]->flag_mask & REFERENCE || + (pic->coded_pic[1] != NULL && + pic->coded_pic[1]->flag_mask & REFERENCE)) { + lock_decoded_picture(pic); + xine_list_push_back(dpb->reference_list, pic); + + /* + * always apply the sliding window reference removal, if more reference + * frames than expected are in the list. we will always remove the oldest + * reference frame */ - if(i > num_ref_frames && !discard_ref) { - discard_ref = dpb->pictures; + if(xine_list_size(dpb->reference_list) > num_ref_frames) { + struct decoded_picture *discard = xine_list_get_value(dpb->reference_list, xine_list_front(dpb->reference_list)); + dpb_unmark_reference_picture(dpb, discard); } } - if(discard_ref != NULL) { - dpb_remove_picture(dpb, discard_ref); - } + printf("DPB list sizes: Output: %2d, Reference: %2d\n", xine_list_size(dpb->output_list), xine_list_size(dpb->reference_list)); return 0; } int dpb_flush(struct dpb *dpb) { - struct decoded_picture *pic = dpb->pictures; + struct decoded_picture *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); - 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); + 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; - - if (pic != NULL) - do { - struct decoded_picture *next_pic = pic->next; - release_decoded_picture(pic); - --dpb->used; - pic = next_pic; - } while (pic != NULL); + 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); + } - 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; - - while (pic != NULL) { + 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; - 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); - - 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); + 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++; + + 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 index 9881ebccb..42d9abd95 100644 --- 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 @@ struct decoded_picture { 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(struct dpb *dpb, uint32_t picnum); 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 @@ static int dp_top_field_first(struct decoded_picture *decoded_pic) 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 index 75e065c12..c4c5ed718 100644 --- a/src/video_dec/libvdpau/h264_parser.c +++ b/src/video_dec/libvdpau/h264_parser.c @@ -1285,7 +1285,10 @@ void calculate_pic_nums(struct h264_parser *parser, struct coded_picture *cpic) 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 @@ void calculate_pic_nums(struct h264_parser *parser, struct coded_picture *cpic) pic->coded_pic[i]->long_term_pic_num++; } } + + ite = xine_list_next(parser->dpb->reference_list, ite); } } @@ -1337,16 +1342,16 @@ void execute_ref_pic_marking(struct coded_picture *cpic, 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 @@ void execute_ref_pic_marking(struct coded_picture *cpic, 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 @@ void execute_ref_pic_marking(struct coded_picture *cpic, 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 @@ struct h264_parser* init_parser(xine_t *xine) 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 reset_parser(struct h264_parser *parser) 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 index d75a1e4d7..49bc56bab 100644 --- a/src/video_dec/libvdpau/h264_parser.h +++ b/src/video_dec/libvdpau/h264_parser.h @@ -83,7 +83,7 @@ struct h264_parser { /* 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 index 4cda672ec..e10e095e7 100644 --- a/src/video_dec/libvdpau/vdpau_h264.c +++ b/src/video_dec/libvdpau/vdpau_h264.c @@ -287,7 +287,7 @@ static void fill_vdpau_pictureinfo_h264(video_decoder_t *this_gen, uint32_t slic /* 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 @@ static int vdpau_decoder_render(video_decoder_t *this_gen, VdpBitstreamBuffer *v // 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 @@ static int vdpau_decoder_render(video_decoder_t *this_gen, VdpBitstreamBuffer *v } 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 @@ static int vdpau_decoder_render(video_decoder_t *this_gen, VdpBitstreamBuffer *v 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; - /* now retrieve the next output frame */ - if ((decoded_pic = dpb_get_next_out_picture(&(this->nal_parser->dpb), 0)) != 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) { 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 @@ static int vdpau_decoder_render(video_decoder_t *this_gen, VdpBitstreamBuffer *v } 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 @@ static void vdpau_h264_decode_data (video_decoder_t *this_gen, 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 @@ static void vdpau_h264_decode_data (video_decoder_t *this_gen, /* 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 @@ static void vdpau_h264_flush (video_decoder_t *this_gen) { 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_flush (video_decoder_t *this_gen) { 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_reset (video_decoder_t *this_gen) { 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 @@ static void vdpau_h264_dispose (video_decoder_t *this_gen) { 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 @@ static video_decoder_t *open_plugin (video_decoder_class_t *class_gen, xine_stre 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; @@ -853,8 +878,6 @@ static video_decoder_t *open_plugin (video_decoder_class_t *class_gen, xine_stre this->reset = VO_NEW_SEQUENCE_FLAG; - this->nal_parser = init_parser(stream->xine); - (this->stream->video_out->open) (this->stream->video_out, this->stream); return &this->video_decoder; |