您的位置:首页 > 其它

X264 - x264_encoder_encode

2013-06-13 16:06 246 查看
这个函数前面有一段注释(如下):
****************************************************************************
* x264_encoder_encode:
* XXX: i_poc : is the poc of the current given picture
* i_frame : is the number of the frame being coded
* ex: type frame poc
* I 0 2*0//poc是实际的帧的位置.
* P 1 2*3//frame是编码的顺序.
* B 2 2*1
* B 3 2*2
* P 4 2*6
* B 5 2*4
* B 6 2*5
****************************************************************************/
要搞清poc和frame的区别.
假设一个视频序列如下:
I B B P B B P
我们编码是按I P B B P B B的顺序,这就是frame的编号.
而我们视频序列的播放序号是POC的序号,这里是乘以了2.

int x264_encoder_encode( x264_t *h,

x264_nal_t **pp_nal, int *pi_nal,

x264_picture_t *pic_in,

x264_picture_t *pic_out )

{

x264_t *thread_current, *thread_prev, *thread_oldest;

int i_nal_type, i_nal_ref_idc, i_global_qp;

int overhead = NALU_OVERHEAD;

#if HAVE_OPENCL

if( h->opencl.b_fatal_error )

return -1;

#endif

if( h->i_thread_frames > 1 )

{

thread_prev = h->thread[ h->i_thread_phase ];

h->i_thread_phase = (h->i_thread_phase + 1) % h->i_thread_frames;

thread_current = h->thread[ h->i_thread_phase ];

thread_oldest = h->thread[ (h->i_thread_phase + 1) % h->i_thread_frames ];

x264_thread_sync_context( thread_current, thread_prev );

x264_thread_sync_ratecontrol( thread_current, thread_prev, thread_oldest );

h = thread_current;

}

else

{

thread_current =

thread_oldest = h;

}

#if HAVE_MMX

if( h->param.cpu&X264_CPU_SSE_MISALIGN )

x264_cpu_mask_misalign_sse();

#endif

h->i_cpb_delay_pir_offset = h->i_cpb_delay_pir_offset_next;

/* no data out */

*pi_nal = 0;

*pp_nal = NULL;

/* ------------------- Setup new frame from picture -------------------- */

if( pic_in != NULL )

{

/* 1: Copy the picture to a frame and move it to a buffer */

// get a unused frame fenc

x264_frame_t *fenc = x264_frame_pop_unused( h, 0 );

if( !fenc )

return -1;

// copy from pic_in to fenc

if( x264_frame_copy_picture( h, fenc, pic_in ) < 0 )

return -1;

if( h->param.i_width != 16 * h->mb.i_mb_width ||

h->param.i_height != 16 * h->mb.i_mb_height )

x264_frame_expand_border_mod16( h, fenc );

fenc->i_frame = h->frames.i_input++; // frame number of frame encoded

if( fenc->i_frame == 0 )

h->frames.i_first_pts = fenc->i_pts;

if( h->frames.i_bframe_delay && fenc->i_frame == h->frames.i_bframe_delay )

h->frames.i_bframe_delay_time = fenc->i_pts - h->frames.i_first_pts;

if( h->param.b_vfr_input && fenc->i_pts <= h->frames.i_largest_pts )

x264_log( h, X264_LOG_WARNING, "non-strictly-monotonic PTS\n" );

h->frames.i_second_largest_pts = h->frames.i_largest_pts;

h->frames.i_largest_pts = fenc->i_pts;

if( (fenc->i_pic_struct < PIC_STRUCT_AUTO) || (fenc->i_pic_struct > PIC_STRUCT_TRIPLE) )

fenc->i_pic_struct = PIC_STRUCT_AUTO;

if( fenc->i_pic_struct == PIC_STRUCT_AUTO )

{

#if HAVE_INTERLACED

int b_interlaced = fenc->param ? fenc->param->b_interlaced : h->param.b_interlaced;

#else

int b_interlaced = 0;

#endif

if( b_interlaced )

{

int b_tff = fenc->param ? fenc->param->b_tff : h->param.b_tff;

fenc->i_pic_struct = b_tff ? PIC_STRUCT_TOP_BOTTOM : PIC_STRUCT_BOTTOM_TOP;

}

else

fenc->i_pic_struct = PIC_STRUCT_PROGRESSIVE;

}

// x264 encode 2 pass

if( h->param.rc.b_mb_tree && h->param.rc.b_stat_read )

{

if( x264_macroblock_tree_read( h, fenc, pic_in->prop.quant_offsets ) )

return -1;

}

else

x264_stack_align( x264_adaptive_quant_frame, h, fenc, pic_in->prop.quant_offsets );

if( pic_in->prop.quant_offsets_free )

pic_in->prop.quant_offsets_free( pic_in->prop.quant_offsets );

// calc 1/2 pixel of luma plane and expand border of luma plane

if( h->frames.b_have_lowres )

x264_frame_init_lowres( h, fenc );

/* 2: Place the frame into the queue for its slice type decision */

// put frame into ifbuf or next list

x264_lookahead_put_frame( h, fenc );

if( h->frames.i_input <= h->frames.i_delay + 1 - h->i_thread_frames )

{

/* Nothing yet to encode, waiting for filling of buffers */

pic_out->i_type = X264_TYPE_AUTO;

return 0;

}

}

else

{

/* signal kills for lookahead thread */

x264_pthread_mutex_lock( &h->lookahead->ifbuf.mutex );

h->lookahead->b_exit_thread = 1;

x264_pthread_cond_broadcast( &h->lookahead->ifbuf.cv_fill );

x264_pthread_mutex_unlock( &h->lookahead->ifbuf.mutex );

}

h->i_frame++; // add h's frame number

/* 3: The picture is analyzed in the lookahead */

// shift items from lookahead->ofbuf to h->frames.current

if( !h->frames.current[0] )

x264_lookahead_get_frames( h );

//

if( !h->frames.current[0] && x264_lookahead_is_empty( h ) )

return x264_encoder_frame_end( thread_oldest, thread_current, pp_nal, pi_nal, pic_out );

/* ------------------- Get frame to be encoded ------------------------- */

/* 4: get picture to encode */

// get h->frames.current[0], and set it to h->fenc

h->fenc = x264_frame_shift( h->frames.current );

/* If applicable, wait for previous frame reconstruction to finish */

if( h->param.b_sliced_threads )

if( x264_threadpool_wait_all( h ) < 0 )

return -1;

if( h->i_frame == h->i_thread_frames - 1 )

h->i_reordered_pts_delay = h->fenc->i_reordered_pts;

if( h->fenc->param )

{

x264_encoder_reconfig( h, h->fenc->param );

if( h->fenc->param->param_free )

{

h->fenc->param->param_free( h->fenc->param );

h->fenc->param = NULL;

}

}

// ok to call this before encoding any frames, since the initial values of fdec have b_kept_as_ref=0

// update reference frame

if( x264_reference_update( h ) )

return -1;

h->fdec->i_lines_completed = -1;

if( !IS_X264_TYPE_I( h->fenc->i_type ) )

{

int valid_refs_left = 0;

for( int i = 0; h->frames.reference[i]; i++ )

if( !h->frames.reference[i]->b_corrupt )

valid_refs_left++;

/* No valid reference frames left: force an IDR. */

if( !valid_refs_left )

{

h->fenc->b_keyframe = 1;

h->fenc->i_type = X264_TYPE_IDR;

}

}

if( h->fenc->b_keyframe )

{

h->frames.i_last_keyframe = h->fenc->i_frame;

if( h->fenc->i_type == X264_TYPE_IDR )

{

h->i_frame_num = 0;

h->frames.i_last_idr = h->fenc->i_frame;

}

}

h->sh.i_mmco_command_count =

h->sh.i_mmco_remove_from_end = 0;

h->b_ref_reorder[0] =

h->b_ref_reorder[1] = 0;

h->fdec->i_poc =

h->fenc->i_poc = 2 * ( h->fenc->i_frame - X264_MAX( h->frames.i_last_idr, 0 ) );

/* ------------------- Setup frame context ----------------------------- */

/* 5: Init data dependent of frame type */

if( h->fenc->i_type == X264_TYPE_IDR )

{

/* reset ref pictures */

i_nal_type = NAL_SLICE_IDR;

i_nal_ref_idc = NAL_PRIORITY_HIGHEST;

h->sh.i_type = SLICE_TYPE_I;

x264_reference_reset( h ); // clear reference frame list

h->frames.i_poc_last_open_gop = -1;

}

else if( h->fenc->i_type == X264_TYPE_I )

{

i_nal_type = NAL_SLICE;

i_nal_ref_idc = NAL_PRIORITY_HIGH; /* Not completely true but for now it is (as all I/P are kept as ref)*/

h->sh.i_type = SLICE_TYPE_I;

x264_reference_hierarchy_reset( h );

if( h->param.b_open_gop )

h->frames.i_poc_last_open_gop = h->fenc->b_keyframe ? h->fenc->i_poc : -1;

}

else if( h->fenc->i_type == X264_TYPE_P )

{

i_nal_type = NAL_SLICE;

i_nal_ref_idc = NAL_PRIORITY_HIGH; /* Not completely true but for now it is (as all I/P are kept as ref)*/

h->sh.i_type = SLICE_TYPE_P;

x264_reference_hierarchy_reset( h );

h->frames.i_poc_last_open_gop = -1;

}

else if( h->fenc->i_type == X264_TYPE_BREF )

{

i_nal_type = NAL_SLICE;

i_nal_ref_idc = h->param.i_bframe_pyramid == X264_B_PYRAMID_STRICT ? NAL_PRIORITY_LOW : NAL_PRIORITY_HIGH;

h->sh.i_type = SLICE_TYPE_B;

x264_reference_hierarchy_reset( h );

}

else /* B frame */

{

i_nal_type = NAL_SLICE;

i_nal_ref_idc = NAL_PRIORITY_DISPOSABLE;

h->sh.i_type = SLICE_TYPE_B;

}

// reconstruct frame as reference, only b_kept_as_ref is true

h->fdec->i_type = h->fenc->i_type;

h->fdec->i_frame = h->fenc->i_frame;

h->fenc->b_kept_as_ref =

h->fdec->b_kept_as_ref = i_nal_ref_idc != NAL_PRIORITY_DISPOSABLE && h->param.i_keyint_max > 1;

h->fdec->mb_info = h->fenc->mb_info;

h->fdec->mb_info_free = h->fenc->mb_info_free;

h->fenc->mb_info = NULL;

h->fenc->mb_info_free = NULL;

h->fdec->i_pts = h->fenc->i_pts;

if( h->frames.i_bframe_delay )

{

int64_t *prev_reordered_pts = thread_current->frames.i_prev_reordered_pts;

h->fdec->i_dts = h->i_frame > h->frames.i_bframe_delay

? prev_reordered_pts[ (h->i_frame - h->frames.i_bframe_delay) % h->frames.i_bframe_delay ]

: h->fenc->i_reordered_pts - h->frames.i_bframe_delay_time;

prev_reordered_pts[ h->i_frame % h->frames.i_bframe_delay ] = h->fenc->i_reordered_pts;

}

else

h->fdec->i_dts = h->fenc->i_reordered_pts;

if( h->fenc->i_type == X264_TYPE_IDR )

h->i_last_idr_pts = h->fdec->i_pts;

/* ------------------- Init ----------------------------- */

/* build ref list 0/1 */

x264_reference_build_list( h, h->fdec->i_poc );

/* ---------------------- Write the bitstream -------------------------- */

/* Init bitstream context */

if( h->param.b_sliced_threads )

{

for( int i = 0; i < h->param.i_threads; i++ )

{

bs_init( &h->thread[i]->out.bs, h->thread[i]->out.p_bitstream, h->thread[i]->out.i_bitstream );

h->thread[i]->out.i_nal = 0;

}

}

else

{

bs_init( &h->out.bs, h->out.p_bitstream, h->out.i_bitstream );

h->out.i_nal = 0;

}

if( h->param.b_aud )

{

int pic_type;

if( h->sh.i_type == SLICE_TYPE_I )

pic_type = 0;

else if( h->sh.i_type == SLICE_TYPE_P )

pic_type = 1;

else if( h->sh.i_type == SLICE_TYPE_B )

pic_type = 2;

else

pic_type = 7;

x264_nal_start( h, NAL_AUD, NAL_PRIORITY_DISPOSABLE );

bs_write( &h->out.bs, 3, pic_type );

bs_rbsp_trailing( &h->out.bs );

if( x264_nal_end( h ) )

return -1;

overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD - (h->param.b_annexb && h->out.i_nal-1);

}

h->i_nal_type = i_nal_type;

h->i_nal_ref_idc = i_nal_ref_idc;

if( h->param.b_intra_refresh )

{

if( IS_X264_TYPE_I( h->fenc->i_type ) )

{

h->fdec->i_frames_since_pir = 0;

h->b_queued_intra_refresh = 0;

/* PIR is currently only supported with ref == 1, so any intra frame effectively refreshes

* the whole frame and counts as an intra refresh. */

h->fdec->f_pir_position = h->mb.i_mb_width;

}

else if( h->fenc->i_type == X264_TYPE_P )

{

int pocdiff = (h->fdec->i_poc - h->fref[0][0]->i_poc)/2;

float increment = X264_MAX( ((float)h->mb.i_mb_width-1) / h->param.i_keyint_max, 1 );

h->fdec->f_pir_position = h->fref[0][0]->f_pir_position;

h->fdec->i_frames_since_pir = h->fref[0][0]->i_frames_since_pir + pocdiff;

if( h->fdec->i_frames_since_pir >= h->param.i_keyint_max ||

(h->b_queued_intra_refresh && h->fdec->f_pir_position + 0.5 >= h->mb.i_mb_width) )

{

h->fdec->f_pir_position = 0;

h->fdec->i_frames_since_pir = 0;

h->b_queued_intra_refresh = 0;

h->fenc->b_keyframe = 1;

}

h->fdec->i_pir_start_col = h->fdec->f_pir_position+0.5;

h->fdec->f_pir_position += increment * pocdiff;

h->fdec->i_pir_end_col = h->fdec->f_pir_position+0.5;

/* If our intra refresh has reached the right side of the frame, we're done. */

if( h->fdec->i_pir_end_col >= h->mb.i_mb_width - 1 )

{

h->fdec->f_pir_position = h->mb.i_mb_width;

h->fdec->i_pir_end_col = h->mb.i_mb_width - 1;

}

}

}

if( h->fenc->b_keyframe )

{

/* Write SPS and PPS */

if( h->param.b_repeat_headers )

{

/* generate sequence parameters */

x264_nal_start( h, NAL_SPS, NAL_PRIORITY_HIGHEST );

x264_sps_write( &h->out.bs, h->sps );

if( x264_nal_end( h ) )

return -1;

overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;

/* generate picture parameters */

x264_nal_start( h, NAL_PPS, NAL_PRIORITY_HIGHEST );

x264_pps_write( &h->out.bs, h->sps, h->pps );

if( x264_nal_end( h ) )

return -1;

overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;

}

/* when frame threading is used, buffering period sei is written in x264_encoder_frame_end */

if( h->i_thread_frames == 1 && h->sps->vui.b_nal_hrd_parameters_present )

{

x264_hrd_fullness( h );

x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );

x264_sei_buffering_period_write( h, &h->out.bs );

if( x264_nal_end( h ) )

return -1;

overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;

}

}

