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
6namespace {
7
8TEST(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
26LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += rush_hour_444.y4m26LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += rush_hour_444.y4m
27LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += screendata.y4m27LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += screendata.y4m
28LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += niklas_640_480_30.yuv28LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += niklas_640_480_30.yuv
29LIBVPX_TEST_DATA-$(CONFIG_RATE_CTRL) += bus_352x288_420_f20_b8.yuv
29 30
30# Test vectors31# Test vectors
31LIBVPX_TEST_DATA-$(CONFIG_VP8_DECODER) += vp80-00-comprehensive-001.ivf32LIBVPX_TEST_DATA-$(CONFIG_VP8_DECODER) += vp80-00-comprehensive-001.ivf
test/test-data.sha1+1−0
@@ -1,3 +1,4 @@
13eaf216d9fc8b4b9bb8c3956311f49a85974806c *bus_352x288_420_f20_b8.yuv
1d5dfb0151c9051f8c85999255645d7a23916d3c0 *hantro_collage_w352h288.yuv2d5dfb0151c9051f8c85999255645d7a23916d3c0 *hantro_collage_w352h288.yuv
2b87815bf86020c592ccc7a846ba2e28ec8043902 *hantro_odd.yuv3b87815bf86020c592ccc7a846ba2e28ec8043902 *hantro_odd.yuv
376024eb753cdac6a5e5703aaea189d35c3c30ac7 *invalid-vp90-2-00-quantizer-00.webm.ivf.s5861_r01-05_b6-.v2.ivf476024eb753cdac6a5e5703aaea189d35c3c30ac7 *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
58LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += svc_test.h58LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += svc_test.h
59LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += svc_end_to_end_test.cc59LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += svc_end_to_end_test.cc
60LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += timestamp_test.cc60LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += timestamp_test.cc
61LIBVPX_TEST_SRCS-$(CONFIG_RATE_CTRL) += simple_encode_test.cc
61 62
62LIBVPX_TEST_SRCS-yes += decode_test_driver.cc63LIBVPX_TEST_SRCS-yes += decode_test_driver.cc
63LIBVPX_TEST_SRCS-yes += decode_test_driver.h64LIBVPX_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
3685 return coding_frame_num;3685 return coding_frame_num;
3686}3686}
3687#endif3687#endif
3688
3689FIRSTPASS_STATS vp9_get_frame_stats(const TWO_PASS *twopass) {
3690 return twopass->this_frame_stats;
3691}
3692FIRSTPASS_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
256 int multi_layer_arf, int allow_alt_ref);256 int multi_layer_arf, int allow_alt_ref);
257#endif257#endif
258 258
259FIRSTPASS_STATS vp9_get_frame_stats(const TWO_PASS *two_pass);
260FIRSTPASS_STATS vp9_get_total_stats(const TWO_PASS *two_pass);
261
259#ifdef __cplusplus262#ifdef __cplusplus
260} // extern "C"263} // extern "C"
261#endif264#endif
vp9/simple_encode.cc+155−9
@@ -1,27 +1,173 @@
1#include <vector>
1#include "vp9/common/vp9_onyxc_int.h"2#include "vp9/common/vp9_onyxc_int.h"
3#include "vp9/vp9_iface_common.h"
2#include "vp9/encoder/vp9_encoder.h"4#include "vp9/encoder/vp9_encoder.h"
5#include "vp9/encoder/vp9_firstpass.h"
3#include "vp9/simple_encode.h"6#include "vp9/simple_encode.h"
4#include "vp9/vp9_cx_iface.h"7#include "vp9/vp9_cx_iface.h"
5 8
9// TODO(angiebird): Merge this function with vpx_img_plane_width()
10static 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()
18static 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()
26static 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
6class SimpleEncode::impl {46class SimpleEncode::impl {
7 public:47 public:
8 VP9_COMP *cpi;48 VP9_COMP *cpi;
9 BufferPool *buffer_pool;49 std::vector<FIRSTPASS_STATS> frame_stats;
10};50};
11 51
52static 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
62static void free_encoder(VP9_COMP *cpi) {
63 vpx_free(cpi->common.buffer_pool);
64 vp9_remove_compressor(cpi);
65}
66
67static 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
12SimpleEncode::SimpleEncode(int frame_width, int frame_height,74SimpleEncode::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)
14 : pimpl{ std::unique_ptr<impl>(new impl()) } {77 : 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
88void 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
139std::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
158void SimpleEncode::StartEncode() {
159 vpx_rational_t frame_rate = make_vpx_rational(frame_rate_num, frame_rate_den);
15 VP9EncoderConfig oxcf = vp9_get_encoder_config(160 VP9EncoderConfig oxcf = vp9_get_encoder_config(
16 frame_width, frame_height, frame_rate, target_bitrate, VPX_RC_LAST_PASS);161 frame_width, frame_height, frame_rate, target_bitrate, VPX_RC_LAST_PASS);
17 pimpl->buffer_pool = (BufferPool *)vpx_calloc(1, sizeof(*pimpl->buffer_pool));162 assert(pimpl->cpi == NULL);
18 vp9_initialize_enc();163 pimpl->cpi = init_encoder(&oxcf, VPX_IMG_FMT_I420);
19 pimpl->cpi = vp9_create_compressor(&oxcf, pimpl->buffer_pool);164 rewind(file);
20 vp9_update_compressor_with_img_fmt(pimpl->cpi, VPX_IMG_FMT_I420);
21}165}
22 166
23SimpleEncode::~SimpleEncode() {167void SimpleEncode::EndEncode() {
24 vpx_free(pimpl->buffer_pool);168 free_encoder(pimpl->cpi);
25 vp9_remove_compressor(pimpl->cpi);
26 pimpl->cpi = nullptr;169 pimpl->cpi = nullptr;
170 rewind(file);
27}171}
172
173SimpleEncode::~SimpleEncode() {}
vp9/simple_encode.h+24−2
@@ -1,13 +1,35 @@
1#include <memory>1#include <memory>
2#include <vector>
2class SimpleEncode {3class SimpleEncode {
3 public:4 public:
4 SimpleEncode(int frame_width, int frame_height, vpx_rational_t frame_rate,5 SimpleEncode(int frame_width, int frame_height, int frame_rate_num,
5 int target_bitrate);6 int frame_rate_den, int target_bitrate, int num_frames,
7 FILE *file);
6 ~SimpleEncode();8 ~SimpleEncode();
7 SimpleEncode(SimpleEncode &&) = delete;9 SimpleEncode(SimpleEncode &&) = delete;
8 SimpleEncode &operator=(SimpleEncode &&) = delete;10 SimpleEncode &operator=(SimpleEncode &&) = delete;
9 11
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
10 private:25 private:
11 class impl;26 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;
12 std::unique_ptr<impl> pimpl;34 std::unique_ptr<impl> pimpl;
13};35};
vp9/vp9_cx_iface.c+1−12
@@ -22,6 +22,7 @@ · 21 unmodified lines
22#include "vp9/encoder/vp9_encoder.h"22#include "vp9/encoder/vp9_encoder.h"
23#include "vpx/vp8cx.h"23#include "vpx/vp8cx.h"
24#include "vp9/common/vp9_alloccommon.h"24#include "vp9/common/vp9_alloccommon.h"
25#include "vp9/vp9_cx_iface.h"
25#include "vp9/encoder/vp9_firstpass.h"26#include "vp9/encoder/vp9_firstpass.h"
26#include "vp9/encoder/vp9_lookahead.h"27#include "vp9/encoder/vp9_lookahead.h"
27#include "vp9/vp9_cx_iface.h"28#include "vp9/vp9_cx_iface.h"
@@ -1086,18 +1087,6 @@ static int write_superframe_index(vpx_codec_alg_priv_t *ctx) { · 1058 unmodified lines
1086 return index_sz;1087 return index_sz;
1087}1088}
1088 1089
1089static 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
1094static 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
1101static vpx_codec_frame_flags_t get_frame_pkt_flags(const VP9_COMP *cpi,1090static vpx_codec_frame_flags_t get_frame_pkt_flags(const VP9_COMP *cpi,
1102 unsigned int lib_flags) {1091 unsigned int lib_flags) {
1103 vpx_codec_frame_flags_t flags = lib_flags << 16;1092 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
23 vpx_enc_pass enc_pass);23 vpx_enc_pass enc_pass);
24FRAME_INFO vp9_get_frame_info(const VP9EncoderConfig *oxcf);24FRAME_INFO vp9_get_frame_info(const VP9EncoderConfig *oxcf);
25 25
26static INLINE int64_t
27timebase_units_to_ticks(const vpx_rational64_t *timestamp_ratio, int64_t n) {
28 return n * timestamp_ratio->num / timestamp_ratio->den;
29}
30
31static INLINE int64_t
32ticks_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
26#ifdef __cplusplus38#ifdef __cplusplus
27} // extern "C"39} // extern "C"
28#endif40#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