00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 #include <stdio.h>
00050 #include <stdlib.h>
00051 #include <string.h>
00052
00053 #include "vpx/vp8cx.h"
00054 #include "vpx/vpx_decoder.h"
00055 #include "vpx/vpx_encoder.h"
00056 #include "vp9/common/vp9_common.h"
00057
00058 #include "./tools_common.h"
00059 #include "./video_writer.h"
00060
00061 static const char *exec_name;
00062
00063 void usage_exit() {
00064 fprintf(stderr,
00065 "Usage: %s <width> <height> <infile> <outfile> "
00066 "<frame> <limit(optional)>\n",
00067 exec_name);
00068 exit(EXIT_FAILURE);
00069 }
00070
00071 static int compare_img(const vpx_image_t *const img1,
00072 const vpx_image_t *const img2) {
00073 uint32_t l_w = img1->d_w;
00074 uint32_t c_w = (img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift;
00075 const uint32_t c_h =
00076 (img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift;
00077 uint32_t i;
00078 int match = 1;
00079
00080 match &= (img1->fmt == img2->fmt);
00081 match &= (img1->d_w == img2->d_w);
00082 match &= (img1->d_h == img2->d_h);
00083
00084 for (i = 0; i < img1->d_h; ++i)
00085 match &= (memcmp(img1->planes[VPX_PLANE_Y] + i * img1->stride[VPX_PLANE_Y],
00086 img2->planes[VPX_PLANE_Y] + i * img2->stride[VPX_PLANE_Y],
00087 l_w) == 0);
00088
00089 for (i = 0; i < c_h; ++i)
00090 match &= (memcmp(img1->planes[VPX_PLANE_U] + i * img1->stride[VPX_PLANE_U],
00091 img2->planes[VPX_PLANE_U] + i * img2->stride[VPX_PLANE_U],
00092 c_w) == 0);
00093
00094 for (i = 0; i < c_h; ++i)
00095 match &= (memcmp(img1->planes[VPX_PLANE_V] + i * img1->stride[VPX_PLANE_V],
00096 img2->planes[VPX_PLANE_V] + i * img2->stride[VPX_PLANE_V],
00097 c_w) == 0);
00098
00099 return match;
00100 }
00101
00102 #define mmin(a, b) ((a) < (b) ? (a) : (b))
00103 static void find_mismatch(const vpx_image_t *const img1,
00104 const vpx_image_t *const img2, int yloc[4],
00105 int uloc[4], int vloc[4]) {
00106 const uint32_t bsize = 64;
00107 const uint32_t bsizey = bsize >> img1->y_chroma_shift;
00108 const uint32_t bsizex = bsize >> img1->x_chroma_shift;
00109 const uint32_t c_w =
00110 (img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift;
00111 const uint32_t c_h =
00112 (img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift;
00113 int match = 1;
00114 uint32_t i, j;
00115 yloc[0] = yloc[1] = yloc[2] = yloc[3] = -1;
00116 for (i = 0, match = 1; match && i < img1->d_h; i += bsize) {
00117 for (j = 0; match && j < img1->d_w; j += bsize) {
00118 int k, l;
00119 const int si = mmin(i + bsize, img1->d_h) - i;
00120 const int sj = mmin(j + bsize, img1->d_w) - j;
00121 for (k = 0; match && k < si; ++k) {
00122 for (l = 0; match && l < sj; ++l) {
00123 if (*(img1->planes[VPX_PLANE_Y] +
00124 (i + k) * img1->stride[VPX_PLANE_Y] + j + l) !=
00125 *(img2->planes[VPX_PLANE_Y] +
00126 (i + k) * img2->stride[VPX_PLANE_Y] + j + l)) {
00127 yloc[0] = i + k;
00128 yloc[1] = j + l;
00129 yloc[2] = *(img1->planes[VPX_PLANE_Y] +
00130 (i + k) * img1->stride[VPX_PLANE_Y] + j + l);
00131 yloc[3] = *(img2->planes[VPX_PLANE_Y] +
00132 (i + k) * img2->stride[VPX_PLANE_Y] + j + l);
00133 match = 0;
00134 break;
00135 }
00136 }
00137 }
00138 }
00139 }
00140
00141 uloc[0] = uloc[1] = uloc[2] = uloc[3] = -1;
00142 for (i = 0, match = 1; match && i < c_h; i += bsizey) {
00143 for (j = 0; match && j < c_w; j += bsizex) {
00144 int k, l;
00145 const int si = mmin(i + bsizey, c_h - i);
00146 const int sj = mmin(j + bsizex, c_w - j);
00147 for (k = 0; match && k < si; ++k) {
00148 for (l = 0; match && l < sj; ++l) {
00149 if (*(img1->planes[VPX_PLANE_U] +
00150 (i + k) * img1->stride[VPX_PLANE_U] + j + l) !=
00151 *(img2->planes[VPX_PLANE_U] +
00152 (i + k) * img2->stride[VPX_PLANE_U] + j + l)) {
00153 uloc[0] = i + k;
00154 uloc[1] = j + l;
00155 uloc[2] = *(img1->planes[VPX_PLANE_U] +
00156 (i + k) * img1->stride[VPX_PLANE_U] + j + l);
00157 uloc[3] = *(img2->planes[VPX_PLANE_U] +
00158 (i + k) * img2->stride[VPX_PLANE_U] + j + l);
00159 match = 0;
00160 break;
00161 }
00162 }
00163 }
00164 }
00165 }
00166 vloc[0] = vloc[1] = vloc[2] = vloc[3] = -1;
00167 for (i = 0, match = 1; match && i < c_h; i += bsizey) {
00168 for (j = 0; match && j < c_w; j += bsizex) {
00169 int k, l;
00170 const int si = mmin(i + bsizey, c_h - i);
00171 const int sj = mmin(j + bsizex, c_w - j);
00172 for (k = 0; match && k < si; ++k) {
00173 for (l = 0; match && l < sj; ++l) {
00174 if (*(img1->planes[VPX_PLANE_V] +
00175 (i + k) * img1->stride[VPX_PLANE_V] + j + l) !=
00176 *(img2->planes[VPX_PLANE_V] +
00177 (i + k) * img2->stride[VPX_PLANE_V] + j + l)) {
00178 vloc[0] = i + k;
00179 vloc[1] = j + l;
00180 vloc[2] = *(img1->planes[VPX_PLANE_V] +
00181 (i + k) * img1->stride[VPX_PLANE_V] + j + l);
00182 vloc[3] = *(img2->planes[VPX_PLANE_V] +
00183 (i + k) * img2->stride[VPX_PLANE_V] + j + l);
00184 match = 0;
00185 break;
00186 }
00187 }
00188 }
00189 }
00190 }
00191 }
00192
00193 static void testing_decode(vpx_codec_ctx_t *encoder, vpx_codec_ctx_t *decoder,
00194 unsigned int frame_out, int *mismatch_seen) {
00195 vpx_image_t enc_img, dec_img;
00196 struct vp9_ref_frame ref_enc, ref_dec;
00197
00198 if (*mismatch_seen) return;
00199
00200 ref_enc.idx = 0;
00201 ref_dec.idx = 0;
00202 if (vpx_codec_control(encoder, VP9_GET_REFERENCE, &ref_enc))
00203 die_codec(encoder, "Failed to get encoder reference frame");
00204 enc_img = ref_enc.img;
00205 if (vpx_codec_control(decoder, VP9_GET_REFERENCE, &ref_dec))
00206 die_codec(decoder, "Failed to get decoder reference frame");
00207 dec_img = ref_dec.img;
00208
00209 if (!compare_img(&enc_img, &dec_img)) {
00210 int y[4], u[4], v[4];
00211
00212 *mismatch_seen = 1;
00213
00214 find_mismatch(&enc_img, &dec_img, y, u, v);
00215 printf(
00216 "Encode/decode mismatch on frame %d at"
00217 " Y[%d, %d] {%d/%d},"
00218 " U[%d, %d] {%d/%d},"
00219 " V[%d, %d] {%d/%d}",
00220 frame_out, y[0], y[1], y[2], y[3], u[0], u[1], u[2], u[3], v[0], v[1],
00221 v[2], v[3]);
00222 }
00223
00224 vpx_img_free(&enc_img);
00225 vpx_img_free(&dec_img);
00226 }
00227
00228 static int encode_frame(vpx_codec_ctx_t *ecodec, vpx_image_t *img,
00229 unsigned int frame_in, VpxVideoWriter *writer,
00230 int test_decode, vpx_codec_ctx_t *dcodec,
00231 unsigned int *frame_out, int *mismatch_seen) {
00232 int got_pkts = 0;
00233 vpx_codec_iter_t iter = NULL;
00234 const vpx_codec_cx_pkt_t *pkt = NULL;
00235 int got_data;
00236 const vpx_codec_err_t res =
00237 vpx_codec_encode(ecodec, img, frame_in, 1, 0, VPX_DL_GOOD_QUALITY);
00238 if (res != VPX_CODEC_OK) die_codec(ecodec, "Failed to encode frame");
00239
00240 got_data = 0;
00241
00242 while ((pkt = vpx_codec_get_cx_data(ecodec, &iter)) != NULL) {
00243 got_pkts = 1;
00244
00245 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
00246 const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
00247
00248 if (!(pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT)) {
00249 *frame_out += 1;
00250 }
00251
00252 if (!vpx_video_writer_write_frame(writer, pkt->data.frame.buf,
00253 pkt->data.frame.sz,
00254 pkt->data.frame.pts)) {
00255 die_codec(ecodec, "Failed to write compressed frame");
00256 }
00257 printf(keyframe ? "K" : ".");
00258 fflush(stdout);
00259 got_data = 1;
00260
00261
00262 if (test_decode) {
00263 if (vpx_codec_decode(dcodec, pkt->data.frame.buf,
00264 (unsigned int)pkt->data.frame.sz, NULL, 0))
00265 die_codec(dcodec, "Failed to decode frame.");
00266 }
00267 }
00268 }
00269
00270
00271 if (got_data && test_decode) {
00272 testing_decode(ecodec, dcodec, *frame_out, mismatch_seen);
00273 }
00274
00275 return got_pkts;
00276 }
00277
00278 int main(int argc, char **argv) {
00279 FILE *infile = NULL;
00280
00281 vpx_codec_ctx_t ecodec;
00282 vpx_codec_enc_cfg_t cfg;
00283 unsigned int frame_in = 0;
00284 vpx_image_t raw;
00285 vpx_codec_err_t res;
00286 VpxVideoInfo info;
00287 VpxVideoWriter *writer = NULL;
00288 const VpxInterface *encoder = NULL;
00289
00290
00291 int test_decode = 1;
00292
00293 vpx_codec_ctx_t dcodec;
00294 unsigned int frame_out = 0;
00295
00296
00297 unsigned int update_frame_num = 0;
00298 int mismatch_seen = 0;
00299
00300 const int fps = 30;
00301 const int bitrate = 500;
00302
00303 const char *width_arg = NULL;
00304 const char *height_arg = NULL;
00305 const char *infile_arg = NULL;
00306 const char *outfile_arg = NULL;
00307 const char *update_frame_num_arg = NULL;
00308 unsigned int limit = 0;
00309
00310 vp9_zero(ecodec);
00311 vp9_zero(cfg);
00312 vp9_zero(info);
00313
00314 exec_name = argv[0];
00315
00316 if (argc < 6) die("Invalid number of arguments");
00317
00318 width_arg = argv[1];
00319 height_arg = argv[2];
00320 infile_arg = argv[3];
00321 outfile_arg = argv[4];
00322 update_frame_num_arg = argv[5];
00323
00324 encoder = get_vpx_encoder_by_name("vp9");
00325 if (!encoder) die("Unsupported codec.");
00326
00327 update_frame_num = (unsigned int)strtoul(update_frame_num_arg, NULL, 0);
00328
00329
00330
00331 if (update_frame_num <= 1) {
00332 die("Couldn't parse frame number '%s'\n", update_frame_num_arg);
00333 }
00334
00335 if (argc > 6) {
00336 limit = (unsigned int)strtoul(argv[6], NULL, 0);
00337 if (update_frame_num > limit)
00338 die("Update frame number couldn't larger than limit\n");
00339 }
00340
00341 info.codec_fourcc = encoder->fourcc;
00342 info.frame_width = (int)strtol(width_arg, NULL, 0);
00343 info.frame_height = (int)strtol(height_arg, NULL, 0);
00344 info.time_base.numerator = 1;
00345 info.time_base.denominator = fps;
00346
00347 if (info.frame_width <= 0 || info.frame_height <= 0 ||
00348 (info.frame_width % 2) != 0 || (info.frame_height % 2) != 0) {
00349 die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
00350 }
00351
00352 if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width,
00353 info.frame_height, 1)) {
00354 die("Failed to allocate image.");
00355 }
00356
00357 printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface()));
00358
00359 res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
00360 if (res) die_codec(&ecodec, "Failed to get default codec config.");
00361
00362 cfg.g_w = info.frame_width;
00363 cfg.g_h = info.frame_height;
00364 cfg.g_timebase.num = info.time_base.numerator;
00365 cfg.g_timebase.den = info.time_base.denominator;
00366 cfg.rc_target_bitrate = bitrate;
00367 cfg.g_lag_in_frames = 3;
00368
00369 writer = vpx_video_writer_open(outfile_arg, kContainerIVF, &info);
00370 if (!writer) die("Failed to open %s for writing.", outfile_arg);
00371
00372 if (!(infile = fopen(infile_arg, "rb")))
00373 die("Failed to open %s for reading.", infile_arg);
00374
00375 if (vpx_codec_enc_init(&ecodec, encoder->codec_interface(), &cfg, 0))
00376 die_codec(&ecodec, "Failed to initialize encoder");
00377
00378
00379 if (vpx_codec_control(&ecodec, VP8E_SET_ENABLEAUTOALTREF, 0))
00380 die_codec(&ecodec, "Failed to set enable auto alt ref");
00381
00382 if (test_decode) {
00383 const VpxInterface *decoder = get_vpx_decoder_by_name("vp9");
00384 if (vpx_codec_dec_init(&dcodec, decoder->codec_interface(), NULL, 0))
00385 die_codec(&dcodec, "Failed to initialize decoder.");
00386 }
00387
00388
00389 while (vpx_img_read(&raw, infile)) {
00390 if (limit && frame_in >= limit) break;
00391 if (update_frame_num > 1 && frame_out + 1 == update_frame_num) {
00392 vpx_ref_frame_t ref;
00393 ref.frame_type = VP8_LAST_FRAME;
00394 ref.img = raw;
00395
00396 if (vpx_codec_control(&ecodec, VP8_SET_REFERENCE, &ref))
00397 die_codec(&ecodec, "Failed to set reference frame");
00398 printf(" <SET_REF>");
00399
00400
00401
00402 if (test_decode) {
00403 if (vpx_codec_control(&dcodec, VP8_SET_REFERENCE, &ref))
00404 die_codec(&dcodec, "Failed to set reference frame");
00405 }
00406 }
00407
00408 encode_frame(&ecodec, &raw, frame_in, writer, test_decode, &dcodec,
00409 &frame_out, &mismatch_seen);
00410 frame_in++;
00411 if (mismatch_seen) break;
00412 }
00413
00414
00415 if (!mismatch_seen)
00416 while (encode_frame(&ecodec, NULL, frame_in, writer, test_decode, &dcodec,
00417 &frame_out, &mismatch_seen)) {
00418 }
00419
00420 printf("\n");
00421 fclose(infile);
00422 printf("Processed %d frames.\n", frame_out);
00423
00424 if (test_decode) {
00425 if (!mismatch_seen)
00426 printf("Encoder/decoder results are matching.\n");
00427 else
00428 printf("Encoder/decoder results are NOT matching.\n");
00429 }
00430
00431 if (test_decode)
00432 if (vpx_codec_destroy(&dcodec))
00433 die_codec(&dcodec, "Failed to destroy decoder");
00434
00435 vpx_img_free(&raw);
00436 if (vpx_codec_destroy(&ecodec))
00437 die_codec(&ecodec, "Failed to destroy encoder.");
00438
00439 vpx_video_writer_close(writer);
00440
00441 return EXIT_SUCCESS;
00442 }