summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/decode_to_md5.c40
-rw-r--r--examples/decode_with_drops.c56
-rw-r--r--examples/postproc.c44
-rw-r--r--examples/simple_decoder.c44
-rw-r--r--examples/simple_encoder.c272
-rw-r--r--examples/twopass_encoder.c336
-rw-r--r--examples/vp8_set_maps.c4
-rw-r--r--examples/vpx_temporal_scalable_patterns.c551
8 files changed, 885 insertions, 462 deletions
diff --git a/examples/decode_to_md5.c b/examples/decode_to_md5.c
index bba218209..077513cc7 100644
--- a/examples/decode_to_md5.c
+++ b/examples/decode_to_md5.c
@@ -38,9 +38,9 @@
#include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h"
-#include "./ivfdec.h"
#include "./md5_utils.h"
#include "./tools_common.h"
+#include "./video_reader.h"
#include "./vpx_config.h"
static void get_image_md5(const vpx_image_t *img, unsigned char digest[16]) {
@@ -79,41 +79,42 @@ void usage_exit() {
}
int main(int argc, char **argv) {
- FILE *infile, *outfile;
+ int frame_cnt = 0;
+ FILE *outfile = NULL;
vpx_codec_ctx_t codec;
- vpx_codec_iface_t *iface;
- int flags = 0, frame_cnt = 0;
- vpx_video_t *video;
+ vpx_codec_iface_t *iface = NULL;
+ VpxVideoReader *reader = NULL;
+ const VpxVideoInfo *info = NULL;
exec_name = argv[0];
if (argc != 3)
- die("Invalid number of arguments");
+ die("Invalid number of arguments.");
- if (!(infile = fopen(argv[1], "rb")))
- die("Failed to open %s for reading", argv[1]);
+ reader = vpx_video_reader_open(argv[1]);
+ if (!reader)
+ die("Failed to open %s for reading.", argv[1]);
if (!(outfile = fopen(argv[2], "wb")))
- die("Failed to open %s for writing", argv[2]);
+ die("Failed to open %s for writing.", argv[2]);
- video = vpx_video_open_file(infile);
- if (!video)
- die("%s is not an IVF file.", argv[1]);
+ info = vpx_video_reader_get_info(reader);
- iface = get_codec_interface(vpx_video_get_fourcc(video));
+ iface = get_codec_interface(info->codec_fourcc);
if (!iface)
- die("Unknown FOURCC code.");
+ die("Unknown input codec.");
printf("Using %s\n", vpx_codec_iface_name(iface));
- if (vpx_codec_dec_init(&codec, iface, NULL, flags))
+ if (vpx_codec_dec_init(&codec, iface, NULL, 0))
die_codec(&codec, "Failed to initialize decoder");
- while (vpx_video_read_frame(video)) {
+ while (vpx_video_reader_read_frame(reader)) {
vpx_codec_iter_t iter = NULL;
vpx_image_t *img = NULL;
size_t frame_size = 0;
- const unsigned char *frame = vpx_video_get_frame(video, &frame_size);
+ const unsigned char *frame = vpx_video_reader_get_frame(reader,
+ &frame_size);
if (vpx_codec_decode(&codec, frame, frame_size, NULL, 0))
die_codec(&codec, "Failed to decode frame");
@@ -129,11 +130,10 @@ int main(int argc, char **argv) {
printf("Processed %d frames.\n", frame_cnt);
if (vpx_codec_destroy(&codec))
- die_codec(&codec, "Failed to destroy codec");
+ die_codec(&codec, "Failed to destroy codec.");
- vpx_video_close(video);
+ vpx_video_reader_close(reader);
fclose(outfile);
- fclose(infile);
return EXIT_SUCCESS;
}
diff --git a/examples/decode_with_drops.c b/examples/decode_with_drops.c
index 12686dedd..e8fc0766b 100644
--- a/examples/decode_with_drops.c
+++ b/examples/decode_with_drops.c
@@ -56,14 +56,13 @@
#include <stdlib.h>
#include <string.h>
-#include "./ivfdec.h"
-
#define VPX_CODEC_DISABLE_COMPAT 1
#include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h"
#include "./tools_common.h"
+#include "./video_reader.h"
#include "./vpx_config.h"
static const char *exec_name;
@@ -74,52 +73,55 @@ void usage_exit() {
}
int main(int argc, char **argv) {
- FILE *infile, *outfile;
+ int frame_cnt = 0;
+ FILE *outfile = NULL;
vpx_codec_ctx_t codec;
- vpx_codec_iface_t *iface;
- int flags = 0, frame_cnt = 0;
- vpx_video_t *video;
- int n, m, is_range;
- char *nptr;
+ vpx_codec_iface_t *iface = NULL;
+ VpxVideoReader *reader = NULL;
+ const VpxVideoInfo *info = NULL;
+ int n = 0;
+ int m = 0;
+ int is_range = 0;
+ char *nptr = NULL;
exec_name = argv[0];
if (argc != 4)
- die("Invalid number of arguments");
+ die("Invalid number of arguments.");
- if (!(infile = fopen(argv[1], "rb")))
- die("Failed to open %s for reading", argv[1]);
+ reader = vpx_video_reader_open(argv[1]);
+ if (!reader)
+ die("Failed to open %s for reading.", argv[1]);
if (!(outfile = fopen(argv[2], "wb")))
- die("Failed to open %s for writing", argv[2]);
+ die("Failed to open %s for writing.", argv[2]);
n = strtol(argv[3], &nptr, 0);
m = strtol(nptr + 1, NULL, 0);
is_range = (*nptr == '-');
if (!n || !m || (*nptr != '-' && *nptr != '/'))
- die("Couldn't parse pattern %s\n", argv[3]);
+ die("Couldn't parse pattern %s.\n", argv[3]);
- video = vpx_video_open_file(infile);
- if (!video)
- die("%s is not a supported input file.", argv[1]);
+ info = vpx_video_reader_get_info(reader);
- iface = get_codec_interface(vpx_video_get_fourcc(video));
+ iface = get_codec_interface(info->codec_fourcc);
if (!iface)
- die("Unknown FOURCC code.");
+ die("Unknown input codec.");
printf("Using %s\n", vpx_codec_iface_name(iface));
- if (vpx_codec_dec_init(&codec, iface, NULL, flags))
- die_codec(&codec, "Failed to initialize decoder");
+ if (vpx_codec_dec_init(&codec, iface, NULL, 0))
+ die_codec(&codec, "Failed to initialize decoder.");
- while (vpx_video_read_frame(video)) {
+ while (vpx_video_reader_read_frame(reader)) {
vpx_codec_iter_t iter = NULL;
vpx_image_t *img = NULL;
size_t frame_size = 0;
int skip;
- const unsigned char *frame = vpx_video_get_frame(video, &frame_size);
+ const unsigned char *frame = vpx_video_reader_get_frame(reader,
+ &frame_size);
if (vpx_codec_decode(&codec, frame, frame_size, NULL, 0))
- die_codec(&codec, "Failed to decode frame");
+ die_codec(&codec, "Failed to decode frame.");
++frame_cnt;
@@ -140,15 +142,13 @@ int main(int argc, char **argv) {
printf("Processed %d frames.\n", frame_cnt);
if (vpx_codec_destroy(&codec))
- die_codec(&codec, "Failed to destroy codec");
+ die_codec(&codec, "Failed to destroy codec.");
printf("Play: ffplay -f rawvideo -pix_fmt yuv420p -s %dx%d %s\n",
- vpx_video_get_width(video), vpx_video_get_height(video), argv[2]);
-
- vpx_video_close(video);
+ info->frame_width, info->frame_height, argv[2]);
+ vpx_video_reader_close(reader);
fclose(outfile);
- fclose(infile);
return EXIT_SUCCESS;
}
diff --git a/examples/postproc.c b/examples/postproc.c
index 4ec2d1f1c..7281f1e3d 100644
--- a/examples/postproc.c
+++ b/examples/postproc.c
@@ -43,14 +43,13 @@
#include <stdlib.h>
#include <string.h>
-#include "./ivfdec.h"
-
#define VPX_CODEC_DISABLE_COMPAT 1
#include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h"
#include "./tools_common.h"
+#include "./video_reader.h"
#include "./vpx_config.h"
static const char *exec_name;
@@ -61,35 +60,34 @@ void usage_exit() {
}
int main(int argc, char **argv) {
- FILE *infile, *outfile;
- vpx_codec_ctx_t codec;
- vpx_codec_iface_t *iface;
int frame_cnt = 0;
- vpx_video_t *video;
+ FILE *outfile = NULL;
+ vpx_codec_ctx_t codec;
vpx_codec_err_t res;
+ vpx_codec_iface_t *iface = NULL;
+ VpxVideoReader *reader = NULL;
+ const VpxVideoInfo *info = NULL;
exec_name = argv[0];
if (argc != 3)
- die("Invalid number of arguments");
+ die("Invalid number of arguments.");
- if (!(infile = fopen(argv[1], "rb")))
- die("Failed to open %s for reading", argv[1]);
+ reader = vpx_video_reader_open(argv[1]);
+ if (!reader)
+ die("Failed to open %s for reading.", argv[1]);
if (!(outfile = fopen(argv[2], "wb")))
die("Failed to open %s for writing", argv[2]);
- video = vpx_video_open_file(infile);
- if (!video)
- die("%s is not a supported input file.", argv[1]);
+ info = vpx_video_reader_get_info(reader);
- iface = get_codec_interface(vpx_video_get_fourcc(video));
+ iface = get_codec_interface(info->codec_fourcc);
if (!iface)
- die("Unknown FOURCC code.");
+ die("Unknown input codec.");
printf("Using %s\n", vpx_codec_iface_name(iface));
-
res = vpx_codec_dec_init(&codec, iface, NULL, VPX_CODEC_USE_POSTPROC);
if (res == VPX_CODEC_INCAPABLE) {
printf("NOTICE: Postproc not supported.\n");
@@ -97,13 +95,14 @@ int main(int argc, char **argv) {
}
if (res)
- die_codec(&codec, "Failed to initialize decoder");
+ die_codec(&codec, "Failed to initialize decoder.");
- while (vpx_video_read_frame(video)) {
+ while (vpx_video_reader_read_frame(reader)) {
vpx_codec_iter_t iter = NULL;
vpx_image_t *img = NULL;
size_t frame_size = 0;
- const unsigned char *frame = vpx_video_get_frame(video, &frame_size);
+ const unsigned char *frame = vpx_video_reader_get_frame(reader,
+ &frame_size);
++frame_cnt;
@@ -111,12 +110,12 @@ int main(int argc, char **argv) {
vp8_postproc_cfg_t pp = {0, 0, 0};
if (vpx_codec_control(&codec, VP8_SET_POSTPROC, &pp))
- die_codec(&codec, "Failed to turn off postproc");
+ die_codec(&codec, "Failed to turn off postproc.");
} else if (frame_cnt % 30 == 16) {
vp8_postproc_cfg_t pp = {VP8_DEBLOCK | VP8_DEMACROBLOCK | VP8_MFQE,
4, 0};
if (vpx_codec_control(&codec, VP8_SET_POSTPROC, &pp))
- die_codec(&codec, "Failed to turn on postproc");
+ die_codec(&codec, "Failed to turn on postproc.");
};
// Decode the frame with 15ms deadline
@@ -133,11 +132,10 @@ int main(int argc, char **argv) {
die_codec(&codec, "Failed to destroy codec");
printf("Play: ffplay -f rawvideo -pix_fmt yuv420p -s %dx%d %s\n",
- vpx_video_get_width(video), vpx_video_get_height(video), argv[2]);
+ info->frame_width, info->frame_height, argv[2]);
- vpx_video_close(video);
+ vpx_video_reader_close(reader);
fclose(outfile);
- fclose(infile);
return EXIT_SUCCESS;
}
diff --git a/examples/simple_decoder.c b/examples/simple_decoder.c
index 23399f44f..4dc930897 100644
--- a/examples/simple_decoder.c
+++ b/examples/simple_decoder.c
@@ -86,8 +86,8 @@
#include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h"
-#include "./ivfdec.h"
#include "./tools_common.h"
+#include "./video_reader.h"
#include "./vpx_config.h"
static const char *exec_name;
@@ -98,43 +98,44 @@ void usage_exit() {
}
int main(int argc, char **argv) {
- FILE *infile, *outfile;
+ int frame_cnt = 0;
+ FILE *outfile = NULL;
vpx_codec_ctx_t codec;
- vpx_codec_iface_t *iface;
- int flags = 0, frame_cnt = 0;
- vpx_video_t *video;
+ vpx_codec_iface_t *iface = NULL;
+ VpxVideoReader *reader = NULL;
+ const VpxVideoInfo *info = NULL;
exec_name = argv[0];
if (argc != 3)
- die("Invalid number of arguments");
+ die("Invalid number of arguments.");
- if (!(infile = fopen(argv[1], "rb")))
- die("Failed to open %s for reading", argv[1]);
+ reader = vpx_video_reader_open(argv[1]);
+ if (!reader)
+ die("Failed to open %s for reading.", argv[1]);
if (!(outfile = fopen(argv[2], "wb")))
- die("Failed to open %s for writing", argv[2]);
+ die("Failed to open %s for writing.", argv[2]);
- video = vpx_video_open_file(infile);
- if (!video)
- die("%s is not an IVF file.", argv[1]);
+ info = vpx_video_reader_get_info(reader);
- iface = get_codec_interface(vpx_video_get_fourcc(video));
+ iface = get_codec_interface(info->codec_fourcc);
if (!iface)
- die("Unknown FOURCC code.");
+ die("Unknown input codec.");
printf("Using %s\n", vpx_codec_iface_name(iface));
- if (vpx_codec_dec_init(&codec, iface, NULL, flags))
- die_codec(&codec, "Failed to initialize decoder");
+ if (vpx_codec_dec_init(&codec, iface, NULL, 0))
+ die_codec(&codec, "Failed to initialize decoder.");
- while (vpx_video_read_frame(video)) {
+ while (vpx_video_reader_read_frame(reader)) {
vpx_codec_iter_t iter = NULL;
vpx_image_t *img = NULL;
size_t frame_size = 0;
- const unsigned char *frame = vpx_video_get_frame(video, &frame_size);
+ const unsigned char *frame = vpx_video_reader_get_frame(reader,
+ &frame_size);
if (vpx_codec_decode(&codec, frame, frame_size, NULL, 0))
- die_codec(&codec, "Failed to decode frame");
+ die_codec(&codec, "Failed to decode frame.");
while ((img = vpx_codec_get_frame(&codec, &iter)) != NULL) {
vpx_img_write(img, outfile);
@@ -147,12 +148,11 @@ int main(int argc, char **argv) {
die_codec(&codec, "Failed to destroy codec");
printf("Play: ffplay -f rawvideo -pix_fmt yuv420p -s %dx%d %s\n",
- vpx_video_get_width(video), vpx_video_get_height(video), argv[2]);
+ info->frame_width, info->frame_height, argv[2]);
- vpx_video_close(video);
+ vpx_video_reader_close(reader);
fclose(outfile);
- fclose(infile);
return EXIT_SUCCESS;
}
diff --git a/examples/simple_encoder.c b/examples/simple_encoder.c
index e64a962ae..50760549a 100644
--- a/examples/simple_encoder.c
+++ b/examples/simple_encoder.c
@@ -83,194 +83,114 @@
#include <stdio.h>
#include <stdlib.h>
-#include <stdarg.h>
#include <string.h>
+
#define VPX_CODEC_DISABLE_COMPAT 1
-#include "vpx/vpx_encoder.h"
#include "vpx/vp8cx.h"
-#define interface (vpx_codec_vp8_cx())
-#define fourcc 0x30385056
-
-#define IVF_FILE_HDR_SZ (32)
-#define IVF_FRAME_HDR_SZ (12)
-
-static void mem_put_le16(char *mem, unsigned int val) {
- mem[0] = val;
- mem[1] = val>>8;
-}
-
-static void mem_put_le32(char *mem, unsigned int val) {
- mem[0] = val;
- mem[1] = val>>8;
- mem[2] = val>>16;
- mem[3] = val>>24;
-}
-
-static void die(const char *fmt, ...) {
- va_list ap;
-
- va_start(ap, fmt);
- vprintf(fmt, ap);
- if(fmt[strlen(fmt)-1] != '\n')
- printf("\n");
- exit(EXIT_FAILURE);
-}
-
-static void die_codec(vpx_codec_ctx_t *ctx, const char *s) {
- const char *detail = vpx_codec_error_detail(ctx);
-
- printf("%s: %s\n", s, vpx_codec_error(ctx));
- if(detail)
- printf(" %s\n",detail);
- exit(EXIT_FAILURE);
-}
-
-static int read_frame(FILE *f, vpx_image_t *img) {
- size_t nbytes, to_read;
- int res = 1;
-
- to_read = img->w*img->h*3/2;
- nbytes = fread(img->planes[0], 1, to_read, f);
- if(nbytes != to_read) {
- res = 0;
- if(nbytes > 0)
- printf("Warning: Read partial frame. Check your width & height!\n");
- }
- return res;
-}
-
-static void write_ivf_file_header(FILE *outfile,
- const vpx_codec_enc_cfg_t *cfg,
- int frame_cnt) {
- char header[32];
-
- if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS)
- return;
- header[0] = 'D';
- header[1] = 'K';
- header[2] = 'I';
- header[3] = 'F';
- mem_put_le16(header+4, 0); /* version */
- mem_put_le16(header+6, 32); /* headersize */
- mem_put_le32(header+8, fourcc); /* headersize */
- mem_put_le16(header+12, cfg->g_w); /* width */
- mem_put_le16(header+14, cfg->g_h); /* height */
- mem_put_le32(header+16, cfg->g_timebase.den); /* rate */
- mem_put_le32(header+20, cfg->g_timebase.num); /* scale */
- mem_put_le32(header+24, frame_cnt); /* length */
- mem_put_le32(header+28, 0); /* unused */
-
- (void) fwrite(header, 1, 32, outfile);
-}
-
+#include "vpx/vpx_encoder.h"
-static void write_ivf_frame_header(FILE *outfile,
- const vpx_codec_cx_pkt_t *pkt)
-{
- char header[12];
- vpx_codec_pts_t pts;
+#include "./tools_common.h"
+#include "./video_writer.h"
- if(pkt->kind != VPX_CODEC_CX_FRAME_PKT)
- return;
+#define interface (vpx_codec_vp8_cx())
- pts = pkt->data.frame.pts;
- mem_put_le32(header, pkt->data.frame.sz);
- mem_put_le32(header+4, pts&0xFFFFFFFF);
- mem_put_le32(header+8, pts >> 32);
+static const char *exec_name;
- (void) fwrite(header, 1, 12, outfile);
+void usage_exit() {
+ fprintf(stderr, "Usage: %s <width> <height> <infile> <outfile>\n", exec_name);
+ exit(EXIT_FAILURE);
}
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;
+ 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};
+ VpxVideoWriter *writer = NULL;
+ const int fps = 30; // TODO(dkovalev) add command line argument
+ const int bitrate = 200; // kbit/s TODO(dkovalev) add command line argument
+
+ exec_name = argv[0];
+
+ if (argc != 5)
+ die("Invalid number of arguments");
+
+ info.codec_fourcc = VP8_FOURCC;
+ info.frame_width = strtol(argv[1], NULL, 0);
+ info.frame_height = 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(interface));
+
+ res = vpx_codec_enc_config_default(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, interface, &cfg, 0))
+ die_codec(&codec, "Failed to initialize encoder");
+
+ while (vpx_img_read(&raw, infile)) {
+ vpx_codec_iter_t iter = NULL;
+ const vpx_codec_cx_pkt_t *pkt = NULL;
+
+ ++frame_count;
+
+ res = vpx_codec_encode(&codec, &raw, frame_count, 1, 0,
+ VPX_DL_GOOD_QUALITY);
+ if (res != VPX_CODEC_OK)
+ die_codec(&codec, "Failed to encode frame");
+
+ while ((pkt = vpx_codec_get_cx_data(&codec, &iter)) != NULL) {
+ if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
+ const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
+ if (!vpx_video_writer_write_frame(writer,
+ pkt->data.frame.buf,
+ pkt->data.frame.sz,
+ pkt->data.frame.pts))
+ die_codec(&codec, "Failed to write compressed frame.");
+ printf(keyframe ? "K" : ".");
+ fflush(stdout);
+ }
}
+ }
+ printf("\n");
+ fclose(infile);
+ printf("Processed %d frames.\n", frame_count);
- /* 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);
- (void) 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);
+ vpx_img_free(&raw);
+ if (vpx_codec_destroy(&codec))
+ die_codec(&codec, "Failed to destroy codec.");
- printf("Processed %d frames.\n",frame_cnt-1);
- vpx_img_free(&raw);
- if(vpx_codec_destroy(&codec))
- die_codec(&codec, "Failed to destroy codec");
+ vpx_video_writer_close(writer);
- /* 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;
+ return EXIT_SUCCESS;
}
diff --git a/examples/twopass_encoder.c b/examples/twopass_encoder.c
index b0f0426c6..93b6150a5 100644
--- a/examples/twopass_encoder.c
+++ b/examples/twopass_encoder.c
@@ -50,218 +50,172 @@
#include <stdio.h>
#include <stdlib.h>
-#include <stdarg.h>
#include <string.h>
+
#define VPX_CODEC_DISABLE_COMPAT 1
-#include "vpx/vpx_encoder.h"
#include "vpx/vp8cx.h"
-#define interface (vpx_codec_vp8_cx())
-#define fourcc 0x30385056
-
-#define IVF_FILE_HDR_SZ (32)
-#define IVF_FRAME_HDR_SZ (12)
-
-static void mem_put_le16(char *mem, unsigned int val) {
- mem[0] = val;
- mem[1] = val>>8;
-}
-
-static void mem_put_le32(char *mem, unsigned int val) {
- mem[0] = val;
- mem[1] = val>>8;
- mem[2] = val>>16;
- mem[3] = val>>24;
-}
+#include "vpx/vpx_encoder.h"
-static void die(const char *fmt, ...) {
- va_list ap;
+#include "./tools_common.h"
+#include "./video_writer.h"
- va_start(ap, fmt);
- vprintf(fmt, ap);
- if(fmt[strlen(fmt)-1] != '\n')
- printf("\n");
- exit(EXIT_FAILURE);
-}
+#define interface (vpx_codec_vp8_cx())
-static void die_codec(vpx_codec_ctx_t *ctx, const char *s) {
- const char *detail = vpx_codec_error_detail(ctx);
+static const char *exec_name;
- printf("%s: %s\n", s, vpx_codec_error(ctx));
- if(detail)
- printf(" %s\n",detail);
- exit(EXIT_FAILURE);
+void usage_exit() {
+ fprintf(stderr, "Usage: %s <width> <height> <infile> <outfile>\n", exec_name);
+ exit(EXIT_FAILURE);
}
-static int read_frame(FILE *f, vpx_image_t *img) {
- size_t nbytes, to_read;
- int res = 1;
-
- to_read = img->w*img->h*3/2;
- nbytes = fread(img->planes[0], 1, to_read, f);
- if(nbytes != to_read) {
- res = 0;
- if(nbytes > 0)
- printf("Warning: Read partial frame. Check your width & height!\n");
+static void get_frame_stats(vpx_codec_ctx_t *ctx,
+ const vpx_image_t *img,
+ vpx_codec_pts_t pts,
+ uint64_t duration,
+ vpx_enc_frame_flags_t flags,
+ uint64_t deadline,
+ vpx_fixed_buf_t *stats) {
+ vpx_codec_iter_t iter = NULL;
+ const vpx_codec_cx_pkt_t *pkt = NULL;
+ const vpx_codec_err_t res = vpx_codec_encode(ctx, img, pts, duration, flags,
+ deadline);
+ if (res != VPX_CODEC_OK)
+ die_codec(ctx, "Failed to get frame stats.");
+
+ while ((pkt = vpx_codec_get_cx_data(ctx, &iter)) != NULL) {
+ if (pkt->kind == VPX_CODEC_STATS_PKT) {
+ const uint8_t *const pkt_buf = pkt->data.twopass_stats.buf;
+ const size_t pkt_size = pkt->data.twopass_stats.sz;
+ stats->buf = realloc(stats->buf, stats->sz + pkt_size);
+ memcpy((uint8_t *)stats->buf + stats->sz, pkt_buf, pkt_size);
+ stats->sz += pkt_size;
}
- return res;
+ }
}
-static void write_ivf_file_header(FILE *outfile,
- const vpx_codec_enc_cfg_t *cfg,
- int frame_cnt) {
- char header[32];
-
- if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS)
- return;
- header[0] = 'D';
- header[1] = 'K';
- header[2] = 'I';
- header[3] = 'F';
- mem_put_le16(header+4, 0); /* version */
- mem_put_le16(header+6, 32); /* headersize */
- mem_put_le32(header+8, fourcc); /* headersize */
- mem_put_le16(header+12, cfg->g_w); /* width */
- mem_put_le16(header+14, cfg->g_h); /* height */
- mem_put_le32(header+16, cfg->g_timebase.den); /* rate */
- mem_put_le32(header+20, cfg->g_timebase.num); /* scale */
- mem_put_le32(header+24, frame_cnt); /* length */
- mem_put_le32(header+28, 0); /* unused */
-
- (void) fwrite(header, 1, 32, outfile);
+static void encode_frame(vpx_codec_ctx_t *ctx,
+ const vpx_image_t *img,
+ vpx_codec_pts_t pts,
+ uint64_t duration,
+ vpx_enc_frame_flags_t flags,
+ uint64_t deadline,
+ VpxVideoWriter *writer) {
+ vpx_codec_iter_t iter = NULL;
+ const vpx_codec_cx_pkt_t *pkt = NULL;
+ const vpx_codec_err_t res = vpx_codec_encode(ctx, img, pts, duration, flags,
+ deadline);
+ if (res != VPX_CODEC_OK)
+ die_codec(ctx, "Failed to encode frame.");
+
+ while ((pkt = vpx_codec_get_cx_data(ctx, &iter)) != NULL) {
+ if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
+ const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
+
+ if (!vpx_video_writer_write_frame(writer, pkt->data.frame.buf,
+ pkt->data.frame.sz,
+ pkt->data.frame.pts))
+ die_codec(ctx, "Failed to write compressed frame.");
+ printf(keyframe ? "K" : ".");
+ fflush(stdout);
+ }
+ }
}
+int main(int argc, char **argv) {
+ FILE *infile = NULL;
+ VpxVideoWriter *writer = NULL;
+ 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 = {0};
+ VpxVideoInfo info = {0};
+ int pass;
+ const int fps = 30; // TODO(dkovalev) add command line argument
+ const int bitrate = 200; // kbit/s TODO(dkovalev) add command line argument
+
+ if (argc != 5)
+ die("Invalid number of arguments.");
+
+ info.codec_fourcc = VP8_FOURCC;
+ info.time_base.numerator = 1;
+ info.time_base.denominator = fps;
+ info.frame_width = strtol(argv[1], NULL, 0);
+ info.frame_height = strtol(argv[2], NULL, 0);
+
+ 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", info.frame_width, info.frame_height);
+ }
+
+ writer = vpx_video_writer_open(argv[4], kContainerIVF, &info);
+ if (!writer)
+ die("Failed to open %s for writing", argv[4]);
+
+ printf("Using %s\n", vpx_codec_iface_name(interface));
+
+ res = vpx_codec_enc_config_default(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;
+
+ for (pass = 0; pass < 2; ++pass) {
+ int frame_count = 0;
+
+ if (pass == 0) {
+ cfg.g_pass = VPX_RC_FIRST_PASS;
+ } else {
+ cfg.g_pass = VPX_RC_LAST_PASS;
+ cfg.rc_twopass_stats_in = stats;
+ }
-static void write_ivf_frame_header(FILE *outfile,
- const vpx_codec_cx_pkt_t *pkt)
-{
- char header[12];
- vpx_codec_pts_t pts;
-
- if(pkt->kind != VPX_CODEC_CX_FRAME_PKT)
- return;
+ if (!(infile = fopen(argv[3], "rb")))
+ die("Failed to open %s for reading", argv[3]);
- pts = pkt->data.frame.pts;
- mem_put_le32(header, pkt->data.frame.sz);
- mem_put_le32(header+4, pts&0xFFFFFFFF);
- mem_put_le32(header+8, pts >> 32);
+ if (vpx_codec_enc_init(&codec, interface, &cfg, 0))
+ die_codec(&codec, "Failed to initialize encoder");
- (void) fwrite(header, 1, 12, outfile);
-}
+ while (vpx_img_read(&raw, infile)) {
+ ++frame_count;
-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;
- int pass;
- vpx_fixed_buf_t stats = {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;
+ if (pass == 0) {
+ get_frame_stats(&codec, &raw, frame_count, 1, 0, VPX_DL_BEST_QUALITY,
+ &stats);
+ } else {
+ encode_frame(&codec, &raw, frame_count, 1, 0, VPX_DL_BEST_QUALITY,
+ writer);
+ }
}
- /* 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);
-
- for(pass=0; pass<2; pass++) {
- frame_cnt = 0;
-
- if(pass == 0)
- cfg.g_pass = VPX_RC_FIRST_PASS;
- else {
- cfg.g_pass = VPX_RC_LAST_PASS;
- cfg.rc_twopass_stats_in = stats;
- }
-
- /* 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_BEST_QUALITY))
- 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);
- (void) fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz,
- outfile);
- break;
- case VPX_CODEC_STATS_PKT:
- stats.buf = realloc(stats.buf, stats.sz
- + pkt->data.twopass_stats.sz);
- if(!stats.buf)
- die("Memory reallocation failed.\n");
- memcpy((char*)stats.buf + stats.sz,
- pkt->data.twopass_stats.buf,
- pkt->data.twopass_stats.sz);
- stats.sz += pkt->data.twopass_stats.sz;
- 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("Pass %d complete.\n", pass+1);
- if(vpx_codec_destroy(&codec))
- die_codec(&codec, "Failed to destroy codec");
+ if (pass == 0) {
+ get_frame_stats(&codec, NULL, frame_count, 1, 0, VPX_DL_BEST_QUALITY,
+ &stats);
+ } else {
+ printf("\n");
}
- printf("Processed %d frames.\n",frame_cnt-1);
- vpx_img_free(&raw);
- free(stats.buf);
+ fclose(infile);
+ printf("Pass %d complete. Processed %d frames.\n", pass + 1, frame_count);
+ if (vpx_codec_destroy(&codec))
+ die_codec(&codec, "Failed to destroy codec.");
+ }
+
+ vpx_img_free(&raw);
+ free(stats.buf);
+
+ vpx_video_writer_close(writer);
- /* 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;
+ return EXIT_SUCCESS;
}
diff --git a/examples/vp8_set_maps.c b/examples/vp8_set_maps.c
index 242788fd4..4c0e8a0ba 100644
--- a/examples/vp8_set_maps.c
+++ b/examples/vp8_set_maps.c
@@ -201,7 +201,7 @@ int main(int argc, char **argv) {
if(frame_cnt + 1 == 22) {
vpx_roi_map_t roi;
- int i;
+ unsigned int i;
roi.rows = cfg.g_h/16;
roi.cols = cfg.g_w/16;
@@ -232,7 +232,7 @@ int main(int argc, char **argv) {
free(roi.roi_map);
} else if(frame_cnt + 1 == 33) {
vpx_active_map_t active;
- int i;
+ unsigned int i;
active.rows = cfg.g_h/16;
active.cols = cfg.g_w/16;
diff --git a/examples/vpx_temporal_scalable_patterns.c b/examples/vpx_temporal_scalable_patterns.c
new file mode 100644
index 000000000..11d331bd8
--- /dev/null
+++ b/examples/vpx_temporal_scalable_patterns.c
@@ -0,0 +1,551 @@
+/*
+ * Copyright (c) 2012 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+// This is an example demonstrating how to implement a multi-layer VP9
+// encoding scheme based on temporal scalability for video applications
+// that benefit from a scalable bitstream.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define VPX_CODEC_DISABLE_COMPAT 1
+#include "vpx/vp8cx.h"
+#include "vpx/vpx_encoder.h"
+
+#include "./tools_common.h"
+#include "./video_writer.h"
+
+static const char *exec_name;
+
+void usage_exit() {
+ exit(EXIT_FAILURE);
+}
+
+static int mode_to_num_layers[12] = {1, 2, 2, 3, 3, 3, 3, 5, 2, 3, 3, 3};
+
+// 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.
+static void set_temporal_layer_pattern(int layering_mode,
+ vpx_codec_enc_cfg_t *cfg,
+ int *layer_flags,
+ int *flag_periodicity) {
+ switch (layering_mode) {
+ case 0: {
+ // 1-layer.
+ int ids[1] = {0};
+ cfg->ts_periodicity = 1;
+ *flag_periodicity = 1;
+ cfg->ts_number_layers = 1;
+ cfg->ts_rate_decimator[0] = 1;
+ memcpy(cfg->ts_layer_id, ids, sizeof(ids));
+ // Update L only.
+ layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF |
+ VP8_EFLAG_NO_UPD_ARF;
+ break;
+ }
+ case 1: {
+ // 2-layers, 2-frame period.
+ int ids[2] = {0, 1};
+ cfg->ts_periodicity = 2;
+ *flag_periodicity = 2;
+ cfg->ts_number_layers = 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 2: {
+ // 2-layers, 3-frame period.
+ int ids[3] = {0, 1, 1};
+ cfg->ts_periodicity = 3;
+ *flag_periodicity = 3;
+ cfg->ts_number_layers = 2;
+ 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 3: {
+ // 3-layers, 6-frame period.
+ int ids[6] = {0, 2, 2, 1, 2, 2};
+ cfg->ts_periodicity = 6;
+ *flag_periodicity = 6;
+ cfg->ts_number_layers = 3;
+ 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 4: {
+ // 3-layers, 4-frame period.
+ int ids[4] = {0, 2, 1, 2};
+ cfg->ts_periodicity = 4;
+ *flag_periodicity = 4;
+ cfg->ts_number_layers = 3;
+ 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 5: {
+ // 3-layers, 4-frame period.
+ int ids[4] = {0, 2, 1, 2};
+ cfg->ts_periodicity = 4;
+ *flag_periodicity = 4;
+ cfg->ts_number_layers = 3;
+ 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 6: {
+ // 3-layers, 4-frame period.
+ int ids[4] = {0, 2, 1, 2};
+ cfg->ts_periodicity = 4;
+ *flag_periodicity = 4;
+ cfg->ts_number_layers = 3;
+ 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 7: {
+ // 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_periodicity = 16;
+ *flag_periodicity = 16;
+ cfg->ts_number_layers = 5;
+ 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;
+ layer_flags[2] =
+ layer_flags[6] =
+ layer_flags[10] =
+ layer_flags[14] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_GF;
+ layer_flags[4] =
+ layer_flags[12] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_UPD_ARF;
+ layer_flags[8] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_GF;
+ break;
+ }
+ case 8: {
+ // 2-layers, with sync point at first frame of layer 1.
+ int ids[2] = {0, 1};
+ cfg->ts_periodicity = 2;
+ *flag_periodicity = 8;
+ cfg->ts_number_layers = 2;
+ cfg->ts_rate_decimator[0] = 2;
+ cfg->ts_rate_decimator[1] = 1;
+ memcpy(cfg->ts_layer_id, ids, sizeof(ids));
+ // 0=L, 1=GF.
+ // ARF is used as predictor for all frames, and is only updated on
+ // key frame. Sync point every 8 frames.
+
+ // Layer 0: predict from L and ARF, update L and G.
+ layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF |
+ VP8_EFLAG_NO_UPD_ARF;
+ // Layer 1: sync point: predict from L and ARF, and update G.
+ layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_UPD_ARF;
+ // Layer 0, predict from L and ARF, update L.
+ layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF |
+ VP8_EFLAG_NO_UPD_ARF;
+ // Layer 1: predict from L, G and ARF, and update G.
+ layer_flags[3] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_UPD_ENTROPY;
+ // Layer 0.
+ layer_flags[4] = layer_flags[2];
+ // Layer 1.
+ layer_flags[5] = layer_flags[3];
+ // Layer 0.
+ layer_flags[6] = layer_flags[4];
+ // Layer 1.
+ layer_flags[7] = layer_flags[5];
+ break;
+ }
+ case 9: {
+ // 3-layers: Sync points for layer 1 and 2 every 8 frames.
+ int ids[4] = {0, 2, 1, 2};
+ cfg->ts_periodicity = 4;
+ *flag_periodicity = 8;
+ cfg->ts_number_layers = 3;
+ 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.
+ 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] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
+ VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
+ layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
+ VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
+ layer_flags[3] =
+ layer_flags[5] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
+ layer_flags[4] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
+ VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
+ layer_flags[6] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_UPD_ARF;
+ layer_flags[7] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
+ VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_ENTROPY;
+ break;
+ }
+ case 10: {
+ // 3-layers structure where ARF is used as predictor for all frames,
+ // and is only updated on key frame.
+ // Sync points for layer 1 and 2 every 8 frames.
+
+ int ids[4] = {0, 2, 1, 2};
+ cfg->ts_periodicity = 4;
+ *flag_periodicity = 8;
+ cfg->ts_number_layers = 3;
+ 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.
+ // Layer 0: predict from L and ARF; update L and G.
+ layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_ARF |
+ VP8_EFLAG_NO_REF_GF;
+ // Layer 2: sync point: predict from L and ARF; update none.
+ layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF |
+ VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_UPD_ENTROPY;
+ // Layer 1: sync point: predict from L and ARF; update G.
+ layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF |
+ VP8_EFLAG_NO_UPD_LAST;
+ // Layer 2: predict from L, G, ARF; update none.
+ layer_flags[3] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
+ VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ENTROPY;
+ // Layer 0: predict from L and ARF; update L.
+ layer_flags[4] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
+ VP8_EFLAG_NO_REF_GF;
+ // Layer 2: predict from L, G, ARF; update none.
+ layer_flags[5] = layer_flags[3];
+ // Layer 1: predict from L, G, ARF; update G.
+ layer_flags[6] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
+ // Layer 2: predict from L, G, ARF; update none.
+ layer_flags[7] = layer_flags[3];
+ break;
+ }
+ case 11:
+ default: {
+ // 3-layers structure as in case 10, but no sync/refresh points for
+ // layer 1 and 2.
+ int ids[4] = {0, 2, 1, 2};
+ cfg->ts_periodicity = 4;
+ *flag_periodicity = 8;
+ cfg->ts_number_layers = 3;
+ 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.
+ // Layer 0: predict from L and ARF; update L.
+ layer_flags[0] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
+ VP8_EFLAG_NO_REF_GF;
+ layer_flags[4] = layer_flags[0];
+ // Layer 1: predict from L, G, ARF; update G.
+ layer_flags[2] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
+ layer_flags[6] = layer_flags[2];
+ // Layer 2: predict from L, G, ARF; update none.
+ layer_flags[1] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
+ VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ENTROPY;
+ layer_flags[3] = layer_flags[1];
+ layer_flags[5] = layer_flags[1];
+ layer_flags[7] = layer_flags[1];
+ break;
+ }
+ }
+}
+
+int main(int argc, char **argv) {
+ VpxVideoWriter *outfile[VPX_TS_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[VPX_TS_MAX_LAYERS] = {0};
+ int layer_flags[VPX_TS_MAX_PERIODICITY] = {0};
+ int flag_periodicity = 1;
+ int max_intra_size_pct;
+ vpx_svc_layer_id_t layer_id = {0, 0};
+ char *codec_type;
+ vpx_codec_iface_t *(*interface)(void);
+ unsigned int fourcc;
+ struct VpxInputContext input_ctx = {0};
+
+ exec_name = argv[0];
+ // Check usage and arguments.
+ if (argc < 10) {
+ die("Usage: %s <infile> <outfile> <codec_type(vp8/vp9)> <width> <height> "
+ "<rate_num> <rate_den> <mode> <Rate_0> ... <Rate_nlayers-1> \n",
+ argv[0]);
+ }
+
+ codec_type = argv[3];
+ if (strncmp(codec_type, "vp9", 3) == 0) {
+#if CONFIG_VP9_ENCODER
+ interface = vpx_codec_vp9_cx;
+ fourcc = VP9_FOURCC;
+#else
+ die("Encoder vp9 selected but not configured");
+#endif
+ } else {
+#if CONFIG_VP8_ENCODER
+ interface = vpx_codec_vp8_cx;
+ fourcc = VP8_FOURCC;
+#else
+ die("Encoder vp8 selected but not configured");
+#endif
+ }
+ printf("Using %s\n", vpx_codec_iface_name(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[8], NULL, 0);
+ if (layering_mode < 0 || layering_mode > 11) {
+ die("Invalid mode (0..11) %s", argv[8]);
+ }
+
+ if (argc != 9 + mode_to_num_layers[layering_mode]) {
+ die("Invalid number of arguments");
+ }
+
+ if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 32)) {
+ die("Failed to allocate image", width, height);
+ }
+
+ // 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.
+ cfg.g_timebase.num = strtol(argv[6], NULL, 0);
+ cfg.g_timebase.den = strtol(argv[7], NULL, 0);
+
+ for (i = 9; i < 9 + mode_to_num_layers[layering_mode]; ++i) {
+ cfg.ts_target_bitrate[i - 9] = strtol(argv[i], NULL, 0);
+ }
+
+ // Real time parameters.
+ cfg.rc_dropframe_thresh = 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 = 100;
+ cfg.rc_overshoot_pct = 15;
+ 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 = 3000;
+
+ // Default setting for bitrate: used in special case of 1 layer (case 0).
+ cfg.rc_target_bitrate = cfg.ts_target_bitrate[0];
+
+ set_temporal_layer_pattern(layering_mode,
+ &cfg,
+ layer_flags,
+ &flag_periodicity);
+
+ // Open input file.
+ input_ctx.filename = argv[1];
+ if (!(input_ctx.file = fopen(input_ctx.filename, "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[PATH_MAX];
+ VpxVideoInfo info;
+ info.codec_fourcc = 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);
+ }
+ // No spatial layers in this encoder.
+ cfg.ss_number_layers = 1;
+
+ // Initialize codec.
+ if (vpx_codec_enc_init(&codec, interface(), &cfg, 0))
+ die_codec(&codec, "Failed to initialize encoder");
+
+ vpx_codec_control(&codec, VP8E_SET_CPUUSED, -6);
+ vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, 1);
+ if (strncmp(codec_type, "vp9", 3) == 0) {
+ vpx_codec_control(&codec, VP8E_SET_CPUUSED, 3);
+ vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, 0);
+ if (vpx_codec_control(&codec, VP9E_SET_SVC, 1)) {
+ 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);
+ max_intra_size_pct = (int) (((double)cfg.rc_buf_optimal_sz * 0.5)
+ * ((double) cfg.g_timebase.den / cfg.g_timebase.num) / 10.0);
+ vpx_codec_control(&codec, VP8E_SET_MAX_INTRA_BITRATE_PCT, max_intra_size_pct);
+
+ frame_avail = 1;
+ while (frame_avail || got_data) {
+ 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];
+ vpx_codec_control(&codec, VP9E_SET_SVC_LAYER_ID, &layer_id);
+ flags = layer_flags[frame_cnt % flag_periodicity];
+ frame_avail = !read_yuv_frame(&input_ctx, &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.
+ 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);
+ ++frames_in_layer[i];
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ ++frame_cnt;
+ pts += frame_duration;
+ }
+ fclose(input_ctx.file);
+ 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)
+ vpx_video_writer_close(outfile[i]);
+
+ return EXIT_SUCCESS;
+}