/* write extra sei */

for( int i = 0; i < h->fenc->extra_sei.num_payloads; i++ )

{

x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );

x264_sei_write( &h->out.bs, h->fenc->extra_sei.payloads[i].payload, h->fenc->extra_sei.payloads[i].payload_size,

h->fenc->extra_sei.payloads[i].payload_type );

if( x264_nal_end( h ) )

return -1;

overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD - (h->param.b_annexb && h->out.i_nal-1);

if( h->fenc->extra_sei.sei_free )

{

h->fenc->extra_sei.sei_free( h->fenc->extra_sei.payloads[i].payload );

h->fenc->extra_sei.payloads[i].payload = NULL;

}

}

if( h->fenc->extra_sei.sei_free )

{

h->fenc->extra_sei.sei_free( h->fenc->extra_sei.payloads );

h->fenc->extra_sei.payloads = NULL;

h->fenc->extra_sei.sei_free = NULL;

}

if( h->fenc->b_keyframe )

{

if( h->param.b_repeat_headers && h->fenc->i_frame == 0 )

{

/* identify ourself */

x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );

if( x264_sei_version_write( h, &h->out.bs ) )

return -1;

if( x264_nal_end( h ) )

return -1;

overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD - (h->param.b_annexb && h->out.i_nal-1);

}

