From 12aaff560b0615c6ebce1f707251a1bbead3d7f3 Mon Sep 17 00:00:00 2001 From: Minghai Shang Date: Thu, 11 Sep 2014 10:52:26 -0700 Subject: [PATCH] [spatial svc] Remove handling frame and stats packets in the codec 1. svc_encodeframe.c will not handle frame or stats packets anymore. The app will process them. 2. Remove APIs that related to these packets. Change-Id: Id0d7f8b458dc09c6f77064c0878fd4e572db001b --- examples/vp9_spatial_svc_encoder.c | 40 ++++++--- test/svc_test.cc | 63 +++++++------ vpx/exports_enc | 5 -- vpx/src/svc_encodeframe.c | 138 +---------------------------- vpx/svc_context.h | 28 ------ 5 files changed, 69 insertions(+), 205 deletions(-) diff --git a/examples/vp9_spatial_svc_encoder.c b/examples/vp9_spatial_svc_encoder.c index 81d380045..7ce3403f5 100644 --- a/examples/vp9_spatial_svc_encoder.c +++ b/examples/vp9_spatial_svc_encoder.c @@ -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; diff --git a/test/svc_test.cc b/test/svc_test.cc index 218f53db7..5035dee40 100644 --- a/test/svc_test.cc +++ b/test/svc_test.cc @@ -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(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); } } diff --git a/vpx/exports_enc b/vpx/exports_enc index 07f0280ec..12e457870 100644 --- a/vpx/exports_enc +++ b/vpx/exports_enc @@ -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 diff --git a/vpx/src/svc_encodeframe.c b/vpx/src/svc_encodeframe.c index ea30b443d..ed33fb2a5 100644 --- a/vpx/src/svc_encodeframe.c +++ b/vpx/src/svc_encodeframe.c @@ -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; -} - - diff --git a/vpx/svc_context.h b/vpx/svc_context.h index eea3b131a..0ed2f0fd7 100644 --- a/vpx/svc_context.h +++ b/vpx/svc_context.h @@ -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 */ -- 2.40.0