mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
add multi slice support
for main profile H.264 streams. I have tested this on all H264 conformance streams and comparing the result with the current CVS version, there is 8 streams which decode correctly more frames and 2 streams which are now completely correct with my patch. This patch also correct some typo in comments. patch by (Loic Le Loarer <lll+ffmpeg >at< m4x org>) Originally committed as revision 3758 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
a2c3bf82a7
commit
5175b9376f
@ -340,8 +340,8 @@ static inline uint32_t pack16to32(int a, int b){
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* fill a rectangle.
|
* fill a rectangle.
|
||||||
* @param h height of the recatangle, should be a constant
|
* @param h height of the rectangle, should be a constant
|
||||||
* @param w width of the recatangle, should be a constant
|
* @param w width of the rectangle, should be a constant
|
||||||
* @param size the size of val (1 or 4), should be a constant
|
* @param size the size of val (1 or 4), should be a constant
|
||||||
*/
|
*/
|
||||||
static inline void fill_rectangle(void *vp, int w, int h, int stride, uint32_t val, int size){ //FIXME ensure this IS inlined
|
static inline void fill_rectangle(void *vp, int w, int h, int stride, uint32_t val, int size){ //FIXME ensure this IS inlined
|
||||||
@ -760,8 +760,10 @@ static inline int check_intra_pred_mode(H264Context *h, int mode){
|
|||||||
static const int8_t top [7]= {LEFT_DC_PRED8x8, 1,-1,-1};
|
static const int8_t top [7]= {LEFT_DC_PRED8x8, 1,-1,-1};
|
||||||
static const int8_t left[7]= { TOP_DC_PRED8x8,-1, 2,-1,DC_128_PRED8x8};
|
static const int8_t left[7]= { TOP_DC_PRED8x8,-1, 2,-1,DC_128_PRED8x8};
|
||||||
|
|
||||||
if(mode < 0 || mode > 6)
|
if(mode < 0 || mode > 6) {
|
||||||
|
av_log(h->s.avctx, AV_LOG_ERROR, "out of range intra chroma pred mode at %d %d\n", s->mb_x, s->mb_y);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if(!(h->top_samples_available&0x8000)){
|
if(!(h->top_samples_available&0x8000)){
|
||||||
mode= top[ mode ];
|
mode= top[ mode ];
|
||||||
@ -980,7 +982,7 @@ static inline void pred_pskip_motion(H264Context * const h, int * const mx, int
|
|||||||
const int top_ref = h->ref_cache[0][ scan8[0] - 8 ];
|
const int top_ref = h->ref_cache[0][ scan8[0] - 8 ];
|
||||||
const int left_ref= h->ref_cache[0][ scan8[0] - 1 ];
|
const int left_ref= h->ref_cache[0][ scan8[0] - 1 ];
|
||||||
|
|
||||||
tprintf("pred_pskip: (%d) (%d) at %2d %2d", top_ref, left_ref, h->s.mb_x, h->s.mb_y);
|
tprintf("pred_pskip: (%d) (%d) at %2d %2d\n", top_ref, left_ref, h->s.mb_x, h->s.mb_y);
|
||||||
|
|
||||||
if(top_ref == PART_NOT_AVAILABLE || left_ref == PART_NOT_AVAILABLE
|
if(top_ref == PART_NOT_AVAILABLE || left_ref == PART_NOT_AVAILABLE
|
||||||
|| (top_ref == 0 && *(uint32_t*)h->mv_cache[0][ scan8[0] - 8 ] == 0)
|
|| (top_ref == 0 && *(uint32_t*)h->mv_cache[0][ scan8[0] - 8 ] == 0)
|
||||||
@ -2696,7 +2698,7 @@ static int pred_weight_table(H264Context *h){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* instantaneos decoder refresh.
|
* instantaneous decoder refresh.
|
||||||
*/
|
*/
|
||||||
static void idr(H264Context *h){
|
static void idr(H264Context *h){
|
||||||
int i;
|
int i;
|
||||||
@ -3001,6 +3003,7 @@ static int decode_slice_header(H264Context *h){
|
|||||||
h->slice_type= get_ue_golomb(&s->gb);
|
h->slice_type= get_ue_golomb(&s->gb);
|
||||||
if(h->slice_type > 9){
|
if(h->slice_type > 9){
|
||||||
av_log(h->s.avctx, AV_LOG_ERROR, "slice type too large (%d) at %d %d\n", h->slice_type, s->mb_x, s->mb_y);
|
av_log(h->s.avctx, AV_LOG_ERROR, "slice type too large (%d) at %d %d\n", h->slice_type, s->mb_x, s->mb_y);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
if(h->slice_type > 4){
|
if(h->slice_type > 4){
|
||||||
h->slice_type -= 5;
|
h->slice_type -= 5;
|
||||||
@ -3035,8 +3038,8 @@ static int decode_slice_header(H264Context *h){
|
|||||||
h->b_stride= s->mb_width*4;
|
h->b_stride= s->mb_width*4;
|
||||||
h->b8_stride= s->mb_width*2;
|
h->b8_stride= s->mb_width*2;
|
||||||
|
|
||||||
s->mb_x = first_mb_in_slice % s->mb_width;
|
s->resync_mb_x = s->mb_x = first_mb_in_slice % s->mb_width;
|
||||||
s->mb_y = first_mb_in_slice / s->mb_width; //FIXME AFFW
|
s->resync_mb_y = s->mb_y = first_mb_in_slice / s->mb_width; //FIXME AFFW
|
||||||
|
|
||||||
s->width = 16*s->mb_width - 2*(h->sps.crop_left + h->sps.crop_right );
|
s->width = 16*s->mb_width - 2*(h->sps.crop_left + h->sps.crop_right );
|
||||||
if(h->sps.frame_mbs_only_flag)
|
if(h->sps.frame_mbs_only_flag)
|
||||||
@ -3065,7 +3068,7 @@ static int decode_slice_header(H264Context *h){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(first_mb_in_slice == 0){
|
if(h->slice_num == 0){
|
||||||
frame_start(h);
|
frame_start(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3136,7 +3139,7 @@ static int decode_slice_header(H264Context *h){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(first_mb_in_slice == 0){
|
if(h->slice_num == 0){
|
||||||
fill_default_ref_list(h);
|
fill_default_ref_list(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3185,9 +3188,11 @@ static int decode_slice_header(H264Context *h){
|
|||||||
slice_group_change_cycle= get_bits(&s->gb, ?);
|
slice_group_change_cycle= get_bits(&s->gb, ?);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
h->slice_num++;
|
||||||
|
|
||||||
if(s->avctx->debug&FF_DEBUG_PICT_INFO){
|
if(s->avctx->debug&FF_DEBUG_PICT_INFO){
|
||||||
av_log(h->s.avctx, AV_LOG_DEBUG, "mb:%d %c pps:%d frame:%d poc:%d/%d ref:%d/%d qp:%d loop:%d\n",
|
av_log(h->s.avctx, AV_LOG_DEBUG, "slice:%d mb:%d %c pps:%d frame:%d poc:%d/%d ref:%d/%d qp:%d loop:%d\n",
|
||||||
first_mb_in_slice,
|
h->slice_num, first_mb_in_slice,
|
||||||
av_get_pict_type_char(h->slice_type),
|
av_get_pict_type_char(h->slice_type),
|
||||||
pps_id, h->frame_num,
|
pps_id, h->frame_num,
|
||||||
s->current_picture_ptr->field_poc[0], s->current_picture_ptr->field_poc[1],
|
s->current_picture_ptr->field_poc[0], s->current_picture_ptr->field_poc[1],
|
||||||
@ -3619,7 +3624,7 @@ decode_intra_mb:
|
|||||||
//FIXME we should set ref_idx_l? to 0 if we use that later ...
|
//FIXME we should set ref_idx_l? to 0 if we use that later ...
|
||||||
if(IS_16X16(mb_type)){
|
if(IS_16X16(mb_type)){
|
||||||
for(list=0; list<2; list++){
|
for(list=0; list<2; list++){
|
||||||
if(h->ref_count[0]>0){
|
if(h->ref_count[list]>0){
|
||||||
if(IS_DIR(mb_type, 0, list)){
|
if(IS_DIR(mb_type, 0, list)){
|
||||||
const int val= get_te0_golomb(&s->gb, h->ref_count[list]);
|
const int val= get_te0_golomb(&s->gb, h->ref_count[list]);
|
||||||
fill_rectangle(&h->ref_cache[list][ scan8[0] ], 4, 4, 8, val, 1);
|
fill_rectangle(&h->ref_cache[list][ scan8[0] ], 4, 4, 8, val, 1);
|
||||||
@ -5126,12 +5131,11 @@ static int decode_slice(H264Context *h){
|
|||||||
if( ++s->mb_x >= s->mb_width ) {
|
if( ++s->mb_x >= s->mb_width ) {
|
||||||
s->mb_x = 0;
|
s->mb_x = 0;
|
||||||
ff_draw_horiz_band(s, 16*s->mb_y, 16);
|
ff_draw_horiz_band(s, 16*s->mb_y, 16);
|
||||||
if( ++s->mb_y >= s->mb_height ) {
|
++s->mb_y;
|
||||||
tprintf("slice end %d %d\n", get_bits_count(&s->gb), s->gb.size_in_bits);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( eos || s->mb_y >= s->mb_height ) {
|
if( eos || s->mb_y >= s->mb_height ) {
|
||||||
|
tprintf("slice end %d %d\n", get_bits_count(&s->gb), s->gb.size_in_bits);
|
||||||
ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x-1, s->mb_y, (AC_END|DC_END|MV_END)&part_mask);
|
ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x-1, s->mb_y, (AC_END|DC_END|MV_END)&part_mask);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -5184,6 +5188,7 @@ static int decode_slice(H264Context *h){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(get_bits_count(&s->gb) >= s->gb.size_in_bits && s->mb_skip_run<=0){
|
if(get_bits_count(&s->gb) >= s->gb.size_in_bits && s->mb_skip_run<=0){
|
||||||
|
tprintf("slice end %d %d\n", get_bits_count(&s->gb), s->gb.size_in_bits);
|
||||||
if(get_bits_count(&s->gb) == s->gb.size_in_bits ){
|
if(get_bits_count(&s->gb) == s->gb.size_in_bits ){
|
||||||
ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x-1, s->mb_y, (AC_END|DC_END|MV_END)&part_mask);
|
ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x-1, s->mb_y, (AC_END|DC_END|MV_END)&part_mask);
|
||||||
|
|
||||||
@ -5492,23 +5497,34 @@ static inline int decode_picture_parameter_set(H264Context *h){
|
|||||||
* finds the end of the current frame in the bitstream.
|
* finds the end of the current frame in the bitstream.
|
||||||
* @return the position of the first byte of the next frame, or -1
|
* @return the position of the first byte of the next frame, or -1
|
||||||
*/
|
*/
|
||||||
static int find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size){
|
static int find_frame_end(H264Context *h, const uint8_t *buf, int buf_size){
|
||||||
int i;
|
int i;
|
||||||
uint32_t state;
|
uint32_t state;
|
||||||
|
ParseContext *pc = &(h->s.parse_context);
|
||||||
//printf("first %02X%02X%02X%02X\n", buf[0], buf[1],buf[2],buf[3]);
|
//printf("first %02X%02X%02X%02X\n", buf[0], buf[1],buf[2],buf[3]);
|
||||||
// mb_addr= pc->mb_addr - 1;
|
// mb_addr= pc->mb_addr - 1;
|
||||||
state= pc->state;
|
state= pc->state;
|
||||||
//FIXME this will fail with slices
|
for(i=0; i<=buf_size; i++){
|
||||||
for(i=0; i<buf_size; i++){
|
|
||||||
state= (state<<8) | buf[i];
|
|
||||||
if((state&0xFFFFFF1F) == 0x101 || (state&0xFFFFFF1F) == 0x102 || (state&0xFFFFFF1F) == 0x105){
|
if((state&0xFFFFFF1F) == 0x101 || (state&0xFFFFFF1F) == 0x102 || (state&0xFFFFFF1F) == 0x105){
|
||||||
|
tprintf("find_frame_end new startcode = %08x, frame_start_found = %d, pos = %d\n", state, pc->frame_start_found, i);
|
||||||
if(pc->frame_start_found){
|
if(pc->frame_start_found){
|
||||||
pc->state=-1;
|
// If there isn't one more byte in the buffer
|
||||||
pc->frame_start_found= 0;
|
// the test on first_mb_in_slice cannot be done yet
|
||||||
return i-3;
|
// do it at next call.
|
||||||
|
if (i >= buf_size) break;
|
||||||
|
if (buf[i] & 0x80) {
|
||||||
|
// first_mb_in_slice is 0, probably the first nal of a new
|
||||||
|
// slice
|
||||||
|
tprintf("find_frame_end frame_end_found, state = %08x, pos = %d\n", state, i);
|
||||||
|
pc->state=-1;
|
||||||
|
pc->frame_start_found= 0;
|
||||||
|
return i-4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pc->frame_start_found= 1;
|
pc->frame_start_found = 1;
|
||||||
}
|
}
|
||||||
|
if (i<buf_size)
|
||||||
|
state= (state<<8) | buf[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
pc->state= state;
|
pc->state= state;
|
||||||
@ -5520,10 +5536,11 @@ static int h264_parse(AVCodecParserContext *s,
|
|||||||
uint8_t **poutbuf, int *poutbuf_size,
|
uint8_t **poutbuf, int *poutbuf_size,
|
||||||
const uint8_t *buf, int buf_size)
|
const uint8_t *buf, int buf_size)
|
||||||
{
|
{
|
||||||
ParseContext *pc = s->priv_data;
|
H264Context *h = s->priv_data;
|
||||||
|
ParseContext *pc = &h->s.parse_context;
|
||||||
int next;
|
int next;
|
||||||
|
|
||||||
next= find_frame_end(pc, buf, buf_size);
|
next= find_frame_end(h, buf, buf_size);
|
||||||
|
|
||||||
if (ff_combine_frame(pc, next, (uint8_t **)&buf, &buf_size) < 0) {
|
if (ff_combine_frame(pc, next, (uint8_t **)&buf, &buf_size) < 0) {
|
||||||
*poutbuf = NULL;
|
*poutbuf = NULL;
|
||||||
@ -5546,6 +5563,7 @@ static int decode_nal_units(H264Context *h, uint8_t *buf, int buf_size){
|
|||||||
printf("%X ", buf[i]);
|
printf("%X ", buf[i]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
h->slice_num = 0;
|
||||||
for(;;){
|
for(;;){
|
||||||
int consumed;
|
int consumed;
|
||||||
int dst_length;
|
int dst_length;
|
||||||
@ -5704,7 +5722,7 @@ static int decode_frame(AVCodecContext *avctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(s->flags&CODEC_FLAG_TRUNCATED){
|
if(s->flags&CODEC_FLAG_TRUNCATED){
|
||||||
int next= find_frame_end(&s->parse_context, buf, buf_size);
|
int next= find_frame_end(h, buf, buf_size);
|
||||||
|
|
||||||
if( ff_combine_frame(&s->parse_context, next, &buf, &buf_size) < 0 )
|
if( ff_combine_frame(&s->parse_context, next, &buf, &buf_size) < 0 )
|
||||||
return buf_size;
|
return buf_size;
|
||||||
@ -5789,7 +5807,7 @@ static int decode_frame(AVCodecContext *avctx,
|
|||||||
#if 0
|
#if 0
|
||||||
/* dont output the last pic after seeking */
|
/* dont output the last pic after seeking */
|
||||||
if(s->last_picture_ptr || s->low_delay)
|
if(s->last_picture_ptr || s->low_delay)
|
||||||
//Note this isnt a issue as a IDR pic should flush teh buffers
|
//Note this isnt a issue as a IDR pic should flush the buffers
|
||||||
#endif
|
#endif
|
||||||
*data_size = sizeof(AVFrame);
|
*data_size = sizeof(AVFrame);
|
||||||
return get_consumed_bytes(s, buf_index, buf_size);
|
return get_consumed_bytes(s, buf_index, buf_size);
|
||||||
@ -6016,7 +6034,7 @@ AVCodec h264_decoder = {
|
|||||||
|
|
||||||
AVCodecParser h264_parser = {
|
AVCodecParser h264_parser = {
|
||||||
{ CODEC_ID_H264 },
|
{ CODEC_ID_H264 },
|
||||||
sizeof(ParseContext),
|
sizeof(H264Context),
|
||||||
NULL,
|
NULL,
|
||||||
h264_parse,
|
h264_parse,
|
||||||
ff_parse_close,
|
ff_parse_close,
|
||||||
|
Loading…
Reference in New Issue
Block a user