if( h->fenc->i_type != X264_TYPE_IDR )

{

int time_to_recovery = h->param.b_open_gop ? 0 : X264_MIN( h->mb.i_mb_width - 1, h->param.i_keyint_max ) + h->param.i_bframe - 1;

x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );

x264_sei_recovery_point_write( h, &h->out.bs, time_to_recovery );

if( x264_nal_end( h ) )

return -1;

overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD - (h->param.b_annexb && h->out.i_nal-1);

}

if ( h->param.i_frame_packing >= 0 )

{

x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );

x264_sei_frame_packing_write( h, &h->out.bs );

if( x264_nal_end( h ) )

return -1;

overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD - (h->param.b_annexb && h->out.i_nal-1);

}

}

/* generate sei pic timing */

if( h->sps->vui.b_pic_struct_present || h->sps->vui.b_nal_hrd_parameters_present )

{

x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );

x264_sei_pic_timing_write( h, &h->out.bs );

if( x264_nal_end( h ) )

return -1;

overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD - (h->param.b_annexb && h->out.i_nal-1);

}

/* As required by Blu-ray. */

if( !IS_X264_TYPE_B( h->fenc->i_type ) && h->b_sh_backup )

{

h->b_sh_backup = 0;

x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );

x264_sei_dec_ref_pic_marking_write( h, &h->out.bs );

