[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
This commit is contained in:
parent
fb754540e9
commit
12aaff560b
@ -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);
|
||||
vpx_codec_iter_t iter = NULL;
|
||||
const vpx_codec_cx_pkt_t *cx_pkt;
|
||||
|
||||
if (*frame_received == 0) {
|
||||
EXPECT_EQ(1, vpx_svc_is_keyframe(&svc_));
|
||||
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
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user