1dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org/* 2dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org * Copyright (c) 2010 The WebM project authors. All Rights Reserved. 3dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org * 4dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org * Use of this source code is governed by a BSD-style license 5dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org * that can be found in the LICENSE file in the root of the source 6dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org * tree. An additional intellectual property rights grant can be found 7dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org * in the file PATENTS. All contributing project authors may 8dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org * be found in the AUTHORS file in the root of the source tree. 9dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org */ 10dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 11dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 12dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// VP8 Set Reference Frame 13dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// ======================= 14dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// 15dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// This is an example demonstrating how to overwrite the VP8 encoder's 16dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// internal reference frame. In the sample we set the last frame to the 17dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// current frame. If this is done at a cut scene it will avoid a keyframe. 18dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// This technique could be used to bounce between two cameras. 19dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// 20dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// Note that the decoder would also have to set the reference frame to the 21dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// same value on the same frame, or the video will become corrupt. 22dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// 23dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// Usage 24dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// ----- 25dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// This example adds a single argument to the `simple_encoder` example, 26dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// which specifies the frame number to update the reference frame on. 27dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// The parameter is parsed as follows: 28dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// 29dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// 30dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// Extra Variables 31dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// --------------- 32dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// This example maintains the frame number passed on the command line 33dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// in the `update_frame_num` variable. 34dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// 35dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// 36dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// Configuration 37dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// ------------- 38dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// 39dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// The reference frame is updated on the frame specified on the command 40dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// line. 41dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// 42dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// Observing The Effects 43dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// --------------------- 44dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// Use the `simple_encoder` example to encode a sample with a cut scene. 45dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// Determine the frame number of the cut scene by looking for a generated 46dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// key-frame (indicated by a 'K'). Supply that frame number as an argument 47dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org// to this example, and observe that no key-frame is generated. 48dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 49dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org#include <stdio.h> 50dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org#include <stdlib.h> 51dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org#include <string.h> 5293a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 53dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org#include "vpx/vp8cx.h" 5493a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org#include "vpx/vpx_encoder.h" 55dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 5693a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org#include "./tools_common.h" 5793a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org#include "./video_writer.h" 58dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 5993a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.orgstatic const char *exec_name; 60dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 6193a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.orgvoid usage_exit() { 6293a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org fprintf(stderr, "Usage: %s <width> <height> <infile> <outfile> <frame>\n", 6393a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org exec_name); 6493a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org exit(EXIT_FAILURE); 65dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org} 66dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 6741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgstatic int encode_frame(vpx_codec_ctx_t *codec, 6841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org vpx_image_t *img, 6941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org int frame_index, 7041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org VpxVideoWriter *writer) { 7141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org int got_pkts = 0; 7293a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org vpx_codec_iter_t iter = NULL; 7393a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org const vpx_codec_cx_pkt_t *pkt = NULL; 7493a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org const vpx_codec_err_t res = vpx_codec_encode(codec, img, frame_index, 1, 0, 7593a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org VPX_DL_GOOD_QUALITY); 7693a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org if (res != VPX_CODEC_OK) 7793a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org die_codec(codec, "Failed to encode frame"); 7893a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 7993a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org while ((pkt = vpx_codec_get_cx_data(codec, &iter)) != NULL) { 8041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org got_pkts = 1; 8141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org 8293a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { 8393a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0; 8493a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org if (!vpx_video_writer_write_frame(writer, 8593a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org pkt->data.frame.buf, 8693a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org pkt->data.frame.sz, 8793a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org pkt->data.frame.pts)) { 8893a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org die_codec(codec, "Failed to write compressed frame"); 8993a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org } 9093a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 9193a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org printf(keyframe ? "K" : "."); 9293a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org fflush(stdout); 93dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org } 9493a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org } 9541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org 9641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org return got_pkts; 97dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org} 98dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 99dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.orgint main(int argc, char **argv) { 10093a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org FILE *infile = NULL; 10193a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org vpx_codec_ctx_t codec = {0}; 10293a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org vpx_codec_enc_cfg_t cfg = {0}; 10393a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org int frame_count = 0; 10493a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org vpx_image_t raw; 10593a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org vpx_codec_err_t res; 10693a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org VpxVideoInfo info = {0}; 10793a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org VpxVideoWriter *writer = NULL; 10893a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org const VpxInterface *encoder = NULL; 10993a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org int update_frame_num = 0; 11093a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org const int fps = 30; // TODO(dkovalev) add command line argument 11193a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org const int bitrate = 200; // kbit/s TODO(dkovalev) add command line argument 11293a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 11393a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org exec_name = argv[0]; 11493a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 11593a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org if (argc != 6) 11693a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org die("Invalid number of arguments"); 11793a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 11893a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org // TODO(dkovalev): add vp9 support and rename the file accordingly 11993a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org encoder = get_vpx_encoder_by_name("vp8"); 12093a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org if (!encoder) 12193a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org die("Unsupported codec."); 12293a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 12393a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org update_frame_num = atoi(argv[5]); 12493a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org if (!update_frame_num) 12593a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org die("Couldn't parse frame number '%s'\n", argv[5]); 12693a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 12793a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org info.codec_fourcc = encoder->fourcc; 12893a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org info.frame_width = strtol(argv[1], NULL, 0); 12993a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org info.frame_height = strtol(argv[2], NULL, 0); 13093a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org info.time_base.numerator = 1; 13193a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org info.time_base.denominator = fps; 13293a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 13393a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org if (info.frame_width <= 0 || 13493a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org info.frame_height <= 0 || 13593a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org (info.frame_width % 2) != 0 || 13693a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org (info.frame_height % 2) != 0) { 13793a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org die("Invalid frame size: %dx%d", info.frame_width, info.frame_height); 13893a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org } 13993a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 14093a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width, 14193a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org info.frame_height, 1)) { 14293a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org die("Failed to allocate image."); 14393a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org } 14493a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 145ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface())); 14693a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 147ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0); 14893a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org if (res) 14993a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org die_codec(&codec, "Failed to get default codec config."); 15093a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 15193a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org cfg.g_w = info.frame_width; 15293a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org cfg.g_h = info.frame_height; 15393a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org cfg.g_timebase.num = info.time_base.numerator; 15493a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org cfg.g_timebase.den = info.time_base.denominator; 15593a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org cfg.rc_target_bitrate = bitrate; 15693a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 15793a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org writer = vpx_video_writer_open(argv[4], kContainerIVF, &info); 15893a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org if (!writer) 15993a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org die("Failed to open %s for writing.", argv[4]); 16093a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 16193a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org if (!(infile = fopen(argv[3], "rb"))) 16293a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org die("Failed to open %s for reading.", argv[3]); 16393a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 164ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org if (vpx_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0)) 16593a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org die_codec(&codec, "Failed to initialize encoder"); 16693a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 16741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org // Encode frames. 16893a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org while (vpx_img_read(&raw, infile)) { 16993a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org if (frame_count + 1 == update_frame_num) { 17093a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org vpx_ref_frame_t ref; 17193a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org ref.frame_type = VP8_LAST_FRAME; 17293a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org ref.img = raw; 17393a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org if (vpx_codec_control(&codec, VP8_SET_REFERENCE, &ref)) 17493a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org die_codec(&codec, "Failed to set reference frame"); 175dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org } 176dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 17793a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org encode_frame(&codec, &raw, frame_count++, writer); 17893a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org } 17941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org 18041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org // Flush encoder. 18141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org while (encode_frame(&codec, NULL, -1, writer)) {}; 182dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 18393a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org printf("\n"); 18493a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org fclose(infile); 18593a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org printf("Processed %d frames.\n", frame_count); 186dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 18793a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org vpx_img_free(&raw); 18893a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org if (vpx_codec_destroy(&codec)) 18993a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org die_codec(&codec, "Failed to destroy codec."); 190dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 19193a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org vpx_video_writer_close(writer); 192dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 19393a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org return EXIT_SUCCESS; 194dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org} 195