mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-28 20:53:54 +02:00
H.264: decode arbitrary frame orders and allow B-frames as references.
Originally committed as revision 4003 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
2f1e1ed3dd
commit
2f944356bf
@ -274,6 +274,7 @@ typedef struct H264Context{
|
||||
|
||||
int direct_spatial_mv_pred;
|
||||
int dist_scale_factor[16];
|
||||
int map_col_to_list0[2][16];
|
||||
|
||||
/**
|
||||
* num_ref_idx_l0/1_active_minus1 + 1
|
||||
@ -285,6 +286,7 @@ typedef struct H264Context{
|
||||
Picture ref_list[2][32]; //FIXME size?
|
||||
Picture field_ref_list[2][32]; //FIXME size?
|
||||
Picture *delayed_pic[16]; //FIXME size?
|
||||
int delayed_output_poc;
|
||||
|
||||
/**
|
||||
* memory management control operations buffer.
|
||||
@ -1060,6 +1062,34 @@ static inline void direct_dist_scale_factor(H264Context * const h){
|
||||
}
|
||||
}
|
||||
}
|
||||
static inline void direct_ref_list_init(H264Context * const h){
|
||||
MpegEncContext * const s = &h->s;
|
||||
Picture * const ref1 = &h->ref_list[1][0];
|
||||
Picture * const cur = s->current_picture_ptr;
|
||||
int list, i, j;
|
||||
if(cur->pict_type == I_TYPE)
|
||||
cur->ref_count[0] = 0;
|
||||
if(cur->pict_type != B_TYPE)
|
||||
cur->ref_count[1] = 0;
|
||||
for(list=0; list<2; list++){
|
||||
cur->ref_count[list] = h->ref_count[list];
|
||||
for(j=0; j<h->ref_count[list]; j++)
|
||||
cur->ref_poc[list][j] = h->ref_list[list][j].poc;
|
||||
}
|
||||
if(cur->pict_type != B_TYPE || h->direct_spatial_mv_pred)
|
||||
return;
|
||||
for(list=0; list<2; list++){
|
||||
for(i=0; i<ref1->ref_count[list]; i++){
|
||||
const int poc = ref1->ref_poc[list][i];
|
||||
h->map_col_to_list0[list][i] = PART_NOT_AVAILABLE;
|
||||
for(j=0; j<h->ref_count[list]; j++)
|
||||
if(h->ref_list[list][j].poc == poc){
|
||||
h->map_col_to_list0[list][i] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void pred_direct_motion(H264Context * const h, int *mb_type){
|
||||
MpegEncContext * const s = &h->s;
|
||||
@ -1069,6 +1099,7 @@ static inline void pred_direct_motion(H264Context * const h, int *mb_type){
|
||||
const int mb_type_col = h->ref_list[1][0].mb_type[mb_xy];
|
||||
const int16_t (*l1mv0)[2] = (const int16_t (*)[2]) &h->ref_list[1][0].motion_val[0][b4_xy];
|
||||
const int8_t *l1ref0 = &h->ref_list[1][0].ref_index[0][b8_xy];
|
||||
const int8_t *l1ref1 = &h->ref_list[1][0].ref_index[1][b8_xy];
|
||||
const int is_b8x8 = IS_8X8(*mb_type);
|
||||
int sub_mb_type;
|
||||
int i8, i4;
|
||||
@ -1178,7 +1209,6 @@ static inline void pred_direct_motion(H264Context * const h, int *mb_type){
|
||||
}
|
||||
}
|
||||
}else{ /* direct temporal mv pred */
|
||||
/* FIXME assumes that L1ref0 used the same ref lists as current frame */
|
||||
if(IS_16X16(*mb_type)){
|
||||
fill_rectangle(&h->ref_cache[1][scan8[0]], 4, 4, 8, 0, 1);
|
||||
if(IS_INTRA(mb_type_col)){
|
||||
@ -1186,7 +1216,9 @@ static inline void pred_direct_motion(H264Context * const h, int *mb_type){
|
||||
fill_rectangle(&h-> mv_cache[0][scan8[0]], 4, 4, 8, 0, 4);
|
||||
fill_rectangle(&h-> mv_cache[1][scan8[0]], 4, 4, 8, 0, 4);
|
||||
}else{
|
||||
const int ref0 = l1ref0[0];
|
||||
const int ref0 = l1ref0[0] >= 0 ? h->map_col_to_list0[0][l1ref0[0]]
|
||||
: h->map_col_to_list0[1][l1ref1[0]];
|
||||
assert(ref0 >= 0);
|
||||
const int dist_scale_factor = h->dist_scale_factor[ref0];
|
||||
const int16_t *mv_col = l1mv0[0];
|
||||
int mv_l0[2];
|
||||
@ -1214,6 +1246,11 @@ static inline void pred_direct_motion(H264Context * const h, int *mb_type){
|
||||
}
|
||||
|
||||
ref0 = l1ref0[x8 + y8*h->b8_stride];
|
||||
if(ref0 >= 0)
|
||||
ref0 = h->map_col_to_list0[0][ref0];
|
||||
else
|
||||
ref0 = h->map_col_to_list0[1][l1ref1[x8 + y8*h->b8_stride]];
|
||||
assert(ref0 >= 0);
|
||||
dist_scale_factor = h->dist_scale_factor[ref0];
|
||||
|
||||
fill_rectangle(&h->ref_cache[0][scan8[i8*4]], 2, 2, 8, ref0, 1);
|
||||
@ -2961,12 +2998,12 @@ static int fill_default_ref_list(H264Context *h){
|
||||
}
|
||||
}else{
|
||||
int index=0;
|
||||
for(i=0; i<h->short_ref_count && index < h->ref_count[0]; i++){
|
||||
for(i=0; i<h->short_ref_count; i++){
|
||||
if(h->short_ref[i]->reference != 3) continue; //FIXME refernce field shit
|
||||
h->default_ref_list[0][index ]= *h->short_ref[i];
|
||||
h->default_ref_list[0][index++].pic_id= h->short_ref[i]->frame_num;
|
||||
}
|
||||
for(i = 0; i < 16 && index < h->ref_count[0]; i++){
|
||||
for(i = 0; i < 16; i++){
|
||||
if(h->long_ref[i] == NULL) continue;
|
||||
if(h->long_ref[i]->reference != 3) continue;
|
||||
h->default_ref_list[0][index ]= *h->long_ref[i];
|
||||
@ -3016,6 +3053,7 @@ static int decode_ref_pic_list_reordering(H264Context *h){
|
||||
int reordering_of_pic_nums_idc= get_ue_golomb(&s->gb);
|
||||
int pic_id;
|
||||
int i;
|
||||
Picture *ref = NULL;
|
||||
|
||||
if(reordering_of_pic_nums_idc==3)
|
||||
break;
|
||||
@ -3038,31 +3076,21 @@ static int decode_ref_pic_list_reordering(H264Context *h){
|
||||
else pred+= abs_diff_pic_num;
|
||||
pred &= h->max_pic_num - 1;
|
||||
|
||||
for(i= h->ref_count[list]-1; i>=0; i--){
|
||||
if(h->ref_list[list][i].data[0] != NULL && h->ref_list[list][i].pic_id == pred && h->ref_list[list][i].long_ref==0) // ignore non existing pictures by testing data[0] pointer
|
||||
for(i= h->short_ref_count-1; i>=0; i--){
|
||||
ref = h->short_ref[i];
|
||||
if(ref->data[0] != NULL && ref->frame_num == pred && ref->long_ref == 0) // ignore non existing pictures by testing data[0] pointer
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
pic_id= get_ue_golomb(&s->gb); //long_term_pic_idx
|
||||
|
||||
for(i= h->ref_count[list]-1; i>=0; i--){
|
||||
if(h->ref_list[list][i].pic_id == pic_id && h->ref_list[list][i].long_ref==1) // no need to ignore non existing pictures as non existing pictures have long_ref==0
|
||||
break;
|
||||
}
|
||||
ref = h->long_ref[pic_id];
|
||||
}
|
||||
|
||||
if (i < 0) {
|
||||
av_log(h->s.avctx, AV_LOG_ERROR, "reference picture missing during reorder\n");
|
||||
memset(&h->ref_list[list][index], 0, sizeof(Picture)); //FIXME
|
||||
} else if (i != index) /* this test is not necessary, it is only an optimisation to skip double copy of Picture structure in this case */ {
|
||||
Picture tmp= h->ref_list[list][i];
|
||||
if (i < index) {
|
||||
i = h->ref_count[list];
|
||||
}
|
||||
for(; i > index; i--){
|
||||
h->ref_list[list][i]= h->ref_list[list][i-1];
|
||||
}
|
||||
h->ref_list[list][index]= tmp;
|
||||
} else {
|
||||
h->ref_list[list][index]= *ref;
|
||||
}
|
||||
}else{
|
||||
av_log(h->s.avctx, AV_LOG_ERROR, "illegal reordering_of_pic_nums_idc\n");
|
||||
@ -3076,6 +3104,7 @@ static int decode_ref_pic_list_reordering(H264Context *h){
|
||||
|
||||
if(h->slice_type==B_TYPE && !h->direct_spatial_mv_pred)
|
||||
direct_dist_scale_factor(h);
|
||||
direct_ref_list_init(h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3509,6 +3538,7 @@ static int decode_slice_header(H264Context *h){
|
||||
int default_ref_list_done = 0;
|
||||
|
||||
s->current_picture.reference= h->nal_ref_idc != 0;
|
||||
s->dropable= h->nal_ref_idc == 0;
|
||||
|
||||
first_mb_in_slice= get_ue_golomb(&s->gb);
|
||||
|
||||
@ -6298,7 +6328,7 @@ static int decode_nal_units(H264Context *h, uint8_t *buf, int buf_size){
|
||||
|
||||
//FIXME move after where irt is set
|
||||
s->current_picture.pict_type= s->pict_type;
|
||||
s->current_picture.key_frame= s->pict_type == I_TYPE;
|
||||
s->current_picture.key_frame= s->pict_type == I_TYPE && h->nal_unit_type == NAL_IDR_SLICE;
|
||||
}
|
||||
|
||||
if(!s->current_picture_ptr) return buf_index; //no frame
|
||||
@ -6423,31 +6453,43 @@ static int decode_frame(AVCodecContext *avctx,
|
||||
//#define DECODE_ORDER
|
||||
Picture *out = s->current_picture_ptr;
|
||||
#ifndef DECODE_ORDER
|
||||
/* Sort B-frames into display order
|
||||
* FIXME doesn't allow for multiple delayed frames */
|
||||
/* Sort B-frames into display order */
|
||||
Picture *cur = s->current_picture_ptr;
|
||||
Picture *prev = h->delayed_pic[0];
|
||||
int out_idx = 0;
|
||||
int pics = 0;
|
||||
int i;
|
||||
out = NULL;
|
||||
|
||||
if(s->low_delay
|
||||
&& (cur->pict_type == B_TYPE
|
||||
|| (!h->sps.gaps_in_frame_num_allowed_flag
|
||||
&& prev && cur->poc - prev->poc > 2))){
|
||||
while(h->delayed_pic[pics]) pics++;
|
||||
h->delayed_pic[pics++] = cur;
|
||||
out = h->delayed_pic[0];
|
||||
for(i=0; h->delayed_pic[i] && !h->delayed_pic[i]->key_frame; i++)
|
||||
if(!out || h->delayed_pic[i]->poc < out->poc){
|
||||
out = h->delayed_pic[i];
|
||||
out_idx = i;
|
||||
}
|
||||
if(cur->reference == 0)
|
||||
cur->reference = 1;
|
||||
if(pics > FFMAX(1, s->avctx->has_b_frames)){
|
||||
if(out->reference == 1)
|
||||
out->reference = 0;
|
||||
for(i=out_idx; h->delayed_pic[i]; i++)
|
||||
h->delayed_pic[i] = h->delayed_pic[i+1];
|
||||
}
|
||||
|
||||
for(i=0; h->delayed_pic[i]; i++)
|
||||
if(h->delayed_pic[i]->key_frame)
|
||||
h->delayed_output_poc = -1;
|
||||
|
||||
if((h->delayed_output_poc >=0 && h->delayed_output_poc > cur->poc)
|
||||
|| (s->low_delay && (cur->pict_type == B_TYPE
|
||||
|| (!h->sps.gaps_in_frame_num_allowed_flag
|
||||
&& cur->poc - out->poc > 2)))){
|
||||
s->low_delay = 0;
|
||||
s->avctx->has_b_frames = 1;
|
||||
if(prev && prev->poc > cur->poc)
|
||||
// too late to display this frame
|
||||
cur = prev;
|
||||
s->avctx->has_b_frames++;
|
||||
}
|
||||
|
||||
if(s->low_delay || !prev || cur->pict_type == B_TYPE)
|
||||
out = cur;
|
||||
else
|
||||
out = prev;
|
||||
if(s->low_delay || !prev || out == prev){
|
||||
if(prev && prev->reference == 1)
|
||||
prev->reference = 0;
|
||||
h->delayed_pic[0] = cur;
|
||||
}
|
||||
h->delayed_output_poc = out->poc;
|
||||
#endif
|
||||
|
||||
*pict= *(AVFrame*)out;
|
||||
|
@ -1471,7 +1471,8 @@ alloc:
|
||||
pic= (AVFrame*)&s->picture[i];
|
||||
}
|
||||
|
||||
pic->reference= s->pict_type != B_TYPE && !s->dropable ? 3 : 0;
|
||||
pic->reference= (s->pict_type != B_TYPE || s->codec_id == CODEC_ID_H264)
|
||||
&& !s->dropable ? 3 : 0;
|
||||
|
||||
pic->coded_picture_number= s->coded_picture_number++;
|
||||
|
||||
@ -1566,7 +1567,7 @@ void MPV_frame_end(MpegEncContext *s)
|
||||
XVMC_field_end(s);
|
||||
}else
|
||||
#endif
|
||||
if(s->unrestricted_mv && s->pict_type != B_TYPE && !s->intra_only && !(s->flags&CODEC_FLAG_EMU_EDGE)) {
|
||||
if(s->unrestricted_mv && s->current_picture.reference && !s->intra_only && !(s->flags&CODEC_FLAG_EMU_EDGE)) {
|
||||
draw_edges(s->current_picture.data[0], s->linesize , s->h_edge_pos , s->v_edge_pos , EDGE_WIDTH );
|
||||
draw_edges(s->current_picture.data[1], s->uvlinesize, s->h_edge_pos>>1, s->v_edge_pos>>1, EDGE_WIDTH/2);
|
||||
draw_edges(s->current_picture.data[2], s->uvlinesize, s->h_edge_pos>>1, s->v_edge_pos>>1, EDGE_WIDTH/2);
|
||||
|
@ -173,6 +173,8 @@ typedef struct Picture{
|
||||
int frame_num; ///< h264 frame_num
|
||||
int pic_id; ///< h264 pic_num or long_term_pic_idx
|
||||
int long_ref; ///< 1->long term reference 0->short term reference
|
||||
int ref_poc[2][16]; ///< h264 POCs of the frames used as reference
|
||||
int ref_count[2]; ///< number of entries in ref_poc
|
||||
|
||||
int mb_var_sum; ///< sum of MB variance for current frame
|
||||
int mc_mb_var_sum; ///< motion compensated MB variance for current frame
|
||||
|
Loading…
Reference in New Issue
Block a user