Commit e9b6c5f6 authored by Minghai Shang's avatar Minghai Shang Committed by Gerrit Code Review

Merge "[spatial svc] Remove handling frame and stats packets in the codec"

parents fb285bab 12aaff56
......@@ -282,7 +282,7 @@ int main(int argc, const char **argv) {
int frame_duration = 1; /* 1 timebase tick per frame */
FILE *infile = NULL;
int end_of_stream = 0;
int frame_size;
int frames_received = 0;
memset(&svc_ctx, 0, sizeof(svc_ctx));
svc_ctx.log_print = 1;
......@@ -325,6 +325,8 @@ int main(int argc, const char **argv) {
// Encode frames
while (!end_of_stream) {
vpx_codec_iter_t iter = NULL;
const vpx_codec_cx_pkt_t *cx_pkt;
if (frame_cnt >= app_input.frames_to_code || !vpx_img_read(&raw, infile)) {
// We need one extra vpx_svc_encode call at end of stream to flush
// encoder and get remaining data
......@@ -337,18 +339,34 @@ int main(int argc, const char **argv) {
if (res != VPX_CODEC_OK) {
die_codec(&codec, "Failed to encode frame");
}
if (!(app_input.passes == 2 && app_input.pass == 1)) {
while ((frame_size = vpx_svc_get_frame_size(&svc_ctx)) > 0) {
vpx_video_writer_write_frame(writer,
vpx_svc_get_buffer(&svc_ctx),
frame_size, pts);
while ((cx_pkt = vpx_codec_get_cx_data(&codec, &iter)) != NULL) {
switch (cx_pkt->kind) {
case VPX_CODEC_CX_FRAME_PKT: {
if (cx_pkt->data.frame.sz > 0)
vpx_video_writer_write_frame(writer,
cx_pkt->data.frame.buf,
cx_pkt->data.frame.sz,
cx_pkt->data.frame.pts);
printf("SVC frame: %d, kf: %d, size: %d, pts: %d\n", frames_received,
!!(cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY),
(int)cx_pkt->data.frame.sz, (int)cx_pkt->data.frame.pts);
++frames_received;
break;
}
case VPX_CODEC_STATS_PKT: {
stats_write(&app_input.rc_stats,
cx_pkt->data.twopass_stats.buf,
cx_pkt->data.twopass_stats.sz);
break;
}
default: {
break;
}
}
}
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));
}
if (!end_of_stream) {
++frame_cnt;
pts += frame_duration;
......
......@@ -74,6 +74,7 @@ class SvcTest : public ::testing::Test {
const vpx_codec_err_t res =
vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_OK, res);
vpx_codec_control(&codec_, VP8E_SET_CPUUSED, 4); // Make the test faster
codec_initialized_ = true;
}
......@@ -83,11 +84,23 @@ class SvcTest : public ::testing::Test {
codec_initialized_ = false;
}
void GetStatsData(std::string *const stats_buf) {
vpx_codec_iter_t iter = NULL;
const vpx_codec_cx_pkt_t *cx_pkt;
while ((cx_pkt = vpx_codec_get_cx_data(&codec_, &iter)) != NULL) {
if (cx_pkt->kind == VPX_CODEC_STATS_PKT) {
EXPECT_GT(cx_pkt->data.twopass_stats.sz, 0U);
ASSERT_TRUE(cx_pkt->data.twopass_stats.buf != NULL);
stats_buf->append(static_cast<char*>(cx_pkt->data.twopass_stats.buf),
cx_pkt->data.twopass_stats.sz);
}
}
}
void Pass1EncodeNFrames(const int n, const int layers,
std::string *const stats_buf) {
vpx_codec_err_t res;
size_t stats_size = 0;
const char *stats_data = NULL;
ASSERT_GT(n, 0);
ASSERT_GT(layers, 0);
......@@ -104,22 +117,15 @@ class SvcTest : public ::testing::Test {
res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
video.duration(), VPX_DL_GOOD_QUALITY);
ASSERT_EQ(VPX_CODEC_OK, res);
stats_size = vpx_svc_get_rc_stats_buffer_size(&svc_);
EXPECT_GT(stats_size, 0U);
stats_data = vpx_svc_get_rc_stats_buffer(&svc_);
ASSERT_TRUE(stats_data != NULL);
stats_buf->append(stats_data, stats_size);
GetStatsData(stats_buf);
video.Next();
}
// Flush encoder and test EOS packet.
res = vpx_svc_encode(&svc_, &codec_, NULL, video.pts(),
video.duration(), VPX_DL_GOOD_QUALITY);
stats_size = vpx_svc_get_rc_stats_buffer_size(&svc_);
EXPECT_GT(stats_size, 0U);
stats_data = vpx_svc_get_rc_stats_buffer(&svc_);
ASSERT_TRUE(stats_data != NULL);
stats_buf->append(stats_data, stats_size);
ASSERT_EQ(VPX_CODEC_OK, res);
GetStatsData(stats_buf);
ReleaseEncoder();
}
......@@ -127,20 +133,27 @@ class SvcTest : public ::testing::Test {
void StoreFrames(const size_t max_frame_received,
struct vpx_fixed_buf *const outputs,
size_t *const frame_received) {
size_t frame_size;
while ((frame_size = vpx_svc_get_frame_size(&svc_)) > 0) {
ASSERT_LT(*frame_received, max_frame_received);
if (*frame_received == 0) {
EXPECT_EQ(1, vpx_svc_is_keyframe(&svc_));
vpx_codec_iter_t iter = NULL;
const vpx_codec_cx_pkt_t *cx_pkt;
while ((cx_pkt = vpx_codec_get_cx_data(&codec_, &iter)) != NULL) {
if (cx_pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
const size_t frame_size = cx_pkt->data.frame.sz;
EXPECT_GT(frame_size, 0U);
ASSERT_TRUE(cx_pkt->data.frame.buf != NULL);
ASSERT_LT(*frame_received, max_frame_received);
if (*frame_received == 0)
EXPECT_EQ(1, !!(cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY));
outputs[*frame_received].buf = malloc(frame_size + 16);
ASSERT_TRUE(outputs[*frame_received].buf != NULL);
memcpy(outputs[*frame_received].buf, cx_pkt->data.frame.buf,
frame_size);
outputs[*frame_received].sz = frame_size;
++(*frame_received);
}
outputs[*frame_received].buf = malloc(frame_size + 16);
ASSERT_TRUE(outputs[*frame_received].buf != NULL);
memcpy(outputs[*frame_received].buf, vpx_svc_get_buffer(&svc_),
frame_size);
outputs[*frame_received].sz = frame_size;
++(*frame_received);
}
}
......
......@@ -8,17 +8,12 @@ text vpx_codec_get_preview_frame
text vpx_codec_set_cx_data_buf
text vpx_svc_dump_statistics
text vpx_svc_encode
text vpx_svc_get_buffer
text vpx_svc_get_encode_frame_count
text vpx_svc_get_frame_size
text vpx_svc_get_message
text vpx_svc_init
text vpx_svc_is_keyframe
text vpx_svc_release
text vpx_svc_set_keyframe
text vpx_svc_set_options
text vpx_svc_set_quantizers
text vpx_svc_set_scale_factors
text vpx_svc_get_layer_resolution
text vpx_svc_get_rc_stats_buffer_size
text vpx_svc_get_rc_stats_buffer
......@@ -114,65 +114,10 @@ typedef struct SvcInternal {
int is_keyframe;
int use_multiple_frame_contexts;
FrameData *frame_list;
FrameData *frame_temp;
char *rc_stats_buf;
size_t rc_stats_buf_size;
size_t rc_stats_buf_used;
char message_buffer[2048];
vpx_codec_ctx_t *codec_ctx;
} SvcInternal;
// create FrameData from encoder output
static struct FrameData *fd_create(void *buf, size_t size,
vpx_codec_frame_flags_t flags) {
struct FrameData *const frame_data =
(struct FrameData *)vpx_malloc(sizeof(*frame_data));
if (frame_data == NULL) {
return NULL;
}
frame_data->buf = vpx_malloc(size);
if (frame_data->buf == NULL) {
vpx_free(frame_data);
return NULL;
}
vpx_memcpy(frame_data->buf, buf, size);
frame_data->size = size;
frame_data->flags = flags;
return frame_data;
}
// free FrameData
static void fd_free(struct FrameData *p) {
if (p) {
if (p->buf)
vpx_free(p->buf);
vpx_free(p);
}
}
// add FrameData to list
static void fd_list_add(struct FrameData **list, struct FrameData *layer_data) {
struct FrameData **p = list;
while (*p != NULL) p = &(*p)->next;
*p = layer_data;
layer_data->next = NULL;
}
// free FrameData list
static void fd_free_list(struct FrameData *list) {
struct FrameData *p = list;
while (p) {
list = list->next;
fd_free(p);
p = list;
}
}
static SvcInternal *get_svc_internal(SvcContext *svc_ctx) {
if (svc_ctx == NULL) return NULL;
if (svc_ctx->internal == NULL) {
......@@ -628,7 +573,6 @@ vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
}
svc_log_reset(svc_ctx);
si->rc_stats_buf_used = 0;
si->layers = svc_ctx->spatial_layers;
if (si->encode_frame_count == 0) {
......@@ -659,20 +603,6 @@ vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
iter = NULL;
while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) {
switch (cx_pkt->kind) {
case VPX_CODEC_CX_FRAME_PKT: {
fd_list_add(&si->frame_list, fd_create(cx_pkt->data.frame.buf,
cx_pkt->data.frame.sz,
cx_pkt->data.frame.flags));
svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, kf: %d, size: %d, "
"pts: %d\n", si->frame_received,
(cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY) ? 1 : 0,
(int)cx_pkt->data.frame.sz, (int)cx_pkt->data.frame.pts);
++si->frame_received;
layer_for_psnr = 0;
break;
}
case VPX_CODEC_PSNR_PKT: {
int i;
svc_log(svc_ctx, SVC_LOG_DEBUG,
......@@ -692,25 +622,8 @@ vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
si->sse_sum[layer_for_psnr][i] += cx_pkt->data.psnr.sse[i];
}
++layer_for_psnr;
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");
return VPX_CODEC_MEM_ERROR;
}
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;
if (layer_for_psnr == svc_ctx->spatial_layers)
layer_for_psnr = 0;
break;
}
#if CONFIG_SPATIAL_SVC
......@@ -741,41 +654,12 @@ const char *vpx_svc_get_message(const SvcContext *svc_ctx) {
return si->message_buffer;
}
// We will maintain a list of output frame buffers since with lag_in_frame
// we need to output all frame buffers at the end. vpx_svc_get_buffer() will
// remove a frame buffer from the list the put it to a temporal pointer, which
// will be removed at the next vpx_svc_get_buffer() or when closing encoder.
void *vpx_svc_get_buffer(SvcContext *svc_ctx) {
SvcInternal *const si = get_svc_internal(svc_ctx);
if (svc_ctx == NULL || si == NULL || si->frame_list == NULL) return NULL;
if (si->frame_temp)
fd_free(si->frame_temp);
si->frame_temp = si->frame_list;
si->frame_list = si->frame_list->next;
return si->frame_temp->buf;
}
size_t vpx_svc_get_frame_size(const SvcContext *svc_ctx) {
const SvcInternal *const si = get_const_svc_internal(svc_ctx);
if (svc_ctx == NULL || si == NULL || si->frame_list == NULL) return 0;
return si->frame_list->size;
}
int vpx_svc_get_encode_frame_count(const SvcContext *svc_ctx) {
const SvcInternal *const si = get_const_svc_internal(svc_ctx);
if (svc_ctx == NULL || si == NULL) return 0;
return si->encode_frame_count;
}
int vpx_svc_is_keyframe(const SvcContext *svc_ctx) {
const SvcInternal *const si = get_const_svc_internal(svc_ctx);
if (svc_ctx == NULL || si == NULL || si->frame_list == NULL) return 0;
return (si->frame_list->flags & VPX_FRAME_IS_KEY) != 0;
}
void vpx_svc_set_keyframe(SvcContext *svc_ctx) {
SvcInternal *const si = get_svc_internal(svc_ctx);
if (svc_ctx == NULL || si == NULL) return;
......@@ -855,26 +739,8 @@ void vpx_svc_release(SvcContext *svc_ctx) {
// SvcInternal if it was not already allocated
si = (SvcInternal *)svc_ctx->internal;
if (si != NULL) {
fd_free(si->frame_temp);
fd_free_list(si->frame_list);
if (si->rc_stats_buf) {
free(si->rc_stats_buf);
}
free(si);
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;
}
......@@ -95,29 +95,6 @@ const char *vpx_svc_dump_statistics(SvcContext *svc_ctx);
*/
const char *vpx_svc_get_message(const SvcContext *svc_ctx);
/**
* return size of encoded data to be returned by vpx_svc_get_buffer.
* it needs to be called before vpx_svc_get_buffer.
*/
size_t vpx_svc_get_frame_size(const SvcContext *svc_ctx);
/**
* return buffer with encoded data. encoder will maintain a list of frame
* buffers. each call of vpx_svc_get_buffer() will return one frame.
*/
void *vpx_svc_get_buffer(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
*/
......@@ -130,11 +107,6 @@ vpx_codec_err_t vpx_svc_get_layer_resolution(const SvcContext *svc_ctx,
*/
int vpx_svc_get_encode_frame_count(const SvcContext *svc_ctx);
/**
* return 1 if last encoded frame was a keyframe
*/
int vpx_svc_is_keyframe(const SvcContext *svc_ctx);
/**
* force the next frame to be a keyframe
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment