diff options
Diffstat (limited to 'third_party/aom/examples')
20 files changed, 2041 insertions, 506 deletions
diff --git a/third_party/aom/examples/analyzer.cc b/third_party/aom/examples/analyzer.cc index ae0801964..6a42eca24 100644 --- a/third_party/aom/examples/analyzer.cc +++ b/third_party/aom/examples/analyzer.cc @@ -12,13 +12,14 @@ #include <wx/aboutdlg.h> #include <wx/cmdline.h> #include <wx/dcbuffer.h> -#include "./tools_common.h" -#include "./video_reader.h" + #include "aom/aom_decoder.h" #include "aom/aomdx.h" -#include "av1/decoder/accounting.h" #include "av1/common/onyxc_int.h" +#include "av1/decoder/accounting.h" #include "av1/decoder/inspection.h" +#include "common/tools_common.h" +#include "common/video_reader.h" #define OD_SIGNMASK(a) (-((a) < 0)) #define OD_FLIPSIGNI(a, b) (((a) + OD_SIGNMASK(b)) ^ OD_SIGNMASK(b)) @@ -108,7 +109,7 @@ bool AV1Decoder::step() { size_t frame_size; const unsigned char *frame_data; frame_data = aom_video_reader_get_frame(reader, &frame_size); - if (aom_codec_decode(&codec, frame_data, frame_size, NULL, 0)) { + if (aom_codec_decode(&codec, frame_data, frame_size, NULL)) { fprintf(stderr, "Failed to decode frame."); return false; } else { @@ -129,11 +130,10 @@ int AV1Decoder::getWidth() const { } int AV1Decoder::getWidthPadding() const { - return show_padding - ? AOMMAX(info->frame_width + 16, - ALIGN_POWER_OF_TWO(info->frame_width, 6)) - - info->frame_width - : 0; + return show_padding ? AOMMAX(info->frame_width + 16, + ALIGN_POWER_OF_TWO(info->frame_width, 6)) - + info->frame_width + : 0; } int AV1Decoder::getHeight() const { @@ -141,11 +141,10 @@ int AV1Decoder::getHeight() const { } int AV1Decoder::getHeightPadding() const { - return show_padding - ? AOMMAX(info->frame_height + 16, - ALIGN_POWER_OF_TWO(info->frame_height, 6)) - - info->frame_height - : 0; + return show_padding ? AOMMAX(info->frame_height + 16, + ALIGN_POWER_OF_TWO(info->frame_height, 6)) - + info->frame_height + : 0; } bool AV1Decoder::getAccountingStruct(Accounting **accounting) { @@ -285,19 +284,22 @@ void AnalyzerPanel::render() { cbval = ((pmask & OD_CB_MASK) >> 1) * (cbval - 128); crval = ((pmask & OD_CR_MASK) >> 2) * (crval - 128); /*This is intentionally slow and very accurate.*/ - rval = OD_CLAMPI(0, (int32_t)OD_DIV_ROUND( - 2916394880000LL * yval + 4490222169144LL * crval, - 9745792000LL), - 65535); - gval = OD_CLAMPI(0, (int32_t)OD_DIV_ROUND(2916394880000LL * yval - - 534117096223LL * cbval - - 1334761232047LL * crval, - 9745792000LL), - 65535); - bval = OD_CLAMPI(0, (int32_t)OD_DIV_ROUND( - 2916394880000LL * yval + 5290866304968LL * cbval, - 9745792000LL), + rval = OD_CLAMPI( + 0, + (int32_t)OD_DIV_ROUND( + 2916394880000LL * yval + 4490222169144LL * crval, 9745792000LL), + 65535); + gval = OD_CLAMPI(0, + (int32_t)OD_DIV_ROUND(2916394880000LL * yval - + 534117096223LL * cbval - + 1334761232047LL * crval, + 9745792000LL), 65535); + bval = OD_CLAMPI( + 0, + (int32_t)OD_DIV_ROUND( + 2916394880000LL * yval + 5290866304968LL * cbval, 9745792000LL), + 65535); unsigned char *px_row = p; for (int v = 0; v < zoom; v++) { unsigned char *px = px_row; @@ -701,8 +703,8 @@ bool Analyzer::OnCmdLineParsed(wxCmdLineParser &parser) { // NOLINT bool bit_accounting = parser.Found(_("a")); if (bit_accounting && !CONFIG_ACCOUNTING) { fprintf(stderr, - "Bit accounting support not found. " - "Recompile with:\n./configure --enable-accounting\n"); + "Bit accounting support not found. " + "Recompile with:\n./cmake -DCONFIG_ACCOUNTING=1\n"); return false; } frame = new AnalyzerFrame(parser.Found(_("a"))); diff --git a/third_party/aom/examples/aom_cx_set_ref.c b/third_party/aom/examples/aom_cx_set_ref.c index 456e81300..e02e94c07 100644 --- a/third_party/aom/examples/aom_cx_set_ref.c +++ b/third_party/aom/examples/aom_cx_set_ref.c @@ -51,12 +51,14 @@ #include <stdlib.h> #include <string.h> -#include "aom/aomcx.h" #include "aom/aom_decoder.h" #include "aom/aom_encoder.h" +#include "aom/aomcx.h" +#include "common/tools_common.h" +#include "common/video_writer.h" #include "examples/encoder_util.h" -#include "./tools_common.h" -#include "./video_writer.h" + +#define AOM_BORDER_IN_PIXELS 288 static const char *exec_name; @@ -71,25 +73,41 @@ void usage_exit() { static void testing_decode(aom_codec_ctx_t *encoder, aom_codec_ctx_t *decoder, unsigned int frame_out, int *mismatch_seen) { aom_image_t enc_img, dec_img; - struct av1_ref_frame ref_enc, ref_dec; if (*mismatch_seen) return; - ref_enc.idx = 0; - ref_dec.idx = 0; - if (aom_codec_control(encoder, AV1_GET_REFERENCE, &ref_enc)) + /* Get the internal reference frame */ + if (aom_codec_control(encoder, AV1_GET_NEW_FRAME_IMAGE, &enc_img)) die_codec(encoder, "Failed to get encoder reference frame"); - enc_img = ref_enc.img; - if (aom_codec_control(decoder, AV1_GET_REFERENCE, &ref_dec)) + if (aom_codec_control(decoder, AV1_GET_NEW_FRAME_IMAGE, &dec_img)) die_codec(decoder, "Failed to get decoder reference frame"); - dec_img = ref_dec.img; + + if ((enc_img.fmt & AOM_IMG_FMT_HIGHBITDEPTH) != + (dec_img.fmt & AOM_IMG_FMT_HIGHBITDEPTH)) { + if (enc_img.fmt & AOM_IMG_FMT_HIGHBITDEPTH) { + aom_image_t enc_hbd_img; + aom_img_alloc(&enc_hbd_img, enc_img.fmt - AOM_IMG_FMT_HIGHBITDEPTH, + enc_img.d_w, enc_img.d_h, 16); + aom_img_truncate_16_to_8(&enc_hbd_img, &enc_img); + enc_img = enc_hbd_img; + } + if (dec_img.fmt & AOM_IMG_FMT_HIGHBITDEPTH) { + aom_image_t dec_hbd_img; + aom_img_alloc(&dec_hbd_img, dec_img.fmt - AOM_IMG_FMT_HIGHBITDEPTH, + dec_img.d_w, dec_img.d_h, 16); + aom_img_truncate_16_to_8(&dec_hbd_img, &dec_img); + dec_img = dec_hbd_img; + } + } if (!aom_compare_img(&enc_img, &dec_img)) { int y[4], u[4], v[4]; + if (enc_img.fmt & AOM_IMG_FMT_HIGHBITDEPTH) { + aom_find_mismatch_high(&enc_img, &dec_img, y, u, v); + } else { + aom_find_mismatch(&enc_img, &dec_img, y, u, v); + } - *mismatch_seen = 1; - - aom_find_mismatch(&enc_img, &dec_img, y, u, v); printf( "Encode/decode mismatch on frame %d at" " Y[%d, %d] {%d/%d}," @@ -97,6 +115,7 @@ static void testing_decode(aom_codec_ctx_t *encoder, aom_codec_ctx_t *decoder, " V[%d, %d] {%d/%d}", frame_out, y[0], y[1], y[2], y[3], u[0], u[1], u[2], u[3], v[0], v[1], v[2], v[3]); + *mismatch_seen = 1; } aom_img_free(&enc_img); @@ -106,13 +125,13 @@ static void testing_decode(aom_codec_ctx_t *encoder, aom_codec_ctx_t *decoder, static int encode_frame(aom_codec_ctx_t *ecodec, aom_image_t *img, unsigned int frame_in, AvxVideoWriter *writer, int test_decode, aom_codec_ctx_t *dcodec, - unsigned int *frame_out, int *mismatch_seen) { + unsigned int *frame_out, int *mismatch_seen, + aom_image_t *ext_ref) { int got_pkts = 0; aom_codec_iter_t iter = NULL; const aom_codec_cx_pkt_t *pkt = NULL; int got_data; - const aom_codec_err_t res = - aom_codec_encode(ecodec, img, frame_in, 1, 0, AOM_DL_GOOD_QUALITY); + const aom_codec_err_t res = aom_codec_encode(ecodec, img, frame_in, 1, 0); if (res != AOM_CODEC_OK) die_codec(ecodec, "Failed to encode frame"); got_data = 0; @@ -139,8 +158,13 @@ static int encode_frame(aom_codec_ctx_t *ecodec, aom_image_t *img, // Decode 1 frame. if (test_decode) { if (aom_codec_decode(dcodec, pkt->data.frame.buf, - (unsigned int)pkt->data.frame.sz, NULL, 0)) + (unsigned int)pkt->data.frame.sz, NULL)) die_codec(dcodec, "Failed to decode frame."); + + // Copy out first decoded frame, and use it as reference later. + if (*frame_out == 1 && ext_ref != NULL) + if (aom_codec_control(dcodec, AV1_GET_NEW_FRAME_IMAGE, ext_ref)) + die_codec(dcodec, "Failed to get decoder new frame"); } } } @@ -160,10 +184,16 @@ int main(int argc, char **argv) { aom_codec_enc_cfg_t cfg; unsigned int frame_in = 0; aom_image_t raw; + aom_image_t raw_shift; + aom_image_t ext_ref; aom_codec_err_t res; AvxVideoInfo info; AvxVideoWriter *writer = NULL; const AvxInterface *encoder = NULL; + int flags = 0; + int allocated_raw_shift = 0; + aom_img_fmt_t raw_fmt = AOM_IMG_FMT_I420; + aom_img_fmt_t ref_fmt = AOM_IMG_FMT_I420; // Test encoder/decoder mismatch. int test_decode = 1; @@ -225,13 +255,21 @@ int main(int argc, char **argv) { info.time_base.numerator = 1; info.time_base.denominator = fps; - if (info.frame_width <= 0 || info.frame_height <= 0 || - (info.frame_width % 2) != 0 || (info.frame_height % 2) != 0) { + if (info.frame_width <= 0 || info.frame_height <= 0) { die("Invalid frame size: %dx%d", info.frame_width, info.frame_height); } - if (!aom_img_alloc(&raw, AOM_IMG_FMT_I420, info.frame_width, - info.frame_height, 1)) { + // In this test, the bit depth of input video is 8-bit, and the input format + // is AOM_IMG_FMT_I420. + if (!aom_img_alloc(&raw, raw_fmt, info.frame_width, info.frame_height, 32)) { + die("Failed to allocate image."); + } + + if (!CONFIG_LOWBITDEPTH) ref_fmt |= AOM_IMG_FMT_HIGHBITDEPTH; + // Allocate memory with the border so that it can be used as a reference. + if (!aom_img_alloc_with_border(&ext_ref, ref_fmt, info.frame_width, + info.frame_height, 32, 8, + AOM_BORDER_IN_PIXELS)) { die("Failed to allocate image."); } @@ -246,6 +284,11 @@ int main(int argc, char **argv) { cfg.g_timebase.den = info.time_base.denominator; cfg.rc_target_bitrate = bitrate; cfg.g_lag_in_frames = 3; + cfg.g_bit_depth = AOM_BITS_8; + + flags |= (cfg.g_bit_depth > AOM_BITS_8 || !CONFIG_LOWBITDEPTH) + ? AOM_CODEC_USE_HIGHBITDEPTH + : 0; writer = aom_video_writer_open(outfile_arg, kContainerIVF, &info); if (!writer) die("Failed to open %s for writing.", outfile_arg); @@ -253,7 +296,7 @@ int main(int argc, char **argv) { if (!(infile = fopen(infile_arg, "rb"))) die("Failed to open %s for reading.", infile_arg); - if (aom_codec_enc_init(&ecodec, encoder->codec_interface(), &cfg, 0)) + if (aom_codec_enc_init(&ecodec, encoder->codec_interface(), &cfg, flags)) die_codec(&ecodec, "Failed to initialize encoder"); // Disable alt_ref. @@ -269,25 +312,43 @@ int main(int argc, char **argv) { // Encode frames. while (aom_img_read(&raw, infile)) { if (limit && frame_in >= limit) break; + aom_image_t *frame_to_encode; + + if (!CONFIG_LOWBITDEPTH) { + // Need to allocate larger buffer to use hbd internal. + int input_shift = 0; + if (!allocated_raw_shift) { + aom_img_alloc(&raw_shift, raw_fmt | AOM_IMG_FMT_HIGHBITDEPTH, + info.frame_width, info.frame_height, 32); + allocated_raw_shift = 1; + } + aom_img_upshift(&raw_shift, &raw, input_shift); + frame_to_encode = &raw_shift; + } else { + frame_to_encode = &raw; + } + if (update_frame_num > 1 && frame_out + 1 == update_frame_num) { av1_ref_frame_t ref; ref.idx = 0; - ref.img = raw; + ref.use_external_ref = 0; + ref.img = ext_ref; // Set reference frame in encoder. if (aom_codec_control(&ecodec, AV1_SET_REFERENCE, &ref)) - die_codec(&ecodec, "Failed to set reference frame"); + die_codec(&ecodec, "Failed to set encoder reference frame"); printf(" <SET_REF>"); // If set_reference in decoder is commented out, the enc/dec mismatch // would be seen. if (test_decode) { + ref.use_external_ref = 1; if (aom_codec_control(&dcodec, AV1_SET_REFERENCE, &ref)) - die_codec(&dcodec, "Failed to set reference frame"); + die_codec(&dcodec, "Failed to set decoder reference frame"); } } - encode_frame(&ecodec, &raw, frame_in, writer, test_decode, &dcodec, - &frame_out, &mismatch_seen); + encode_frame(&ecodec, frame_to_encode, frame_in, writer, test_decode, + &dcodec, &frame_out, &mismatch_seen, &ext_ref); frame_in++; if (mismatch_seen) break; } @@ -295,7 +356,7 @@ int main(int argc, char **argv) { // Flush encoder. if (!mismatch_seen) while (encode_frame(&ecodec, NULL, frame_in, writer, test_decode, &dcodec, - &frame_out, &mismatch_seen)) { + &frame_out, &mismatch_seen, NULL)) { } printf("\n"); @@ -313,6 +374,8 @@ int main(int argc, char **argv) { if (aom_codec_destroy(&dcodec)) die_codec(&dcodec, "Failed to destroy decoder"); + if (allocated_raw_shift) aom_img_free(&raw_shift); + aom_img_free(&ext_ref); aom_img_free(&raw); if (aom_codec_destroy(&ecodec)) die_codec(&ecodec, "Failed to destroy encoder."); diff --git a/third_party/aom/examples/decode_to_md5.c b/third_party/aom/examples/decode_to_md5.c index 5ab253209..bc127b78d 100644 --- a/third_party/aom/examples/decode_to_md5.c +++ b/third_party/aom/examples/decode_to_md5.c @@ -34,13 +34,11 @@ #include <stdlib.h> #include <string.h> -#include "aom/aomdx.h" #include "aom/aom_decoder.h" - -#include "../md5_utils.h" -#include "../tools_common.h" -#include "../video_reader.h" -#include "./aom_config.h" +#include "aom/aomdx.h" +#include "common/md5_utils.h" +#include "common/tools_common.h" +#include "common/video_reader.h" static void get_image_md5(const aom_image_t *img, unsigned char digest[16]) { int plane, y; @@ -110,7 +108,7 @@ int main(int argc, char **argv) { size_t frame_size = 0; const unsigned char *frame = aom_video_reader_get_frame(reader, &frame_size); - if (aom_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0)) + if (aom_codec_decode(&codec, frame, frame_size, NULL)) die_codec(&codec, "Failed to decode frame"); while ((img = aom_codec_get_frame(&codec, &iter)) != NULL) { diff --git a/third_party/aom/examples/decode_with_drops.c b/third_party/aom/examples/decode_with_drops.c index 45e0fb027..214401958 100644 --- a/third_party/aom/examples/decode_with_drops.c +++ b/third_party/aom/examples/decode_with_drops.c @@ -57,12 +57,10 @@ #include <stdlib.h> #include <string.h> -#include "aom/aomdx.h" #include "aom/aom_decoder.h" - -#include "../tools_common.h" -#include "../video_reader.h" -#include "./aom_config.h" +#include "aom/aomdx.h" +#include "common/tools_common.h" +#include "common/video_reader.h" static const char *exec_name; @@ -116,9 +114,6 @@ int main(int argc, char **argv) { int skip; const unsigned char *frame = aom_video_reader_get_frame(reader, &frame_size); - if (aom_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0)) - die_codec(&codec, "Failed to decode frame."); - ++frame_cnt; skip = (is_range && frame_cnt >= n && frame_cnt <= m) || @@ -126,6 +121,8 @@ int main(int argc, char **argv) { if (!skip) { putc('.', stdout); + if (aom_codec_decode(&codec, frame, frame_size, NULL)) + die_codec(&codec, "Failed to decode frame."); while ((img = aom_codec_get_frame(&codec, &iter)) != NULL) aom_img_write(img, outfile); diff --git a/third_party/aom/examples/encoder_util.c b/third_party/aom/examples/encoder_util.c index 1aa3a7eef..e43b37250 100644 --- a/third_party/aom/examples/encoder_util.c +++ b/third_party/aom/examples/encoder_util.c @@ -11,10 +11,11 @@ // Utility functions used by encoder binaries. +#include "examples/encoder_util.h" + #include <assert.h> #include <string.h> -#include "./encoder_util.h" #include "aom/aom_integer.h" #define mmin(a, b) ((a) < (b) ? (a) : (b)) @@ -40,6 +41,7 @@ static void find_mismatch_plane(const aom_image_t *const img1, assert(img1->x_chroma_shift == img2->x_chroma_shift && img1->y_chroma_shift == img2->y_chroma_shift); loc[0] = loc[1] = loc[2] = loc[3] = -1; + if (img1->monochrome && img2->monochrome && plane) return; int match = 1; uint32_t i, j; for (i = 0; match && i < c_h; i += bsizey) { @@ -79,21 +81,16 @@ static void find_mismatch_helper(const aom_image_t *const img1, const aom_image_t *const img2, int use_highbitdepth, int yloc[4], int uloc[4], int vloc[4]) { -#if !CONFIG_HIGHBITDEPTH - assert(!use_highbitdepth); -#endif // !CONFIG_HIGHBITDEPTH find_mismatch_plane(img1, img2, AOM_PLANE_Y, use_highbitdepth, yloc); find_mismatch_plane(img1, img2, AOM_PLANE_U, use_highbitdepth, uloc); find_mismatch_plane(img1, img2, AOM_PLANE_V, use_highbitdepth, vloc); } -#if CONFIG_HIGHBITDEPTH void aom_find_mismatch_high(const aom_image_t *const img1, const aom_image_t *const img2, int yloc[4], int uloc[4], int vloc[4]) { find_mismatch_helper(img1, img2, 1, yloc, uloc, vloc); } -#endif void aom_find_mismatch(const aom_image_t *const img1, const aom_image_t *const img2, int yloc[4], int uloc[4], @@ -103,37 +100,37 @@ void aom_find_mismatch(const aom_image_t *const img1, int aom_compare_img(const aom_image_t *const img1, const aom_image_t *const img2) { + assert(img1->cp == img2->cp); + assert(img1->tc == img2->tc); + assert(img1->mc == img2->mc); + assert(img1->monochrome == img2->monochrome); + + int num_planes = img1->monochrome ? 1 : 3; + uint32_t l_w = img1->d_w; uint32_t c_w = (img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift; const uint32_t c_h = (img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift; - uint32_t i; int match = 1; match &= (img1->fmt == img2->fmt); match &= (img1->d_w == img2->d_w); match &= (img1->d_h == img2->d_h); -#if CONFIG_HIGHBITDEPTH if (img1->fmt & AOM_IMG_FMT_HIGHBITDEPTH) { l_w *= 2; c_w *= 2; } -#endif - - for (i = 0; i < img1->d_h; ++i) - match &= (memcmp(img1->planes[AOM_PLANE_Y] + i * img1->stride[AOM_PLANE_Y], - img2->planes[AOM_PLANE_Y] + i * img2->stride[AOM_PLANE_Y], - l_w) == 0); - - for (i = 0; i < c_h; ++i) - match &= (memcmp(img1->planes[AOM_PLANE_U] + i * img1->stride[AOM_PLANE_U], - img2->planes[AOM_PLANE_U] + i * img2->stride[AOM_PLANE_U], - c_w) == 0); - - for (i = 0; i < c_h; ++i) - match &= (memcmp(img1->planes[AOM_PLANE_V] + i * img1->stride[AOM_PLANE_V], - img2->planes[AOM_PLANE_V] + i * img2->stride[AOM_PLANE_V], - c_w) == 0); + + for (int plane = 0; plane < num_planes; ++plane) { + uint32_t height = plane ? c_h : img1->d_h; + uint32_t width = plane ? c_w : l_w; + + for (uint32_t i = 0; i < height; ++i) { + match &= + (memcmp(img1->planes[plane] + i * img1->stride[plane], + img2->planes[plane] + i * img2->stride[plane], width) == 0); + } + } return match; } diff --git a/third_party/aom/examples/encoder_util.h b/third_party/aom/examples/encoder_util.h index 38deef03d..966f5e004 100644 --- a/third_party/aom/examples/encoder_util.h +++ b/third_party/aom/examples/encoder_util.h @@ -14,16 +14,13 @@ #ifndef EXAMPLES_ENCODER_UTIL_H_ #define EXAMPLES_ENCODER_UTIL_H_ -#include "./aom_config.h" #include "aom/aom_image.h" // Returns mismatch location (?loc[0],?loc[1]) and the values at that location // in img1 (?loc[2]) and img2 (?loc[3]). -#if CONFIG_HIGHBITDEPTH void aom_find_mismatch_high(const aom_image_t *const img1, const aom_image_t *const img2, int yloc[4], int uloc[4], int vloc[4]); -#endif // CONFIG_HIGHBITDEPTH void aom_find_mismatch(const aom_image_t *const img1, const aom_image_t *const img2, int yloc[4], int uloc[4], diff --git a/third_party/aom/examples/inspect.c b/third_party/aom/examples/inspect.c index 74e770b84..4887fc4a3 100644 --- a/third_party/aom/examples/inspect.c +++ b/third_party/aom/examples/inspect.c @@ -19,27 +19,27 @@ #include <stdlib.h> #include <string.h> -#include "./args.h" #ifdef __EMSCRIPTEN__ #include <emscripten.h> #else #define EMSCRIPTEN_KEEPALIVE #endif +#include "config/aom_config.h" + #include "aom/aom_decoder.h" -#include "./aom_config.h" -#if CONFIG_ACCOUNTING -#include "../av1/decoder/accounting.h" -#endif -#include "../av1/decoder/inspection.h" #include "aom/aomdx.h" +#include "av1/common/onyxc_int.h" -#include "../tools_common.h" -#include "../video_reader.h" -// #include "av1/av1_dx_iface.c" -#include "../av1/common/onyxc_int.h" +#if CONFIG_ACCOUNTING +#include "av1/decoder/accounting.h" +#endif -#include "../video_common.h" +#include "av1/decoder/inspection.h" +#include "common/args.h" +#include "common/tools_common.h" +#include "common/video_common.h" +#include "common/video_reader.h" // Max JSON buffer size. const int MAX_BUFFER = 1024 * 1024 * 32; @@ -57,7 +57,10 @@ typedef enum { MOTION_VECTORS_LAYER = 1 << 9, UV_MODE_LAYER = 1 << 10, CFL_LAYER = 1 << 11, - ALL_LAYERS = (1 << 12) - 1 + DUAL_FILTER_LAYER = 1 << 12, + Q_INDEX_LAYER = 1 << 13, + SEGMENT_ID_LAYER = 1 << 14, + ALL_LAYERS = (1 << 15) - 1 } LayerType; static LayerType layers = 0; @@ -87,12 +90,16 @@ static const arg_def_t dump_skip_arg = ARG_DEF("s", "skip", 0, "Dump Skip"); static const arg_def_t dump_filter_arg = ARG_DEF("f", "filter", 0, "Dump Filter"); static const arg_def_t dump_cdef_arg = ARG_DEF("c", "cdef", 0, "Dump CDEF"); -#if CONFIG_CFL static const arg_def_t dump_cfl_arg = ARG_DEF("cfl", "chroma_from_luma", 0, "Dump Chroma from Luma Alphas"); -#endif +static const arg_def_t dump_dual_filter_type_arg = + ARG_DEF("df", "dualFilterType", 0, "Dump Dual Filter Type"); static const arg_def_t dump_reference_frame_arg = ARG_DEF("r", "referenceFrame", 0, "Dump Reference Frame"); +static const arg_def_t dump_delta_q_arg = + ARG_DEF("dq", "delta_q", 0, "Dump QIndex"); +static const arg_def_t dump_seg_id_arg = + ARG_DEF("si", "seg_id", 0, "Dump Segment ID"); static const arg_def_t usage_arg = ARG_DEF("h", "help", 0, "Help"); static const arg_def_t *main_args[] = { &limit_arg, @@ -108,14 +115,13 @@ static const arg_def_t *main_args[] = { &limit_arg, &dump_uv_mode_arg, &dump_skip_arg, &dump_filter_arg, -#if CONFIG_CDEF &dump_cdef_arg, -#endif -#if CONFIG_CFL + &dump_dual_filter_type_arg, &dump_cfl_arg, -#endif &dump_reference_frame_arg, &dump_motion_vectors_arg, + &dump_delta_q_arg, + &dump_seg_id_arg, &usage_arg, NULL }; #define ENUM(name) \ @@ -127,58 +133,35 @@ typedef struct map_entry { int value; } map_entry; -const map_entry refs_map[] = { ENUM(INTRA_FRAME), ENUM(LAST_FRAME), -#if CONFIG_EXT_REFS - ENUM(LAST2_FRAME), ENUM(LAST3_FRAME), - ENUM(GOLDEN_FRAME), ENUM(BWDREF_FRAME), - ENUM(ALTREF_FRAME), -#else - ENUM(GOLDEN_FRAME), ENUM(ALTREF_FRAME), -#endif - LAST_ENUM }; +const map_entry refs_map[] = { + ENUM(INTRA_FRAME), ENUM(LAST_FRAME), ENUM(LAST2_FRAME), + ENUM(LAST3_FRAME), ENUM(GOLDEN_FRAME), ENUM(BWDREF_FRAME), + ENUM(ALTREF2_FRAME), ENUM(ALTREF_FRAME), LAST_ENUM +}; const map_entry block_size_map[] = { -#if CONFIG_CHROMA_2X2 || CONFIG_CHROMA_SUB8X8 - ENUM(BLOCK_2X2), ENUM(BLOCK_2X4), ENUM(BLOCK_4X2), -#endif - ENUM(BLOCK_4X4), ENUM(BLOCK_4X8), ENUM(BLOCK_8X4), - ENUM(BLOCK_8X8), ENUM(BLOCK_8X16), ENUM(BLOCK_16X8), - ENUM(BLOCK_16X16), ENUM(BLOCK_16X32), ENUM(BLOCK_32X16), - ENUM(BLOCK_32X32), ENUM(BLOCK_32X64), ENUM(BLOCK_64X32), - ENUM(BLOCK_64X64), -#if CONFIG_EXT_PARTITION - ENUM(BLOCK_64X128), ENUM(BLOCK_128X64), ENUM(BLOCK_128X128), -#endif - ENUM(BLOCK_4X16), ENUM(BLOCK_16X4), ENUM(BLOCK_8X32), - ENUM(BLOCK_32X8), ENUM(BLOCK_16X64), ENUM(BLOCK_64X16), -#if CONFIG_EXT_PARTITION - ENUM(BLOCK_32X128), ENUM(BLOCK_128X32), -#endif - LAST_ENUM + ENUM(BLOCK_4X4), ENUM(BLOCK_4X8), ENUM(BLOCK_8X4), + ENUM(BLOCK_8X8), ENUM(BLOCK_8X16), ENUM(BLOCK_16X8), + ENUM(BLOCK_16X16), ENUM(BLOCK_16X32), ENUM(BLOCK_32X16), + ENUM(BLOCK_32X32), ENUM(BLOCK_32X64), ENUM(BLOCK_64X32), + ENUM(BLOCK_64X64), ENUM(BLOCK_64X128), ENUM(BLOCK_128X64), + ENUM(BLOCK_128X128), ENUM(BLOCK_4X16), ENUM(BLOCK_16X4), + ENUM(BLOCK_8X32), ENUM(BLOCK_32X8), ENUM(BLOCK_16X64), + ENUM(BLOCK_64X16), LAST_ENUM }; const map_entry tx_size_map[] = { -#if CONFIG_CHROMA_2X2 - ENUM(TX_2X2), -#endif ENUM(TX_4X4), ENUM(TX_8X8), ENUM(TX_16X16), ENUM(TX_32X32), -#if CONFIG_TX64X64 - ENUM(TX_64X64), -#endif - ENUM(TX_4X8), ENUM(TX_8X4), ENUM(TX_8X16), ENUM(TX_16X8), - ENUM(TX_16X32), ENUM(TX_32X16), -#if CONFIG_TX64X64 - ENUM(TX_32X64), ENUM(TX_64X32), -#endif // CONFIG_TX64X64 - ENUM(TX_4X16), ENUM(TX_16X4), ENUM(TX_8X32), ENUM(TX_32X8), - LAST_ENUM + ENUM(TX_64X64), ENUM(TX_4X8), ENUM(TX_8X4), ENUM(TX_8X16), + ENUM(TX_16X8), ENUM(TX_16X32), ENUM(TX_32X16), ENUM(TX_32X64), + ENUM(TX_64X32), ENUM(TX_4X16), ENUM(TX_16X4), ENUM(TX_8X32), + ENUM(TX_32X8), LAST_ENUM }; const map_entry tx_type_map[] = { ENUM(DCT_DCT), ENUM(ADST_DCT), ENUM(DCT_ADST), ENUM(ADST_ADST), -#if CONFIG_EXT_TX ENUM(FLIPADST_DCT), ENUM(DCT_FLIPADST), ENUM(FLIPADST_FLIPADST), @@ -191,43 +174,35 @@ const map_entry tx_type_map[] = { ENUM(DCT_DCT), ENUM(H_ADST), ENUM(V_FLIPADST), ENUM(H_FLIPADST), -#endif LAST_ENUM }; +const map_entry dual_filter_map[] = { ENUM(REG_REG), ENUM(REG_SMOOTH), + ENUM(REG_SHARP), ENUM(SMOOTH_REG), + ENUM(SMOOTH_SMOOTH), ENUM(SMOOTH_SHARP), + ENUM(SHARP_REG), ENUM(SHARP_SMOOTH), + ENUM(SHARP_SHARP), LAST_ENUM }; const map_entry prediction_mode_map[] = { - ENUM(DC_PRED), ENUM(V_PRED), ENUM(H_PRED), - ENUM(D45_PRED), ENUM(D135_PRED), ENUM(D117_PRED), - ENUM(D153_PRED), ENUM(D207_PRED), ENUM(D63_PRED), - ENUM(SMOOTH_PRED), -#if CONFIG_SMOOTH_HV - ENUM(SMOOTH_V_PRED), ENUM(SMOOTH_H_PRED), -#endif // CONFIG_SMOOTH_HV - ENUM(TM_PRED), ENUM(NEARESTMV), ENUM(NEARMV), - ENUM(ZEROMV), ENUM(NEWMV), ENUM(NEAREST_NEARESTMV), - ENUM(NEAR_NEARMV), ENUM(NEAREST_NEWMV), ENUM(NEW_NEARESTMV), - ENUM(NEAR_NEWMV), ENUM(NEW_NEARMV), ENUM(ZERO_ZEROMV), - ENUM(NEW_NEWMV), ENUM(INTRA_INVALID), LAST_ENUM + ENUM(DC_PRED), ENUM(V_PRED), ENUM(H_PRED), + ENUM(D45_PRED), ENUM(D135_PRED), ENUM(D113_PRED), + ENUM(D157_PRED), ENUM(D203_PRED), ENUM(D67_PRED), + ENUM(SMOOTH_PRED), ENUM(SMOOTH_V_PRED), ENUM(SMOOTH_H_PRED), + ENUM(PAETH_PRED), ENUM(NEARESTMV), ENUM(NEARMV), + ENUM(GLOBALMV), ENUM(NEWMV), ENUM(NEAREST_NEARESTMV), + ENUM(NEAR_NEARMV), ENUM(NEAREST_NEWMV), ENUM(NEW_NEARESTMV), + ENUM(NEAR_NEWMV), ENUM(NEW_NEARMV), ENUM(GLOBAL_GLOBALMV), + ENUM(NEW_NEWMV), ENUM(INTRA_INVALID), LAST_ENUM }; -#if CONFIG_CFL const map_entry uv_prediction_mode_map[] = { ENUM(UV_DC_PRED), ENUM(UV_V_PRED), ENUM(UV_H_PRED), ENUM(UV_D45_PRED), - ENUM(UV_D135_PRED), ENUM(UV_D117_PRED), - ENUM(UV_D153_PRED), ENUM(UV_D207_PRED), - ENUM(UV_D63_PRED), ENUM(UV_SMOOTH_PRED), -#if CONFIG_SMOOTH_HV + ENUM(UV_D135_PRED), ENUM(UV_D113_PRED), + ENUM(UV_D157_PRED), ENUM(UV_D203_PRED), + ENUM(UV_D67_PRED), ENUM(UV_SMOOTH_PRED), ENUM(UV_SMOOTH_V_PRED), ENUM(UV_SMOOTH_H_PRED), -#endif // CONFIG_SMOOTH_HV - ENUM(UV_TM_PRED), -#if CONFIG_CFL - ENUM(UV_CFL_PRED), -#endif + ENUM(UV_PAETH_PRED), ENUM(UV_CFL_PRED), ENUM(UV_MODE_INVALID), LAST_ENUM }; -#else -#define uv_prediction_mode_map prediction_mode_map -#endif #define NO_SKIP 0 #define SKIP 1 @@ -327,7 +302,7 @@ int put_map(char *buffer, const map_entry *map) { *(buf++) = ','; } } - return buf - buffer; + return (int)(buf - buffer); } int put_reference_frame(char *buffer) { @@ -365,7 +340,7 @@ int put_reference_frame(char *buffer) { if (r < mi_rows - 1) *(buf++) = ','; } buf += put_str(buf, "],\n"); - return buf - buffer; + return (int)(buf - buffer); } int put_motion_vectors(char *buffer) { @@ -404,15 +379,19 @@ int put_motion_vectors(char *buffer) { if (r < mi_rows - 1) *(buf++) = ','; } buf += put_str(buf, "],\n"); - return buf - buffer; + return (int)(buf - buffer); } int put_block_info(char *buffer, const map_entry *map, const char *name, - size_t offset) { + size_t offset, int len) { const int mi_rows = frame_data.mi_rows; const int mi_cols = frame_data.mi_cols; char *buf = buffer; - int r, c, t, v; + int r, c, t, i; + if (compress && len == 1) { + die("Can't encode scalars as arrays when RLE compression is enabled."); + return -1; + } if (map) { buf += snprintf(buf, MAX_BUFFER, " \"%sMap\": {", name); buf += put_map(buf, map); @@ -422,13 +401,36 @@ int put_block_info(char *buffer, const map_entry *map, const char *name, for (r = 0; r < mi_rows; ++r) { *(buf++) = '['; for (c = 0; c < mi_cols; ++c) { - insp_mi_data *curr_mi = &frame_data.mi_grid[r * mi_cols + c]; - v = *(((int8_t *)curr_mi) + offset); - buf += put_num(buf, 0, v, 0); + insp_mi_data *mi = &frame_data.mi_grid[r * mi_cols + c]; + int16_t *v = (int16_t *)(((int8_t *)mi) + offset); + if (len == 0) { + buf += put_num(buf, 0, v[0], 0); + } else { + buf += put_str(buf, "["); + for (i = 0; i < len; i++) { + buf += put_num(buf, 0, v[i], 0); + if (i < len - 1) { + buf += put_str(buf, ","); + } + } + buf += put_str(buf, "]"); + } if (compress) { // RLE for (t = c + 1; t < mi_cols; ++t) { insp_mi_data *next_mi = &frame_data.mi_grid[r * mi_cols + t]; - if (v != *(((int8_t *)next_mi) + offset)) { + int16_t *nv = (int16_t *)(((int8_t *)next_mi) + offset); + int same = 0; + if (len == 0) { + same = v[0] == nv[0]; + } else { + for (i = 0; i < len; i++) { + same = v[i] == nv[i]; + if (!same) { + break; + } + } + } + if (!same) { break; } } @@ -444,7 +446,7 @@ int put_block_info(char *buffer, const map_entry *map, const char *name, if (r < mi_rows - 1) *(buf++) = ','; } buf += put_str(buf, "],\n"); - return buf - buffer; + return (int)(buf - buffer); } #if CONFIG_ACCOUNTING @@ -484,7 +486,7 @@ int put_accounting(char *buffer) { if (i < num_syms - 1) *(buf++) = ','; } buf += put_str(buf, "],\n"); - return buf - buffer; + return (int)(buf - buffer); } #endif @@ -499,51 +501,62 @@ void inspect(void *pbi, void *data) { buf += put_str(buf, "{\n"); if (layers & BLOCK_SIZE_LAYER) { buf += put_block_info(buf, block_size_map, "blockSize", - offsetof(insp_mi_data, sb_type)); + offsetof(insp_mi_data, sb_type), 0); } if (layers & TRANSFORM_SIZE_LAYER) { buf += put_block_info(buf, tx_size_map, "transformSize", - offsetof(insp_mi_data, tx_size)); + offsetof(insp_mi_data, tx_size), 0); } if (layers & TRANSFORM_TYPE_LAYER) { buf += put_block_info(buf, tx_type_map, "transformType", - offsetof(insp_mi_data, tx_type)); + offsetof(insp_mi_data, tx_type), 0); + } + if (layers & DUAL_FILTER_LAYER) { + buf += put_block_info(buf, dual_filter_map, "dualFilterType", + offsetof(insp_mi_data, dual_filter_type), 0); } if (layers & MODE_LAYER) { buf += put_block_info(buf, prediction_mode_map, "mode", - offsetof(insp_mi_data, mode)); + offsetof(insp_mi_data, mode), 0); } if (layers & UV_MODE_LAYER) { buf += put_block_info(buf, uv_prediction_mode_map, "uv_mode", - offsetof(insp_mi_data, uv_mode)); + offsetof(insp_mi_data, uv_mode), 0); } if (layers & SKIP_LAYER) { - buf += put_block_info(buf, skip_map, "skip", offsetof(insp_mi_data, skip)); + buf += + put_block_info(buf, skip_map, "skip", offsetof(insp_mi_data, skip), 0); } if (layers & FILTER_LAYER) { - buf += put_block_info(buf, NULL, "filter", offsetof(insp_mi_data, filter)); + buf += + put_block_info(buf, NULL, "filter", offsetof(insp_mi_data, filter), 2); } -#if CONFIG_CDEF if (layers & CDEF_LAYER) { buf += put_block_info(buf, NULL, "cdef_level", - offsetof(insp_mi_data, cdef_level)); + offsetof(insp_mi_data, cdef_level), 0); buf += put_block_info(buf, NULL, "cdef_strength", - offsetof(insp_mi_data, cdef_strength)); + offsetof(insp_mi_data, cdef_strength), 0); } -#endif -#if CONFIG_CFL if (layers & CFL_LAYER) { buf += put_block_info(buf, NULL, "cfl_alpha_idx", - offsetof(insp_mi_data, cfl_alpha_idx)); + offsetof(insp_mi_data, cfl_alpha_idx), 0); buf += put_block_info(buf, NULL, "cfl_alpha_sign", - offsetof(insp_mi_data, cfl_alpha_sign)); + offsetof(insp_mi_data, cfl_alpha_sign), 0); + } + if (layers & Q_INDEX_LAYER) { + buf += put_block_info(buf, NULL, "delta_q", + offsetof(insp_mi_data, current_qindex), 0); + } + if (layers & SEGMENT_ID_LAYER) { + buf += put_block_info(buf, NULL, "seg_id", + offsetof(insp_mi_data, segment_id), 0); } -#endif if (layers & MOTION_VECTORS_LAYER) { buf += put_motion_vectors(buf); } if (layers & REFERENCE_FRAME_LAYER) { - buf += put_reference_frame(buf); + buf += put_block_info(buf, refs_map, "referenceFrame", + offsetof(insp_mi_data, ref_frame), 2); } #if CONFIG_ACCOUNTING if (layers & ACCOUNTING_LAYER) { @@ -561,6 +574,10 @@ void inspect(void *pbi, void *data) { frame_data.tile_mi_cols); buf += snprintf(buf, MAX_BUFFER, " \"tileRows\": %d,\n", frame_data.tile_mi_rows); + buf += snprintf(buf, MAX_BUFFER, " \"deltaQPresentFlag\": %d,\n", + frame_data.delta_q_present_flag); + buf += snprintf(buf, MAX_BUFFER, " \"deltaQRes\": %d,\n", + frame_data.delta_q_res); buf += put_str(buf, " \"config\": {"); buf += put_map(buf, config_map); buf += put_str(buf, "},\n"); @@ -608,15 +625,18 @@ int read_frame() { aom_codec_iter_t iter = NULL; size_t frame_size = 0; const unsigned char *frame = aom_video_reader_get_frame(reader, &frame_size); - if (aom_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0) != + if (aom_codec_decode(&codec, frame, (unsigned int)frame_size, NULL) != AOM_CODEC_OK) { die_codec(&codec, "Failed to decode frame."); } - img = aom_codec_get_frame(&codec, &iter); - if (img == NULL) { + int got_any_frames = 0; + while ((img = aom_codec_get_frame(&codec, &iter))) { + ++frame_count; + got_any_frames = 1; + } + if (!got_any_frames) { return EXIT_FAILURE; } - ++frame_count; return EXIT_SUCCESS; } @@ -674,18 +694,20 @@ static void parse_args(char **argv) { layers |= SKIP_LAYER; else if (arg_match(&arg, &dump_filter_arg, argi)) layers |= FILTER_LAYER; -#if CONFIG_CDEF else if (arg_match(&arg, &dump_cdef_arg, argi)) layers |= CDEF_LAYER; -#endif -#if CONFIG_CFL else if (arg_match(&arg, &dump_cfl_arg, argi)) layers |= CFL_LAYER; -#endif else if (arg_match(&arg, &dump_reference_frame_arg, argi)) layers |= REFERENCE_FRAME_LAYER; else if (arg_match(&arg, &dump_motion_vectors_arg, argi)) layers |= MOTION_VECTORS_LAYER; + else if (arg_match(&arg, &dump_dual_filter_type_arg, argi)) + layers |= DUAL_FILTER_LAYER; + else if (arg_match(&arg, &dump_delta_q_arg, argi)) + layers |= Q_INDEX_LAYER; + else if (arg_match(&arg, &dump_seg_id_arg, argi)) + layers |= SEGMENT_ID_LAYER; else if (arg_match(&arg, &dump_all_arg, argi)) layers |= ALL_LAYERS; else if (arg_match(&arg, &compress_arg, argi)) diff --git a/third_party/aom/examples/lightfield_bitstream_parsing.c b/third_party/aom/examples/lightfield_bitstream_parsing.c new file mode 100644 index 000000000..d13f3f172 --- /dev/null +++ b/third_party/aom/examples/lightfield_bitstream_parsing.c @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2018, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +// Lightfield Bitstream Parsing +// ============================ +// +// This is an lightfield bitstream parsing example. It takes an input file +// containing the whole compressed lightfield bitstream(ivf file), and parses it +// and constructs and outputs a new bitstream that can be decoded by an AV1 +// decoder. The output bitstream contains tile list OBUs. The lf_width and +// lf_height arguments are the number of lightfield images in each dimension. +// The lf_blocksize determines the number of reference images used. +// After running the lightfield encoder, run lightfield bitstream parsing: +// examples/lightfield_bitstream_parsing vase10x10.ivf vase_tile_list.ivf 10 10 +// 5 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "aom/aom_decoder.h" +#include "aom/aom_encoder.h" +#include "aom/aom_integer.h" +#include "aom/aomdx.h" +#include "aom_dsp/bitwriter_buffer.h" +#include "common/tools_common.h" +#include "common/video_reader.h" +#include "common/video_writer.h" + +static const char *exec_name; + +void usage_exit(void) { + fprintf( + stderr, + "Usage: %s <infile> <outfile> <lf_width> <lf_height> <lf_blocksize> \n", + exec_name); + exit(EXIT_FAILURE); +} + +#define ALIGN_POWER_OF_TWO(value, n) \ + (((value) + ((1 << (n)) - 1)) & ~((1 << (n)) - 1)) + +// SB size: 64x64 +const uint8_t output_frame_width_in_tiles_minus_1 = 512 / 64 - 1; +const uint8_t output_frame_height_in_tiles_minus_1 = 512 / 64 - 1; + +// Spec: +// typedef struct { +// uint8_t anchor_frame_idx; +// uint8_t tile_row; +// uint8_t tile_col; +// uint16_t coded_tile_data_size_minus_1; +// uint8_t *coded_tile_data; +// } TILE_LIST_ENTRY; + +// Tile list entry provided by the application +typedef struct { + int image_idx; + int reference_idx; + int tile_col; + int tile_row; +} TILE_LIST_INFO; + +// M references: 0 - M-1; N images(including references): 0 - N-1; +// Note: order the image index incrementally, so that we only go through the +// bitstream once to construct the tile list. +const int num_tile_lists = 2; +const uint16_t tile_count_minus_1 = 9 - 1; +const TILE_LIST_INFO tile_list[2][9] = { + { { 16, 0, 4, 5 }, + { 83, 3, 13, 2 }, + { 57, 2, 2, 6 }, + { 31, 1, 11, 5 }, + { 2, 0, 7, 4 }, + { 77, 3, 9, 9 }, + { 49, 1, 0, 1 }, + { 6, 0, 3, 10 }, + { 63, 2, 5, 8 } }, + { { 65, 2, 11, 1 }, + { 42, 1, 3, 7 }, + { 88, 3, 8, 4 }, + { 76, 3, 1, 15 }, + { 1, 0, 2, 2 }, + { 19, 0, 5, 6 }, + { 60, 2, 4, 0 }, + { 25, 1, 11, 15 }, + { 50, 2, 5, 4 } }, +}; + +int main(int argc, char **argv) { + aom_codec_ctx_t codec; + AvxVideoReader *reader = NULL; + AvxVideoWriter *writer = NULL; + const AvxInterface *decoder = NULL; + const AvxVideoInfo *info = NULL; + const char *lf_width_arg; + const char *lf_height_arg; + const char *lf_blocksize_arg; + int width, height; + int lf_width, lf_height; + int lf_blocksize; + int u_blocks, v_blocks; + int n, i; + aom_codec_pts_t pts; + + exec_name = argv[0]; + if (argc != 6) die("Invalid number of arguments."); + + reader = aom_video_reader_open(argv[1]); + if (!reader) die("Failed to open %s for reading.", argv[1]); + + lf_width_arg = argv[3]; + lf_height_arg = argv[4]; + lf_blocksize_arg = argv[5]; + + lf_width = (int)strtol(lf_width_arg, NULL, 0); + lf_height = (int)strtol(lf_height_arg, NULL, 0); + lf_blocksize = (int)strtol(lf_blocksize_arg, NULL, 0); + + info = aom_video_reader_get_info(reader); + width = info->frame_width; + height = info->frame_height; + + // The writer to write out ivf file in tile list OBU, which can be decoded by + // AV1 decoder. + writer = aom_video_writer_open(argv[2], kContainerIVF, info); + if (!writer) die("Failed to open %s for writing", argv[2]); + + decoder = get_aom_decoder_by_fourcc(info->codec_fourcc); + if (!decoder) die("Unknown input codec."); + printf("Using %s\n", aom_codec_iface_name(decoder->codec_interface())); + + if (aom_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0)) + die_codec(&codec, "Failed to initialize decoder."); + + // Decode anchor frames. + aom_codec_control_(&codec, AV1_SET_TILE_MODE, 0); + + // How many anchor frames we have. + u_blocks = (lf_width + lf_blocksize - 1) / lf_blocksize; + v_blocks = (lf_height + lf_blocksize - 1) / lf_blocksize; + + int num_references = v_blocks * u_blocks; + for (i = 0; i < num_references; ++i) { + aom_video_reader_read_frame(reader); + + size_t frame_size = 0; + const unsigned char *frame = + aom_video_reader_get_frame(reader, &frame_size); + pts = (aom_codec_pts_t)aom_video_reader_get_frame_pts(reader); + + // Copy references bitstream directly. + if (!aom_video_writer_write_frame(writer, frame, frame_size, pts)) + die_codec(&codec, "Failed to copy compressed anchor frame."); + + if (aom_codec_decode(&codec, frame, frame_size, NULL)) + die_codec(&codec, "Failed to decode frame."); + } + + // Decode camera frames. + aom_codec_control_(&codec, AV1_SET_TILE_MODE, 1); + aom_codec_control_(&codec, AV1D_EXT_TILE_DEBUG, 1); + + FILE *infile = aom_video_reader_get_file(reader); + // Record the offset of the first camera image. + const FileOffset camera_frame_pos = ftello(infile); + + // Read out the first camera frame. + aom_video_reader_read_frame(reader); + + // Copy first camera frame for getting camera frame header. This is done + // only once. + { + size_t frame_size = 0; + const unsigned char *frame = + aom_video_reader_get_frame(reader, &frame_size); + pts = (aom_codec_pts_t)aom_video_reader_get_frame_pts(reader); + aom_tile_data frame_header_info = { 0, NULL, 0 }; + + // Need to decode frame header to get camera frame header info. So, here + // decoding 1 tile is enough. + aom_codec_control_(&codec, AV1_SET_DECODE_TILE_ROW, 0); + aom_codec_control_(&codec, AV1_SET_DECODE_TILE_COL, 0); + + aom_codec_err_t aom_status = + aom_codec_decode(&codec, frame, frame_size, NULL); + if (aom_status) die_codec(&codec, "Failed to decode tile."); + + aom_codec_control_(&codec, AV1D_GET_FRAME_HEADER_INFO, &frame_header_info); + + size_t obu_size_offset = + (uint8_t *)frame_header_info.coded_tile_data - frame; + size_t length_field_size = frame_header_info.coded_tile_data_size; + // Remove ext-tile tile info. + uint32_t frame_header_size = (uint32_t)frame_header_info.extra_size - 1; + size_t bytes_to_copy = + obu_size_offset + length_field_size + frame_header_size; + + unsigned char *frame_hdr_buf = (unsigned char *)malloc(bytes_to_copy); + if (frame_hdr_buf == NULL) + die_codec(&codec, "Failed to allocate frame header buffer."); + + memcpy(frame_hdr_buf, frame, bytes_to_copy); + + // Update frame header OBU size. + size_t bytes_written = 0; + if (aom_uleb_encode_fixed_size( + frame_header_size, length_field_size, length_field_size, + frame_hdr_buf + obu_size_offset, &bytes_written)) + die_codec(&codec, "Failed to encode the tile list obu size."); + + // Copy camera frame header bitstream. + if (!aom_video_writer_write_frame(writer, frame_hdr_buf, bytes_to_copy, + pts)) + die_codec(&codec, "Failed to copy compressed camera frame header."); + } + + // Allocate a buffer to store tile list bitstream. Image format + // AOM_IMG_FMT_I420. + size_t data_sz = + ALIGN_POWER_OF_TWO(width, 5) * ALIGN_POWER_OF_TWO(height, 5) * 12 / 8; + unsigned char *tl_buf = (unsigned char *)malloc(data_sz); + if (tl_buf == NULL) die_codec(&codec, "Failed to allocate tile list buffer."); + + aom_codec_pts_t tl_pts = pts; + + // Process 1 tile list. + for (n = 0; n < num_tile_lists; n++) { + unsigned char *tl = tl_buf; + struct aom_write_bit_buffer wb = { tl, 0 }; + unsigned char *saved_obu_size_loc = NULL; + uint32_t tile_list_obu_header_size = 0; + uint32_t tile_list_obu_size = 0; + + // Write the tile list OBU header that is 1 byte long. + aom_wb_write_literal(&wb, 0, 1); // forbidden bit. + aom_wb_write_literal(&wb, 8, 4); // tile list OBU: "1000" + aom_wb_write_literal(&wb, 0, 1); // obu_extension = 0 + aom_wb_write_literal(&wb, 1, 1); // obu_has_size_field + aom_wb_write_literal(&wb, 0, 1); // reserved + tl++; + tile_list_obu_header_size++; + + // Write the OBU size using a fixed length_field_size of 4 bytes. + saved_obu_size_loc = tl; + aom_wb_write_literal(&wb, 0, 32); + tl += 4; + tile_list_obu_header_size += 4; + + // write_tile_list_obu() + aom_wb_write_literal(&wb, output_frame_width_in_tiles_minus_1, 8); + aom_wb_write_literal(&wb, output_frame_height_in_tiles_minus_1, 8); + aom_wb_write_literal(&wb, tile_count_minus_1, 16); + tl += 4; + tile_list_obu_size += 4; + + // Write each tile's data + for (i = 0; i <= tile_count_minus_1; i++) { + aom_tile_data tile_data = { 0, NULL, 0 }; + + int image_idx = tile_list[n][i].image_idx; + int ref_idx = tile_list[n][i].reference_idx; + int tc = tile_list[n][i].tile_col; + int tr = tile_list[n][i].tile_row; + int frame_cnt = -1; + + // Reset bit writer to the right location. + wb.bit_buffer = tl; + wb.bit_offset = 0; + + // Seek to the first camera image. + fseeko(infile, camera_frame_pos, SEEK_SET); + + // Read out the camera image + while (frame_cnt != image_idx) { + aom_video_reader_read_frame(reader); + frame_cnt++; + } + + size_t frame_size = 0; + const unsigned char *frame = + aom_video_reader_get_frame(reader, &frame_size); + + aom_codec_control_(&codec, AV1_SET_DECODE_TILE_ROW, tr); + aom_codec_control_(&codec, AV1_SET_DECODE_TILE_COL, tc); + + aom_codec_err_t aom_status = + aom_codec_decode(&codec, frame, frame_size, NULL); + if (aom_status) die_codec(&codec, "Failed to decode tile."); + + aom_codec_control_(&codec, AV1D_GET_TILE_DATA, &tile_data); + + // Copy over tile info. + // uint8_t anchor_frame_idx; + // uint8_t tile_row; + // uint8_t tile_col; + // uint16_t coded_tile_data_size_minus_1; + // uint8_t *coded_tile_data; + uint32_t tile_info_bytes = 5; + aom_wb_write_literal(&wb, ref_idx, 8); + aom_wb_write_literal(&wb, tr, 8); + aom_wb_write_literal(&wb, tc, 8); + aom_wb_write_literal(&wb, (int)tile_data.coded_tile_data_size - 1, 16); + tl += tile_info_bytes; + + memcpy(tl, (uint8_t *)tile_data.coded_tile_data, + tile_data.coded_tile_data_size); + tl += tile_data.coded_tile_data_size; + + tile_list_obu_size += + tile_info_bytes + (uint32_t)tile_data.coded_tile_data_size; + } + + // Write tile list OBU size. + size_t bytes_written = 0; + if (aom_uleb_encode_fixed_size(tile_list_obu_size, 4, 4, saved_obu_size_loc, + &bytes_written)) + die_codec(&codec, "Failed to encode the tile list obu size."); + + // Copy the tile list. + if (!aom_video_writer_write_frame( + writer, tl_buf, tile_list_obu_header_size + tile_list_obu_size, + tl_pts)) + die_codec(&codec, "Failed to copy compressed tile list."); + + tl_pts++; + } + + free(tl_buf); + if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec"); + aom_video_writer_close(writer); + aom_video_reader_close(reader); + + return EXIT_SUCCESS; +} diff --git a/third_party/aom/examples/lightfield_decoder.c b/third_party/aom/examples/lightfield_decoder.c index 8743df9bc..625cddcac 100644 --- a/third_party/aom/examples/lightfield_decoder.c +++ b/third_party/aom/examples/lightfield_decoder.c @@ -14,14 +14,14 @@ // // This is an example of a simple lightfield decoder. It builds upon the // simple_decoder.c example. It takes an input file containing the compressed -// data (in webm format), treating it as a lightfield instead of a video and +// data (in ivf format), treating it as a lightfield instead of a video and // will decode a single lightfield tile. The lf_width and lf_height arguments // are the number of lightfield images in each dimension. The tile to decode // is specified by the tile_u, tile_v, tile_s, tile_t arguments. The tile_u, // tile_v specify the image and tile_s, tile_t specify the tile in the image. // After running the lightfield encoder, run lightfield decoder to decode a // single tile: -// examples/lightfield_decoder vase10x10.webm vase_tile.yuv 10 10 3 4 5 10 5 +// examples/lightfield_decoder vase10x10.ivf vase_reference.yuv 10 10 5 #include <stdio.h> #include <stdlib.h> @@ -29,47 +29,57 @@ #include "aom/aom_decoder.h" #include "aom/aomdx.h" +#include "common/tools_common.h" +#include "common/video_reader.h" -#include "../tools_common.h" -#include "../video_reader.h" -#include "./aom_config.h" +#define MAX_EXTERNAL_REFERENCES 128 +#define AOM_BORDER_IN_PIXELS 288 static const char *exec_name; void usage_exit(void) { - fprintf(stderr, - "Usage: %s <infile> <outfile> <lf_width> <lf_height> <tlie_u>" - " <tile_v> <tile_s> <tile_t> <lf_blocksize>\n", - exec_name); + fprintf( + stderr, + "Usage: %s <infile> <outfile> <lf_width> <lf_height> <lf_blocksize>\n", + exec_name); exit(EXIT_FAILURE); } -aom_image_t *aom_img_copy(aom_image_t *src, aom_image_t *dst) { - dst = aom_img_alloc(dst, src->fmt, src->d_w, src->d_h, 16); - - int plane; - - for (plane = 0; plane < 3; ++plane) { - uint8_t *src_buf = src->planes[plane]; - const int src_stride = src->stride[plane]; - const int src_w = plane == 0 ? src->d_w : src->d_w >> 1; - const int src_h = plane == 0 ? src->d_h : src->d_h >> 1; - - uint8_t *dst_buf = dst->planes[plane]; - const int dst_stride = dst->stride[plane]; - int y; - - for (y = 0; y < src_h; ++y) { - memcpy(dst_buf, src_buf, src_w); - src_buf += src_stride; - dst_buf += dst_stride; - } - } - return dst; -} +// Tile list entry provided by the application +typedef struct { + int image_idx; + int reference_idx; + int tile_col; + int tile_row; +} TILE_LIST_INFO; + +// M references: 0 - M-1; N images(including references): 0 - N-1; +// Note: order the image index incrementally, so that we only go through the +// bitstream once to construct the tile list. +const int num_tile_lists = 2; +const uint16_t tile_count_minus_1 = 9 - 1; +const TILE_LIST_INFO tile_list[2][9] = { + { { 16, 0, 4, 5 }, + { 83, 3, 13, 2 }, + { 57, 2, 2, 6 }, + { 31, 1, 11, 5 }, + { 2, 0, 7, 4 }, + { 77, 3, 9, 9 }, + { 49, 1, 0, 1 }, + { 6, 0, 3, 10 }, + { 63, 2, 5, 8 } }, + { { 65, 2, 11, 1 }, + { 42, 1, 3, 7 }, + { 88, 3, 8, 4 }, + { 76, 3, 1, 15 }, + { 1, 0, 2, 2 }, + { 19, 0, 5, 6 }, + { 60, 2, 4, 0 }, + { 25, 1, 11, 15 }, + { 50, 2, 5, 4 } }, +}; int main(int argc, char **argv) { - int frame_cnt = 0; FILE *outfile = NULL; aom_codec_ctx_t codec; AvxVideoReader *reader = NULL; @@ -77,20 +87,20 @@ int main(int argc, char **argv) { const AvxVideoInfo *info = NULL; const char *lf_width_arg; const char *lf_height_arg; - const char *tile_u_arg; - const char *tile_v_arg; - const char *tile_s_arg; - const char *tile_t_arg; const char *lf_blocksize_arg; + int width, height; int lf_width, lf_height; - int tile_u, tile_v, tile_s, tile_t; int lf_blocksize; int u_blocks; int v_blocks; + aom_image_t reference_images[MAX_EXTERNAL_REFERENCES]; + size_t frame_size = 0; + const unsigned char *frame = NULL; + int n, i; exec_name = argv[0]; - if (argc != 10) die("Invalid number of arguments."); + if (argc != 6) die("Invalid number of arguments."); reader = aom_video_reader_open(argv[1]); if (!reader) die("Failed to open %s for reading.", argv[1]); @@ -100,86 +110,113 @@ int main(int argc, char **argv) { lf_width_arg = argv[3]; lf_height_arg = argv[4]; - tile_u_arg = argv[5]; - tile_v_arg = argv[6]; - tile_s_arg = argv[7]; - tile_t_arg = argv[8]; - lf_blocksize_arg = argv[9]; + lf_blocksize_arg = argv[5]; lf_width = (int)strtol(lf_width_arg, NULL, 0); lf_height = (int)strtol(lf_height_arg, NULL, 0); - tile_u = (int)strtol(tile_u_arg, NULL, 0); - tile_v = (int)strtol(tile_v_arg, NULL, 0); - tile_s = (int)strtol(tile_s_arg, NULL, 0); - tile_t = (int)strtol(tile_t_arg, NULL, 0); lf_blocksize = (int)strtol(lf_blocksize_arg, NULL, 0); info = aom_video_reader_get_info(reader); + width = info->frame_width; + height = info->frame_height; decoder = get_aom_decoder_by_fourcc(info->codec_fourcc); if (!decoder) die("Unknown input codec."); - printf("Using %s\n", aom_codec_iface_name(decoder->codec_interface())); if (aom_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0)) die_codec(&codec, "Failed to initialize decoder."); - // How many reference images we need to encode. + // How many anchor frames we have. u_blocks = (lf_width + lf_blocksize - 1) / lf_blocksize; v_blocks = (lf_height + lf_blocksize - 1) / lf_blocksize; - aom_image_t *reference_images = - (aom_image_t *)malloc(u_blocks * v_blocks * sizeof(aom_image_t)); - for (int bv = 0; bv < v_blocks; ++bv) { - for (int bu = 0; bu < u_blocks; ++bu) { - aom_video_reader_read_frame(reader); - aom_codec_iter_t iter = NULL; - aom_image_t *img = NULL; - size_t frame_size = 0; - const unsigned char *frame = - aom_video_reader_get_frame(reader, &frame_size); - if (aom_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0)) - die_codec(&codec, "Failed to decode frame."); - - while ((img = aom_codec_get_frame(&codec, &iter)) != NULL) { - aom_img_copy(img, &reference_images[bu + bv * u_blocks]); - char name[1024]; - snprintf(name, sizeof(name), "ref_%d_%d.yuv", bu, bv); - printf("writing ref image to %s, %d, %d\n", name, img->d_w, img->d_h); - FILE *ref_file = fopen(name, "wb"); - aom_img_write(img, ref_file); - fclose(ref_file); - ++frame_cnt; - } + + int num_references = v_blocks * u_blocks; + + // Allocate memory to store decoded references. + aom_img_fmt_t ref_fmt = AOM_IMG_FMT_I420; + if (!CONFIG_LOWBITDEPTH) ref_fmt |= AOM_IMG_FMT_HIGHBITDEPTH; + // Allocate memory with the border so that it can be used as a reference. + for (i = 0; i < num_references; i++) { + unsigned int border = AOM_BORDER_IN_PIXELS; + if (!aom_img_alloc_with_border(&reference_images[i], ref_fmt, width, height, + 32, 8, border)) { + die("Failed to allocate references."); } } - int decode_frame_index = tile_v * lf_width + tile_u; - do { + // Decode anchor frames. + aom_codec_control_(&codec, AV1_SET_TILE_MODE, 0); + + for (i = 0; i < num_references; ++i) { aom_video_reader_read_frame(reader); - } while (frame_cnt++ != decode_frame_index); - size_t frame_size = 0; - const unsigned char *frame = aom_video_reader_get_frame(reader, &frame_size); - - int ref_bu = tile_u / lf_blocksize; - int ref_bv = tile_v / lf_blocksize; - int ref_bi = ref_bu + ref_bv * u_blocks; - av1_ref_frame_t ref; - ref.idx = 0; - ref.img = reference_images[ref_bi]; - // This is too slow for real lightfield rendering. This copies the - // reference image bytes. We need a way to just set a pointer - // in order to make this fast enough. - if (aom_codec_control(&codec, AV1_SET_REFERENCE, &ref)) { - die_codec(&codec, "Failed to set reference image."); + frame = aom_video_reader_get_frame(reader, &frame_size); + if (aom_codec_decode(&codec, frame, frame_size, NULL)) + die_codec(&codec, "Failed to decode frame."); + + if (aom_codec_control(&codec, AV1_COPY_NEW_FRAME_IMAGE, + &reference_images[i])) + die_codec(&codec, "Failed to copy decoded reference frame"); + + aom_codec_iter_t iter = NULL; + aom_image_t *img = NULL; + while ((img = aom_codec_get_frame(&codec, &iter)) != NULL) { + char name[1024]; + snprintf(name, sizeof(name), "ref_%d.yuv", i); + printf("writing ref image to %s, %d, %d\n", name, img->d_w, img->d_h); + FILE *ref_file = fopen(name, "wb"); + aom_img_write(img, ref_file); + fclose(ref_file); + } + } + + FILE *infile = aom_video_reader_get_file(reader); + // Record the offset of the first camera image. + const FileOffset camera_frame_pos = ftello(infile); + + // Process 1 tile. + for (n = 0; n < num_tile_lists; n++) { + for (i = 0; i <= tile_count_minus_1; i++) { + int image_idx = tile_list[n][i].image_idx; + int ref_idx = tile_list[n][i].reference_idx; + int tc = tile_list[n][i].tile_col; + int tr = tile_list[n][i].tile_row; + int frame_cnt = -1; + + // Seek to the first camera image. + fseeko(infile, camera_frame_pos, SEEK_SET); + + // Read out the camera image + while (frame_cnt != image_idx) { + aom_video_reader_read_frame(reader); + frame_cnt++; + } + + frame = aom_video_reader_get_frame(reader, &frame_size); + + aom_codec_control_(&codec, AV1_SET_TILE_MODE, 1); + aom_codec_control_(&codec, AV1D_EXT_TILE_DEBUG, 1); + aom_codec_control_(&codec, AV1_SET_DECODE_TILE_ROW, tr); + aom_codec_control_(&codec, AV1_SET_DECODE_TILE_COL, tc); + + av1_ref_frame_t ref; + ref.idx = 0; + ref.use_external_ref = 1; + ref.img = reference_images[ref_idx]; + if (aom_codec_control(&codec, AV1_SET_REFERENCE, &ref)) { + die_codec(&codec, "Failed to set reference frame."); + } + + aom_codec_err_t aom_status = + aom_codec_decode(&codec, frame, frame_size, NULL); + if (aom_status) die_codec(&codec, "Failed to decode tile."); + + aom_codec_iter_t iter = NULL; + aom_image_t *img = aom_codec_get_frame(&codec, &iter); + aom_img_write(img, outfile); + } } - aom_codec_control_(&codec, AV1_SET_DECODE_TILE_ROW, tile_t); - aom_codec_control_(&codec, AV1_SET_DECODE_TILE_COL, tile_s); - aom_codec_err_t aom_status = - aom_codec_decode(&codec, frame, frame_size, NULL, 0); - if (aom_status) die_codec(&codec, "Failed to decode tile."); - aom_codec_iter_t iter = NULL; - aom_image_t *img = aom_codec_get_frame(&codec, &iter); - aom_img_write(img, outfile); + for (i = 0; i < num_references; i++) aom_img_free(&reference_images[i]); if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec"); aom_video_reader_close(reader); fclose(outfile); diff --git a/third_party/aom/examples/lightfield_encoder.c b/third_party/aom/examples/lightfield_encoder.c index 0a424db8c..22daf622c 100644 --- a/third_party/aom/examples/lightfield_encoder.c +++ b/third_party/aom/examples/lightfield_encoder.c @@ -24,7 +24,12 @@ // image for MCP. // Run "make test" to download lightfield test data: vase10x10.yuv. // Run lightfield encoder to encode whole lightfield: -// examples/lightfield_encoder 1024 1024 vase10x10.yuv vase10x10.webm 10 10 5 +// examples/lightfield_encoder 1024 1024 vase10x10.yuv vase10x10.ivf 10 10 5 + +// Note: In bitstream.c and encoder.c, define EXT_TILE_DEBUG as 1 will print +// out the uncompressed header and the frame contexts, which can be used to +// test the bit exactness of the headers and the frame contexts for large scale +// tile coded frames. #include <stdio.h> #include <stdlib.h> @@ -34,11 +39,13 @@ #include "aom/aomcx.h" #include "av1/common/enums.h" -#include "../tools_common.h" -#include "../video_writer.h" +#include "common/tools_common.h" +#include "common/video_writer.h" + +#define MAX_EXTERNAL_REFERENCES 128 +#define AOM_BORDER_IN_PIXELS 288 static const char *exec_name; -static const unsigned int deadline = AOM_DL_GOOD_QUALITY; void usage_exit(void) { fprintf(stderr, @@ -48,52 +55,26 @@ void usage_exit(void) { exit(EXIT_FAILURE); } -static aom_image_t *aom_img_copy(aom_image_t *src, aom_image_t *dst) { - dst = aom_img_alloc(dst, src->fmt, src->d_w, src->d_h, 16); - - int plane; - - for (plane = 0; plane < 3; ++plane) { - unsigned char *src_buf = src->planes[plane]; - const int src_stride = src->stride[plane]; - const int src_w = plane == 0 ? src->d_w : src->d_w >> 1; - const int src_h = plane == 0 ? src->d_h : src->d_h >> 1; - - unsigned char *dst_buf = dst->planes[plane]; - const int dst_stride = dst->stride[plane]; - int y; - - for (y = 0; y < src_h; ++y) { - memcpy(dst_buf, src_buf, src_w); - src_buf += src_stride; - dst_buf += dst_stride; - } - } - return dst; -} - static int aom_img_size_bytes(aom_image_t *img) { int image_size_bytes = 0; int plane; for (plane = 0; plane < 3; ++plane) { - const int stride = img->stride[plane]; const int w = aom_img_plane_width(img, plane) * ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1); const int h = aom_img_plane_height(img, plane); - image_size_bytes += (w + stride) * h; + image_size_bytes += w * h; } return image_size_bytes; } static int get_frame_stats(aom_codec_ctx_t *ctx, const aom_image_t *img, aom_codec_pts_t pts, unsigned int duration, - aom_enc_frame_flags_t flags, unsigned int dl, + aom_enc_frame_flags_t flags, aom_fixed_buf_t *stats) { int got_pkts = 0; aom_codec_iter_t iter = NULL; const aom_codec_cx_pkt_t *pkt = NULL; - const aom_codec_err_t res = - aom_codec_encode(ctx, img, pts, duration, flags, dl); + const aom_codec_err_t res = aom_codec_encode(ctx, img, pts, duration, flags); if (res != AOM_CODEC_OK) die_codec(ctx, "Failed to get frame stats."); while ((pkt = aom_codec_get_cx_data(ctx, &iter)) != NULL) { @@ -113,13 +94,11 @@ static int get_frame_stats(aom_codec_ctx_t *ctx, const aom_image_t *img, static int encode_frame(aom_codec_ctx_t *ctx, const aom_image_t *img, aom_codec_pts_t pts, unsigned int duration, - aom_enc_frame_flags_t flags, unsigned int dl, - AvxVideoWriter *writer) { + aom_enc_frame_flags_t flags, AvxVideoWriter *writer) { int got_pkts = 0; aom_codec_iter_t iter = NULL; const aom_codec_cx_pkt_t *pkt = NULL; - const aom_codec_err_t res = - aom_codec_encode(ctx, img, pts, duration, flags, dl); + const aom_codec_err_t res = aom_codec_encode(ctx, img, pts, duration, flags); if (res != AOM_CODEC_OK) die_codec(ctx, "Failed to encode frame."); while ((pkt = aom_codec_get_cx_data(ctx, &iter)) != NULL) { @@ -139,33 +118,44 @@ static int encode_frame(aom_codec_ctx_t *ctx, const aom_image_t *img, return got_pkts; } +static void get_raw_image(aom_image_t **frame_to_encode, aom_image_t *raw, + aom_image_t *raw_shift) { + if (!CONFIG_LOWBITDEPTH) { + // Need to allocate larger buffer to use hbd internal. + int input_shift = 0; + aom_img_upshift(raw_shift, raw, input_shift); + *frame_to_encode = raw_shift; + } else { + *frame_to_encode = raw; + } +} + static aom_fixed_buf_t pass0(aom_image_t *raw, FILE *infile, const AvxInterface *encoder, const aom_codec_enc_cfg_t *cfg, int lf_width, - int lf_height, int lf_blocksize) { + int lf_height, int lf_blocksize, int flags, + aom_image_t *raw_shift) { aom_codec_ctx_t codec; int frame_count = 0; - int image_size_bytes = 0; + int image_size_bytes = aom_img_size_bytes(raw); int u_blocks, v_blocks; int bu, bv; aom_fixed_buf_t stats = { NULL, 0 }; + aom_image_t *frame_to_encode; - if (aom_codec_enc_init(&codec, encoder->codec_interface(), cfg, 0)) + if (aom_codec_enc_init(&codec, encoder->codec_interface(), cfg, flags)) die_codec(&codec, "Failed to initialize encoder"); - if (aom_codec_control(&codec, AV1E_SET_FRAME_PARALLEL_DECODING, 1)) - die_codec(&codec, "Failed to set frame parallel decoding"); if (aom_codec_control(&codec, AOME_SET_ENABLEAUTOALTREF, 0)) die_codec(&codec, "Failed to turn off auto altref"); - if (aom_codec_control(&codec, AV1E_SET_SINGLE_TILE_DECODING, 1)) - die_codec(&codec, "Failed to turn on single tile decoding"); - - image_size_bytes = aom_img_size_bytes(raw); + if (aom_codec_control(&codec, AV1E_SET_FRAME_PARALLEL_DECODING, 0)) + die_codec(&codec, "Failed to set frame parallel decoding"); // How many reference images we need to encode. u_blocks = (lf_width + lf_blocksize - 1) / lf_blocksize; v_blocks = (lf_height + lf_blocksize - 1) / lf_blocksize; - aom_image_t *reference_images = - (aom_image_t *)malloc(u_blocks * v_blocks * sizeof(aom_image_t)); + + printf("\n First pass: "); + for (bv = 0; bv < v_blocks; ++bv) { for (bu = 0; bu < u_blocks; ++bu) { const int block_u_min = bu * lf_blocksize; @@ -174,7 +164,6 @@ static aom_fixed_buf_t pass0(aom_image_t *raw, FILE *infile, int block_v_end = (bv + 1) * lf_blocksize; int u_block_size, v_block_size; int block_ref_u, block_ref_v; - struct av1_ref_frame ref_frame; block_u_end = block_u_end < lf_width ? block_u_end : lf_width; block_v_end = block_v_end < lf_height ? block_v_end : lf_height; @@ -182,22 +171,28 @@ static aom_fixed_buf_t pass0(aom_image_t *raw, FILE *infile, v_block_size = block_v_end - block_v_min; block_ref_u = block_u_min + u_block_size / 2; block_ref_v = block_v_min + v_block_size / 2; + + printf("A%d, ", (block_ref_u + block_ref_v * lf_width)); fseek(infile, (block_ref_u + block_ref_v * lf_width) * image_size_bytes, SEEK_SET); aom_img_read(raw, infile); - if (aom_codec_control(&codec, AOME_USE_REFERENCE, - AOM_LAST_FLAG | AOM_GOLD_FLAG | AOM_ALT_FLAG)) - die_codec(&codec, "Failed to set reference flags"); + get_raw_image(&frame_to_encode, raw, raw_shift); + // Reference frames can be encoded encoded without tiles. ++frame_count; - get_frame_stats(&codec, raw, frame_count, 1, - AOM_EFLAG_FORCE_GF | AOM_EFLAG_NO_UPD_ENTROPY, deadline, + get_frame_stats(&codec, frame_to_encode, frame_count, 1, + AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 | + AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF | + AOM_EFLAG_NO_REF_BWD | AOM_EFLAG_NO_REF_ARF2 | + AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF | + AOM_EFLAG_NO_UPD_ARF, &stats); - ref_frame.idx = 0; - aom_codec_control(&codec, AV1_GET_REFERENCE, &ref_frame); - aom_img_copy(&ref_frame.img, &reference_images[frame_count - 1]); } } + + if (aom_codec_control(&codec, AV1E_SET_FRAME_PARALLEL_DECODING, 1)) + die_codec(&codec, "Failed to set frame parallel decoding"); + for (bv = 0; bv < v_blocks; ++bv) { for (bu = 0; bu < u_blocks; ++bu) { const int block_u_min = bu * lf_blocksize; @@ -209,58 +204,39 @@ static aom_fixed_buf_t pass0(aom_image_t *raw, FILE *infile, block_v_end = block_v_end < lf_height ? block_v_end : lf_height; for (v = block_v_min; v < block_v_end; ++v) { for (u = block_u_min; u < block_u_end; ++u) { - // This was a work around for a bug in libvpx. I'm not sure if this - // same bug exists in current version of av1. Need to call this, - // otherwise the default is to not use any reference frames. Then - // if you don't have at least one AOM_EFLAG_NO_REF_* flag, all frames - // will be intra encoded. I'm not sure why the default is not to use - // any reference frames. It looks like there is something about the - // way I encode the reference frames above that sets that as - // default... - if (aom_codec_control(&codec, AOME_USE_REFERENCE, - AOM_LAST_FLAG | AOM_GOLD_FLAG | AOM_ALT_FLAG)) - die_codec(&codec, "Failed to set reference flags"); - - // Set tile size to 64 pixels. The tile_columns and - // tile_rows in the tile coding are overloaded to represent - // tile_width and tile_height, that range from 1 to 64, in the unit - // of 64 pixels. - if (aom_codec_control(&codec, AV1E_SET_TILE_COLUMNS, 1)) - die_codec(&codec, "Failed to set tile width"); - if (aom_codec_control(&codec, AV1E_SET_TILE_ROWS, 1)) - die_codec(&codec, "Failed to set tile height"); - - av1_ref_frame_t ref; - ref.idx = 0; - ref.img = reference_images[bv * u_blocks + bu]; - if (aom_codec_control(&codec, AV1_SET_REFERENCE, &ref)) - die_codec(&codec, "Failed to set reference frame"); - + printf("C%d, ", (u + v * lf_width)); fseek(infile, (u + v * lf_width) * image_size_bytes, SEEK_SET); aom_img_read(raw, infile); + get_raw_image(&frame_to_encode, raw, raw_shift); + ++frame_count; - get_frame_stats(&codec, raw, frame_count, 1, - AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF | - AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_ENTROPY | - AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF, - deadline, &stats); + get_frame_stats(&codec, frame_to_encode, frame_count, 1, + AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 | + AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF | + AOM_EFLAG_NO_REF_BWD | AOM_EFLAG_NO_REF_ARF2 | + AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF | + AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_ENTROPY, + &stats); } } } } // Flush encoder. - while (get_frame_stats(&codec, NULL, frame_count, 1, 0, deadline, &stats)) { + // No ARF, this should not be needed. + while (get_frame_stats(&codec, NULL, frame_count, 1, 0, &stats)) { } - printf("Pass 0 complete. Processed %d frames.\n", frame_count); if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec."); + printf("\nFirst pass complete. Processed %d frames.\n", frame_count); + return stats; } static void pass1(aom_image_t *raw, FILE *infile, const char *outfile_name, - const AvxInterface *encoder, const aom_codec_enc_cfg_t *cfg, - int lf_width, int lf_height, int lf_blocksize) { + const AvxInterface *encoder, aom_codec_enc_cfg_t *cfg, + int lf_width, int lf_height, int lf_blocksize, int flags, + aom_image_t *raw_shift) { AvxVideoInfo info = { encoder->fourcc, cfg->g_w, cfg->g_h, @@ -268,27 +244,48 @@ static void pass1(aom_image_t *raw, FILE *infile, const char *outfile_name, AvxVideoWriter *writer = NULL; aom_codec_ctx_t codec; int frame_count = 0; - int image_size_bytes; + int image_size_bytes = aom_img_size_bytes(raw); int bu, bv; int u_blocks, v_blocks; + aom_image_t *frame_to_encode; + aom_image_t reference_images[MAX_EXTERNAL_REFERENCES]; + int reference_image_num = 0; + int i; writer = aom_video_writer_open(outfile_name, kContainerIVF, &info); if (!writer) die("Failed to open %s for writing", outfile_name); - if (aom_codec_enc_init(&codec, encoder->codec_interface(), cfg, 0)) + if (aom_codec_enc_init(&codec, encoder->codec_interface(), cfg, flags)) die_codec(&codec, "Failed to initialize encoder"); - if (aom_codec_control(&codec, AV1E_SET_FRAME_PARALLEL_DECODING, 1)) - die_codec(&codec, "Failed to set frame parallel decoding"); if (aom_codec_control(&codec, AOME_SET_ENABLEAUTOALTREF, 0)) die_codec(&codec, "Failed to turn off auto altref"); - if (aom_codec_control(&codec, AV1E_SET_SINGLE_TILE_DECODING, 1)) - die_codec(&codec, "Failed to turn on single tile decoding"); + if (aom_codec_control(&codec, AV1E_SET_FRAME_PARALLEL_DECODING, 0)) + die_codec(&codec, "Failed to set frame parallel decoding"); + // Note: The superblock is a sequence parameter and has to be the same for 1 + // sequence. In lightfield application, must choose the superblock size(either + // 64x64 or 128x128) before the encoding starts. Otherwise, the default is + // AOM_SUPERBLOCK_SIZE_DYNAMIC, and the superblock size will be set to 64x64 + // internally. + if (aom_codec_control(&codec, AV1E_SET_SUPERBLOCK_SIZE, + AOM_SUPERBLOCK_SIZE_64X64)) + die_codec(&codec, "Failed to set SB size"); - image_size_bytes = aom_img_size_bytes(raw); u_blocks = (lf_width + lf_blocksize - 1) / lf_blocksize; v_blocks = (lf_height + lf_blocksize - 1) / lf_blocksize; - aom_image_t *reference_images = - (aom_image_t *)malloc(u_blocks * v_blocks * sizeof(aom_image_t)); + + reference_image_num = u_blocks * v_blocks; + aom_img_fmt_t ref_fmt = AOM_IMG_FMT_I420; + if (!CONFIG_LOWBITDEPTH) ref_fmt |= AOM_IMG_FMT_HIGHBITDEPTH; + // Allocate memory with the border so that it can be used as a reference. + for (i = 0; i < reference_image_num; i++) { + if (!aom_img_alloc_with_border(&reference_images[i], ref_fmt, cfg->g_w, + cfg->g_h, 32, 8, AOM_BORDER_IN_PIXELS)) { + die("Failed to allocate image."); + } + } + + printf("\n Second pass: "); + // Encode reference images first. printf("Encoding Reference Images\n"); for (bv = 0; bv < v_blocks; ++bv) { @@ -299,7 +296,6 @@ static void pass1(aom_image_t *raw, FILE *infile, const char *outfile_name, int block_v_end = (bv + 1) * lf_blocksize; int u_block_size, v_block_size; int block_ref_u, block_ref_v; - struct av1_ref_frame ref_frame; block_u_end = block_u_end < lf_width ? block_u_end : lf_width; block_v_end = block_v_end < lf_height ? block_v_end : lf_height; @@ -307,25 +303,52 @@ static void pass1(aom_image_t *raw, FILE *infile, const char *outfile_name, v_block_size = block_v_end - block_v_min; block_ref_u = block_u_min + u_block_size / 2; block_ref_v = block_v_min + v_block_size / 2; + + printf("A%d, ", (block_ref_u + block_ref_v * lf_width)); fseek(infile, (block_ref_u + block_ref_v * lf_width) * image_size_bytes, SEEK_SET); aom_img_read(raw, infile); - if (aom_codec_control(&codec, AOME_USE_REFERENCE, - AOM_LAST_FLAG | AOM_GOLD_FLAG | AOM_ALT_FLAG)) - die_codec(&codec, "Failed to set reference flags"); + + get_raw_image(&frame_to_encode, raw, raw_shift); + // Reference frames may be encoded without tiles. ++frame_count; printf("Encoding reference image %d of %d\n", bv * u_blocks + bu, u_blocks * v_blocks); - encode_frame(&codec, raw, frame_count, 1, - AOM_EFLAG_FORCE_GF | AOM_EFLAG_NO_UPD_ENTROPY, deadline, + encode_frame(&codec, frame_to_encode, frame_count, 1, + AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 | + AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF | + AOM_EFLAG_NO_REF_BWD | AOM_EFLAG_NO_REF_ARF2 | + AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF | + AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_ENTROPY, writer); - ref_frame.idx = 0; - aom_codec_control(&codec, AV1_GET_REFERENCE, &ref_frame); - aom_img_copy(&ref_frame.img, &reference_images[frame_count - 1]); + + if (aom_codec_control(&codec, AV1_COPY_NEW_FRAME_IMAGE, + &reference_images[frame_count - 1])) + die_codec(&codec, "Failed to copy decoder reference frame"); } } + cfg->large_scale_tile = 1; + // Fixed q encoding for camera frames. + cfg->rc_end_usage = AOM_Q; + if (aom_codec_enc_config_set(&codec, cfg)) + die_codec(&codec, "Failed to configure encoder"); + + // The fixed q value used in encoding. + if (aom_codec_control(&codec, AOME_SET_CQ_LEVEL, 36)) + die_codec(&codec, "Failed to set cq level"); + if (aom_codec_control(&codec, AV1E_SET_FRAME_PARALLEL_DECODING, 1)) + die_codec(&codec, "Failed to set frame parallel decoding"); + if (aom_codec_control(&codec, AV1E_SET_SINGLE_TILE_DECODING, 1)) + die_codec(&codec, "Failed to turn on single tile decoding"); + // Set tile_columns and tile_rows to MAX values, which guarantees the tile + // size of 64 x 64 pixels(i.e. 1 SB) for <= 4k resolution. + if (aom_codec_control(&codec, AV1E_SET_TILE_COLUMNS, 6)) + die_codec(&codec, "Failed to set tile width"); + if (aom_codec_control(&codec, AV1E_SET_TILE_ROWS, 6)) + die_codec(&codec, "Failed to set tile height"); + for (bv = 0; bv < v_blocks; ++bv) { for (bu = 0; bu < u_blocks; ++bu) { const int block_u_min = bu * lf_blocksize; @@ -337,56 +360,44 @@ static void pass1(aom_image_t *raw, FILE *infile, const char *outfile_name, block_v_end = block_v_end < lf_height ? block_v_end : lf_height; for (v = block_v_min; v < block_v_end; ++v) { for (u = block_u_min; u < block_u_end; ++u) { - // This was a work around for a bug in libvpx. I'm not sure if this - // same bug exists in current version of av1. Need to call this, - // otherwise the default is to not use any reference frames. Then - // if you don't have at least one AOM_EFLAG_NO_REF_* flag, all frames - // will be intra encoded. I'm not sure why the default is not to use - // any reference frames. It looks like there is something about the - // way I encode the reference frames above that sets that as - // default... - if (aom_codec_control(&codec, AOME_USE_REFERENCE, - AOM_LAST_FLAG | AOM_GOLD_FLAG | AOM_ALT_FLAG)) - die_codec(&codec, "Failed to set reference flags"); - - // Set tile size to 64 pixels. The tile_columns and - // tile_rows in the tile coding are overloaded to represent tile_width - // and tile_height, that range from 1 to 64, in the unit of 64 pixels. - if (aom_codec_control(&codec, AV1E_SET_TILE_COLUMNS, 1)) - die_codec(&codec, "Failed to set tile width"); - if (aom_codec_control(&codec, AV1E_SET_TILE_ROWS, 1)) - die_codec(&codec, "Failed to set tile height"); - av1_ref_frame_t ref; ref.idx = 0; + ref.use_external_ref = 1; ref.img = reference_images[bv * u_blocks + bu]; if (aom_codec_control(&codec, AV1_SET_REFERENCE, &ref)) die_codec(&codec, "Failed to set reference frame"); + + printf("C%d, ", (u + v * lf_width)); fseek(infile, (u + v * lf_width) * image_size_bytes, SEEK_SET); aom_img_read(raw, infile); - ++frame_count; + get_raw_image(&frame_to_encode, raw, raw_shift); + ++frame_count; printf("Encoding image %d of %d\n", frame_count - (u_blocks * v_blocks), lf_width * lf_height); - encode_frame(&codec, raw, frame_count, 1, - AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF | - AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_ENTROPY | - AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF, - deadline, writer); + encode_frame(&codec, frame_to_encode, frame_count, 1, + AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 | + AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF | + AOM_EFLAG_NO_REF_BWD | AOM_EFLAG_NO_REF_ARF2 | + AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF | + AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_ENTROPY, + writer); } } } } // Flush encoder. - while (encode_frame(&codec, NULL, -1, 1, 0, deadline, writer)) { + // No ARF, this should not be needed. + while (encode_frame(&codec, NULL, -1, 1, 0, writer)) { } - if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec."); + for (i = 0; i < reference_image_num; i++) aom_img_free(&reference_images[i]); + if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec."); aom_video_writer_close(writer); - printf("Pass 1 complete. Processed %d frames.\n", frame_count); + printf("\nSecond pass complete. Processed %d frames.\n", frame_count); } int main(int argc, char **argv) { @@ -401,8 +412,10 @@ int main(int argc, char **argv) { aom_codec_ctx_t codec; aom_codec_enc_cfg_t cfg; aom_image_t raw; + aom_image_t raw_shift; aom_codec_err_t res; aom_fixed_buf_t stats; + int flags = 0; const AvxInterface *encoder = NULL; const int fps = 30; @@ -435,14 +448,19 @@ int main(int argc, char **argv) { die("Invalid lf_width and/or lf_height: %dx%d", lf_width, lf_height); if (lf_blocksize <= 0) die("Invalid lf_blocksize: %d", lf_blocksize); - if (!aom_img_alloc(&raw, AOM_IMG_FMT_I420, w, h, 1)) - die("Failed to allocate image", w, h); + if (!aom_img_alloc(&raw, AOM_IMG_FMT_I420, w, h, 32)) { + die("Failed to allocate image."); + } + if (!CONFIG_LOWBITDEPTH) { + // Need to allocate larger buffer to use hbd internal. + aom_img_alloc(&raw_shift, AOM_IMG_FMT_I420 | AOM_IMG_FMT_HIGHBITDEPTH, w, h, + 32); + } printf("Using %s\n", aom_codec_iface_name(encoder->codec_interface())); // Configuration res = aom_codec_enc_config_default(encoder->codec_interface(), &cfg, 0); - if (res) die_codec(&codec, "Failed to get default codec config."); cfg.g_w = w; @@ -450,29 +468,32 @@ int main(int argc, char **argv) { cfg.g_timebase.num = 1; cfg.g_timebase.den = fps; cfg.rc_target_bitrate = bitrate; - cfg.g_error_resilient = AOM_ERROR_RESILIENT_DEFAULT; - // Need to set lag_in_frames to 1 or 0. Otherwise the frame flags get - // overridden after the first frame in encode_frame_to_data_rate() (see where - // get_frame_flags() is called). - cfg.g_lag_in_frames = 0; + cfg.g_error_resilient = 0; // This is required. + cfg.g_lag_in_frames = 0; // need to set this since default is 19. cfg.kf_mode = AOM_KF_DISABLED; - cfg.large_scale_tile = 1; + cfg.large_scale_tile = 0; // Only set it to 1 for camera frame encoding. + cfg.g_bit_depth = AOM_BITS_8; + flags |= (cfg.g_bit_depth > AOM_BITS_8 || !CONFIG_LOWBITDEPTH) + ? AOM_CODEC_USE_HIGHBITDEPTH + : 0; if (!(infile = fopen(infile_arg, "rb"))) die("Failed to open %s for reading", infile_arg); // Pass 0 cfg.g_pass = AOM_RC_FIRST_PASS; - stats = pass0(&raw, infile, encoder, &cfg, lf_width, lf_height, lf_blocksize); + stats = pass0(&raw, infile, encoder, &cfg, lf_width, lf_height, lf_blocksize, + flags, &raw_shift); // Pass 1 rewind(infile); cfg.g_pass = AOM_RC_LAST_PASS; cfg.rc_twopass_stats_in = stats; pass1(&raw, infile, outfile_arg, encoder, &cfg, lf_width, lf_height, - lf_blocksize); + lf_blocksize, flags, &raw_shift); free(stats.buf); + if (!CONFIG_LOWBITDEPTH) aom_img_free(&raw_shift); aom_img_free(&raw); fclose(infile); diff --git a/third_party/aom/examples/lightfield_tile_list_decoder.c b/third_party/aom/examples/lightfield_tile_list_decoder.c new file mode 100644 index 000000000..cec6baa2c --- /dev/null +++ b/third_party/aom/examples/lightfield_tile_list_decoder.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2018, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +// Lightfield Tile List Decoder +// ============================ +// +// This is a lightfield tile list decoder example. It takes an input file that +// contains the anchor frames that are references of the coded tiles, the camera +// frame header, and tile list OBUs that include the tile information and the +// compressed tile data. This input file is reconstructed from the encoded +// lightfield ivf file, and is decodable by AV1 decoder. The lf_width and +// lf_height arguments are the number of lightfield images in each dimension. +// The lf_blocksize determines the number of reference images used. +// Run lightfield tile list decoder to decode an AV1 tile list file: +// examples/lightfield_tile_list_decoder vase_tile_list.ivf vase_tile_list.yuv +// 10 10 5 2 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "aom/aom_decoder.h" +#include "aom/aomdx.h" +#include "common/tools_common.h" +#include "common/video_reader.h" + +#define MAX_EXTERNAL_REFERENCES 128 +#define AOM_BORDER_IN_PIXELS 288 + +static const char *exec_name; + +void usage_exit(void) { + fprintf(stderr, + "Usage: %s <infile> <outfile> <lf_width> <lf_height> <lf_blocksize> " + "<num_tile_lists>\n", + exec_name); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) { + FILE *outfile = NULL; + aom_codec_ctx_t codec; + AvxVideoReader *reader = NULL; + const AvxInterface *decoder = NULL; + const AvxVideoInfo *info = NULL; + const char *lf_width_arg; + const char *lf_height_arg; + const char *lf_blocksize_arg; + int width, height; + int lf_width, lf_height, lf_blocksize; + int u_blocks, v_blocks; + int num_tile_lists; + aom_image_t reference_images[MAX_EXTERNAL_REFERENCES]; + size_t frame_size = 0; + const unsigned char *frame = NULL; + int i, n; + + exec_name = argv[0]; + + if (argc != 7) die("Invalid number of arguments."); + + reader = aom_video_reader_open(argv[1]); + if (!reader) die("Failed to open %s for reading.", argv[1]); + + if (!(outfile = fopen(argv[2], "wb"))) + die("Failed to open %s for writing.", argv[2]); + + lf_width_arg = argv[3]; + lf_height_arg = argv[4]; + lf_blocksize_arg = argv[5]; + lf_width = (int)strtol(lf_width_arg, NULL, 0); + lf_height = (int)strtol(lf_height_arg, NULL, 0); + lf_blocksize = (int)strtol(lf_blocksize_arg, NULL, 0); + num_tile_lists = (int)strtol(argv[6], NULL, 0); + + info = aom_video_reader_get_info(reader); + width = info->frame_width; + height = info->frame_height; + + decoder = get_aom_decoder_by_fourcc(info->codec_fourcc); + if (!decoder) die("Unknown input codec."); + printf("Using %s\n", aom_codec_iface_name(decoder->codec_interface())); + + if (aom_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0)) + die_codec(&codec, "Failed to initialize decoder."); + + // How many anchor frames we have. + u_blocks = (lf_width + lf_blocksize - 1) / lf_blocksize; + v_blocks = (lf_height + lf_blocksize - 1) / lf_blocksize; + + int num_references = v_blocks * u_blocks; + + // Allocate memory to store decoded references. + aom_img_fmt_t ref_fmt = AOM_IMG_FMT_I420; + if (!CONFIG_LOWBITDEPTH) ref_fmt |= AOM_IMG_FMT_HIGHBITDEPTH; + // Allocate memory with the border so that it can be used as a reference. + for (i = 0; i < num_references; i++) { + unsigned int border = AOM_BORDER_IN_PIXELS; + if (!aom_img_alloc_with_border(&reference_images[i], ref_fmt, width, height, + 32, 8, border)) { + die("Failed to allocate references."); + } + } + + // Decode anchor frames. + aom_codec_control_(&codec, AV1_SET_TILE_MODE, 0); + + for (i = 0; i < num_references; ++i) { + aom_video_reader_read_frame(reader); + frame = aom_video_reader_get_frame(reader, &frame_size); + if (aom_codec_decode(&codec, frame, frame_size, NULL)) + die_codec(&codec, "Failed to decode frame."); + + if (aom_codec_control(&codec, AV1_COPY_NEW_FRAME_IMAGE, + &reference_images[i])) + die_codec(&codec, "Failed to copy decoded reference frame"); + + aom_codec_iter_t iter = NULL; + aom_image_t *img = NULL; + while ((img = aom_codec_get_frame(&codec, &iter)) != NULL) { + char name[1024]; + snprintf(name, sizeof(name), "ref_%d.yuv", i); + printf("writing ref image to %s, %d, %d\n", name, img->d_w, img->d_h); + FILE *ref_file = fopen(name, "wb"); + aom_img_write(img, ref_file); + fclose(ref_file); + } + } + + // Decode the lightfield. + aom_codec_control_(&codec, AV1_SET_TILE_MODE, 1); + + // Set external references. + av1_ext_ref_frame_t set_ext_ref = { &reference_images[0], num_references }; + aom_codec_control_(&codec, AV1D_SET_EXT_REF_PTR, &set_ext_ref); + + // Must decode the camera frame header first. + aom_video_reader_read_frame(reader); + frame = aom_video_reader_get_frame(reader, &frame_size); + if (aom_codec_decode(&codec, frame, frame_size, NULL)) + die_codec(&codec, "Failed to decode the frame."); + + // Decode tile lists one by one. + for (n = 0; n < num_tile_lists; n++) { + aom_video_reader_read_frame(reader); + frame = aom_video_reader_get_frame(reader, &frame_size); + + if (aom_codec_decode(&codec, frame, frame_size, NULL)) + die_codec(&codec, "Failed to decode the tile list."); + + aom_codec_iter_t iter = NULL; + aom_image_t *img; + while ((img = aom_codec_get_frame(&codec, &iter))) + fwrite(img->img_data, 1, img->sz, outfile); + } + + for (i = 0; i < num_references; i++) aom_img_free(&reference_images[i]); + if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec"); + aom_video_reader_close(reader); + fclose(outfile); + + return EXIT_SUCCESS; +} diff --git a/third_party/aom/examples/lossless_encoder.c b/third_party/aom/examples/lossless_encoder.c index 32ab18a16..438ff21c6 100644 --- a/third_party/aom/examples/lossless_encoder.c +++ b/third_party/aom/examples/lossless_encoder.c @@ -15,9 +15,8 @@ #include "aom/aom_encoder.h" #include "aom/aomcx.h" - -#include "../tools_common.h" -#include "../video_writer.h" +#include "common/tools_common.h" +#include "common/video_writer.h" static const char *exec_name; @@ -35,7 +34,7 @@ static int encode_frame(aom_codec_ctx_t *codec, aom_image_t *img, aom_codec_iter_t iter = NULL; const aom_codec_cx_pkt_t *pkt = NULL; const aom_codec_err_t res = - aom_codec_encode(codec, img, frame_index, 1, flags, AOM_DL_GOOD_QUALITY); + aom_codec_encode(codec, img, frame_index, 1, flags); if (res != AOM_CODEC_OK) die_codec(codec, "Failed to encode frame"); while ((pkt = aom_codec_get_cx_data(codec, &iter)) != NULL) { diff --git a/third_party/aom/examples/noise_model.c b/third_party/aom/examples/noise_model.c new file mode 100644 index 000000000..5a5b4d40d --- /dev/null +++ b/third_party/aom/examples/noise_model.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2018, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +/*!\file + * \brief This is an sample binary to create noise params from input video. + * + * To allow for external denoising applications, this sample binary illustrates + * how to create a film grain table (film grain params as a function of time) + * from an input video and its corresponding denoised source. + * + * The --output-grain-table file can be passed as input to the encoder (in + * aomenc this is done through the "--film-grain-table" parameter). + * + * As an example, where the input source is an 854x480 yuv420p 8-bit video + * named "input.854_480.yuv" you would use steps similar to the following: + * + * # Run your denoiser (e.g, using hqdn3d filter): + * ffmpeg -vcodec rawvideo -video_size 854x480 -i input.854_480.yuv \ + * -vf hqdn3d=5:5:5:5 -vcodec rawvideo -an -f rawvideo \ + * denoised.854_480.yuv + * + * # Model the noise between the denoised version and original source: + * ./examples/noise_model --fps=25/1 --width=854 --height=480 --i420 \ + * --input-denoised=denoised.854_480.yuv --input=original.854_480.yuv \ + * --output-grain-table=film_grain.tbl + * + * # Encode with your favorite settings (including the grain table): + * aomenc --limit=100 --cpu-used=4 --input-bit-depth=8 \ + * --i420 -w 854 -h 480 --end-usage=q --cq-level=25 --lag-in-frames=25 \ + * --auto-alt-ref=2 --bit-depth=8 --film-grain-table=film_grain.tbl \ + * -o denoised_with_grain_params.ivf denoised.854_480.yuv + */ +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "aom/aom_encoder.h" +#include "aom_dsp/aom_dsp_common.h" + +#if CONFIG_AV1_DECODER +#include "aom_dsp/grain_synthesis.h" +#endif + +#include "aom_dsp/grain_table.h" +#include "aom_dsp/noise_model.h" +#include "aom_dsp/noise_util.h" +#include "aom_mem/aom_mem.h" +#include "common/args.h" +#include "common/tools_common.h" +#include "common/video_writer.h" + +static const char *exec_name; + +void usage_exit(void) { + fprintf(stderr, + "Usage: %s --input=<input> --input-denoised=<denoised> " + "--output-grain-table=<outfile> " + "See comments in noise_model.c for more information.\n", + exec_name); + exit(EXIT_FAILURE); +} + +static const arg_def_t help = + ARG_DEF(NULL, "help", 0, "Show usage options and exit"); +static const arg_def_t width_arg = + ARG_DEF("w", "width", 1, "Input width (if rawvideo)"); +static const arg_def_t height_arg = + ARG_DEF("h", "height", 1, "Input height (if rawvideo)"); +static const arg_def_t skip_frames_arg = + ARG_DEF("s", "skip-frames", 1, "Number of frames to skip (default = 1)"); +static const arg_def_t fps_arg = ARG_DEF(NULL, "fps", 1, "Frame rate"); +static const arg_def_t input_arg = ARG_DEF("-i", "input", 1, "Input filename"); +static const arg_def_t output_grain_table_arg = + ARG_DEF("n", "output-grain-table", 1, "Output noise file"); +static const arg_def_t input_denoised_arg = + ARG_DEF("d", "input-denoised", 1, "Input denoised filename (YUV) only"); +static const arg_def_t flat_block_finder_arg = + ARG_DEF("b", "flat-block-finder", 1, "Run the flat block finder"); +static const arg_def_t block_size_arg = + ARG_DEF("b", "block-size", 1, "Block size"); +static const arg_def_t bit_depth_arg = + ARG_DEF(NULL, "bit-depth", 1, "Bit depth of input"); +static const arg_def_t use_i420 = + ARG_DEF(NULL, "i420", 0, "Input file (and denoised) is I420 (default)"); +static const arg_def_t use_i422 = + ARG_DEF(NULL, "i422", 0, "Input file (and denoised) is I422"); +static const arg_def_t use_i444 = + ARG_DEF(NULL, "i444", 0, "Input file (and denoised) is I444"); +static const arg_def_t debug_file_arg = + ARG_DEF(NULL, "debug-file", 1, "File to output debug info"); + +typedef struct { + int width; + int height; + struct aom_rational fps; + const char *input; + const char *input_denoised; + const char *output_grain_table; + int img_fmt; + int block_size; + int bit_depth; + int run_flat_block_finder; + int force_flat_psd; + int skip_frames; + const char *debug_file; +} noise_model_args_t; + +void parse_args(noise_model_args_t *noise_args, int *argc, char **argv) { + struct arg arg; + static const arg_def_t *main_args[] = { &help, + &input_arg, + &fps_arg, + &width_arg, + &height_arg, + &block_size_arg, + &output_grain_table_arg, + &input_denoised_arg, + &use_i420, + &use_i422, + &use_i444, + &debug_file_arg, + NULL }; + for (int argi = *argc + 1; *argv; argi++, argv++) { + if (arg_match(&arg, &help, argv)) { + fprintf(stdout, "\nOptions:\n"); + arg_show_usage(stdout, main_args); + exit(0); + } else if (arg_match(&arg, &width_arg, argv)) { + noise_args->width = atoi(arg.val); + } else if (arg_match(&arg, &height_arg, argv)) { + noise_args->height = atoi(arg.val); + } else if (arg_match(&arg, &input_arg, argv)) { + noise_args->input = arg.val; + } else if (arg_match(&arg, &input_denoised_arg, argv)) { + noise_args->input_denoised = arg.val; + } else if (arg_match(&arg, &output_grain_table_arg, argv)) { + noise_args->output_grain_table = arg.val; + } else if (arg_match(&arg, &block_size_arg, argv)) { + noise_args->block_size = atoi(arg.val); + } else if (arg_match(&arg, &bit_depth_arg, argv)) { + noise_args->bit_depth = atoi(arg.val); + } else if (arg_match(&arg, &flat_block_finder_arg, argv)) { + noise_args->run_flat_block_finder = atoi(arg.val); + } else if (arg_match(&arg, &fps_arg, argv)) { + noise_args->fps = arg_parse_rational(&arg); + } else if (arg_match(&arg, &use_i420, argv)) { + noise_args->img_fmt = AOM_IMG_FMT_I420; + } else if (arg_match(&arg, &use_i422, argv)) { + noise_args->img_fmt = AOM_IMG_FMT_I422; + } else if (arg_match(&arg, &use_i444, argv)) { + noise_args->img_fmt = AOM_IMG_FMT_I444; + } else if (arg_match(&arg, &skip_frames_arg, argv)) { + noise_args->skip_frames = atoi(arg.val); + } else if (arg_match(&arg, &debug_file_arg, argv)) { + noise_args->debug_file = arg.val; + } else { + fprintf(stdout, "Unknown arg: %s\n\nUsage:\n", *argv); + arg_show_usage(stdout, main_args); + exit(0); + } + } + if (noise_args->bit_depth > 8) { + noise_args->img_fmt |= AOM_IMG_FMT_HIGHBITDEPTH; + } +} + +#if CONFIG_AV1_DECODER +static void print_variance_y(FILE *debug_file, aom_image_t *raw, + aom_image_t *denoised, const uint8_t *flat_blocks, + int block_size, aom_film_grain_t *grain) { + aom_image_t renoised; + grain->apply_grain = 1; + grain->random_seed = 1071; + aom_img_alloc(&renoised, raw->fmt, raw->w, raw->h, 1); + av1_add_film_grain(grain, denoised, &renoised); + + const int num_blocks_w = (raw->w + block_size - 1) / block_size; + const int num_blocks_h = (raw->h + block_size - 1) / block_size; + fprintf(debug_file, "x = ["); + for (int by = 0; by < num_blocks_h; by++) { + for (int bx = 0; bx < num_blocks_w; bx++) { + double block_mean = 0; + double noise_std = 0, noise_mean = 0; + double renoise_std = 0, renoise_mean = 0; + for (int yi = 0; yi < block_size; ++yi) { + const int y = by * block_size + yi; + for (int xi = 0; xi < block_size; ++xi) { + const int x = bx * block_size + xi; + const double noise_v = (raw->planes[0][y * raw->stride[0] + x] - + denoised->planes[0][y * raw->stride[0] + x]); + noise_mean += noise_v; + noise_std += noise_v * noise_v; + + block_mean += raw->planes[0][y * raw->stride[0] + x]; + + const double renoise_v = + (renoised.planes[0][y * raw->stride[0] + x] - + denoised->planes[0][y * raw->stride[0] + x]); + renoise_mean += renoise_v; + renoise_std += renoise_v * renoise_v; + } + } + int n = (block_size * block_size); + block_mean /= n; + noise_mean /= n; + renoise_mean /= n; + noise_std = sqrt(noise_std / n - noise_mean * noise_mean); + renoise_std = sqrt(renoise_std / n - renoise_mean * renoise_mean); + fprintf(debug_file, "%d %3.2lf %3.2lf %3.2lf ", + flat_blocks[by * num_blocks_w + bx], block_mean, noise_std, + renoise_std); + } + fprintf(debug_file, "\n"); + } + fprintf(debug_file, "];\n"); + + if (raw->fmt & AOM_IMG_FMT_HIGHBITDEPTH) { + fprintf(stderr, + "Detailed debug info not supported for high bit" + "depth formats\n"); + } else { + fprintf(debug_file, "figure(2); clf;\n"); + fprintf(debug_file, + "scatter(x(:, 2:4:end), x(:, 3:4:end), 'r'); hold on;\n"); + fprintf(debug_file, "scatter(x(:, 2:4:end), x(:, 4:4:end), 'b');\n"); + fprintf(debug_file, + "plot(linspace(0, 255, length(noise_strength_0)), " + "noise_strength_0, 'b');\n"); + fprintf(debug_file, + "title('Scatter plot of intensity vs noise strength');\n"); + fprintf(debug_file, + "legend('Actual', 'Estimated', 'Estimated strength');\n"); + fprintf(debug_file, "figure(3); clf;\n"); + fprintf(debug_file, "scatter(x(:, 3:4:end), x(:, 4:4:end), 'k');\n"); + fprintf(debug_file, "title('Actual vs Estimated');\n"); + fprintf(debug_file, "pause(3);\n"); + } + aom_img_free(&renoised); +} +#endif + +static void print_debug_info(FILE *debug_file, aom_image_t *raw, + aom_image_t *denoised, uint8_t *flat_blocks, + int block_size, aom_noise_model_t *noise_model) { + (void)raw; + (void)denoised; + (void)flat_blocks; + (void)block_size; + fprintf(debug_file, "figure(3); clf;\n"); + fprintf(debug_file, "figure(2); clf;\n"); + fprintf(debug_file, "figure(1); clf;\n"); + for (int c = 0; c < 3; ++c) { + fprintf(debug_file, "noise_strength_%d = [\n", c); + const aom_equation_system_t *eqns = + &noise_model->combined_state[c].strength_solver.eqns; + for (int k = 0; k < eqns->n; ++k) { + fprintf(debug_file, "%lf ", eqns->x[k]); + } + fprintf(debug_file, "];\n"); + fprintf(debug_file, "plot(noise_strength_%d); hold on;\n", c); + } + fprintf(debug_file, "legend('Y', 'cb', 'cr');\n"); + fprintf(debug_file, "title('Noise strength function');\n"); + +#if CONFIG_AV1_DECODER + aom_film_grain_t grain; + aom_noise_model_get_grain_parameters(noise_model, &grain); + print_variance_y(debug_file, raw, denoised, flat_blocks, block_size, &grain); +#endif + fflush(debug_file); +} + +int main(int argc, char *argv[]) { + noise_model_args_t args = { 0, 0, { 25, 1 }, 0, 0, 0, AOM_IMG_FMT_I420, + 32, 8, 1, 0, 1, NULL }; + aom_image_t raw, denoised; + FILE *infile = NULL; + AvxVideoInfo info; + + memset(&info, 0, sizeof(info)); + + exec_name = argv[0]; + parse_args(&args, &argc, argv + 1); + + info.frame_width = args.width; + info.frame_height = args.height; + info.time_base.numerator = args.fps.den; + info.time_base.denominator = args.fps.num; + + if (info.frame_width <= 0 || info.frame_height <= 0 || + (info.frame_width % 2) != 0 || (info.frame_height % 2) != 0) { + die("Invalid frame size: %dx%d", info.frame_width, info.frame_height); + } + if (!aom_img_alloc(&raw, args.img_fmt, info.frame_width, info.frame_height, + 1)) { + die("Failed to allocate image."); + } + if (!aom_img_alloc(&denoised, args.img_fmt, info.frame_width, + info.frame_height, 1)) { + die("Failed to allocate image."); + } + infile = fopen(args.input, "r"); + if (!infile) { + die("Failed to open input file:", args.input); + } + fprintf(stderr, "Bit depth: %d stride:%d\n", args.bit_depth, raw.stride[0]); + + const int high_bd = args.bit_depth > 8; + const int block_size = args.block_size; + aom_flat_block_finder_t block_finder; + aom_flat_block_finder_init(&block_finder, block_size, args.bit_depth, + high_bd); + + const int num_blocks_w = (info.frame_width + block_size - 1) / block_size; + const int num_blocks_h = (info.frame_height + block_size - 1) / block_size; + uint8_t *flat_blocks = (uint8_t *)aom_malloc(num_blocks_w * num_blocks_h); + // Sets the random seed on the first entry in the output table + int16_t random_seed = 1071; + aom_noise_model_t noise_model; + aom_noise_model_params_t params = { AOM_NOISE_SHAPE_SQUARE, 3, args.bit_depth, + high_bd }; + aom_noise_model_init(&noise_model, params); + + FILE *denoised_file = 0; + if (args.input_denoised) { + denoised_file = fopen(args.input_denoised, "rb"); + if (!denoised_file) + die("Unable to open input_denoised: %s", args.input_denoised); + } else { + die("--input-denoised file must be specified"); + } + FILE *debug_file = 0; + if (args.debug_file) { + debug_file = fopen(args.debug_file, "w"); + } + aom_film_grain_table_t grain_table = { 0, 0 }; + + int64_t prev_timestamp = 0; + int frame_count = 0; + while (aom_img_read(&raw, infile)) { + if (args.input_denoised) { + if (!aom_img_read(&denoised, denoised_file)) { + die("Unable to read input denoised file"); + } + } + if (frame_count % args.skip_frames == 0) { + int num_flat_blocks = num_blocks_w * num_blocks_h; + memset(flat_blocks, 1, num_flat_blocks); + if (args.run_flat_block_finder) { + memset(flat_blocks, 0, num_flat_blocks); + num_flat_blocks = aom_flat_block_finder_run( + &block_finder, raw.planes[0], info.frame_width, info.frame_height, + info.frame_width, flat_blocks); + fprintf(stdout, "Num flat blocks %d\n", num_flat_blocks); + } + + const uint8_t *planes[3] = { raw.planes[0], raw.planes[1], + raw.planes[2] }; + uint8_t *denoised_planes[3] = { denoised.planes[0], denoised.planes[1], + denoised.planes[2] }; + int strides[3] = { raw.stride[0] >> high_bd, raw.stride[1] >> high_bd, + raw.stride[2] >> high_bd }; + int chroma_sub[3] = { raw.x_chroma_shift, raw.y_chroma_shift, 0 }; + + fprintf(stdout, "Updating noise model...\n"); + aom_noise_status_t status = aom_noise_model_update( + &noise_model, (const uint8_t *const *)planes, + (const uint8_t *const *)denoised_planes, info.frame_width, + info.frame_height, strides, chroma_sub, flat_blocks, block_size); + + int64_t cur_timestamp = + frame_count * 10000000ULL * args.fps.den / args.fps.num; + if (status == AOM_NOISE_STATUS_DIFFERENT_NOISE_TYPE) { + fprintf(stdout, + "Noise type is different, updating parameters for time " + "[ %" PRId64 ", %" PRId64 ")\n", + prev_timestamp, cur_timestamp); + aom_film_grain_t grain; + aom_noise_model_get_grain_parameters(&noise_model, &grain); + grain.random_seed = random_seed; + random_seed = 0; + aom_film_grain_table_append(&grain_table, prev_timestamp, cur_timestamp, + &grain); + aom_noise_model_save_latest(&noise_model); + prev_timestamp = cur_timestamp; + } + if (debug_file) { + print_debug_info(debug_file, &raw, &denoised, flat_blocks, block_size, + &noise_model); + } + fprintf(stdout, "Done noise model update, status = %d\n", status); + } + frame_count++; + } + + aom_film_grain_t grain; + aom_noise_model_get_grain_parameters(&noise_model, &grain); + grain.random_seed = random_seed; + aom_film_grain_table_append(&grain_table, prev_timestamp, INT64_MAX, &grain); + if (args.output_grain_table) { + struct aom_internal_error_info error_info; + if (AOM_CODEC_OK != aom_film_grain_table_write(&grain_table, + args.output_grain_table, + &error_info)) { + die("Unable to write output film grain table"); + } + } + aom_film_grain_table_free(&grain_table); + + if (infile) fclose(infile); + if (denoised_file) fclose(denoised_file); + if (debug_file) fclose(debug_file); + aom_img_free(&raw); + aom_img_free(&denoised); + + return EXIT_SUCCESS; +} diff --git a/third_party/aom/examples/resize_util.c b/third_party/aom/examples/resize_util.c index 5485691a8..6a84d5740 100644 --- a/third_party/aom/examples/resize_util.c +++ b/third_party/aom/examples/resize_util.c @@ -16,8 +16,8 @@ #include <stdlib.h> #include <string.h> -#include "../tools_common.h" -#include "../av1/encoder/av1_resize.h" +#include "av1/common/resize.h" +#include "common/tools_common.h" static const char *exec_name = NULL; diff --git a/third_party/aom/examples/scalable_decoder.c b/third_party/aom/examples/scalable_decoder.c new file mode 100644 index 000000000..c22924223 --- /dev/null +++ b/third_party/aom/examples/scalable_decoder.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2018, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +// Scalable Decoder +// ============== +// +// This is an example of a scalable decoder loop. It takes a 2-spatial-layer +// input file +// containing the compressed data (in OBU format), passes it through the +// decoder, and writes the decompressed frames to disk. The base layer and +// enhancement layers are stored as separate files, out_lyr0.yuv and +// out_lyr1.yuv, respectively. +// +// Standard Includes +// ----------------- +// For decoders, you only have to include `aom_decoder.h` and then any +// header files for the specific codecs you use. In this case, we're using +// av1. +// +// Initializing The Codec +// ---------------------- +// The libaom decoder is initialized by the call to aom_codec_dec_init(). +// Determining the codec interface to use is handled by AvxVideoReader and the +// functions prefixed with aom_video_reader_. Discussion of those functions is +// beyond the scope of this example, but the main gist is to open the input file +// and parse just enough of it to determine if it's a AVx file and which AVx +// codec is contained within the file. +// Note the NULL pointer passed to aom_codec_dec_init(). We do that in this +// example because we want the algorithm to determine the stream configuration +// (width/height) and allocate memory automatically. +// +// Decoding A Frame +// ---------------- +// Once the frame has been read into memory, it is decoded using the +// `aom_codec_decode` function. The call takes a pointer to the data +// (`frame`) and the length of the data (`frame_size`). No application data +// is associated with the frame in this example, so the `user_priv` +// parameter is NULL. The `deadline` parameter is left at zero for this +// example. This parameter is generally only used when doing adaptive post +// processing. +// +// Codecs may produce a variable number of output frames for every call to +// `aom_codec_decode`. These frames are retrieved by the +// `aom_codec_get_frame` iterator function. The iterator variable `iter` is +// initialized to NULL each time `aom_codec_decode` is called. +// `aom_codec_get_frame` is called in a loop, returning a pointer to a +// decoded image or NULL to indicate the end of list. +// +// Processing The Decoded Data +// --------------------------- +// In this example, we simply write the encoded data to disk. It is +// important to honor the image's `stride` values. +// +// Cleanup +// ------- +// The `aom_codec_destroy` call frees any memory allocated by the codec. +// +// Error Handling +// -------------- +// This example does not special case any error return codes. If there was +// an error, a descriptive message is printed and the program exits. With +// few exceptions, aom_codec functions return an enumerated error status, +// with the value `0` indicating success. + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "aom/aom_decoder.h" +#include "aom/aomdx.h" +#include "common/obudec.h" +#include "common/tools_common.h" +#include "common/video_reader.h" + +static const char *exec_name; + +#define MAX_LAYERS 5 + +void usage_exit(void) { + fprintf(stderr, "Usage: %s <infile>\n", exec_name); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) { + int frame_cnt = 0; + FILE *outfile[MAX_LAYERS]; + char filename[80]; + aom_codec_ctx_t codec; + const AvxInterface *decoder = NULL; + FILE *inputfile = NULL; + uint8_t *buf = NULL; + size_t bytes_in_buffer = 0; + size_t buffer_size = 0; + struct AvxInputContext aom_input_ctx; + struct ObuDecInputContext obu_ctx = { &aom_input_ctx, NULL, 0, 0, 0 }; + aom_codec_stream_info_t si; + uint8_t tmpbuf[32]; + unsigned int i; + + exec_name = argv[0]; + + if (argc != 2) die("Invalid number of arguments."); + + if (!(inputfile = fopen(argv[1], "rb"))) + die("Failed to open %s for read.", argv[1]); + obu_ctx.avx_ctx->file = inputfile; + obu_ctx.avx_ctx->filename = argv[1]; + + decoder = get_aom_decoder_by_index(0); + printf("Using %s\n", aom_codec_iface_name(decoder->codec_interface())); + + if (aom_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0)) + die_codec(&codec, "Failed to initialize decoder."); + + if (aom_codec_control(&codec, AV1D_SET_OUTPUT_ALL_LAYERS, 1)) { + die_codec(&codec, "Failed to set output_all_layers control."); + } + + // peak sequence header OBU to get number of spatial layers + const size_t ret = fread(tmpbuf, 1, 32, inputfile); + if (ret != 32) die_codec(&codec, "Input is not a valid obu file"); + si.is_annexb = 0; + if (aom_codec_peek_stream_info(decoder->codec_interface(), tmpbuf, 32, &si)) { + die_codec(&codec, "Input is not a valid obu file"); + } + fseek(inputfile, -32, SEEK_CUR); + + if (!file_is_obu(&obu_ctx)) + die_codec(&codec, "Input is not a valid obu file"); + + // open base layer output yuv file + snprintf(filename, sizeof(filename), "out_lyr%d.yuv", 0); + if (!(outfile[0] = fopen(filename, "wb"))) + die("Failed top open output for writing."); + + // open any enhancement layer output yuv files + for (i = 1; i < si.number_spatial_layers; i++) { + snprintf(filename, sizeof(filename), "out_lyr%d.yuv", i); + if (!(outfile[i] = fopen(filename, "wb"))) + die("Failed to open output for writing."); + } + + while (!obudec_read_temporal_unit(&obu_ctx, &buf, &bytes_in_buffer, + &buffer_size)) { + aom_codec_iter_t iter = NULL; + aom_image_t *img = NULL; + if (aom_codec_decode(&codec, buf, bytes_in_buffer, NULL)) + die_codec(&codec, "Failed to decode frame."); + + while ((img = aom_codec_get_frame(&codec, &iter)) != NULL) { + aom_image_t *img_shifted = + aom_img_alloc(NULL, AOM_IMG_FMT_I420, img->d_w, img->d_h, 16); + img_shifted->bit_depth = 8; + aom_img_downshift(img_shifted, img, + img->bit_depth - img_shifted->bit_depth); + if (img->spatial_id == 0) { + printf("Writing base layer 0 %d\n", frame_cnt); + aom_img_write(img_shifted, outfile[0]); + } else if (img->spatial_id <= (int)(si.number_spatial_layers - 1)) { + printf("Writing enhancement layer %d %d\n", img->spatial_id, frame_cnt); + aom_img_write(img_shifted, outfile[img->spatial_id]); + } else { + die_codec(&codec, "Invalid bitstream. Layer id exceeds layer count"); + } + if (img->spatial_id == (int)(si.number_spatial_layers - 1)) ++frame_cnt; + } + } + + printf("Processed %d frames.\n", frame_cnt); + if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec"); + + for (i = 0; i < si.number_spatial_layers; i++) fclose(outfile[i]); + + fclose(inputfile); + + return EXIT_SUCCESS; +} diff --git a/third_party/aom/examples/scalable_encoder.c b/third_party/aom/examples/scalable_encoder.c new file mode 100644 index 000000000..7af03e29f --- /dev/null +++ b/third_party/aom/examples/scalable_encoder.c @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2018, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +// Scalable Encoder +// ============== +// +// This is an example of a scalable encoder loop. It takes two input files in +// YV12 format, passes it through the encoder, and writes the compressed +// frames to disk in OBU format. +// +// Getting The Default Configuration +// --------------------------------- +// Encoders have the notion of "usage profiles." For example, an encoder +// may want to publish default configurations for both a video +// conferencing application and a best quality offline encoder. These +// obviously have very different default settings. Consult the +// documentation for your codec to see if it provides any default +// configurations. All codecs provide a default configuration, number 0, +// which is valid for material in the vacinity of QCIF/QVGA. +// +// Updating The Configuration +// --------------------------------- +// Almost all applications will want to update the default configuration +// with settings specific to their usage. Here we set the width and height +// of the video file to that specified on the command line. We also scale +// the default bitrate based on the ratio between the default resolution +// and the resolution specified on the command line. +// +// Encoding A Frame +// ---------------- +// The frame is read as a continuous block (size = width * height * 3 / 2) +// from the input file. If a frame was read (the input file has not hit +// EOF) then the frame is passed to the encoder. Otherwise, a NULL +// is passed, indicating the End-Of-Stream condition to the encoder. The +// `frame_cnt` is reused as the presentation time stamp (PTS) and each +// frame is shown for one frame-time in duration. The flags parameter is +// unused in this example. + +// Forced Keyframes +// ---------------- +// Keyframes can be forced by setting the AOM_EFLAG_FORCE_KF bit of the +// flags passed to `aom_codec_control()`. In this example, we force a +// keyframe every <keyframe-interval> frames. Note, the output stream can +// contain additional keyframes beyond those that have been forced using the +// AOM_EFLAG_FORCE_KF flag because of automatic keyframe placement by the +// encoder. +// +// Processing The Encoded Data +// --------------------------- +// Each packet of type `AOM_CODEC_CX_FRAME_PKT` contains the encoded data +// for this frame. We write a IVF frame header, followed by the raw data. +// +// Cleanup +// ------- +// The `aom_codec_destroy` call frees any memory allocated by the codec. +// +// Error Handling +// -------------- +// This example does not special case any error return codes. If there was +// an error, a descriptive message is printed and the program exits. With +// few exeptions, aom_codec functions return an enumerated error status, +// with the value `0` indicating success. + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "aom/aom_encoder.h" +#include "aom/aomcx.h" +#include "av1/common/enums.h" +#include "common/tools_common.h" +#include "common/video_writer.h" + +static const char *exec_name; + +void usage_exit(void) { + fprintf(stderr, + "Usage: %s <codec> <width> <height> <infile0> <infile1> " + "<outfile> <frames to encode>\n" + "See comments in scalable_encoder.c for more information.\n", + exec_name); + exit(EXIT_FAILURE); +} + +static int encode_frame(aom_codec_ctx_t *codec, aom_image_t *img, + int frame_index, int flags, FILE *outfile) { + int got_pkts = 0; + aom_codec_iter_t iter = NULL; + const aom_codec_cx_pkt_t *pkt = NULL; + const aom_codec_err_t res = + aom_codec_encode(codec, img, frame_index, 1, flags); + if (res != AOM_CODEC_OK) die_codec(codec, "Failed to encode frame"); + + while ((pkt = aom_codec_get_cx_data(codec, &iter)) != NULL) { + got_pkts = 1; + + if (pkt->kind == AOM_CODEC_CX_FRAME_PKT) { + const int keyframe = (pkt->data.frame.flags & AOM_FRAME_IS_KEY) != 0; + if (fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile) != + pkt->data.frame.sz) { + die_codec(codec, "Failed to write compressed frame"); + } + printf(keyframe ? "K" : "."); + printf(" %6d\n", (int)pkt->data.frame.sz); + fflush(stdout); + } + } + + return got_pkts; +} + +int main(int argc, char **argv) { + FILE *infile0 = NULL; + FILE *infile1 = NULL; + aom_codec_ctx_t codec; + aom_codec_enc_cfg_t cfg; + int frame_count = 0; + aom_image_t raw0, raw1; + aom_codec_err_t res; + AvxVideoInfo info; + const AvxInterface *encoder = NULL; + const int fps = 30; + const int bitrate = 200; + int keyframe_interval = 0; + int max_frames = 0; + int frames_encoded = 0; + const char *codec_arg = NULL; + const char *width_arg = NULL; + const char *height_arg = NULL; + const char *infile0_arg = NULL; + const char *infile1_arg = NULL; + const char *outfile_arg = NULL; + // const char *keyframe_interval_arg = NULL; + FILE *outfile = NULL; + + exec_name = argv[0]; + + // Clear explicitly, as simply assigning "{ 0 }" generates + // "missing-field-initializers" warning in some compilers. + memset(&info, 0, sizeof(info)); + + if (argc != 8) die("Invalid number of arguments"); + + codec_arg = argv[1]; + width_arg = argv[2]; + height_arg = argv[3]; + infile0_arg = argv[4]; + infile1_arg = argv[5]; + outfile_arg = argv[6]; + max_frames = (int)strtol(argv[7], NULL, 0); + + encoder = get_aom_encoder_by_name(codec_arg); + if (!encoder) die("Unsupported codec."); + + info.codec_fourcc = encoder->fourcc; + info.frame_width = (int)strtol(width_arg, NULL, 0); + info.frame_height = (int)strtol(height_arg, NULL, 0); + info.time_base.numerator = 1; + info.time_base.denominator = fps; + + if (info.frame_width <= 0 || info.frame_height <= 0 || + (info.frame_width % 2) != 0 || (info.frame_height % 2) != 0) { + die("Invalid frame size: %dx%d", info.frame_width, info.frame_height); + } + + if (!aom_img_alloc(&raw0, AOM_IMG_FMT_I420, info.frame_width, + info.frame_height, 1)) { + die("Failed to allocate image for layer 0."); + } + if (!aom_img_alloc(&raw1, AOM_IMG_FMT_I420, info.frame_width, + info.frame_height, 1)) { + die("Failed to allocate image for layer 1."); + } + + // keyframe_interval = (int)strtol(keyframe_interval_arg, NULL, 0); + keyframe_interval = 100; + if (keyframe_interval < 0) die("Invalid keyframe interval value."); + + printf("Using %s\n", aom_codec_iface_name(encoder->codec_interface())); + + res = aom_codec_enc_config_default(encoder->codec_interface(), &cfg, 0); + if (res) die_codec(&codec, "Failed to get default codec config."); + + cfg.g_w = info.frame_width; + cfg.g_h = info.frame_height; + cfg.g_timebase.num = info.time_base.numerator; + cfg.g_timebase.den = info.time_base.denominator; + cfg.rc_target_bitrate = bitrate; + cfg.g_error_resilient = 0; + cfg.g_lag_in_frames = 0; + cfg.rc_end_usage = AOM_Q; + cfg.save_as_annexb = 0; + + outfile = fopen(outfile_arg, "wb"); + if (!outfile) die("Failed to open %s for writing.", outfile_arg); + + if (!(infile0 = fopen(infile0_arg, "rb"))) + die("Failed to open %s for reading.", infile0_arg); + if (!(infile1 = fopen(infile1_arg, "rb"))) + die("Failed to open %s for reading.", infile0_arg); + + if (aom_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0)) + die_codec(&codec, "Failed to initialize encoder"); + if (aom_codec_control(&codec, AOME_SET_CPUUSED, 8)) + die_codec(&codec, "Failed to set cpu to 8"); + + if (aom_codec_control(&codec, AV1E_SET_TILE_COLUMNS, 2)) + die_codec(&codec, "Failed to set tile columns to 2"); + if (aom_codec_control(&codec, AV1E_SET_NUM_TG, 3)) + die_codec(&codec, "Failed to set num of tile groups to 3"); + + if (aom_codec_control(&codec, AOME_SET_NUMBER_SPATIAL_LAYERS, 2)) + die_codec(&codec, "Failed to set number of spatial layers to 2"); + + // Encode frames. + while (aom_img_read(&raw0, infile0)) { + int flags = 0; + + // configure and encode base layer + + if (keyframe_interval > 0 && frames_encoded % keyframe_interval == 0) + flags |= AOM_EFLAG_FORCE_KF; + else + // use previous base layer (LAST) as sole reference + // save this frame as LAST to be used as reference by enhanmcent layer + // and next base layer + flags |= AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 | + AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF | + AOM_EFLAG_NO_REF_BWD | AOM_EFLAG_NO_REF_ARF2 | + AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF | + AOM_EFLAG_NO_UPD_ENTROPY; + cfg.g_w = info.frame_width; + cfg.g_h = info.frame_height; + if (aom_codec_enc_config_set(&codec, &cfg)) + die_codec(&codec, "Failed to set enc cfg for layer 0"); + if (aom_codec_control(&codec, AOME_SET_SPATIAL_LAYER_ID, 0)) + die_codec(&codec, "Failed to set layer id to 0"); + if (aom_codec_control(&codec, AOME_SET_CQ_LEVEL, 62)) + die_codec(&codec, "Failed to set cq level"); + encode_frame(&codec, &raw0, frame_count++, flags, outfile); + + // configure and encode enhancement layer + + // use LAST (base layer) as sole reference + flags = AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 | + AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_REF_BWD | + AOM_EFLAG_NO_REF_ARF2 | AOM_EFLAG_NO_UPD_LAST | + AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF | + AOM_EFLAG_NO_UPD_ENTROPY; + cfg.g_w = info.frame_width; + cfg.g_h = info.frame_height; + aom_img_read(&raw1, infile1); + if (aom_codec_enc_config_set(&codec, &cfg)) + die_codec(&codec, "Failed to set enc cfg for layer 1"); + if (aom_codec_control(&codec, AOME_SET_SPATIAL_LAYER_ID, 1)) + die_codec(&codec, "Failed to set layer id to 1"); + if (aom_codec_control(&codec, AOME_SET_CQ_LEVEL, 10)) + die_codec(&codec, "Failed to set cq level"); + encode_frame(&codec, &raw1, frame_count++, flags, outfile); + + frames_encoded++; + + if (max_frames > 0 && frames_encoded >= max_frames) break; + } + + // Flush encoder. + while (encode_frame(&codec, NULL, -1, 0, outfile)) continue; + + printf("\n"); + fclose(infile0); + fclose(infile1); + printf("Processed %d frames.\n", frame_count / 2); + + aom_img_free(&raw0); + aom_img_free(&raw1); + if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec."); + + fclose(outfile); + + return EXIT_SUCCESS; +} diff --git a/third_party/aom/examples/set_maps.c b/third_party/aom/examples/set_maps.c index 3a54e5f96..9aeb96e43 100644 --- a/third_party/aom/examples/set_maps.c +++ b/third_party/aom/examples/set_maps.c @@ -47,11 +47,10 @@ #include <stdlib.h> #include <string.h> -#include "aom/aomcx.h" #include "aom/aom_encoder.h" - -#include "../tools_common.h" -#include "../video_writer.h" +#include "aom/aomcx.h" +#include "common/tools_common.h" +#include "common/video_writer.h" static const char *exec_name; @@ -95,8 +94,7 @@ static int encode_frame(aom_codec_ctx_t *codec, aom_image_t *img, int got_pkts = 0; aom_codec_iter_t iter = NULL; const aom_codec_cx_pkt_t *pkt = NULL; - const aom_codec_err_t res = - aom_codec_encode(codec, img, frame_index, 1, 0, AOM_DL_GOOD_QUALITY); + const aom_codec_err_t res = aom_codec_encode(codec, img, frame_index, 1, 0); if (res != AOM_CODEC_OK) die_codec(codec, "Failed to encode frame"); while ((pkt = aom_codec_get_cx_data(codec, &iter)) != NULL) { diff --git a/third_party/aom/examples/simple_decoder.c b/third_party/aom/examples/simple_decoder.c index 33a894539..d098d1e0b 100644 --- a/third_party/aom/examples/simple_decoder.c +++ b/third_party/aom/examples/simple_decoder.c @@ -49,9 +49,7 @@ // `aom_codec_decode` function. The call takes a pointer to the data // (`frame`) and the length of the data (`frame_size`). No application data // is associated with the frame in this example, so the `user_priv` -// parameter is NULL. The `deadline` parameter is left at zero for this -// example. This parameter is generally only used when doing adaptive post -// processing. +// parameter is NULL. // // Codecs may produce a variable number of output frames for every call to // `aom_codec_decode`. These frames are retrieved by the @@ -81,10 +79,8 @@ #include <string.h> #include "aom/aom_decoder.h" - -#include "../tools_common.h" -#include "../video_reader.h" -#include "./aom_config.h" +#include "common/tools_common.h" +#include "common/video_reader.h" static const char *exec_name; @@ -127,7 +123,7 @@ int main(int argc, char **argv) { size_t frame_size = 0; const unsigned char *frame = aom_video_reader_get_frame(reader, &frame_size); - if (aom_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0)) + if (aom_codec_decode(&codec, frame, frame_size, NULL)) die_codec(&codec, "Failed to decode frame."); while ((img = aom_codec_get_frame(&codec, &iter)) != NULL) { diff --git a/third_party/aom/examples/simple_encoder.c b/third_party/aom/examples/simple_encoder.c index 996f6dacf..01a37cf0c 100644 --- a/third_party/aom/examples/simple_encoder.c +++ b/third_party/aom/examples/simple_encoder.c @@ -100,9 +100,8 @@ #include <string.h> #include "aom/aom_encoder.h" - -#include "../tools_common.h" -#include "../video_writer.h" +#include "common/tools_common.h" +#include "common/video_writer.h" static const char *exec_name; @@ -121,7 +120,7 @@ static int encode_frame(aom_codec_ctx_t *codec, aom_image_t *img, aom_codec_iter_t iter = NULL; const aom_codec_cx_pkt_t *pkt = NULL; const aom_codec_err_t res = - aom_codec_encode(codec, img, frame_index, 1, flags, AOM_DL_GOOD_QUALITY); + aom_codec_encode(codec, img, frame_index, 1, flags); if (res != AOM_CODEC_OK) die_codec(codec, "Failed to encode frame"); while ((pkt = aom_codec_get_cx_data(codec, &iter)) != NULL) { diff --git a/third_party/aom/examples/twopass_encoder.c b/third_party/aom/examples/twopass_encoder.c index e767bb5d7..1b134cce0 100644 --- a/third_party/aom/examples/twopass_encoder.c +++ b/third_party/aom/examples/twopass_encoder.c @@ -52,9 +52,8 @@ #include <string.h> #include "aom/aom_encoder.h" - -#include "../tools_common.h" -#include "../video_writer.h" +#include "common/tools_common.h" +#include "common/video_writer.h" static const char *exec_name; @@ -68,13 +67,12 @@ void usage_exit(void) { static int get_frame_stats(aom_codec_ctx_t *ctx, const aom_image_t *img, aom_codec_pts_t pts, unsigned int duration, - aom_enc_frame_flags_t flags, unsigned int deadline, + aom_enc_frame_flags_t flags, aom_fixed_buf_t *stats) { int got_pkts = 0; aom_codec_iter_t iter = NULL; const aom_codec_cx_pkt_t *pkt = NULL; - const aom_codec_err_t res = - aom_codec_encode(ctx, img, pts, duration, flags, deadline); + const aom_codec_err_t res = aom_codec_encode(ctx, img, pts, duration, flags); if (res != AOM_CODEC_OK) die_codec(ctx, "Failed to get frame stats."); while ((pkt = aom_codec_get_cx_data(ctx, &iter)) != NULL) { @@ -94,13 +92,11 @@ static int get_frame_stats(aom_codec_ctx_t *ctx, const aom_image_t *img, static int encode_frame(aom_codec_ctx_t *ctx, const aom_image_t *img, aom_codec_pts_t pts, unsigned int duration, - aom_enc_frame_flags_t flags, unsigned int deadline, - AvxVideoWriter *writer) { + aom_enc_frame_flags_t flags, AvxVideoWriter *writer) { int got_pkts = 0; aom_codec_iter_t iter = NULL; const aom_codec_cx_pkt_t *pkt = NULL; - const aom_codec_err_t res = - aom_codec_encode(ctx, img, pts, duration, flags, deadline); + const aom_codec_err_t res = aom_codec_encode(ctx, img, pts, duration, flags); if (res != AOM_CODEC_OK) die_codec(ctx, "Failed to encode frame."); while ((pkt = aom_codec_get_cx_data(ctx, &iter)) != NULL) { @@ -133,13 +129,11 @@ static aom_fixed_buf_t pass0(aom_image_t *raw, FILE *infile, // Calculate frame statistics. while (aom_img_read(raw, infile) && frame_count < limit) { ++frame_count; - get_frame_stats(&codec, raw, frame_count, 1, 0, AOM_DL_GOOD_QUALITY, - &stats); + get_frame_stats(&codec, raw, frame_count, 1, 0, &stats); } // Flush encoder. - while (get_frame_stats(&codec, NULL, frame_count, 1, 0, AOM_DL_GOOD_QUALITY, - &stats)) { + while (get_frame_stats(&codec, NULL, frame_count, 1, 0, &stats)) { } printf("Pass 0 complete. Processed %d frames.\n", frame_count); @@ -168,11 +162,11 @@ static void pass1(aom_image_t *raw, FILE *infile, const char *outfile_name, // Encode frames. while (aom_img_read(raw, infile) && frame_count < limit) { ++frame_count; - encode_frame(&codec, raw, frame_count, 1, 0, AOM_DL_GOOD_QUALITY, writer); + encode_frame(&codec, raw, frame_count, 1, 0, writer); } // Flush encoder. - while (encode_frame(&codec, NULL, -1, 1, 0, AOM_DL_GOOD_QUALITY, writer)) { + while (encode_frame(&codec, NULL, -1, 1, 0, writer)) { } printf("\n"); |