scalable_encoder.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /*
  2. * Copyright (c) 2018, Alliance for Open Media. All rights reserved
  3. *
  4. * This source code is subject to the terms of the BSD 2 Clause License and
  5. * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
  6. * was not distributed with this source code in the LICENSE file, you can
  7. * obtain it at www.aomedia.org/license/software. If the Alliance for Open
  8. * Media Patent License 1.0 was not distributed with this source code in the
  9. * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  10. */
  11. // Scalable Encoder
  12. // ==============
  13. //
  14. // This is an example of a scalable encoder loop. It takes two input files in
  15. // YV12 format, passes it through the encoder, and writes the compressed
  16. // frames to disk in OBU format.
  17. //
  18. // Getting The Default Configuration
  19. // ---------------------------------
  20. // Encoders have the notion of "usage profiles." For example, an encoder
  21. // may want to publish default configurations for both a video
  22. // conferencing application and a best quality offline encoder. These
  23. // obviously have very different default settings. Consult the
  24. // documentation for your codec to see if it provides any default
  25. // configurations. All codecs provide a default configuration, number 0,
  26. // which is valid for material in the vacinity of QCIF/QVGA.
  27. //
  28. // Updating The Configuration
  29. // ---------------------------------
  30. // Almost all applications will want to update the default configuration
  31. // with settings specific to their usage. Here we set the width and height
  32. // of the video file to that specified on the command line. We also scale
  33. // the default bitrate based on the ratio between the default resolution
  34. // and the resolution specified on the command line.
  35. //
  36. // Encoding A Frame
  37. // ----------------
  38. // The frame is read as a continuous block (size = width * height * 3 / 2)
  39. // from the input file. If a frame was read (the input file has not hit
  40. // EOF) then the frame is passed to the encoder. Otherwise, a NULL
  41. // is passed, indicating the End-Of-Stream condition to the encoder. The
  42. // `frame_cnt` is reused as the presentation time stamp (PTS) and each
  43. // frame is shown for one frame-time in duration. The flags parameter is
  44. // unused in this example.
  45. // Forced Keyframes
  46. // ----------------
  47. // Keyframes can be forced by setting the AOM_EFLAG_FORCE_KF bit of the
  48. // flags passed to `aom_codec_control()`. In this example, we force a
  49. // keyframe every <keyframe-interval> frames. Note, the output stream can
  50. // contain additional keyframes beyond those that have been forced using the
  51. // AOM_EFLAG_FORCE_KF flag because of automatic keyframe placement by the
  52. // encoder.
  53. //
  54. // Processing The Encoded Data
  55. // ---------------------------
  56. // Each packet of type `AOM_CODEC_CX_FRAME_PKT` contains the encoded data
  57. // for this frame. We write a IVF frame header, followed by the raw data.
  58. //
  59. // Cleanup
  60. // -------
  61. // The `aom_codec_destroy` call frees any memory allocated by the codec.
  62. //
  63. // Error Handling
  64. // --------------
  65. // This example does not special case any error return codes. If there was
  66. // an error, a descriptive message is printed and the program exits. With
  67. // few exeptions, aom_codec functions return an enumerated error status,
  68. // with the value `0` indicating success.
  69. #include <stdio.h>
  70. #include <stdlib.h>
  71. #include <string.h>
  72. #include "aom/aom_encoder.h"
  73. #include "aom/aomcx.h"
  74. #include "av1/common/enums.h"
  75. #include "common/tools_common.h"
  76. #include "common/video_writer.h"
  77. static const char *exec_name;
  78. void usage_exit(void) {
  79. fprintf(stderr,
  80. "Usage: %s <codec> <width> <height> <infile0> <infile1> "
  81. "<outfile> <frames to encode>\n"
  82. "See comments in scalable_encoder.c for more information.\n",
  83. exec_name);
  84. exit(EXIT_FAILURE);
  85. }
  86. static int encode_frame(aom_codec_ctx_t *codec, aom_image_t *img,
  87. int frame_index, int flags, FILE *outfile) {
  88. int got_pkts = 0;
  89. aom_codec_iter_t iter = NULL;
  90. const aom_codec_cx_pkt_t *pkt = NULL;
  91. const aom_codec_err_t res =
  92. aom_codec_encode(codec, img, frame_index, 1, flags);
  93. if (res != AOM_CODEC_OK) die_codec(codec, "Failed to encode frame");
  94. while ((pkt = aom_codec_get_cx_data(codec, &iter)) != NULL) {
  95. got_pkts = 1;
  96. if (pkt->kind == AOM_CODEC_CX_FRAME_PKT) {
  97. const int keyframe = (pkt->data.frame.flags & AOM_FRAME_IS_KEY) != 0;
  98. if (fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile) !=
  99. pkt->data.frame.sz) {
  100. die_codec(codec, "Failed to write compressed frame");
  101. }
  102. printf(keyframe ? "K" : ".");
  103. printf(" %6d\n", (int)pkt->data.frame.sz);
  104. fflush(stdout);
  105. }
  106. }
  107. return got_pkts;
  108. }
  109. int main(int argc, char **argv) {
  110. FILE *infile0 = NULL;
  111. FILE *infile1 = NULL;
  112. aom_codec_enc_cfg_t cfg;
  113. int frame_count = 0;
  114. aom_image_t raw0, raw1;
  115. aom_codec_err_t res;
  116. AvxVideoInfo info;
  117. const int fps = 30;
  118. const int bitrate = 200;
  119. int keyframe_interval = 0;
  120. int max_frames = 0;
  121. int frames_encoded = 0;
  122. const char *codec_arg = NULL;
  123. const char *width_arg = NULL;
  124. const char *height_arg = NULL;
  125. const char *infile0_arg = NULL;
  126. const char *infile1_arg = NULL;
  127. const char *outfile_arg = NULL;
  128. // const char *keyframe_interval_arg = NULL;
  129. FILE *outfile = NULL;
  130. exec_name = argv[0];
  131. // Clear explicitly, as simply assigning "{ 0 }" generates
  132. // "missing-field-initializers" warning in some compilers.
  133. memset(&info, 0, sizeof(info));
  134. if (argc != 8) die("Invalid number of arguments");
  135. codec_arg = argv[1];
  136. width_arg = argv[2];
  137. height_arg = argv[3];
  138. infile0_arg = argv[4];
  139. infile1_arg = argv[5];
  140. outfile_arg = argv[6];
  141. max_frames = (int)strtol(argv[7], NULL, 0);
  142. aom_codec_iface_t *encoder = get_aom_encoder_by_short_name(codec_arg);
  143. if (!encoder) die("Unsupported codec.");
  144. info.codec_fourcc = get_fourcc_by_aom_encoder(encoder);
  145. info.frame_width = (int)strtol(width_arg, NULL, 0);
  146. info.frame_height = (int)strtol(height_arg, NULL, 0);
  147. info.time_base.numerator = 1;
  148. info.time_base.denominator = fps;
  149. if (info.frame_width <= 0 || info.frame_height <= 0 ||
  150. (info.frame_width % 2) != 0 || (info.frame_height % 2) != 0) {
  151. die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
  152. }
  153. if (!aom_img_alloc(&raw0, AOM_IMG_FMT_I420, info.frame_width,
  154. info.frame_height, 1)) {
  155. die("Failed to allocate image for layer 0.");
  156. }
  157. if (!aom_img_alloc(&raw1, AOM_IMG_FMT_I420, info.frame_width,
  158. info.frame_height, 1)) {
  159. die("Failed to allocate image for layer 1.");
  160. }
  161. // keyframe_interval = (int)strtol(keyframe_interval_arg, NULL, 0);
  162. keyframe_interval = 100;
  163. if (keyframe_interval < 0) die("Invalid keyframe interval value.");
  164. printf("Using %s\n", aom_codec_iface_name(encoder));
  165. aom_codec_ctx_t codec;
  166. res = aom_codec_enc_config_default(encoder, &cfg, 0);
  167. if (res) die_codec(&codec, "Failed to get default codec config.");
  168. cfg.g_w = info.frame_width;
  169. cfg.g_h = info.frame_height;
  170. cfg.g_timebase.num = info.time_base.numerator;
  171. cfg.g_timebase.den = info.time_base.denominator;
  172. cfg.rc_target_bitrate = bitrate;
  173. cfg.g_error_resilient = 0;
  174. cfg.g_lag_in_frames = 0;
  175. cfg.rc_end_usage = AOM_Q;
  176. cfg.save_as_annexb = 0;
  177. outfile = fopen(outfile_arg, "wb");
  178. if (!outfile) die("Failed to open %s for writing.", outfile_arg);
  179. if (!(infile0 = fopen(infile0_arg, "rb")))
  180. die("Failed to open %s for reading.", infile0_arg);
  181. if (!(infile1 = fopen(infile1_arg, "rb")))
  182. die("Failed to open %s for reading.", infile0_arg);
  183. if (aom_codec_enc_init(&codec, encoder, &cfg, 0))
  184. die("Failed to initialize encoder");
  185. if (aom_codec_control(&codec, AOME_SET_CPUUSED, 8))
  186. die_codec(&codec, "Failed to set cpu to 8");
  187. if (aom_codec_control(&codec, AV1E_SET_TILE_COLUMNS, 2))
  188. die_codec(&codec, "Failed to set tile columns to 2");
  189. if (aom_codec_control(&codec, AV1E_SET_NUM_TG, 3))
  190. die_codec(&codec, "Failed to set num of tile groups to 3");
  191. if (aom_codec_control(&codec, AOME_SET_NUMBER_SPATIAL_LAYERS, 2))
  192. die_codec(&codec, "Failed to set number of spatial layers to 2");
  193. // Encode frames.
  194. while (aom_img_read(&raw0, infile0)) {
  195. int flags = 0;
  196. // configure and encode base layer
  197. if (keyframe_interval > 0 && frames_encoded % keyframe_interval == 0)
  198. flags |= AOM_EFLAG_FORCE_KF;
  199. else
  200. // use previous base layer (LAST) as sole reference
  201. // save this frame as LAST to be used as reference by enhanmcent layer
  202. // and next base layer
  203. flags |= AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 |
  204. AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF |
  205. AOM_EFLAG_NO_REF_BWD | AOM_EFLAG_NO_REF_ARF2 |
  206. AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF |
  207. AOM_EFLAG_NO_UPD_ENTROPY;
  208. cfg.g_w = info.frame_width;
  209. cfg.g_h = info.frame_height;
  210. if (aom_codec_enc_config_set(&codec, &cfg))
  211. die_codec(&codec, "Failed to set enc cfg for layer 0");
  212. if (aom_codec_control(&codec, AOME_SET_SPATIAL_LAYER_ID, 0))
  213. die_codec(&codec, "Failed to set layer id to 0");
  214. if (aom_codec_control(&codec, AOME_SET_CQ_LEVEL, 62))
  215. die_codec(&codec, "Failed to set cq level");
  216. encode_frame(&codec, &raw0, frame_count++, flags, outfile);
  217. // configure and encode enhancement layer
  218. // use LAST (base layer) as sole reference
  219. flags = AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 |
  220. AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_REF_BWD |
  221. AOM_EFLAG_NO_REF_ARF2 | AOM_EFLAG_NO_UPD_LAST |
  222. AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF |
  223. AOM_EFLAG_NO_UPD_ENTROPY;
  224. cfg.g_w = info.frame_width;
  225. cfg.g_h = info.frame_height;
  226. aom_img_read(&raw1, infile1);
  227. if (aom_codec_enc_config_set(&codec, &cfg))
  228. die_codec(&codec, "Failed to set enc cfg for layer 1");
  229. if (aom_codec_control(&codec, AOME_SET_SPATIAL_LAYER_ID, 1))
  230. die_codec(&codec, "Failed to set layer id to 1");
  231. if (aom_codec_control(&codec, AOME_SET_CQ_LEVEL, 10))
  232. die_codec(&codec, "Failed to set cq level");
  233. encode_frame(&codec, &raw1, frame_count++, flags, outfile);
  234. frames_encoded++;
  235. if (max_frames > 0 && frames_encoded >= max_frames) break;
  236. }
  237. // Flush encoder.
  238. while (encode_frame(&codec, NULL, -1, 0, outfile)) continue;
  239. printf("\n");
  240. fclose(infile0);
  241. fclose(infile1);
  242. printf("Processed %d frames.\n", frame_count / 2);
  243. aom_img_free(&raw0);
  244. aom_img_free(&raw1);
  245. if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec.");
  246. fclose(outfile);
  247. return EXIT_SUCCESS;
  248. }