History

Add ComputeFirstPassStats()

angiebird committed 7 years ago

Commit 7ee697a1 parent 9f33d7510 files · +241 −23Browse files

Unified · Split

10 files
  1. test/simple_encode_test.cc +36 −0
  2. test/test-data.mk +1 −0
  3. test/test-data.sha1 +1 −0
  4. test/test.mk +1 −0
  5. vp9/encoder/vp9_firstpass.c +7 −0
  6. vp9/encoder/vp9_firstpass.h +3 −0
  7. vp9/simple_encode.cc +155 −9
  8. vp9/simple_encode.h +24 −2
  9. vp9/vp9_cx_iface.c +1 −12
  10. vp9/vp9_cx_iface.h +12 −0
test/simple_encode_test.cc+36−0
@@ -0,0 +1,36 @@
1+#include <memory>
2+#include <vector>
3+#include "third_party/googletest/src/include/gtest/gtest.h"
4+#include "vp9/simple_encode.h"
5+
6+namespace {
7+
8+TEST(SimpleEncode, ComputeFirstPassStats) {
9+ int w = 352;
10+ int h = 288;
11+ int frame_rate_num = 30;
12+ int frame_rate_den = 1;
13+ int target_bitrate = 200;
14+ int num_frames = 17;
15+ // TODO(angiebird): Figure out how to upload test video to our codebase
16+ FILE *file = fopen("bus_352x288_420_f20_b8.yuv", "r");
17+ SimpleEncode simple_encode(w, h, frame_rate_num, frame_rate_den,
18+ target_bitrate, num_frames, file);
19+ simple_encode.ComputeFirstPassStats();
20+ std::vector<std::vector<double>> frame_stats =
21+ simple_encode.ObserveFirstPassStats();
22+ EXPECT_EQ(frame_stats.size(), static_cast<size_t>(num_frames));
23+ size_t data_num = frame_stats[0].size();
24+ // Read ObserveFirstPassStats before changing FIRSTPASS_STATS.
25+ EXPECT_EQ(data_num, static_cast<size_t>(25));
26+ for (size_t i = 0; i < frame_stats.size(); ++i) {
27+ EXPECT_EQ(frame_stats[i].size(), data_num);
28+ // FIRSTPASS_STATS's first element is frame
29+ EXPECT_EQ(frame_stats[i][0], i);
30+ // FIRSTPASS_STATS's last element is count, and the count is 1 for single
31+ // frame stats
32+ EXPECT_EQ(frame_stats[i][data_num - 1], 1);
33+ }
34+}
35+
36+} // namespace
test/test-data.mk+1−0
@@ -26,6 +26,7 @@ LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += noisy_clip_640_360.y4m · 25 unmodified lines
2626 LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += rush_hour_444.y4m
2727 LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += screendata.y4m
2828 LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += niklas_640_480_30.yuv
29+LIBVPX_TEST_DATA-$(CONFIG_RATE_CTRL) += bus_352x288_420_f20_b8.yuv
2930
3031 # Test vectors
3132 LIBVPX_TEST_DATA-$(CONFIG_VP8_DECODER) += vp80-00-comprehensive-001.ivf
test/test-data.sha1+1−0
@@ -1,3 +1,4 @@
1+3eaf216d9fc8b4b9bb8c3956311f49a85974806c *bus_352x288_420_f20_b8.yuv
12 d5dfb0151c9051f8c85999255645d7a23916d3c0 *hantro_collage_w352h288.yuv
23 b87815bf86020c592ccc7a846ba2e28ec8043902 *hantro_odd.yuv
34 76024eb753cdac6a5e5703aaea189d35c3c30ac7 *invalid-vp90-2-00-quantizer-00.webm.ivf.s5861_r01-05_b6-.v2.ivf
test/test.mk+1−0
@@ -58,6 +58,7 @@ LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += svc_test.cc · 57 unmodified lines
5858 LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += svc_test.h
5959 LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += svc_end_to_end_test.cc
6060 LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += timestamp_test.cc
61+LIBVPX_TEST_SRCS-$(CONFIG_RATE_CTRL) += simple_encode_test.cc
6162
6263 LIBVPX_TEST_SRCS-yes += decode_test_driver.cc
6364 LIBVPX_TEST_SRCS-yes += decode_test_driver.h
vp9/encoder/vp9_firstpass.c+7−0
@@ -3685,3 +3685,10 @@ int vp9_get_coding_frame_num(const struct VP9EncoderConfig *oxcf, · 3684 unmodified lines
36853685 return coding_frame_num;
36863686 }
36873687 #endif
3688+
3689+FIRSTPASS_STATS vp9_get_frame_stats(const TWO_PASS *twopass) {
3690+ return twopass->this_frame_stats;
3691+}
3692+FIRSTPASS_STATS vp9_get_total_stats(const TWO_PASS *twopass) {
3693+ return twopass->total_stats;
3694+}
vp9/encoder/vp9_firstpass.h+3−0
@@ -256,6 +256,9 @@ int vp9_get_coding_frame_num(const struct VP9EncoderConfig *oxcf, · 255 unmodified lines
256256 int multi_layer_arf, int allow_alt_ref);
257257 #endif
258258
259+FIRSTPASS_STATS vp9_get_frame_stats(const TWO_PASS *two_pass);
260+FIRSTPASS_STATS vp9_get_total_stats(const TWO_PASS *two_pass);
261+
259262 #ifdef __cplusplus
260263 } // extern "C"
261264 #endif
vp9/simple_encode.cc+155−9
@@ -1,27 +1,173 @@
1+#include <vector>
12 #include "vp9/common/vp9_onyxc_int.h"
3+#include "vp9/vp9_iface_common.h"
24 #include "vp9/encoder/vp9_encoder.h"
5+#include "vp9/encoder/vp9_firstpass.h"
36 #include "vp9/simple_encode.h"
47 #include "vp9/vp9_cx_iface.h"
58
9+// TODO(angiebird): Merge this function with vpx_img_plane_width()
10+static int img_plane_width(const vpx_image_t *img, int plane) {
11+ if (plane > 0 && img->x_chroma_shift > 0)
12+ return (img->d_w + 1) >> img->x_chroma_shift;
13+ else
14+ return img->d_w;
15+}
16+
17+// TODO(angiebird): Merge this function with vpx_img_plane_height()
18+static int img_plane_height(const vpx_image_t *img, int plane) {
19+ if (plane > 0 && img->y_chroma_shift > 0)
20+ return (img->d_h + 1) >> img->y_chroma_shift;
21+ else
22+ return img->d_h;
23+}
24+
25+// TODO(angiebird): Merge this function with vpx_img_read()
26+static int img_read(vpx_image_t *img, FILE *file) {
27+ int plane;
28+
29+ for (plane = 0; plane < 3; ++plane) {
30+ unsigned char *buf = img->planes[plane];
31+ const int stride = img->stride[plane];
32+ const int w = img_plane_width(img, plane) *
33+ ((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);
34+ const int h = img_plane_height(img, plane);
35+ int y;
36+
37+ for (y = 0; y < h; ++y) {
38+ if (fread(buf, 1, w, file) != (size_t)w) return 0;
39+ buf += stride;
40+ }
41+ }
42+
43+ return 1;
44+}
45+
646 class SimpleEncode::impl {
747 public:
848 VP9_COMP *cpi;
9− BufferPool *buffer_pool;
49+ std::vector<FIRSTPASS_STATS> frame_stats;
1050 };
1151
52+static VP9_COMP *init_encoder(const VP9EncoderConfig *oxcf,
53+ vpx_img_fmt_t img_fmt) {
54+ VP9_COMP *cpi;
55+ BufferPool *buffer_pool = (BufferPool *)vpx_calloc(1, sizeof(*buffer_pool));
56+ vp9_initialize_enc();
57+ cpi = vp9_create_compressor(oxcf, buffer_pool);
58+ vp9_update_compressor_with_img_fmt(cpi, img_fmt);
59+ return cpi;
60+}
61+
62+static void free_encoder(VP9_COMP *cpi) {
63+ vpx_free(cpi->common.buffer_pool);
64+ vp9_remove_compressor(cpi);
65+}
66+
67+static INLINE vpx_rational_t make_vpx_rational(int num, int den) {
68+ vpx_rational_t v;
69+ v.num = num;
70+ v.den = den;
71+ return v;
72+}
73+
1274 SimpleEncode::SimpleEncode(int frame_width, int frame_height,
13− vpx_rational_t frame_rate, int target_bitrate)
75+ int frame_rate_num, int frame_rate_den,
76+ int target_bitrate, int num_frames, FILE *file)
1477 : pimpl{ std::unique_ptr<impl>(new impl()) } {
78+ this->frame_width = frame_width;
79+ this->frame_height = frame_height;
80+ this->frame_rate_num = frame_rate_num;
81+ this->frame_rate_den = frame_rate_den;
82+ this->target_bitrate = target_bitrate;
83+ this->num_frames = num_frames;
84+ this->file = file;
85+ pimpl->cpi = NULL;
86+}
87+
88+void SimpleEncode::ComputeFirstPassStats() {
89+ const vpx_img_fmt_t img_fmt = VPX_IMG_FMT_I420;
90+ vpx_rational_t frame_rate = make_vpx_rational(frame_rate_num, frame_rate_den);
91+ const VP9EncoderConfig oxcf = vp9_get_encoder_config(
92+ frame_width, frame_height, frame_rate, target_bitrate, VPX_RC_FIRST_PASS);
93+ VP9_COMP *cpi = init_encoder(&oxcf, img_fmt);
94+ struct lookahead_ctx *lookahead = cpi->lookahead;
95+ int i;
96+ int use_highbitdepth = 0;
97+#if CONFIG_VP9_HIGHBITDEPTH
98+ use_highbitdepth = cpi->common.use_highbitdepth;
99+#endif
100+ vpx_image_t img;
101+ vpx_img_alloc(&img, img_fmt, frame_width, frame_height, 1);
102+ rewind(file);
103+ pimpl->frame_stats.clear();
104+ for (i = 0; i < num_frames; ++i) {
105+ assert(!vp9_lookahead_full(lookahead));
106+ if (img_read(&img, file)) {
107+ int next_show_idx = vp9_lookahead_next_show_idx(lookahead);
108+ int64_t ts_start =
109+ timebase_units_to_ticks(&oxcf.g_timebase_in_ts, next_show_idx);
110+ int64_t ts_end =
111+ timebase_units_to_ticks(&oxcf.g_timebase_in_ts, next_show_idx + 1);
112+ YV12_BUFFER_CONFIG sd;
113+ image2yuvconfig(&img, &sd);
114+ vp9_lookahead_push(lookahead, &sd, ts_start, ts_end, use_highbitdepth, 0);
115+ {
116+ int64_t time_stamp;
117+ int64_t time_end;
118+ int flush = 1; // Make vp9_get_compressed_data process a frame
119+ size_t size;
120+ unsigned int frame_flags = 0;
121+ // TODO(angiebird): Call vp9_first_pass directly
122+ vp9_get_compressed_data(cpi, &frame_flags, &size, NULL, &time_stamp,
123+ &time_end, flush);
124+ // vp9_get_compressed_data only generates first pass stats not
125+ // compresses data
126+ assert(size == 0);
127+ }
128+ pimpl->frame_stats.push_back(vp9_get_frame_stats(&cpi->twopass));
129+ }
130+ }
131+ vp9_end_first_pass(cpi);
132+ // TODO(angiebird): Store the total_stats apart form frame_stats
133+ pimpl->frame_stats.push_back(vp9_get_total_stats(&cpi->twopass));
134+ free_encoder(cpi);
135+ rewind(file);
136+ vpx_img_free(&img);
137+}
138+
139+std::vector<std::vector<double>> SimpleEncode::ObserveFirstPassStats() {
140+ std::vector<std::vector<double>> output_stats;
141+ // TODO(angiebird): This function make several assumptions of
142+ // FIRSTPASS_STATS. 1) All elements in FIRSTPASS_STATS are double except the
143+ // last one. 2) The last entry of frame_stats is the total_stats.
144+ // Change the code structure, so that we don't have to make these assumptions
145+
146+ // Note the last entry of frame_stats is the total_stats, we don't need it.
147+ for (size_t i = 0; i < pimpl->frame_stats.size() - 1; ++i) {
148+ double *buf_start = reinterpret_cast<double *>(&pimpl->frame_stats[i]);
149+ // We use - 1 here because the last member in FIRSTPASS_STATS is not double
150+ double *buf_end =
151+ buf_start + sizeof(pimpl->frame_stats[i]) / sizeof(*buf_end) - 1;
152+ std::vector<double> this_stats(buf_start, buf_end);
153+ output_stats.push_back(this_stats);
154+ }
155+ return output_stats;
156+}
157+
158+void SimpleEncode::StartEncode() {
159+ vpx_rational_t frame_rate = make_vpx_rational(frame_rate_num, frame_rate_den);
15160 VP9EncoderConfig oxcf = vp9_get_encoder_config(
16161 frame_width, frame_height, frame_rate, target_bitrate, VPX_RC_LAST_PASS);
17− pimpl->buffer_pool = (BufferPool *)vpx_calloc(1, sizeof(*pimpl->buffer_pool));
18− vp9_initialize_enc();
19− pimpl->cpi = vp9_create_compressor(&oxcf, pimpl->buffer_pool);
20− vp9_update_compressor_with_img_fmt(pimpl->cpi, VPX_IMG_FMT_I420);
162+ assert(pimpl->cpi == NULL);
163+ pimpl->cpi = init_encoder(&oxcf, VPX_IMG_FMT_I420);
164+ rewind(file);
21165 }
22166
23−SimpleEncode::~SimpleEncode() {
24− vpx_free(pimpl->buffer_pool);
25− vp9_remove_compressor(pimpl->cpi);
167+void SimpleEncode::EndEncode() {
168+ free_encoder(pimpl->cpi);
26169 pimpl->cpi = nullptr;
170+ rewind(file);
27171 }
172+
173+SimpleEncode::~SimpleEncode() {}
vp9/simple_encode.h+24−2
@@ -1,13 +1,35 @@
11 #include <memory>
2+#include <vector>
23 class SimpleEncode {
34 public:
4− SimpleEncode(int frame_width, int frame_height, vpx_rational_t frame_rate,
5− int target_bitrate);
5+ SimpleEncode(int frame_width, int frame_height, int frame_rate_num,
6+ int frame_rate_den, int target_bitrate, int num_frames,
7+ FILE *file);
68 ~SimpleEncode();
79 SimpleEncode(SimpleEncode &&) = delete;
810 SimpleEncode &operator=(SimpleEncode &&) = delete;
911
12+ // Make encoder compute the first pass stats and store it internally for
13+ // future encode
14+ void ComputeFirstPassStats();
15+
16+ // Output the first pass stats
17+ std::vector<std::vector<double>> ObserveFirstPassStats();
18+
19+ // Initialize the encoder for actual encoding
20+ void StartEncode();
21+
22+ // Free the encoder
23+ void EndEncode();
24+
1025 private:
1126 class impl;
27+ int frame_width;
28+ int frame_height;
29+ int frame_rate_num;
30+ int frame_rate_den;
31+ int target_bitrate;
32+ int num_frames;
33+ FILE *file;
1234 std::unique_ptr<impl> pimpl;
1335 };
vp9/vp9_cx_iface.c+1−12
@@ -22,6 +22,7 @@ · 21 unmodified lines
2222 #include "vp9/encoder/vp9_encoder.h"
2323 #include "vpx/vp8cx.h"
2424 #include "vp9/common/vp9_alloccommon.h"
25+#include "vp9/vp9_cx_iface.h"
2526 #include "vp9/encoder/vp9_firstpass.h"
2627 #include "vp9/encoder/vp9_lookahead.h"
2728 #include "vp9/vp9_cx_iface.h"
@@ -1086,18 +1087,6 @@ static int write_superframe_index(vpx_codec_alg_priv_t *ctx) { · 1058 unmodified lines
10861087 return index_sz;
10871088 }
10881089
1089−static int64_t timebase_units_to_ticks(const vpx_rational64_t *timestamp_ratio,
1090− int64_t n) {
1091− return n * timestamp_ratio->num / timestamp_ratio->den;
1092−}
1093−
1094−static int64_t ticks_to_timebase_units(const vpx_rational64_t *timestamp_ratio,
1095− int64_t n) {
1096− int64_t round = timestamp_ratio->num / 2;
1097− if (round > 0) --round;
1098− return (n * timestamp_ratio->den + round) / timestamp_ratio->num;
1099−}
1100−
11011090 static vpx_codec_frame_flags_t get_frame_pkt_flags(const VP9_COMP *cpi,
11021091 unsigned int lib_flags) {
11031092 vpx_codec_frame_flags_t flags = lib_flags << 16;
vp9/vp9_cx_iface.h+12−0
@@ -23,6 +23,18 @@ VP9EncoderConfig vp9_get_encoder_config(int frame_width, int frame_height, · 22 unmodified lines
2323 vpx_enc_pass enc_pass);
2424 FRAME_INFO vp9_get_frame_info(const VP9EncoderConfig *oxcf);
2525
26+static INLINE int64_t
27+timebase_units_to_ticks(const vpx_rational64_t *timestamp_ratio, int64_t n) {
28+ return n * timestamp_ratio->num / timestamp_ratio->den;
29+}
30+
31+static INLINE int64_t
32+ticks_to_timebase_units(const vpx_rational64_t *timestamp_ratio, int64_t n) {
33+ int64_t round = timestamp_ratio->num / 2;
34+ if (round > 0) --round;
35+ return (n * timestamp_ratio->den + round) / timestamp_ratio->num;
36+}
37+
2638 #ifdef __cplusplus
2739 } // extern "C"
2840 #endif

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t