Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1453)

Side by Side Diff: source/libvpx/examples/twopass_encoder.c

Issue 168343002: libvpx: Pull from upstream (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/libvpx/
Patch Set: libvpx: Pull from upstream Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « source/libvpx/examples/simple_encoder.c ('k') | source/libvpx/examples/vp8_set_maps.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved. 2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source 5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 // It's sometimes helpful to see when each pass completes. 43 // It's sometimes helpful to see when each pass completes.
44 // 44 //
45 // 45 //
46 // Clean-up 46 // Clean-up
47 // ----------------------------- 47 // -----------------------------
48 // Destruction of the encoder instance must be done on each pass. The 48 // Destruction of the encoder instance must be done on each pass. The
49 // raw image should be destroyed at the end as usual. 49 // raw image should be destroyed at the end as usual.
50 50
51 #include <stdio.h> 51 #include <stdio.h>
52 #include <stdlib.h> 52 #include <stdlib.h>
53 #include <stdarg.h>
54 #include <string.h> 53 #include <string.h>
54
55 #define VPX_CODEC_DISABLE_COMPAT 1 55 #define VPX_CODEC_DISABLE_COMPAT 1
56 #include "vpx/vpx_encoder.h" 56 #include "vpx/vpx_encoder.h"
57 #include "vpx/vp8cx.h"
58 #define interface (vpx_codec_vp8_cx())
59 #define fourcc 0x30385056
60 57
61 #define IVF_FILE_HDR_SZ (32) 58 #include "./tools_common.h"
62 #define IVF_FRAME_HDR_SZ (12) 59 #include "./video_writer.h"
63 60
64 static void mem_put_le16(char *mem, unsigned int val) { 61 static const char *exec_name;
65 mem[0] = val; 62
66 mem[1] = val>>8; 63 void usage_exit() {
64 fprintf(stderr, "Usage: %s <codec> <width> <height> <infile> <outfile>\n",
65 exec_name);
66 exit(EXIT_FAILURE);
67 } 67 }
68 68
69 static void mem_put_le32(char *mem, unsigned int val) { 69 static void get_frame_stats(vpx_codec_ctx_t *ctx,
70 mem[0] = val; 70 const vpx_image_t *img,
71 mem[1] = val>>8; 71 vpx_codec_pts_t pts,
72 mem[2] = val>>16; 72 uint64_t duration,
73 mem[3] = val>>24; 73 vpx_enc_frame_flags_t flags,
74 uint64_t deadline,
75 vpx_fixed_buf_t *stats) {
76 vpx_codec_iter_t iter = NULL;
77 const vpx_codec_cx_pkt_t *pkt = NULL;
78 const vpx_codec_err_t res = vpx_codec_encode(ctx, img, pts, duration, flags,
79 deadline);
80 if (res != VPX_CODEC_OK)
81 die_codec(ctx, "Failed to get frame stats.");
82
83 while ((pkt = vpx_codec_get_cx_data(ctx, &iter)) != NULL) {
84 if (pkt->kind == VPX_CODEC_STATS_PKT) {
85 const uint8_t *const pkt_buf = pkt->data.twopass_stats.buf;
86 const size_t pkt_size = pkt->data.twopass_stats.sz;
87 stats->buf = realloc(stats->buf, stats->sz + pkt_size);
88 memcpy((uint8_t *)stats->buf + stats->sz, pkt_buf, pkt_size);
89 stats->sz += pkt_size;
90 }
91 }
74 } 92 }
75 93
76 static void die(const char *fmt, ...) { 94 static void encode_frame(vpx_codec_ctx_t *ctx,
77 va_list ap; 95 const vpx_image_t *img,
96 vpx_codec_pts_t pts,
97 uint64_t duration,
98 vpx_enc_frame_flags_t flags,
99 uint64_t deadline,
100 VpxVideoWriter *writer) {
101 vpx_codec_iter_t iter = NULL;
102 const vpx_codec_cx_pkt_t *pkt = NULL;
103 const vpx_codec_err_t res = vpx_codec_encode(ctx, img, pts, duration, flags,
104 deadline);
105 if (res != VPX_CODEC_OK)
106 die_codec(ctx, "Failed to encode frame.");
78 107
79 va_start(ap, fmt); 108 while ((pkt = vpx_codec_get_cx_data(ctx, &iter)) != NULL) {
80 vprintf(fmt, ap); 109 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
81 if(fmt[strlen(fmt)-1] != '\n') 110 const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
82 printf("\n");
83 exit(EXIT_FAILURE);
84 }
85 111
86 static void die_codec(vpx_codec_ctx_t *ctx, const char *s) { 112 if (!vpx_video_writer_write_frame(writer, pkt->data.frame.buf,
87 const char *detail = vpx_codec_error_detail(ctx); 113 pkt->data.frame.sz,
88 114 pkt->data.frame.pts))
89 printf("%s: %s\n", s, vpx_codec_error(ctx)); 115 die_codec(ctx, "Failed to write compressed frame.");
90 if(detail) 116 printf(keyframe ? "K" : ".");
91 printf(" %s\n",detail); 117 fflush(stdout);
92 exit(EXIT_FAILURE);
93 }
94
95 static int read_frame(FILE *f, vpx_image_t *img) {
96 size_t nbytes, to_read;
97 int res = 1;
98
99 to_read = img->w*img->h*3/2;
100 nbytes = fread(img->planes[0], 1, to_read, f);
101 if(nbytes != to_read) {
102 res = 0;
103 if(nbytes > 0)
104 printf("Warning: Read partial frame. Check your width & height!\n");
105 } 118 }
106 return res; 119 }
107 }
108
109 static void write_ivf_file_header(FILE *outfile,
110 const vpx_codec_enc_cfg_t *cfg,
111 int frame_cnt) {
112 char header[32];
113
114 if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS)
115 return;
116 header[0] = 'D';
117 header[1] = 'K';
118 header[2] = 'I';
119 header[3] = 'F';
120 mem_put_le16(header+4, 0); /* version */
121 mem_put_le16(header+6, 32); /* headersize */
122 mem_put_le32(header+8, fourcc); /* headersize */
123 mem_put_le16(header+12, cfg->g_w); /* width */
124 mem_put_le16(header+14, cfg->g_h); /* height */
125 mem_put_le32(header+16, cfg->g_timebase.den); /* rate */
126 mem_put_le32(header+20, cfg->g_timebase.num); /* scale */
127 mem_put_le32(header+24, frame_cnt); /* length */
128 mem_put_le32(header+28, 0); /* unused */
129
130 (void) fwrite(header, 1, 32, outfile);
131 }
132
133
134 static void write_ivf_frame_header(FILE *outfile,
135 const vpx_codec_cx_pkt_t *pkt)
136 {
137 char header[12];
138 vpx_codec_pts_t pts;
139
140 if(pkt->kind != VPX_CODEC_CX_FRAME_PKT)
141 return;
142
143 pts = pkt->data.frame.pts;
144 mem_put_le32(header, pkt->data.frame.sz);
145 mem_put_le32(header+4, pts&0xFFFFFFFF);
146 mem_put_le32(header+8, pts >> 32);
147
148 (void) fwrite(header, 1, 12, outfile);
149 } 120 }
150 121
151 int main(int argc, char **argv) { 122 int main(int argc, char **argv) {
152 FILE *infile, *outfile; 123 FILE *infile = NULL;
153 vpx_codec_ctx_t codec; 124 VpxVideoWriter *writer = NULL;
154 vpx_codec_enc_cfg_t cfg; 125 vpx_codec_ctx_t codec;
155 int frame_cnt = 0; 126 vpx_codec_enc_cfg_t cfg;
156 vpx_image_t raw; 127 vpx_image_t raw;
157 vpx_codec_err_t res; 128 vpx_codec_err_t res;
158 long width; 129 vpx_fixed_buf_t stats = {0};
159 long height; 130 VpxVideoInfo info = {0};
160 int frame_avail; 131 const VpxInterface *encoder = NULL;
161 int got_data; 132 int pass;
162 int flags = 0; 133 const int fps = 30; // TODO(dkovalev) add command line argument
163 int pass; 134 const int bitrate = 200; // kbit/s TODO(dkovalev) add command line argument
164 vpx_fixed_buf_t stats = {0}; 135 const char *const codec_arg = argv[1];
136 const char *const width_arg = argv[2];
137 const char *const height_arg = argv[3];
138 const char *const infile_arg = argv[4];
139 const char *const outfile_arg = argv[5];
140 exec_name = argv[0];
165 141
166 /* Open files */ 142 if (argc != 6)
167 if(argc!=5) 143 die("Invalid number of arguments.");
168 die("Usage: %s <width> <height> <infile> <outfile>\n", argv[0]);
169 width = strtol(argv[1], NULL, 0);
170 height = strtol(argv[2], NULL, 0);
171 if(width < 16 || width%2 || height <16 || height%2)
172 die("Invalid resolution: %ldx%ld", width, height);
173 if(!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 1))
174 die("Faile to allocate image", width, height);
175 if(!(outfile = fopen(argv[4], "wb")))
176 die("Failed to open %s for writing", argv[4]);
177 144
178 printf("Using %s\n",vpx_codec_iface_name(interface)); 145 encoder = get_vpx_encoder_by_name(codec_arg);
146 if (!encoder)
147 die("Unsupported codec.");
179 148
180 /* Populate encoder configuration */ 149 info.codec_fourcc = encoder->fourcc;
181 res = vpx_codec_enc_config_default(interface, &cfg, 0); 150 info.time_base.numerator = 1;
182 if(res) { 151 info.time_base.denominator = fps;
183 printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); 152 info.frame_width = strtol(width_arg, NULL, 0);
184 return EXIT_FAILURE; 153 info.frame_height = strtol(height_arg, NULL, 0);
154
155 if (info.frame_width <= 0 ||
156 info.frame_height <= 0 ||
157 (info.frame_width % 2) != 0 ||
158 (info.frame_height % 2) != 0) {
159 die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
160 }
161
162 if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width,
163 info.frame_height, 1)) {
164 die("Failed to allocate image", info.frame_width, info.frame_height);
165 }
166
167 writer = vpx_video_writer_open(outfile_arg, kContainerIVF, &info);
168 if (!writer)
169 die("Failed to open %s for writing", outfile_arg);
170
171 printf("Using %s\n", vpx_codec_iface_name(encoder->interface()));
172
173 res = vpx_codec_enc_config_default(encoder->interface(), &cfg, 0);
174 if (res)
175 die_codec(&codec, "Failed to get default codec config.");
176
177 cfg.g_w = info.frame_width;
178 cfg.g_h = info.frame_height;
179 cfg.g_timebase.num = info.time_base.numerator;
180 cfg.g_timebase.den = info.time_base.denominator;
181 cfg.rc_target_bitrate = bitrate;
182
183 for (pass = 0; pass < 2; ++pass) {
184 int frame_count = 0;
185
186 if (pass == 0) {
187 cfg.g_pass = VPX_RC_FIRST_PASS;
188 } else {
189 cfg.g_pass = VPX_RC_LAST_PASS;
190 cfg.rc_twopass_stats_in = stats;
185 } 191 }
186 192
187 /* Update the default configuration with our settings */ 193 if (!(infile = fopen(infile_arg, "rb")))
188 cfg.rc_target_bitrate = width * height * cfg.rc_target_bitrate 194 die("Failed to open %s for reading", infile_arg);
189 / cfg.g_w / cfg.g_h;
190 cfg.g_w = width;
191 cfg.g_h = height;
192 195
193 write_ivf_file_header(outfile, &cfg, 0); 196 if (vpx_codec_enc_init(&codec, encoder->interface(), &cfg, 0))
197 die_codec(&codec, "Failed to initialize encoder");
194 198
195 for(pass=0; pass<2; pass++) { 199 while (vpx_img_read(&raw, infile)) {
196 frame_cnt = 0; 200 ++frame_count;
197 201
198 if(pass == 0) 202 if (pass == 0) {
199 cfg.g_pass = VPX_RC_FIRST_PASS; 203 get_frame_stats(&codec, &raw, frame_count, 1, 0, VPX_DL_BEST_QUALITY,
200 else { 204 &stats);
201 cfg.g_pass = VPX_RC_LAST_PASS; 205 } else {
202 cfg.rc_twopass_stats_in = stats; 206 encode_frame(&codec, &raw, frame_count, 1, 0, VPX_DL_BEST_QUALITY,
203 } 207 writer);
204 208 }
205 /* Open input file for this encoding pass */
206 if(!(infile = fopen(argv[3], "rb")))
207 die("Failed to open %s for reading", argv[3]);
208
209 /* Initialize codec */
210 if(vpx_codec_enc_init(&codec, interface, &cfg, 0))
211 die_codec(&codec, "Failed to initialize encoder");
212
213 frame_avail = 1;
214 got_data = 0;
215 while(frame_avail || got_data) {
216 vpx_codec_iter_t iter = NULL;
217 const vpx_codec_cx_pkt_t *pkt;
218
219 frame_avail = read_frame(infile, &raw);
220 if(vpx_codec_encode(&codec, frame_avail? &raw : NULL, frame_cnt,
221 1, flags, VPX_DL_BEST_QUALITY))
222 die_codec(&codec, "Failed to encode frame");
223 got_data = 0;
224 while( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) {
225 got_data = 1;
226 switch(pkt->kind) {
227 case VPX_CODEC_CX_FRAME_PKT:
228 write_ivf_frame_header(outfile, pkt);
229 (void) fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz,
230 outfile);
231 break;
232 case VPX_CODEC_STATS_PKT:
233 stats.buf = realloc(stats.buf, stats.sz
234 + pkt->data.twopass_stats.sz);
235 if(!stats.buf)
236 die("Memory reallocation failed.\n");
237 memcpy((char*)stats.buf + stats.sz,
238 pkt->data.twopass_stats.buf,
239 pkt->data.twopass_stats.sz);
240 stats.sz += pkt->data.twopass_stats.sz;
241 break;
242 default:
243 break;
244 }
245 printf(pkt->kind == VPX_CODEC_CX_FRAME_PKT
246 && (pkt->data.frame.flags & VPX_FRAME_IS_KEY)? "K":".");
247 fflush(stdout);
248 }
249 frame_cnt++;
250 }
251 printf("\n");
252 fclose(infile);
253 printf("Pass %d complete.\n", pass+1);
254 if(vpx_codec_destroy(&codec))
255 die_codec(&codec, "Failed to destroy codec");
256 } 209 }
257 210
258 printf("Processed %d frames.\n",frame_cnt-1); 211 if (pass == 0) {
259 vpx_img_free(&raw); 212 get_frame_stats(&codec, NULL, frame_count, 1, 0, VPX_DL_BEST_QUALITY,
260 free(stats.buf); 213 &stats);
214 } else {
215 printf("\n");
216 }
261 217
262 /* Try to rewrite the file header with the actual frame count */ 218 fclose(infile);
263 if(!fseek(outfile, 0, SEEK_SET)) 219 printf("Pass %d complete. Processed %d frames.\n", pass + 1, frame_count);
264 write_ivf_file_header(outfile, &cfg, frame_cnt-1); 220 if (vpx_codec_destroy(&codec))
265 fclose(outfile); 221 die_codec(&codec, "Failed to destroy codec.");
266 return EXIT_SUCCESS; 222 }
223
224 vpx_img_free(&raw);
225 free(stats.buf);
226
227 vpx_video_writer_close(writer);
228
229 return EXIT_SUCCESS;
267 } 230 }
OLDNEW
« no previous file with comments | « source/libvpx/examples/simple_encoder.c ('k') | source/libvpx/examples/vp8_set_maps.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698