static void load_headers(struct obs_x264 *obsx264) { x264_nal_t *nals; int nal_count; DARRAY(uint8_t) header; DARRAY(uint8_t) sei; da_init(header); da_init(sei); x264_encoder_headers(obsx264->context, &nals, &nal_count); for (int i = 0; i < nal_count; i++) { x264_nal_t *nal = nals+i; if (nal->i_type == NAL_SEI) da_push_back_array(sei, nal->p_payload, nal->i_payload); else da_push_back_array(header, nal->p_payload, nal->i_payload); } obsx264->extra_data = header.array; obsx264->extra_data_size = header.num; obsx264->sei = sei.array; obsx264->sei_size = sei.num; }
void encode_spspps() { int i = 0; int i_nal = 0; x264_nal_t* p_nal = NULL; if (x264_encoder_headers(x264_encode.handle, &p_nal, &i_nal) < 0) CAP_DBG_EXIT("x264_encoder_headers error!\n"); for (i = 0; i < i_nal; i++) { if (p_nal[i].i_type == 7) { //sps spslen = p_nal[i].i_payload - 4; memcpy(sps, p_nal[i].p_payload + 4, spslen); } else if (p_nal[i].i_type == 8) { //pps ppslen = p_nal[i].i_payload - 4; memcpy(pps, p_nal[i].p_payload + 4, ppslen); } } // ricann debug CAP_DBG("sps = %s, len = %d\n", sps, spslen); CAP_DBG("pps = %s, len = %d\n", sps, ppslen); // ricann todo //write(fd_write, sps, spslen); //write(fd_write, pps, ppslen); }
uint8_t* video_encoder_get_headers(VideoEncoder *enc, int *bytesRead){ x264_nal_t *nal_scoop; int n_nal; int nbytes = x264_encoder_headers(enc->encoder,&nal_scoop,&n_nal); if(nbytes < 0){ fprintf(stderr,"x264_encoder_get_headers returns %d\n",nbytes); return NULL; } if(nbytes > enc->output_buffer_size){ fprintf( stderr, "buffer overflow: x264_encoder_get_headers returns %d bytes, greater than %d buffer size\n", nbytes,enc->output_buffer_size); return NULL; } int i; int read = 0; for(i=0; i < n_nal ; i++){ memcpy( &enc->output_buffer[read], nal_scoop[i].p_payload, nal_scoop[i].i_payload ); read += nal_scoop[i].i_payload; } *bytesRead = read; return enc->output_buffer; }
static int config(struct vf_instance *vf, int width, int height, int d_width, int d_height, unsigned int flags, unsigned int outfmt) { h264_module_t *mod=(h264_module_t*)vf->priv; if(parse_error) return 0; mod->mux->bih->biWidth = width; mod->mux->bih->biHeight = height; mod->mux->bih->biSizeImage = width * height * 3; mod->mux->aspect = (float)d_width/d_height; // make sure param is initialized x264enc_set_param(NULL, ""); param.i_width = width; param.i_height = height; param.i_fps_num = mod->mux->h.dwRate; param.i_fps_den = mod->mux->h.dwScale; param.b_vfr_input = 0; param.vui.i_sar_width = d_width*height; param.vui.i_sar_height = d_height*width; x264_param_parse(¶m, "stats", passtmpfile); switch(outfmt) { case IMGFMT_I420: param.i_csp = X264_CSP_I420; break; case IMGFMT_YV12: param.i_csp = X264_CSP_YV12; break; default: mp_msg(MSGT_MENCODER, MSGL_ERR, "Wrong colorspace.\n"); return 0; } mod->x264 = x264_encoder_open(¶m); if(!mod->x264) { mp_msg(MSGT_MENCODER, MSGL_ERR, "x264_encoder_open failed.\n"); return 0; } if(!param.b_repeat_headers){ x264_nal_t *nal; int extradata_size, nnal; extradata_size = x264_encoder_headers(mod->x264, &nal, &nnal); mod->mux->bih= realloc(mod->mux->bih, sizeof(*mod->mux->bih) + extradata_size); memcpy(mod->mux->bih + 1, nal->p_payload, extradata_size); mod->mux->bih->biSize= sizeof(*mod->mux->bih) + extradata_size; } if (param.i_bframe > 1 && param.i_bframe_pyramid) mod->mux->decoder_delay = 2; else mod->mux->decoder_delay = param.i_bframe ? 1 : 0; return 1; }
bool x264Encoder::createHeader (void) { x264_nal_t *nal; int nalCount; extraDataLen = x264_encoder_headers(handle, &nal, &nalCount); extraData = new uint8_t[extraDataLen]; extraDataLen = encodeNals(extraData, extraDataLen, nal, nalCount, true); return 1; }
x264_t* msx264::msx264_encoder_open() { int iResult; pX264Handle = x264_encoder_open(¶ms); assert(pX264Handle); iResult = x264_encoder_headers(pX264Handle, &pNals, &iNal); assert(iResult >= 0); //* 获取整个流的PPS和SPS,不需要可以不调用. iResult = x264_encoder_headers(pX264Handle, &pNals, &iNal); assert(iResult >= 0); //* PPS SPS 总共只有36B,如何解析出来呢? for (int i = 0; i < iNal; ++i) { switch (pNals[i].i_type) { case NAL_SPS: break; case NAL_PPS: break; default: break; } } }
void CH264Encoder::GetSPSAndPPS(unsigned char*sps,long&spslen,unsigned char*pps,long&ppslen) { if (m_hx264!=NULL) { int i_nal=0; x264_nal_t*tnal=NULL; x264_encoder_headers(m_hx264,&tnal,&i_nal); spslen=tnal[0].i_payload-4; memcpy(sps,tnal[0].p_payload+4,spslen); ppslen=tnal[1].i_payload-4; memcpy(pps,tnal[1].p_payload+4,ppslen); }else { spslen=0; ppslen=0; } }
int init_head(x264_t * x264_handle, char * header, int hlen) { x264_nal_t * nal_; int nal_size = 0; x264_encoder_headers(x264_handle, &nal_, &nal_size); for (int i = 0; i < nal_size; i++) { x264_nal_t & nal = nal_[i]; switch (nal.i_type) { case NAL_SPS: printb(nal.p_payload, nal.i_payload); break; case NAL_PPS: printb(nal.p_payload, nal.i_payload); break; } } }
void GetHeaders(DataPacket &packet) { if(!HeaderPacket.Num()) { x264_nal_t *nalOut; int nalNum; x264_encoder_headers(x264, &nalOut, &nalNum); for(int i=0; i<nalNum; i++) { x264_nal_t &nal = nalOut[i]; if(nal.i_type == NAL_SPS) { BufferOutputSerializer headerOut(HeaderPacket); headerOut.OutputByte(0x17); headerOut.OutputByte(0); headerOut.OutputByte(0); headerOut.OutputByte(0); headerOut.OutputByte(0); headerOut.OutputByte(1); headerOut.Serialize(nal.p_payload+5, 3); headerOut.OutputByte(0xff); headerOut.OutputByte(0xe1); headerOut.OutputWord(htons(nal.i_payload-4)); headerOut.Serialize(nal.p_payload+4, nal.i_payload-4); x264_nal_t &pps = nalOut[i+1]; //the PPS always comes after the SPS headerOut.OutputByte(1); headerOut.OutputWord(htons(pps.i_payload-4)); headerOut.Serialize(pps.p_payload+4, pps.i_payload-4); } } } packet.lpPacket = HeaderPacket.Array(); packet.size = HeaderPacket.Num(); }
bool VideoEncoder::createDecoderConfigurationRecord(AVCDecoderConfigurationRecord& rec) { assert(encoder); int num_nals = 0; x264_nal_t* nals = NULL; x264_encoder_headers(encoder, &nals, &num_nals); if(!nals) { STREAMER_ERROR("error: cannot get encoder headers from x264.\n"); return false; } if(num_nals != 3) { STREAMER_WARNING("warning: we expect number of nals from x264_encoder_headers to be 3.\n"); return false; } int sps_size = nals[0].i_payload; int pps_size = nals[1].i_payload; int sei_size = nals[2].i_payload; uint8_t* sps = nals[0].p_payload + 4; uint8_t* pps = nals[1].p_payload + 4; uint8_t* sei = nals[2].p_payload + 4; rec.configuration_version = 1; rec.avc_profile_indication = sps[1]; rec.profile_compatibility = sps[2]; rec.avc_level_indication = sps[3]; std::copy(sps, sps+(sps_size-4), std::back_inserter(rec.sps)); std::copy(pps, pps+(pps_size-4), std::back_inserter(rec.pps)); std::copy(sei, sei+(sei_size-4), std::back_inserter(rec.sei)); STREAMER_VERBOSE("nals[0].i_payload: %d, sps_size: %d, profile: %d\n", nals[0].i_payload, sps_size, sps[1]); STREAMER_VERBOSE("nals[1].i_payload: %d, pps_size: %d\n", nals[1].i_payload, pps_size); STREAMER_VERBOSE("nals[2].i_payload: %d, sei_size: %d / %ld\n", nals[2].i_payload, sei_size, rec.sei.size()); return true; }
jlong Java_com_H264_H264Encoder_CompressBegin(JNIEnv* env,jobject thiz, jint width,jint height, jint FrameRate, jbyteArray filename){ en = (Encoder *) malloc(sizeof(Encoder)); en->param = (x264_param_t *) malloc(sizeof(x264_param_t)); en->picture = (x264_picture_t *) malloc(sizeof(x264_picture_t)); opt = (cli_opt_t *)malloc(sizeof(cli_opt_t)); //test nalcount=0; last_pts = 0; i_frame= 0; //test x264_nal_t *headers; int i_nal; jbyte * fname = (jbyte*)(*env)->GetByteArrayElements(env, filename, 0); mp4_output.open_file( fname, &opt->hout, &output_opt ); x264_param_default(en->param); // default param en->param->i_log_level = X264_LOG_NONE; en->param->i_width = width; // frame width en->param->i_height = height; // frame height en->param->rc.i_lookahead =0; en->param->i_bframe=0; en->param->i_fps_num =FrameRate; en->param->i_fps_den = 1; en->param->i_frame_reference=5; en->param->i_bframe_adaptive=1; en->param->b_vfr_input=1; en->param->i_timebase_num = 1; en->param->i_timebase_den = FrameRate; en->param->i_csp =X264_CSP_I420; en->param->analyse.b_psnr = 1; en->param->analyse.b_ssim = 1; int frames = 0; en->param->i_frame_total = 0; /////// // Intra refres: en->param->i_keyint_max = 30; en->param->b_intra_refresh = 1; //Rate control: en->param->rc.f_rf_constant = 25; en->param->rc.f_rf_constant_max = 35; //For streaming: en->param->b_repeat_headers = 0; en->param->b_annexb = 0; /////// uv = en->param->i_width * en->param->i_height; if ((en->handle = x264_encoder_open(en->param)) == 0) { return 0; } x264_encoder_parameters( en->handle, en->param ); /* Create a new pic */ x264_picture_alloc(en->picture, X264_CSP_I420, en->param->i_width, en->param->i_height); mp4_output.set_param(opt->hout,en->param); ticks_per_frame = (int64_t)en->param->i_timebase_den * en->param->i_fps_den / en->param->i_timebase_num / en->param->i_fps_num; ticks_per_frame = X264_MAX( ticks_per_frame, 1 ); __android_log_print(ANDROID_LOG_INFO, "H264Encoder native", "ticks_per_frame:%d",ticks_per_frame); if(x264_encoder_headers( en->handle, &headers, &i_nal)<0) ; __android_log_print(ANDROID_LOG_INFO, "H264Encoder native", "encoder header:%d",i_nal); mp4_output.write_headers(opt->hout, headers); (*env)->ReleaseByteArrayElements(env,filename,fname,0); return (jlong) en; }
/***************************************************************************** * Open: probe the encoder *****************************************************************************/ static int Open ( vlc_object_t *p_this ) { encoder_t *p_enc = (encoder_t *)p_this; encoder_sys_t *p_sys; int i_val; char *psz_val; int i_qmin = 0, i_qmax = 0; x264_nal_t *nal; int i, i_nal; if( p_enc->fmt_out.i_codec != VLC_CODEC_H264 && !p_enc->b_force ) { return VLC_EGENERIC; } /* X264_POINTVER or X264_VERSION are not available */ msg_Dbg ( p_enc, "version x264 0.%d.X", X264_BUILD ); config_ChainParse( p_enc, SOUT_CFG_PREFIX, ppsz_sout_options, p_enc->p_cfg ); p_enc->fmt_out.i_cat = VIDEO_ES; p_enc->fmt_out.i_codec = VLC_CODEC_H264; p_enc->fmt_in.i_codec = VLC_CODEC_I420; p_enc->pf_encode_video = Encode; p_enc->pf_encode_audio = NULL; p_enc->p_sys = p_sys = malloc( sizeof( encoder_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; p_sys->i_interpolated_dts = 0; p_sys->psz_stat_name = NULL; p_sys->p_buffer = NULL; x264_param_default( &p_sys->param ); p_sys->param.i_width = p_enc->fmt_in.video.i_width; p_sys->param.i_height = p_enc->fmt_in.video.i_height; p_sys->param.rc.f_qcompress = var_GetFloat( p_enc, SOUT_CFG_PREFIX "qcomp" ); /* transcode-default bitrate is 0, * set more to ABR if user specifies bitrate */ if( p_enc->fmt_out.i_bitrate > 0 ) { p_sys->param.rc.i_bitrate = p_enc->fmt_out.i_bitrate / 1000; p_sys->param.rc.i_rc_method = X264_RC_ABR; } else /* Set default to CRF */ { i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "crf" ); if( i_val > 0 && i_val <= 51 ) { p_sys->param.rc.f_rf_constant = i_val; p_sys->param.rc.i_rc_method = X264_RC_CRF; } } i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "qpstep" ); if( i_val >= 0 && i_val <= 51 ) p_sys->param.rc.i_qp_step = i_val; i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "qpmin" ); if( i_val >= 0 && i_val <= 51 ) { i_qmin = i_val; p_sys->param.rc.i_qp_min = i_qmin; } i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "qpmax" ); if( i_val >= 0 && i_val <= 51 ) { i_qmax = i_val; p_sys->param.rc.i_qp_max = i_qmax; } i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "qp" ); if( i_val >= 0 && i_val <= 51 ) { if( i_qmin > i_val ) i_qmin = i_val; if( i_qmax < i_val ) i_qmax = i_val; /* User defined QP-value, so change ratecontrol method */ p_sys->param.rc.i_rc_method = X264_RC_CQP; p_sys->param.rc.i_qp_constant = i_val; p_sys->param.rc.i_qp_min = i_qmin; p_sys->param.rc.i_qp_max = i_qmax; } p_sys->param.rc.f_rate_tolerance = var_GetFloat( p_enc, SOUT_CFG_PREFIX "ratetol" ); p_sys->param.rc.f_vbv_buffer_init = var_GetFloat( p_enc, SOUT_CFG_PREFIX "vbv-init" ); p_sys->param.rc.i_vbv_buffer_size = var_GetInteger( p_enc, SOUT_CFG_PREFIX "vbv-bufsize" ); /* max bitrate = average bitrate -> CBR */ i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "vbv-maxrate" ); if( !i_val && p_sys->param.rc.i_rc_method == X264_RC_ABR ) p_sys->param.rc.i_vbv_max_bitrate = p_sys->param.rc.i_bitrate; else if ( i_val ) p_sys->param.rc.i_vbv_max_bitrate = i_val; p_sys->param.b_cabac = var_GetBool( p_enc, SOUT_CFG_PREFIX "cabac" ); /* disable deblocking when nf (no loop filter) is enabled */ p_sys->param.b_deblocking_filter = !var_GetBool( p_enc, SOUT_CFG_PREFIX "nf" ); psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "deblock" ); if( psz_val ) { char *p = strchr( psz_val, ':' ); p_sys->param.i_deblocking_filter_alphac0 = atoi( psz_val ); p_sys->param.i_deblocking_filter_beta = p ? atoi( p+1 ) : p_sys->param.i_deblocking_filter_alphac0; free( psz_val ); } psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "psy-rd" ); if( psz_val ) { char *p = strchr( psz_val, ':' ); p_sys->param.analyse.f_psy_rd = us_atof( psz_val ); p_sys->param.analyse.f_psy_trellis = p ? us_atof( p+1 ) : 0; free( psz_val ); } psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "level" ); if( psz_val ) { if( us_atof (psz_val) < 6 ) p_sys->param.i_level_idc = (int) (10 * us_atof (psz_val) + .5); else p_sys->param.i_level_idc = atoi (psz_val); free( psz_val ); } p_sys->param.b_interlaced = var_GetBool( p_enc, SOUT_CFG_PREFIX "interlaced" ); p_sys->param.rc.f_ip_factor = var_GetFloat( p_enc, SOUT_CFG_PREFIX "ipratio" ); p_sys->param.rc.f_pb_factor = var_GetFloat( p_enc, SOUT_CFG_PREFIX "pbratio" ); p_sys->param.rc.f_complexity_blur = var_GetFloat( p_enc, SOUT_CFG_PREFIX "cplxblur" ); p_sys->param.rc.f_qblur = var_GetFloat( p_enc, SOUT_CFG_PREFIX "qblur" ); p_sys->param.rc.i_aq_mode = var_GetInteger( p_enc, SOUT_CFG_PREFIX "aq-mode" ); p_sys->param.rc.f_aq_strength = var_GetFloat( p_enc, SOUT_CFG_PREFIX "aq-strength" ); if( var_GetBool( p_enc, SOUT_CFG_PREFIX "verbose" ) ) p_sys->param.i_log_level = X264_LOG_DEBUG; if( var_GetBool( p_enc, SOUT_CFG_PREFIX "quiet" ) ) p_sys->param.i_log_level = X264_LOG_NONE; i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "sps-id" ); if( i_val >= 0 ) p_sys->param.i_sps_id = i_val; if( var_GetBool( p_enc, SOUT_CFG_PREFIX "aud" ) ) p_sys->param.b_aud = true; i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "keyint" ); if( i_val > 0 ) p_sys->param.i_keyint_max = i_val; i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "min-keyint" ); if( i_val > 0 ) p_sys->param.i_keyint_min = i_val; i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "bframes" ); if( i_val >= 0 && i_val <= 16 ) p_sys->param.i_bframe = i_val; #if X264_BUILD >= 78 psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "bpyramid" ); p_sys->param.i_bframe_pyramid = X264_B_PYRAMID_NONE; if( !strcmp( psz_val, "none" ) ) { p_sys->param.i_bframe_pyramid = X264_B_PYRAMID_NONE; } else if ( !strcmp( psz_val, "strict" ) ) { p_sys->param.i_bframe_pyramid = X264_B_PYRAMID_STRICT; } else if ( !strcmp( psz_val, "normal" ) ) { p_sys->param.i_bframe_pyramid = X264_B_PYRAMID_NORMAL; } free( psz_val ); #else p_sys->param.b_bframe_pyramid = var_GetBool( p_enc, SOUT_CFG_PREFIX "bpyramid" ); #endif i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "ref" ); if( i_val > 0 && i_val <= 15 ) p_sys->param.i_frame_reference = i_val; i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "scenecut" ); if( i_val >= -1 && i_val <= 100 ) p_sys->param.i_scenecut_threshold = i_val; p_sys->param.b_deterministic = var_GetBool( p_enc, SOUT_CFG_PREFIX "non-deterministic" ); i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "subme" ); if( i_val >= 1 && i_val <= SUBME_MAX ) p_sys->param.analyse.i_subpel_refine = i_val; //TODO: psz_val == NULL ? psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "me" ); if( !strcmp( psz_val, "dia" ) ) { p_sys->param.analyse.i_me_method = X264_ME_DIA; } else if( !strcmp( psz_val, "hex" ) ) { p_sys->param.analyse.i_me_method = X264_ME_HEX; } else if( !strcmp( psz_val, "umh" ) ) { p_sys->param.analyse.i_me_method = X264_ME_UMH; } else if( !strcmp( psz_val, "esa" ) ) { p_sys->param.analyse.i_me_method = X264_ME_ESA; } else if( !strcmp( psz_val, "tesa" ) ) { p_sys->param.analyse.i_me_method = X264_ME_TESA; } free( psz_val ); i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "merange" ); if( i_val >= 0 && i_val <= 64 ) p_sys->param.analyse.i_me_range = i_val; p_sys->param.analyse.i_mv_range = var_GetInteger( p_enc, SOUT_CFG_PREFIX "mvrange" ); p_sys->param.analyse.i_mv_range_thread = var_GetInteger( p_enc, SOUT_CFG_PREFIX "mvrange-thread" ); psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "direct" ); if( !strcmp( psz_val, "none" ) ) { p_sys->param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_NONE; } else if( !strcmp( psz_val, "spatial" ) ) { p_sys->param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_SPATIAL; } else if( !strcmp( psz_val, "temporal" ) ) { p_sys->param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_TEMPORAL; } else if( !strcmp( psz_val, "auto" ) ) { p_sys->param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_AUTO; } free( psz_val ); p_sys->param.analyse.b_psnr = var_GetBool( p_enc, SOUT_CFG_PREFIX "psnr" ); p_sys->param.analyse.b_ssim = var_GetBool( p_enc, SOUT_CFG_PREFIX "ssim" ); p_sys->param.analyse.b_weighted_bipred = var_GetBool( p_enc, SOUT_CFG_PREFIX "weightb" ); p_sys->param.i_bframe_adaptive = var_GetInteger( p_enc, SOUT_CFG_PREFIX "b-adapt" ); i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "b-bias" ); if( i_val >= -100 && i_val <= 100 ) p_sys->param.i_bframe_bias = i_val; p_sys->param.analyse.b_chroma_me = var_GetBool( p_enc, SOUT_CFG_PREFIX "chroma-me" ); p_sys->param.analyse.i_chroma_qp_offset = var_GetInteger( p_enc, SOUT_CFG_PREFIX "chroma-qp-offset" ); p_sys->param.analyse.b_mixed_references = var_GetBool( p_enc, SOUT_CFG_PREFIX "mixed-refs" ); i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "trellis" ); if( i_val >= 0 && i_val <= 2 ) p_sys->param.analyse.i_trellis = i_val; p_sys->param.analyse.b_fast_pskip = var_GetBool( p_enc, SOUT_CFG_PREFIX "fast-pskip" ); i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "nr" ); if( i_val >= 0 && i_val <= 1000 ) p_sys->param.analyse.i_noise_reduction = i_val; p_sys->param.analyse.b_dct_decimate = var_GetBool( p_enc, SOUT_CFG_PREFIX "dct-decimate" ); i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "deadzone-inter" ); if( i_val >= 0 && i_val <= 32 ) p_sys->param.analyse.i_luma_deadzone[0] = i_val; i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "deadzone-intra" ); if( i_val >= 0 && i_val <= 32 ) p_sys->param.analyse.i_luma_deadzone[1] = i_val; if( !var_GetBool( p_enc, SOUT_CFG_PREFIX "asm" ) ) p_sys->param.cpu = 0; #ifndef X264_ANALYSE_BSUB16x16 # define X264_ANALYSE_BSUB16x16 0 #endif psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "partitions" ); if( !strcmp( psz_val, "none" ) ) { p_sys->param.analyse.inter = 0; } else if( !strcmp( psz_val, "fast" ) ) { p_sys->param.analyse.inter = X264_ANALYSE_I4x4; } else if( !strcmp( psz_val, "normal" ) ) { p_sys->param.analyse.inter = X264_ANALYSE_I4x4 | X264_ANALYSE_PSUB16x16; #ifdef X264_ANALYSE_I8x8 p_sys->param.analyse.inter |= X264_ANALYSE_I8x8; #endif } else if( !strcmp( psz_val, "slow" ) ) { p_sys->param.analyse.inter = X264_ANALYSE_I4x4 | X264_ANALYSE_PSUB16x16 | X264_ANALYSE_BSUB16x16; #ifdef X264_ANALYSE_I8x8 p_sys->param.analyse.inter |= X264_ANALYSE_I8x8; #endif } else if( !strcmp( psz_val, "all" ) ) { p_sys->param.analyse.inter = ~0; } free( psz_val ); p_sys->param.analyse.b_transform_8x8 = var_GetBool( p_enc, SOUT_CFG_PREFIX "8x8dct" ); if( p_enc->fmt_in.video.i_aspect > 0 ) { int64_t i_num, i_den; unsigned int i_dst_num, i_dst_den; i_num = p_enc->fmt_in.video.i_aspect * (int64_t)p_enc->fmt_in.video.i_height; i_den = VOUT_ASPECT_FACTOR * p_enc->fmt_in.video.i_width; vlc_ureduce( &i_dst_num, &i_dst_den, i_num, i_den, 0 ); p_sys->param.vui.i_sar_width = i_dst_num; p_sys->param.vui.i_sar_height = i_dst_den; } if( p_enc->fmt_in.video.i_frame_rate_base > 0 ) { p_sys->param.i_fps_num = p_enc->fmt_in.video.i_frame_rate; p_sys->param.i_fps_den = p_enc->fmt_in.video.i_frame_rate_base; } /* x264 vbv-bufsize = 0 (default). if not provided set period in seconds for local maximum bitrate (cache/bufsize) based on average bitrate when use has told bitrate. vbv-buffer size is set to bitrate * secods between keyframes */ if( !p_sys->param.rc.i_vbv_buffer_size && p_sys->param.rc.i_rc_method == X264_RC_ABR && p_sys->param.i_fps_num ) { p_sys->param.rc.i_vbv_buffer_size = p_sys->param.rc.i_bitrate * p_sys->param.i_fps_den; p_sys->param.rc.i_vbv_buffer_size *= p_sys->param.i_keyint_max; p_sys->param.rc.i_vbv_buffer_size /= p_sys->param.i_fps_num; } /* Check if user has given some profile (baseline,main,high) to limit * settings, and apply those*/ psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "profile" ); if( psz_val ) { if( !strcasecmp( psz_val, "baseline" ) ) { msg_Dbg( p_enc, "Limiting to baseline profile"); p_sys->param.analyse.b_transform_8x8 = 0; p_sys->param.b_cabac = 0; p_sys->param.i_bframe = 0; } else if (!strcasecmp( psz_val, "main" ) ) { msg_Dbg( p_enc, "Limiting to main-profile"); p_sys->param.analyse.b_transform_8x8 = 0; } /* high profile don't restrict stuff*/ } free( psz_val ); unsigned i_cpu = vlc_CPU(); if( !(i_cpu & CPU_CAPABILITY_MMX) ) { p_sys->param.cpu &= ~X264_CPU_MMX; } if( !(i_cpu & CPU_CAPABILITY_MMXEXT) ) { p_sys->param.cpu &= ~X264_CPU_MMXEXT; } if( !(i_cpu & CPU_CAPABILITY_SSE) ) { p_sys->param.cpu &= ~X264_CPU_SSE; } if( !(i_cpu & CPU_CAPABILITY_SSE2) ) { p_sys->param.cpu &= ~X264_CPU_SSE2; } /* BUILD 29 adds support for multi-threaded encoding while BUILD 49 (r543) also adds support for threads = 0 for automatically selecting an optimal value (cores * 1.5) based on detected CPUs. Default behavior for x264 is threads = 1, however VLC usage differs and uses threads = 0 (auto) by default unless ofcourse transcode threads is explicitly specified.. */ p_sys->param.i_threads = p_enc->i_threads; psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "stats" ); if( psz_val ) { p_sys->param.rc.psz_stat_in = p_sys->param.rc.psz_stat_out = p_sys->psz_stat_name = psz_val; } i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "pass" ); if( i_val > 0 && i_val <= 3 ) { p_sys->param.rc.b_stat_write = i_val & 1; p_sys->param.rc.b_stat_read = i_val & 2; } /* We need to initialize pthreadw32 before we open the encoder, but only once for the whole application. Since pthreadw32 doesn't keep a refcount, do it ourselves. */ #ifdef PTW32_STATIC_LIB vlc_value_t lock, count; var_Create( p_enc->p_libvlc, "pthread_win32_mutex", VLC_VAR_MUTEX ); var_Get( p_enc->p_libvlc, "pthread_win32_mutex", &lock ); vlc_mutex_lock( lock.p_address ); var_Create( p_enc->p_libvlc, "pthread_win32_count", VLC_VAR_INTEGER ); var_Get( p_enc->p_libvlc, "pthread_win32_count", &count ); if( count.i_int == 0 ) { msg_Dbg( p_enc, "initializing pthread-win32" ); if( !pthread_win32_process_attach_np() || !pthread_win32_thread_attach_np() ) { msg_Warn( p_enc, "pthread Win32 Initialization failed" ); vlc_mutex_unlock( lock.p_address ); return VLC_EGENERIC; } } count.i_int++; var_Set( p_enc->p_libvlc, "pthread_win32_count", count ); vlc_mutex_unlock( lock.p_address ); #endif /* Set lookahead value to lower than default, * as rtp-output without mux doesn't handle * difference that well yet*/ p_sys->param.rc.i_lookahead=5; /* Open the encoder */ p_sys->h = x264_encoder_open( &p_sys->param ); if( p_sys->h == NULL ) { msg_Err( p_enc, "cannot open x264 encoder" ); Close( VLC_OBJECT(p_enc) ); return VLC_EGENERIC; } /* alloc mem */ p_sys->i_buffer = 4 * p_enc->fmt_in.video.i_width * p_enc->fmt_in.video.i_height + 1000; p_sys->p_buffer = malloc( p_sys->i_buffer ); if( !p_sys->p_buffer ) { Close( VLC_OBJECT(p_enc) ); return VLC_ENOMEM; } /* get the globals headers */ p_enc->fmt_out.i_extra = 0; p_enc->fmt_out.p_extra = NULL; p_enc->fmt_out.i_extra = x264_encoder_headers( p_sys->h, &nal, &i_nal ); p_enc->fmt_out.p_extra = malloc( p_enc->fmt_out.i_extra ); if( !p_enc->fmt_out.p_extra ) { Close( VLC_OBJECT(p_enc) ); return VLC_ENOMEM; } void *p_tmp = p_enc->fmt_out.p_extra; for( i = 0; i < i_nal; i++ ) { memcpy( p_tmp, nal[i].p_payload, nal[i].i_payload ); p_tmp += nal[i].i_payload; } return VLC_SUCCESS; }
bool CX264VideoEncoder::GetEsConfig (uint8_t **ppEsConfig, uint32_t *pEsConfigLen) { #ifdef DEBUG_H264 debug_message("Getting es config for x264"); #endif CHECK_AND_FREE(Profile()->m_videoMpeg4Config); Profile()->m_videoMpeg4ConfigLength = 0; x264_nal_t *nal; int nal_num; if (x264_encoder_headers(m_h, &nal, &nal_num) != 0) { error_message("x264 - can't create headers"); StopEncoder(); return false; } uint8_t *seqptr = m_vopBuffer; uint8_t *picptr = m_vopBuffer; uint32_t seqlen = 0, piclen = 0; bool found_seq = false, found_pic = false; if (m_vopBuffer == NULL) { m_vopBuffer = (u_int8_t*)malloc(Profile()->m_videoMaxVopSize); } uint8_t *vopBuffer = m_vopBuffer; int vopBufferLen = Profile()->m_videoMaxVopSize; for (int ix = 0; ix < nal_num; ix++) { int i_size; i_size = x264_nal_encode(vopBuffer, &vopBufferLen, 1, &nal[ix]); if (i_size > 0) { bool useit = false; uint header_size = 0; if (h264_is_start_code(vopBuffer)) { header_size = vopBuffer[2] == 1 ? 3 : 4; } if (nal[ix].i_type == H264_NAL_TYPE_SEQ_PARAM) { found_seq = true; seqlen = i_size - header_size; seqptr = vopBuffer + header_size; useit = true; } else if (nal[ix].i_type == H264_NAL_TYPE_PIC_PARAM) { found_pic = true; piclen = i_size - header_size; picptr = vopBuffer + header_size; useit = true; } if (useit) { vopBuffer += i_size; vopBufferLen -= i_size; } } } if (found_seq == false) { error_message("Can't find seq pointer in x264 header"); StopEncoder(); return false; } if (found_pic == false) { error_message("Can't find pic pointer in x264 header"); StopEncoder(); return false; } uint8_t *p = seqptr; if (*p == 0 && p[1] == 0 && (p[2] == 1 || (p[2] == 0 && p[3] == 1))) { if (p[2] == 0) p += 4; else p += 3; } Profile()->m_videoMpeg4ProfileId = p[1] << 16 | p[2] << 8 | p[3]; debug_message("profile id %x", Profile()->m_videoMpeg4ProfileId); char *sprop = NULL; char *base64; base64 = MP4BinaryToBase64(seqptr, seqlen); sprop = strdup(base64); free(base64); base64 = MP4BinaryToBase64(picptr, piclen); sprop = (char *)realloc(sprop, strlen(sprop) + strlen(base64) + 1 + 1); strcat(sprop, ","); strcat(sprop, base64); free(base64); debug_message("sprop %s", sprop); Profile()->m_videoMpeg4Config = (uint8_t *)sprop; Profile()->m_videoMpeg4ConfigLength = strlen(sprop) + 1; StopEncoder(); return true; }
bool X264Encoder::openX264Encoder() { this->closeX264Encoder(); if(!pParameter) { pParameter = (x264_param_t *)malloc(sizeof(x264_param_t)); if (!pParameter) { this->closeX264Encoder(); return false; } memset(pParameter, 0, sizeof(x264_param_t)); } int ret = x264_param_default_preset(pParameter, "ultrafast", "zerolatency"); if (ret != 0) { this->closeX264Encoder(); return false; } pParameter->i_threads = 1; pParameter->b_sliced_threads = 0; pParameter->i_sync_lookahead = X264_SYNC_LOOKAHEAD_AUTO; pParameter->i_width = width; pParameter->i_height = height; pParameter->i_frame_total = 0; pParameter->b_deterministic = 1; pParameter->i_frame_reference = 4; pParameter->i_bframe = 0; pParameter->i_bframe_pyramid = 0; pParameter->i_bframe_adaptive = 0; pParameter->b_intra_refresh = 0; pParameter->i_csp = X264_CSP_I420; pParameter->i_level_idc = 9; pParameter->i_keyint_min = 10; pParameter->i_keyint_max = 30; pParameter->b_repeat_headers = 1; pParameter->b_interlaced = 0; pParameter->i_cqm_preset = X264_CQM_FLAT; pParameter->psz_cqm_file = NULL; pParameter->b_aud = 0; pParameter->i_nal_hrd = X264_NAL_HRD_NONE; pParameter->i_scenecut_threshold = 40; pParameter->i_bframe_bias = 0; pParameter->i_fps_num = i_fps; pParameter->i_fps_den = 1; pParameter->i_timebase_num = 1; pParameter->i_timebase_den = 1000000; pParameter->analyse.i_weighted_pred = 0; pParameter->analyse.b_weighted_bipred = 0; pParameter->analyse.b_chroma_me = 1; pParameter->analyse.i_trellis = 1; pParameter->analyse.i_subpel_refine = 4; pParameter->analyse.b_transform_8x8 = 1; pParameter->analyse.i_me_range = 8; pParameter->analyse.i_me_method = X264_ME_UMH; //2 pParameter->analyse.i_direct_mv_pred = X264_DIRECT_PRED_TEMPORAL; //2 pParameter->analyse.intra = 0; pParameter->analyse.inter = 0; pParameter->b_cabac = 0; pParameter->b_vfr_input = 0; pParameter->rc.i_rc_method = X264_RC_ABR;//X264_RC_CQP; pParameter->rc.f_qcompress = 0.6f; // 0.0 => cbr, 1.0 => constant qp pParameter->rc.i_lookahead = 0; pParameter->rc.b_mb_tree = 0; pParameter->rc.i_qp_min = 10; pParameter->rc.i_qp_max = 51; pParameter->rc.i_qp_step = 3; pParameter->rc.i_qp_constant = 10; pParameter->rc.f_rf_constant = 10; // 1pass VBR, nominal QP pParameter->rc.i_bitrate = 300; pParameter->rc.i_vbv_max_bitrate = 300; pParameter->rc.i_vbv_buffer_size = 300; pParameter->rc.f_vbv_buffer_init = 0.6f; pParameter->rc.f_rate_tolerance = 10 / 100.0f; // In CRF mode,maximum CRF as caused by VBV if(x264_param_apply_profile(pParameter, "baseline")) { this->closeX264Encoder(); return false; } if (!x264EncoderHandle) { x264EncoderHandle = x264_encoder_open(pParameter); assert(x264EncoderHandle != NULL); } int nal_count = 0; x264_nal_t* nals = NULL; x264_encoder_headers(x264EncoderHandle, &nals, &nal_count); assert(nal_count > 0); for (int index = 0; index < nal_count; ++index) { if (nals[index].i_type == NAL_SPS) { spslen = createNalBuffer(sps, nals[index].p_payload, nals[index].i_payload); } if (nals[index].i_type == NAL_PPS) { ppslen = createNalBuffer(pps, nals[index].p_payload, nals[index].i_payload); } } assert(spslen != 0); assert(ppslen != 0); if (!pOutput) { pOutput = (x264_picture_t *)malloc(sizeof(x264_picture_t)); if (!pOutput) { this->closeX264Encoder(); return false; } } memset(pOutput, 0, sizeof(x264_picture_t)); return true; }
int BleX264Encoder::init() { MOption *option = MOption::instance(); QString presetName = option->option("preset", "x264").toString(); QString tuneName = option->option("tune", "x264").toString(); QString profileName = option->option("profile", "x264").toString(); int fps = option->option("fps", "encoder").toInt(); int kbps = option->option("bitrate", "encoder").toInt(); QSize wh = option->option("res", "encoder").toSize(); int width = wh.width(); int height = wh.height(); int maxBitRate = kbps; int bufferSize = maxBitRate; bool bUseCBR = (option->option("BitrateMode", "x264").toString() == "CBR"); int quality = option->option("quality", "x264").toInt(); int KeyFrameInterval = option->option("KeyFrameInterval", "x264").toInt(); int threadCount = option->option(Key_Thread_Count, Group_X264).toInt(); bool enableBFrame = option->option(Key_Enable_B_Frame, Group_X264).toString() == "true" ? true : false; int B_frame_count = option->option(Key_B_Frame_Count, Group_X264).toInt(); m_x264Param = new x264_param_t; if (tuneName == "Default" || tuneName.isEmpty()) { x264_param_default_preset(m_x264Param , presetName.toStdString().c_str(), NULL); log_trace("libx264 preset set to %s, tune set to NULL" , presetName.toStdString().c_str()); } else { x264_param_default_preset(m_x264Param , presetName.toStdString().c_str(), tuneName.toStdString().c_str()); log_trace("libx264 preset set to %s, tune set to %s"\ , presetName.toStdString().c_str(), tuneName.toStdString().c_str()); } if (profileName != "Default") { x264_param_apply_profile(m_x264Param, profileName.toStdString().c_str()); log_trace("libx264 profile set to %s", profileName.toStdString().c_str()); } else { log_trace("libx264 profile set to Default"); } if(bUseCBR) { m_x264Param->rc.i_bitrate = maxBitRate; m_x264Param->rc.i_vbv_max_bitrate = maxBitRate; // vbv-maxrate m_x264Param->rc.i_vbv_buffer_size = bufferSize; // vbv-bufsize m_x264Param->i_nal_hrd = X264_NAL_HRD_CBR; m_x264Param->rc.i_rc_method = X264_RC_ABR; m_x264Param->rc.f_rf_constant = 0.0f; } else { m_x264Param->rc.i_vbv_max_bitrate = maxBitRate; // vbv-maxrate m_x264Param->rc.i_vbv_buffer_size = bufferSize; // vbv-bufsize m_x264Param->rc.i_rc_method = X264_RC_CRF; // X264_RC_CRF; m_x264Param->rc.f_rf_constant = 10.0f + float(20 - quality); log_trace("libx264 quality set to %d", quality); } m_x264Param->b_vfr_input = 1; m_x264Param->i_keyint_max = fps * KeyFrameInterval; m_x264Param->i_width = width; m_x264Param->i_height = height; m_x264Param->vui.b_fullrange = 0; //specify full range input levels // For some codecs, the time base is closer to the field rate than the frame rate. // Most notably, H.264 and MPEG-2 specify time_base as half of frame duration // if no telecine is used ... // Set to time_base ticks per frame. Default 1, e.g., H.264/MPEG-2 set it to 2. // @see ffmpeg: AVodecContex::ticks_per_frame // never use timebase = 1000, because vlc will show 1000 fps !! int ticks_per_frame = 2; m_x264Param->i_timebase_num = 1; m_x264Param->i_timebase_den = fps; m_x264Param->i_fps_num = m_x264Param->i_timebase_den; m_x264Param->i_fps_den = m_x264Param->i_timebase_num * ticks_per_frame; // disable start code 00 00 00 01 before NAL // instead of nalu size m_x264Param->b_repeat_headers = 0; m_x264Param->b_annexb = 0; m_x264Param->i_frame_reference = 5; if (enableBFrame) { m_x264Param->i_bframe = B_frame_count; m_x264Param->i_bframe_bias = 100; m_x264Param->i_bframe_adaptive = 1; if (B_frame_count >= 2) m_x264Param->i_bframe_pyramid = 1; } else m_x264Param->i_bframe = 0; if (threadCount > 0) m_x264Param->i_threads = threadCount; // @note // never use cpu capabilities. // let libx264 to choose. #if 0 m_x264Param->cpu = 0; m_x264Param->cpu |=X264_CPU_MMX; m_x264Param->cpu |=X264_CPU_MMXEXT; m_x264Param->cpu |=X264_CPU_SSE; #endif m_x264Encoder = x264_encoder_open(m_x264Param); // update video sh x264_nal_t *nalOut; int nalNum; x264_encoder_headers(m_x264Encoder, &nalOut, &nalNum); for (int i = 0; i < nalNum; ++i) { x264_nal_t &nal = nalOut[i]; if (nal.i_type == NAL_SPS) { BleVideoPacket *pkt = new BleVideoPacket(Video_Type_H264); pkt->dts = 0; MStream &body = pkt->data; // SPS Serialize body.write1Bytes(0x17); body.write1Bytes(0x00); body.write3Bytes(0x00); body.write1Bytes(0x01); body.writeString((char*)nal.p_payload + 5, 3); body.write1Bytes(0xff); body.write1Bytes(0xe1); body.write2Bytes(nal.i_payload - 4); body.writeString((char*)nal.p_payload + 4, nal.i_payload - 4); //the PPS always comes after the SPS x264_nal_t &pps = nalOut[++i]; // PPS Serialize body.write1Bytes(0x01); body.write2Bytes(pps.i_payload - 4); body.writeString(MString((char*)pps.p_payload + 4, pps.i_payload - 4)); appCtx->setVideoSh(pkt); } else if (nal.i_type == NAL_SEI) { BleVideoPacket *seiPkt = new BleVideoPacket(Video_Type_H264); seiPkt->dts = 0; seiPkt->has_encoded = true; MStream &seiBody = seiPkt->data; int skipBytes = 4; int newPayloadSize = (nal.i_payload - skipBytes); unsigned char flshFrameType = 0x17; seiBody.write1Bytes(flshFrameType); seiBody.write1Bytes(0x01); seiBody.write3Bytes(0x00); seiBody.write4Bytes(newPayloadSize); seiBody.writeString((char*)nal.p_payload + skipBytes, newPayloadSize); BleAVQueue::instance()->enqueue(seiPkt); } } m_pictureIn = new x264_picture_t; m_pictureIn->i_pts = 0; return BLE_SUCESS; }
sc_streamer sc_streamer_init_video(const char* stream_host, const char* room_name, sc_frame_rect capture_rect, sc_time start_time_stamp){ sc_streamer_setup_windows(); x264_param_t param; char *stream_uri = (char *) malloc (100); sprintf(stream_uri, "rtmp://%s/screenshare/%s", stream_host, room_name); sc_streamer streamer = {.start_time_stamp = start_time_stamp, .stream_uri = stream_uri, .room_name = room_name, .capture_rect = capture_rect, .frames = 0, .rtmpt = 0}; streamer.flv_out_handle = open_flv_buffer(); streamer.rtmp = open_RTMP_stream( stream_uri ); if(!RTMP_IsConnected(streamer.rtmp) || RTMP_IsTimedout(streamer.rtmp)) { printf("Using rtmpt \n"); streamer.rtmpt = 1; free(stream_uri); char *stream_uri = (char *) malloc (100); sprintf(stream_uri, "rtmpt://%s/screenshare/%s", stream_host, room_name); streamer.rtmp = open_RTMP_stream( stream_uri ); } write_RTMP_header(streamer.flv_out_handle, streamer.rtmp); x264_param_default_preset(¶m, "veryfast", "zerolatency"); param.i_log_level = X264_LOG_ERROR; //param.psz_dump_yuv = (char *)"/tmp/dump.y4m"; param.b_vfr_input = 1; param.i_keyint_max = 30; param.i_width = capture_rect.width; param.i_height = capture_rect.height; param.i_timebase_num = 1.0; param.i_timebase_den = SC_TimeBase; //Rate control/quality param.rc.i_rc_method = X264_RC_CRF; param.i_slice_max_size = 1024; param.rc.i_vbv_max_bitrate = 1024; param.rc.i_vbv_buffer_size = 2000; param.rc.f_rf_constant = 23; param.b_sliced_threads = 0; param.b_intra_refresh = 0; param.b_repeat_headers = 1; param.b_annexb = 0; x264_param_apply_profile(¶m, "main"); streamer.encoder = x264_encoder_open(¶m); set_RTMP_param( streamer.flv_out_handle, ¶m ); x264_nal_t *headers; int i_nal; x264_encoder_headers( streamer.encoder, &headers, &i_nal ); write_RTMP_headers( streamer.flv_out_handle, streamer.rtmp, headers ); headers = NULL; free(headers); streamer.rtmp_setup = 1; streamer.reconnect_tries = 0; return streamer; } sc_streamer sc_streamer_init_cursor(const char* stream_host, const char* room_name, sc_time start_time_stamp){ sc_streamer_setup_windows(); char *so_name = (char *) malloc (100); sprintf(so_name, "SC.SS.%s.Cursor", room_name); char *stream_uri = (char *) malloc (100); sprintf(stream_uri, "rtmp://%s/screenshare/%s-cursor", stream_host, room_name); sc_streamer streamer = {.start_time_stamp = start_time_stamp, .stream_uri = stream_uri, .room_name = room_name, .so_name = so_name, .rtmpt = 0, .have_inital_SO = 0}; streamer.flv_out_handle = open_flv_buffer(); streamer.rtmp = open_RTMP_stream( stream_uri ); if(!RTMP_IsConnected(streamer.rtmp) || RTMP_IsTimedout(streamer.rtmp)) { streamer.rtmpt = 1; free(stream_uri); char *stream_uri = (char *) malloc (100); sprintf(stream_uri, "rtmpt://%s/screenshare/%s-cursor", stream_host, room_name); streamer.rtmp = open_RTMP_stream( stream_uri ); } setup_shared_object(streamer.so_name, streamer.rtmp); streamer.rtmp_setup = 1; streamer.so_version = 0; streamer.reconnect_tries = 0; return streamer; } void sc_streamer_send_frame(sc_streamer *streamer, sc_frame *frame, sc_time frame_time_stamp) { x264_picture_t pic_in, pic_out; x264_picture_alloc(&pic_in, X264_CSP_I420, streamer->capture_rect.width, streamer->capture_rect.height); const size_t image_size = (streamer->capture_rect.width * streamer->capture_rect.height); x264_free(pic_in.img.plane[0]); pic_in.img.plane[0] = frame->framePtr; pic_in.img.plane[1] = frame->framePtr + image_size; pic_in.img.plane[2] = frame->framePtr + image_size + image_size / 4; pic_in.i_pts = floor((frame_time_stamp - streamer->start_time_stamp)); x264_nal_t* nals; int i_nals; int frame_size = x264_encoder_encode(streamer->encoder, &nals, &i_nals, &pic_in, &pic_out); if(frame_size > 0) { write_RTMP_frame( streamer->flv_out_handle, streamer->rtmp, nals[0].p_payload, frame_size, &pic_out ); streamer->frames++; } nals = NULL; free(nals); //x264_picture_clean(&pic_in); }
int main(int argc, char* argv[]) { if (argc != 5) { printf("usage : app [input] [width] [height] [output]\n"); return 0; } const char* input = argv[1]; const char* out264 = argv[4]; const int width = atoi(argv[2]); const int height = atoi(argv[3]); FILE *fin = 0, *fout = 0; fopen_s(&fin, input, "rb"); fopen_s(&fout, out264, "wb"); if (fin == 0 || fout == 0) { printf("openf file failed\n"); return -1; } x264_param_t param; x264_param_default_preset(¶m, "fast", "zerolatency"); //x264_param_default(¶m); param.i_width = width; param.i_height = height; param.i_bframe = 0; param.i_threads = 1; param.i_sync_lookahead = 0; // param.b_deblocking_filter = 1; param.b_cabac = 1; param.i_fps_num = 25; param.i_fps_den = 1; param.i_level_idc = 30; param.i_keyint_min = param.i_fps_num; param.i_keyint_max = param.i_fps_num * 2; param.analyse.i_subpel_refine = 5; param.analyse.i_me_method = X264_ME_HEX; param.analyse.inter = X264_ANALYSE_I4x4 | X264_ANALYSE_I8x8 | X264_ANALYSE_PSUB16x16 | X264_ANALYSE_BSUB16x16; param.analyse.intra = X264_ANALYSE_I4x4 | X264_ANALYSE_I8x8; if ((param.analyse.inter | param.analyse.intra) & X264_ANALYSE_I8x8) { param.analyse.b_transform_8x8 = 1; } param.rc.i_lookahead = 0; param.rc.i_bitrate = 500; param.rc.i_vbv_max_bitrate = param.rc.i_bitrate; param.rc.i_vbv_buffer_size = param.rc.i_bitrate; param.rc.f_vbv_buffer_init = 0.7f; param.rc.b_mb_tree = 0; // param.rc.i_qp_min = 2; // param.rc.i_qp_max = 31; // param.rc.f_qcompress = 0.5f; // param.rc.i_qp_constant = 0; param.rc.i_rc_method = X264_RC_ABR; param.rc.f_rf_constant = 8.5f; param.rc.f_rf_constant_max = 20.0f; param.rc.f_rate_tolerance = 0.1f; param.rc.i_aq_mode = X264_AQ_AUTOVARIANCE; param.rc.f_aq_strength = 0.5f; param.b_repeat_headers = 0; // param.b_annexb = 0; #ifdef _DEBUG // param.analyse.b_psnr = true; // param.analyse.b_ssim = true; param.i_log_level = X264_LOG_INFO; #endif x264_t* h264 = x264_encoder_open(¶m); if (h264 == NULL) { printf("x264 open failed\n"); return -1; } x264_picture_t pic_in; x264_picture_t pic_out; x264_picture_alloc(&pic_in, X264_CSP_I420, width, height); x264_picture_init(&pic_out); int bufferSize = width * height * 3 / 2; uchar* buffer = (uchar*)malloc(bufferSize); pic_in.img.i_csp = X264_CSP_I420; pic_in.img.i_plane = 3; pic_in.img.plane[0] = buffer; pic_in.img.plane[1] = buffer + width * height; pic_in.img.plane[2] = buffer + width * height * 5 / 4; pic_in.img.i_stride[0] = width; pic_in.img.i_stride[1] = width / 2; pic_in.img.i_stride[2] = width / 2; pic_in.i_pts = 0; int frameCount = 0; int encodeFrameCount = 0; int frameSize = 0; int i_nal = 0; x264_nal_t* p_nal = NULL; //从头部信息里面获取PPS、SPS等 x264_encoder_headers(h264, &p_nal, &i_nal); for (int i = 0; i < i_nal; i++) { fwrite(p_nal[i].p_payload, 1, p_nal[i].i_payload, fout); } while (!feof(fin)) { int bytes = fread(buffer, 1, bufferSize, fin); if (bytes != bufferSize) { break; } if (frameCount++ % 8 == 0) { pic_in.i_type = X264_TYPE_IDR; } else { pic_in.i_type = X264_TYPE_AUTO; } frameSize = x264_encoder_encode(h264, &p_nal, &i_nal, &pic_in, &pic_out); if (frameSize < 0) { printf("x264 encode failed\n"); break; } if (frameSize > 0) { for (int i = 0; i < i_nal; i++) { fwrite(p_nal[i].p_payload, 1, p_nal[i].i_payload, fout); } encodeFrameCount++; } pic_in.i_pts++; } while (frameSize = x264_encoder_encode(h264, &p_nal, &i_nal, NULL, &pic_out)) { for (int i = 0; i < i_nal; i++) { fwrite(p_nal[i].p_payload, 1, p_nal[i].i_payload, fout); } encodeFrameCount++; } free(buffer); x264_encoder_close(h264); fclose(fin); fclose(fout); printf("read video frame = %d\n", frameCount); printf("encode video frame = %d\n", encodeFrameCount); system("pause"); return 0; }