summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Scheel <julian@jusst.de>2010-06-11 14:04:29 +0200
committerJulian Scheel <julian@jusst.de>2010-06-11 14:04:29 +0200
commit65c389b2851e978cd3c86bff53b1749081b2bd46 (patch)
treec4e57e4f891ca23a9be424bbd0493dafeecc529c
parentfe09ed17c1a83b5576834e6eaa2e241b1c4f6328 (diff)
downloadxine-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.c671
-rw-r--r--src/video_dec/libvdpau/dpb.h45
-rw-r--r--src/video_dec/libvdpau/h264_parser.c24
-rw-r--r--src/video_dec/libvdpau/h264_parser.h2
-rw-r--r--src/video_dec/libvdpau/vdpau_h264.c63
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;