if( x264_nal_end( h ) )

return -1;

overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD - (h->param.b_annexb && h->out.i_nal-1);

}

if( h->fenc->b_keyframe && h->param.b_intra_refresh )

h->i_cpb_delay_pir_offset_next = h->fenc->i_cpb_delay;

/* Init the rate control */

/* FIXME: Include slice header bit cost. */

x264_ratecontrol_start( h, h->fenc->i_qpplus1, overhead*8 );

i_global_qp = x264_ratecontrol_qp( h );

pic_out->i_qpplus1 =

h->fdec->i_qpplus1 = i_global_qp + 1;

if( h->param.rc.b_stat_read && h->sh.i_type != SLICE_TYPE_I )

{

x264_reference_build_list_optimal( h );

x264_reference_check_reorder( h );

}

if( h->i_ref[0] )

h->fdec->i_poc_l0ref0 = h->fref[0][0]->i_poc;

/* ------------------------ Create slice header ----------------------- */

x264_slice_init( h, i_nal_type, i_global_qp );

/*------------------------- Weights -------------------------------------*/

if( h->sh.i_type == SLICE_TYPE_B )

x264_macroblock_bipred_init( h );

x264_weighted_pred_init( h );

if( i_nal_ref_idc != NAL_PRIORITY_DISPOSABLE )

h->i_frame_num++;

/* Write frame */

h->i_threadslice_start = 0;

h->i_threadslice_end = h->mb.i_mb_height;

if( h->i_thread_frames > 1 )

{

x264_threadpool_run( h->threadpool, (void*)x264_slices_write, h );

h->b_thread_active = 1;

}

else if( h->param.b_sliced_threads )

{

if( x264_threaded_slices_write( h ) )

return -1;

}

else

if( (intptr_t)x264_slices_write( h ) )

return -1;

return x264_encoder_frame_end( thread_oldest, thread_current, pp_nal, pi_nal, pic_out );

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: