static switch_status_t switch_vpx_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings) { vpx_context_t *context = NULL; int encoding, decoding; encoding = (flags & SWITCH_CODEC_FLAG_ENCODE); decoding = (flags & SWITCH_CODEC_FLAG_DECODE); if (!(encoding || decoding) || ((context = switch_core_alloc(codec->memory_pool, sizeof(*context))) == 0)) { return SWITCH_STATUS_FALSE; } memset(context, 0, sizeof(*context)); context->flags = flags; codec->private_info = context; context->pool = codec->memory_pool; if (codec_settings) { context->codec_settings = *codec_settings; } if (!strcmp(codec->implementation->iananame, "VP9")) { context->is_vp9 = 1; context->encoder_interface = vpx_codec_vp9_cx(); context->decoder_interface = vpx_codec_vp9_dx(); } else { context->encoder_interface = vpx_codec_vp8_cx(); context->decoder_interface = vpx_codec_vp8_dx(); } if (codec->fmtp_in) { codec->fmtp_out = switch_core_strdup(codec->memory_pool, codec->fmtp_in); } if (vpx_codec_enc_config_default(context->encoder_interface, &context->config, 0) != VPX_CODEC_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Encoder config Error\n"); return SWITCH_STATUS_FALSE; } context->codec_settings.video.width = 320; context->codec_settings.video.height = 240; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VPX VER:%s VPX_IMAGE_ABI_VERSION:%d VPX_CODEC_ABI_VERSION:%d\n", vpx_codec_version_str(), VPX_IMAGE_ABI_VERSION, VPX_CODEC_ABI_VERSION); return SWITCH_STATUS_SUCCESS; }
krad_vpx_encoder_t *krad_vpx_encoder_create (int width, int height, int fps_numerator, int fps_denominator, int bitrate) { krad_vpx_encoder_t *kradvpx; kradvpx = calloc(1, sizeof(krad_vpx_encoder_t)); kradvpx->width = width; kradvpx->height = height; kradvpx->fps_numerator = fps_numerator; kradvpx->fps_denominator = fps_denominator; kradvpx->bitrate = bitrate; printk ("Krad Radio using libvpx version: %s", vpx_codec_version_str ()); if ((kradvpx->image = vpx_img_alloc (NULL, VPX_IMG_FMT_YV12, kradvpx->width, kradvpx->height, 1)) == NULL) { failfast ("Failed to allocate vpx image\n"); } kradvpx->res = vpx_codec_enc_config_default (vpx_codec_vp8_cx(), &kradvpx->cfg, 0); if (kradvpx->res) { failfast ("Failed to get config: %s\n", vpx_codec_err_to_string(kradvpx->res)); } // print default config //krad_vpx_encoder_print_config (kradvpx); kradvpx->cfg.g_w = kradvpx->width; kradvpx->cfg.g_h = kradvpx->height; /* Next two lines are really right */ kradvpx->cfg.g_timebase.num = kradvpx->fps_denominator; kradvpx->cfg.g_timebase.den = kradvpx->fps_numerator; kradvpx->cfg.rc_target_bitrate = bitrate; kradvpx->cfg.g_threads = 4; kradvpx->cfg.kf_mode = VPX_KF_AUTO; kradvpx->cfg.rc_end_usage = VPX_VBR; kradvpx->deadline = 15 * 1000; kradvpx->min_quantizer = kradvpx->cfg.rc_min_quantizer; kradvpx->max_quantizer = kradvpx->cfg.rc_max_quantizer; //krad_vpx_encoder_print_config (kradvpx); if (vpx_codec_enc_init(&kradvpx->encoder, vpx_codec_vp8_cx(), &kradvpx->cfg, 0)) { krad_vpx_fail (&kradvpx->encoder, "Failed to initialize encoder"); } //krad_vpx_encoder_print_config (kradvpx); #ifdef BENCHMARK printk ("Benchmarking enabled, reporting every %d frames", BENCHMARK_COUNT); kradvpx->krad_timer = krad_timer_create(); #endif return kradvpx; }
krad_vpx_encoder_t *krad_vpx_encoder_create (int width, int height, int fps_numerator, int fps_denominator, int bitrate) { krad_vpx_encoder_t *vpx; vpx = calloc (1, sizeof(krad_vpx_encoder_t)); vpx->width = width; vpx->height = height; vpx->fps_numerator = fps_numerator; vpx->fps_denominator = fps_denominator; vpx->bitrate = bitrate; printk ("Krad Radio using libvpx version: %s", vpx_codec_version_str ()); vpx->res = vpx_codec_enc_config_default (vpx_codec_vp8_cx(), &vpx->cfg, 0); if (vpx->res) { failfast ("Failed to get config: %s\n", vpx_codec_err_to_string(vpx->res)); } printk ("For reference the default config is:"); krad_vpx_encoder_print_config (vpx); vpx->cfg.g_w = vpx->width; vpx->cfg.g_h = vpx->height; /* Next two lines are really right */ vpx->cfg.g_timebase.num = vpx->fps_denominator; vpx->cfg.g_timebase.den = vpx->fps_numerator; vpx->cfg.rc_target_bitrate = bitrate; vpx->cfg.g_threads = 4; vpx->cfg.kf_mode = VPX_KF_AUTO; vpx->cfg.rc_end_usage = VPX_VBR; vpx->cfg.kf_max_dist = 120; vpx->deadline = 15 * 1000; vpx->min_quantizer = vpx->cfg.rc_min_quantizer; vpx->max_quantizer = vpx->cfg.rc_max_quantizer; if (vpx_codec_enc_init (&vpx->encoder, vpx_codec_vp8_cx(), &vpx->cfg, 0)) { krad_vpx_fail (&vpx->encoder, "Failed to initialize encoder"); } krad_vpx_encoder_print_config (vpx); return vpx; }
/* * Method: codec_enc_config_default */ JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_video_VPX_codec_1enc_1config_1default (JNIEnv *env, jclass clazz, jint iface, jlong cfg, jint usage) { return vpx_codec_enc_config_default( GET_INTERFACE(iface), (vpx_codec_enc_cfg_t *) (intptr_t) cfg, (int) usage); }
int vp8Encoder::initilize(int frameWidth, int frameHeight) { //display_width = frameWidth; //display_height = frameHeight; pthread_mutex_lock (&mCodecLock); frame_cnt = 0; vpx_codec_enc_cfg_t cfg; int cpu_used = 8; int static_threshold = 1200; vpx_codec_enc_config_default(interface, &cfg, 0); LOGD("Using %s\n",vpx_codec_iface_name(interface)); cfg.rc_target_bitrate = 10*frameWidth * frameHeight * cfg.rc_target_bitrate / cfg.g_w / cfg.g_h; LOGD("Encoder cfg.rc_target_bitrate=%d", cfg.rc_target_bitrate); cfg.g_w = display_width; cfg.g_h = display_height; /*cfg.g_timebase.num = 1; cfg.g_timebase.den = (int) 10000000; cfg.rc_end_usage = VPX_CBR; cfg.g_pass = VPX_RC_ONE_PASS; cfg.g_lag_in_frames = 0; cfg.rc_min_quantizer = 20; cfg.rc_max_quantizer = 50; cfg.rc_dropframe_thresh = 1; cfg.rc_buf_optimal_sz = 1000; cfg.rc_buf_initial_sz = 1000; cfg.rc_buf_sz = 1000; cfg.g_error_resilient = 1; cfg.kf_mode = VPX_KF_DISABLED; cfg.kf_max_dist = 999999; cfg.g_threads = 1;*/ vpx_codec_enc_init(&encoder, interface, &cfg, 0); /*vpx_codec_control_(&encoder, VP8E_SET_CPUUSED, cpu_used); vpx_codec_control_(&encoder, VP8E_SET_STATIC_THRESHOLD, static_threshold); vpx_codec_control_(&encoder, VP8E_SET_ENABLEAUTOALTREF, 0); */ vpx_img_alloc(&raw, VPX_IMG_FMT_I420, display_width, display_height, 1); //create_packetizer(&x, XOR, fec_numerator, fec_denominator); //sDecoder->initilize(); pthread_mutex_unlock (&mCodecLock); return 0; }
int x_vpx_encoder_init(vpx_codec_ctx_t *_p_encoder, int numcores, int width, int height) { int res; vpx_codec_enc_cfg_t cfg; res = vpx_codec_enc_config_default((vpx_codec_vp8_cx()), &cfg, 0); if (res) { printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); return -EBADF; } /* Update the default configuration with our settings */ printf("Initializing: %dx%d, BR=%d, cfg.g_timebase.den=%d\n", width, height, cfg.rc_target_bitrate, cfg.g_timebase.den); cfg.rc_target_bitrate = width * height * cfg.rc_target_bitrate / cfg.g_w / cfg.g_h * 2; cfg.g_w = width; cfg.g_h = height; cfg.g_profile = 0; //cfg.kf_mode = VPX_KF_AUTO; cfg.kf_max_dist = 30; //cfg.kf_min_dist = 0; cfg.g_threads = 4; cfg.g_pass = VPX_RC_ONE_PASS; cfg.rc_end_usage = VPX_CBR; if (cfg.rc_end_usage == VPX_CBR) { cfg.rc_buf_initial_sz = 2000; cfg.rc_buf_optimal_sz = 2000; cfg.rc_buf_sz = 3000; } // cfg.g_timebase.num = 1001; // cfg.g_timebase.den = 30000; if (vpx_codec_enc_init(_p_encoder, (vpx_codec_vp8_cx()), &cfg, 0)) { printf("Failed to init config: %s\n", vpx_codec_error(_p_encoder)); die_codec(_p_encoder, "vpx_codec_enc_init()"); return -ENOMEM; } return 0; }
void WebMEncoder::initializeVideoEncoder() { /* Populate encoder configuration */ vpx_codec_err_t res = vpx_codec_enc_config_default(&vpx_enc_vp8_algo, &cfg, 0); if (res) { fprintf(stderr, "Failed to get config: %s\n", vpx_codec_err_to_string(res)); exit(1); } if(boost::thread::hardware_concurrency()) { cfg.g_threads = boost::thread::hardware_concurrency() - 1; } /* Change the default timebase to a high enough value so that the encoder * will always create strictly increasing timestamps. */ cfg.g_timebase.num = 1; cfg.g_timebase.den = 30; // lag_in_frames allows for extra optimization at the expense of not writing frames in realtime cfg.g_lag_in_frames = 5; // Variable bit rate cfg.rc_end_usage = VPX_VBR; // Target data rate in Kbps (lowercase b) cfg.rc_target_bitrate = 1024; //1 Mbit/sec /* Never use the library's default resolution, require it be parsed * from the file or set on the command line. */ cfg.g_w = width; cfg.g_h = height; vpx_img_alloc(&raw, VPX_IMG_FMT_YV12, cfg.g_w, cfg.g_h, 1); cfg.g_pass = VPX_RC_ONE_PASS; /* Construct Encoder Context */ vpx_codec_enc_init(&encoder, &vpx_enc_vp8_algo, &cfg, 0); if(encoder.err) { printf("Failed to initialize encoder\n"); } }
information() { m_raw.planes[0] = NULL; m_codec.iface = NULL; vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &m_cfg, 0); m_cfg.rc_target_bitrate = 2000; m_cfg.g_w = 640; m_cfg.g_h = 480; m_frameCnt = 0; vpx_codec_enc_init(&m_codec, vpx_codec_vp8_cx(), &m_cfg, 0); vpx_img_alloc(&m_raw, VPX_IMG_FMT_I420, 640, 480, 1); }
static void gst_vp9_enc_init (GstVP9Enc * gst_vp9_enc) { vpx_codec_err_t status; GstVPXEnc *gst_vpx_enc = GST_VPX_ENC (gst_vp9_enc); GST_DEBUG_OBJECT (gst_vp9_enc, "gst_vp9_enc_init"); status = vpx_codec_enc_config_default (gst_vp9_enc_get_algo (gst_vpx_enc), &gst_vpx_enc->cfg, 0); if (status != VPX_CODEC_OK) { GST_ERROR_OBJECT (gst_vpx_enc, "Failed to get default encoder configuration: %s", gst_vpx_error_name (status)); gst_vpx_enc->have_default_config = FALSE; } else { gst_vpx_enc->have_default_config = TRUE; } }
JNIEXPORT jint Java_ryulib_VideoZip_VPX_OpenEncoder(JNIEnv* env, jclass clazz, jint width, jint height, jint bitRate, int fps, int gop) { RyuVPX *pHandle = (RyuVPX *) malloc(sizeof(RyuVPX)); pHandle->errorCode = 0; if (!vpx_img_alloc(&pHandle->img, VPX_IMG_FMT_I420 , width, height, 1)) { pHandle->errorCode = _Error_Allocate_Image; goto EXIT; } if (vpx_codec_enc_config_default(interfaceEnc, &pHandle->cfgEnc, 0)) { pHandle->errorCode = _Error_Getting_Config; goto EXIT; } pHandle->cfgEnc.g_w = width; pHandle->cfgEnc.g_h = height; pHandle->cfgEnc.rc_target_bitrate = bitRate; if (0 != bitRate) { pHandle->cfgEnc.rc_target_bitrate = bitRate; } else { pHandle->cfgEnc.rc_target_bitrate = width * height * pHandle->cfgEnc.rc_target_bitrate / pHandle->cfgEnc.g_w / pHandle->cfgEnc.g_h; } if (0 != gop) { pHandle->cfgEnc.kf_max_dist = gop; } if (-1 == gop) { pHandle->cfgEnc.kf_mode = VPX_KF_DISABLED; } if (vpx_codec_enc_init(&pHandle->codec, interfaceEnc, &pHandle->cfgEnc, 0)) { pHandle->errorCode = _Error_Init_VideoCodec; goto EXIT; } EXIT: return pHandle; }
HRESULT InitVPXEncoder(vpx_codec_enc_cfg_t * vpxConfig, vpx_codec_ctx_t * vpxCodec, unsigned int width, unsigned int height) { //vpx_codec_ctx_t codec; vpx_codec_err_t res; printf("Using %s\n", vpx_codec_iface_name(vpx_codec_vp8_cx())); /* Populate encoder configuration */ res = vpx_codec_enc_config_default((vpx_codec_vp8_cx()), vpxConfig, 0); if (res) { printf("Failed to get VPX codec config: %s\n", vpx_codec_err_to_string(res)); return -1; } else { vpx_img_alloc(&_rawImage, VIDEO_INPUT_FORMAT, WIDTH, HEIGHT, 0); vpxConfig->g_w = width; vpxConfig->g_h = height; vpxConfig->rc_target_bitrate = 5000; // in kbps. vpxConfig->rc_min_quantizer = 20; // 50; vpxConfig->rc_max_quantizer = 30; // 60; vpxConfig->g_pass = VPX_RC_ONE_PASS; vpxConfig->rc_end_usage = VPX_CBR; //vpxConfig->kf_min_dist = 50; //vpxConfig->kf_max_dist = 50; //vpxConfig->kf_mode = VPX_KF_DISABLED; vpxConfig->g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT; vpxConfig->g_lag_in_frames = 0; vpxConfig->rc_resize_allowed = 0; /* Initialize codec */ if (vpx_codec_enc_init(vpxCodec, (vpx_codec_vp8_cx()), vpxConfig, 0)) { printf("Failed to initialize libvpx encoder.\n"); return -1; } else { return S_OK; } } }
static void enc_init(MSFilter *f) { vpx_codec_err_t res; MSVideoSize vsize; EncState *s=(EncState *)ms_new0(EncState,1); ms_message("Using %s\n",vpx_codec_iface_name(interface)); /* Populate encoder configuration */ res = vpx_codec_enc_config_default(interface, &s->cfg, 0); if(res) { ms_error("Failed to get config: %s\n", vpx_codec_err_to_string(res)); } if (ms_get_cpu_count() > 1) s->vconf_list = &multicore_vp8_conf_list[0]; else s->vconf_list = &vp8_conf_list[0]; MS_VIDEO_SIZE_ASSIGN(vsize, CIF); s->vconf = ms_video_find_best_configuration_for_size(s->vconf_list, vsize); s->frame_count = 0; s->cfg.g_w = s->vconf.vsize.width; s->cfg.g_h = s->vconf.vsize.height; /* encoder automatically places keyframes */ s->cfg.kf_mode = VPX_KF_AUTO; s->cfg.kf_max_dist = 300; s->cfg.rc_target_bitrate = ((float)s->vconf.required_bitrate)*0.92/1024.0; //0.9=take into account IP/UDP/RTP overhead, in average. s->cfg.g_pass = VPX_RC_ONE_PASS; /* -p 1 */ s->cfg.g_timebase.num = 1; s->cfg.g_timebase.den = s->vconf.fps; s->cfg.rc_end_usage = VPX_CBR; /* --end-usage=cbr */ #if TARGET_IPHONE_SIMULATOR s->cfg.g_threads = 1; /*workaround to remove crash on ipad simulator*/ #else s->cfg.g_threads = ms_get_cpu_count(); #endif ms_message("VP8 g_threads=%d", s->cfg.g_threads); s->cfg.rc_undershoot_pct = 95; /* --undershoot-pct=95 */ s->cfg.g_error_resilient = 1; s->cfg.g_lag_in_frames = 0; s->mtu=ms_get_payload_max_size()-1;/*-1 for the vp8 payload header*/ f->data = s; }
int VPXEncoder::InitEncoder(unsigned int width, unsigned int height) { _vpxCodec = new vpx_codec_ctx_t(); _rawImage = new vpx_image_t(); _width = width; _height = height; vpx_codec_enc_cfg_t vpxConfig; vpx_codec_err_t res; printf("Using %s\n", vpx_codec_iface_name(vpx_codec_vp8_cx())); /* Populate encoder configuration */ res = vpx_codec_enc_config_default((vpx_codec_vp8_cx()), &vpxConfig, 0); if (res) { printf("Failed to get VPX codec config: %s\n", vpx_codec_err_to_string(res)); return -1; } else { vpx_img_alloc(_rawImage, VPX_IMG_FMT_I420, width, height, 0); vpxConfig.g_w = width; vpxConfig.g_h = height; vpxConfig.rc_target_bitrate = 300; // 5000; // in kbps. vpxConfig.rc_min_quantizer = 20; // 50; vpxConfig.rc_max_quantizer = 30; // 60; vpxConfig.g_pass = VPX_RC_ONE_PASS; vpxConfig.rc_end_usage = VPX_CBR; vpxConfig.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT; vpxConfig.g_lag_in_frames = 0; vpxConfig.rc_resize_allowed = 0; vpxConfig.kf_max_dist = 20; /* Initialize codec */ if (vpx_codec_enc_init(_vpxCodec, (vpx_codec_vp8_cx()), &vpxConfig, 0)) { printf("Failed to initialize libvpx encoder.\n"); return -1; } } }
static int init_video_encoder(CSSession *cs, uint16_t max_width, uint16_t max_height, uint32_t video_bitrate) { vpx_codec_enc_cfg_t cfg; int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); if (rc != VPX_CODEC_OK) { LOGGER_ERROR("Failed to get config: %s", vpx_codec_err_to_string(rc)); return -1; } cfg.rc_target_bitrate = video_bitrate; cfg.g_w = max_width; cfg.g_h = max_height; cfg.g_pass = VPX_RC_ONE_PASS; cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT | VPX_ERROR_RESILIENT_PARTITIONS; cfg.g_lag_in_frames = 0; cfg.kf_min_dist = 0; cfg.kf_max_dist = 48; cfg.kf_mode = VPX_KF_AUTO; rc = vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION); if ( rc != VPX_CODEC_OK) { LOGGER_ERROR("Failed to initialize encoder: %s", vpx_codec_err_to_string(rc)); return -1; } rc = vpx_codec_control(&cs->v_encoder, VP8E_SET_CPUUSED, 8); if ( rc != VPX_CODEC_OK) { LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); return -1; } cs->max_width = max_width; cs->max_height = max_height; cs->video_bitrate = video_bitrate; return 0; }
int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t video_bitrate) { vpx_codec_enc_cfg_t cfg; int res = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); if (res) { fprintf(stderr, "Failed to get config: %s\n", vpx_codec_err_to_string(res)); return -1; } cfg.rc_target_bitrate = video_bitrate; cfg.g_w = width; cfg.g_h = height; if (vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION) != VPX_CODEC_OK) { fprintf(stderr, "Failed to initialize encoder\n"); return -1; } return 0; }
int start_encode(encoding_context *context, char *path, int width, int height, float fps, int *durations, int deadline) { if (0!=vpx_codec_enc_config_default(WG_CODEC_INTERFACE, &context->cfg, 0)) return 1000; context->cfg.g_w = width; context->cfg.g_h = height; context->deadline = deadline; // microseconds to spend encoding each frame context->timebase_units_per_second = 30.0f; // always 30? context->frames_per_second = fps; context->frame_durations = durations; FILE *outfile = fopen(path, "wb"); if (!outfile) return 1001; context->ebml.stream = outfile; if (!vpx_img_alloc(&context->vpx_image, VPX_IMG_FMT_I420, width, height, 1)) return 1002; if (0!=vpx_codec_enc_init(&context->codec, WG_CODEC_INTERFACE, &context->cfg, 0)) return 1003; struct vpx_rational framerate = {fps, 1}; const struct VpxRational pixel_aspect_ratio = {1, 1}; write_webm_file_header(&context->ebml, &context->cfg, &framerate, STEREO_FORMAT_MONO, WG_FOURCC, &pixel_aspect_ratio); return 0; }
struct vpx_context *init_encoder(int width, int height, const char *colorspace) { vpx_codec_enc_cfg_t cfg; vpx_img_fmt_t vpx_colorspace; struct vpx_context *ctx; vpx_codec_iface_t *codec_iface; vpx_colorspace = get_vpx_colorspace(colorspace); if (vpx_colorspace<0) return NULL; codec_iface = vpx_codec_vp8_cx(); if (vpx_codec_enc_config_default(codec_iface, &cfg, 0)) return NULL; cfg.rc_target_bitrate = width * height * cfg.rc_target_bitrate / cfg.g_w / cfg.g_h; cfg.g_w = width; cfg.g_h = height; cfg.g_error_resilient = 0; cfg.g_lag_in_frames = 0; cfg.rc_dropframe_thresh = 0; //cfg.rc_resize_allowed = 1; ctx = malloc(sizeof(struct vpx_context)); if (ctx == NULL) return NULL; memset(ctx, 0, sizeof(struct vpx_context)); if (vpx_codec_enc_init(&ctx->codec, codec_iface, &cfg, 0)) { codec_error(&ctx->codec, "vpx_codec_enc_init"); free(ctx); return NULL; } ctx->width = width; ctx->height = height; ctx->pixfmt = vpx_colorspace; return ctx; }
static void enc_init(MSFilter *f) { vpx_codec_err_t res; EncState *s=(EncState *)ms_new0(EncState,1); ms_message("Using %s\n",vpx_codec_iface_name(interface)); /* Populate encoder configuration */ res = vpx_codec_enc_config_default(interface, &s->cfg, 0); if(res) { ms_error("Failed to get config: %s\n", vpx_codec_err_to_string(res)); } s->width = MS_VIDEO_SIZE_CIF_W; s->height = MS_VIDEO_SIZE_CIF_H; s->bitrate=256000; s->frame_count = 0; s->cfg.g_w = s->width; s->cfg.g_h = s->height; /* encoder automatically places keyframes */ s->cfg.kf_mode = VPX_KF_AUTO; s->cfg.kf_max_dist = 300; s->cfg.rc_target_bitrate = ((float)s->bitrate)*0.92/1024.0; //0.9=take into account IP/UDP/RTP overhead, in average. s->cfg.g_pass = VPX_RC_ONE_PASS; /* -p 1 */ s->fps=15; s->cfg.g_timebase.num = 1; s->cfg.g_timebase.den = s->fps; s->cfg.rc_end_usage = VPX_CBR; /* --end-usage=cbr */ s->cfg.g_threads = ms_get_cpu_count(); ms_message("VP8 g_threads=%d", s->cfg.g_threads); s->cfg.rc_undershoot_pct = 95; /* --undershoot-pct=95 */ s->cfg.g_error_resilient = 1; s->cfg.g_lag_in_frames = 0; s->mtu=ms_get_payload_max_size()-1;/*-1 for the vp8 payload header*/ f->data = s; }
int main(int argc, char **argv) { FILE *infile, *outfile; vpx_codec_ctx_t codec; vpx_codec_enc_cfg_t cfg; int frame_cnt = 0; vpx_image_t raw; vpx_codec_err_t res; long width; long height; int frame_avail; int got_data; int flags = 0; /* Open files */ if(argc!=5) die("Usage: %s <width> <height> <infile> <outfile>\n", argv[0]); width = strtol(argv[1], NULL, 0); height = strtol(argv[2], NULL, 0); if(width < 16 || width%2 || height <16 || height%2) die("Invalid resolution: %ldx%ld", width, height); if(!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 1)) die("Faile to allocate image", width, height); if(!(outfile = fopen(argv[4], "wb"))) die("Failed to open %s for writing", argv[4]); printf("Using %s\n",vpx_codec_iface_name(interface)); /* Populate encoder configuration */ // res = vpx_codec_enc_config_default(interface, &cfg, 0); // if(res) { // printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); // return EXIT_FAILURE; // } // /* Update the default configuration with our settings */ // cfg.rc_target_bitrate = width * height * cfg.rc_target_bitrate // / cfg.g_w / cfg.g_h; // cfg.g_w = width; // cfg.g_h = height; // write_ivf_file_header(outfile, &cfg, 0); /* Open input file for this encoding pass */ if(!(infile = fopen(argv[3], "rb"))) die("Failed to open %s for reading", argv[3]); /* Initialize codec */ // if(vpx_codec_enc_init(&codec, interface, &cfg, 0)) // die_codec(&codec, "Failed to initialize encoder"); // frame_avail = 1; got_data = 0; while(frame_avail || got_data) { vpx_codec_iter_t iter = NULL; const vpx_codec_cx_pkt_t *pkt; frame_avail = read_frame(infile, &raw); // if(vpx_codec_encode(&codec, frame_avail? &raw : NULL, frame_cnt, // 1, flags, VPX_DL_REALTIME)) // die_codec(&codec, "Failed to encode frame"); // got_data = 0; while( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) { got_data = 1; switch(pkt->kind) { case VPX_CODEC_CX_FRAME_PKT: // write_ivf_frame_header(outfile, pkt); // if(fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, // outfile)); // break; // default: break; } printf(pkt->kind == VPX_CODEC_CX_FRAME_PKT && (pkt->data.frame.flags & VPX_FRAME_IS_KEY)? "K":"."); fflush(stdout); } frame_cnt++; } printf("\n"); fclose(infile); printf("Processed %d frames.\n",frame_cnt-1); if(vpx_codec_destroy(&codec)) // die_codec(&codec, "Failed to destroy codec"); // /* Try to rewrite the file header with the actual frame count */ if(!fseek(outfile, 0, SEEK_SET)) write_ivf_file_header(outfile, &cfg, frame_cnt-1); fclose(outfile); return EXIT_SUCCESS; }
int main(int argc, char* argv[]) { if (argc != 7) { fprintf(stderr, " Usage: WebMEnc <input filename> <flip> <threads> <bit-rates> <frame-per-second> <output filename>\nExample: WebMEnc frame.%%.5d.tiff 1 8 512 30 frame.webm\n"); return EXIT_FAILURE; } ilInit(); iluInit(); // Initialize VPX codec. // vpx_codec_ctx_t vpxContext; vpx_codec_enc_cfg_t vpxConfig; if (vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &vpxConfig, 0) != VPX_CODEC_OK) { return EXIT_FAILURE; } // Try to load the first frame to initialize width and height. // int flip = (bool)atoi(argv[2]); vpx_image_t *rgbImage = NULL, *yv12Image = NULL; if (readImage(argv[1], 0, &rgbImage, &yv12Image, flip) == false) { return EXIT_FAILURE; } vpxConfig.g_h = yv12Image->h; vpxConfig.g_w = yv12Image->w; vpxConfig.g_threads = atoi(argv[3]); vpxConfig.rc_target_bitrate = atoi(argv[4]); vpxConfig.g_timebase.den = atoi(argv[5]); vpxConfig.g_timebase.num = 1; // Prepare the output .webm file. // EbmlGlobal ebml; memset(&ebml, 0, sizeof(EbmlGlobal)); ebml.last_pts_ms = -1; ebml.stream = fopen(argv[6], "wb"); if (ebml.stream == NULL) { return EXIT_FAILURE; } vpx_rational ebmlFPS = vpxConfig.g_timebase; struct vpx_rational arg_framerate = {atoi(argv[5]), 1}; Ebml_WriteWebMFileHeader(&ebml, &vpxConfig, &arg_framerate); unsigned long duration = (float)arg_framerate.den / (float)arg_framerate.num * 1000; if (vpx_codec_enc_init(&vpxContext, vpx_codec_vp8_cx(), &vpxConfig, 0) != VPX_CODEC_OK) { return EXIT_FAILURE; } // fprintf(stdout, "input=%s\nflip=%s\nthreads=%s\nbps=%s\nfps=%s\noutput=%s\n", argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]); // Reading image file sequence, encoding to .WebM file. // int frameNumber = 0; while(readImage(argv[1], frameNumber, &rgbImage, &yv12Image, flip)) { vpx_codec_err_t vpxError = vpx_codec_encode(&vpxContext, yv12Image, frameNumber, duration, 0, 0); if (vpxError != VPX_CODEC_OK) { return EXIT_FAILURE; } vpx_codec_iter_t iter = NULL; const vpx_codec_cx_pkt_t *packet; while( (packet = vpx_codec_get_cx_data(&vpxContext, &iter)) ) { Ebml_WriteWebMBlock(&ebml, &vpxConfig, packet); } frameNumber ++; printf("Processed %d frames.\r", frameNumber); vpx_img_free(yv12Image); yv12Image = NULL; } Ebml_WriteWebMFileFooter(&ebml, 0); fclose(ebml.stream); vpx_codec_destroy(&vpxContext); return EXIT_SUCCESS; }
int main(int argc, char **argv) { FILE *infile, *outfile[MAX_LAYERS]; vpx_codec_ctx_t codec; vpx_codec_enc_cfg_t cfg; int frame_cnt = 0; vpx_image_t raw; vpx_codec_err_t res; unsigned int width; unsigned int height; int frame_avail; int got_data; int flags = 0; int i; int pts = 0; // PTS starts at 0 int frame_duration = 1; // 1 timebase tick per frame int layering_mode = 0; int frames_in_layer[MAX_LAYERS] = {0}; int layer_flags[MAX_PERIODICITY] = {0}; // Check usage and arguments if (argc < 9) die("Usage: %s <infile> <outfile> <width> <height> <rate_num> " " <rate_den> <mode> <Rate_0> ... <Rate_nlayers-1>\n", argv[0]); width = strtol (argv[3], NULL, 0); height = strtol (argv[4], NULL, 0); if (width < 16 || width%2 || height <16 || height%2) die ("Invalid resolution: %d x %d", width, height); if (!sscanf(argv[7], "%d", &layering_mode)) die ("Invalid mode %s", argv[7]); if (layering_mode<0 || layering_mode>6) die ("Invalid mode (0..6) %s", argv[7]); if (argc != 8+mode_to_num_layers[layering_mode]) die ("Invalid number of arguments"); if (!vpx_img_alloc (&raw, VPX_IMG_FMT_I420, width, height, 1)) die ("Failed to allocate image", width, height); printf("Using %s\n",vpx_codec_iface_name(interface)); // Populate encoder configuration res = vpx_codec_enc_config_default(interface, &cfg, 0); if(res) { printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); return EXIT_FAILURE; } // Update the default configuration with our settings cfg.g_w = width; cfg.g_h = height; // Timebase format e.g. 30fps: numerator=1, demoninator=30 if (!sscanf (argv[5], "%d", &cfg.g_timebase.num )) die ("Invalid timebase numerator %s", argv[5]); if (!sscanf (argv[6], "%d", &cfg.g_timebase.den )) die ("Invalid timebase denominator %s", argv[6]); for (i=8; i<8+mode_to_num_layers[layering_mode]; i++) if (!sscanf(argv[i], "%d", &cfg.ts_target_bitrate[i-8])) die ("Invalid data rate %s", argv[i]); // Real time parameters cfg.rc_dropframe_thresh = 0; cfg.rc_end_usage = VPX_CBR; cfg.rc_resize_allowed = 0; cfg.rc_min_quantizer = 4; cfg.rc_max_quantizer = 63; cfg.rc_undershoot_pct = 98; cfg.rc_overshoot_pct = 100; cfg.rc_buf_initial_sz = 500; cfg.rc_buf_optimal_sz = 600; cfg.rc_buf_sz = 1000; // Enable error resilient mode cfg.g_error_resilient = 1; cfg.g_lag_in_frames = 0; cfg.kf_mode = VPX_KF_DISABLED; // Disable automatic keyframe placement cfg.kf_min_dist = cfg.kf_max_dist = 1000; // Temporal scaling parameters: // NOTE: The 3 prediction frames cannot be used interchangeably due to // differences in the way they are handled throughout the code. The // frames should be allocated to layers in the order LAST, GF, ARF. // Other combinations work, but may produce slightly inferior results. switch (layering_mode) { case 0: { // 2-layers, 2-frame period int ids[2] = {0,1}; cfg.ts_number_layers = 2; cfg.ts_periodicity = 2; cfg.ts_rate_decimator[0] = 2; cfg.ts_rate_decimator[1] = 1; memcpy(cfg.ts_layer_id, ids, sizeof(ids)); #if 1 // 0=L, 1=GF, Intra-layer prediction enabled layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF; layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_REF_ARF; #else // 0=L, 1=GF, Intra-layer prediction disabled layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF; layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_LAST; #endif break; } case 1: { // 2-layers, 3-frame period int ids[3] = {0,1,1}; cfg.ts_number_layers = 2; cfg.ts_periodicity = 3; cfg.ts_rate_decimator[0] = 3; cfg.ts_rate_decimator[1] = 1; memcpy(cfg.ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, Intra-layer prediction enabled layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[1] = layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; break; } case 2: { // 3-layers, 6-frame period int ids[6] = {0,2,2,1,2,2}; cfg.ts_number_layers = 3; cfg.ts_periodicity = 6; cfg.ts_rate_decimator[0] = 6; cfg.ts_rate_decimator[1] = 3; cfg.ts_rate_decimator[2] = 1; memcpy(cfg.ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; layer_flags[1] = layer_flags[2] = layer_flags[4] = layer_flags[5] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST; break; } case 3: { // 3-layers, 4-frame period int ids[4] = {0,2,1,2}; cfg.ts_number_layers = 3; cfg.ts_periodicity = 4; cfg.ts_rate_decimator[0] = 4; cfg.ts_rate_decimator[1] = 2; cfg.ts_rate_decimator[2] = 1; memcpy(cfg.ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, 2=ARF, Intra-layer prediction disabled layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; layer_flags[1] = layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; break; } case 4: { // 3-layers, 4-frame period int ids[4] = {0,2,1,2}; cfg.ts_number_layers = 3; cfg.ts_periodicity = 4; cfg.ts_rate_decimator[0] = 4; cfg.ts_rate_decimator[1] = 2; cfg.ts_rate_decimator[2] = 1; memcpy(cfg.ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled in layer 1, // disabled in layer 2 layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[2] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; layer_flags[1] = layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; break; } case 5: { // 3-layers, 4-frame period int ids[4] = {0,2,1,2}; cfg.ts_number_layers = 3; cfg.ts_periodicity = 4; cfg.ts_rate_decimator[0] = 4; cfg.ts_rate_decimator[1] = 2; cfg.ts_rate_decimator[2] = 1; memcpy(cfg.ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[2] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; layer_flags[1] = layer_flags[3] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF; break; } case 6: { // NOTE: Probably of academic interest only // 5-layers, 16-frame period int ids[16] = {0,4,3,4,2,4,3,4,1,4,3,4,2,4,3,4}; cfg.ts_number_layers = 5; cfg.ts_periodicity = 16; cfg.ts_rate_decimator[0] = 16; cfg.ts_rate_decimator[1] = 8; cfg.ts_rate_decimator[2] = 4; cfg.ts_rate_decimator[3] = 2; cfg.ts_rate_decimator[4] = 1; memcpy(cfg.ts_layer_id, ids, sizeof(ids)); layer_flags[0] = VPX_EFLAG_FORCE_KF; layer_flags[1] = layer_flags[3] = layer_flags[5] = layer_flags[7] = layer_flags[9] = layer_flags[11] = layer_flags[13] = layer_flags[15] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_ENTROPY; layer_flags[2] = layer_flags[6] = layer_flags[10] = layer_flags[14] = 0; layer_flags[4] = layer_flags[12] = VP8_EFLAG_NO_REF_LAST; layer_flags[8] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ENTROPY; break; } default: break; } // Open input file if(!(infile = fopen(argv[1], "rb"))) die("Failed to open %s for reading", argv[1]); // Open an output file for each stream for (i=0; i<cfg.ts_number_layers; i++) { char file_name[512]; sprintf (file_name, "%s_%d.ivf", argv[2], i); if (!(outfile[i] = fopen(file_name, "wb"))) die("Failed to open %s for writing", file_name); write_ivf_file_header(outfile[i], &cfg, 0); } // Initialize codec if (vpx_codec_enc_init (&codec, interface, &cfg, 0)) die_codec (&codec, "Failed to initialize encoder"); // Cap CPU & first I-frame size vpx_codec_control (&codec, VP8E_SET_CPUUSED, -6); vpx_codec_control (&codec, VP8E_SET_MAX_INTRA_BITRATE_PCT, 600); frame_avail = 1; while (frame_avail || got_data) { vpx_codec_iter_t iter = NULL; const vpx_codec_cx_pkt_t *pkt; flags = layer_flags[frame_cnt % cfg.ts_periodicity]; frame_avail = read_frame(infile, &raw); if (vpx_codec_encode(&codec, frame_avail? &raw : NULL, pts, 1, flags, VPX_DL_REALTIME)) die_codec(&codec, "Failed to encode frame"); // Reset KF flag layer_flags[0] &= ~VPX_EFLAG_FORCE_KF; got_data = 0; while ( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) { got_data = 1; switch (pkt->kind) { case VPX_CODEC_CX_FRAME_PKT: for (i=cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity]; i<cfg.ts_number_layers; i++) { write_ivf_frame_header(outfile[i], pkt); if (fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile[i])); frames_in_layer[i]++; } break; default: break; } printf (pkt->kind == VPX_CODEC_CX_FRAME_PKT && (pkt->data.frame.flags & VPX_FRAME_IS_KEY)? "K":"."); fflush (stdout); } frame_cnt++; pts += frame_duration; } printf ("\n"); fclose (infile); printf ("Processed %d frames.\n",frame_cnt-1); if (vpx_codec_destroy(&codec)) die_codec (&codec, "Failed to destroy codec"); // Try to rewrite the output file headers with the actual frame count for (i=0; i<cfg.ts_number_layers; i++) { if (!fseek(outfile[i], 0, SEEK_SET)) write_ivf_file_header (outfile[i], &cfg, frames_in_layer[i]); fclose (outfile[i]); } return EXIT_SUCCESS; }
// Prepare to compress frames. // Compressor should record session and sessionOptions for use in later calls. // Compressor may modify imageDescription at this point. // Compressor may create and return pixel buffer options. ComponentResult VP8_Encoder_PrepareToCompressFrames( VP8EncoderGlobals glob, ICMCompressorSessionRef session, ICMCompressionSessionOptionsRef sessionOptions, ImageDescriptionHandle imageDescription, void *reserved, CFDictionaryRef *compressorPixelBufferAttributesOut) { dbg_printf("[vp8e] Prepare to Compress Frames\n", (UInt32)glob); ComponentResult err = noErr; CFMutableDictionaryRef compressorPixelBufferAttributes = NULL; //This format later needs to be converted OSType pixelFormatList[] = { k422YpCbCr8PixelFormat }; // also known as '2vuy' Fixed gammaLevel; int frameIndex; SInt32 widthRoundedUp, heightRoundedUp; // Record the compressor session for later calls to the ICM. // Note: this is NOT a CF type and should NOT be CFRetained or CFReleased. glob->session = session; // Retain the session options for later use. ICMCompressionSessionOptionsRelease(glob->sessionOptions); glob->sessionOptions = sessionOptions; ICMCompressionSessionOptionsRetain(glob->sessionOptions); // Modify imageDescription here if needed. // We'll set the image description gamma level to say "2.2". gammaLevel = kQTCCIR601VideoGammaLevel; err = ICMImageDescriptionSetProperty(imageDescription, kQTPropertyClass_ImageDescription, kICMImageDescriptionPropertyID_GammaLevel, sizeof(gammaLevel), &gammaLevel); if (err) goto bail; // Record the dimensions from the image description. glob->width = (*imageDescription)->width; glob->height = (*imageDescription)->height; dbg_printf("[vp8e - %08lx] Prepare to compress frame width %d height %d\n", (UInt32)glob, glob->width, glob->height); if (glob->width < 16 || glob->width % 2 || glob->height < 16 || glob->height % 2) dbg_printf("[vp8e - %08lx] Warning :: Invalid resolution: %ldx%ld", (UInt32)glob, glob->width, glob->height); if (glob->raw == NULL) glob->raw = calloc(1, sizeof(vpx_image_t)); //Right now I'm only using YV12, this is great for webm, as I control the spit component if (!vpx_img_alloc(glob->raw, IMG_FMT_YV12, glob->width, glob->height, 1)) { dbg_printf("[vp8e - %08lx] Error: Failed to allocate image %dx%d", (UInt32)glob, glob->width, glob->height); err = paramErr; goto bail; } glob->maxEncodedDataSize = glob->width * glob->height * 2; dbg_printf("[vp8e - %08lx] currently allocating %d bytes as my max encoded size\n", (UInt32)glob, glob->maxEncodedDataSize); // Create a pixel buffer attributes dictionary. err = createPixelBufferAttributesDictionary(glob->width, glob->height, pixelFormatList, sizeof(pixelFormatList) / sizeof(OSType), &compressorPixelBufferAttributes); if (err) goto bail; *compressorPixelBufferAttributesOut = compressorPixelBufferAttributes; compressorPixelBufferAttributes = NULL; /* Populate encoder configuration */ glob->res = vpx_codec_enc_config_default((&vpx_codec_vp8_cx_algo), &glob->cfg, 0); if (glob->res) { dbg_printf("[vp8e - %08lx] Failed to get config: %s\n", (UInt32)glob, vpx_codec_err_to_string(glob->res)); err = paramErr; //this may be something different .... goto bail; } glob->cfg.g_w = glob->width; glob->cfg.g_h = glob->height; dbg_printf("[vp8e - %08lx] resolution %dx%d\n", (UInt32)glob, glob->cfg.g_w, glob->cfg.g_h); bail: if (err) dbg_printf("[vp8e - %08lx] Error %d\n", (UInt32)glob, err); if (compressorPixelBufferAttributes) CFRelease(compressorPixelBufferAttributes); return err; }
static gboolean gst_vp8_enc_handle_frame (GstBaseVideoEncoder * base_video_encoder, GstVideoFrame * frame) { GstVP8Enc *encoder; const GstVideoState *state; vpx_codec_err_t status; int flags = 0; vpx_codec_iter_t iter = NULL; const vpx_codec_cx_pkt_t *pkt; vpx_image_t *image; GstVP8EncCoderHook *hook; GST_DEBUG_OBJECT (base_video_encoder, "handle_frame"); encoder = GST_VP8_ENC (base_video_encoder); state = gst_base_video_encoder_get_state (base_video_encoder); encoder->n_frames++; GST_DEBUG_OBJECT (base_video_encoder, "size %d %d", state->width, state->height); if (!encoder->inited) { vpx_codec_enc_cfg_t cfg; status = vpx_codec_enc_config_default (&vpx_codec_vp8_cx_algo, &cfg, 0); if (status != VPX_CODEC_OK) { GST_ELEMENT_ERROR (encoder, LIBRARY, INIT, ("Failed to get default encoder configuration"), ("%s", gst_vpx_error_name (status))); return FALSE; } cfg.g_w = state->width; cfg.g_h = state->height; cfg.g_timebase.num = state->fps_d; cfg.g_timebase.den = state->fps_n; cfg.g_error_resilient = encoder->error_resilient; cfg.g_lag_in_frames = encoder->max_latency; cfg.g_threads = encoder->threads; cfg.rc_end_usage = encoder->mode; if (encoder->bitrate) { cfg.rc_target_bitrate = encoder->bitrate / 1000; } else { cfg.rc_min_quantizer = 63 - encoder->quality * 5.0; cfg.rc_max_quantizer = 63 - encoder->quality * 5.0; cfg.rc_target_bitrate = encoder->bitrate; } cfg.kf_mode = VPX_KF_AUTO; cfg.kf_min_dist = 0; cfg.kf_max_dist = encoder->max_keyframe_distance; cfg.g_pass = encoder->multipass_mode; if (encoder->multipass_mode == VPX_RC_FIRST_PASS) { encoder->first_pass_cache_content = g_byte_array_sized_new (4096); } else if (encoder->multipass_mode == VPX_RC_LAST_PASS) { GError *err = NULL; if (!encoder->multipass_cache_file) { GST_ELEMENT_ERROR (encoder, RESOURCE, OPEN_READ, ("No multipass cache file provided"), (NULL)); return GST_FLOW_ERROR; } if (!g_file_get_contents (encoder->multipass_cache_file, (gchar **) & encoder->last_pass_cache_content.buf, &encoder->last_pass_cache_content.sz, &err)) { GST_ELEMENT_ERROR (encoder, RESOURCE, OPEN_READ, ("Failed to read multipass cache file provided"), ("%s", err->message)); g_error_free (err); return GST_FLOW_ERROR; } cfg.rc_twopass_stats_in = encoder->last_pass_cache_content; } status = vpx_codec_enc_init (&encoder->encoder, &vpx_codec_vp8_cx_algo, &cfg, 0); if (status != VPX_CODEC_OK) { GST_ELEMENT_ERROR (encoder, LIBRARY, INIT, ("Failed to initialize encoder"), ("%s", gst_vpx_error_name (status))); return GST_FLOW_ERROR; } status = vpx_codec_control (&encoder->encoder, VP8E_SET_CPUUSED, 0); if (status != VPX_CODEC_OK) { GST_WARNING_OBJECT (encoder, "Failed to set VP8E_SET_CPUUSED to 0: %s", gst_vpx_error_name (status)); } status = vpx_codec_control (&encoder->encoder, VP8E_SET_ENABLEAUTOALTREF, (encoder->auto_alt_ref_frames ? 1 : 0)); if (status != VPX_CODEC_OK) { GST_WARNING_OBJECT (encoder, "Failed to set VP8E_ENABLEAUTOALTREF to %d: %s", (encoder->auto_alt_ref_frames ? 1 : 0), gst_vpx_error_name (status)); } gst_base_video_encoder_set_latency (base_video_encoder, 0, gst_util_uint64_scale (encoder->max_latency, state->fps_d * GST_SECOND, state->fps_n)); encoder->inited = TRUE; } image = gst_vp8_enc_buffer_to_image (encoder, frame->sink_buffer); hook = g_slice_new0 (GstVP8EncCoderHook); hook->image = image; frame->coder_hook = hook; if (encoder->force_keyframe) { flags |= VPX_EFLAG_FORCE_KF; } status = vpx_codec_encode (&encoder->encoder, image, encoder->n_frames, 1, flags, speed_table[encoder->speed]); if (status != 0) { GST_ELEMENT_ERROR (encoder, LIBRARY, ENCODE, ("Failed to encode frame"), ("%s", gst_vpx_error_name (status))); g_slice_free (GstVP8EncCoderHook, hook); frame->coder_hook = NULL; g_slice_free (vpx_image_t, image); return FALSE; } pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter); while (pkt != NULL) { GstBuffer *buffer; gboolean invisible; GST_DEBUG_OBJECT (encoder, "packet %u type %d", (guint) pkt->data.frame.sz, pkt->kind); if (pkt->kind == VPX_CODEC_STATS_PKT && encoder->multipass_mode == VPX_RC_FIRST_PASS) { GST_LOG_OBJECT (encoder, "handling STATS packet"); g_byte_array_append (encoder->first_pass_cache_content, pkt->data.twopass_stats.buf, pkt->data.twopass_stats.sz); frame = gst_base_video_encoder_get_oldest_frame (base_video_encoder); if (frame != NULL) { buffer = gst_buffer_new (); GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_PREROLL); frame->src_buffer = buffer; gst_base_video_encoder_finish_frame (base_video_encoder, frame); } pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter); continue; } else if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) { GST_LOG_OBJECT (encoder, "non frame pkt: %d", pkt->kind); pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter); continue; } invisible = (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE) != 0; frame = gst_base_video_encoder_get_oldest_frame (base_video_encoder); g_assert (frame != NULL); frame->is_sync_point = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0; hook = frame->coder_hook; buffer = gst_buffer_new_and_alloc (pkt->data.frame.sz); memcpy (GST_BUFFER_DATA (buffer), pkt->data.frame.buf, pkt->data.frame.sz); if (hook->image) g_slice_free (vpx_image_t, hook->image); hook->image = NULL; if (invisible) { hook->invisible = g_list_append (hook->invisible, buffer); } else { frame->src_buffer = buffer; gst_base_video_encoder_finish_frame (base_video_encoder, frame); } pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter); } return TRUE; }
static pj_status_t pj_vpx_encoder_open(vpx_private *vpx) { vpx_codec_flags_t flags = 0; const struct vpx_codec_iface *iface = &vpx_codec_vp8_cx_algo; struct vpx_codec_enc_cfg enccfg; int cpu_speed, rc_max_intra_target; int res; PJ_LOG(4, (THIS_FILE, "vpx pj_vpx_encoder_open")); res = vpx_codec_enc_config_default(iface, &enccfg, 0); if (res != VPX_CODEC_OK) { PJ_LOG(1, (THIS_FILE, "Failed to get vpx default config : %s", vpx_codec_err_to_string(res))); return PJMEDIA_CODEC_EFAILED; } enccfg.g_w = vpx->param.enc_fmt.det.vid.size.w; enccfg.g_h = vpx->param.enc_fmt.det.vid.size.h; enccfg.g_timebase.num = vpx->param.enc_fmt.det.vid.fps.num; enccfg.g_timebase.den = vpx->param.enc_fmt.det.vid.fps.denum; //provide dummy value to initialize wrapper, values will be updated each _encode() vpx_img_wrap(&vpx->rawimg, VPX_IMG_FMT_I420, vpx->param.enc_fmt.det.vid.size.w, vpx->param.enc_fmt.det.vid.size.h, 1, (unsigned char*)1); // Following config taken from webRTC project. // vpx seems to support more configurable/complex settings. // could be interesting to have a look, but for now, consider // webRTC settings as optimized for our needs #if defined(PJ_HAS_UNISTD_H) && PJ_HAS_UNISTD_H!=0 if (enccfg.g_w * enccfg.g_h > 704 * 576 && sysconf(_SC_NPROCESSORS_CONF) > 1) { // 2 threads when larger than 4CIF enccfg.g_threads = 2; } else #endif { enccfg.g_threads = 1; } enccfg.g_lag_in_frames = 0; enccfg.g_pass = VPX_RC_ONE_PASS; enccfg.rc_end_usage = VPX_CBR; enccfg.rc_target_bitrate = vpx->param.enc_fmt.det.vid.avg_bps / 1000; // in kbit/s enccfg.g_timebase.num = 1; enccfg.g_timebase.den = 90000; // TODO : need a setting for 2 following ? enccfg.g_error_resilient = 0; enccfg.rc_resize_allowed = 1; enccfg.rc_min_quantizer = 2; enccfg.rc_max_quantizer = 56; enccfg.rc_undershoot_pct = 100; enccfg.rc_overshoot_pct = 15; enccfg.rc_buf_initial_sz = 500; enccfg.rc_buf_optimal_sz = 600; enccfg.rc_buf_sz = 1000; // Not use feedback_mode enccfg.kf_mode = VPX_KF_AUTO; enccfg.kf_max_dist = 3000; /* scalePar = 0.5; maxFrameRate = 30fps*/ /* Don't go below 3 times the per frame bandwidth. */ rc_max_intra_target = PJ_MAX(300, enccfg.rc_buf_sz * 0.5 * 30 / 10); // for android cpu speed set to -12 // TODO : adjust for other platform as done in webRTC cpu_speed = -12; //flags |= VPX_CODEC_USE_OUTPUT_PARTITION; res = vpx_codec_enc_init(&vpx->encoder, vpx_codec_vp8_cx(), &enccfg, flags); if (res != VPX_CODEC_OK) { PJ_LOG(1, (THIS_FILE, "Failed to init vpx encoder : %s", vpx_codec_err_to_string(res))); return PJMEDIA_CODEC_EFAILED; } vpx_codec_control(&vpx->encoder, VP8E_SET_STATIC_THRESHOLD, 1); vpx_codec_control(&vpx->encoder, VP8E_SET_CPUUSED, cpu_speed); vpx_codec_control(&vpx->encoder, VP8E_SET_TOKEN_PARTITIONS, VP8_ONE_TOKENPARTITION); vpx_codec_control(&vpx->encoder, VP8E_SET_NOISE_SENSITIVITY, 1); vpx_codec_control(&vpx->encoder, VP8E_SET_MAX_INTRA_BITRATE_PCT, rc_max_intra_target); vpx->enc_iter = NULL; vpx->enc_buf_size = vpx->enc_vafp.framebytes; vpx->enc_buf = pj_pool_alloc(vpx->pool, vpx->enc_buf_size); vpx->dec_buf_size = vpx->dec_vafp.framebytes; vpx->dec_buf = pj_pool_alloc(vpx->pool, vpx->dec_buf_size); return PJ_SUCCESS; }
static void parse_command_line(int argc, const char **argv_, AppInput *app_input, SvcContext *svc_ctx, vpx_codec_enc_cfg_t *enc_cfg) { struct arg arg; char **argv, **argi, **argj; vpx_codec_err_t res; // initialize SvcContext with parameters that will be passed to vpx_svc_init svc_ctx->log_level = SVC_LOG_DEBUG; svc_ctx->spatial_layers = default_spatial_layers; svc_ctx->encoding_mode = default_encoding_mode; // start with default encoder configuration res = vpx_codec_enc_config_default(vpx_codec_vp9_cx(), enc_cfg, 0); if (res) { die("Failed to get config: %s\n", vpx_codec_err_to_string(res)); } // update enc_cfg with app default values enc_cfg->g_w = default_width; enc_cfg->g_h = default_height; enc_cfg->g_timebase.num = default_timebase_num; enc_cfg->g_timebase.den = default_timebase_den; enc_cfg->rc_target_bitrate = default_bitrate; enc_cfg->kf_min_dist = default_kf_dist; enc_cfg->kf_max_dist = default_kf_dist; // initialize AppInput with default values app_input->frames_to_code = default_frames_to_code; app_input->frames_to_skip = default_frames_to_skip; // process command line options argv = argv_dup(argc - 1, argv_ + 1); for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) { arg.argv_step = 1; if (arg_match(&arg, &encoding_mode_arg, argi)) { svc_ctx->encoding_mode = arg_parse_enum_or_int(&arg); } else if (arg_match(&arg, &frames_arg, argi)) { app_input->frames_to_code = arg_parse_uint(&arg); } else if (arg_match(&arg, &width_arg, argi)) { enc_cfg->g_w = arg_parse_uint(&arg); } else if (arg_match(&arg, &height_arg, argi)) { enc_cfg->g_h = arg_parse_uint(&arg); } else if (arg_match(&arg, &timebase_arg, argi)) { enc_cfg->g_timebase = arg_parse_rational(&arg); } else if (arg_match(&arg, &bitrate_arg, argi)) { enc_cfg->rc_target_bitrate = arg_parse_uint(&arg); } else if (arg_match(&arg, &skip_frames_arg, argi)) { app_input->frames_to_skip = arg_parse_uint(&arg); } else if (arg_match(&arg, &layers_arg, argi)) { svc_ctx->spatial_layers = arg_parse_uint(&arg); } else if (arg_match(&arg, &kf_dist_arg, argi)) { enc_cfg->kf_min_dist = arg_parse_uint(&arg); enc_cfg->kf_max_dist = enc_cfg->kf_min_dist; } else if (arg_match(&arg, &scale_factors_arg, argi)) { vpx_svc_set_scale_factors(svc_ctx, arg.val); } else if (arg_match(&arg, &quantizers_arg, argi)) { vpx_svc_set_quantizers(svc_ctx, arg.val); } else { ++argj; } } // Check for unrecognized options for (argi = argv; *argi; ++argi) if (argi[0][0] == '-' && strlen(argi[0]) > 1) die("Error: Unrecognized option %s\n", *argi); if (argv[0] == NULL || argv[1] == 0) { usage_exit(); } app_input->input_ctx.filename = argv[0]; app_input->output_filename = argv[1]; free(argv); if (enc_cfg->g_w < 16 || enc_cfg->g_w % 2 || enc_cfg->g_h < 16 || enc_cfg->g_h % 2) die("Invalid resolution: %d x %d\n", enc_cfg->g_w, enc_cfg->g_h); printf( "Codec %s\nframes: %d, skip: %d\n" "mode: %d, layers: %d\n" "width %d, height: %d,\n" "num: %d, den: %d, bitrate: %d,\n" "gop size: %d\n", vpx_codec_iface_name(vpx_codec_vp9_cx()), app_input->frames_to_code, app_input->frames_to_skip, svc_ctx->encoding_mode, svc_ctx->spatial_layers, enc_cfg->g_w, enc_cfg->g_h, enc_cfg->g_timebase.num, enc_cfg->g_timebase.den, enc_cfg->rc_target_bitrate, enc_cfg->kf_max_dist); }
int main(int argc, char **argv) { VpxVideoWriter *outfile[VPX_TS_MAX_LAYERS] = {NULL}; vpx_codec_ctx_t codec; vpx_codec_enc_cfg_t cfg; int frame_cnt = 0; vpx_image_t raw; vpx_codec_err_t res; unsigned int width; unsigned int height; int speed; int frame_avail; int got_data; int flags = 0; unsigned int i; int pts = 0; // PTS starts at 0. int frame_duration = 1; // 1 timebase tick per frame. int layering_mode = 0; int layer_flags[VPX_TS_MAX_PERIODICITY] = {0}; int flag_periodicity = 1; #if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION) vpx_svc_layer_id_t layer_id = {0, 0}; #else vpx_svc_layer_id_t layer_id = {0}; #endif const VpxInterface *encoder = NULL; FILE *infile = NULL; struct RateControlMetrics rc; int64_t cx_time = 0; const int min_args_base = 11; #if CONFIG_VP9_HIGHBITDEPTH vpx_bit_depth_t bit_depth = VPX_BITS_8; int input_bit_depth = 8; const int min_args = min_args_base + 1; #else const int min_args = min_args_base; #endif // CONFIG_VP9_HIGHBITDEPTH double sum_bitrate = 0.0; double sum_bitrate2 = 0.0; double framerate = 30.0; exec_name = argv[0]; // Check usage and arguments. if (argc < min_args) { #if CONFIG_VP9_HIGHBITDEPTH die("Usage: %s <infile> <outfile> <codec_type(vp8/vp9)> <width> <height> " "<rate_num> <rate_den> <speed> <frame_drop_threshold> <mode> " "<Rate_0> ... <Rate_nlayers-1> <bit-depth> \n", argv[0]); #else die("Usage: %s <infile> <outfile> <codec_type(vp8/vp9)> <width> <height> " "<rate_num> <rate_den> <speed> <frame_drop_threshold> <mode> " "<Rate_0> ... <Rate_nlayers-1> \n", argv[0]); #endif // CONFIG_VP9_HIGHBITDEPTH } encoder = get_vpx_encoder_by_name(argv[3]); if (!encoder) die("Unsupported codec."); printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface())); width = strtol(argv[4], NULL, 0); height = strtol(argv[5], NULL, 0); if (width < 16 || width % 2 || height < 16 || height % 2) { die("Invalid resolution: %d x %d", width, height); } layering_mode = strtol(argv[10], NULL, 0); if (layering_mode < 0 || layering_mode > 12) { die("Invalid layering mode (0..12) %s", argv[10]); } if (argc != min_args + mode_to_num_layers[layering_mode]) { die("Invalid number of arguments"); } #if CONFIG_VP9_HIGHBITDEPTH switch (strtol(argv[argc-1], NULL, 0)) { case 8: bit_depth = VPX_BITS_8; input_bit_depth = 8; break; case 10: bit_depth = VPX_BITS_10; input_bit_depth = 10; break; case 12: bit_depth = VPX_BITS_12; input_bit_depth = 12; break; default: die("Invalid bit depth (8, 10, 12) %s", argv[argc-1]); } if (!vpx_img_alloc(&raw, bit_depth == VPX_BITS_8 ? VPX_IMG_FMT_I420 : VPX_IMG_FMT_I42016, width, height, 32)) { die("Failed to allocate image", width, height); } #else if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 32)) { die("Failed to allocate image", width, height); } #endif // CONFIG_VP9_HIGHBITDEPTH // Populate encoder configuration. res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0); if (res) { printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); return EXIT_FAILURE; } // Update the default configuration with our settings. cfg.g_w = width; cfg.g_h = height; #if CONFIG_VP9_HIGHBITDEPTH if (bit_depth != VPX_BITS_8) { cfg.g_bit_depth = bit_depth; cfg.g_input_bit_depth = input_bit_depth; cfg.g_profile = 2; } #endif // CONFIG_VP9_HIGHBITDEPTH // Timebase format e.g. 30fps: numerator=1, demoninator = 30. cfg.g_timebase.num = strtol(argv[6], NULL, 0); cfg.g_timebase.den = strtol(argv[7], NULL, 0); speed = strtol(argv[8], NULL, 0); if (speed < 0) { die("Invalid speed setting: must be positive"); } for (i = min_args_base; (int)i < min_args_base + mode_to_num_layers[layering_mode]; ++i) { rc.layer_target_bitrate[i - 11] = strtol(argv[i], NULL, 0); if (strncmp(encoder->name, "vp8", 3) == 0) cfg.ts_target_bitrate[i - 11] = rc.layer_target_bitrate[i - 11]; else if (strncmp(encoder->name, "vp9", 3) == 0) cfg.layer_target_bitrate[i - 11] = rc.layer_target_bitrate[i - 11]; } // Real time parameters. cfg.rc_dropframe_thresh = strtol(argv[9], NULL, 0); cfg.rc_end_usage = VPX_CBR; cfg.rc_min_quantizer = 2; cfg.rc_max_quantizer = 56; if (strncmp(encoder->name, "vp9", 3) == 0) cfg.rc_max_quantizer = 52; cfg.rc_undershoot_pct = 50; cfg.rc_overshoot_pct = 50; cfg.rc_buf_initial_sz = 500; cfg.rc_buf_optimal_sz = 600; cfg.rc_buf_sz = 1000; // Disable dynamic resizing by default. cfg.rc_resize_allowed = 0; // Use 1 thread as default. cfg.g_threads = 1; // Enable error resilient mode. cfg.g_error_resilient = 1; cfg.g_lag_in_frames = 0; cfg.kf_mode = VPX_KF_AUTO; // Disable automatic keyframe placement. cfg.kf_min_dist = cfg.kf_max_dist = 3000; cfg.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS; set_temporal_layer_pattern(layering_mode, &cfg, layer_flags, &flag_periodicity); set_rate_control_metrics(&rc, &cfg); // Target bandwidth for the whole stream. // Set to layer_target_bitrate for highest layer (total bitrate). cfg.rc_target_bitrate = rc.layer_target_bitrate[cfg.ts_number_layers - 1]; // Open input file. if (!(infile = fopen(argv[1], "rb"))) { die("Failed to open %s for reading", argv[1]); } framerate = cfg.g_timebase.den / cfg.g_timebase.num; // Open an output file for each stream. for (i = 0; i < cfg.ts_number_layers; ++i) { char file_name[PATH_MAX]; VpxVideoInfo info; info.codec_fourcc = encoder->fourcc; info.frame_width = cfg.g_w; info.frame_height = cfg.g_h; info.time_base.numerator = cfg.g_timebase.num; info.time_base.denominator = cfg.g_timebase.den; snprintf(file_name, sizeof(file_name), "%s_%d.ivf", argv[2], i); outfile[i] = vpx_video_writer_open(file_name, kContainerIVF, &info); if (!outfile[i]) die("Failed to open %s for writing", file_name); assert(outfile[i] != NULL); } // No spatial layers in this encoder. cfg.ss_number_layers = 1; // Initialize codec. #if CONFIG_VP9_HIGHBITDEPTH if (vpx_codec_enc_init( &codec, encoder->codec_interface(), &cfg, bit_depth == VPX_BITS_8 ? 0 : VPX_CODEC_USE_HIGHBITDEPTH)) #else if (vpx_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0)) #endif // CONFIG_VP9_HIGHBITDEPTH die_codec(&codec, "Failed to initialize encoder"); // configuration for vp8/vp9 if (strncmp(encoder->name, "vp8", 3) == 0) { vpx_codec_control(&codec, VP8E_SET_CPUUSED, -speed); vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, kDenoiserOff); vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 0); } else if (strncmp(encoder->name, "vp9", 3) == 0) { vpx_svc_extra_cfg_t svc_params; vpx_codec_control(&codec, VP8E_SET_CPUUSED, speed); vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3); vpx_codec_control(&codec, VP9E_SET_FRAME_PERIODIC_BOOST, 0); vpx_codec_control(&codec, VP9E_SET_NOISE_SENSITIVITY, 0); vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 0); vpx_codec_control(&codec, VP9E_SET_TUNE_CONTENT, 0); vpx_codec_control(&codec, VP9E_SET_TILE_COLUMNS, (cfg.g_threads >> 1)); if (vpx_codec_control(&codec, VP9E_SET_SVC, layering_mode > 0 ? 1: 0)) die_codec(&codec, "Failed to set SVC"); for (i = 0; i < cfg.ts_number_layers; ++i) { svc_params.max_quantizers[i] = cfg.rc_max_quantizer; svc_params.min_quantizers[i] = cfg.rc_min_quantizer; } svc_params.scaling_factor_num[0] = cfg.g_h; svc_params.scaling_factor_den[0] = cfg.g_h; vpx_codec_control(&codec, VP9E_SET_SVC_PARAMETERS, &svc_params); }
int main(int argc, char **argv) { FILE *infile = NULL; vpx_codec_ctx_t codec; vpx_codec_enc_cfg_t cfg; int frame_count = 0; vpx_image_t raw; vpx_codec_err_t res; VpxVideoInfo info; VpxVideoWriter *writer = NULL; const VpxInterface *encoder = NULL; const int fps = 2; // TODO(dkovalev) add command line argument const double bits_per_pixel_per_frame = 0.067; exec_name = argv[0]; if (argc != 6) die("Invalid number of arguments"); memset(&info, 0, sizeof(info)); encoder = get_vpx_encoder_by_name(argv[1]); if (encoder == NULL) { die("Unsupported codec."); } assert(encoder != NULL); info.codec_fourcc = encoder->fourcc; info.frame_width = strtol(argv[2], NULL, 0); info.frame_height = strtol(argv[3], NULL, 0); info.time_base.numerator = 1; info.time_base.denominator = fps; if (info.frame_width <= 0 || info.frame_height <= 0 || (info.frame_width % 2) != 0 || (info.frame_height % 2) != 0) { die("Invalid frame size: %dx%d", info.frame_width, info.frame_height); } if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width, info.frame_height, 1)) { die("Failed to allocate image."); } printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface())); res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0); if (res) die_codec(&codec, "Failed to get default codec config."); cfg.g_w = info.frame_width; cfg.g_h = info.frame_height; cfg.g_timebase.num = info.time_base.numerator; cfg.g_timebase.den = info.time_base.denominator; cfg.rc_target_bitrate = (unsigned int)(bits_per_pixel_per_frame * cfg.g_w * cfg.g_h * fps / 1000); cfg.g_lag_in_frames = 0; writer = vpx_video_writer_open(argv[5], kContainerIVF, &info); if (!writer) die("Failed to open %s for writing.", argv[5]); if (!(infile = fopen(argv[4], "rb"))) die("Failed to open %s for reading.", argv[4]); if (vpx_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0)) die_codec(&codec, "Failed to initialize encoder"); // Encode frames. while (vpx_img_read(&raw, infile)) { ++frame_count; if (frame_count == 22 && encoder->fourcc == VP8_FOURCC) { set_roi_map(&cfg, &codec); } else if (frame_count == 33) { set_active_map(&cfg, &codec); } else if (frame_count == 44) { unset_active_map(&cfg, &codec); } encode_frame(&codec, &raw, frame_count, writer); } // Flush encoder. while (encode_frame(&codec, NULL, -1, writer)) {} printf("\n"); fclose(infile); printf("Processed %d frames.\n", frame_count); vpx_img_free(&raw); if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec."); vpx_video_writer_close(writer); return EXIT_SUCCESS; }
static pj_status_t pj_vpx_encoder_open(vpx_private *vpx) { vpx_codec_flags_t flags = 0; /* XXX: use VPX_CODEC_USE_OUTPUT_PARTITION ? */ const struct vpx_codec_iface *iface = &vpx_codec_vp8_cx_algo; struct vpx_codec_enc_cfg enccfg; int res; TRACE_((THIS_FILE, "vpx pj_vpx_encoder_open")); res = vpx_codec_enc_config_default(iface, &enccfg, 0); if (res != VPX_CODEC_OK) { PJ_LOG(1, (THIS_FILE, "Failed to get vpx default config : %s", vpx_codec_err_to_string(res))); return PJMEDIA_CODEC_EFAILED; } enccfg.g_w = vpx->param.enc_fmt.det.vid.size.w; enccfg.g_h = vpx->param.enc_fmt.det.vid.size.h; enccfg.g_timebase.num = vpx->param.enc_fmt.det.vid.fps.num; enccfg.g_timebase.den = vpx->param.enc_fmt.det.vid.fps.denum; //provide dummy value to initialize wrapper, values will be updated each _encode() vpx_img_wrap(&vpx->rawimg, VPX_IMG_FMT_I420, vpx->param.enc_fmt.det.vid.size.w, vpx->param.enc_fmt.det.vid.size.h, 1, NULL); enccfg.g_threads = number_of_threads(enccfg.g_w, enccfg.g_h, number_of_cores()); PJ_LOG(4, (THIS_FILE, "Using %d threads for VPX encoding", enccfg.g_threads)); enccfg.g_lag_in_frames = 0; enccfg.g_pass = VPX_RC_ONE_PASS; enccfg.rc_end_usage = VPX_CBR; enccfg.rc_target_bitrate = vpx->param.enc_fmt.det.vid.avg_bps / 1000; // in kbit/s enccfg.g_timebase.num = 1; enccfg.g_timebase.den = 90000; enccfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT; enccfg.rc_resize_allowed = 1; enccfg.rc_min_quantizer = 2; enccfg.rc_max_quantizer = 56; enccfg.rc_undershoot_pct = 100; enccfg.rc_overshoot_pct = 15; enccfg.rc_buf_initial_sz = 500; enccfg.rc_buf_optimal_sz = 600; enccfg.rc_buf_sz = 1000; enccfg.kf_mode = VPX_KF_AUTO; enccfg.kf_max_dist = 3000; vpx->rc_max_intra_target = PJ_MAX(300, enccfg.rc_buf_sz * 0.5 * enccfg.g_timebase.num / 10); res = vpx_codec_enc_init(&vpx->encoder, vpx_codec_vp8_cx(), &enccfg, flags); if (res != VPX_CODEC_OK) { PJ_LOG(1, (THIS_FILE, "Failed to init vpx encoder : %s", vpx_codec_err_to_string(res))); return PJMEDIA_CODEC_EFAILED; } vpx_codec_control(&vpx->encoder, VP8E_SET_STATIC_THRESHOLD, 1); vpx_codec_control(&vpx->encoder, VP8E_SET_CPUUSED, -6); // XXX: test vpx_codec_control(&vpx->encoder, VP8E_SET_TOKEN_PARTITIONS, VP8_ONE_TOKENPARTITION); vpx_codec_control(&vpx->encoder, VP8E_SET_MAX_INTRA_BITRATE_PCT, vpx->rc_max_intra_target); #ifdef VP8E_SET_SCREEN_CONTENT_MODE vpx_codec_control(&vpx->encoder, VP8E_SET_SCREEN_CONTENT_MODE, 0); #endif vpx->enc_iter = NULL; vpx->enc_buf_size = vpx->enc_vafp.framebytes; vpx->enc_buf = pj_pool_alloc(vpx->pool, vpx->enc_buf_size); vpx->dec_buf_size = vpx->dec_vafp.framebytes; vpx->dec_buf = pj_pool_alloc(vpx->pool, vpx->dec_buf_size); return PJ_SUCCESS; }
static void enc_preprocess(MSFilter *f) { EncState *s = (EncState *)f->data; vpx_codec_err_t res; vpx_codec_caps_t caps; int cpuused=0; /* Populate encoder configuration */ s->flags = 0; caps = vpx_codec_get_caps(s->iface); if ((s->avpf_enabled == TRUE) && (caps & VPX_CODEC_CAP_OUTPUT_PARTITION)) { s->flags |= VPX_CODEC_USE_OUTPUT_PARTITION; } res = vpx_codec_enc_config_default(s->iface, &s->cfg, 0); if (res) { ms_error("Failed to get config: %s", vpx_codec_err_to_string(res)); return; } s->cfg.rc_target_bitrate = (unsigned int)(((float)s->vconf.required_bitrate) * 0.92f / 1024.0f); //0.92=take into account IP/UDP/RTP overhead, in average. s->cfg.g_pass = VPX_RC_ONE_PASS; /* -p 1 */ s->cfg.g_timebase.num = 1; s->cfg.g_timebase.den = (int)s->vconf.fps; s->cfg.rc_end_usage = VPX_CBR; /* --end-usage=cbr */ if (s->avpf_enabled == TRUE) { s->cfg.kf_mode = VPX_KF_DISABLED; } else { s->cfg.kf_mode = VPX_KF_AUTO; /* encoder automatically places keyframes */ s->cfg.kf_max_dist = 10 * s->cfg.g_timebase.den; /* 1 keyframe each 10s. */ } #if TARGET_IPHONE_SIMULATOR s->cfg.g_threads = 1; /*workaround to remove crash on ipad simulator*/ #else s->cfg.g_threads = ms_factory_get_cpu_count(f->factory); #endif ms_message("VP8 g_threads=%d", s->cfg.g_threads); s->cfg.rc_undershoot_pct = 95; /* --undershoot-pct=95 */ s->cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT|VPX_ERROR_RESILIENT_PARTITIONS; s->cfg.g_lag_in_frames = 0; #if defined(ANDROID) || (TARGET_OS_IPHONE == 1) || defined(__arm__) || defined(_M_ARM) cpuused = 10 - s->cfg.g_threads; /*cpu/quality tradeoff: positive values decrease CPU usage at the expense of quality*/ if (cpuused < 7) cpuused = 7; /*values beneath 7 consume too much CPU*/ if( s->cfg.g_threads == 1 ){ /* on mono-core iOS devices, we reduce the quality a bit more due to VP8 being slower with new Clang compilers */ cpuused = 16; } #endif s->cfg.g_w = s->vconf.vsize.width; s->cfg.g_h = s->vconf.vsize.height; /* Initialize codec */ res = vpx_codec_enc_init(&s->codec, s->iface, &s->cfg, s->flags); if (res) { ms_error("vpx_codec_enc_init failed: %s (%s)", vpx_codec_err_to_string(res), vpx_codec_error_detail(&s->codec)); return; } vpx_codec_control(&s->codec, VP8E_SET_CPUUSED, cpuused); vpx_codec_control(&s->codec, VP8E_SET_STATIC_THRESHOLD, 0); vpx_codec_control(&s->codec, VP8E_SET_ENABLEAUTOALTREF, !s->avpf_enabled); vpx_codec_control(&s->codec, VP8E_SET_MAX_INTRA_BITRATE_PCT, 400); /*limite iFrame size to 4 pframe*/ if (s->flags & VPX_CODEC_USE_OUTPUT_PARTITION) { vpx_codec_control(&s->codec, VP8E_SET_TOKEN_PARTITIONS, 2); /* Output 4 partitions per frame */ } else { vpx_codec_control(&s->codec, VP8E_SET_TOKEN_PARTITIONS, 0); } s->invalid_frame_reported = FALSE; vp8rtpfmt_packer_init(&s->packer); if (s->avpf_enabled == TRUE) { s->force_keyframe = TRUE; } else if (s->frame_count == 0) { ms_video_starter_init(&s->starter); } s->ready = TRUE; }
int main(int argc, char **argv) { FILE *infile = NULL; vpx_codec_ctx_t codec; vpx_codec_enc_cfg_t cfg; int frame_count = 0; vpx_image_t raw; vpx_codec_err_t res; VpxVideoInfo info; VpxVideoWriter *writer = NULL; const VpxInterface *encoder = NULL; int update_frame_num = 0; const int fps = 30; // TODO(dkovalev) add command line argument const int bitrate = 200; // kbit/s TODO(dkovalev) add command line argument vp8_zero(codec); vp8_zero(cfg); vp8_zero(info); exec_name = argv[0]; if (argc != 6) die("Invalid number of arguments"); // TODO(dkovalev): add vp9 support and rename the file accordingly encoder = get_vpx_encoder_by_name("vp8"); if (!encoder) die("Unsupported codec."); update_frame_num = atoi(argv[5]); if (!update_frame_num) die("Couldn't parse frame number '%s'\n", argv[5]); info.codec_fourcc = encoder->fourcc; info.frame_width = (int)strtol(argv[1], NULL, 0); info.frame_height = (int)strtol(argv[2], NULL, 0); info.time_base.numerator = 1; info.time_base.denominator = fps; if (info.frame_width <= 0 || info.frame_height <= 0 || (info.frame_width % 2) != 0 || (info.frame_height % 2) != 0) { die("Invalid frame size: %dx%d", info.frame_width, info.frame_height); } if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width, info.frame_height, 1)) { die("Failed to allocate image."); } printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface())); res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0); if (res) die_codec(&codec, "Failed to get default codec config."); cfg.g_w = info.frame_width; cfg.g_h = info.frame_height; cfg.g_timebase.num = info.time_base.numerator; cfg.g_timebase.den = info.time_base.denominator; cfg.rc_target_bitrate = bitrate; writer = vpx_video_writer_open(argv[4], kContainerIVF, &info); if (!writer) die("Failed to open %s for writing.", argv[4]); if (!(infile = fopen(argv[3], "rb"))) die("Failed to open %s for reading.", argv[3]); if (vpx_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0)) die_codec(&codec, "Failed to initialize encoder"); // Encode frames. while (vpx_img_read(&raw, infile)) { if (frame_count + 1 == update_frame_num) { vpx_ref_frame_t ref; ref.frame_type = VP8_LAST_FRAME; ref.img = raw; if (vpx_codec_control(&codec, VP8_SET_REFERENCE, &ref)) die_codec(&codec, "Failed to set reference frame"); } encode_frame(&codec, &raw, frame_count++, writer); } // Flush encoder. while (encode_frame(&codec, NULL, -1, writer)) { } printf("\n"); fclose(infile); printf("Processed %d frames.\n", frame_count); vpx_img_free(&raw); if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec."); vpx_video_writer_close(writer); return EXIT_SUCCESS; }