bool readImage(char *filename, int frameNumber, vpx_image_t **pRGBImage, vpx_image_t **pYV12Image, int flip) { // Load image. // char path[512]; sprintf(path, filename, frameNumber); ILuint imageHandle; ilGenImages(1, &imageHandle); ilBindImage(imageHandle); ILboolean ok = ilLoadImage(path); if (ok) { if (ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE)) { unsigned int w = ilGetInteger(IL_IMAGE_WIDTH); unsigned int h = ilGetInteger(IL_IMAGE_HEIGHT); if (*pRGBImage == NULL) { *pRGBImage = vpx_img_alloc(NULL, VPX_IMG_FMT_RGB24, w, h, 1); } if (*pYV12Image == NULL) { *pYV12Image = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, w, h, 1); } memcpy((*pRGBImage)->img_data, ilGetData(), w * h * 3); rgb24toyv12(*pRGBImage, *pYV12Image); if (flip) { vpx_img_flip(*pYV12Image); } ilDeleteImages(1, &imageHandle); return true; } } else { ILenum ilError = ilGetError(); fprintf(stderr, "Can't load [%s], [%x %s]\n.", path, ilError, iluErrorString(ilError)); } return false; }
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; }
static bool video_device_init(void *handle) { // initialize video (will populate video_width and video_height) if (handle == (void *)1) { if (!native_video_init((void *)1)) { LOG_TRACE("uToxVideo", "native_video_init() failed for desktop" ); return false; } } else { if (!handle || !native_video_init(*(void **)handle)) { LOG_TRACE("uToxVideo", "native_video_init() failed webcam" ); return false; } } vpx_img_alloc(&input, VPX_IMG_FMT_I420, video_width, video_height, 1); utox_video_frame.y = input.planes[0]; utox_video_frame.u = input.planes[1]; utox_video_frame.v = input.planes[2]; utox_video_frame.w = input.d_w; utox_video_frame.h = input.d_h; LOG_NOTE("uToxVideo", "video init done!" ); video_device_status = true; return true; }
VpxImage& operator =(const VpxImage& src) { if (image_) { vpx_img_free(image_); image_ = 0; } assert(src.format() == VPX_IMG_FMT_RGB24); image_ = vpx_img_alloc(NULL, src.format(), src.width(), src.height(), 1); if (image_) { memcpy(image_->img_data, src.buffer(), width()*height()*3); } return *this; }
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; }
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 dispatchFrameCb(int32_t width, int32_t height, const uint8_t* buffer, int32_t length, void* ctxt) { struct CamTox* tox = (struct CamTox*)ctxt; static uint8_t* frame = NULL; if (!frame) { frame = calloc(1, width * height * 3); if (!frame) return; } static vpx_image_t input; static int alloced = 0; static uint8_t* y = NULL; static uint8_t* u = NULL; static uint8_t* v = NULL; static uint16_t w = 0; static uint16_t h = 0; if (!alloced) { vpx_img_alloc(&input, VPX_IMG_FMT_I420, width, height, 1); y = input.planes[0]; u = input.planes[1]; v = input.planes[2]; w = input.d_w; h = input.d_h; alloced = 1; } if ((w != width) || (h != height)) { printf(" width, height mismatch.\n"); return; } uint8_t* dst = frame + width * height * 3; uint8_t* src = (uint8_t*) buffer; int32_t sz = width * 3; for (int i = 0; i < height; i++) { dst -= sz; memcpy(dst, src, sz); src += sz; } bgrtoyuv420(y, u, v, frame, width, height); tox->ops->sendVideoFrame(tox, y, u, v, w, h); return; }
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; } } }
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; } } }
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; }
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; vpx_svc_layer_id_t layer_id = {0, 0}; 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) { cfg.ts_target_bitrate[i - 11] = strtol(argv[i], NULL, 0); } // Real time parameters. cfg.rc_dropframe_thresh = strtol(argv[9], NULL, 0); cfg.rc_end_usage = VPX_CBR; cfg.rc_resize_allowed = 0; cfg.rc_min_quantizer = 2; cfg.rc_max_quantizer = 56; 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; // 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; 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 ts_target_bitrate for highest layer (total bitrate). cfg.rc_target_bitrate = cfg.ts_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"); if (strncmp(encoder->name, "vp8", 3) == 0) { vpx_codec_control(&codec, VP8E_SET_CPUUSED, -speed); vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, kDenoiserOnYOnly); } else if (strncmp(encoder->name, "vp9", 3) == 0) { 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); if (vpx_codec_control(&codec, VP9E_SET_SVC, layering_mode > 0 ? 1: 0)) { die_codec(&codec, "Failed to set SVC"); } } vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 1); vpx_codec_control(&codec, VP8E_SET_TOKEN_PARTITIONS, 1); // This controls the maximum target size of the key frame. // For generating smaller key frames, use a smaller max_intra_size_pct // value, like 100 or 200. { const int max_intra_size_pct = 900; vpx_codec_control(&codec, VP8E_SET_MAX_INTRA_BITRATE_PCT, max_intra_size_pct); } frame_avail = 1; while (frame_avail || got_data) { struct vpx_usec_timer timer; vpx_codec_iter_t iter = NULL; const vpx_codec_cx_pkt_t *pkt; // Update the temporal layer_id. No spatial layers in this test. layer_id.spatial_layer_id = 0; layer_id.temporal_layer_id = cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity]; if (strncmp(encoder->name, "vp9", 3) == 0) { vpx_codec_control(&codec, VP9E_SET_SVC_LAYER_ID, &layer_id); } flags = layer_flags[frame_cnt % flag_periodicity]; frame_avail = vpx_img_read(&raw, infile); if (frame_avail) ++rc.layer_input_frames[layer_id.temporal_layer_id]; vpx_usec_timer_start(&timer); if (vpx_codec_encode(&codec, frame_avail? &raw : NULL, pts, 1, flags, VPX_DL_REALTIME)) { die_codec(&codec, "Failed to encode frame"); } vpx_usec_timer_mark(&timer); cx_time += vpx_usec_timer_elapsed(&timer); // Reset KF flag. if (layering_mode != 7) { 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) { vpx_video_writer_write_frame(outfile[i], pkt->data.frame.buf, pkt->data.frame.sz, pts); ++rc.layer_tot_enc_frames[i]; rc.layer_encoding_bitrate[i] += 8.0 * pkt->data.frame.sz; // Keep count of rate control stats per layer (for non-key frames). if (i == cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity] && !(pkt->data.frame.flags & VPX_FRAME_IS_KEY)) { rc.layer_avg_frame_size[i] += 8.0 * pkt->data.frame.sz; rc.layer_avg_rate_mismatch[i] += fabs(8.0 * pkt->data.frame.sz - rc.layer_pfb[i]) / rc.layer_pfb[i]; ++rc.layer_enc_frames[i]; } } // Update for short-time encoding bitrate states, for moving window // of size rc->window, shifted by rc->window / 2. // Ignore first window segment, due to key frame. if (frame_cnt > rc.window_size) { sum_bitrate += 0.001 * 8.0 * pkt->data.frame.sz * framerate; if (frame_cnt % rc.window_size == 0) { rc.window_count += 1; rc.avg_st_encoding_bitrate += sum_bitrate / rc.window_size; rc.variance_st_encoding_bitrate += (sum_bitrate / rc.window_size) * (sum_bitrate / rc.window_size); sum_bitrate = 0.0; } } // Second shifted window. if (frame_cnt > rc.window_size + rc.window_size / 2) { sum_bitrate2 += 0.001 * 8.0 * pkt->data.frame.sz * framerate; if (frame_cnt > 2 * rc.window_size && frame_cnt % rc.window_size == 0) { rc.window_count += 1; rc.avg_st_encoding_bitrate += sum_bitrate2 / rc.window_size; rc.variance_st_encoding_bitrate += (sum_bitrate2 / rc.window_size) * (sum_bitrate2 / rc.window_size); sum_bitrate2 = 0.0; } } break; default: break; } } ++frame_cnt; pts += frame_duration; } fclose(infile); printout_rate_control_summary(&rc, &cfg, frame_cnt); printf("\n"); printf("Frame cnt and encoding time/FPS stats for encoding: %d %f %f \n", frame_cnt, 1000 * (float)cx_time / (double)(frame_cnt * 1000000), 1000000 * (double)frame_cnt / (double)cx_time); 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) vpx_video_writer_close(outfile[i]); vpx_img_free(&raw); return EXIT_SUCCESS; }
void VideoProgress::onNextFrame() { size_t maxFrames = encoder->fpsValue() * durationSeconds; renderSurface->renderNow(frameCount/float(encoder->fpsValue())); QImage image = renderSurface->getImage(); //if (!frameCount || frameCount % 3 == 0) { QImage preview = image.scaled(320,200,Qt::KeepAspectRatio,Qt::FastTransformation); frame->setPixmap(QPixmap::fromImage(preview)); //} image = image.convertToFormat(QImage::Format_RGB888); vpx_image_t* vpxImage = vpx_img_alloc(NULL, VPX_IMG_FMT_RGB24, renderSurface->width(), renderSurface->height(), 1); if (!vpxImage) { finishCapture("An error occured during capture: Out of memory."); return; } size_t size = renderSurface->width() * renderSurface->height() * 3; if (size != size_t(image.byteCount())) { finishCapture("An error occured during capture: Image size error."); vpx_img_free(vpxImage); return; } memcpy(vpxImage->img_data, image.bits(), size); if (!encoder->writeFrame(vpxImage)) { finishCapture("An error occured during capture: Frame write error."); vpx_img_free(vpxImage); return; } if (vpxImage) { vpx_img_free(vpxImage); } bool complete = false; if (++frameCount == maxFrames) { finalFrame = true; complete = true; } else { bar->setValue(frameCount/float(maxFrames)*100); } if (finalFrame) { bar->setValue(100); encoder->finish(); delete encoder; if (complete) { finishCapture("The capture is complete."); } else { finishCapture("The capture was canceled."); } } if (!finalFrame) { QTimer::singleShot(0, this, SLOT(onNextFrame())); } }
int main_loop(int argc, const char **argv_) { vpx_codec_ctx_t decoder; char *fn = NULL; int i; uint8_t *buf = NULL; size_t bytes_in_buffer = 0, buffer_size = 0; FILE *infile; int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0; int do_md5 = 0, progress = 0; int stop_after = 0, postproc = 0, summary = 0, quiet = 1; int arg_skip = 0; int ec_enabled = 0; const VpxInterface *interface = NULL; const VpxInterface *fourcc_interface = NULL; uint64_t dx_time = 0; struct arg arg; char **argv, **argi, **argj; int single_file; int use_y4m = 1; vpx_codec_dec_cfg_t cfg = {0}; #if CONFIG_VP8_DECODER vp8_postproc_cfg_t vp8_pp_cfg = {0}; int vp8_dbg_color_ref_frame = 0; int vp8_dbg_color_mb_modes = 0; int vp8_dbg_color_b_modes = 0; int vp8_dbg_display_mv = 0; #endif int frames_corrupted = 0; int dec_flags = 0; int do_scale = 0; vpx_image_t *scaled_img = NULL; int frame_avail, got_data; int num_external_frame_buffers = 0; struct ExternalFrameBufferList ext_fb_list = {0}; const char *outfile_pattern = NULL; char outfile_name[PATH_MAX] = {0}; FILE *outfile = NULL; MD5Context md5_ctx; unsigned char md5_digest[16]; struct VpxDecInputContext input = {0}; struct VpxInputContext vpx_input_ctx = {0}; struct WebmInputContext webm_ctx = {0}; input.vpx_input_ctx = &vpx_input_ctx; input.webm_ctx = &webm_ctx; /* Parse command line */ exec_name = argv_[0]; argv = argv_dup(argc - 1, argv_ + 1); for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) { memset(&arg, 0, sizeof(arg)); arg.argv_step = 1; if (arg_match(&arg, &codecarg, argi)) { interface = get_vpx_decoder_by_name(arg.val); if (!interface) die("Error: Unrecognized argument (%s) to --codec\n", arg.val); } else if (arg_match(&arg, &looparg, argi)) { // no-op } else if (arg_match(&arg, &outputfile, argi)) outfile_pattern = arg.val; else if (arg_match(&arg, &use_yv12, argi)) { use_y4m = 0; flipuv = 1; } else if (arg_match(&arg, &use_i420, argi)) { use_y4m = 0; flipuv = 0; } else if (arg_match(&arg, &flipuvarg, argi)) flipuv = 1; else if (arg_match(&arg, &noblitarg, argi)) noblit = 1; else if (arg_match(&arg, &progressarg, argi)) progress = 1; else if (arg_match(&arg, &limitarg, argi)) stop_after = arg_parse_uint(&arg); else if (arg_match(&arg, &skiparg, argi)) arg_skip = arg_parse_uint(&arg); else if (arg_match(&arg, &postprocarg, argi)) postproc = 1; else if (arg_match(&arg, &md5arg, argi)) do_md5 = 1; else if (arg_match(&arg, &summaryarg, argi)) summary = 1; else if (arg_match(&arg, &threadsarg, argi)) cfg.threads = arg_parse_uint(&arg); else if (arg_match(&arg, &verbosearg, argi)) quiet = 0; else if (arg_match(&arg, &scalearg, argi)) do_scale = 1; else if (arg_match(&arg, &fb_arg, argi)) num_external_frame_buffers = arg_parse_uint(&arg); #if CONFIG_VP8_DECODER else if (arg_match(&arg, &addnoise_level, argi)) { postproc = 1; vp8_pp_cfg.post_proc_flag |= VP8_ADDNOISE; vp8_pp_cfg.noise_level = arg_parse_uint(&arg); } else if (arg_match(&arg, &demacroblock_level, argi)) { postproc = 1; vp8_pp_cfg.post_proc_flag |= VP8_DEMACROBLOCK; vp8_pp_cfg.deblocking_level = arg_parse_uint(&arg); } else if (arg_match(&arg, &deblock, argi)) { postproc = 1; vp8_pp_cfg.post_proc_flag |= VP8_DEBLOCK; } else if (arg_match(&arg, &mfqe, argi)) { postproc = 1; vp8_pp_cfg.post_proc_flag |= VP8_MFQE; } else if (arg_match(&arg, &pp_debug_info, argi)) { unsigned int level = arg_parse_uint(&arg); postproc = 1; vp8_pp_cfg.post_proc_flag &= ~0x7; if (level) vp8_pp_cfg.post_proc_flag |= level; } else if (arg_match(&arg, &pp_disp_ref_frame, argi)) { unsigned int flags = arg_parse_int(&arg); if (flags) { postproc = 1; vp8_dbg_color_ref_frame = flags; } } else if (arg_match(&arg, &pp_disp_mb_modes, argi)) { unsigned int flags = arg_parse_int(&arg); if (flags) { postproc = 1; vp8_dbg_color_mb_modes = flags; } } else if (arg_match(&arg, &pp_disp_b_modes, argi)) { unsigned int flags = arg_parse_int(&arg); if (flags) { postproc = 1; vp8_dbg_color_b_modes = flags; } } else if (arg_match(&arg, &pp_disp_mvs, argi)) { unsigned int flags = arg_parse_int(&arg); if (flags) { postproc = 1; vp8_dbg_display_mv = flags; } } else if (arg_match(&arg, &error_concealment, argi)) { ec_enabled = 1; } #endif 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); /* Handle non-option arguments */ fn = argv[0]; if (!fn) usage_exit(); /* Open file */ infile = strcmp(fn, "-") ? fopen(fn, "rb") : set_binary_mode(stdin); if (!infile) { fprintf(stderr, "Failed to open file '%s'", strcmp(fn, "-") ? fn : "stdin"); return EXIT_FAILURE; } #if CONFIG_OS_SUPPORT /* Make sure we don't dump to the terminal, unless forced to with -o - */ if (!outfile_pattern && isatty(fileno(stdout)) && !do_md5 && !noblit) { fprintf(stderr, "Not dumping raw video to your terminal. Use '-o -' to " "override.\n"); return EXIT_FAILURE; } #endif input.vpx_input_ctx->file = infile; if (file_is_ivf(input.vpx_input_ctx)) input.vpx_input_ctx->file_type = FILE_TYPE_IVF; #if CONFIG_WEBM_IO else if (file_is_webm(input.webm_ctx, input.vpx_input_ctx)) input.vpx_input_ctx->file_type = FILE_TYPE_WEBM; #endif else if (file_is_raw(input.vpx_input_ctx)) input.vpx_input_ctx->file_type = FILE_TYPE_RAW; else { fprintf(stderr, "Unrecognized input file type.\n"); #if !CONFIG_WEBM_IO fprintf(stderr, "vpxdec was built without WebM container support.\n"); #endif return EXIT_FAILURE; } outfile_pattern = outfile_pattern ? outfile_pattern : "-"; single_file = is_single_file(outfile_pattern); if (!noblit && single_file) { generate_filename(outfile_pattern, outfile_name, PATH_MAX, vpx_input_ctx.width, vpx_input_ctx.height, 0); if (do_md5) MD5Init(&md5_ctx); else outfile = open_outfile(outfile_name); } if (use_y4m && !noblit) { if (!single_file) { fprintf(stderr, "YUV4MPEG2 not supported with output patterns," " try --i420 or --yv12.\n"); return EXIT_FAILURE; } #if CONFIG_WEBM_IO if (vpx_input_ctx.file_type == FILE_TYPE_WEBM) { if (webm_guess_framerate(input.webm_ctx, input.vpx_input_ctx)) { fprintf(stderr, "Failed to guess framerate -- error parsing " "webm file?\n"); return EXIT_FAILURE; } } #endif } fourcc_interface = get_vpx_decoder_by_fourcc(vpx_input_ctx.fourcc); if (interface && fourcc_interface && interface != fourcc_interface) warn("Header indicates codec: %s\n", fourcc_interface->name); else interface = fourcc_interface; if (!interface) interface = get_vpx_decoder_by_index(0); dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0) | (ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0); if (vpx_codec_dec_init(&decoder, interface->interface(), &cfg, dec_flags)) { fprintf(stderr, "Failed to initialize decoder: %s\n", vpx_codec_error(&decoder)); return EXIT_FAILURE; } if (!quiet) fprintf(stderr, "%s\n", decoder.name); #if CONFIG_VP8_DECODER if (vp8_pp_cfg.post_proc_flag && vpx_codec_control(&decoder, VP8_SET_POSTPROC, &vp8_pp_cfg)) { fprintf(stderr, "Failed to configure postproc: %s\n", vpx_codec_error(&decoder)); return EXIT_FAILURE; } if (vp8_dbg_color_ref_frame && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_REF_FRAME, vp8_dbg_color_ref_frame)) { fprintf(stderr, "Failed to configure reference block visualizer: %s\n", vpx_codec_error(&decoder)); return EXIT_FAILURE; } if (vp8_dbg_color_mb_modes && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_MB_MODES, vp8_dbg_color_mb_modes)) { fprintf(stderr, "Failed to configure macro block visualizer: %s\n", vpx_codec_error(&decoder)); return EXIT_FAILURE; } if (vp8_dbg_color_b_modes && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_B_MODES, vp8_dbg_color_b_modes)) { fprintf(stderr, "Failed to configure block visualizer: %s\n", vpx_codec_error(&decoder)); return EXIT_FAILURE; } if (vp8_dbg_display_mv && vpx_codec_control(&decoder, VP8_SET_DBG_DISPLAY_MV, vp8_dbg_display_mv)) { fprintf(stderr, "Failed to configure motion vector visualizer: %s\n", vpx_codec_error(&decoder)); return EXIT_FAILURE; } #endif if (arg_skip) fprintf(stderr, "Skipping first %d frames.\n", arg_skip); while (arg_skip) { if (read_frame(&input, &buf, &bytes_in_buffer, &buffer_size)) break; arg_skip--; } if (num_external_frame_buffers > 0) { ext_fb_list.num_external_frame_buffers = num_external_frame_buffers; ext_fb_list.ext_fb = (struct ExternalFrameBuffer *)calloc( num_external_frame_buffers, sizeof(*ext_fb_list.ext_fb)); if (vpx_codec_set_frame_buffer_functions( &decoder, get_vp9_frame_buffer, release_vp9_frame_buffer, &ext_fb_list)) { fprintf(stderr, "Failed to configure external frame buffers: %s\n", vpx_codec_error(&decoder)); return EXIT_FAILURE; } } frame_avail = 1; got_data = 0; /* Decode file */ while (frame_avail || got_data) { vpx_codec_iter_t iter = NULL; vpx_image_t *img; struct vpx_usec_timer timer; int corrupted; frame_avail = 0; if (!stop_after || frame_in < stop_after) { if (!read_frame(&input, &buf, &bytes_in_buffer, &buffer_size)) { frame_avail = 1; frame_in++; vpx_usec_timer_start(&timer); if (vpx_codec_decode(&decoder, buf, (unsigned int)bytes_in_buffer, NULL, 0)) { const char *detail = vpx_codec_error_detail(&decoder); warn("Failed to decode frame %d: %s", frame_in, vpx_codec_error(&decoder)); if (detail) warn("Additional information: %s", detail); goto fail; } vpx_usec_timer_mark(&timer); dx_time += vpx_usec_timer_elapsed(&timer); } } vpx_usec_timer_start(&timer); got_data = 0; if ((img = vpx_codec_get_frame(&decoder, &iter))) { ++frame_out; got_data = 1; } vpx_usec_timer_mark(&timer); dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer); if (vpx_codec_control(&decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted)) { warn("Failed VP8_GET_FRAME_CORRUPTED: %s", vpx_codec_error(&decoder)); goto fail; } frames_corrupted += corrupted; if (progress) show_progress(frame_in, frame_out, dx_time); if (!noblit && img) { const int PLANES_YUV[] = {VPX_PLANE_Y, VPX_PLANE_U, VPX_PLANE_V}; const int PLANES_YVU[] = {VPX_PLANE_Y, VPX_PLANE_V, VPX_PLANE_U}; const int *planes = flipuv ? PLANES_YVU : PLANES_YUV; if (do_scale) { if (frame_out == 1) { // If the output frames are to be scaled to a fixed display size then // use the width and height specified in the container. If either of // these is set to 0, use the display size set in the first frame // header. If that is unavailable, use the raw decoded size of the // first decoded frame. int display_width = vpx_input_ctx.width; int display_height = vpx_input_ctx.height; if (!display_width || !display_height) { int display_size[2]; if (vpx_codec_control(&decoder, VP9D_GET_DISPLAY_SIZE, display_size)) { // As last resort use size of first frame as display size. display_width = img->d_w; display_height = img->d_h; } else { display_width = display_size[0]; display_height = display_size[1]; } } scaled_img = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, display_width, display_height, 16); } if (img->d_w != scaled_img->d_w || img->d_h != scaled_img->d_h) { vpx_image_scale(img, scaled_img, kFilterBox); img = scaled_img; } } if (single_file) { if (use_y4m) { char buf[Y4M_BUFFER_SIZE] = {0}; size_t len = 0; if (frame_out == 1) { // Y4M file header len = y4m_write_file_header(buf, sizeof(buf), vpx_input_ctx.width, vpx_input_ctx.height, &vpx_input_ctx.framerate, img->fmt); if (do_md5) { MD5Update(&md5_ctx, (md5byte *)buf, (unsigned int)len); } else { fputs(buf, outfile); } } // Y4M frame header len = y4m_write_frame_header(buf, sizeof(buf)); if (do_md5) { MD5Update(&md5_ctx, (md5byte *)buf, (unsigned int)len); } else { fputs(buf, outfile); } } if (do_md5) { update_image_md5(img, planes, &md5_ctx); } else { write_image_file(img, planes, outfile); } } else { generate_filename(outfile_pattern, outfile_name, PATH_MAX, img->d_w, img->d_h, frame_in); if (do_md5) { MD5Init(&md5_ctx); update_image_md5(img, planes, &md5_ctx); MD5Final(md5_digest, &md5_ctx); print_md5(md5_digest, outfile_name); } else { outfile = open_outfile(outfile_name); write_image_file(img, planes, outfile); fclose(outfile); } } } if (stop_after && frame_in >= stop_after) break; } if (summary || progress) { show_progress(frame_in, frame_out, dx_time); fprintf(stderr, "\n"); } if (frames_corrupted) fprintf(stderr, "WARNING: %d frames corrupted.\n", frames_corrupted); fail: if (vpx_codec_destroy(&decoder)) { fprintf(stderr, "Failed to destroy decoder: %s\n", vpx_codec_error(&decoder)); return EXIT_FAILURE; } if (!noblit && single_file) { if (do_md5) { MD5Final(md5_digest, &md5_ctx); print_md5(md5_digest, outfile_name); } else { fclose(outfile); } } #if CONFIG_WEBM_IO if (input.vpx_input_ctx->file_type == FILE_TYPE_WEBM) webm_free(input.webm_ctx); #endif if (input.vpx_input_ctx->file_type != FILE_TYPE_WEBM) free(buf); if (scaled_img) vpx_img_free(scaled_img); for (i = 0; i < ext_fb_list.num_external_frame_buffers; ++i) { free(ext_fb_list.ext_fb[i].data); } free(ext_fb_list.ext_fb); fclose(infile); free(argv); return frames_corrupted ? EXIT_FAILURE : 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; }
int main(int argc, char **argv) { FILE *infile = NULL; int w, h; vpx_codec_ctx_t codec; vpx_codec_enc_cfg_t cfg; vpx_image_t raw; vpx_codec_err_t res; vpx_fixed_buf_t stats; const VpxInterface *encoder = NULL; const int fps = 30; // TODO(dkovalev) add command line argument const int bitrate = 200; // kbit/s TODO(dkovalev) add command line argument const char *const codec_arg = argv[1]; const char *const width_arg = argv[2]; const char *const height_arg = argv[3]; const char *const infile_arg = argv[4]; const char *const outfile_arg = argv[5]; exec_name = argv[0]; if (argc != 6) die("Invalid number of arguments."); encoder = get_vpx_encoder_by_name(codec_arg); if (!encoder) die("Unsupported codec."); w = strtol(width_arg, NULL, 0); h = strtol(height_arg, NULL, 0); if (w <= 0 || h <= 0 || (w % 2) != 0 || (h % 2) != 0) die("Invalid frame size: %dx%d", w, h); if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, w, h, 1)) die("Failed to allocate image", w, h); printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface())); // Configuration 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 = w; cfg.g_h = h; cfg.g_timebase.num = 1; cfg.g_timebase.den = fps; cfg.rc_target_bitrate = bitrate; if (!(infile = fopen(infile_arg, "rb"))) die("Failed to open %s for reading", infile_arg); // Pass 0 cfg.g_pass = VPX_RC_FIRST_PASS; stats = pass0(&raw, infile, encoder, &cfg); // Pass 1 rewind(infile); cfg.g_pass = VPX_RC_LAST_PASS; cfg.rc_twopass_stats_in = stats; pass1(&raw, infile, outfile_arg, encoder, &cfg); free(stats.buf); vpx_img_free(&raw); fclose(infile); 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; }
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, *outfile; vpx_codec_ctx_t codec; vpx_codec_enc_cfg_t cfg; int frame_cnt = 0; unsigned char file_hdr[IVF_FILE_HDR_SZ]; unsigned char frame_hdr[IVF_FRAME_HDR_SZ]; vpx_image_t raw; vpx_codec_err_t ret; int width,height; int y_size; int frame_avail; int got_data; int flags = 0; width = 640; height = 360; infile = fopen("../cuc_ieschool_640x360_yuv420p.yuv", "rb"); outfile = fopen("cuc_ieschool.ivf", "wb"); if(infile==NULL||outfile==NULL){ printf("Error open files.\n"); return -1; } if(!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 1)){ printf("Fail to allocate image\n"); return -1; } printf("Using %s\n",vpx_codec_iface_name(interface)); //Populate encoder configuration ret = vpx_codec_enc_config_default(interface, &cfg, 0); if(ret) { printf("Failed to get config: %s\n", vpx_codec_err_to_string(ret)); return -1; } cfg.rc_target_bitrate =800; cfg.g_w = width; cfg.g_h = height; write_ivf_file_header(outfile, &cfg, 0); //Initialize codec if(vpx_codec_enc_init(&codec, interface, &cfg, 0)){ printf("Failed to initialize encoder\n"); return -1; } frame_avail = 1; got_data = 0; y_size=cfg.g_w*cfg.g_h; while(frame_avail || got_data) { vpx_codec_iter_t iter = NULL; const vpx_codec_cx_pkt_t *pkt; if(fread(raw.planes[0], 1, y_size*3/2, infile)!=y_size*3/2){ frame_avail=0; } if(frame_avail){ //Encode ret=vpx_codec_encode(&codec,&raw,frame_cnt,1,flags,VPX_DL_REALTIME); }else{ //Flush Encoder ret=vpx_codec_encode(&codec,NULL,frame_cnt,1,flags,VPX_DL_REALTIME); } if(ret){ printf("Failed to encode frame\n"); return -1; } 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); fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz,outfile); break; default: break; } } printf("Succeed encode frame: %5d\n",frame_cnt); frame_cnt++; } fclose(infile); vpx_codec_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 0; }
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; }
int main(int argc, char **argv) { FILE *infile = NULL; // Encoder vpx_codec_ctx_t ecodec = {0}; vpx_codec_enc_cfg_t cfg = {0}; unsigned int frame_in = 0; vpx_image_t raw; vpx_codec_err_t res; VpxVideoInfo info = {0}; VpxVideoWriter *writer = NULL; const VpxInterface *encoder = NULL; // Test encoder/decoder mismatch. int test_decode = 1; // Decoder vpx_codec_ctx_t dcodec; unsigned int frame_out = 0; // The frame number to set reference frame on unsigned int update_frame_num = 0; int mismatch_seen = 0; const int fps = 30; const int bitrate = 500; const char *width_arg = NULL; const char *height_arg = NULL; const char *infile_arg = NULL; const char *outfile_arg = NULL; unsigned int limit = 0; exec_name = argv[0]; if (argc < 6) die("Invalid number of arguments"); width_arg = argv[1]; height_arg = argv[2]; infile_arg = argv[3]; outfile_arg = argv[4]; encoder = get_vpx_encoder_by_name("vp9"); if (!encoder) die("Unsupported codec."); update_frame_num = atoi(argv[5]); // In VP9, the reference buffers (cm->buffer_pool->frame_bufs[i].buf) are // allocated while calling vpx_codec_encode(), thus, setting reference for // 1st frame isn't supported. if (update_frame_num <= 1) die("Couldn't parse frame number '%s'\n", argv[5]); if (argc > 6) { limit = atoi(argv[6]); if (update_frame_num > limit) die("Update frame number couldn't larger than limit\n"); } info.codec_fourcc = encoder->fourcc; info.frame_width = strtol(width_arg, NULL, 0); info.frame_height = strtol(height_arg, 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(&ecodec, "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; cfg.g_lag_in_frames = 3; writer = vpx_video_writer_open(outfile_arg, kContainerIVF, &info); if (!writer) die("Failed to open %s for writing.", outfile_arg); if (!(infile = fopen(infile_arg, "rb"))) die("Failed to open %s for reading.", infile_arg); if (vpx_codec_enc_init(&ecodec, encoder->codec_interface(), &cfg, 0)) die_codec(&ecodec, "Failed to initialize encoder"); // Disable alt_ref. if (vpx_codec_control(&ecodec, VP8E_SET_ENABLEAUTOALTREF, 0)) die_codec(&ecodec, "Failed to set enable auto alt ref"); if (test_decode) { const VpxInterface *decoder = get_vpx_decoder_by_name("vp9"); if (vpx_codec_dec_init(&dcodec, decoder->codec_interface(), NULL, 0)) die_codec(&dcodec, "Failed to initialize decoder."); } // Encode frames. while (vpx_img_read(&raw, infile)) { if (limit && frame_in >= limit) break; if (update_frame_num > 1 && frame_out + 1 == update_frame_num) { vpx_ref_frame_t ref; ref.frame_type = VP8_LAST_FRAME; ref.img = raw; // Set reference frame in encoder. if (vpx_codec_control(&ecodec, VP8_SET_REFERENCE, &ref)) die_codec(&ecodec, "Failed to set reference frame"); printf(" <SET_REF>"); // If set_reference in decoder is commented out, the enc/dec mismatch // would be seen. if (test_decode) { if (vpx_codec_control(&dcodec, VP8_SET_REFERENCE, &ref)) die_codec(&dcodec, "Failed to set reference frame"); } } encode_frame(&ecodec, &cfg, &raw, frame_in, writer, test_decode, &dcodec, &frame_out, &mismatch_seen); frame_in++; if (mismatch_seen) break; } // Flush encoder. if (!mismatch_seen) while (encode_frame(&ecodec, &cfg, NULL, frame_in, writer, test_decode, &dcodec, &frame_out, &mismatch_seen)) {} printf("\n"); fclose(infile); printf("Processed %d frames.\n", frame_out); if (test_decode) { if (!mismatch_seen) printf("Encoder/decoder results are matching.\n"); else printf("Encoder/decoder results are NOT matching.\n"); } if (test_decode) if (vpx_codec_destroy(&dcodec)) die_codec(&dcodec, "Failed to destroy decoder"); vpx_img_free(&raw); if (vpx_codec_destroy(&ecodec)) die_codec(&ecodec, "Failed to destroy encoder."); vpx_video_writer_close(writer); return EXIT_SUCCESS; }
// Initialize encoder, given setup in the encoder parameters bool LumaEncoder::initialize(const char *outputFile, const unsigned int w, const unsigned int h, bool verbose) { // Initialize base. Creates a Matroska file for writing LumaEncoderBase::initialize(outputFile, w, h); // Adjust profile for the specified bit depth (0-1 for 8 bits, and 2-3 for higher bit depths) if (m_params.profile > 1 && m_params.bitDepth == 8) m_params.profile -=2; if (m_params.profile < 2 && m_params.bitDepth > 8) m_params.profile +=2; // Initialize quantizer m_quant.setQuantizer(m_params.ptf, m_params.ptfBitDepth, m_params.colorSpace, m_params.colorBitDepth); // Add attachments with meta data to Matroska file unsigned int *buffer1 = new unsigned int; *buffer1 = m_params.ptfBitDepth; m_writer.addAttachment(430, (const binary*)buffer1, sizeof(unsigned int), "PTF bit depth"); unsigned int *buffer2 = new unsigned int; *buffer2 = m_params.colorBitDepth; m_writer.addAttachment(431, (const binary*)buffer2, sizeof(unsigned int), "Color bit depth"); LumaQuantizer::ptf_t *buffer3 = new LumaQuantizer::ptf_t; *buffer3 = m_params.ptf; m_writer.addAttachment(432, (const binary*)buffer3, sizeof(LumaQuantizer::ptf_t), "PTF description"); LumaQuantizer::colorSpace_t *buffer4 = new LumaQuantizer::colorSpace_t; *buffer4 = m_params.colorSpace; m_writer.addAttachment(433, (const binary*)buffer4, sizeof(LumaQuantizer::colorSpace_t), "Color space"); float *buffer5 = new float[m_quant.getSize()]; memcpy((void*)buffer5, (void*)m_quant.getMapping(), (m_quant.getSize())*sizeof(float)); m_writer.addAttachment(434, (const binary*)buffer5, (m_quant.getSize())*sizeof(float), "PTF"); float *buffer6 = new float; *buffer6 = m_params.preScaling; m_writer.addAttachment(435, (const binary*)buffer6, sizeof(float), "Scaling"); m_writer.writeAttachments(); // Framerate for timecodes m_writer.setFramerate(m_params.fps); m_writer.setVerbose(verbose); // Initialize VPX codec vpx_codec_err_t res; vpx_codec_enc_cfg_t cfg; const vpx_codec_iface_t *(*const vpx_encoder)() = &vpx_codec_vp9_cx; if (w <= 0 || h <= 0 || (w % 2) != 0 || (h % 2) != 0) throw LumaException("Invalid frame size"); if (m_params.profile == 0 && !vpx_img_alloc(&m_rawFrame, VPX_IMG_FMT_I420, w, h, 32)) throw LumaException("Failed to allocate 8 bit 420 image"); else if (m_params.profile == 1 && !vpx_img_alloc(&m_rawFrame, VPX_IMG_FMT_I444, w, h, 32)) throw LumaException("Failed to allocate 8 bit 444 image"); else if (m_params.profile == 2 && !vpx_img_alloc(&m_rawFrame, VPX_IMG_FMT_I42016, w, h, 32)) throw LumaException("Failed to allocate 16 bit 420 image"); else if (m_params.profile == 3 && !vpx_img_alloc(&m_rawFrame, VPX_IMG_FMT_I44416, w, h, 32)) throw LumaException("Failed to allocate 16 bit 444 image"); res = vpx_codec_enc_config_default(vpx_encoder(), &cfg, 0); if (res) throw LumaException("Failed to get default codec config"); cfg.g_threads = 6; cfg.rc_min_quantizer = m_params.quantizerScale; cfg.rc_max_quantizer = m_params.quantizerScale; cfg.g_w = w; cfg.g_h = h; cfg.g_timebase.num = 1; cfg.g_timebase.den = 25; cfg.rc_target_bitrate = m_params.bitrate; cfg.g_error_resilient = 0; cfg.g_pass = VPX_RC_ONE_PASS; cfg.rc_end_usage = VPX_VBR; cfg.g_lag_in_frames = 0; cfg.rc_end_usage = VPX_Q; cfg.kf_max_dist = 25; cfg.kf_mode = VPX_KF_AUTO; cfg.g_profile = m_params.profile; fprintf(stderr, "Encoding options:\n"); fprintf(stderr, "--------------------------------------------------------\n"); fprintf(stderr, "Transfer function (PTF): %s\n", m_quant.name(m_params.ptf).c_str()); fprintf(stderr, "Color space: %s\n", m_quant.name(m_params.colorSpace).c_str()); fprintf(stderr, "PTF bit depth: %d\n", m_params.ptfBitDepth); fprintf(stderr, "Color bit depth: %d\n", m_params.colorBitDepth); fprintf(stderr, "Encoding profile: %d (4%d%d)\n", m_params.profile, (m_params.profile%2==0) ? 2 : 4, (m_params.profile%2==0) ? 2 : 4); fprintf(stderr, "Encoding bit depth: "); if (m_params.bitDepth == 8 || m_params.profile < 2) { cfg.g_bit_depth = VPX_BITS_8; fprintf(stderr, "8\n"); } else if (m_params.bitDepth == 10) { cfg.g_bit_depth = VPX_BITS_10; fprintf(stderr, "10\n"); } else { cfg.g_bit_depth = VPX_BITS_12; fprintf(stderr, "12\n"); } fprintf(stderr, "Codec: %s\n", vpx_codec_iface_name(vpx_encoder())); fprintf(stderr, "Output: %s\n", outputFile); fprintf(stderr, "--------------------------------------------------------\n\n"); int flags = m_params.profile < 2 ? 0 : VPX_CODEC_USE_HIGHBITDEPTH; if (vpx_codec_enc_init(&m_codec, vpx_encoder(), &cfg, flags)) throw LumaException("Failed to initialize vpxEncoder\n"); if (m_params.lossLess && vpx_codec_control_(&m_codec, VP9E_SET_LOSSLESS, 1)) throw LumaException("Failed to use lossless mode\n"); m_initialized = true; return true; }
int main(int argc, const char **argv) { AppInput app_input = {0}; FILE *outfile; vpx_codec_ctx_t codec; vpx_codec_enc_cfg_t enc_cfg; SvcContext svc_ctx; uint32_t i; uint32_t frame_cnt = 0; vpx_image_t raw; vpx_codec_err_t res; int pts = 0; /* PTS starts at 0 */ int frame_duration = 1; /* 1 timebase tick per frame */ vpx_codec_cx_pkt_t packet = {0}; packet.kind = VPX_CODEC_CX_FRAME_PKT; memset(&svc_ctx, 0, sizeof(svc_ctx)); svc_ctx.log_print = 1; exec_name = argv[0]; parse_command_line(argc, argv, &app_input, &svc_ctx, &enc_cfg); // Allocate image buffer if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, enc_cfg.g_w, enc_cfg.g_h, 32)) die("Failed to allocate image %dx%d\n", enc_cfg.g_w, enc_cfg.g_h); if (!(app_input.input_ctx.file = fopen(app_input.input_ctx.filename, "rb"))) die("Failed to open %s for reading\n", app_input.input_ctx.filename); if (!(outfile = fopen(app_input.output_filename, "wb"))) die("Failed to open %s for writing\n", app_input.output_filename); // Initialize codec if (vpx_svc_init(&svc_ctx, &codec, vpx_codec_vp9_cx(), &enc_cfg) != VPX_CODEC_OK) die("Failed to initialize encoder\n"); ivf_write_file_header(outfile, &enc_cfg, VP9_FOURCC, 0); // skip initial frames for (i = 0; i < app_input.frames_to_skip; ++i) { read_yuv_frame(&app_input.input_ctx, &raw); } // Encode frames while (frame_cnt < app_input.frames_to_code) { if (read_yuv_frame(&app_input.input_ctx, &raw)) break; res = vpx_svc_encode(&svc_ctx, &codec, &raw, pts, frame_duration, VPX_DL_REALTIME); printf("%s", vpx_svc_get_message(&svc_ctx)); if (res != VPX_CODEC_OK) { die_codec(&codec, "Failed to encode frame"); } if (vpx_svc_get_frame_size(&svc_ctx) > 0) { packet.data.frame.pts = pts; packet.data.frame.sz = vpx_svc_get_frame_size(&svc_ctx); ivf_write_frame_header(outfile, &packet); (void)fwrite(vpx_svc_get_buffer(&svc_ctx), 1, vpx_svc_get_frame_size(&svc_ctx), outfile); } ++frame_cnt; pts += frame_duration; } printf("Processed %d frames\n", frame_cnt); fclose(app_input.input_ctx.file); if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec"); // rewrite the output file headers with the actual frame count, and // resolution of the highest layer if (!fseek(outfile, 0, SEEK_SET)) { // get resolution of highest layer if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(&svc_ctx, svc_ctx.spatial_layers - 1, &enc_cfg.g_w, &enc_cfg.g_h)) { die("Failed to get output resolution"); } ivf_write_file_header(outfile, &enc_cfg, VP9_FOURCC, frame_cnt); } fclose(outfile); vpx_img_free(&raw); // display average size, psnr printf("%s", vpx_svc_dump_statistics(&svc_ctx)); vpx_svc_release(&svc_ctx); return EXIT_SUCCESS; }
VideoSurface::VideoSurface() : QAbstractVideoSurface() { vpx_img_alloc(&input, VPX_IMG_FMT_YV12, TOXAV_MAX_VIDEO_WIDTH, TOXAV_MAX_VIDEO_HEIGHT, 1); }
void *encode_video_thread(void *arg) { INFO("Started encode video thread!"); av_session_t *_phone = arg; _phone->running_encvid = 1; //CodecState *cs = get_cs_temp(_phone->av); AVPacket pkt1, *packet = &pkt1; //int p = 0; //int got_packet; int video_frame_finished; AVFrame *s_video_frame; AVFrame *webcam_frame; s_video_frame = avcodec_alloc_frame(); webcam_frame = avcodec_alloc_frame(); //AVPacket enc_video_packet; uint8_t *buffer; int numBytes; /* Determine required buffer size and allocate buffer */ numBytes = avpicture_get_size(PIX_FMT_YUV420P, _phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height); buffer = (uint8_t *)av_calloc(numBytes * sizeof(uint8_t), 1); avpicture_fill((AVPicture *)s_video_frame, buffer, PIX_FMT_YUV420P, _phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height); _phone->sws_ctx = sws_getContext(_phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height, _phone->webcam_decoder_ctx->pix_fmt, _phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height, PIX_FMT_YUV420P, SWS_BILINEAR, NULL, NULL, NULL); vpx_image_t *image = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, _phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height, 1); //uint32_t frame_counter = 0; while (_phone->running_encvid) { if (av_read_frame(_phone->video_format_ctx, packet) < 0) { printf("error reading frame\n"); if (_phone->video_format_ctx->pb->error != 0) break; continue; } if (packet->stream_index == _phone->video_stream) { if (avcodec_decode_video2(_phone->webcam_decoder_ctx, webcam_frame, &video_frame_finished, packet) < 0) { printf("couldn't decode\n"); continue; } av_free_packet(packet); sws_scale(_phone->sws_ctx, (uint8_t const * const *)webcam_frame->data, webcam_frame->linesize, 0, _phone->webcam_decoder_ctx->height, s_video_frame->data, s_video_frame->linesize); /* create a new I-frame every 60 frames */ //++p; /* if (p == 60) { s_video_frame->pict_type = AV_PICTURE_TYPE_BI ; } else if (p == 61) { s_video_frame->pict_type = AV_PICTURE_TYPE_I ; p = 0; } else { s_video_frame->pict_type = AV_PICTURE_TYPE_P ; }*/ if (video_frame_finished) { memcpy(image->planes[VPX_PLANE_Y], s_video_frame->data[0], s_video_frame->linesize[0] * _phone->webcam_decoder_ctx->height); memcpy(image->planes[VPX_PLANE_U], s_video_frame->data[1], s_video_frame->linesize[1] * _phone->webcam_decoder_ctx->height / 2); memcpy(image->planes[VPX_PLANE_V], s_video_frame->data[2], s_video_frame->linesize[2] * _phone->webcam_decoder_ctx->height / 2); toxav_send_video (_phone->av, image); //if (avcodec_encode_video2(cs->video_encoder_ctx, &enc_video_packet, s_video_frame, &got_packet) < 0) { /*if (vpx_codec_encode(&cs->v_encoder, image, frame_counter, 1, 0, 0) != VPX_CODEC_OK) { printf("could not encode video frame\n"); continue; } ++frame_counter; vpx_codec_iter_t iter = NULL; vpx_codec_cx_pkt_t *pkt; while( (pkt = vpx_codec_get_cx_data(&cs->v_encoder, &iter)) ) { if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) toxav_send_rtp_payload(_phone->av, TypeVideo, pkt->data.frame.buf, pkt->data.frame.sz); }*/ //if (!got_packet) { // continue; //} //if (!enc_video_packet.data) fprintf(stderr, "video packet data is NULL\n"); //toxav_send_rtp_payload(_phone->av, TypeVideo, enc_video_packet.data, enc_video_packet.size); //av_free_packet(&enc_video_packet); } } else { av_free_packet(packet); } } vpx_img_free(image); /* clean up codecs */ //pthread_mutex_lock(&cs->ctrl_mutex); av_free(buffer); av_free(webcam_frame); av_free(s_video_frame); sws_freeContext(_phone->sws_ctx); //avcodec_close(webcam_decoder_ctx); //avcodec_close(cs->video_encoder_ctx); //pthread_mutex_unlock(&cs->ctrl_mutex); _phone->running_encvid = -1; pthread_exit ( NULL ); }
// TODO(tomfinegan): Improve command line parsing and add args for bitrate/fps. 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 = { 0, 0, 0, { 0, 0 } }; VpxVideoWriter *writer = NULL; const VpxInterface *encoder = NULL; const int fps = 30; const int bitrate = 200; int keyframe_interval = 0; int max_frames = 0; int frames_encoded = 0; const char *codec_arg = NULL; const char *width_arg = NULL; const char *height_arg = NULL; const char *infile_arg = NULL; const char *outfile_arg = NULL; const char *keyframe_interval_arg = NULL; exec_name = argv[0]; if (argc != 9) die("Invalid number of arguments"); codec_arg = argv[1]; width_arg = argv[2]; height_arg = argv[3]; infile_arg = argv[4]; outfile_arg = argv[5]; keyframe_interval_arg = argv[6]; max_frames = (int)strtol(argv[8], NULL, 0); encoder = get_vpx_encoder_by_name(codec_arg); if (!encoder) die("Unsupported codec."); info.codec_fourcc = encoder->fourcc; info.frame_width = (int)strtol(width_arg, NULL, 0); info.frame_height = (int)strtol(height_arg, 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."); } keyframe_interval = (int)strtol(keyframe_interval_arg, NULL, 0); if (keyframe_interval < 0) die("Invalid keyframe interval value."); 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; cfg.g_error_resilient = (vpx_codec_er_flags_t)strtoul(argv[7], NULL, 0); writer = vpx_video_writer_open(outfile_arg, kContainerIVF, &info); if (!writer) die("Failed to open %s for writing.", outfile_arg); if (!(infile = fopen(infile_arg, "rb"))) die("Failed to open %s for reading.", infile_arg); 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)) { int flags = 0; if (keyframe_interval > 0 && frame_count % keyframe_interval == 0) flags |= VPX_EFLAG_FORCE_KF; encode_frame(&codec, &raw, frame_count++, flags, writer); frames_encoded++; if (max_frames > 0 && frames_encoded >= max_frames) break; } // Flush encoder. while (encode_frame(&codec, NULL, -1, 0, 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; }
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) { 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; if(frame_cnt + 1 == 22) { // vpx_roi_map_t roi; // int i; // // roi.rows = cfg.g_h/16; // roi.cols = cfg.g_w/16; // // roi.delta_q[0] = 0; // roi.delta_q[1] = -2; // roi.delta_q[2] = -4; // roi.delta_q[3] = -6; // // roi.delta_lf[0] = 0; // roi.delta_lf[1] = 1; // roi.delta_lf[2] = 2; // roi.delta_lf[3] = 3; // // roi.static_threshold[0] = 1500; // roi.static_threshold[1] = 1000; // roi.static_threshold[2] = 500; // roi.static_threshold[3] = 0; // // /* generate an ROI map for example */ // roi.roi_map = malloc(roi.rows * roi.cols); // for(i=0;i<roi.rows*roi.cols;i++) // roi.roi_map[i] = i & 3; // // if(vpx_codec_control(&codec, VP8E_SET_ROI_MAP, &roi)) // die_codec(&codec, "Failed to set ROI map"); // // free(roi.roi_map); // } else if(frame_cnt + 1 == 33) { // vpx_active_map_t active; // int i; // // active.rows = cfg.g_h/16; // active.cols = cfg.g_w/16; // // /* generate active map for example */ // active.active_map = malloc(active.rows * active.cols); // for(i=0;i<active.rows*active.cols;i++) // active.active_map[i] = i & 1; // // if(vpx_codec_control(&codec, VP8E_SET_ACTIVEMAP, &active)) // die_codec(&codec, "Failed to set active map"); // // free(active.active_map); // } else if(frame_cnt + 1 == 44) { // vpx_active_map_t active; // // active.rows = cfg.g_h/16; // active.cols = cfg.g_w/16; // // /* pass in null map to disable active_map*/ // active.active_map = NULL; // // if(vpx_codec_control(&codec, VP8E_SET_ACTIVEMAP, &active)) // die_codec(&codec, "Failed to set active map"); // } // 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) { 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; }