Merge "[svc] 1. Add two pass RC options in vp9_spatial_scalable_encoder. 2. Add read/write for RC stats file The two pass RC for svc does not work yet. This is just the first step. We need further development to make it working. Change-Id: I8ef0e177dff0b5ed3c97a916beea5123717cc6f2"
This commit is contained in:
commit
2740507142
@ -62,6 +62,7 @@ vp9_spatial_scalable_encoder.SRCS += ivfenc.c ivfenc.h
|
|||||||
vp9_spatial_scalable_encoder.SRCS += tools_common.c tools_common.h
|
vp9_spatial_scalable_encoder.SRCS += tools_common.c tools_common.h
|
||||||
vp9_spatial_scalable_encoder.SRCS += video_common.h
|
vp9_spatial_scalable_encoder.SRCS += video_common.h
|
||||||
vp9_spatial_scalable_encoder.SRCS += video_writer.h video_writer.c
|
vp9_spatial_scalable_encoder.SRCS += video_writer.h video_writer.c
|
||||||
|
vp9_spatial_scalable_encoder.SRCS += vpxstats.c vpxstats.h
|
||||||
vp9_spatial_scalable_encoder.GUID = 4A38598D-627D-4505-9C7B-D4020C84100D
|
vp9_spatial_scalable_encoder.GUID = 4A38598D-627D-4505-9C7B-D4020C84100D
|
||||||
vp9_spatial_scalable_encoder.DESCRIPTION = Spatial Scalable Encoder
|
vp9_spatial_scalable_encoder.DESCRIPTION = Spatial Scalable Encoder
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "vpx/svc_context.h"
|
#include "vpx/svc_context.h"
|
||||||
#include "vpx/vp8cx.h"
|
#include "vpx/vp8cx.h"
|
||||||
#include "vpx/vpx_encoder.h"
|
#include "vpx/vpx_encoder.h"
|
||||||
|
#include "./vpxstats.h"
|
||||||
|
|
||||||
static const struct arg_enum_list encoding_mode_enum[] = {
|
static const struct arg_enum_list encoding_mode_enum[] = {
|
||||||
{"i", INTER_LAYER_PREDICTION_I},
|
{"i", INTER_LAYER_PREDICTION_I},
|
||||||
@ -60,12 +61,19 @@ static const arg_def_t quantizers_arg =
|
|||||||
static const arg_def_t quantizers_keyframe_arg =
|
static const arg_def_t quantizers_keyframe_arg =
|
||||||
ARG_DEF("qn", "quantizers-keyframe", 1, "quantizers for key frames (lowest "
|
ARG_DEF("qn", "quantizers-keyframe", 1, "quantizers for key frames (lowest "
|
||||||
"to highest layer)");
|
"to highest layer)");
|
||||||
|
static const arg_def_t passes_arg =
|
||||||
|
ARG_DEF("p", "passes", 1, "Number of passes (1/2)");
|
||||||
|
static const arg_def_t pass_arg =
|
||||||
|
ARG_DEF(NULL, "pass", 1, "Pass to execute (1/2)");
|
||||||
|
static const arg_def_t fpf_name_arg =
|
||||||
|
ARG_DEF(NULL, "fpf", 1, "First pass statistics file name");
|
||||||
|
|
||||||
static const arg_def_t *svc_args[] = {
|
static const arg_def_t *svc_args[] = {
|
||||||
&encoding_mode_arg, &frames_arg, &width_arg, &height_arg,
|
&encoding_mode_arg, &frames_arg, &width_arg, &height_arg,
|
||||||
&timebase_arg, &bitrate_arg, &skip_frames_arg, &layers_arg,
|
&timebase_arg, &bitrate_arg, &skip_frames_arg, &layers_arg,
|
||||||
&kf_dist_arg, &scale_factors_arg, &quantizers_arg,
|
&kf_dist_arg, &scale_factors_arg, &quantizers_arg,
|
||||||
&quantizers_keyframe_arg, NULL
|
&quantizers_keyframe_arg, &passes_arg, &pass_arg,
|
||||||
|
&fpf_name_arg, NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static const SVC_ENCODING_MODE default_encoding_mode =
|
static const SVC_ENCODING_MODE default_encoding_mode =
|
||||||
@ -85,6 +93,10 @@ typedef struct {
|
|||||||
const char *output_filename;
|
const char *output_filename;
|
||||||
uint32_t frames_to_code;
|
uint32_t frames_to_code;
|
||||||
uint32_t frames_to_skip;
|
uint32_t frames_to_skip;
|
||||||
|
struct VpxInputContext input_ctx;
|
||||||
|
stats_io_t rc_stats;
|
||||||
|
int passes;
|
||||||
|
int pass;
|
||||||
} AppInput;
|
} AppInput;
|
||||||
|
|
||||||
static const char *exec_name;
|
static const char *exec_name;
|
||||||
@ -105,6 +117,9 @@ static void parse_command_line(int argc, const char **argv_,
|
|||||||
char **argi = NULL;
|
char **argi = NULL;
|
||||||
char **argj = NULL;
|
char **argj = NULL;
|
||||||
vpx_codec_err_t res;
|
vpx_codec_err_t res;
|
||||||
|
int passes = 0;
|
||||||
|
int pass = 0;
|
||||||
|
const char *fpf_file_name = NULL;
|
||||||
|
|
||||||
// initialize SvcContext with parameters that will be passed to vpx_svc_init
|
// initialize SvcContext with parameters that will be passed to vpx_svc_init
|
||||||
svc_ctx->log_level = SVC_LOG_DEBUG;
|
svc_ctx->log_level = SVC_LOG_DEBUG;
|
||||||
@ -159,11 +174,53 @@ static void parse_command_line(int argc, const char **argv_,
|
|||||||
vpx_svc_set_quantizers(svc_ctx, arg.val, 0);
|
vpx_svc_set_quantizers(svc_ctx, arg.val, 0);
|
||||||
} else if (arg_match(&arg, &quantizers_keyframe_arg, argi)) {
|
} else if (arg_match(&arg, &quantizers_keyframe_arg, argi)) {
|
||||||
vpx_svc_set_quantizers(svc_ctx, arg.val, 1);
|
vpx_svc_set_quantizers(svc_ctx, arg.val, 1);
|
||||||
|
} else if (arg_match(&arg, &passes_arg, argi)) {
|
||||||
|
passes = arg_parse_uint(&arg);
|
||||||
|
if (passes < 1 || passes > 2) {
|
||||||
|
die("Error: Invalid number of passes (%d)\n", passes);
|
||||||
|
}
|
||||||
|
} else if (arg_match(&arg, &pass_arg, argi)) {
|
||||||
|
pass = arg_parse_uint(&arg);
|
||||||
|
if (pass < 1 || pass > 2) {
|
||||||
|
die("Error: Invalid pass selected (%d)\n", pass);
|
||||||
|
}
|
||||||
|
} else if (arg_match(&arg, &fpf_name_arg, argi)) {
|
||||||
|
fpf_file_name = arg.val;
|
||||||
} else {
|
} else {
|
||||||
++argj;
|
++argj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (passes == 0 || passes == 1) {
|
||||||
|
if (pass) {
|
||||||
|
fprintf(stderr, "pass is ignored since there's only one pass\n");
|
||||||
|
}
|
||||||
|
enc_cfg->g_pass = VPX_RC_ONE_PASS;
|
||||||
|
} else {
|
||||||
|
if (pass == 0) {
|
||||||
|
die("pass must be specified when passes is 2\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fpf_file_name == NULL) {
|
||||||
|
die("fpf must be specified when passes is 2\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pass == 1) {
|
||||||
|
enc_cfg->g_pass = VPX_RC_FIRST_PASS;
|
||||||
|
if (!stats_open_file(&app_input->rc_stats, fpf_file_name, 0)) {
|
||||||
|
fatal("Failed to open statistics store");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
enc_cfg->g_pass = VPX_RC_LAST_PASS;
|
||||||
|
if (!stats_open_file(&app_input->rc_stats, fpf_file_name, 1)) {
|
||||||
|
fatal("Failed to open statistics store");
|
||||||
|
}
|
||||||
|
enc_cfg->rc_twopass_stats_in = stats_get(&app_input->rc_stats);
|
||||||
|
}
|
||||||
|
app_input->passes = passes;
|
||||||
|
app_input->pass = pass;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for unrecognized options
|
// Check for unrecognized options
|
||||||
for (argi = argv; *argi; ++argi)
|
for (argi = argv; *argi; ++argi)
|
||||||
if (argi[0][0] == '-' && strlen(argi[0]) > 1)
|
if (argi[0][0] == '-' && strlen(argi[0]) > 1)
|
||||||
@ -234,10 +291,14 @@ int main(int argc, const char **argv) {
|
|||||||
VPX_CODEC_OK) {
|
VPX_CODEC_OK) {
|
||||||
die("Failed to get output resolution");
|
die("Failed to get output resolution");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(app_input.passes == 2 && app_input.pass == 1)) {
|
||||||
|
// We don't save the bitstream for the 1st pass on two pass rate control
|
||||||
writer = vpx_video_writer_open(app_input.output_filename, kContainerIVF,
|
writer = vpx_video_writer_open(app_input.output_filename, kContainerIVF,
|
||||||
&info);
|
&info);
|
||||||
if (!writer)
|
if (!writer)
|
||||||
die("Failed to open %s for writing\n", app_input.output_filename);
|
die("Failed to open %s for writing\n", app_input.output_filename);
|
||||||
|
}
|
||||||
|
|
||||||
// skip initial frames
|
// skip initial frames
|
||||||
for (i = 0; i < app_input.frames_to_skip; ++i)
|
for (i = 0; i < app_input.frames_to_skip; ++i)
|
||||||
@ -254,12 +315,19 @@ int main(int argc, const char **argv) {
|
|||||||
if (res != VPX_CODEC_OK) {
|
if (res != VPX_CODEC_OK) {
|
||||||
die_codec(&codec, "Failed to encode frame");
|
die_codec(&codec, "Failed to encode frame");
|
||||||
}
|
}
|
||||||
|
if (!(app_input.passes == 2 && app_input.pass == 1)) {
|
||||||
if (vpx_svc_get_frame_size(&svc_ctx) > 0) {
|
if (vpx_svc_get_frame_size(&svc_ctx) > 0) {
|
||||||
vpx_video_writer_write_frame(writer,
|
vpx_video_writer_write_frame(writer,
|
||||||
vpx_svc_get_buffer(&svc_ctx),
|
vpx_svc_get_buffer(&svc_ctx),
|
||||||
vpx_svc_get_frame_size(&svc_ctx),
|
vpx_svc_get_frame_size(&svc_ctx),
|
||||||
pts);
|
pts);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (vpx_svc_get_rc_stats_buffer_size(&svc_ctx) > 0) {
|
||||||
|
stats_write(&app_input.rc_stats,
|
||||||
|
vpx_svc_get_rc_stats_buffer(&svc_ctx),
|
||||||
|
vpx_svc_get_rc_stats_buffer_size(&svc_ctx));
|
||||||
|
}
|
||||||
++frame_cnt;
|
++frame_cnt;
|
||||||
pts += frame_duration;
|
pts += frame_duration;
|
||||||
}
|
}
|
||||||
@ -269,7 +337,12 @@ int main(int argc, const char **argv) {
|
|||||||
fclose(infile);
|
fclose(infile);
|
||||||
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");
|
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");
|
||||||
|
|
||||||
|
if (app_input.passes == 2)
|
||||||
|
stats_close(&app_input.rc_stats, 1);
|
||||||
|
|
||||||
|
if (writer) {
|
||||||
vpx_video_writer_close(writer);
|
vpx_video_writer_close(writer);
|
||||||
|
}
|
||||||
|
|
||||||
vpx_img_free(&raw);
|
vpx_img_free(&raw);
|
||||||
|
|
||||||
|
@ -21,3 +21,5 @@ text vpx_svc_set_options
|
|||||||
text vpx_svc_set_quantizers
|
text vpx_svc_set_quantizers
|
||||||
text vpx_svc_set_scale_factors
|
text vpx_svc_set_scale_factors
|
||||||
text vpx_svc_get_layer_resolution
|
text vpx_svc_get_layer_resolution
|
||||||
|
text vpx_svc_get_rc_stats_buffer_size
|
||||||
|
text vpx_svc_get_rc_stats_buffer
|
@ -81,6 +81,10 @@ typedef struct SvcInternal {
|
|||||||
size_t buffer_size;
|
size_t buffer_size;
|
||||||
void *buffer;
|
void *buffer;
|
||||||
|
|
||||||
|
char *rc_stats_buf;
|
||||||
|
size_t rc_stats_buf_size;
|
||||||
|
size_t rc_stats_buf_used;
|
||||||
|
|
||||||
char message_buffer[2048];
|
char message_buffer[2048];
|
||||||
vpx_codec_ctx_t *codec_ctx;
|
vpx_codec_ctx_t *codec_ctx;
|
||||||
} SvcInternal;
|
} SvcInternal;
|
||||||
@ -569,7 +573,6 @@ vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
|
|||||||
enc_cfg->ss_number_layers = si->layers;
|
enc_cfg->ss_number_layers = si->layers;
|
||||||
enc_cfg->ts_number_layers = 1; // Temporal layers not used in this encoder.
|
enc_cfg->ts_number_layers = 1; // Temporal layers not used in this encoder.
|
||||||
enc_cfg->kf_mode = VPX_KF_DISABLED;
|
enc_cfg->kf_mode = VPX_KF_DISABLED;
|
||||||
enc_cfg->g_pass = VPX_RC_ONE_PASS;
|
|
||||||
// Lag in frames not currently supported
|
// Lag in frames not currently supported
|
||||||
enc_cfg->g_lag_in_frames = 0;
|
enc_cfg->g_lag_in_frames = 0;
|
||||||
|
|
||||||
@ -851,6 +854,7 @@ vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
|
|||||||
|
|
||||||
memset(&superframe, 0, sizeof(superframe));
|
memset(&superframe, 0, sizeof(superframe));
|
||||||
svc_log_reset(svc_ctx);
|
svc_log_reset(svc_ctx);
|
||||||
|
si->rc_stats_buf_used = 0;
|
||||||
|
|
||||||
si->layers = svc_ctx->spatial_layers;
|
si->layers = svc_ctx->spatial_layers;
|
||||||
if (si->frame_within_gop >= si->kf_dist ||
|
if (si->frame_within_gop >= si->kf_dist ||
|
||||||
@ -923,6 +927,25 @@ vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case VPX_CODEC_STATS_PKT: {
|
||||||
|
size_t new_size = si->rc_stats_buf_used +
|
||||||
|
cx_pkt->data.twopass_stats.sz;
|
||||||
|
|
||||||
|
if (new_size > si->rc_stats_buf_size) {
|
||||||
|
char *p = (char*)realloc(si->rc_stats_buf, new_size);
|
||||||
|
if (p == NULL) {
|
||||||
|
svc_log(svc_ctx, SVC_LOG_ERROR, "Error allocating stats buf\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
si->rc_stats_buf = p;
|
||||||
|
si->rc_stats_buf_size = new_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(si->rc_stats_buf + si->rc_stats_buf_used,
|
||||||
|
cx_pkt->data.twopass_stats.buf, cx_pkt->data.twopass_stats.sz);
|
||||||
|
si->rc_stats_buf_used += cx_pkt->data.twopass_stats.sz;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1077,7 +1100,24 @@ void vpx_svc_release(SvcContext *svc_ctx) {
|
|||||||
si = (SvcInternal *)svc_ctx->internal;
|
si = (SvcInternal *)svc_ctx->internal;
|
||||||
if (si != NULL) {
|
if (si != NULL) {
|
||||||
free(si->buffer);
|
free(si->buffer);
|
||||||
|
if (si->rc_stats_buf) {
|
||||||
|
free(si->rc_stats_buf);
|
||||||
|
}
|
||||||
free(si);
|
free(si);
|
||||||
svc_ctx->internal = NULL;
|
svc_ctx->internal = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t vpx_svc_get_rc_stats_buffer_size(const SvcContext *svc_ctx) {
|
||||||
|
const SvcInternal *const si = get_const_svc_internal(svc_ctx);
|
||||||
|
if (svc_ctx == NULL || si == NULL) return 0;
|
||||||
|
return si->rc_stats_buf_used;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *vpx_svc_get_rc_stats_buffer(const SvcContext *svc_ctx) {
|
||||||
|
const SvcInternal *const si = get_const_svc_internal(svc_ctx);
|
||||||
|
if (svc_ctx == NULL || si == NULL) return NULL;
|
||||||
|
return si->rc_stats_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -113,6 +113,17 @@ size_t vpx_svc_get_frame_size(const SvcContext *svc_ctx);
|
|||||||
*/
|
*/
|
||||||
void *vpx_svc_get_buffer(const SvcContext *svc_ctx);
|
void *vpx_svc_get_buffer(const SvcContext *svc_ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return size of two pass rate control stats data to be returned by
|
||||||
|
* vpx_svc_get_rc_stats_buffer
|
||||||
|
*/
|
||||||
|
size_t vpx_svc_get_rc_stats_buffer_size(const SvcContext *svc_ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return buffer two pass of rate control stats data
|
||||||
|
*/
|
||||||
|
char *vpx_svc_get_rc_stats_buffer(const SvcContext *svc_ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return spatial resolution of the specified layer
|
* return spatial resolution of the specified layer
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user