void set_encoding_quality(struct x264lib_ctx *ctx, int pct) { if (ctx->supports_csc_option) { int new_colour_sampling = get_x264_colour_sampling(ctx, pct); if (ctx->colour_sampling!=new_colour_sampling) { //pixel encoding has changed, we must re-init everything: //printf("set_encoding_quality(%i) old colour_sampling=%i, new colour_sampling %i\n", pct, ctx->colour_sampling, new_colour_sampling); do_clean_encoder(ctx); do_init_encoder(ctx, ctx->width , ctx->height, pct, ctx->supports_csc_option); return; } } if ((ctx->quality & ~0x1)!=(pct & ~0x1)) { float new_quality = get_x264_quality(pct); //float old_quality = ctx->x264_quality; //printf("set_encoding_quality(%i) was %i, new x264 quality %f was %f\n", pct, ctx->quality, new_quality, old_quality); //only f_rf_constant was changed, //read new configuration is sufficient x264_param_t param; // Retrieve current parameters x264_encoder_parameters(ctx->encoder, ¶m); ctx->quality = pct; ctx->x264_quality = new_quality; param.rc.f_rf_constant = new_quality; x264_encoder_reconfig(ctx->encoder, ¶m); } int old_csc_algo = ctx->csc_algo; ctx->csc_algo = get_csc_algo_for_quality(pct); if (old_csc_algo!=ctx->csc_algo) { ctx->rgb2yuv = init_encoder_csc(ctx); } }
void H264Encoder::init_(const int wid, const int hei) { // 0. building encoder parameters. x264_param_default_preset(&x264_opt_, "ultrafast", "zerolatency"); x264_opt_.i_width = wid; x264_opt_.i_height = hei; x264_opt_.i_threads = 1; x264_opt_.b_repeat_headers = 1; x264_opt_.b_intra_refresh = 1; x264_opt_.rc.i_rc_method = X264_RC_CQP; x264_opt_.rc.i_qp_constant = 24; x264_opt_.rc.i_qp_min = 24; x264_opt_.rc.i_qp_max = 24; //x264_param_default(&opt); x264_param_apply_profile(&x264_opt_, "baseline"); // 1. Prepare the output buffer and target file x264_picture_alloc(&x264_picin_, X264_CSP_NV12, x264_opt_.i_width, x264_opt_.i_height); x264_picture_alloc(&x264_picout_, X264_CSP_NV12, x264_opt_.i_width, x264_opt_.i_height); // 2. Building the encoder handler x264_hdl_ = x264_encoder_open(&x264_opt_); x264_encoder_parameters(x264_hdl_, &x264_opt_); }
int H264Encoder::Prepare(const MediaDescription& desc) { if ( desc.isVideo == false) return -1; int wid = desc.width; int hei = desc.height; // 0. building a default encoder parameters. x264_param_default_preset(&x264_opt_, "ultrafast", "zerolatency"); x264_opt_.rc.i_rc_method = X264_RC_CRF; x264_opt_.rc.i_bitrate = 512; x264_opt_.i_nal_hrd = X264_NAL_HRD_CBR; //x264_param_default(&opt); // 1. Setting the fields of parameter struct x264_opt_.i_width = wid; x264_opt_.i_height = hei; //opt.i_slice_count = 5; //opt.b_intra_refresh = 1; // 3. Prepare the output buffer and target file x264_picture_alloc(&x264_picin_[0], X264_CSP_NV12, x264_opt_.i_width, x264_opt_.i_height); x264_picture_alloc(&x264_picin_[1], X264_CSP_NV12, x264_opt_.i_width, x264_opt_.i_height); x264_picture_alloc(&x264_picout_, X264_CSP_NV12, x264_opt_.i_width, x264_opt_.i_height); ppIndex = -1; // 4. Building the encoder handler x264_hdl_ = x264_encoder_open(&x264_opt_); x264_encoder_parameters(x264_hdl_, &x264_opt_); return 0; }
void change_encoding_speed(struct x264lib_ctx *ctx, int increase) { x264_param_t param; x264_encoder_parameters(ctx->encoder, ¶m); ctx->encoding_preset -= increase; if (ctx->encoding_preset < 0) ctx->encoding_preset = 0; if (ctx->encoding_preset > 5) ctx->encoding_preset = 5; x264_param_default_preset(¶m, x264_preset_names[ctx->encoding_preset], "zerolatency"); //printf("Setting encoding preset %s %d\n", x264_preset_names[ctx->encoding_preset], ctx->encoding_preset); x264_param_apply_profile(¶m, "baseline"); x264_encoder_reconfig(ctx->encoder, ¶m); }
void set_encoding_speed(struct x264lib_ctx *ctx, int pct) { x264_param_t param; x264_encoder_parameters(ctx->encoder, ¶m); int new_preset = 7-MAX(0, MIN(7, pct/12.5)); if (new_preset==ctx->encoding_preset) return; ctx->encoding_preset = new_preset; //"tune" options: film, animation, grain, stillimage, psnr, ssim, fastdecode, zerolatency //Multiple tunings can be used if separated by a delimiter in ",./-+" //however multiple psy tunings cannot be used. //film, animation, grain, stillimage, psnr, and ssim are psy tunings. x264_param_default_preset(¶m, x264_preset_names[ctx->encoding_preset], "zerolatency"); x264_param_apply_profile(¶m, "baseline"); x264_encoder_reconfig(ctx->encoder, ¶m); }
int compress_image(struct x264lib_ctx *ctx, x264_picture_t *pic_in, uint8_t **out, int *outsz, int quality_override) { if (!ctx->encoder || !ctx->rgb2yuv) { free_csc_image(pic_in); *out = NULL; *outsz = 0; return 1; } x264_picture_t pic_out; /* Encoding */ pic_in->i_pts = 1; if (quality_override>=0) { // Retrieve current parameters and override quality for this frame float new_q = get_x264_quality(quality_override); if (new_q!=ctx->x264_quality) { x264_param_t *param = malloc(sizeof(x264_param_t)); x264_encoder_parameters(ctx->encoder, param); param->rc.f_rf_constant = new_q; pic_in->param = param; pic_in->param->param_free = free; } } x264_nal_t* nals; int i_nals; int frame_size = x264_encoder_encode(ctx->encoder, &nals, &i_nals, pic_in, &pic_out); if (frame_size < 0) { fprintf(stderr, "Problem during x264_encoder_encode: frame_size is invalid!\n"); free_csc_image(pic_in); *out = NULL; *outsz = 0; return 2; } free_csc_image(pic_in); /* Do not clean that! */ *out = nals[0].p_payload; *outsz = frame_size; return 0; }
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; }
// See https://gist.github.com/roxlu/0f61a499df75e64b764d for an older version of this, with some rate control tests // @todo - we should check if the supplied settings are valid for the current profile.. e.g. bframes are not supported by the baseline profile bool VideoEncoder::initializeX264() { assert(settings.width > 0); assert(settings.height > 0); assert(settings.fps > 0); int r = 0; x264_param_t* p = ¶ms; std::string preset = (settings.preset.size()) ? settings.preset : "superfast"; std::string tune = (settings.tune.size()) ? settings.tune : "zerolatency"; STREAMER_STATUS("x264 using preset: %s and tune: %s\n", preset.c_str(), tune.c_str()); r = x264_param_default_preset(p, preset.c_str(), tune.c_str()); if(r != 0) { STREAMER_ERROR("error: cannot set the default preset on x264.\n"); return false; } p->i_threads = settings.threads; p->i_width = settings.width; p->i_height = settings.height; p->i_fps_num = settings.fps; p->i_fps_den = 1; p->b_annexb = 0; // flv == no annexb, but strangely, when I disable it the generated flv cannot be played back, for raw h264 you'll need to set annexb to 1 when you want to play it in vlc (vlc isn't properly playing back flv) p->rc.i_rc_method = X264_RC_ABR; // when you're limited to bandwidth you set the vbv_buffer_size and vbv_max_bitrate using the X264_RC_ABR rate control method. The vbv_buffer_size is a decoder option and tells the decoder how much data must be buffered before playback can start. When vbv_max_bitrate == vbv_buffer_size, then it will take one second before the playback might start. when vbv_buffer_size == vbv_max_bitrate * 0.5, it might start in 0.5 sec. p->rc.i_bitrate = settings.bitrate; p->rc.i_vbv_buffer_size = (settings.vbv_buffer_size < 0) ? p->rc.i_bitrate : settings.vbv_buffer_size; p->rc.i_vbv_max_bitrate = (settings.vbv_max_bitrate < 0) ? p->rc.i_bitrate : settings.vbv_max_bitrate;; if(settings.keyint_max > 0) { p->i_keyint_max = settings.keyint_max; } if(settings.bframe > 0) { p->i_bframe = settings.bframe; } if(settings.level_idc > 0) { p->i_level_idc = settings.level_idc; } #if !defined(NDEBUG) p->i_log_level = X264_LOG_DEBUG; p->pf_log = videoencoder_x264_log; #endif if(settings.profile.size()) { r = x264_param_apply_profile(p, settings.profile.c_str()); if(r != 0) { STREAMER_ERROR("error: cannot set the baseline profile on x264.\n"); return false; } } encoder = x264_encoder_open(p); if(!encoder) { STREAMER_ERROR("error: cannot create the encoder.\n"); return false; } x264_encoder_parameters(encoder, ¶ms); print_x264_params(p); return true; }
static void *start_encoder( void *ptr ) { obe_vid_enc_params_t *enc_params = ptr; obe_t *h = enc_params->h; obe_encoder_t *encoder = enc_params->encoder; x264_t *s = NULL; x264_picture_t pic, pic_out; x264_nal_t *nal; int i_nal, frame_size = 0, user_sar_width, user_sar_height; int64_t pts = 0, arrival_time = 0, frame_duration, buffer_duration; int64_t *pts2; float buffer_fill; obe_raw_frame_t *raw_frame; obe_coded_frame_t *coded_frame; /* TODO: check for width, height changes */ /* Lock the mutex until we verify and fetch new parameters */ pthread_mutex_lock( &encoder->encoder_mutex ); enc_params->avc_param.pf_log = x264_logger; s = x264_encoder_open( &enc_params->avc_param ); if( !s ) { pthread_mutex_unlock( &encoder->encoder_mutex ); fprintf( stderr, "[x264]: encoder configuration failed\n" ); goto end; } x264_encoder_parameters( s, &enc_params->avc_param ); encoder->encoder_params = malloc( sizeof(enc_params->avc_param) ); if( !encoder->encoder_params ) { pthread_mutex_unlock( &encoder->encoder_mutex ); syslog( LOG_ERR, "Malloc failed\n" ); goto end; } memcpy( encoder->encoder_params, &enc_params->avc_param, sizeof(enc_params->avc_param) ); encoder->is_ready = 1; /* XXX: This will need fixing for soft pulldown streams */ frame_duration = av_rescale_q( 1, (AVRational){enc_params->avc_param.i_fps_den, enc_params->avc_param.i_fps_num}, (AVRational){1, OBE_CLOCK} ); buffer_duration = frame_duration * enc_params->avc_param.sc.i_buffer_size; /* Broadcast because input and muxer can be stuck waiting for encoder */ pthread_cond_broadcast( &encoder->encoder_cv ); pthread_mutex_unlock( &encoder->encoder_mutex ); user_sar_width = enc_params->avc_param.vui.i_sar_width; user_sar_height = enc_params->avc_param.vui.i_sar_height; while( 1 ) { pthread_mutex_lock( &encoder->encoder_mutex ); if( encoder->cancel_thread ) { pthread_mutex_unlock( &encoder->encoder_mutex ); break; } if( !encoder->num_raw_frames ) pthread_cond_wait( &encoder->encoder_cv, &encoder->encoder_mutex ); if( encoder->cancel_thread ) { pthread_mutex_unlock( &encoder->encoder_mutex ); break; } /* Reset the speedcontrol buffer if the source has dropped frames. Otherwise speedcontrol * stays in an underflow state and is locked to the fastest preset */ pthread_mutex_lock( &h->drop_mutex ); if( h->encoder_drop ) { pthread_mutex_lock( &h->smoothing_mutex ); h->smoothing_buffer_complete = 0; pthread_mutex_unlock( &h->smoothing_mutex ); syslog( LOG_INFO, "Speedcontrol reset\n" ); x264_speedcontrol_sync( s, enc_params->avc_param.sc.i_buffer_size, enc_params->avc_param.sc.f_buffer_init, 0 ); h->encoder_drop = 0; } pthread_mutex_unlock( &h->drop_mutex ); raw_frame = encoder->frames[0]; pthread_mutex_unlock( &encoder->encoder_mutex ); if( convert_obe_to_x264_pic( &pic, raw_frame ) < 0 ) { syslog( LOG_ERR, "Malloc failed\n" ); break; } /* FIXME: if frames are dropped this might not be true */ pic.i_pts = pts++; pts2 = malloc( sizeof(int64_t) ); if( !pts2 ) { syslog( LOG_ERR, "Malloc failed\n" ); break; } pts2[0] = raw_frame->pts; pic.opaque = pts2; /* If the AFD has changed, then change the SAR. x264 will write the SAR at the next keyframe * TODO: allow user to force keyframes in order to be frame accurate */ if( raw_frame->sar_width != enc_params->avc_param.vui.i_sar_width || raw_frame->sar_height != enc_params->avc_param.vui.i_sar_height ) { /* If the frame's SAR has been guessed but the user entered a reasonable SAR, then use it. * Otherwise, use the guessed SAR. */ if( raw_frame->sar_guess && user_sar_width > 0 && user_sar_height > 0 ) { enc_params->avc_param.vui.i_sar_width = user_sar_width; enc_params->avc_param.vui.i_sar_height = user_sar_height; } else { enc_params->avc_param.vui.i_sar_width = raw_frame->sar_width; enc_params->avc_param.vui.i_sar_height = raw_frame->sar_height; } x264_encoder_reconfig( s, &enc_params->avc_param ); } /* Update speedcontrol based on the system state */ if( h->obe_system == OBE_SYSTEM_TYPE_GENERIC ) { pthread_mutex_lock( &h->smoothing_mutex ); if( h->smoothing_buffer_complete ) { /* Wait until a frame is sent out. */ while( !h->smoothing_last_exit_time ) pthread_cond_wait( &h->smoothing_out_cv, &h->smoothing_mutex ); /* time elapsed since last frame was removed */ int64_t last_frame_delta = get_input_clock_in_mpeg_ticks( h ) - h->smoothing_last_exit_time; if( h->num_smoothing_frames ) { int64_t frame_durations = h->smoothing_frames[h->num_smoothing_frames-1]->real_dts - h->smoothing_frames[0]->real_dts + frame_duration; buffer_fill = (float)(frame_durations - last_frame_delta)/buffer_duration; } else buffer_fill = (float)(-1 * last_frame_delta)/buffer_duration; x264_speedcontrol_sync( s, buffer_fill, enc_params->avc_param.sc.i_buffer_size, 1 ); } pthread_mutex_unlock( &h->smoothing_mutex ); } frame_size = x264_encoder_encode( s, &nal, &i_nal, &pic, &pic_out ); arrival_time = raw_frame->arrival_time; raw_frame->release_data( raw_frame ); raw_frame->release_frame( raw_frame ); remove_frame_from_encode_queue( encoder ); if( frame_size < 0 ) { syslog( LOG_ERR, "x264_encoder_encode failed\n" ); break; } if( frame_size ) { coded_frame = new_coded_frame( encoder->stream_id, frame_size ); if( !coded_frame ) { syslog( LOG_ERR, "Malloc failed\n" ); break; } memcpy( coded_frame->data, nal[0].p_payload, frame_size ); coded_frame->is_video = 1; coded_frame->len = frame_size; coded_frame->cpb_initial_arrival_time = pic_out.hrd_timing.safe_cpb_initial_arrival_time; coded_frame->cpb_final_arrival_time = pic_out.hrd_timing.cpb_final_arrival_time; coded_frame->real_dts = pic_out.hrd_timing.cpb_removal_time; coded_frame->real_pts = pic_out.hrd_timing.dpb_output_time; pts2 = pic_out.opaque; coded_frame->pts = pts2[0]; coded_frame->random_access = pic_out.b_keyframe; coded_frame->priority = IS_X264_TYPE_I( pic_out.i_type ); free( pic_out.opaque ); if( h->obe_system == OBE_SYSTEM_TYPE_LOW_LATENCY ) { coded_frame->arrival_time = arrival_time; //printf("\n Encode Latency %"PRIi64" \n", obe_mdate() - coded_frame->arrival_time ); } add_to_smoothing_queue( h, coded_frame ); } } end: if( s ) x264_encoder_close( s ); free( enc_params ); return NULL; }