}
OPT("bluray-compat")
p->b_bluray_compat = atobool(value);
+ OPT("avcintra-compat")
+ p->b_avcintra_compat = atobool(value);
OPT("sar")
{
b_error = ( 2 != sscanf( value, "%d:%d", &p->vui.i_sar_width, &p->vui.i_sar_height ) &&
#define NALU_OVERHEAD 5 // startcode + NAL type costs 5 bytes per frame
#define FILLER_OVERHEAD (NALU_OVERHEAD+1)
+#define SEI_OVERHEAD (NALU_OVERHEAD - (h->param.b_annexb && !h->param.b_avcintra_compat && (h->out.i_nal-1)))
/****************************************************************************
* Includes
x264_cqm_jvt8i, x264_cqm_jvt8p
};
+// 1080i25_avci50, 1080p25_avci50
+static const uint8_t x264_cqm_avci50_4ic[16] =
+{
+ 16,22,28,40,
+ 22,28,40,44,
+ 28,40,44,48,
+ 40,44,48,60
+};
+
+// 1080i25_avci50,
+static const uint8_t x264_cqm_avci50_1080i_8iy[64] =
+{
+ 16,18,19,21,27,33,81,87,
+ 18,19,21,24,30,33,81,87,
+ 19,21,24,27,30,78,84,90,
+ 21,24,27,30,33,78,84,90,
+ 24,27,30,33,78,81,84,90,
+ 24,27,30,33,78,81,84,93,
+ 27,30,33,78,78,81,87,93,
+ 30,33,33,78,81,84,87,96
+};
+
+// 1080p25_avci50, 720p25_avci50, 720p50_avci50
+static const uint8_t x264_cqm_avci50_p_8iy[64] =
+{
+ 16,18,19,21,24,27,30,33,
+ 18,19,21,24,27,30,33,78,
+ 19,21,24,27,30,33,78,81,
+ 21,24,27,30,33,78,81,84,
+ 24,27,30,33,78,81,84,87,
+ 27,30,33,78,81,84,87,90,
+ 30,33,78,81,84,87,90,93,
+ 33,78,81,84,87,90,93,96
+};
+
+// 1080i25_avci100, 1080p25_avci100
+static const uint8_t x264_cqm_avci100_1080_4ic[16] =
+{
+ 16,20,26,32,
+ 20,26,32,38,
+ 26,32,38,44,
+ 32,38,44,50
+};
+
+// 720p25_avci100, 720p50_avci100
+static const uint8_t x264_cqm_avci100_720p_4ic[16] =
+{
+ 16,21,27,34,
+ 21,27,34,41,
+ 27,34,41,46,
+ 34,41,46,54
+};
+
+// 1080i25_avci100,
+static const uint8_t x264_cqm_avci100_1080i_8iy[64] =
+{
+ 16,19,20,23,24,26,32,42,
+ 18,19,22,24,26,32,36,42,
+ 18,20,23,24,26,32,36,63,
+ 19,20,23,26,32,36,42,63,
+ 20,22,24,26,32,36,59,63,
+ 22,23,24,26,32,36,59,68,
+ 22,23,24,26,32,42,59,68,
+ 22,23,24,26,36,42,59,72
+};
+
+// 1080p25_avci100,
+static const uint8_t x264_cqm_avci100_1080p_8iy[64] =
+{
+ 16,18,19,20,22,23,24,26,
+ 18,19,20,22,23,24,26,32,
+ 19,20,22,23,24,26,32,36,
+ 20,22,23,24,26,32,36,42,
+ 22,23,24,26,32,36,42,59,
+ 23,24,26,32,36,42,59,63,
+ 24,26,32,36,42,59,63,68,
+ 26,32,36,42,59,63,68,72
+};
+
+// 720p25_avci100, 720p50_avci100
+static const uint8_t x264_cqm_avci100_720p_8iy[64] =
+{
+ 16,18,19,21,22,24,26,32,
+ 18,19,19,21,22,24,26,32,
+ 19,19,21,22,22,24,26,32,
+ 21,21,22,22,23,24,26,34,
+ 22,22,22,23,24,25,26,34,
+ 24,24,24,24,25,26,34,36,
+ 26,26,26,26,26,34,36,38,
+ 32,32,32,34,34,36,38,42
+};
+
int x264_cqm_init( x264_t *h );
void x264_cqm_delete( x264_t *h );
int x264_cqm_parse_file( x264_t *h, const char *filename );
/* non-RD PCM decision is inaccurate (as is psy-rd), so don't do it.
* PCM cost can overflow with high lambda2, so cap it at COST_MAX. */
uint64_t pcm_cost = ((uint64_t)X264_PCM_COST*a->i_lambda2 + 128) >> 8;
- a->i_satd_pcm = !h->mb.i_psy_rd && a->i_mbrd && pcm_cost < COST_MAX ? pcm_cost : COST_MAX;
+ a->i_satd_pcm = !h->param.b_avcintra_compat && !h->mb.i_psy_rd && a->i_mbrd && pcm_cost < COST_MAX ? pcm_cost : COST_MAX;
a->b_fast_intra = 0;
a->b_avoid_topright = 0;
int lambda = a->i_lambda;
/*---------------- Try all mode and calculate their score ---------------*/
-
- /* 16x16 prediction selection */
- const int8_t *predict_mode = predict_16x16_mode_available( h->mb.i_neighbour_intra );
-
- /* Not heavily tuned */
- static const uint8_t i16x16_thresh_lut[11] = { 2, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4 };
- int i16x16_thresh = a->b_fast_intra ? (i16x16_thresh_lut[h->mb.i_subpel_refine]*i_satd_inter)>>1 : COST_MAX;
-
- if( !h->mb.b_lossless && predict_mode[3] >= 0 )
+ /* Disabled i16x16 for AVC-Intra compat */
+ if( !h->param.b_avcintra_compat )
{
- h->pixf.intra_mbcmp_x3_16x16( p_src, p_dst, a->i_satd_i16x16_dir );
- a->i_satd_i16x16_dir[0] += lambda * bs_size_ue(0);
- a->i_satd_i16x16_dir[1] += lambda * bs_size_ue(1);
- a->i_satd_i16x16_dir[2] += lambda * bs_size_ue(2);
- COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[0], a->i_predict16x16, 0 );
- COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[1], a->i_predict16x16, 1 );
- COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[2], a->i_predict16x16, 2 );
+ const int8_t *predict_mode = predict_16x16_mode_available( h->mb.i_neighbour_intra );
- /* Plane is expensive, so don't check it unless one of the previous modes was useful. */
- if( a->i_satd_i16x16 <= i16x16_thresh )
+ /* Not heavily tuned */
+ static const uint8_t i16x16_thresh_lut[11] = { 2, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4 };
+ int i16x16_thresh = a->b_fast_intra ? (i16x16_thresh_lut[h->mb.i_subpel_refine]*i_satd_inter)>>1 : COST_MAX;
+
+ if( !h->mb.b_lossless && predict_mode[3] >= 0 )
{
- h->predict_16x16[I_PRED_16x16_P]( p_dst );
- a->i_satd_i16x16_dir[I_PRED_16x16_P] = h->pixf.mbcmp[PIXEL_16x16]( p_dst, FDEC_STRIDE, p_src, FENC_STRIDE );
- a->i_satd_i16x16_dir[I_PRED_16x16_P] += lambda * bs_size_ue(3);
- COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[I_PRED_16x16_P], a->i_predict16x16, 3 );
+ h->pixf.intra_mbcmp_x3_16x16( p_src, p_dst, a->i_satd_i16x16_dir );
+ a->i_satd_i16x16_dir[0] += lambda * bs_size_ue(0);
+ a->i_satd_i16x16_dir[1] += lambda * bs_size_ue(1);
+ a->i_satd_i16x16_dir[2] += lambda * bs_size_ue(2);
+ COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[0], a->i_predict16x16, 0 );
+ COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[1], a->i_predict16x16, 1 );
+ COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[2], a->i_predict16x16, 2 );
+
+ /* Plane is expensive, so don't check it unless one of the previous modes was useful. */
+ if( a->i_satd_i16x16 <= i16x16_thresh )
+ {
+ h->predict_16x16[I_PRED_16x16_P]( p_dst );
+ a->i_satd_i16x16_dir[I_PRED_16x16_P] = h->pixf.mbcmp[PIXEL_16x16]( p_dst, FDEC_STRIDE, p_src, FENC_STRIDE );
+ a->i_satd_i16x16_dir[I_PRED_16x16_P] += lambda * bs_size_ue(3);
+ COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[I_PRED_16x16_P], a->i_predict16x16, 3 );
+ }
}
- }
- else
- {
- for( ; *predict_mode >= 0; predict_mode++ )
+ else
{
- int i_satd;
- int i_mode = *predict_mode;
+ for( ; *predict_mode >= 0; predict_mode++ )
+ {
+ int i_satd;
+ int i_mode = *predict_mode;
- if( h->mb.b_lossless )
- x264_predict_lossless_16x16( h, 0, i_mode );
- else
- h->predict_16x16[i_mode]( p_dst );
+ if( h->mb.b_lossless )
+ x264_predict_lossless_16x16( h, 0, i_mode );
+ else
+ h->predict_16x16[i_mode]( p_dst );
- i_satd = h->pixf.mbcmp[PIXEL_16x16]( p_dst, FDEC_STRIDE, p_src, FENC_STRIDE ) +
- lambda * bs_size_ue( x264_mb_pred_mode16x16_fix[i_mode] );
- COPY2_IF_LT( a->i_satd_i16x16, i_satd, a->i_predict16x16, i_mode );
- a->i_satd_i16x16_dir[i_mode] = i_satd;
+ i_satd = h->pixf.mbcmp[PIXEL_16x16]( p_dst, FDEC_STRIDE, p_src, FENC_STRIDE ) +
+ lambda * bs_size_ue( x264_mb_pred_mode16x16_fix[i_mode] );
+ COPY2_IF_LT( a->i_satd_i16x16, i_satd, a->i_predict16x16, i_mode );
+ a->i_satd_i16x16_dir[i_mode] = i_satd;
+ }
}
- }
- if( h->sh.i_type == SLICE_TYPE_B )
- /* cavlc mb type prefix */
- a->i_satd_i16x16 += lambda * i_mb_b_cost_table[I_16x16];
+ if( h->sh.i_type == SLICE_TYPE_B )
+ /* cavlc mb type prefix */
+ a->i_satd_i16x16 += lambda * i_mb_b_cost_table[I_16x16];
- if( a->i_satd_i16x16 > i16x16_thresh )
- return;
+ if( a->i_satd_i16x16 > i16x16_thresh )
+ return;
+ }
uint16_t *cost_i4x4_mode = (uint16_t*)ALIGN((intptr_t)x264_cost_i4x4_mode,64) + a->i_qp*32 + 8;
/* 8x8 prediction selection */
int i_best = COST_MAX;
int i_pred_mode = x264_mb_predict_intra4x4_mode( h, 4*idx );
- predict_mode = predict_8x8_mode_available( a->b_avoid_topright, h->mb.i_neighbour8[idx], idx );
+ const int8_t *predict_mode = predict_8x8_mode_available( a->b_avoid_topright, h->mb.i_neighbour8[idx], idx );
h->predict_8x8_filter( p_dst_by, edge, h->mb.i_neighbour8[idx], ALL_NEIGHBORS );
if( h->pixf.intra_mbcmp_x9_8x8 && predict_mode[8] >= 0 )
int i_best = COST_MAX;
int i_pred_mode = x264_mb_predict_intra4x4_mode( h, idx );
- predict_mode = predict_4x4_mode_available( a->b_avoid_topright, h->mb.i_neighbour4[idx], idx );
+ const int8_t *predict_mode = predict_4x4_mode_available( a->b_avoid_topright, h->mb.i_neighbour4[idx], idx );
if( (h->mb.i_neighbour4[idx] & (MB_TOPRIGHT|MB_TOP)) == MB_TOP )
/* emulate missing topright samples */
{
h->param.b_intra_refresh = 0;
h->param.analyse.i_weighted_pred = 0;
+ h->param.i_frame_reference = 1;
+ h->param.i_dpb_size = 1;
}
h->param.i_frame_packing = x264_clip3( h->param.i_frame_packing, -1, 5 );
x264_log( h, X264_LOG_ERROR, "no ratecontrol method specified\n" );
return -1;
}
+
+ if( PARAM_INTERLACED )
+ h->param.b_pic_struct = 1;
+
+ if( h->param.b_avcintra_compat )
+ {
+ if( BIT_DEPTH != 10 )
+ {
+ x264_log( h, X264_LOG_ERROR, "%2d-bit AVC-Intra is not widely compatible\n", BIT_DEPTH );
+ x264_log( h, X264_LOG_ERROR, "10-bit x264 is required to encode AVC-Intra\n" );
+ return -1;
+ }
+
+ /* [50/100][res][fps] */
+ static const struct
+ {
+ uint16_t fps_num;
+ uint16_t fps_den;
+ uint8_t interlaced;
+ uint16_t frame_size;
+ const uint8_t *cqm_4ic;
+ const uint8_t *cqm_8iy;
+ } avcintra_lut[2][2][5] =
+ {
+ {{{ 60000, 1001, 0, 912, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy },
+ { 50, 1, 0, 1100, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy },
+ { 30000, 1001, 0, 912, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy },
+ { 25, 1, 0, 1100, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy },
+ { 24000, 1001, 0, 912, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }},
+ {{ 30000, 1001, 1, 1820, x264_cqm_avci50_4ic, x264_cqm_avci50_1080i_8iy },
+ { 25, 1, 1, 2196, x264_cqm_avci50_4ic, x264_cqm_avci50_1080i_8iy },
+ { 30000, 1001, 0, 1820, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy },
+ { 25, 1, 0, 2196, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy },
+ { 24000, 1001, 0, 1820, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }}},
+ {{{ 60000, 1001, 0, 1848, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy },
+ { 50, 1, 0, 2224, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy },
+ { 30000, 1001, 0, 1848, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy },
+ { 25, 1, 0, 2224, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy },
+ { 24000, 1001, 0, 1848, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy }},
+ {{ 30000, 1001, 1, 3692, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080i_8iy },
+ { 25, 1, 1, 4444, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080i_8iy },
+ { 30000, 1001, 0, 3692, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 25, 1, 0, 4444, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 24000, 1001, 0, 3692, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }}}
+ };
+
+ int res = -1;
+ int type = i_csp == X264_CSP_I422;
+ if( type )
+ {
+ if( h->param.i_width == 1920 && h->param.i_height == 1080 ) res = 1;
+ else if( h->param.i_width == 1280 && h->param.i_height == 720 ) res = 0;
+ }
+ else if( i_csp == X264_CSP_I420 )
+ {
+ if( h->param.i_width == 1440 && h->param.i_height == 1080 ) res = 1;
+ else if( h->param.i_width == 960 && h->param.i_height == 720 ) res = 0;
+ }
+ else
+ {
+ x264_log( h, X264_LOG_ERROR, "Invalid colorspace for AVC-Intra\n" );
+ return -1;
+ }
+
+ if( res < 0 )
+ {
+ x264_log( h, X264_LOG_ERROR, "Resolution %dx%d invalid for AVC-Intra %s\n",
+ h->param.i_width, h->param.i_height, type ? "100" : "50" );
+ return -1;
+ }
+
+ if( h->param.nalu_process )
+ {
+ x264_log( h, X264_LOG_ERROR, "nalu_process is not supported in AVC-Intra mode\n" );
+ return -1;
+ }
+
+ if( !h->param.b_repeat_headers )
+ {
+ x264_log( h, X264_LOG_ERROR, "Separate headers not supported in AVC-Intra mode\n" );
+ return -1;
+ }
+
+ int i;
+ uint32_t fps_num = h->param.i_fps_num, fps_den = h->param.i_fps_den;
+ x264_reduce_fraction( &fps_num, &fps_den );
+ for( i = 0; i < 5; i++ )
+ {
+ if( avcintra_lut[type][res][i].fps_num == fps_num &&
+ avcintra_lut[type][res][i].fps_den == fps_den &&
+ avcintra_lut[type][res][i].interlaced == PARAM_INTERLACED )
+ {
+ break;
+ }
+ }
+ if( i == 5 )
+ {
+ x264_log( h, X264_LOG_ERROR, "FPS %d/%d%c not compatible with AVC-Intra\n",
+ h->param.i_fps_num, h->param.i_fps_den, PARAM_INTERLACED ? 'i' : 'p' );
+ return -1;
+ }
+
+ h->param.i_keyint_max = 1;
+ h->param.b_intra_refresh = 0;
+ h->param.analyse.i_weighted_pred = 0;
+ h->param.i_frame_reference = 1;
+ h->param.i_dpb_size = 1;
+
+ h->param.b_bluray_compat = 0;
+ h->param.b_vfr_input = 0;
+ h->param.b_aud = 1;
+ h->param.vui.i_chroma_loc = 0;
+ h->param.i_nal_hrd = X264_NAL_HRD_NONE;
+ h->param.b_deblocking_filter = 0;
+ h->param.b_stitchable = 1;
+ h->param.b_pic_struct = 0;
+ h->param.analyse.b_transform_8x8 = 1;
+ h->param.analyse.intra = X264_ANALYSE_I8x8;
+ h->param.analyse.i_chroma_qp_offset = res && type ? 3 : 4;
+ h->param.b_cabac = !type;
+ h->param.rc.i_vbv_buffer_size = avcintra_lut[type][res][i].frame_size;
+ h->param.rc.i_vbv_max_bitrate =
+ h->param.rc.i_bitrate = h->param.rc.i_vbv_buffer_size * fps_num / fps_den;
+ h->param.rc.i_rc_method = X264_RC_ABR;
+ h->param.rc.f_vbv_buffer_init = 1.0;
+ h->param.i_cqm_preset = X264_CQM_CUSTOM;
+ memcpy( h->param.cqm_4iy, x264_cqm_jvt4i, sizeof(h->param.cqm_4iy) );
+ memcpy( h->param.cqm_4ic, avcintra_lut[type][res][i].cqm_4ic, sizeof(h->param.cqm_4ic) );
+ memcpy( h->param.cqm_8iy, avcintra_lut[type][res][i].cqm_8iy, sizeof(h->param.cqm_8iy) );
+
+ /* Need exactly 10 slices of equal MB count... why? $deity knows... */
+ h->param.i_slice_max_mbs = ((h->param.i_width + 15) / 16) * ((h->param.i_height + 15) / 16) / 10;
+ h->param.i_slice_max_size = 0;
+ /* The slice structure only allows a maximum of 2 threads for 1080i/p
+ * and 1 or 5 threads for 720p */
+ if( h->param.b_sliced_threads )
+ {
+ if( res )
+ h->param.i_threads = X264_MIN( 2, h->param.i_threads );
+ else
+ {
+ h->param.i_threads = X264_MIN( 5, h->param.i_threads );
+ if( h->param.i_threads < 5 )
+ h->param.i_threads = 1;
+ }
+ }
+
+ if( type )
+ h->param.vui.i_sar_width = h->param.vui.i_sar_height = 1;
+ else
+ {
+ h->param.vui.i_sar_width = 4;
+ h->param.vui.i_sar_height = 3;
+ }
+
+ /* Avid cannot handle negative QPs */
+ h->param.rc.i_qp_min = X264_MAX( h->param.rc.i_qp_min, QP_BD_OFFSET );
+ }
+
h->param.rc.f_rf_constant = x264_clip3f( h->param.rc.f_rf_constant, -QP_BD_OFFSET, 51 );
h->param.rc.f_rf_constant_max = x264_clip3f( h->param.rc.f_rf_constant_max, -QP_BD_OFFSET, 51 );
h->param.rc.i_qp_constant = x264_clip3( h->param.rc.i_qp_constant, 0, QP_MAX );
h->param.analyse.i_chroma_qp_offset += 6;
/* Psy RDO increases overall quantizers to improve the quality of luma--this indirectly hurts chroma quality */
/* so we lower the chroma QP offset to compensate */
- if( b_open && h->mb.i_psy_rd )
+ if( b_open && h->mb.i_psy_rd && !h->param.b_avcintra_compat )
h->param.analyse.i_chroma_qp_offset -= h->param.analyse.f_psy_rd < 0.25 ? 1 : 2;
/* Psy trellis has a similar effect. */
- if( b_open && h->mb.i_psy_trellis )
+ if( b_open && h->mb.i_psy_trellis && !h->param.b_avcintra_compat )
h->param.analyse.i_chroma_qp_offset -= h->param.analyse.f_psy_trellis < 0.25 ? 1 : 2;
h->param.analyse.i_chroma_qp_offset = x264_clip3(h->param.analyse.i_chroma_qp_offset, -12, 12);
/* MB-tree requires AQ to be on, even if the strength is zero. */
h->param.i_sps_id &= 31;
- if( PARAM_INTERLACED )
- h->param.b_pic_struct = 1;
-
h->param.i_nal_hrd = x264_clip3( h->param.i_nal_hrd, X264_NAL_HRD_NONE, X264_NAL_HRD_CBR );
if( h->param.i_nal_hrd && !h->param.rc.i_vbv_buffer_size )
BOOLIFY( b_stitchable );
BOOLIFY( b_full_recon );
BOOLIFY( b_opencl );
+ BOOLIFY( b_avcintra_compat );
BOOLIFY( analyse.b_transform_8x8 );
BOOLIFY( analyse.b_weighted_bipred );
BOOLIFY( analyse.b_chroma_me );
nal->i_payload= 0;
nal->p_payload= &h->out.p_bitstream[bs_pos( &h->out.bs ) / 8];
+ nal->i_padding= 0;
}
/* if number of allocated nals is not enough, re-allocate a larger one. */
return x264_nal_check_buffer( h );
}
+static int x264_check_encapsulated_buffer( x264_t *h, x264_t *h0, int start,
+ int previous_nal_size, int necessary_size )
+{
+ if( h0->nal_buffer_size < necessary_size )
+ {
+ necessary_size *= 2;
+ uint8_t *buf = x264_malloc( necessary_size );
+ if( !buf )
+ return -1;
+ if( previous_nal_size )
+ memcpy( buf, h0->nal_buffer, previous_nal_size );
+
+ intptr_t delta = buf - h0->nal_buffer;
+ for( int i = 0; i < start; i++ )
+ h->out.nal[i].p_payload += delta;
+
+ x264_free( h0->nal_buffer );
+ h0->nal_buffer = buf;
+ h0->nal_buffer_size = necessary_size;
+ }
+
+ return 0;
+}
+
static int x264_encoder_encapsulate_nals( x264_t *h, int start )
{
x264_t *h0 = h->thread[0];
/* Worst-case NAL unit escaping: reallocate the buffer if it's too small. */
int necessary_size = previous_nal_size + nal_size * 3/2 + h->out.i_nal * 4 + 4 + 64;
- if( h0->nal_buffer_size < necessary_size )
- {
- necessary_size *= 2;
- uint8_t *buf = x264_malloc( necessary_size );
- if( !buf )
- return -1;
- if( previous_nal_size )
- memcpy( buf, h0->nal_buffer, previous_nal_size );
-
- intptr_t delta = buf - h0->nal_buffer;
- for( int i = 0; i < start; i++ )
- h->out.nal[i].p_payload += delta;
-
- x264_free( h0->nal_buffer );
- h0->nal_buffer = buf;
- h0->nal_buffer_size = necessary_size;
- }
+ for( int i = start; i < h->out.i_nal; i++ )
+ necessary_size += h->out.nal[i].i_padding;
+ if( x264_check_encapsulated_buffer( h, h0, start, previous_nal_size, necessary_size ) )
+ return -1;
uint8_t *nal_buffer = h0->nal_buffer + previous_nal_size;
for( int i = start; i < h->out.i_nal; i++ )
{
- h->out.nal[i].b_long_startcode = !i || h->out.nal[i].i_type == NAL_SPS || h->out.nal[i].i_type == NAL_PPS;
+ int old_payload_len = h->out.nal[i].i_payload;
+ h->out.nal[i].b_long_startcode = !i || h->out.nal[i].i_type == NAL_SPS || h->out.nal[i].i_type == NAL_PPS ||
+ h->param.b_avcintra_compat;
x264_nal_encode( h, nal_buffer, &h->out.nal[i] );
nal_buffer += h->out.nal[i].i_payload;
+ if( h->param.b_avcintra_compat )
+ {
+ h->out.nal[i].i_padding -= h->out.nal[i].i_payload - (old_payload_len + NALU_OVERHEAD);
+ if( h->out.nal[i].i_padding > 0 )
+ {
+ memset( nal_buffer, 0, h->out.nal[i].i_padding );
+ nal_buffer += h->out.nal[i].i_padding;
+ h->out.nal[i].i_payload += h->out.nal[i].i_padding;
+ }
+ h->out.nal[i].i_padding = X264_MAX( h->out.nal[i].i_padding, 0 );
+ }
}
x264_emms();
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);
+ overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;
}
h->i_nal_type = i_nal_type;
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;
+ /* Pad AUD/SPS to 256 bytes like Panasonic */
+ if( h->param.b_avcintra_compat )
+ h->out.nal[h->out.i_nal-1].i_padding = 256 - bs_pos( &h->out.bs ) / 8 - 2*NALU_OVERHEAD;
+ overhead += h->out.nal[h->out.i_nal-1].i_payload + h->out.nal[h->out.i_nal-1].i_padding + 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;
+ if( h->param.b_avcintra_compat )
+ h->out.nal[h->out.i_nal-1].i_padding = 256 - h->out.nal[h->out.i_nal-1].i_payload - NALU_OVERHEAD;
+ overhead += h->out.nal[h->out.i_nal-1].i_payload + h->out.nal[h->out.i_nal-1].i_padding + NALU_OVERHEAD;
}
/* when frame threading is used, buffering period sei is written in x264_encoder_frame_end */
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;
+ overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD;
}
}
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);
+ overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD;
if( h->fenc->extra_sei.sei_free )
{
h->fenc->extra_sei.sei_free( h->fenc->extra_sei.payloads[i].payload );
if( h->fenc->b_keyframe )
{
- if( h->param.b_repeat_headers && h->fenc->i_frame == 0 )
+ /* Avid's decoder strictly wants two SEIs for AVC-Intra so we can't insert the x264 SEI */
+ if( h->param.b_repeat_headers && h->fenc->i_frame == 0 && !h->param.b_avcintra_compat )
{
/* identify ourself */
x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
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);
+ overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD;
}
if( h->fenc->i_type != X264_TYPE_IDR )
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);
+ overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD;
}
- if ( h->param.i_frame_packing >= 0 )
+ 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);
+ overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD;
}
}
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);
+ overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD;
}
/* As required by Blu-ray. */
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);
+ overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD;
}
if( h->fenc->b_keyframe && h->param.b_intra_refresh )
h->i_cpb_delay_pir_offset_next = h->fenc->i_cpb_delay;
+ /* Filler space: 10 or 18 SEIs' worth of space, depending on resolution */
+ if( h->param.b_avcintra_compat )
+ {
+ /* Write an empty filler NAL to mimic the AUD in the P2 format*/
+ if( h->param.b_avcintra_compat )
+ {
+ x264_nal_start( h, NAL_FILLER, NAL_PRIORITY_DISPOSABLE );
+ x264_filler_write( h, &h->out.bs, 0 );
+ if( x264_nal_end( h ) )
+ return -1;
+ overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;
+ }
+
+ /* All lengths are magic lengths that decoders expect to see */
+ /* "UMID" SEI */
+ x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
+ if( x264_sei_avcintra_write( h, &h->out.bs, 497, "UMID" ) < 0 )
+ return -1;
+ if( x264_nal_end( h ) )
+ return -1;
+ overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD;
+
+
+ int unpadded_len;
+ int total_len;
+ if( h->param.i_height == 1080 )
+ {
+ unpadded_len = 5780;
+ total_len = 17*512;
+ }
+ else
+ {
+ unpadded_len = 2900;
+ total_len = 9*512;
+ }
+ /* "VANC" SEI */
+ x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
+ if( x264_sei_avcintra_write( h, &h->out.bs, unpadded_len, "VANC" ) < 0 )
+ return -1;
+ if( x264_nal_end( h ) )
+ return -1;
+
+ h->out.nal[h->out.i_nal-1].i_padding = total_len - h->out.nal[h->out.i_nal-1].i_payload - SEI_OVERHEAD;
+ overhead += h->out.nal[h->out.i_nal-1].i_payload + h->out.nal[h->out.i_nal-1].i_padding + SEI_OVERHEAD;
+ }
+
/* Init the rate control */
/* FIXME: Include slice header bit cost. */
x264_ratecontrol_start( h, h->fenc->i_qpplus1, overhead*8 );
pic_out->hrd_timing = h->fenc->hrd_timing;
pic_out->prop.f_crf_avg = h->fdec->f_crf_avg;
- while( filler > 0 )
+ /* Filler in AVC-Intra mode is written as zero bytes to the last slice
+ * We don't know the size of the last slice until encapsulation so we add filler to the encapsulated NAL */
+ if( h->param.b_avcintra_compat )
+ {
+ x264_t *h0 = h->thread[0];
+ int ret = x264_check_encapsulated_buffer( h, h0, h->out.i_nal, frame_size, frame_size + filler );
+ if( ret < 0 )
+ return -1;
+ memset( h->out.nal[0].p_payload + frame_size, 0, filler );
+ h->out.nal[h->out.i_nal-1].i_payload += filler;
+ h->out.nal[h->out.i_nal-1].i_padding = filler;
+ frame_size += filler;
+ }
+ else
{
- int f, overhead;
- overhead = (FILLER_OVERHEAD - h->param.b_annexb);
- if( h->param.i_slice_max_size && filler > h->param.i_slice_max_size )
+ while( filler > 0 )
{
- int next_size = filler - h->param.i_slice_max_size;
- int overflow = X264_MAX( overhead - next_size, 0 );
- f = h->param.i_slice_max_size - overhead - overflow;
- }
- else
- f = X264_MAX( 0, filler - overhead );
+ int f, overhead;
+ overhead = (FILLER_OVERHEAD - h->param.b_annexb);
+ if( h->param.i_slice_max_size && filler > h->param.i_slice_max_size )
+ {
+ int next_size = filler - h->param.i_slice_max_size;
+ int overflow = X264_MAX( overhead - next_size, 0 );
+ f = h->param.i_slice_max_size - overhead - overflow;
+ }
+ else
+ f = X264_MAX( 0, filler - overhead );
- if( x264_bitstream_check_buffer_filler( h, f ) )
- return -1;
- x264_nal_start( h, NAL_FILLER, NAL_PRIORITY_DISPOSABLE );
- x264_filler_write( h, &h->out.bs, f );
- if( x264_nal_end( h ) )
- return -1;
- int total_size = x264_encoder_encapsulate_nals( h, h->out.i_nal-1 );
- if( total_size < 0 )
- return -1;
- frame_size += total_size;
- filler -= total_size;
+ if( x264_bitstream_check_buffer_filler( h, f ) )
+ return -1;
+ x264_nal_start( h, NAL_FILLER, NAL_PRIORITY_DISPOSABLE );
+ x264_filler_write( h, &h->out.bs, f );
+ if( x264_nal_end( h ) )
+ return -1;
+ int total_size = x264_encoder_encapsulate_nals( h, h->out.i_nal-1 );
+ if( total_size < 0 )
+ return -1;
+ frame_size += total_size;
+ filler -= total_size;
+ }
}
/* End bitstream, set output */
h->param.rc.i_vbv_buffer_size );
}
- int vbv_buffer_size = h->param.rc.i_vbv_buffer_size * 1000;
- int vbv_max_bitrate = h->param.rc.i_vbv_max_bitrate * 1000;
+ int kilobit_size = h->param.b_avcintra_compat ? 1024 : 1000;
+ int vbv_buffer_size = h->param.rc.i_vbv_buffer_size * kilobit_size;
+ int vbv_max_bitrate = h->param.rc.i_vbv_max_bitrate * kilobit_size;
/* Init HRD */
if( h->param.i_nal_hrd && b_init )
#define BR_SHIFT 6
#define CPB_SHIFT 4
- int bitrate = 1000*h->param.rc.i_vbv_max_bitrate;
- int bufsize = 1000*h->param.rc.i_vbv_buffer_size;
-
// normalize HRD size and rate to the value / scale notation
- h->sps->vui.hrd.i_bit_rate_scale = x264_clip3( x264_ctz( bitrate ) - BR_SHIFT, 0, 15 );
- h->sps->vui.hrd.i_bit_rate_value = bitrate >> ( h->sps->vui.hrd.i_bit_rate_scale + BR_SHIFT );
+ h->sps->vui.hrd.i_bit_rate_scale = x264_clip3( x264_ctz( vbv_max_bitrate ) - BR_SHIFT, 0, 15 );
+ h->sps->vui.hrd.i_bit_rate_value = vbv_max_bitrate >> ( h->sps->vui.hrd.i_bit_rate_scale + BR_SHIFT );
h->sps->vui.hrd.i_bit_rate_unscaled = h->sps->vui.hrd.i_bit_rate_value << ( h->sps->vui.hrd.i_bit_rate_scale + BR_SHIFT );
- h->sps->vui.hrd.i_cpb_size_scale = x264_clip3( x264_ctz( bufsize ) - CPB_SHIFT, 0, 15 );
- h->sps->vui.hrd.i_cpb_size_value = bufsize >> ( h->sps->vui.hrd.i_cpb_size_scale + CPB_SHIFT );
+ h->sps->vui.hrd.i_cpb_size_scale = x264_clip3( x264_ctz( vbv_buffer_size ) - CPB_SHIFT, 0, 15 );
+ h->sps->vui.hrd.i_cpb_size_value = vbv_buffer_size >> ( h->sps->vui.hrd.i_cpb_size_scale + CPB_SHIFT );
h->sps->vui.hrd.i_cpb_size_unscaled = h->sps->vui.hrd.i_cpb_size_value << ( h->sps->vui.hrd.i_cpb_size_scale + CPB_SHIFT );
#undef CPB_SHIFT
x264_log( h, X264_LOG_WARNING, "VBV parameters cannot be changed when NAL HRD is in use\n" );
return;
}
+ if( h->param.b_avcintra_compat )
+ h->sps->vui.hrd.b_cbr_hrd = 1;
h->sps->vui.hrd.i_bit_rate_unscaled = vbv_max_bitrate;
h->sps->vui.hrd.i_cpb_size_unscaled = vbv_buffer_size;
if( rc->b_vbv_min_rate )
- rc->bitrate = h->param.rc.i_bitrate * 1000.;
+ rc->bitrate = (double)h->param.rc.i_bitrate * kilobit_size;
rc->buffer_rate = vbv_max_bitrate / rc->fps;
rc->vbv_max_rate = vbv_max_bitrate;
rc->buffer_size = vbv_buffer_size;
else
rc->qcompress = h->param.rc.f_qcompress;
- rc->bitrate = h->param.rc.i_bitrate * 1000.;
+ rc->bitrate = h->param.rc.i_bitrate * (h->param.b_avcintra_compat ? 1024. : 1000.);
rc->rate_tolerance = h->param.rc.f_rate_tolerance;
rc->nmb = h->mb.i_mb_count;
rc->last_non_b_pict_type = -1;
if( rct->buffer_fill_final < 0 )
x264_log( h, X264_LOG_WARNING, "VBV underflow (frame %d, %.0f bits)\n", h->i_frame, (double)rct->buffer_fill_final / h->sps->vui.i_time_scale );
rct->buffer_fill_final = X264_MAX( rct->buffer_fill_final, 0 );
- rct->buffer_fill_final += (uint64_t)bitrate * h->sps->vui.i_num_units_in_tick * h->fenc->i_cpb_duration;
+
+ if( h->param.b_avcintra_compat )
+ rct->buffer_fill_final += buffer_size;
+ else
+ rct->buffer_fill_final += (uint64_t)bitrate * h->sps->vui.i_num_units_in_tick * h->fenc->i_cpb_duration;
if( h->sps->vui.hrd.b_cbr_hrd && rct->buffer_fill_final > buffer_size )
{
int64_t scale = (int64_t)h->sps->vui.i_time_scale * 8;
filler = (rct->buffer_fill_final - buffer_size + scale - 1) / scale;
- bits = X264_MAX( (FILLER_OVERHEAD - h->param.b_annexb), filler ) * 8;
+ bits = h->param.b_avcintra_compat ? filler * 8 : X264_MAX( (FILLER_OVERHEAD - h->param.b_annexb), filler ) * 8;
rct->buffer_fill_final -= (uint64_t)bits * h->sps->vui.i_time_scale;
}
else
bs_write( s, 8, payload_size-i );
for( i = 0; i < payload_size; i++ )
- bs_write(s, 8, payload[i] );
+ bs_write( s, 8, payload[i] );
bs_rbsp_trailing( s );
bs_flush( s );
// NOTE: HRD related parts of the SPS are initialised in x264_ratecontrol_init_reconfigurable
- sps->vui.b_bitstream_restriction = 1;
+ sps->vui.b_bitstream_restriction = param->i_keyint_max > 1;
if( sps->vui.b_bitstream_restriction )
{
sps->vui.b_motion_vectors_over_pic_boundaries = 1;
pps->i_sps_id = sps->i_id;
pps->b_cabac = param->b_cabac;
- pps->b_pic_order = param->b_interlaced;
+ pps->b_pic_order = !param->b_avcintra_compat && param->b_interlaced;
pps->i_num_slice_groups = 1;
pps->i_num_ref_idx_l0_default_active = param->i_frame_reference;
x264_sei_write( s, tmp_buf, bs_pos( &q ) / 8, SEI_DEC_REF_PIC_MARKING );
}
+int x264_sei_avcintra_write( x264_t *h, bs_t *s, int len, const char *msg )
+{
+ const static uint8_t avcintra_uuid[] = {0xF7, 0x49, 0x3E, 0xB3, 0xD4, 0x00, 0x47, 0x96, 0x86, 0x86, 0xC9, 0x70, 0x7B, 0x64, 0x37, 0x2A};
+ uint8_t data[6000];
+ if( len > sizeof(data) )
+ {
+ x264_log( h, X264_LOG_ERROR, "AVC-Intra SEI is too large (%d)\n", len );
+ return -1;
+ }
+
+ memset( data, 0xff, len );
+ memcpy( data, avcintra_uuid, sizeof(avcintra_uuid) );
+ memcpy( data+16, msg, strlen(msg) );
+
+ x264_sei_write( &h->out.bs, data, len, SEI_USER_DATA_UNREGISTERED );
+
+ return 0;
+}
+
const x264_level_t x264_levels[] =
{
{ 10, 1485, 99, 396, 64, 175, 64, 64, 0, 2, 0, 0, 1 },
void x264_sei_pic_timing_write( x264_t *h, bs_t *s );
void x264_sei_dec_ref_pic_marking_write( x264_t *h, bs_t *s );
void x264_sei_frame_packing_write( x264_t *h, bs_t *s );
+int x264_sei_avcintra_write( x264_t *h, bs_t *s, int len, const char *msg );
void x264_sei_write( bs_t *s, uint8_t *payload, int payload_size, int payload_type );
void x264_filler_write( x264_t *h, bs_t *s, int filler );
H0( " --frames <integer> Maximum number of frames to encode\n" );
H0( " --level <string> Specify level (as defined by Annex A)\n" );
H1( " --bluray-compat Enable compatibility hacks for Blu-ray support\n" );
+ H1( " --avcintra-compat Enable compatibility hacks for AVC-Intra support\n" );
H1( " --stitchable Don't optimize headers based on video content\n"
" Ensures ability to recombine a segmented encode\n" );
H1( "\n" );
H2( " --no-asm Disable all CPU optimizations\n" );
H2( " --opencl Enable use of OpenCL\n" );
H2( " --opencl-clbin <string> Specify path of compiled OpenCL kernel cache\n" );
- H2( " --opencl-device <integer> Specify OpenCL device ordinal\n" );
+ H2( " --opencl-device <integer> Specify OpenCL device ordinal\n" );
H2( " --visualize Show MB types overlayed on the encoded video\n" );
H2( " --dump-yuv <string> Save reconstructed frames\n" );
H2( " --sps-id <integer> Set SPS and PPS id numbers [%d]\n", defaults->i_sps_id );
{ "b-pyramid", required_argument, NULL, 0 },
{ "open-gop", no_argument, NULL, 0 },
{ "bluray-compat", no_argument, NULL, 0 },
+ { "avcintra-compat", no_argument, NULL, 0 },
{ "min-keyint", required_argument, NULL, 'i' },
{ "keyint", required_argument, NULL, 'I' },
{ "intra-refresh", no_argument, NULL, 0 },
#include "x264_config.h"
-#define X264_BUILD 136
+#define X264_BUILD 137
/* Application developers planning to link against a shared library version of
* libx264 from a Microsoft Visual Studio or similar development environment
int i_first_mb; /* If this NAL is a slice, the index of the first MB in the slice. */
int i_last_mb; /* If this NAL is a slice, the index of the last MB in the slice. */
- /* Size of payload in bytes. */
+ /* Size of payload (including any padding) in bytes. */
int i_payload;
/* If param->b_annexb is set, Annex-B bytestream with startcode.
* Otherwise, startcode is replaced with a 4-byte size.
* This size is the size used in mp4/similar muxing; it is equal to i_payload-4 */
uint8_t *p_payload;
+
+ /* Size of padding in bytes. */
+ int i_padding;
} x264_nal_t;
/****************************************************************************
int i_bframe_pyramid; /* Keep some B-frames as references: 0=off, 1=strict hierarchical, 2=normal */
int b_open_gop;
int b_bluray_compat;
+ int b_avcintra_compat;
int b_deblocking_filter;
int i_deblocking_filter_alphac0; /* [-6, 6] -6 light filter, 6 strong */