From 8f8c70fc5e2ce169b95290f9c672f3692c4b0826 Mon Sep 17 00:00:00 2001 From: jscheel-guest Date: Mon, 11 Jan 2010 13:38:01 +0100 Subject: complete rework of the h264 decoder coded_picture replaces the abused nal_units, while nal_units are just what their name says. sps and pps are handled in buffers as the spec proposes. pic_num calculation and ref-frame marking reworked to be spec compliant --- src/video_dec/libvdpau/Makefile.am | 4 +- src/video_dec/libvdpau/cpb.c | 45 ++ src/video_dec/libvdpau/cpb.h | 67 +++ src/video_dec/libvdpau/dpb.c | 229 +++++-- src/video_dec/libvdpau/dpb.h | 46 +- src/video_dec/libvdpau/h264_parser.c | 1093 +++++++++++++++++++++++----------- src/video_dec/libvdpau/h264_parser.h | 65 +- src/video_dec/libvdpau/nal.c | 190 +++++- src/video_dec/libvdpau/nal.h | 69 ++- src/video_dec/libvdpau/vdpau_h264.c | 188 +++--- 10 files changed, 1403 insertions(+), 593 deletions(-) create mode 100644 src/video_dec/libvdpau/cpb.c create mode 100644 src/video_dec/libvdpau/cpb.h (limited to 'src') diff --git a/src/video_dec/libvdpau/Makefile.am b/src/video_dec/libvdpau/Makefile.am index ef82195fd..f2a6e5176 100644 --- a/src/video_dec/libvdpau/Makefile.am +++ b/src/video_dec/libvdpau/Makefile.am @@ -3,7 +3,7 @@ include $(top_srcdir)/misc/Makefile.common AM_CFLAGS = $(DEFAULT_OCFLAGS) $(VISIBILITY_FLAG) AM_LDFLAGS = $(xineplug_ldflags) -noinst_HEADERS = bits_reader.h dpb.h h264_parser.h nal.h +noinst_HEADERS = bits_reader.h dpb.h cpb.h h264_parser.h nal.h if ENABLE_VDPAU vdpau_h264_module = xineplug_decode_vdpau_h264.la @@ -16,7 +16,7 @@ endif xineplug_LTLIBRARIES = $(vdpau_h264_module) $(vdpau_mpeg12_module) $(vdpau_vc1_module) -xineplug_decode_vdpau_h264_la_SOURCES = nal.c dpb.c h264_parser.c vdpau_h264.c +xineplug_decode_vdpau_h264_la_SOURCES = nal.c dpb.c cpb.c h264_parser.c vdpau_h264.c xineplug_decode_vdpau_h264_la_CFLAGS = $(AM_CFLAGS) $(VDPAU_CFLAGS) xineplug_decode_vdpau_h264_la_LIBADD = $(XINE_LIB) $(DYNAMIC_LD_LIBS) -lm diff --git a/src/video_dec/libvdpau/cpb.c b/src/video_dec/libvdpau/cpb.c new file mode 100644 index 000000000..ec61e55a1 --- /dev/null +++ b/src/video_dec/libvdpau/cpb.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2009 Julian Scheel + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * cpb.c: Coded Picture Buffer + */ + +#include "cpb.h" + +#include + +struct coded_picture* create_coded_picture() +{ + struct coded_picture* pic = calloc(1, sizeof(struct coded_picture)); + return pic; +} + +void free_coded_picture(struct coded_picture *pic) +{ + if(!pic) + return; + + release_nal_unit(pic->sei_nal); + release_nal_unit(pic->sps_nal); + release_nal_unit(pic->pps_nal); + release_nal_unit(pic->slc_nal); + + free(pic); +} + diff --git a/src/video_dec/libvdpau/cpb.h b/src/video_dec/libvdpau/cpb.h new file mode 100644 index 000000000..0bb46816f --- /dev/null +++ b/src/video_dec/libvdpau/cpb.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009 Julian Scheel + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * cpb.h: Coded Picture Buffer + */ + +#ifndef CPB_H_ +#define CPB_H_ + +#include "nal.h" + +enum picture_flags { + IDR_PIC = 0x01, + REFERENCE = 0x02, + NOT_EXISTING = 0x04, + INTERLACED = 0x08 +}; + +struct coded_picture +{ + uint32_t flag_mask; + + uint32_t max_pic_num; + int32_t pic_num; + + uint8_t used_for_long_term_ref; + uint32_t long_term_pic_num; + uint32_t long_term_frame_idx; + + int32_t top_field_order_cnt; + int32_t bottom_field_order_cnt; + + uint8_t repeat_pic; + + /* buffer data for the image slices, which + * are passed to the decoder + */ + uint32_t slice_cnt; + + int64_t pts; + + struct nal_unit *sei_nal; + struct nal_unit *sps_nal; + struct nal_unit *pps_nal; + struct nal_unit *slc_nal; +}; + +struct coded_picture* create_coded_picture(); +void free_coded_picture(struct coded_picture *pic); + +#endif /* CPB_H_ */ 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 #include +#include "cpb.h" #include "dpb.h" #include "nal.h" + #include -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; diff --git a/src/video_dec/libvdpau/dpb.h b/src/video_dec/libvdpau/dpb.h index be4982761..ef57c462c 100644 --- a/src/video_dec/libvdpau/dpb.h +++ b/src/video_dec/libvdpau/dpb.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * - * dpb.h: Decoder Picture Buffer + * dpb.h: Decoded Picture Buffer */ #ifndef DPB_H_ @@ -26,13 +26,22 @@ #define MAX_DPB_SIZE 16 #include "nal.h" +#include "cpb.h" #include struct decoded_picture { VdpVideoSurface surface; vo_frame_t *img; /* this is the image we block, to make sure * the surface is not double-used */ - struct nal_unit *nal; + + /** + * a decoded picture always contains a whole frame, + * respective a field pair, so it can contain up to + * 2 coded pics + */ + struct coded_picture *coded_pic[2]; + + int32_t frame_num_wrap; uint8_t used_for_reference; uint8_t top_is_reference; @@ -51,9 +60,18 @@ struct dpb { uint32_t used; }; -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); void free_decoded_picture(struct decoded_picture *pic); +void dpb_add_coded_picture(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); @@ -65,7 +83,7 @@ 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, 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); @@ -77,4 +95,24 @@ void dpb_clear_all_pts( struct dpb *dpb ); int fill_vdpau_reference_list(struct dpb *dpb, VdpReferenceFrameH264 *reflist); +static int dp_top_field_first(struct decoded_picture *decoded_pic) +{ + int top_field_first = 0; + + if (decoded_pic->coded_pic[0] == NULL) { + printf("SOMETHINGS VERY WRONG!\n"); + } + 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); + } + } + + return top_field_first; +} + #endif /* DPB_H_ */ diff --git a/src/video_dec/libvdpau/h264_parser.c b/src/video_dec/libvdpau/h264_parser.c index fffa1389e..c84673218 100644 --- a/src/video_dec/libvdpau/h264_parser.c +++ b/src/video_dec/libvdpau/h264_parser.c @@ -26,6 +26,7 @@ #include "h264_parser.h" #include "nal.h" +#include "cpb.h" /* default scaling_lists according to Table 7-2 */ uint8_t default_4x4_intra[16] = { 6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, @@ -52,40 +53,61 @@ struct buf_reader int cur_offset; }; +struct h264_parser* init_parser(); + static inline uint32_t read_bits(struct buf_reader *buf, int len); uint32_t read_exp_golomb(struct buf_reader *buf); int32_t read_exp_golomb_s(struct buf_reader *buf); -void calculate_pic_order(struct nal_parser *parser); +void calculate_pic_order(struct h264_parser *parser, struct coded_picture *pic, + struct slice_header *slc); void skip_scaling_list(struct buf_reader *buf, int size); void parse_scaling_list(struct buf_reader *buf, uint8_t *scaling_list, int length, int index); -int parse_nal_header(struct buf_reader *buf, struct nal_parser *parser); -static void sps_scaling_list_fallback(struct seq_parameter_set_rbsp *sps, int i); -static void pps_scaling_list_fallback(struct seq_parameter_set_rbsp *sps, struct pic_parameter_set_rbsp *pps, int i); -uint8_t parse_sps(struct buf_reader *buf, struct nal_parser *parser); + +struct nal_unit* parse_nal_header(struct buf_reader *buf, + struct coded_picture *pic, struct h264_parser *parser); +static void sps_scaling_list_fallback(struct seq_parameter_set_rbsp *sps, + int i); +static void pps_scaling_list_fallback(struct seq_parameter_set_rbsp *sps, + struct pic_parameter_set_rbsp *pps, int i); + +uint8_t parse_sps(struct buf_reader *buf, struct seq_parameter_set_rbsp *sps); +void interpret_sps(struct coded_picture *pic, struct h264_parser *parser); + void parse_vui_parameters(struct buf_reader *buf, struct seq_parameter_set_rbsp *sps); void parse_hrd_parameters(struct buf_reader *buf, struct hrd_parameters *hrd); -uint8_t parse_pps(struct buf_reader *buf, struct pic_parameter_set_rbsp *pps, - struct seq_parameter_set_rbsp *sps); -void parse_sei(struct buf_reader *buf, struct nal_parser *parser); -uint8_t parse_slice_header(struct buf_reader *buf, struct nal_parser *parser); -void - parse_ref_pic_list_reordering(struct buf_reader *buf, struct nal_unit *nal, - struct nal_parser *parser); -void decode_ref_pic_marking(struct nal_unit *nal, + +uint8_t parse_pps(struct buf_reader *buf, struct pic_parameter_set_rbsp *pps); +void interpret_pps(struct coded_picture *pic); + +void parse_sei(struct buf_reader *buf, struct sei_message *sei, + struct h264_parser *parser); +void interpret_sei(struct coded_picture *pic); + +uint8_t parse_slice_header(struct buf_reader *buf, struct nal_unit *slc_nal, + struct h264_parser *parser); +void interpret_slice_header(struct h264_parser *parser, struct nal_unit *slc_nal); + +void parse_ref_pic_list_reordering(struct buf_reader *buf, + struct slice_header *slc); + +void calculate_pic_nums(struct h264_parser *parser, struct coded_picture *cpic); +void execute_ref_pic_marking(struct coded_picture *cpic, uint32_t memory_management_control_operation, uint32_t marking_nr, - struct nal_parser *parser); -void parse_pred_weight_table(struct buf_reader *buf, struct nal_unit *nal); + struct h264_parser *parser); +void parse_pred_weight_table(struct buf_reader *buf, struct slice_header *slc, + struct h264_parser *parser); void parse_dec_ref_pic_marking(struct buf_reader *buf, - struct nal_parser *parser); + struct nal_unit *slc_nal); /* here goes the parser implementation */ static void decode_nal(uint8_t **ret, int *len_ret, uint8_t *buf, int buf_len) { + // TODO: rework without copying uint8_t *end = &buf[buf_len]; uint8_t *pos = malloc(buf_len); @@ -119,6 +141,9 @@ static inline void dump_bits(const char *label, const struct buf_reader *buf, in } #endif +/** + * @return total number of bits read by the buf_reader + */ static inline uint32_t bits_read(struct buf_reader *buf) { int bits_read = 0; @@ -128,6 +153,10 @@ static inline uint32_t bits_read(struct buf_reader *buf) return bits_read; } +/* + * read len bits from the buffer and return them + * @return right aligned bits + */ static inline uint32_t read_bits(struct buf_reader *buf, int len) { static uint32_t i_mask[33] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, @@ -178,7 +207,7 @@ static inline int rbsp_trailing_bits(uint8_t *buf, int buf_len) cur_buf--; } - printf("rbsp trailing bits could not be found\n"); + fprintf(stderr, "rbsp trailing bits could not be found\n"); return 0; } @@ -201,16 +230,20 @@ int32_t read_exp_golomb_s(struct buf_reader *buf) return code; } -int parse_nal_header(struct buf_reader *buf, struct nal_parser *parser) + +/** + * parses the NAL header data and calls the subsequent + * parser methods that handle specific NAL units + */ +struct nal_unit* parse_nal_header(struct buf_reader *buf, + struct coded_picture *pic, struct h264_parser *parser) { if (buf->len < 1) - return -1; + return NULL; - int ret = -1; - struct nal_unit *nal = parser->current_nal; + struct nal_unit *nal = create_nal_unit(); - memset(nal, 0x00, sizeof(struct nal_unit) - sizeof(struct seq_parameter_set_rbsp*) - sizeof(struct pic_parameter_set_rbsp*) - sizeof(struct slice_header*)); nal->nal_ref_idc = (buf->buf[0] >> 5) & 0x03; nal->nal_unit_type = buf->buf[0] & 0x1f; @@ -225,126 +258,134 @@ int parse_nal_header(struct buf_reader *buf, struct nal_parser *parser) decode_nal(&ibuf.buf, &ibuf.len, buf->cur_pos, buf->len - 1); ibuf.cur_pos = ibuf.buf; - if (!nal->sps) - nal->sps = calloc(1, sizeof(struct seq_parameter_set_rbsp)); - else - memset(nal->sps, 0x00, sizeof(struct seq_parameter_set_rbsp)); - - parse_sps(&ibuf, parser); + parse_sps(&ibuf, &nal->sps); free(ibuf.buf); - ret = NAL_SPS; break; case NAL_PPS: - if (!nal->pps) - nal->pps = calloc(1, sizeof(struct pic_parameter_set_rbsp)); - else - memset(nal->pps, 0x00, sizeof(struct pic_parameter_set_rbsp)); - - parse_pps(buf, nal->pps, nal->sps); - ret = NAL_PPS; + parse_pps(buf, &nal->pps); break; case NAL_SLICE: case NAL_PART_A: case NAL_PART_B: case NAL_PART_C: case NAL_SLICE_IDR: - if (nal->sps && nal->pps) { - if (!nal->slc) - nal->slc = calloc(1, sizeof(struct slice_header)); - else - memset(nal->slc, 0x00, sizeof(struct slice_header)); - - parse_slice_header(buf, parser); - ret = nal->nal_unit_type; - } + parse_slice_header(buf, nal, parser); break; case NAL_SEI: memset(&(nal->sei), 0x00, sizeof(struct sei_message)); - parse_sei(buf, parser); - ret = nal->nal_unit_type; + parse_sei(buf, &nal->sei, parser); break; default: - ret = nal->nal_unit_type; break; } - return ret; + return nal; } -void calculate_pic_order(struct nal_parser *parser) +/** + * calculates the picture order count according to ITU-T Rec. H.264 (11/2007) + * chapter 8.2.1, p104f + */ +void calculate_pic_order(struct h264_parser *parser, struct coded_picture *pic, + struct slice_header *slc) { - struct nal_unit *nal = parser->current_nal; + /* retrieve sps and pps from the buffers */ + struct nal_unit *pps_nal = + nal_buffer_get_by_pps_id(parser->pps_buffer, slc->pic_parameter_set_id); + + if (pps_nal == NULL) { + fprintf(stderr, "ERR: calculate_pic_order: pic_parameter_set_id %d not found in buffers\n", + slc->pic_parameter_set_id); + return; + } - struct seq_parameter_set_rbsp *sps = nal->sps; - struct slice_header *slc = nal->slc; - if (!sps || !slc) - return; + struct pic_parameter_set_rbsp *pps = &pps_nal->pps; - if (nal->nal_unit_type == NAL_SLICE_IDR) { - parser->prev_pic_order_cnt_lsb = 0; - parser->prev_pic_order_cnt_msb = 0; - parser->frame_num_offset = 0; + struct nal_unit *sps_nal = + nal_buffer_get_by_sps_id(parser->sps_buffer, pps->seq_parameter_set_id); + + if (sps_nal == NULL) { + fprintf(stderr, "ERR: calculate_pic_order: seq_parameter_set_id %d not found in buffers\n", + pps->seq_parameter_set_id); + return; } + struct seq_parameter_set_rbsp *sps = &sps_nal->sps; + if (sps->pic_order_cnt_type == 0) { + if (pic->flag_mask & IDR_PIC) { + parser->prev_pic_order_cnt_lsb = 0; + parser->prev_pic_order_cnt_msb = 0; + + + // FIXME + parser->frame_num_offset = 0; + } + const int max_poc_lsb = 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4); + uint32_t pic_order_cnt_msb = 0; + if (slc->pic_order_cnt_lsb < parser->prev_pic_order_cnt_lsb && parser->prev_pic_order_cnt_lsb - slc->pic_order_cnt_lsb >= max_poc_lsb / 2) - parser->pic_order_cnt_msb = parser->prev_pic_order_cnt_msb + max_poc_lsb; + pic_order_cnt_msb = parser->prev_pic_order_cnt_msb + max_poc_lsb; else if (slc->pic_order_cnt_lsb > parser->prev_pic_order_cnt_lsb && parser->prev_pic_order_cnt_lsb - slc->pic_order_cnt_lsb < -max_poc_lsb / 2) - parser->pic_order_cnt_msb = parser->prev_pic_order_cnt_msb - max_poc_lsb; + pic_order_cnt_msb = parser->prev_pic_order_cnt_msb - max_poc_lsb; else - parser->pic_order_cnt_msb = parser->prev_pic_order_cnt_msb; + pic_order_cnt_msb = parser->prev_pic_order_cnt_msb; + + if(!slc->field_pic_flag || !slc->bottom_field_flag) { + pic->top_field_order_cnt = pic_order_cnt_msb + slc->pic_order_cnt_lsb; + parser->prev_top_field_order_cnt = pic->top_field_order_cnt; + } - if(!slc->field_pic_flag || !slc->bottom_field_flag) - nal->top_field_order_cnt = parser->pic_order_cnt_msb + slc->pic_order_cnt_lsb; + if (pic->flag_mask & REFERENCE) { + parser->prev_pic_order_cnt_msb = pic_order_cnt_msb; + } - nal->bottom_field_order_cnt = 0; + pic->bottom_field_order_cnt = 0; if(!slc->field_pic_flag) - nal->bottom_field_order_cnt = nal->top_field_order_cnt + slc->delta_pic_order_cnt_bottom; - else //if(slc->bottom_field_flag) TODO: this is not spec compliant, but works... - nal->bottom_field_order_cnt = parser->pic_order_cnt_msb + slc->pic_order_cnt_lsb; + pic->bottom_field_order_cnt = pic->top_field_order_cnt + slc->delta_pic_order_cnt_bottom; + else //if(slc->bottom_field_flag) //TODO: this is not spec compliant, but works... + pic->bottom_field_order_cnt = pic_order_cnt_msb + slc->pic_order_cnt_lsb; - /*if(slc->bottom_field_flag) - nal->top_field_order_cnt = parser->last_nal->top_field_order_cnt;*/ + if(slc->field_pic_flag && slc->bottom_field_flag) + pic->top_field_order_cnt = parser->prev_top_field_order_cnt; } else if (sps->pic_order_cnt_type == 2) { - uint32_t prev_frame_num = parser->last_nal->slc->frame_num; + uint32_t prev_frame_num = parser->last_vcl_nal->slc.frame_num; uint32_t prev_frame_num_offset = parser->frame_num_offset; - uint32_t max_frame_num = 1 << (sps->log2_max_frame_num_minus4+4); uint32_t temp_pic_order_cnt = 0; - if (parser->is_idr) + if (parser->pic->flag_mask & IDR_PIC) parser->frame_num_offset = 0; else if (prev_frame_num > slc->frame_num) - parser->frame_num_offset = prev_frame_num_offset + max_frame_num; + parser->frame_num_offset = prev_frame_num_offset + sps->max_frame_num; else parser->frame_num_offset = prev_frame_num_offset; - if(parser->is_idr) + if(parser->pic->flag_mask & IDR_PIC) temp_pic_order_cnt = 0; - else if(nal->nal_ref_idc == 0) + else if(!(parser->pic->flag_mask & REFERENCE)) temp_pic_order_cnt = 2 * (parser->frame_num_offset + slc->frame_num)-1; else temp_pic_order_cnt = 2 * (parser->frame_num_offset + slc->frame_num); if(!slc->field_pic_flag) - nal->top_field_order_cnt = nal->bottom_field_order_cnt = temp_pic_order_cnt; + pic->top_field_order_cnt = pic->bottom_field_order_cnt = temp_pic_order_cnt; else if(slc->bottom_field_flag) - nal->bottom_field_order_cnt = temp_pic_order_cnt; + pic->bottom_field_order_cnt = temp_pic_order_cnt; else - nal->top_field_order_cnt = temp_pic_order_cnt; + pic->top_field_order_cnt = temp_pic_order_cnt; } else { - printf("FIXME: Unsupported poc_type: %d\n", sps->pic_order_cnt_type); + fprintf(stderr, "FIXME: Unsupported poc_type: %d\n", sps->pic_order_cnt_type); } - } void skip_scaling_list(struct buf_reader *buf, int size) @@ -364,7 +405,7 @@ void parse_scaling_list(struct buf_reader *buf, uint8_t *scaling_list, uint8_t use_default_scaling_matrix_flag = 0; int i; - uint8_t *zigzag = (length==64) ? zigzag_8x8 : zigzag_4x4; + const uint8_t *zigzag = (length==64) ? zigzag_8x8 : zigzag_4x4; for (i = 0; i < length; i++) { if (next_scale != 0) { @@ -480,9 +521,8 @@ static void pps_scaling_list_fallback(struct seq_parameter_set_rbsp *sps, struct } -uint8_t parse_sps(struct buf_reader *buf, struct nal_parser *parser) +uint8_t parse_sps(struct buf_reader *buf, struct seq_parameter_set_rbsp *sps) { - struct seq_parameter_set_rbsp *sps = parser->current_nal->sps; sps->profile_idc = read_bits(buf, 8); sps->constraint_setN_flag = read_bits(buf, 4); read_bits(buf, 4); @@ -523,6 +563,7 @@ uint8_t parse_sps(struct buf_reader *buf, struct nal_parser *parser) sps->chroma_format_idc = 1; sps->log2_max_frame_num_minus4 = read_exp_golomb(buf); + sps->max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4); sps->pic_order_cnt_type = read_exp_golomb(buf); if (!sps->pic_order_cnt_type) @@ -567,23 +608,65 @@ uint8_t parse_sps(struct buf_reader *buf, struct nal_parser *parser) sps->vui_parameters_present_flag = read_bits(buf, 1); if (sps->vui_parameters_present_flag) { parse_vui_parameters(buf, sps); - if(sps->vui_parameters.nal_hrd_parameters_present_flag || - sps->vui_parameters.vc1_hrd_parameters_present_flag) { - parser->cpb_dpb_delays_present_flag = 1; - } else - parser->cpb_dpb_delays_present_flag = 0; - } else - parser->cpb_dpb_delays_present_flag = 0; + } return 0; } -void parse_sei(struct buf_reader *buf, struct nal_parser *parser) +/* evaluates values parsed by sps and modifies the current + * picture according to them + */ +void interpret_sps(struct coded_picture *pic, struct h264_parser *parser) +{ + if(pic->sps_nal == NULL) { + fprintf(stderr, "WARNING: Picture contains no seq_parameter_set\n"); + return; + } + + struct seq_parameter_set_rbsp *sps = &pic->sps_nal->sps; + + if(sps->vui_parameters_present_flag && + sps->vui_parameters.pic_struct_present_flag) { + parser->flag_mask |= PIC_STRUCT_PRESENT; + } else { + parser->flag_mask &= ~PIC_STRUCT_PRESENT; + } + + if(sps->vui_parameters_present_flag && + (sps->vui_parameters.nal_hrd_parameters_present_flag || + sps->vui_parameters.vc1_hrd_parameters_present_flag)) { + parser->flag_mask |= CPB_DPB_DELAYS_PRESENT; + } else { + parser->flag_mask &= ~(CPB_DPB_DELAYS_PRESENT); + } + + if(pic->slc_nal != NULL) { + struct slice_header *slc = &pic->slc_nal->slc; + if (slc->field_pic_flag == 0) { + pic->max_pic_num = sps->max_frame_num; + parser->curr_pic_num = slc->frame_num; + } else { + pic->max_pic_num = 2 * sps->max_frame_num; + parser->curr_pic_num = 2 * slc->frame_num + 1; + } + } +} + +void parse_sei(struct buf_reader *buf, struct sei_message *sei, + struct h264_parser *parser) { - struct sei_message *sei = &(parser->current_nal->sei); - struct seq_parameter_set_rbsp *sps = parser->current_nal->sps; uint8_t tmp; + struct nal_unit *sps_nal = + nal_buffer_get_last(parser->sps_buffer); + + if (sps_nal == NULL) { + fprintf(stderr, "ERR: parse_sei: seq_parameter_set_id not found in buffers\n"); + return; + } + + struct seq_parameter_set_rbsp *sps = &sps_nal->sps; + sei->payload_type = 0; while((tmp = read_bits(buf, 8)) == 0xff) { sei->payload_type += 255; @@ -600,39 +683,111 @@ void parse_sei(struct buf_reader *buf, struct nal_parser *parser) /* pic_timing */ if(sei->payload_type == 1) { - if(parser->cpb_dpb_delays_present_flag) { + if(parser->flag_mask & CPB_DPB_DELAYS_PRESENT) { sei->pic_timing.cpb_removal_delay = read_bits(buf, 5); sei->pic_timing.dpb_output_delay = read_bits(buf, 5); } - if(sps && sps->vui_parameters_present_flag && - sps->vui_parameters.pic_struct_present_flag) { + if(parser->flag_mask & PIC_STRUCT_PRESENT) { sei->pic_timing.pic_struct = read_bits(buf, 4); + + uint8_t NumClockTs = 0; switch(sei->pic_timing.pic_struct) { - case DISP_FRAME: - parser->current_nal->interlaced = 0; - parser->current_nal->repeat_pic = 0; + case 0: + case 1: + case 2: + NumClockTs = 1; break; - case DISP_TOP: - case DISP_BOTTOM: - case DISP_TOP_BOTTOM: - case DISP_BOTTOM_TOP: - parser->current_nal->interlaced = 1; + case 3: + case 4: + case 7: + NumClockTs = 2; break; - case DISP_TOP_BOTTOM_TOP: - case DISP_BOTTOM_TOP_BOTTOM: - parser->current_nal->interlaced = 1; - parser->current_nal->repeat_pic = 1; + case 5: + case 6: + case 8: + NumClockTs = 3; break; - case DISP_FRAME_DOUBLING: - parser->current_nal->interlaced = 0; - parser->current_nal->repeat_pic = 2; - break; - case DISP_FRAME_TRIPLING: - parser->current_nal->interlaced = 0; - parser->current_nal->repeat_pic = 3; + } + + int i; + for(i = 0; i < NumClockTs; i++) { + if(read_bits(buf, 1)) { /* clock_timestamp_flag == 1 */ + printf("parse clock timestamp!\n"); + sei->pic_timing.ct_type = read_bits(buf, 2); + sei->pic_timing.nuit_field_based_flag = read_bits(buf, 1); + sei->pic_timing.counting_type = read_bits(buf, 5); + sei->pic_timing.full_timestamp_flag = read_bits(buf, 1); + sei->pic_timing.discontinuity_flag = read_bits(buf, 1); + sei->pic_timing.cnt_dropped_flag = read_bits(buf, 1); + sei->pic_timing.n_frames = read_bits(buf, 8); + if(sei->pic_timing.full_timestamp_flag) { + sei->pic_timing.seconds_value = read_bits(buf, 6); + sei->pic_timing.minutes_value = read_bits(buf, 6); + sei->pic_timing.hours_value = read_bits(buf, 5); + } else { + if(read_bits(buf, 1)) { + sei->pic_timing.seconds_value = read_bits(buf, 6); + + if(read_bits(buf, 1)) { + sei->pic_timing.minutes_value = read_bits(buf, 6); + + if(read_bits(buf, 1)) { + sei->pic_timing.hours_value = read_bits(buf, 5); + } + } + } + } + + if(sps->vui_parameters_present_flag && + sps->vui_parameters.nal_hrd_parameters_present_flag) { + sei->pic_timing.time_offset = + read_bits(buf, + sps->vui_parameters.nal_hrd_parameters.time_offset_length); + } + } } } + } /*else { + fprintf(stderr, "Unimplemented SEI payload: %d\n", sei->payload_type); + }*/ + +} + +void interpret_sei(struct coded_picture *pic) +{ + if(!pic->sps_nal || !pic->sei_nal) + return; + + struct seq_parameter_set_rbsp *sps = &pic->sps_nal->sps; + struct sei_message *sei = &pic->sei_nal->sei; + + if(sps && sps->vui_parameters_present_flag && + sps->vui_parameters.pic_struct_present_flag) { + switch(sei->pic_timing.pic_struct) { + case DISP_FRAME: + pic->flag_mask &= ~INTERLACED; + pic->repeat_pic = 0; + break; + case DISP_TOP: + case DISP_BOTTOM: + case DISP_TOP_BOTTOM: + case DISP_BOTTOM_TOP: + pic->flag_mask |= INTERLACED; + break; + case DISP_TOP_BOTTOM_TOP: + case DISP_BOTTOM_TOP_BOTTOM: + pic->flag_mask |= INTERLACED; + pic->repeat_pic = 1; + break; + case DISP_FRAME_DOUBLING: + pic->flag_mask &= ~INTERLACED; + pic->repeat_pic = 2; + break; + case DISP_FRAME_TRIPLING: + pic->flag_mask &= ~INTERLACED; + pic->repeat_pic = 3; + } } } @@ -726,8 +881,7 @@ void parse_hrd_parameters(struct buf_reader *buf, struct hrd_parameters *hrd) hrd->time_offset_length = read_bits(buf, 5); } -uint8_t parse_pps(struct buf_reader *buf, struct pic_parameter_set_rbsp *pps, - struct seq_parameter_set_rbsp *sps) +uint8_t parse_pps(struct buf_reader *buf, struct pic_parameter_set_rbsp *pps) { pps->pic_parameter_set_id = read_exp_golomb(buf); pps->seq_parameter_set_id = read_exp_golomb(buf); @@ -795,8 +949,6 @@ uint8_t parse_pps(struct buf_reader *buf, struct pic_parameter_set_rbsp *pps, parse_scaling_list(buf, pps->scaling_lists_4x4[i], 16, i); else parse_scaling_list(buf, pps->scaling_lists_8x8[i - 6], 64, i); - } else { - pps_scaling_list_fallback(sps, pps, i); } } } @@ -805,26 +957,41 @@ uint8_t parse_pps(struct buf_reader *buf, struct pic_parameter_set_rbsp *pps, } else pps->second_chroma_qp_index_offset = pps->chroma_qp_index_offset; + return 0; +} + +void interpret_pps(struct coded_picture *pic) +{ + if(pic->sps_nal == NULL) { + fprintf(stderr, "WARNING: Picture contains no seq_parameter_set\n"); + return; + } else if(pic->pps_nal == NULL) { + fprintf(stderr, "WARNING: Picture contains no pic_parameter_set\n"); + return; + } + + struct seq_parameter_set_rbsp *sps = &pic->sps_nal->sps; + struct pic_parameter_set_rbsp *pps = &pic->pps_nal->pps; + + int i; + for (i = 0; i < 8; i++) { + if (!pps->pic_scaling_list_present_flag[i]) { + pps_scaling_list_fallback(sps, pps, i); + } + } + if (!pps->pic_scaling_matrix_present_flag && sps != NULL) { memcpy(pps->scaling_lists_4x4, sps->scaling_lists_4x4, sizeof(pps->scaling_lists_4x4)); memcpy(pps->scaling_lists_8x8, sps->scaling_lists_8x8, sizeof(pps->scaling_lists_8x8)); } - - return 0; } -uint8_t parse_slice_header(struct buf_reader *buf, struct nal_parser *parser) +uint8_t parse_slice_header(struct buf_reader *buf, struct nal_unit *slc_nal, + struct h264_parser *parser) { - struct nal_unit *nal = parser->current_nal; - - struct seq_parameter_set_rbsp *sps = nal->sps; - struct pic_parameter_set_rbsp *pps = nal->pps; - struct slice_header *slc = nal->slc; - memset(slc, 0x00, sizeof(struct slice_header)); - if (!sps || !pps) - return -1; + struct slice_header *slc = &slc_nal->slc; slc->first_mb_in_slice = read_exp_golomb(buf); /* we do some parsing on the slice type, because the list is doubled */ @@ -832,6 +999,30 @@ uint8_t parse_slice_header(struct buf_reader *buf, struct nal_parser *parser) //print_slice_type(slc->slice_type); slc->pic_parameter_set_id = read_exp_golomb(buf); + + /* retrieve sps and pps from the buffers */ + struct nal_unit *pps_nal = + nal_buffer_get_by_pps_id(parser->pps_buffer, slc->pic_parameter_set_id); + + if (pps_nal == NULL) { + fprintf(stderr, "ERR: parse_slice_header: pic_parameter_set_id %d not found in buffers\n", + slc->pic_parameter_set_id); + return -1; + } + + struct pic_parameter_set_rbsp *pps = &pps_nal->pps; + + struct nal_unit *sps_nal = + nal_buffer_get_by_sps_id(parser->sps_buffer, pps->seq_parameter_set_id); + + if (sps_nal == NULL) { + fprintf(stderr, "ERR: parse_slice_header: seq_parameter_set_id %d not found in buffers\n", + pps->seq_parameter_set_id); + return -1; + } + + struct seq_parameter_set_rbsp *sps = &sps_nal->sps; + if(sps->separate_colour_plane_flag) slc->colour_plane_id = read_bits(buf, 2); @@ -848,15 +1039,7 @@ uint8_t parse_slice_header(struct buf_reader *buf, struct nal_parser *parser) slc->bottom_field_flag = 0; } - if (slc->field_pic_flag == 0) { - nal->max_pic_num = 1 << (sps->log2_max_frame_num_minus4+4); - nal->curr_pic_num = slc->frame_num; - } else { - nal->curr_pic_num = 2 * slc->frame_num + 1; - nal->max_pic_num = 2 * (1 << (sps->log2_max_frame_num_minus4+4)); - } - - if (nal->nal_unit_type == NAL_SLICE_IDR) + if (slc_nal->nal_unit_type == NAL_SLICE_IDR) slc->idr_pic_id = read_exp_golomb(buf); if (!sps->pic_order_cnt_type) { @@ -897,28 +1080,62 @@ uint8_t parse_slice_header(struct buf_reader *buf, struct nal_parser *parser) } /* --- ref_pic_list_reordering --- */ - parse_ref_pic_list_reordering(buf, nal, parser); + parse_ref_pic_list_reordering(buf, slc); /* --- pred_weight_table --- */ if ((pps->weighted_pred_flag && (slc->slice_type == SLICE_P || slc->slice_type == SLICE_SP)) || (pps->weighted_bipred_idc == 1 && slc->slice_type == SLICE_B)) { - parse_pred_weight_table(buf, nal); + parse_pred_weight_table(buf, slc, parser); } /* --- dec_ref_pic_marking --- */ - if (nal->nal_ref_idc != 0) - parse_dec_ref_pic_marking(buf, parser); + if (slc_nal->nal_ref_idc != 0) + parse_dec_ref_pic_marking(buf, slc_nal); else slc->dec_ref_pic_marking_count = 0; return 0; } -void parse_ref_pic_list_reordering(struct buf_reader *buf, struct nal_unit *nal, struct nal_parser *parser) +void interpret_slice_header(struct h264_parser *parser, struct nal_unit *slc_nal) { - struct slice_header *slc = nal->slc; + struct coded_picture *pic = parser->pic; + struct slice_header *slc = &slc_nal->slc; + + /* retrieve sps and pps from the buffers */ + struct nal_unit *pps_nal = + nal_buffer_get_by_pps_id(parser->pps_buffer, slc->pic_parameter_set_id); + + if (pps_nal == NULL) { + fprintf(stderr, "ERR: interpret_slice_header: pic_parameter_set_id %d not found in buffers\n", + slc->pic_parameter_set_id); + return; + } + + struct nal_unit *sps_nal = + nal_buffer_get_by_sps_id(parser->sps_buffer, pps_nal->pps.seq_parameter_set_id); + + if (sps_nal == NULL) { + fprintf(stderr, "ERR: interpret_slice_header: seq_parameter_set_id %d not found in buffers\n", + pps_nal->pps.seq_parameter_set_id); + return; + } + + if (pic->sps_nal) { + release_nal_unit(pic->sps_nal); + } + if (pic->pps_nal) { + release_nal_unit(pic->pps_nal); + } + lock_nal_unit(sps_nal); + pic->sps_nal = sps_nal; + lock_nal_unit(pps_nal); + pic->pps_nal = pps_nal; +} +void parse_ref_pic_list_reordering(struct buf_reader *buf, struct slice_header *slc) +{ if (slc->slice_type != SLICE_I && slc->slice_type != SLICE_SI) { slc->ref_pic_list_reordering.ref_pic_list_reordering_flag_l0 = read_bits( buf, 1); @@ -962,30 +1179,34 @@ void parse_ref_pic_list_reordering(struct buf_reader *buf, struct nal_unit *nal, } } -void parse_pred_weight_table(struct buf_reader *buf, struct nal_unit *nal) +void parse_pred_weight_table(struct buf_reader *buf, struct slice_header *slc, + struct h264_parser *parser) { - struct seq_parameter_set_rbsp *sps = nal->sps; - struct pic_parameter_set_rbsp *pps = nal->pps; - struct slice_header *slc = nal->slc; - if (!sps || !pps) - return; + /* retrieve sps and pps from the buffers */ + struct pic_parameter_set_rbsp *pps = + &nal_buffer_get_by_pps_id(parser->pps_buffer, slc->pic_parameter_set_id) + ->pps; + + struct seq_parameter_set_rbsp *sps = + &nal_buffer_get_by_sps_id(parser->sps_buffer, pps->seq_parameter_set_id) + ->sps; - nal->slc->pred_weight_table.luma_log2_weight_denom = read_exp_golomb(buf); + slc->pred_weight_table.luma_log2_weight_denom = read_exp_golomb(buf); uint32_t ChromaArrayType = sps->chroma_format_idc; if(sps->separate_colour_plane_flag) ChromaArrayType = 0; if (ChromaArrayType != 0) - nal->slc->pred_weight_table.chroma_log2_weight_denom = read_exp_golomb(buf); + slc->pred_weight_table.chroma_log2_weight_denom = read_exp_golomb(buf); int i; for (i = 0; i <= slc->num_ref_idx_l0_active_minus1; i++) { uint8_t luma_weight_l0_flag = read_bits(buf, 1); if (luma_weight_l0_flag == 1) { - nal->slc->pred_weight_table.luma_weight_l0[i] = read_exp_golomb_s(buf); - nal->slc->pred_weight_table.luma_offset_l0[i] = read_exp_golomb_s(buf); + slc->pred_weight_table.luma_weight_l0[i] = read_exp_golomb_s(buf); + slc->pred_weight_table.luma_offset_l0[i] = read_exp_golomb_s(buf); } if (ChromaArrayType != 0) { @@ -994,9 +1215,9 @@ void parse_pred_weight_table(struct buf_reader *buf, struct nal_unit *nal) if (chroma_weight_l0_flag == 1) { int j; for (j = 0; j < 2; j++) { - nal->slc->pred_weight_table.chroma_weight_l0[i][j] + slc->pred_weight_table.chroma_weight_l0[i][j] = read_exp_golomb_s(buf); - nal->slc->pred_weight_table.chroma_offset_l0[i][j] + slc->pred_weight_table.chroma_offset_l0[i][j] = read_exp_golomb_s(buf); } } @@ -1011,8 +1232,8 @@ void parse_pred_weight_table(struct buf_reader *buf, struct nal_unit *nal) uint8_t luma_weight_l1_flag = read_bits(buf, 1); if (luma_weight_l1_flag == 1) { - nal->slc->pred_weight_table.luma_weight_l1[i] = read_exp_golomb_s(buf); - nal->slc->pred_weight_table.luma_offset_l1[i] = read_exp_golomb_s(buf); + slc->pred_weight_table.luma_weight_l1[i] = read_exp_golomb_s(buf); + slc->pred_weight_table.luma_offset_l1[i] = read_exp_golomb_s(buf); } if (ChromaArrayType != 0) { @@ -1021,9 +1242,9 @@ void parse_pred_weight_table(struct buf_reader *buf, struct nal_unit *nal) if (chroma_weight_l1_flag == 1) { int j; for (j = 0; j < 2; j++) { - nal->slc->pred_weight_table.chroma_weight_l1[i][j] + slc->pred_weight_table.chroma_weight_l1[i][j] = read_exp_golomb_s(buf); - nal->slc->pred_weight_table.chroma_offset_l1[i][j] + slc->pred_weight_table.chroma_offset_l1[i][j] = read_exp_golomb_s(buf); } } @@ -1032,51 +1253,139 @@ void parse_pred_weight_table(struct buf_reader *buf, struct nal_unit *nal) } } -void decode_ref_pic_marking(struct nal_unit *nal, +/** + * PicNum calculation following ITU-T H264 11/2007 + * 8.2.4.1 p112f + */ +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) { + int i; + for (i=0; i<2; i++) { + if(pic->coded_pic[i] == NULL) + continue; + + struct slice_header *slc = &pic->coded_pic[i]->slc_nal->slc; + struct seq_parameter_set_rbsp *sps = &pic->coded_pic[i]->sps_nal->sps; + + if (!pic->coded_pic[i]->used_for_long_term_ref) { + int32_t frame_num_wrap = 0; + if (slc->frame_num > cslc->frame_num) + frame_num_wrap = slc->frame_num - sps->max_frame_num; + else + frame_num_wrap = slc->frame_num; + + if(i == 0) { + pic->frame_num_wrap = frame_num_wrap; + } + + if (cslc->field_pic_flag == 0) { + pic->coded_pic[i]->pic_num = frame_num_wrap; + } else { + pic->coded_pic[i]->pic_num = 2 * frame_num_wrap; + if((slc->field_pic_flag == 1 && + cslc->bottom_field_flag == slc->bottom_field_flag) || + (slc->field_pic_flag == 0 && !cslc->bottom_field_flag)) + pic->coded_pic[i]->pic_num++; + } + } else { + pic->coded_pic[i]->long_term_pic_num = pic->coded_pic[i]->long_term_frame_idx; + if(slc->bottom_field_flag == cslc->bottom_field_flag) + pic->coded_pic[i]->long_term_pic_num++; + } + } + } +} + +void execute_ref_pic_marking(struct coded_picture *cpic, uint32_t memory_management_control_operation, uint32_t marking_nr, - struct nal_parser *parser) + struct h264_parser *parser) { - struct slice_header *slc = nal->slc; + /** + * according to NOTE 6, p83 the dec_ref_pic_marking + * structure is identical for all slice headers within + * a coded picture, so we can simply use the last + * slice_header we saw in the pic + */ + if (!cpic->slc_nal) + return; + struct slice_header *slc = &cpic->slc_nal->slc; struct dpb *dpb = &parser->dpb; - if (!slc) + + 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); + } else { + dpb_set_unused_ref_picture_lidx_gt(&parser->dpb, -1); + } return; + } + /* MMC operation == 1 : 8.2.5.4.1, p. 120 */ if (memory_management_control_operation == 1) { // short-term -> unused for reference - uint32_t pic_num_x = (nal->curr_pic_num - - (slc->dec_ref_pic_marking[marking_nr].difference_of_pic_nums_minus1 + 1))%nal->max_pic_num; + int32_t pic_num_x = (parser->curr_pic_num + - (slc->dec_ref_pic_marking[marking_nr].difference_of_pic_nums_minus1 + 1)); + //% cpic->max_pic_num; struct decoded_picture* pic = NULL; if ((pic = dpb_get_picture(dpb, pic_num_x)) != NULL) { - if (pic->nal->slc->field_pic_flag == 0) { + if (cpic->slc_nal->slc.field_pic_flag == 0) { dpb_set_unused_ref_picture_a(dpb, pic); } else { - //if(!pic->top_is_reference) - dpb_set_unused_ref_picture_a(dpb, pic); - /*else - pic->top_is_reference = 0;*/ - //printf("FIXME: We might need do delete more from the DPB...\n"); - // FIXME: some more handling needed here?! See 8.2.5.4.1, p. 120 + if (pic->coded_pic[0]->slc_nal->slc.field_pic_flag == 1) { + if (pic->top_is_reference) + pic->top_is_reference = 0; + else if (pic->bottom_is_reference) + pic->bottom_is_reference = 0; + + if(!pic->top_is_reference && !pic->bottom_is_reference) + dpb_set_unused_ref_picture_a(dpb, pic); + } else { + pic->top_is_reference = pic->bottom_is_reference = 0; + dpb_set_unused_ref_picture_a(dpb, pic); + } } + } else { + fprintf(stderr, "H264: mmc 1 failed: %d not existent - curr_pic: %d\n", pic_num_x, parser->curr_pic_num); } } else if (memory_management_control_operation == 2) { // long-term -> unused for reference struct decoded_picture* pic = dpb_get_picture_by_ltpn(dpb, slc->dec_ref_pic_marking[marking_nr].long_term_pic_num); if (pic != NULL) { - if (pic->nal->slc->field_pic_flag == 0) - dpb_set_unused_ref_picture(dpb, + if (cpic->slc_nal->slc.field_pic_flag == 0) + dpb_set_unused_ref_picture_byltpn(dpb, slc->dec_ref_pic_marking[marking_nr].long_term_pic_num); else { - dpb_set_unused_ref_picture(dpb, - slc->dec_ref_pic_marking[marking_nr].long_term_pic_num); - printf("FIXME: We might need do delete more from the DPB...\n"); + + if (pic->coded_pic[0]->slc_nal->slc.field_pic_flag == 1) { + if (pic->top_is_reference) + pic->top_is_reference = 0; + else if (pic->bottom_is_reference) + pic->bottom_is_reference = 0; + + if(!pic->top_is_reference && !pic->bottom_is_reference) { + dpb_set_unused_ref_picture_byltpn(dpb, + slc->dec_ref_pic_marking[marking_nr].long_term_pic_num); + } + } else { + pic->top_is_reference = pic->bottom_is_reference = 0; + dpb_set_unused_ref_picture_byltpn(dpb, + slc->dec_ref_pic_marking[marking_nr].long_term_pic_num); + } } } } else if (memory_management_control_operation == 3) { // short-term -> long-term, set long-term frame index - uint32_t pic_num_x = nal->curr_pic_num + uint32_t pic_num_x = parser->curr_pic_num - (slc->dec_ref_pic_marking[marking_nr].difference_of_pic_nums_minus1 + 1); struct decoded_picture* pic = dpb_get_picture_by_ltidx(dpb, slc->dec_ref_pic_marking[marking_nr].long_term_pic_num); @@ -1086,16 +1395,29 @@ void decode_ref_pic_marking(struct nal_unit *nal, pic = dpb_get_picture(dpb, pic_num_x); if (pic) { - if (pic->nal->slc->field_pic_flag == 0) { - pic = dpb_get_picture(dpb, pic_num_x); - pic->nal->long_term_frame_idx + pic = dpb_get_picture(dpb, pic_num_x); + + if (pic->coded_pic[0]->slc_nal->slc.field_pic_flag == 0) { + pic->coded_pic[0]->long_term_frame_idx = slc->dec_ref_pic_marking[marking_nr].long_term_frame_idx; + pic->coded_pic[0]->long_term_pic_num = pic->coded_pic[0]->long_term_frame_idx; } - else + else { + if(pic->coded_pic[0]->pic_num == pic_num_x) { + pic->coded_pic[0]->long_term_frame_idx + = slc->dec_ref_pic_marking[marking_nr].long_term_frame_idx; + pic->coded_pic[0]->long_term_pic_num = pic->coded_pic[0]->long_term_frame_idx * 2 + 1; + } else if(pic->coded_pic[1] != NULL && + pic->coded_pic[1]->pic_num == pic_num_x) { + pic->coded_pic[1]->long_term_frame_idx + = slc->dec_ref_pic_marking[marking_nr].long_term_frame_idx; + pic->coded_pic[1]->long_term_pic_num = pic->coded_pic[1]->long_term_frame_idx * 2 + 1; + } printf("FIXME: B Set frame %d to long-term ref\n", pic_num_x); + } } else { - printf("memory_management_control_operation: 3 failed. No such picture.\n"); + fprintf(stderr, "memory_management_control_operation: 3 failed. No such picture.\n"); } } else if (memory_management_control_operation == 4) { @@ -1111,10 +1433,14 @@ void decode_ref_pic_marking(struct nal_unit *nal, // mark all ref pics as unused for reference, // set max-long-term frame index = no long-term frame idxs dpb_flush(dpb); - parser->pic_order_cnt_lsb = 0; - parser->pic_order_cnt_msb = 0; - parser->prev_pic_order_cnt_lsb = 0; - parser->prev_pic_order_cnt_msb = 0; + + if (!slc->bottom_field_flag) { + parser->prev_pic_order_cnt_lsb = cpic->top_field_order_cnt; + parser->prev_pic_order_cnt_msb = 0; + } else { + parser->prev_pic_order_cnt_lsb = 0; + parser->prev_pic_order_cnt_msb = 0; + } } else if (memory_management_control_operation == 6) { // mark current picture as used for long-term ref, // assing long-term frame idx to it @@ -1124,33 +1450,34 @@ void decode_ref_pic_marking(struct nal_unit *nal, dpb_set_unused_ref_picture_bylidx(dpb, slc->dec_ref_pic_marking[marking_nr].long_term_frame_idx); - nal->long_term_frame_idx = slc->dec_ref_pic_marking[marking_nr].long_term_frame_idx; + cpic->long_term_frame_idx = slc->dec_ref_pic_marking[marking_nr].long_term_frame_idx; + cpic->used_for_long_term_ref = 1; if (slc->field_pic_flag == 0) { - nal->used_for_long_term_ref = 1; + cpic->long_term_pic_num = cpic->long_term_frame_idx; } - else - printf("FIXME: BY Set frame to long-term ref\n"); + else { + cpic->long_term_pic_num = cpic->long_term_frame_idx * 2 + 1; + } + } - /* FIXME: Do we need to care about MMC=0? */ } void parse_dec_ref_pic_marking(struct buf_reader *buf, - struct nal_parser *parser) + struct nal_unit *slc_nal) { - struct nal_unit *nal = parser->current_nal; - struct pic_parameter_set_rbsp *pps = parser->current_nal->pps; - struct slice_header *slc = nal->slc; + struct slice_header *slc = &slc_nal->slc; - if (!slc || !pps) + if (!slc) return; slc->dec_ref_pic_marking_count = 0; int i = slc->dec_ref_pic_marking_count; - if (nal->nal_unit_type == NAL_SLICE_IDR) { + if (slc_nal->nal_unit_type == NAL_SLICE_IDR) { slc->dec_ref_pic_marking[i].no_output_of_prior_pics_flag = read_bits(buf, 1); slc->dec_ref_pic_marking[i].long_term_reference_flag = read_bits(buf, 1); + i+=2; } else { slc->dec_ref_pic_marking[i].adaptive_ref_pic_marking_mode_flag = read_bits( buf, 1); @@ -1180,7 +1507,7 @@ void parse_dec_ref_pic_marking(struct buf_reader *buf, i++; if(i >= 10) { - printf("Error: Not more than 10 MMC operations supported per slice. Dropping some.\n"); + fprintf(stderr, "Error: Not more than 10 MMC operations supported per slice. Dropping some.\n"); i = 0; } } while (slc->dec_ref_pic_marking[i-1].memory_management_control_operation @@ -1193,33 +1520,31 @@ void parse_dec_ref_pic_marking(struct buf_reader *buf, /* ----------------- NAL parser ----------------- */ -struct nal_parser* init_parser() +struct h264_parser* init_parser() { - struct nal_parser *parser = calloc(1, sizeof(struct nal_parser)); - parser->nal0 = init_nal_unit(); - parser->nal1 = init_nal_unit(); - parser->current_nal = parser->nal0; - parser->last_nal = parser->nal1; - parser->slice_cnt = 1; - - parser->field = -1; + struct h264_parser *parser = calloc(1, sizeof(struct h264_parser)); + parser->pic = create_coded_picture(); + parser->position = NON_VCL; + parser->last_vcl_nal = NULL; + parser->sps_buffer = create_nal_buffer(32); + parser->pps_buffer = create_nal_buffer(32); + memset(&parser->dpb, 0x00, sizeof(struct dpb)); /* no idea why we do that. inspired by libavcodec, * as we couldn't figure in the specs.... */ - parser->prev_pic_order_cnt_msb = parser->pic_order_cnt_lsb = 1 << 16; + parser->prev_pic_order_cnt_msb = 1 << 16; return parser; } -void free_parser(struct nal_parser *parser) +void free_parser(struct h264_parser *parser) { - free_nal_unit(parser->nal0); - free_nal_unit(parser->nal1); + dpb_free_all(&parser->dpb); free(parser); } -void parse_codec_private(struct nal_parser *parser, uint8_t *inbuf, int inbuf_len) +void parse_codec_private(struct h264_parser *parser, uint8_t *inbuf, int inbuf_len) { struct buf_reader bufr; @@ -1228,19 +1553,15 @@ void parse_codec_private(struct nal_parser *parser, uint8_t *inbuf, int inbuf_le bufr.cur_offset = 8; bufr.len = inbuf_len; - struct nal_unit *nal = parser->current_nal; - struct nal_unit *nal1 = parser->last_nal; + // FIXME: Might be broken! + struct nal_unit *nal = calloc(1, sizeof(struct nal_unit)); - if (!nal->sps) - nal->sps = calloc(1, sizeof(struct seq_parameter_set_rbsp)); - else - memset(nal->sps, 0x00, sizeof(struct seq_parameter_set_rbsp)); /* reserved */ read_bits(&bufr, 8); - nal->sps->profile_idc = read_bits(&bufr, 8); + nal->sps.profile_idc = read_bits(&bufr, 8); read_bits(&bufr, 8); - nal->sps->level_idc = read_bits(&bufr, 8); + nal->sps.level_idc = read_bits(&bufr, 8); read_bits(&bufr, 6); parser->nal_size_length = read_bits(&bufr, 2) + 1; @@ -1251,11 +1572,13 @@ void parse_codec_private(struct nal_parser *parser, uint8_t *inbuf, int inbuf_le inbuf += 6; inbuf_len -= 6; int i; + + struct coded_picture *dummy = NULL; for(i = 0; i < sps_count; i++) { uint16_t sps_size = read_bits(&bufr, 16); inbuf += 2; inbuf_len -= 2; - parse_nal(inbuf, sps_size, parser); + parse_nal(inbuf, sps_size, parser, &dummy); inbuf += sps_size; inbuf_len -= sps_size; } @@ -1271,47 +1594,49 @@ void parse_codec_private(struct nal_parser *parser, uint8_t *inbuf, int inbuf_le uint16_t pps_size = read_bits(&bufr, 16); inbuf += 2; inbuf_len -= 2; - parse_nal(inbuf, pps_size, parser); + parse_nal(inbuf, pps_size, parser, &dummy); inbuf += pps_size; inbuf_len -= pps_size; } - copy_nal_unit(nal1, nal); - printf("done parsing extradata\n"); + nal_buffer_append(parser->sps_buffer, nal); } -void process_mmc_operations(struct nal_parser *parser) +void process_mmc_operations(struct h264_parser *parser, struct coded_picture *picture) { - if(parser->last_nal_res == 1 && parser->current_nal && - parser->current_nal->slc) { - int i; - for(i = 0; i < parser->current_nal->slc->dec_ref_pic_marking_count; i++) { - decode_ref_pic_marking( - parser->current_nal, - parser->current_nal->slc->dec_ref_pic_marking[i].memory_management_control_operation, - i, - parser); - } + if (picture->flag_mask & REFERENCE) { + parser->prev_pic_order_cnt_lsb + = picture->slc_nal->slc.pic_order_cnt_lsb; + } - if (parser->last_nal->slc != NULL) - parser->prev_pic_order_cnt_lsb - = parser->last_nal->slc->pic_order_cnt_lsb; - parser->prev_pic_order_cnt_msb = parser->pic_order_cnt_msb; + int i; + for(i = 0; i < picture->slc_nal->slc. + dec_ref_pic_marking_count; i++) { + execute_ref_pic_marking( + picture, + picture->slc_nal->slc.dec_ref_pic_marking[i]. + memory_management_control_operation, + i, + parser); } } -int parse_frame(struct nal_parser *parser, uint8_t *inbuf, int inbuf_len, - uint8_t **ret_buf, uint32_t *ret_len, uint32_t *ret_slice_cnt) +int parse_frame(struct h264_parser *parser, uint8_t *inbuf, int inbuf_len, + int64_t pts, + uint8_t **ret_buf, uint32_t *ret_len, struct coded_picture **ret_pic) { int32_t next_nal = 0; int32_t offset = 0; int start_seq_len = 3; + *ret_pic = *ret_buf = NULL; + *ret_len = 0; + if(parser->nal_size_length > 0) start_seq_len = offset = parser->nal_size_length; if (parser->prebuf_len + inbuf_len > MAX_FRAME_SIZE) { - printf("buf underrun!!\n"); + fprintf(stderr, "h264_parser: prebuf underrung\n"); *ret_len = 0; *ret_buf = NULL; parser->prebuf_len = 0; @@ -1328,27 +1653,41 @@ int parse_frame(struct nal_parser *parser, uint8_t *inbuf, int inbuf_len, while((next_nal = seek_for_nal(parser->prebuf+start_seq_len-offset, parser->prebuf_len-start_seq_len+offset, parser)) > 0) { + struct coded_picture *completed_pic = NULL; + if(!parser->nal_size_length && - (parser->prebuf[0] != 0x00 || parser->prebuf[1] != 0x00 || parser->prebuf[2] != 0x01)) { - printf("Broken NAL, skip it.\n"); + (parser->prebuf[0] != 0x00 || parser->prebuf[1] != 0x00 || + parser->prebuf[2] != 0x01)) { + fprintf(stderr, "Broken NAL, skip it.\n"); parser->last_nal_res = 2; - } else - parser->last_nal_res = parse_nal(parser->prebuf+start_seq_len, next_nal, parser); + } else { + parser->last_nal_res = parse_nal(parser->prebuf+start_seq_len, + next_nal, parser, &completed_pic); + } - if ((parser->last_nal_res == 1 || parser->last_nal_res == 3) && parser->buf_len > 0) { + if (completed_pic != NULL && + completed_pic->slice_cnt > 0 && + parser->buf_len > 0) { //printf("Frame complete: %d bytes\n", parser->buf_len); *ret_len = parser->buf_len; - *ret_buf = malloc(*ret_len); + *ret_buf = malloc(parser->buf_len); xine_fast_memcpy(*ret_buf, parser->buf, parser->buf_len); - *ret_slice_cnt = parser->slice_cnt; - parser->slice_cnt = 1; + *ret_pic = completed_pic; + parser->buf_len = 0; - /* this is a SLICE, keep it in the buffer */ + if (pts != 0 && (parser->pic->pts == 0 || parser->pic->pts != pts)) { + parser->pic->pts = pts; + } - if(parser->last_nal_res != 3) { + /** + * if the new coded picture started with a VCL nal + * we have to copy this to buffer for the next picture + * now. + */ + if(parser->last_nal_res == 1) { if(parser->nal_size_length > 0) { static const uint8_t start_seq[3] = { 0x00, 0x00, 0x01 }; xine_fast_memcpy(parser->buf, start_seq, 3); @@ -1370,7 +1709,7 @@ int parse_frame(struct nal_parser *parser, uint8_t *inbuf, int inbuf_len, */ if (parser->last_nal_res < 2) { if (parser->buf_len + next_nal+start_seq_len-offset > MAX_FRAME_SIZE) { - printf("buf underrun 1!!\n"); + fprintf(stderr, "h264_parser: buf underrun!\n"); parser->buf_len = 0; *ret_len = 0; *ret_buf = NULL; @@ -1395,6 +1734,10 @@ int parse_frame(struct nal_parser *parser, uint8_t *inbuf, int inbuf_len, } } + if (pts != 0 && (parser->pic->pts == 0 || parser->pic->pts != pts)) { + parser->pic->pts = pts; + } + *ret_buf = NULL; *ret_len = 0; return inbuf_len; @@ -1407,8 +1750,11 @@ int parse_frame(struct nal_parser *parser, uint8_t *inbuf, int inbuf_len, * 1: NAL is the beginning of a new coded picture * 3: NAL is marked as END_OF_SEQUENCE */ -int parse_nal(uint8_t *buf, int buf_len, struct nal_parser *parser) +int parse_nal(uint8_t *buf, int buf_len, struct h264_parser *parser, + struct coded_picture **completed_picture) { + int ret = 0; + struct buf_reader bufr; bufr.buf = buf; @@ -1416,137 +1762,166 @@ int parse_nal(uint8_t *buf, int buf_len, struct nal_parser *parser) bufr.cur_offset = 8; bufr.len = buf_len; - struct nal_unit *nal = parser->current_nal; - struct nal_unit *last_nal = parser->last_nal; - - int res = parse_nal_header(&bufr, parser); - if (res == NAL_SLICE_IDR) { - parser->is_idr = 1; - } + *completed_picture = NULL; - calculate_pic_order(parser); + struct nal_unit *nal = parse_nal_header(&bufr, parser->pic, parser); - if (res >= NAL_SLICE && res <= NAL_SLICE_IDR) { - // now detect if it's a new frame! - int ret = 0; - uint8_t reason = 0; - if (nal->slc->field_pic_flag == 1) - parser->field = nal->slc->bottom_field_flag; - else { - parser->have_top = 1; - parser->field = -1; + /** + * we detect the start of a new access unit if + * a non-vcl nal unit is received after a vcl + * nal unit + */ + if (nal->nal_unit_type >= NAL_SLICE && + nal->nal_unit_type <= NAL_SLICE_IDR) { + parser->position = VCL; + } else if ((parser->position == VCL && + nal->nal_unit_type >= NAL_SEI && + nal->nal_unit_type <= NAL_PPS) || + nal->nal_unit_type == NAL_AU_DELIMITER) { + /* start of a new access unit! */ + *completed_picture = parser->pic; + parser->pic = create_coded_picture(); + + if(parser->last_vcl_nal != NULL) { + release_nal_unit(parser->last_vcl_nal); + parser->last_vcl_nal = NULL; } + parser->position = NON_VCL; + } else { + parser->position = NON_VCL; + } - if (nal->slc->field_pic_flag == 1 && nal->slc->bottom_field_flag == 0) - parser->have_top = 1; + switch(nal->nal_unit_type) { + case NAL_SPS: + nal_buffer_append(parser->sps_buffer, nal); + break; + case NAL_PPS: + nal_buffer_append(parser->pps_buffer, nal); + break; + case NAL_SEI: { + if (parser->pic != NULL) { + if(parser->pic->sei_nal) { + release_nal_unit(parser->pic->sei_nal); + } + lock_nal_unit(nal); + parser->pic->sei_nal = nal; + interpret_sei(parser->pic); + } + } + default: + break; + } - parser->slice = 1; + /** + * in case of an access unit which does not contain any + * non-vcl nal units we have to detect the new access + * unit through the algorithm for detecting first vcl nal + * units of a primary coded picture + */ + if (parser->position == VCL && parser->last_vcl_nal != NULL && + nal->nal_unit_type >= NAL_SLICE && nal->nal_unit_type <= NAL_SLICE_IDR) { + /** + * frame boundary detection according to + * ITU-T Rec. H264 (11/2007) chapt 7.4.1.2.4, p65 + */ + struct nal_unit* last_nal = parser->last_vcl_nal; - if (nal->slc == NULL || last_nal->slc == NULL) { + if (nal == NULL || last_nal == NULL) { ret = 1; - reason++; - } - if (nal->slc && last_nal->slc && (nal->slc->frame_num - != last_nal->slc->frame_num)) { + } else if (nal->slc.frame_num != last_nal->slc.frame_num) { ret = 1; - reason++; - } - if (nal->slc && last_nal->slc && (nal->slc->pic_parameter_set_id - != last_nal->slc->pic_parameter_set_id)) { + } else if (nal->slc.pic_parameter_set_id + != last_nal->slc.pic_parameter_set_id) { ret = 1; - reason++; - } - if (nal->slc && last_nal->slc && (nal->slc->field_pic_flag - != last_nal->slc->field_pic_flag)) { + } else if (nal->slc.field_pic_flag + != last_nal->slc.field_pic_flag) { ret = 1; - reason++; - } - if (nal->slc && last_nal->slc && nal->slc->bottom_field_flag - != last_nal->slc->bottom_field_flag) { + } else if (nal->slc.bottom_field_flag + != last_nal->slc.bottom_field_flag) { ret = 1; - reason++; - } - if (nal->nal_ref_idc != last_nal->nal_ref_idc && (nal->nal_ref_idc == 0 - || last_nal->nal_ref_idc == 0)) { + } else if (nal->nal_ref_idc != last_nal->nal_ref_idc && + (nal->nal_ref_idc == 0 || last_nal->nal_ref_idc == 0)) { ret = 1; - reason++; - } - if (nal->sps && nal->slc && last_nal->slc && (nal->sps->pic_order_cnt_type - == 0 && last_nal->sps->pic_order_cnt_type == 0 - && (nal->slc->pic_order_cnt_lsb != last_nal->slc->pic_order_cnt_lsb - || nal->slc->delta_pic_order_cnt_bottom - != last_nal->slc->delta_pic_order_cnt_bottom))) { + } else if (nal->sps.pic_order_cnt_type == 0 + && last_nal->sps.pic_order_cnt_type == 0 + && (nal->slc.pic_order_cnt_lsb != last_nal->slc.pic_order_cnt_lsb + || nal->slc.delta_pic_order_cnt_bottom + != last_nal->slc.delta_pic_order_cnt_bottom)) { ret = 1; - reason++; - /*printf("C: Reason: %d, %d, %d\n", res, nal->slc->pic_order_cnt_lsb, - last_nal->slc->pic_order_cnt_lsb);*/ - } - if (nal->slc && last_nal->slc && (nal->sps->pic_order_cnt_type == 1 - && last_nal->sps->pic_order_cnt_type == 1 - && (nal->slc->delta_pic_order_cnt[0] - != last_nal->slc->delta_pic_order_cnt[0] - || nal->slc->delta_pic_order_cnt[1] - != last_nal->slc->delta_pic_order_cnt[1]))) { + } else if (nal->sps.pic_order_cnt_type == 1 + && last_nal->sps.pic_order_cnt_type == 1 + && (nal->slc.delta_pic_order_cnt[0] + != last_nal->slc.delta_pic_order_cnt[0] + || nal->slc.delta_pic_order_cnt[1] + != last_nal->slc.delta_pic_order_cnt[1])) { ret = 1; - reason++; - } - if (nal->nal_unit_type != last_nal->nal_unit_type && (nal->nal_unit_type - == 5 || last_nal->nal_unit_type == 5)) { + } else if (nal->nal_unit_type != last_nal->nal_unit_type && (nal->nal_unit_type + == NAL_SLICE_IDR || last_nal->nal_unit_type == NAL_SLICE_IDR)) { ret = 1; - reason++; - } - if (nal->slc && last_nal->slc && (nal->nal_unit_type == 5 - && last_nal->nal_unit_type == 5 && nal->slc->idr_pic_id - != last_nal->slc->idr_pic_id)) { + } else if (nal->nal_unit_type == NAL_SLICE_IDR + && last_nal->nal_unit_type == NAL_SLICE_IDR && nal->slc.idr_pic_id + != last_nal->slc.idr_pic_id) { ret = 1; - reason++; } - if (parser->current_nal == parser->nal0) { - parser->current_nal = parser->nal1; - parser->last_nal = parser->nal0; - } - else { - parser->current_nal = parser->nal0; - parser->last_nal = parser->nal1; + /* increase the slice_cnt until a new frame is detected */ + if (ret) { + *completed_picture = parser->pic; + parser->pic = create_coded_picture(); } - if(!parser->current_nal->sps && parser->last_nal->sps) { - parser->current_nal->sps = malloc(sizeof(struct seq_parameter_set_rbsp)); - xine_fast_memcpy(parser->current_nal->sps, parser->last_nal->sps, sizeof(struct seq_parameter_set_rbsp)); - } + } else if (nal->nal_unit_type == NAL_PPS || nal->nal_unit_type == NAL_SPS) { + ret = 2; + } else if (nal->nal_unit_type == NAL_AU_DELIMITER) { + ret = 2; + } else if (nal->nal_unit_type == NAL_END_OF_SEQUENCE) { + ret = 3; + } else if (nal->nal_unit_type >= NAL_SEI) { + ret = 2; + } - if(!parser->current_nal->pps && parser->last_nal->pps) { - parser->current_nal->pps = malloc(sizeof(struct pic_parameter_set_rbsp)); - xine_fast_memcpy(parser->current_nal->pps, parser->last_nal->pps, sizeof(struct pic_parameter_set_rbsp)); + if (parser->pic) { + + if (nal->nal_unit_type == NAL_SLICE_IDR) { + parser->pic->flag_mask |= IDR_PIC; } - /* increase the slice_cnt until a new frame is detected */ - if (!ret) - parser->slice_cnt++; - - return ret; - } else if (res == NAL_PPS || res == NAL_SPS) { - return 2; - } else if (res == NAL_END_OF_SEQUENCE) { - if (parser->current_nal == parser->nal0) { - parser->current_nal = parser->nal1; - parser->last_nal = parser->nal0; + if (nal->nal_ref_idc) { + parser->pic->flag_mask |= REFERENCE; } - else { - parser->current_nal = parser->nal0; - parser->last_nal = parser->nal1; + + if (nal->nal_unit_type >= NAL_SLICE && + nal->nal_unit_type <= NAL_SLICE_IDR) { + lock_nal_unit(nal); + if(parser->last_vcl_nal) { + release_nal_unit(parser->last_vcl_nal); + } + parser->last_vcl_nal = nal; + + parser->pic->slice_cnt++; + if(parser->pic->slc_nal) { + release_nal_unit(parser->pic->slc_nal); + } + lock_nal_unit(nal); + parser->pic->slc_nal = nal; + + interpret_slice_header(parser, nal); } - return 3; - } else if (res >= NAL_SEI) { - return 2; + if (*completed_picture != NULL && + (*completed_picture)->slice_cnt > 0) { + calculate_pic_order(parser, *completed_picture, + &((*completed_picture)->slc_nal->slc)); + interpret_sps(*completed_picture, parser); + interpret_pps(*completed_picture); + } } - return 0; + release_nal_unit(nal); + return ret; } -int seek_for_nal(uint8_t *buf, int buf_len, struct nal_parser *parser) +int seek_for_nal(uint8_t *buf, int buf_len, struct h264_parser *parser) { if(buf_len <= 0) return -1; diff --git a/src/video_dec/libvdpau/h264_parser.h b/src/video_dec/libvdpau/h264_parser.h index 4eeea3ae7..e6ed91802 100644 --- a/src/video_dec/libvdpau/h264_parser.h +++ b/src/video_dec/libvdpau/h264_parser.h @@ -31,7 +31,21 @@ #define MAX_FRAME_SIZE 1024*1024 -struct nal_parser { +/* specifies wether the parser last parsed + * non-vcl or vcl nal units. depending on + * this the access unit boundaries are detected + */ +enum parser_position { + NON_VCL, + VCL +}; + +enum parser_flags { + CPB_DPB_DELAYS_PRESENT = 0x01, + PIC_STRUCT_PRESENT = 0x02 +}; + +struct h264_parser { uint8_t buf[MAX_FRAME_SIZE]; uint32_t buf_len; @@ -40,59 +54,54 @@ struct nal_parser { uint8_t prebuf[MAX_FRAME_SIZE]; uint32_t prebuf_len; uint32_t next_nal_position; - uint8_t incomplete_nal; - uint8_t found_sps; - uint8_t found_pps; uint8_t last_nal_res; - uint8_t is_idr; - - int field; /* 0=top, 1=bottom, -1=both */ - int slice; - int slice_cnt; - - uint8_t have_top; - uint8_t have_frame; - uint8_t nal_size_length; uint32_t next_nal_size; uint8_t *nal_size_length_buf; uint8_t have_nal_size_length_buf; - struct nal_unit *nal0; - struct nal_unit *nal1; - struct nal_unit *current_nal; - struct nal_unit *last_nal; + enum parser_position position; + + struct coded_picture *pic; - uint8_t cpb_dpb_delays_present_flag; + struct nal_unit *last_vcl_nal; + struct nal_buffer *sps_buffer; + struct nal_buffer *pps_buffer; - uint32_t pic_order_cnt_lsb; - uint32_t pic_order_cnt_msb; uint32_t prev_pic_order_cnt_lsb; uint32_t prev_pic_order_cnt_msb; uint32_t frame_num_offset; + int32_t prev_top_field_order_cnt; + + uint32_t curr_pic_num; + + uint16_t flag_mask; + /* this is dpb used for reference frame * heading to vdpau + unordered frames */ struct dpb dpb; }; -int parse_nal(uint8_t *buf, int buf_len, struct nal_parser *parser); +int parse_nal(uint8_t *buf, int buf_len, struct h264_parser *parser, + struct coded_picture **completed_picture); -int seek_for_nal(uint8_t *buf, int buf_len, struct nal_parser *parser); +int seek_for_nal(uint8_t *buf, int buf_len, struct h264_parser *parser); -struct nal_parser* init_parser(); -void free_parser(struct nal_parser *parser); -int parse_frame(struct nal_parser *parser, uint8_t *inbuf, int inbuf_len, - uint8_t **ret_buf, uint32_t *ret_len, uint32_t *ret_slice_cnt); +struct h264_parser* init_parser(); +void free_parser(struct h264_parser *parser); +int parse_frame(struct h264_parser *parser, uint8_t *inbuf, int inbuf_len, + int64_t pts, + uint8_t **ret_buf, uint32_t *ret_len, struct coded_picture **ret_pic); /* this has to be called after decoding the frame delivered by parse_frame, * but before adding a decoded frame to the dpb. */ -void process_mmc_operations(struct nal_parser *parser); +void process_mmc_operations(struct h264_parser *parser, struct coded_picture *picture); -void parse_codec_private(struct nal_parser *parser, uint8_t *inbuf, int inbuf_len); +void parse_codec_private(struct h264_parser *parser, uint8_t *inbuf, int inbuf_len); #endif diff --git a/src/video_dec/libvdpau/nal.c b/src/video_dec/libvdpau/nal.c index b81c8fe1d..07c672e33 100644 --- a/src/video_dec/libvdpau/nal.c +++ b/src/video_dec/libvdpau/nal.c @@ -27,49 +27,183 @@ #include "nal.h" #include -struct nal_unit* init_nal_unit() +struct nal_buffer* create_nal_buffer(uint8_t max_size) { - struct nal_unit *nal = calloc(1, sizeof(struct nal_unit)); + struct nal_buffer *nal_buffer = calloc(1, sizeof(struct nal_buffer)); + nal_buffer->max_size = max_size; + + return nal_buffer; +} + +/** + * destroys a nal buffer. all referenced nals are released + */ +void free_nal_buffer(struct nal_buffer *nal_buffer) +{ + struct nal_unit *nal = nal_buffer->first; + + do { + struct nal_unit *delete = nal; + nal = nal->next; + release_nal_unit(delete); + } while(nal != NULL); + + free(nal_buffer); +} + +/** + * appends a nal unit to the end of the buffer + */ +void nal_buffer_append(struct nal_buffer *nal_buffer, struct nal_unit *nal) +{ + if(nal_buffer->used == nal_buffer->max_size) { + nal_buffer_remove(nal_buffer, nal_buffer->first); + } + + if (nal_buffer->first == NULL) { + nal_buffer->first = nal_buffer->last = nal; + nal->prev = nal->next = NULL; + + lock_nal_unit(nal); + nal_buffer->used++; + } else if (nal_buffer->last != NULL) { + nal_buffer->last->next = nal; + nal->prev = nal_buffer->last; + nal_buffer->last = nal; - /*nal->sps = calloc(1, sizeof(struct seq_parameter_set_rbsp)); - nal->pps = calloc(1, sizeof(struct pic_parameter_set_rbsp)); - nal->slc = calloc(1, sizeof(struct slice_header));*/ + lock_nal_unit(nal); + nal_buffer->used++; + } else { + printf("ERR: nal_buffer is in a broken state\n"); + } +} + +void nal_buffer_remove(struct nal_buffer *nal_buffer, struct nal_unit *nal) +{ + if (nal == nal_buffer->first && nal == nal_buffer->last) { + nal_buffer->first = nal_buffer->last = NULL; + } else { + if (nal == nal_buffer->first) { + nal_buffer->first = nal->next; + nal_buffer->first->prev = NULL; + } else { + nal->prev->next = nal->next; + } + + if (nal == nal_buffer->last) { + nal_buffer->last = nal->prev; + nal_buffer->last->next = NULL; + } else { + nal->next->prev = nal->prev; + } + } + + nal->next = nal->prev = NULL; + release_nal_unit(nal); + + nal_buffer->used--; +} + +void nal_buffer_flush(struct nal_buffer *nal_buffer) +{ + while(nal_buffer->used > 0) { + nal_buffer_remove(nal_buffer, nal_buffer->first); + } +} + +/** + * returns the last element in the buffer + */ +struct nal_unit *nal_buffer_get_last(struct nal_buffer *nal_buffer) +{ + return nal_buffer->last; +} + +/** + * get a nal unit from a nal_buffer from it's + * seq parameter_set_id + */ +struct nal_unit* nal_buffer_get_by_sps_id(struct nal_buffer *nal_buffer, + uint32_t seq_parameter_set_id) +{ + struct nal_unit *nal = nal_buffer->last; + + if (nal != NULL) { + do { + if(nal->nal_unit_type == NAL_SPS) { + if(nal->sps.seq_parameter_set_id == seq_parameter_set_id) { + return nal; + } + } + + nal = nal->prev; + } while(nal != NULL); + } + + return NULL; +} + +/** + * get a nal unit from a nal_buffer from it's + * pic parameter_set_id + */ +struct nal_unit* nal_buffer_get_by_pps_id(struct nal_buffer *nal_buffer, + uint32_t pic_parameter_set_id) +{ + struct nal_unit *nal = nal_buffer->last; + + if (nal != NULL) { + do { + if(nal->nal_unit_type == NAL_PPS) { + if(nal->pps.pic_parameter_set_id == pic_parameter_set_id) { + return nal; + } + } + + nal = nal->prev; + } while(nal != NULL); + } + + return NULL; +} + +/** + * create a new nal unit, with a lock_counter of 1 + */ +struct nal_unit* create_nal_unit() +{ + struct nal_unit *nal = calloc(1, sizeof(struct nal_unit)); + nal->lock_counter = 1; return nal; } -void free_nal_unit(struct nal_unit *nal) +void lock_nal_unit(struct nal_unit *nal) +{ + nal->lock_counter++; +} + +void release_nal_unit(struct nal_unit *nal) { if(!nal) return; - free(nal->sps); - free(nal->pps); - free(nal->slc); - free(nal); + nal->lock_counter--; + + if(nal->lock_counter <= 0) { + free(nal); + } } +/** + * creates a copy of a nal unit with a single lock + */ void copy_nal_unit(struct nal_unit *dest, struct nal_unit *src) { /* size without pps, sps and slc units: */ - int size = sizeof(struct nal_unit) - sizeof(struct seq_parameter_set_rbsp*) - - sizeof(struct pic_parameter_set_rbsp*) - sizeof(struct slice_header*); + int size = sizeof(struct nal_unit); xine_fast_memcpy(dest, src, size); - - if(!dest->sps) - dest->sps = calloc(1, sizeof(struct seq_parameter_set_rbsp)); - - if(!dest->pps) - dest->pps = calloc(1, sizeof(struct pic_parameter_set_rbsp)); - - if(!dest->slc) - dest->slc = calloc(1, sizeof(struct slice_header)); - - if(src->sps) - xine_fast_memcpy(dest->sps, src->sps, sizeof(struct seq_parameter_set_rbsp)); - if(src->pps) - xine_fast_memcpy(dest->pps, src->pps, sizeof(struct pic_parameter_set_rbsp)); - if(src->slc) - xine_fast_memcpy(dest->slc, src->slc, sizeof(struct slice_header)); + dest->lock_counter = 1; + dest->prev = dest->next = NULL; } diff --git a/src/video_dec/libvdpau/nal.h b/src/video_dec/libvdpau/nal.h index 4e039b8b8..500efa495 100644 --- a/src/video_dec/libvdpau/nal.h +++ b/src/video_dec/libvdpau/nal.h @@ -118,6 +118,7 @@ static inline uint32_t slice_type(uint32_t slice_type) return (slice_type < 10 ? slice_type % 5 : slice_type); } +#if 0 static inline void print_slice_type(uint32_t slice_type) { switch(slice_type) { @@ -140,6 +141,7 @@ static inline void print_slice_type(uint32_t slice_type) printf("Unknown SLICE\n"); } } +#endif struct hrd_parameters { @@ -178,6 +180,7 @@ struct seq_parameter_set_rbsp /* endif */ uint32_t log2_max_frame_num_minus4; + uint32_t max_frame_num; uint32_t pic_order_cnt_type; // if pic_order_cnt_type==0 uint32_t log2_max_pic_order_cnt_lsb_minus4; @@ -341,7 +344,19 @@ struct sei_message uint8_t dpb_output_delay; uint8_t pic_struct; - //uint8_t clock_timestamp_flag[3]; + uint8_t ct_type : 1; + uint8_t nuit_field_based_flag : 1; + uint8_t counting_type : 5; + uint8_t full_timestamp_flag : 1; + uint8_t discontinuity_flag : 1; + uint8_t cnt_dropped_flag : 1; + uint8_t n_frames; + + uint8_t seconds_value : 6; + uint8_t minutes_value : 6; + uint8_t hours_value : 5; + + int32_t time_offset; } pic_timing; }; @@ -435,32 +450,46 @@ struct slice_header uint32_t dec_ref_pic_marking_count; }; -struct nal_unit -{ - uint8_t nal_ref_idc; // 0x03 - uint8_t nal_unit_type; // 0x1f +struct nal_unit { + uint8_t nal_ref_idc; // 0x03 + enum nal_unit_types nal_unit_type; // 0x1f - uint32_t max_pic_num; - uint32_t curr_pic_num; - uint8_t used_for_long_term_ref; - uint32_t long_term_pic_num; - uint32_t long_term_frame_idx; + //union { + struct sei_message sei; + struct seq_parameter_set_rbsp sps; + struct pic_parameter_set_rbsp pps; + struct slice_header slc; + //}; - int32_t top_field_order_cnt; - int32_t bottom_field_order_cnt; + struct nal_unit *prev; + struct nal_unit *next; - uint8_t interlaced; - uint8_t repeat_pic; + uint32_t lock_counter; +}; - struct sei_message sei; +struct nal_buffer { + struct nal_unit *first; + struct nal_unit *last; - struct seq_parameter_set_rbsp *sps; - struct pic_parameter_set_rbsp *pps; - struct slice_header *slc; + uint8_t max_size; + uint8_t used; }; -struct nal_unit* init_nal_unit(); -void free_nal_unit(struct nal_unit *nal); +struct nal_buffer* create_nal_buffer(uint8_t max_size); +void free_nal_buffer(struct nal_buffer *nal_buffer); +void nal_buffer_append(struct nal_buffer *nal_buffer, struct nal_unit *nal); +void nal_buffer_remove(struct nal_buffer *nal_buffer, struct nal_unit *nal); +void nal_buffer_flush(struct nal_buffer *nal_buffer); + +struct nal_unit* nal_buffer_get_by_sps_id(struct nal_buffer *nal_buffer, + uint32_t seq_parameter_set_id); +struct nal_unit* nal_buffer_get_by_pps_id(struct nal_buffer *nal_buffer, + uint32_t pic_parameter_set_id); +struct nal_unit* nal_buffer_get_last(struct nal_buffer *nal_buffer); + +struct nal_unit* create_nal_unit(); +void lock_nal_unit(struct nal_unit *nal); +void release_nal_unit(struct nal_unit *nal); void copy_nal_unit(struct nal_unit *dest, struct nal_unit *src); #endif /* NAL_H_ */ diff --git a/src/video_dec/libvdpau/vdpau_h264.c b/src/video_dec/libvdpau/vdpau_h264.c index 2f675dfbb..c9ef68ebf 100644 --- a/src/video_dec/libvdpau/vdpau_h264.c +++ b/src/video_dec/libvdpau/vdpau_h264.c @@ -35,6 +35,9 @@ #include "accel_vdpau.h" #include "h264_parser.h" #include "dpb.h" +#include "cpb.h" + +//#define DEBUG_H264 #define VIDEOBUFSIZE 128*1024 @@ -56,7 +59,7 @@ typedef struct vdpau_h264_decoder_s { double ratio; /* the width to height ratio */ - struct nal_parser *nal_parser; /* h264 nal parser. extracts stream data for vdpau */ + struct h264_parser *nal_parser; /* h264 nal parser. extracts stream data for vdpau */ uint8_t wait_for_bottom_field; struct decoded_picture *last_ref_pic; uint32_t last_top_field_order_cnt; @@ -73,9 +76,7 @@ typedef struct vdpau_h264_decoder_s { xine_t *xine; - int64_t curr_pts; - int64_t next_pts; - + struct coded_picture *completed_pic; vo_frame_t *last_img; vo_frame_t *dangling_img; @@ -97,7 +98,7 @@ static void vdpau_h264_flush (video_decoder_t *this_gen); * xine video plugin functions *************************************************************************/ - +#ifdef DEBUG_H264 static inline void dump_pictureinfo_h264(VdpPictureInfoH264 *pic) { printf("C: slice_count: %d\n", pic->slice_count); @@ -168,14 +169,15 @@ static inline void dump_pictureinfo_h264(VdpPictureInfoH264 *pic) memcpy(pic.referenceFrames, this->reference_frames, sizeof(this->reference_frames));*/ } +#endif static void set_ratio(video_decoder_t *this_gen) { vdpau_h264_decoder_t *this = (vdpau_h264_decoder_t *)this_gen; this->ratio = (double)this->width / (double)this->height; - if(this->nal_parser->current_nal->sps->vui_parameters.aspect_ration_info_present_flag) { - switch(this->nal_parser->current_nal->sps->vui_parameters.aspect_ratio_idc) { + if(this->completed_pic->sps_nal->sps.vui_parameters.aspect_ration_info_present_flag) { + switch(this->completed_pic->sps_nal->sps.vui_parameters.aspect_ratio_idc) { case ASPECT_1_1: this->ratio = 1 * this->ratio; break; @@ -226,8 +228,8 @@ static void set_ratio(video_decoder_t *this_gen) break; case ASPECT_EXTENDED_SAR: this->ratio *= - (double)this->nal_parser->current_nal->sps->vui_parameters.sar_width/ - (double)this->nal_parser->current_nal->sps->vui_parameters.sar_height; + (double)this->completed_pic->sps_nal->sps.vui_parameters.sar_width/ + (double)this->completed_pic->sps_nal->sps.vui_parameters.sar_height; break; } } @@ -237,15 +239,15 @@ static void fill_vdpau_pictureinfo_h264(video_decoder_t *this_gen, uint32_t slic { vdpau_h264_decoder_t *this = (vdpau_h264_decoder_t *)this_gen; - struct pic_parameter_set_rbsp *pps = this->nal_parser->current_nal->pps; - struct seq_parameter_set_rbsp *sps = this->nal_parser->current_nal->sps; - struct slice_header *slc = this->nal_parser->current_nal->slc; + struct pic_parameter_set_rbsp *pps = &this->completed_pic->pps_nal->pps; + struct seq_parameter_set_rbsp *sps = &this->completed_pic->sps_nal->sps; + struct slice_header *slc = &this->completed_pic->slc_nal->slc; pic->slice_count = slice_count; - pic->field_order_cnt[0] = this->nal_parser->current_nal->top_field_order_cnt; - pic->field_order_cnt[1] = this->nal_parser->current_nal->bottom_field_order_cnt; + pic->field_order_cnt[0] = this->completed_pic->top_field_order_cnt; + pic->field_order_cnt[1] = this->completed_pic->bottom_field_order_cnt; pic->is_reference = - (this->nal_parser->current_nal->nal_ref_idc != 0) ? VDP_TRUE : VDP_FALSE; + (this->completed_pic->flag_mask & REFERENCE) ? VDP_TRUE : VDP_FALSE; pic->frame_num = slc->frame_num; pic->field_pic_flag = slc->field_pic_flag; pic->bottom_field_flag = slc->bottom_field_flag; @@ -286,12 +288,9 @@ static int vdpau_decoder_init(video_decoder_t *this_gen) vdpau_h264_decoder_t *this = (vdpau_h264_decoder_t *)this_gen; vo_frame_t *img; - this->curr_pts = this->next_pts; - this->next_pts = 0; - if(this->width == 0) { - this->width = this->nal_parser->current_nal->sps->pic_width; - this->height = this->nal_parser->current_nal->sps->pic_height; + this->width = this->completed_pic->sps_nal->sps.pic_width; + this->height = this->completed_pic->sps_nal->sps.pic_height; } set_ratio(this_gen); @@ -312,7 +311,7 @@ static int vdpau_decoder_init(video_decoder_t *this_gen) data.aspect = this->ratio; xine_event_send( this->stream, &event ); - switch(this->nal_parser->current_nal->sps->profile_idc) { + switch(this->completed_pic->sps_nal->sps.profile_idc) { case 100: this->profile = VDP_DECODER_PROFILE_H264_HIGH; break; @@ -330,8 +329,8 @@ static int vdpau_decoder_init(video_decoder_t *this_gen) // Level 4.1 limits: int ref_frames = 0; - if(this->nal_parser->current_nal->sps->num_ref_frames) { - ref_frames = this->nal_parser->current_nal->sps->num_ref_frames; + if(this->completed_pic->sps_nal->sps.num_ref_frames) { + ref_frames = this->completed_pic->sps_nal->sps.num_ref_frames; } else { uint32_t round_width = (this->width + 15) & ~15; uint32_t round_height = (this->height + 15) & ~15; @@ -343,7 +342,8 @@ static int vdpau_decoder_init(video_decoder_t *this_gen) ref_frames = 16; } - printf("Allocate %d reference frames\n", ref_frames); + xprintf(this->xine, XINE_VERBOSITY_LOG, "Allocate %d reference frames\n", + ref_frames); /* get the vdpau context from vo */ //(this->stream->video_out->open) (this->stream->video_out, this->stream); img = this->stream->video_out->get_frame (this->stream->video_out, @@ -352,10 +352,11 @@ static int vdpau_decoder_init(video_decoder_t *this_gen) XINE_IMGFMT_VDPAU, VO_BOTH_FIELDS); img->duration = this->video_step; - img->pts = this->curr_pts; + img->pts = this->completed_pic->pts; if (this->dangling_img) { - fprintf(stderr, "broken stream: current img wasn't processed -- freeing it\n!"); + xprintf(this->xine, XINE_VERBOSITY_LOG, + "broken stream: current img wasn't processed -- freeing it\n!"); this->dangling_img->free(this->dangling_img); } this->dangling_img = img; @@ -386,23 +387,24 @@ static int vdpau_decoder_render(video_decoder_t *this_gen, VdpBitstreamBuffer *v vdpau_h264_decoder_t *this = (vdpau_h264_decoder_t *)this_gen; vo_frame_t *img = this->last_img; - if(this->nal_parser->current_nal->nal_unit_type == NAL_SLICE_IDR) { + // 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)); + this->last_ref_pic = NULL; } VdpPictureInfoH264 pic; fill_vdpau_pictureinfo_h264(this_gen, slice_count, &pic); - //printf("next decode: %d, %d\n", pic.field_order_cnt[0], pic.field_order_cnt[1]); - if(!this->decoder_started && !pic.is_reference) return 0; this->decoder_started = 1; - struct seq_parameter_set_rbsp *sps = this->nal_parser->current_nal->sps; - struct slice_header *slc = this->nal_parser->current_nal->slc; + struct seq_parameter_set_rbsp *sps = &this->completed_pic->sps_nal->sps; + struct slice_header *slc = &this->completed_pic->slc_nal->slc; if(sps->vui_parameters_present_flag && sps->vui_parameters.timing_info_present_flag && @@ -410,28 +412,26 @@ static int vdpau_decoder_render(video_decoder_t *this_gen, VdpBitstreamBuffer *v this->video_step = 2*90000/(1/((double)sps->vui_parameters.num_units_in_tick/(double)sps->vui_parameters.time_scale)); } - /* flush the DPB if this frame was an IDR */ - //printf("is_idr: %d\n", this->nal_parser->is_idr); - this->nal_parser->is_idr = 0; - /* go and decode a frame */ +#ifdef DEBUG_H264 + dump_pictureinfo_h264(&pic); - //dump_pictureinfo_h264(&pic); - - /*int i; - printf("Decode data: \n"); + int i; + printf("E: Bytes used: %d\n", vdp_buffer->bitstream_bytes); + printf("E: Decode data: \nE:"); for(i = 0; i < ((vdp_buffer->bitstream_bytes < 20) ? vdp_buffer->bitstream_bytes : 20); i++) { printf("%02x ", ((uint8_t*)vdp_buffer->bitstream)[i]); if((i+1) % 10 == 0) - printf("\n"); + printf("\nE:"); } printf("\n...\n"); for(i = vdp_buffer->bitstream_bytes - 20; i < vdp_buffer->bitstream_bytes; i++) { printf("%02x ", ((uint8_t*)vdp_buffer->bitstream)[i]); if((i+1) % 10 == 0) - printf("\n"); - }*/ - + printf("\nE:"); + } + printf("\nE: ---------------------------------------------------------------\n"); +#endif if(img == NULL) { img = this->stream->video_out->get_frame (this->stream->video_out, @@ -441,17 +441,23 @@ static int vdpau_decoder_render(video_decoder_t *this_gen, VdpBitstreamBuffer *v this->vdpau_accel = (vdpau_accel_t*)img->accel_data; img->duration = this->video_step; - img->pts = this->curr_pts; + img->pts = this->completed_pic->pts; if (this->dangling_img) { - fprintf(stderr, "broken stream: current img wasn't processed -- freeing it\n!"); + xprintf(this->xine, XINE_VERBOSITY_LOG, + "broken stream: current img wasn't processed -- freeing it\n!"); this->dangling_img->free(this->dangling_img); } this->dangling_img = img; + } else { + if (img->pts == 0) { + img->pts = this->completed_pic->pts; + } } if(this->vdp_runtime_nr != *(this->vdpau_accel->current_vdp_runtime_nr)) { - printf("VDPAU was preempted. Reinitialise the decoder.\n"); + xprintf(this->xine, XINE_VERBOSITY_LOG, + "VDPAU was preempted. Reinitialise the decoder.\n"); this->decoder = VDP_INVALID_HANDLE; vdpau_h264_reset(this_gen); this->vdp_runtime_nr = this->vdpau_accel->vdp_runtime_nr; @@ -460,20 +466,17 @@ static int vdpau_decoder_render(video_decoder_t *this_gen, VdpBitstreamBuffer *v VdpVideoSurface surface = this->vdpau_accel->surface; - //printf("Decode: NUM: %d, REF: %d, BYTES: %d, PTS: %lld\n", pic.frame_num, pic.is_reference, vdp_buffer->bitstream_bytes, this->curr_pts); + //xprintf(this->xine, XINE_VERBOSITY_DEBUG, + // "Decode: NUM: %d, REF: %d, BYTES: %d, PTS: %lld\n", pic.frame_num, pic.is_reference, vdp_buffer->bitstream_bytes, this->completed_pic->pts); VdpStatus status = this->vdpau_accel->vdp_decoder_render(this->decoder, surface, (VdpPictureInfo*)&pic, 1, vdp_buffer); - /* only free the actual data, as the start seq is only - * locally allocated anyway. */ + /* free the image data */ if(((uint8_t*)vdp_buffer->bitstream) != NULL) { free((uint8_t*)vdp_buffer->bitstream); } - this->curr_pts = this->next_pts; - this->next_pts = 0; - - process_mmc_operations(this->nal_parser); + process_mmc_operations(this->nal_parser, this->completed_pic); if(status != VDP_STATUS_OK) { @@ -481,19 +484,21 @@ static int vdpau_decoder_render(video_decoder_t *this_gen, VdpBitstreamBuffer *v if (this->dangling_img) this->dangling_img->free(this->dangling_img); img = this->last_img = this->dangling_img = NULL; + free_coded_picture(this->completed_pic); + this->completed_pic = NULL; } else { img->bad_frame = 0; - if((sps->vui_parameters_present_flag && + img->progressive_frame = 0; + + if(/*(sps->vui_parameters_present_flag && sps->vui_parameters.pic_struct_present_flag && - !this->nal_parser->current_nal->interlaced) || + !(this->completed_pic->flag_mask & INTERLACED)) ||*/ (!pic.field_pic_flag && !pic.mb_adaptive_frame_field_flag)) img->progressive_frame = 1; - else - img->progressive_frame = 0; - if(!img->progressive_frame && this->nal_parser->current_nal->repeat_pic) + if(!img->progressive_frame && this->completed_pic->repeat_pic) img->repeat_first_field = 1; //else if(img->progressive_frame && this->nal_parser->current_nal->repeat_pic) // img->duration *= this->nal_parser->current_nal->repeat_pic; @@ -517,7 +522,8 @@ static int vdpau_decoder_render(video_decoder_t *this_gen, VdpBitstreamBuffer *v struct decoded_picture *decoded_pic = NULL; if(pic.is_reference) { if(!slc->field_pic_flag || !this->wait_for_bottom_field) { - decoded_pic = init_decoded_picture(this->nal_parser->current_nal, surface, img); + decoded_pic = init_decoded_picture(this->completed_pic, surface, img); + this->completed_pic = NULL; this->last_ref_pic = decoded_pic; decoded_pic->used_for_reference = 1; dpb_add_picture(&(this->nal_parser->dpb), decoded_pic, sps->num_ref_frames); @@ -526,8 +532,9 @@ static int vdpau_decoder_render(video_decoder_t *this_gen, VdpBitstreamBuffer *v if(this->last_ref_pic) { decoded_pic = this->last_ref_pic; //copy_nal_unit(decoded_pic->nal, this->nal_parser->current_nal); - decoded_pic->nal->bottom_field_order_cnt = this->nal_parser->current_nal->bottom_field_order_cnt; - this->last_ref_pic->bottom_is_reference = 1; + + dpb_add_coded_picture(this->last_ref_pic, this->completed_pic); + this->completed_pic = NULL; } } } @@ -536,26 +543,21 @@ static int vdpau_decoder_render(video_decoder_t *this_gen, VdpBitstreamBuffer *v (slc->field_pic_flag && slc->bottom_field_flag && this->wait_for_bottom_field)) { if(!decoded_pic) { - decoded_pic = init_decoded_picture(this->nal_parser->current_nal, surface, img); + decoded_pic = init_decoded_picture(this->completed_pic, surface, img); + this->completed_pic = NULL; //decoded_pic->nal->top_field_order_cnt = this->last_top_field_order_cnt; dpb_add_picture(&(this->nal_parser->dpb), decoded_pic, sps->num_ref_frames); this->dangling_img = NULL; - - if(decoded_pic->nal->slc->bottom_field_flag) - decoded_pic->nal->top_field_order_cnt = this->last_top_field_order_cnt; } decoded_pic->delayed_output = 1; - if(this->wait_for_bottom_field && slc->bottom_field_flag) - decoded_pic->nal->bottom_field_order_cnt = this->nal_parser->current_nal->bottom_field_order_cnt; - 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) { - decoded_pic->img->top_field_first = (decoded_pic->nal->top_field_order_cnt <= decoded_pic->nal->bottom_field_order_cnt); - //printf("draw pts: %lld\n", decoded_pic->img->pts); + + 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); } @@ -564,7 +566,7 @@ static int vdpau_decoder_render(video_decoder_t *this_gen, VdpBitstreamBuffer *v } else if(slc->field_pic_flag && !slc->bottom_field_flag) { // don't draw yet, second field is missing. - this->last_top_field_order_cnt = this->nal_parser->current_nal->top_field_order_cnt; + //this->last_top_field_order_cnt = this->nal_parser->completed_pic->top_field_order_cnt; this->wait_for_bottom_field = 1; this->last_img = img; } @@ -627,33 +629,36 @@ static void vdpau_h264_decode_data (video_decoder_t *this_gen, parse_codec_private(this->nal_parser, codec_private, codec_private_len); } } else if (buf->decoder_info[1] == BUF_SPECIAL_PALETTE) { - printf("SPECIAL PALETTE is not yet handled\n"); + xprintf(this->xine, XINE_VERBOSITY_LOG, + "SPECIAL PALETTE is not yet handled\n"); } else - printf("UNKNOWN SPECIAL HEADER\n"); + xprintf(this->xine, XINE_VERBOSITY_LOG, + "UNKNOWN SPECIAL HEADER\n"); } else { /* parse the first nal packages to retrieve profile type */ int len = 0; - uint32_t slice_count; while(len < buf->size && !(this->wait_for_frame_start && !(buf->decoder_flags & BUF_FLAG_FRAME_START))) { this->wait_for_frame_start = 0; len += parse_frame(this->nal_parser, buf->content + len, buf->size - len, - (uint8_t*)&vdp_buffer.bitstream, &vdp_buffer.bitstream_bytes, &slice_count); + buf->pts, + (uint8_t*)&vdp_buffer.bitstream, &vdp_buffer.bitstream_bytes, &this->completed_pic); if(this->decoder == VDP_INVALID_HANDLE && - this->nal_parser->current_nal->sps != NULL && - this->nal_parser->current_nal->sps->pic_width > 0 && - this->nal_parser->current_nal->sps->pic_height > 0) { + this->completed_pic && + this->completed_pic->sps_nal != NULL && + this->completed_pic->sps_nal->sps.pic_width > 0 && + this->completed_pic->sps_nal->sps.pic_height > 0) { vdpau_decoder_init(this_gen); } if(this->decoder != VDP_INVALID_HANDLE && vdp_buffer.bitstream_bytes > 0 && - this->nal_parser->current_nal->slc != NULL && - this->nal_parser->current_nal->pps != NULL) { - vdpau_decoder_render(this_gen, &vdp_buffer, slice_count); + this->completed_pic->slc_nal != NULL && + this->completed_pic->pps_nal != NULL) { + vdpau_decoder_render(this_gen, &vdp_buffer, this->completed_pic->slice_cnt); } /* in case the last nal was detected as END_OF_SEQUENCE @@ -662,11 +667,6 @@ static void vdpau_h264_decode_data (video_decoder_t *this_gen, if(this->nal_parser->last_nal_res == 3) vdpau_h264_flush(this_gen); } - - if(buf->pts != 0 && buf->pts != this->next_pts) { - //printf("next pts: %lld\n", buf->pts); - this->next_pts = buf->pts; - } } if(buf->decoder_flags & BUF_FLAG_FRAME_END) @@ -681,11 +681,13 @@ static void vdpau_h264_flush (video_decoder_t *this_gen) { struct decoded_picture *decoded_pic = NULL; while ((decoded_pic = dpb_get_next_out_picture(&(this->nal_parser->dpb), 1)) != NULL) { - decoded_pic->img->top_field_first = (decoded_pic->nal->top_field_order_cnt <= decoded_pic->nal->bottom_field_order_cnt); - printf("FLUSH draw pts: %lld\n", decoded_pic->img->pts); + decoded_pic->img->top_field_first = dp_top_field_first(decoded_pic); + xprintf(this->xine, XINE_VERBOSITY_DEBUG, + "h264 flush, draw pts: %lld\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_free_all(&this->nal_parser->dpb); } /* @@ -694,8 +696,6 @@ 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; - printf("vdpau_h264_reset\n"); - dpb_free_all( &(this->nal_parser->dpb) ); if (this->decoder != VDP_INVALID_HANDLE) { @@ -708,8 +708,6 @@ static void vdpau_h264_reset (video_decoder_t *this_gen) { this->color_standard = VDP_COLOR_STANDARD_ITUR_BT_601; this->wait_for_bottom_field = 0; this->video_step = 0; - this->curr_pts = 0; - this->next_pts = 0; this->nal_parser = init_parser(); if(this->codec_private_len > 0) { @@ -736,8 +734,6 @@ 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; - this->curr_pts = 0; - this->next_pts = 0; dpb_clear_all_pts(&this->nal_parser->dpb); } @@ -787,7 +783,7 @@ static video_decoder_t *open_plugin (video_decoder_class_t *class_gen, xine_stre VdpStatus st = accel->vdp_decoder_create( accel->vdp_device, VDP_DECODER_PROFILE_H264_MAIN, 1920, 1080, 16, &decoder ); if ( st!=VDP_STATUS_OK ) { lprintf( "can't create vdpau decoder.\n" ); - return 1; + return NULL; } accel->vdp_decoder_destroy( decoder ); @@ -864,6 +860,6 @@ static const decoder_info_t dec_info_video = { */ const plugin_info_t xine_plugin_info[] EXPORTED = { /* { type, API, "name", version, special_info, init_function } */ - { PLUGIN_VIDEO_DECODER, 19, "vdpau_h264", XINE_VERSION_CODE, &dec_info_video, init_plugin }, + { PLUGIN_VIDEO_DECODER | PLUGIN_MUST_PRELOAD, 19, "vdpau_h264", XINE_VERSION_CODE, &dec_info_video, init_plugin }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; -- cgit v1.2.3