summaryrefslogtreecommitdiff
path: root/src/video_dec/libvdpau/dpb.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_dec/libvdpau/dpb.c')
-rw-r--r--src/video_dec/libvdpau/dpb.c229
1 files changed, 173 insertions, 56 deletions
diff --git a/src/video_dec/libvdpau/dpb.c b/src/video_dec/libvdpau/dpb.c
index d95fdd20c..09a6ec58a 100644
--- a/src/video_dec/libvdpau/dpb.c
+++ b/src/video_dec/libvdpau/dpb.c
@@ -24,33 +24,74 @@
#include <stdlib.h>
#include <string.h>
+#include "cpb.h"
#include "dpb.h"
#include "nal.h"
+
#include <xine/video_out.h>
-struct decoded_picture* init_decoded_picture(struct nal_unit *src_nal,
+struct decoded_picture* init_decoded_picture(struct coded_picture *cpic,
VdpVideoSurface surface, vo_frame_t *img)
{
struct decoded_picture *pic = calloc(1, sizeof(struct decoded_picture));
- pic->nal = init_nal_unit();
- copy_nal_unit(pic->nal, src_nal);
- pic->top_is_reference = pic->nal->slc->field_pic_flag
- ? (pic->nal->slc->bottom_field_flag ? 0 : 1) : 1;
- pic->bottom_is_reference = pic->nal->slc->field_pic_flag
- ? (pic->nal->slc->bottom_field_flag ? 1 : 0) : 1;
+
+ 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;
pic->img = img;
+ pic->delayed_output = 1;
return pic;
}
+void dpb_add_coded_picture(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;
+ }
+
+ }
+}
+
void free_decoded_picture(struct decoded_picture *pic)
{
pic->img->free(pic->img);
- free_nal_unit(pic->nal);
+ free_coded_picture(pic->coded_pic[0]);
+ pic->coded_pic[0] = NULL;
+ free_coded_picture(pic->coded_pic[1]);
+ pic->coded_pic[1] = NULL;
free(pic);
}
+struct decoded_picture* dpb_get_next_ref_pic(struct dpb *dpb,
+ struct decoded_picture *pic)
+{
+ if (pic == NULL) {
+ pic = dpb->pictures;
+ } else {
+ pic = pic->next;
+ }
+
+ while (pic != NULL) {
+ if (pic->used_for_reference) {
+ return pic;
+ }
+
+ pic = pic->next;
+ }
+}
+
struct decoded_picture* dpb_get_next_out_picture(struct dpb *dpb, int do_flush)
{
struct decoded_picture *pic = dpb->pictures;
@@ -59,17 +100,39 @@ struct decoded_picture* dpb_get_next_out_picture(struct dpb *dpb, int do_flush)
if(!do_flush && dpb->used < MAX_DPB_SIZE)
return NULL;
- if (pic != NULL)
+ if (pic != NULL) {
do {
- if (pic->delayed_output &&
- (outpic == NULL ||
- (pic->nal->top_field_order_cnt <= outpic->nal->top_field_order_cnt &&
- pic->nal->bottom_field_order_cnt <= outpic->nal->bottom_field_order_cnt)||
- (outpic->nal->top_field_order_cnt < 0 && pic->nal->top_field_order_cnt > 0 &&
- outpic->nal->bottom_field_order_cnt < 0 && pic->nal->bottom_field_order_cnt > 0)||
- outpic->nal->nal_unit_type == NAL_SLICE_IDR))
- outpic = pic;
+ 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);
+ }
+
+ int32_t out_top_field_order_cnt = outpic != NULL ?
+ outpic->coded_pic[0]->top_field_order_cnt : 0;
+ 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;
return outpic;
}
@@ -80,8 +143,12 @@ struct decoded_picture* dpb_get_picture(struct dpb *dpb, uint32_t picnum)
if (pic != NULL)
do {
- if (pic->nal->curr_pic_num == picnum)
+ 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);
return NULL;
@@ -94,8 +161,11 @@ struct decoded_picture* dpb_get_picture_by_ltpn(struct dpb *dpb,
if (pic != NULL)
do {
- if (pic->nal->long_term_pic_num == longterm_picnum)
+ 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);
return NULL;
@@ -108,8 +178,11 @@ struct decoded_picture* dpb_get_picture_by_ltidx(struct dpb *dpb,
if (pic != NULL)
do {
- if (pic->nal->long_term_frame_idx == longterm_idx)
+ 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);
return NULL;
@@ -136,7 +209,9 @@ int dpb_set_unused_ref_picture(struct dpb *dpb, uint32_t picnum)
struct decoded_picture *pic = dpb->pictures;
if (pic != NULL)
do {
- if (pic->nal->curr_pic_num == picnum) {
+ 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);
@@ -152,12 +227,30 @@ int dpb_set_unused_ref_picture_byltpn(struct dpb *dpb, uint32_t longterm_picnum)
struct decoded_picture *pic = dpb->pictures;
if (pic != NULL)
do {
- if (pic->nal->long_term_pic_num == longterm_picnum) {
+ 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;
+ }
+
+ 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)) {
pic->used_for_reference = 0;
if(!pic->delayed_output)
dpb_remove_picture(dpb, pic);
- return 0;
}
+
+ if (found)
+ return 0;
+
} while ((pic = pic->next) != NULL);
return -1;
@@ -168,24 +261,56 @@ int dpb_set_unused_ref_picture_bylidx(struct dpb *dpb, uint32_t longterm_idx)
struct decoded_picture *pic = dpb->pictures;
if (pic != NULL)
do {
- if (pic->nal->long_term_frame_idx == longterm_idx) {
- pic->nal->used_for_long_term_ref = 0;
+ 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)) {
pic->used_for_reference = 0;
if(!pic->delayed_output)
dpb_remove_picture(dpb, pic);
- return 0;
}
+
+ if (found)
+ return 0;
+
} while ((pic = pic->next) != NULL);
return -1;
}
-int dpb_set_unused_ref_picture_lidx_gt(struct dpb *dpb, uint32_t longterm_idx)
+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 {
- if (pic->nal->long_term_frame_idx >= longterm_idx) {
+ 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)) {
pic->used_for_reference = 0;
if(!pic->delayed_output) {
struct decoded_picture *next_pic = pic->next;
@@ -224,8 +349,6 @@ int dpb_remove_picture(struct dpb *dpb, struct decoded_picture *rempic)
if (pic != NULL)
do {
if (pic == rempic) {
- // FIXME: free the picture....
-
if (last_pic != NULL)
last_pic->next = pic->next;
else
@@ -249,8 +372,6 @@ static int dpb_remove_picture_by_img(struct dpb *dpb, vo_frame_t *remimg)
if (pic != NULL)
do {
if (pic->img == remimg) {
- // FIXME: free the picture....
-
if (last_pic != NULL)
last_pic->next = pic->next;
else
@@ -266,22 +387,6 @@ static int dpb_remove_picture_by_img(struct dpb *dpb, vo_frame_t *remimg)
return -1;
}
-int dpb_remove_picture_by_picnum(struct dpb *dpb, uint32_t picnum)
-{
- struct decoded_picture *pic = dpb->pictures;
- struct decoded_picture *last_pic = NULL;
-
- if (pic != NULL)
- do {
- if (pic->nal->curr_pic_num == picnum) {
- dpb_remove_picture(dpb, pic);
- }
-
- last_pic = pic;
- } while ((pic = pic->next) != NULL);
-
- return -1;
-}
int dpb_add_picture(struct dpb *dpb, struct decoded_picture *pic, uint32_t num_ref_frames)
{
@@ -294,6 +399,8 @@ int dpb_add_picture(struct dpb *dpb, struct decoded_picture *pic, uint32_t num_r
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;
@@ -309,7 +416,12 @@ int dpb_add_picture(struct dpb *dpb, struct decoded_picture *pic, uint32_t num_r
last_pic = pic->next;
if(!pic->delayed_output) {
- dpb_remove_picture(dpb, pic);
+ 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)
@@ -320,6 +432,10 @@ int dpb_add_picture(struct dpb *dpb, struct decoded_picture *pic, uint32_t num_r
} while (pic != NULL && (pic = pic->next) != NULL);
}
+ if(discard_ref != NULL) {
+ dpb_remove_picture(dpb, pic);
+ }
+
return 0;
}
@@ -377,15 +493,16 @@ int fill_vdpau_reference_list(struct dpb *dpb, VdpReferenceFrameH264 *reflist)
do {
if (pic->used_for_reference) {
reflist[i].surface = pic->surface;
- reflist[i].is_long_term = pic->nal->used_for_long_term_ref;
- if(reflist[i].is_long_term)
- reflist[i].frame_idx = pic->nal->slc->frame_num;
- else
- reflist[i].frame_idx = pic->nal->slc->frame_num;
+ 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]->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->nal->top_field_order_cnt;
- reflist[i].field_order_cnt[1] = pic->nal->bottom_field_order_cnt;
+ 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;