mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
Set keyframe flag only on IDR-frames (needed for reordering across I-frames).
Read vui bitstream restrictions (allows B-frame delay in advance, rather than waiting till we're out of order.) Mark duplicate frames due to delay as duplicates. Originally committed as revision 4028 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
6d021b00e2
commit
4e4d983e8b
@ -87,6 +87,8 @@ typedef struct SPS{
|
|||||||
uint32_t time_scale;
|
uint32_t time_scale;
|
||||||
int fixed_frame_rate_flag;
|
int fixed_frame_rate_flag;
|
||||||
short offset_for_ref_frame[256]; //FIXME dyn aloc?
|
short offset_for_ref_frame[256]; //FIXME dyn aloc?
|
||||||
|
int bitstream_restriction_flag;
|
||||||
|
int num_reorder_frames;
|
||||||
}SPS;
|
}SPS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -289,7 +291,7 @@ typedef struct H264Context{
|
|||||||
Picture ref_list[2][32]; //FIXME size?
|
Picture ref_list[2][32]; //FIXME size?
|
||||||
Picture field_ref_list[2][32]; //FIXME size?
|
Picture field_ref_list[2][32]; //FIXME size?
|
||||||
Picture *delayed_pic[16]; //FIXME size?
|
Picture *delayed_pic[16]; //FIXME size?
|
||||||
int delayed_output_poc;
|
Picture *delayed_output_pic;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* memory management control operations buffer.
|
* memory management control operations buffer.
|
||||||
@ -3249,36 +3251,40 @@ static void implicit_weight_table(H264Context *h){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void unreference_pic(H264Context *h, Picture *pic){
|
||||||
|
int i;
|
||||||
|
pic->reference=0;
|
||||||
|
if(pic == h->delayed_output_pic)
|
||||||
|
pic->reference=1;
|
||||||
|
else{
|
||||||
|
for(i = 0; h->delayed_pic[i]; i++)
|
||||||
|
if(pic == h->delayed_pic[i]){
|
||||||
|
pic->reference=1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* instantaneous decoder refresh.
|
* instantaneous decoder refresh.
|
||||||
*/
|
*/
|
||||||
static void idr(H264Context *h){
|
static void idr(H264Context *h){
|
||||||
int i,j;
|
int i;
|
||||||
|
|
||||||
#define CHECK_DELAY(pic) \
|
|
||||||
for(j = 0; h->delayed_pic[j]; j++) \
|
|
||||||
if(pic == h->delayed_pic[j]){ \
|
|
||||||
pic->reference=1; \
|
|
||||||
break; \
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i=0; i<16; i++){
|
for(i=0; i<16; i++){
|
||||||
if (h->long_ref[i] != NULL) {
|
if (h->long_ref[i] != NULL) {
|
||||||
h->long_ref[i]->reference=0;
|
unreference_pic(h, h->long_ref[i]);
|
||||||
CHECK_DELAY(h->long_ref[i]);
|
|
||||||
h->long_ref[i]= NULL;
|
h->long_ref[i]= NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
h->long_ref_count=0;
|
h->long_ref_count=0;
|
||||||
|
|
||||||
for(i=0; i<h->short_ref_count; i++){
|
for(i=0; i<h->short_ref_count; i++){
|
||||||
h->short_ref[i]->reference=0;
|
unreference_pic(h, h->short_ref[i]);
|
||||||
CHECK_DELAY(h->short_ref[i]);
|
|
||||||
h->short_ref[i]= NULL;
|
h->short_ref[i]= NULL;
|
||||||
}
|
}
|
||||||
h->short_ref_count=0;
|
h->short_ref_count=0;
|
||||||
}
|
}
|
||||||
#undef CHECK_DELAY
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -3369,11 +3375,11 @@ static int execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count){
|
|||||||
case MMCO_SHORT2UNUSED:
|
case MMCO_SHORT2UNUSED:
|
||||||
pic= remove_short(h, mmco[i].short_frame_num);
|
pic= remove_short(h, mmco[i].short_frame_num);
|
||||||
if(pic==NULL) return -1;
|
if(pic==NULL) return -1;
|
||||||
pic->reference= 0;
|
unreference_pic(h, pic);
|
||||||
break;
|
break;
|
||||||
case MMCO_SHORT2LONG:
|
case MMCO_SHORT2LONG:
|
||||||
pic= remove_long(h, mmco[i].long_index);
|
pic= remove_long(h, mmco[i].long_index);
|
||||||
if(pic) pic->reference=0;
|
if(pic) unreference_pic(h, pic);
|
||||||
|
|
||||||
h->long_ref[ mmco[i].long_index ]= remove_short(h, mmco[i].short_frame_num);
|
h->long_ref[ mmco[i].long_index ]= remove_short(h, mmco[i].short_frame_num);
|
||||||
h->long_ref[ mmco[i].long_index ]->long_ref=1;
|
h->long_ref[ mmco[i].long_index ]->long_ref=1;
|
||||||
@ -3382,11 +3388,11 @@ static int execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count){
|
|||||||
case MMCO_LONG2UNUSED:
|
case MMCO_LONG2UNUSED:
|
||||||
pic= remove_long(h, mmco[i].long_index);
|
pic= remove_long(h, mmco[i].long_index);
|
||||||
if(pic==NULL) return -1;
|
if(pic==NULL) return -1;
|
||||||
pic->reference= 0;
|
unreference_pic(h, pic);
|
||||||
break;
|
break;
|
||||||
case MMCO_LONG:
|
case MMCO_LONG:
|
||||||
pic= remove_long(h, mmco[i].long_index);
|
pic= remove_long(h, mmco[i].long_index);
|
||||||
if(pic) pic->reference=0;
|
if(pic) unreference_pic(h, pic);
|
||||||
|
|
||||||
h->long_ref[ mmco[i].long_index ]= s->current_picture_ptr;
|
h->long_ref[ mmco[i].long_index ]= s->current_picture_ptr;
|
||||||
h->long_ref[ mmco[i].long_index ]->long_ref=1;
|
h->long_ref[ mmco[i].long_index ]->long_ref=1;
|
||||||
@ -3399,17 +3405,17 @@ static int execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count){
|
|||||||
// just remove the long term which index is greater than new max
|
// just remove the long term which index is greater than new max
|
||||||
for(j = mmco[i].long_index; j<16; j++){
|
for(j = mmco[i].long_index; j<16; j++){
|
||||||
pic = remove_long(h, j);
|
pic = remove_long(h, j);
|
||||||
if (pic) pic->reference=0;
|
if (pic) unreference_pic(h, pic);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MMCO_RESET:
|
case MMCO_RESET:
|
||||||
while(h->short_ref_count){
|
while(h->short_ref_count){
|
||||||
pic= remove_short(h, h->short_ref[0]->frame_num);
|
pic= remove_short(h, h->short_ref[0]->frame_num);
|
||||||
pic->reference=0;
|
unreference_pic(h, pic);
|
||||||
}
|
}
|
||||||
for(j = 0; j < 16; j++) {
|
for(j = 0; j < 16; j++) {
|
||||||
pic= remove_long(h, j);
|
pic= remove_long(h, j);
|
||||||
if(pic) pic->reference=0;
|
if(pic) unreference_pic(h, pic);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: assert(0);
|
default: assert(0);
|
||||||
@ -3419,7 +3425,7 @@ static int execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count){
|
|||||||
if(!current_is_long){
|
if(!current_is_long){
|
||||||
pic= remove_short(h, s->current_picture_ptr->frame_num);
|
pic= remove_short(h, s->current_picture_ptr->frame_num);
|
||||||
if(pic){
|
if(pic){
|
||||||
pic->reference=0;
|
unreference_pic(h, pic);
|
||||||
av_log(h->s.avctx, AV_LOG_ERROR, "illegal short term buffer state detected\n");
|
av_log(h->s.avctx, AV_LOG_ERROR, "illegal short term buffer state detected\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3756,7 +3762,7 @@ static int decode_slice_header(H264Context *h){
|
|||||||
else
|
else
|
||||||
h->use_weight = 0;
|
h->use_weight = 0;
|
||||||
|
|
||||||
if(s->current_picture.reference)
|
if(s->current_picture.reference == 3)
|
||||||
decode_ref_pic_marking(h);
|
decode_ref_pic_marking(h);
|
||||||
|
|
||||||
if( h->slice_type != I_TYPE && h->slice_type != SI_TYPE && h->pps.cabac )
|
if( h->slice_type != I_TYPE && h->slice_type != SI_TYPE && h->pps.cabac )
|
||||||
@ -5974,9 +5980,27 @@ static int decode_slice(H264Context *h){
|
|||||||
return -1; //not reached
|
return -1; //not reached
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void decode_hrd_parameters(H264Context *h, SPS *sps){
|
||||||
|
MpegEncContext * const s = &h->s;
|
||||||
|
int cpb_count, i;
|
||||||
|
cpb_count = get_ue_golomb(&s->gb) + 1;
|
||||||
|
get_bits(&s->gb, 4); /* bit_rate_scale */
|
||||||
|
get_bits(&s->gb, 4); /* cpb_size_scale */
|
||||||
|
for(i=0; i<cpb_count; i++){
|
||||||
|
get_ue_golomb(&s->gb); /* bit_rate_value_minus1 */
|
||||||
|
get_ue_golomb(&s->gb); /* cpb_size_value_minus1 */
|
||||||
|
get_bits1(&s->gb); /* cbr_flag */
|
||||||
|
}
|
||||||
|
get_bits(&s->gb, 5); /* initial_cpb_removal_delay_length_minus1 */
|
||||||
|
get_bits(&s->gb, 5); /* cpb_removal_delay_length_minus1 */
|
||||||
|
get_bits(&s->gb, 5); /* dpb_output_delay_length_minus1 */
|
||||||
|
get_bits(&s->gb, 5); /* time_offset_length */
|
||||||
|
}
|
||||||
|
|
||||||
static inline int decode_vui_parameters(H264Context *h, SPS *sps){
|
static inline int decode_vui_parameters(H264Context *h, SPS *sps){
|
||||||
MpegEncContext * const s = &h->s;
|
MpegEncContext * const s = &h->s;
|
||||||
int aspect_ratio_info_present_flag, aspect_ratio_idc;
|
int aspect_ratio_info_present_flag, aspect_ratio_idc;
|
||||||
|
int nal_hrd_parameters_present_flag, vcl_hrd_parameters_present_flag;
|
||||||
|
|
||||||
aspect_ratio_info_present_flag= get_bits1(&s->gb);
|
aspect_ratio_info_present_flag= get_bits1(&s->gb);
|
||||||
|
|
||||||
@ -6023,29 +6047,27 @@ static inline int decode_vui_parameters(H264Context *h, SPS *sps){
|
|||||||
sps->fixed_frame_rate_flag = get_bits1(&s->gb);
|
sps->fixed_frame_rate_flag = get_bits1(&s->gb);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
nal_hrd_parameters_present_flag = get_bits1(&s->gb);
|
||||||
| nal_hrd_parameters_present_flag |0 |u(1) |
|
if(nal_hrd_parameters_present_flag)
|
||||||
| if( nal_hrd_parameters_present_flag = = 1) | | |
|
decode_hrd_parameters(h, sps);
|
||||||
| hrd_parameters( ) | | |
|
vcl_hrd_parameters_present_flag = get_bits1(&s->gb);
|
||||||
| vcl_hrd_parameters_present_flag |0 |u(1) |
|
if(vcl_hrd_parameters_present_flag)
|
||||||
| if( vcl_hrd_parameters_present_flag = = 1) | | |
|
decode_hrd_parameters(h, sps);
|
||||||
| hrd_parameters( ) | | |
|
if(nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag)
|
||||||
| if( ( nal_hrd_parameters_present_flag = = 1 | || | |
|
get_bits1(&s->gb); /* low_delay_hrd_flag */
|
||||||
| | | |
|
get_bits1(&s->gb); /* pic_struct_present_flag */
|
||||||
|( vcl_hrd_parameters_present_flag = = 1 ) ) | | |
|
|
||||||
| low_delay_hrd_flag |0 |u(1) |
|
sps->bitstream_restriction_flag = get_bits1(&s->gb);
|
||||||
| bitstream_restriction_flag |0 |u(1) |
|
if(sps->bitstream_restriction_flag){
|
||||||
| if( bitstream_restriction_flag ) { |0 |u(1) |
|
get_bits1(&s->gb); /* motion_vectors_over_pic_boundaries_flag */
|
||||||
| motion_vectors_over_pic_boundaries_flag |0 |u(1) |
|
get_ue_golomb(&s->gb); /* max_bytes_per_pic_denom */
|
||||||
| max_bytes_per_pic_denom |0 |ue(v) |
|
get_ue_golomb(&s->gb); /* max_bits_per_mb_denom */
|
||||||
| max_bits_per_mb_denom |0 |ue(v) |
|
get_ue_golomb(&s->gb); /* log2_max_mv_length_horizontal */
|
||||||
| log2_max_mv_length_horizontal |0 |ue(v) |
|
get_ue_golomb(&s->gb); /* log2_max_mv_length_vertical */
|
||||||
| log2_max_mv_length_vertical |0 |ue(v) |
|
sps->num_reorder_frames = get_ue_golomb(&s->gb);
|
||||||
| num_reorder_frames |0 |ue(v) |
|
get_ue_golomb(&s->gb); /* max_dec_frame_buffering */
|
||||||
| max_dec_frame_buffering |0 |ue(v) |
|
}
|
||||||
| } | | |
|
|
||||||
|} | | |
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6390,13 +6412,12 @@ static int decode_nal_units(H264Context *h, uint8_t *buf, int buf_size){
|
|||||||
default:
|
default:
|
||||||
av_log(avctx, AV_LOG_ERROR, "Unknown NAL code: %d\n", h->nal_unit_type);
|
av_log(avctx, AV_LOG_ERROR, "Unknown NAL code: %d\n", h->nal_unit_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
//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 && h->nal_unit_type == NAL_IDR_SLICE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!s->current_picture_ptr) return buf_index; //no frame
|
if(!s->current_picture_ptr) return buf_index; //no frame
|
||||||
|
|
||||||
|
s->current_picture_ptr->pict_type= s->pict_type;
|
||||||
|
s->current_picture_ptr->key_frame= s->pict_type == I_TYPE && h->nal_unit_type == NAL_IDR_SLICE;
|
||||||
|
|
||||||
h->prev_frame_num_offset= h->frame_num_offset;
|
h->prev_frame_num_offset= h->frame_num_offset;
|
||||||
h->prev_frame_num= h->frame_num;
|
h->prev_frame_num= h->frame_num;
|
||||||
@ -6517,50 +6538,73 @@ static int decode_frame(AVCodecContext *avctx,
|
|||||||
{
|
{
|
||||||
//#define DECODE_ORDER
|
//#define DECODE_ORDER
|
||||||
Picture *out = s->current_picture_ptr;
|
Picture *out = s->current_picture_ptr;
|
||||||
|
*data_size = sizeof(AVFrame);
|
||||||
#ifndef DECODE_ORDER
|
#ifndef DECODE_ORDER
|
||||||
/* Sort B-frames into display order */
|
/* Sort B-frames into display order */
|
||||||
Picture *cur = s->current_picture_ptr;
|
Picture *cur = s->current_picture_ptr;
|
||||||
|
Picture *prev = h->delayed_output_pic;
|
||||||
int out_idx = 0;
|
int out_idx = 0;
|
||||||
int pics = 0;
|
int pics = 0;
|
||||||
|
int out_of_order;
|
||||||
|
int cross_idr = 0;
|
||||||
|
int dropped_frame = 0;
|
||||||
int i;
|
int i;
|
||||||
out = NULL;
|
|
||||||
|
if(h->sps.bitstream_restriction_flag
|
||||||
|
&& s->avctx->has_b_frames < h->sps.num_reorder_frames){
|
||||||
|
s->avctx->has_b_frames = h->sps.num_reorder_frames;
|
||||||
|
s->low_delay = 0;
|
||||||
|
}
|
||||||
|
|
||||||
while(h->delayed_pic[pics]) pics++;
|
while(h->delayed_pic[pics]) pics++;
|
||||||
h->delayed_pic[pics++] = cur;
|
h->delayed_pic[pics++] = cur;
|
||||||
|
if(cur->reference == 0)
|
||||||
|
cur->reference = 1;
|
||||||
|
|
||||||
|
for(i=0; h->delayed_pic[i]; i++)
|
||||||
|
if(h->delayed_pic[i]->key_frame)
|
||||||
|
cross_idr = 1;
|
||||||
|
|
||||||
out = h->delayed_pic[0];
|
out = h->delayed_pic[0];
|
||||||
for(i=0; h->delayed_pic[i] && !h->delayed_pic[i]->key_frame; i++)
|
for(i=1; h->delayed_pic[i] && !h->delayed_pic[i]->key_frame; i++)
|
||||||
if(!out || h->delayed_pic[i]->poc < out->poc){
|
if(h->delayed_pic[i]->poc < out->poc){
|
||||||
out = h->delayed_pic[i];
|
out = h->delayed_pic[i];
|
||||||
out_idx = i;
|
out_idx = i;
|
||||||
}
|
}
|
||||||
if(cur->reference == 0)
|
|
||||||
cur->reference = 1;
|
out_of_order = !cross_idr && prev && out->poc < prev->poc;
|
||||||
for(i=0; h->delayed_pic[i]; i++)
|
if(prev && pics <= s->avctx->has_b_frames)
|
||||||
if(h->delayed_pic[i]->key_frame)
|
out = prev;
|
||||||
h->delayed_output_poc = -1;
|
else if((out_of_order && pics-1 == s->avctx->has_b_frames)
|
||||||
if(pics > FFMAX(1, s->avctx->has_b_frames)){
|
|| (s->low_delay &&
|
||||||
if(out->reference == 1)
|
((!cross_idr && prev && out->poc > prev->poc + 2)
|
||||||
out->reference = 0;
|
|| cur->pict_type == B_TYPE)))
|
||||||
|
{
|
||||||
|
s->low_delay = 0;
|
||||||
|
s->avctx->has_b_frames++;
|
||||||
|
out = prev;
|
||||||
|
}
|
||||||
|
else if(out_of_order)
|
||||||
|
out = prev;
|
||||||
|
|
||||||
|
if(out_of_order || pics > s->avctx->has_b_frames){
|
||||||
|
dropped_frame = (out != h->delayed_pic[out_idx]);
|
||||||
for(i=out_idx; h->delayed_pic[i]; i++)
|
for(i=out_idx; h->delayed_pic[i]; i++)
|
||||||
h->delayed_pic[i] = h->delayed_pic[i+1];
|
h->delayed_pic[i] = h->delayed_pic[i+1];
|
||||||
}
|
}
|
||||||
|
|
||||||
if((h->delayed_output_poc >=0 && h->delayed_output_poc > cur->poc)
|
if(prev == out && !dropped_frame)
|
||||||
|| (s->low_delay && (cur->pict_type == B_TYPE
|
*data_size = 0;
|
||||||
|| (!h->sps.gaps_in_frame_num_allowed_flag
|
if(prev && prev != out && prev->reference == 1)
|
||||||
&& cur->poc - out->poc > 2)))){
|
prev->reference = 0;
|
||||||
s->low_delay = 0;
|
h->delayed_output_pic = out;
|
||||||
s->avctx->has_b_frames++;
|
|
||||||
}
|
|
||||||
|
|
||||||
h->delayed_output_poc = out->poc;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
*pict= *(AVFrame*)out;
|
*pict= *(AVFrame*)out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ff_print_debug_info(s, pict);
|
|
||||||
assert(pict->data[0]);
|
assert(pict->data[0]);
|
||||||
|
ff_print_debug_info(s, pict);
|
||||||
//printf("out %d\n", (int)pict->data[0]);
|
//printf("out %d\n", (int)pict->data[0]);
|
||||||
#if 0 //?
|
#if 0 //?
|
||||||
|
|
||||||
@ -6568,12 +6612,6 @@ static int decode_frame(AVCodecContext *avctx,
|
|||||||
/* we substract 1 because it is added on utils.c */
|
/* we substract 1 because it is added on utils.c */
|
||||||
avctx->frame_number = s->picture_number - 1;
|
avctx->frame_number = s->picture_number - 1;
|
||||||
#endif
|
#endif
|
||||||
#if 0
|
|
||||||
/* dont output the last pic after seeking */
|
|
||||||
if(s->last_picture_ptr || s->low_delay)
|
|
||||||
//Note this isnt a issue as a IDR pic should flush the buffers
|
|
||||||
#endif
|
|
||||||
*data_size = sizeof(AVFrame);
|
|
||||||
return get_consumed_bytes(s, buf_index, buf_size);
|
return get_consumed_bytes(s, buf_index, buf_size);
|
||||||
}
|
}
|
||||||
#if 0
|
#if 0
|
||||||
|
Loading…
Reference in New Issue
Block a user