svc_encodeframe.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. /*
  2. * Copyright (c) 2013 The WebM project authors. All Rights Reserved.
  3. *
  4. * Use of this source code is governed by a BSD-style license
  5. * that can be found in the LICENSE file in the root of the source
  6. * tree. An additional intellectual property rights grant can be found
  7. * in the file PATENTS. All contributing project authors may
  8. * be found in the AUTHORS file in the root of the source tree.
  9. */
  10. /**
  11. * @file
  12. * VP9 SVC encoding support via libvpx
  13. */
  14. #include <assert.h>
  15. #include <math.h>
  16. #include <limits.h>
  17. #include <stdarg.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #define VPX_DISABLE_CTRL_TYPECHECKS 1
  22. #include "./vpx_config.h"
  23. #include "./svc_context.h"
  24. #include "vpx/vp8cx.h"
  25. #include "vpx/vpx_encoder.h"
  26. #include "vpx_mem/vpx_mem.h"
  27. #include "vp9/common/vp9_onyxc_int.h"
  28. #ifdef __MINGW32__
  29. #define strtok_r strtok_s
  30. #ifndef MINGW_HAS_SECURE_API
  31. // proto from /usr/x86_64-w64-mingw32/include/sec_api/string_s.h
  32. _CRTIMP char *__cdecl strtok_s(char *str, const char *delim, char **context);
  33. #endif /* MINGW_HAS_SECURE_API */
  34. #endif /* __MINGW32__ */
  35. #ifdef _MSC_VER
  36. #define strdup _strdup
  37. #define strtok_r strtok_s
  38. #endif
  39. #define SVC_REFERENCE_FRAMES 8
  40. #define SUPERFRAME_SLOTS (8)
  41. #define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2)
  42. #define MAX_QUANTIZER 63
  43. static const int DEFAULT_SCALE_FACTORS_NUM[VPX_SS_MAX_LAYERS] = { 4, 5, 7, 11,
  44. 16 };
  45. static const int DEFAULT_SCALE_FACTORS_DEN[VPX_SS_MAX_LAYERS] = { 16, 16, 16,
  46. 16, 16 };
  47. static const int DEFAULT_SCALE_FACTORS_NUM_2x[VPX_SS_MAX_LAYERS] = { 1, 2, 4 };
  48. static const int DEFAULT_SCALE_FACTORS_DEN_2x[VPX_SS_MAX_LAYERS] = { 4, 4, 4 };
  49. typedef enum {
  50. QUANTIZER = 0,
  51. BITRATE,
  52. SCALE_FACTOR,
  53. AUTO_ALT_REF,
  54. ALL_OPTION_TYPES
  55. } LAYER_OPTION_TYPE;
  56. static const int option_max_values[ALL_OPTION_TYPES] = { 63, INT_MAX, INT_MAX,
  57. 1 };
  58. static const int option_min_values[ALL_OPTION_TYPES] = { 0, 0, 1, 0 };
  59. // One encoded frame
  60. typedef struct FrameData {
  61. void *buf; // compressed data buffer
  62. size_t size; // length of compressed data
  63. vpx_codec_frame_flags_t flags; /**< flags for this frame */
  64. struct FrameData *next;
  65. } FrameData;
  66. static SvcInternal_t *get_svc_internal(SvcContext *svc_ctx) {
  67. if (svc_ctx == NULL) return NULL;
  68. if (svc_ctx->internal == NULL) {
  69. SvcInternal_t *const si = (SvcInternal_t *)malloc(sizeof(*si));
  70. if (si != NULL) {
  71. memset(si, 0, sizeof(*si));
  72. }
  73. svc_ctx->internal = si;
  74. }
  75. return (SvcInternal_t *)svc_ctx->internal;
  76. }
  77. static const SvcInternal_t *get_const_svc_internal(const SvcContext *svc_ctx) {
  78. if (svc_ctx == NULL) return NULL;
  79. return (const SvcInternal_t *)svc_ctx->internal;
  80. }
  81. static int svc_log(SvcContext *svc_ctx, SVC_LOG_LEVEL level, const char *fmt,
  82. ...) {
  83. char buf[512];
  84. int retval = 0;
  85. va_list ap;
  86. if (level > svc_ctx->log_level) {
  87. return retval;
  88. }
  89. va_start(ap, fmt);
  90. retval = vsnprintf(buf, sizeof(buf), fmt, ap);
  91. va_end(ap);
  92. printf("%s", buf);
  93. return retval;
  94. }
  95. static vpx_codec_err_t extract_option(LAYER_OPTION_TYPE type, char *input,
  96. int *value0, int *value1) {
  97. if (type == SCALE_FACTOR) {
  98. *value0 = (int)strtol(input, &input, 10);
  99. if (*input++ != '/') return VPX_CODEC_INVALID_PARAM;
  100. *value1 = (int)strtol(input, &input, 10);
  101. if (*value0 < option_min_values[SCALE_FACTOR] ||
  102. *value1 < option_min_values[SCALE_FACTOR] ||
  103. *value0 > option_max_values[SCALE_FACTOR] ||
  104. *value1 > option_max_values[SCALE_FACTOR] ||
  105. *value0 > *value1) // num shouldn't be greater than den
  106. return VPX_CODEC_INVALID_PARAM;
  107. } else {
  108. *value0 = atoi(input);
  109. if (*value0 < option_min_values[type] || *value0 > option_max_values[type])
  110. return VPX_CODEC_INVALID_PARAM;
  111. }
  112. return VPX_CODEC_OK;
  113. }
  114. static vpx_codec_err_t parse_layer_options_from_string(SvcContext *svc_ctx,
  115. LAYER_OPTION_TYPE type,
  116. const char *input,
  117. int *option0,
  118. int *option1) {
  119. int i;
  120. vpx_codec_err_t res = VPX_CODEC_OK;
  121. char *input_string;
  122. char *token;
  123. const char *delim = ",";
  124. char *save_ptr;
  125. int num_layers = svc_ctx->spatial_layers;
  126. if (type == BITRATE)
  127. num_layers = svc_ctx->spatial_layers * svc_ctx->temporal_layers;
  128. if (input == NULL || option0 == NULL ||
  129. (option1 == NULL && type == SCALE_FACTOR))
  130. return VPX_CODEC_INVALID_PARAM;
  131. input_string = strdup(input);
  132. if (input_string == NULL) return VPX_CODEC_MEM_ERROR;
  133. token = strtok_r(input_string, delim, &save_ptr);
  134. for (i = 0; i < num_layers; ++i) {
  135. if (token != NULL) {
  136. res = extract_option(type, token, option0 + i, option1 + i);
  137. if (res != VPX_CODEC_OK) break;
  138. token = strtok_r(NULL, delim, &save_ptr);
  139. } else {
  140. break;
  141. }
  142. }
  143. if (res == VPX_CODEC_OK && i != num_layers) {
  144. svc_log(svc_ctx, SVC_LOG_ERROR,
  145. "svc: layer params type: %d %d values required, "
  146. "but only %d specified\n",
  147. type, num_layers, i);
  148. res = VPX_CODEC_INVALID_PARAM;
  149. }
  150. free(input_string);
  151. return res;
  152. }
  153. /**
  154. * Parse SVC encoding options
  155. * Format: encoding-mode=<svc_mode>,layers=<layer_count>
  156. * scale-factors=<n1>/<d1>,<n2>/<d2>,...
  157. * quantizers=<q1>,<q2>,...
  158. * svc_mode = [i|ip|alt_ip|gf]
  159. */
  160. static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) {
  161. char *input_string;
  162. char *option_name;
  163. char *option_value;
  164. char *input_ptr = NULL;
  165. SvcInternal_t *const si = get_svc_internal(svc_ctx);
  166. vpx_codec_err_t res = VPX_CODEC_OK;
  167. int i, alt_ref_enabled = 0;
  168. if (options == NULL) return VPX_CODEC_OK;
  169. input_string = strdup(options);
  170. if (input_string == NULL) return VPX_CODEC_MEM_ERROR;
  171. // parse option name
  172. option_name = strtok_r(input_string, "=", &input_ptr);
  173. while (option_name != NULL) {
  174. // parse option value
  175. option_value = strtok_r(NULL, " ", &input_ptr);
  176. if (option_value == NULL) {
  177. svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n",
  178. option_name);
  179. res = VPX_CODEC_INVALID_PARAM;
  180. break;
  181. }
  182. if (strcmp("spatial-layers", option_name) == 0) {
  183. svc_ctx->spatial_layers = atoi(option_value);
  184. } else if (strcmp("temporal-layers", option_name) == 0) {
  185. svc_ctx->temporal_layers = atoi(option_value);
  186. } else if (strcmp("scale-factors", option_name) == 0) {
  187. res = parse_layer_options_from_string(svc_ctx, SCALE_FACTOR, option_value,
  188. si->svc_params.scaling_factor_num,
  189. si->svc_params.scaling_factor_den);
  190. if (res != VPX_CODEC_OK) break;
  191. } else if (strcmp("max-quantizers", option_name) == 0) {
  192. res =
  193. parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value,
  194. si->svc_params.max_quantizers, NULL);
  195. if (res != VPX_CODEC_OK) break;
  196. } else if (strcmp("min-quantizers", option_name) == 0) {
  197. res =
  198. parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value,
  199. si->svc_params.min_quantizers, NULL);
  200. if (res != VPX_CODEC_OK) break;
  201. } else if (strcmp("auto-alt-refs", option_name) == 0) {
  202. res = parse_layer_options_from_string(svc_ctx, AUTO_ALT_REF, option_value,
  203. si->enable_auto_alt_ref, NULL);
  204. if (res != VPX_CODEC_OK) break;
  205. } else if (strcmp("bitrates", option_name) == 0) {
  206. res = parse_layer_options_from_string(svc_ctx, BITRATE, option_value,
  207. si->bitrates, NULL);
  208. if (res != VPX_CODEC_OK) break;
  209. } else if (strcmp("multi-frame-contexts", option_name) == 0) {
  210. si->use_multiple_frame_contexts = atoi(option_value);
  211. } else {
  212. svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name);
  213. res = VPX_CODEC_INVALID_PARAM;
  214. break;
  215. }
  216. option_name = strtok_r(NULL, "=", &input_ptr);
  217. }
  218. free(input_string);
  219. for (i = 0; i < svc_ctx->spatial_layers; ++i) {
  220. if (si->svc_params.max_quantizers[i] > MAX_QUANTIZER ||
  221. si->svc_params.max_quantizers[i] < 0 ||
  222. si->svc_params.min_quantizers[i] > si->svc_params.max_quantizers[i] ||
  223. si->svc_params.min_quantizers[i] < 0)
  224. res = VPX_CODEC_INVALID_PARAM;
  225. }
  226. if (si->use_multiple_frame_contexts &&
  227. (svc_ctx->spatial_layers > 3 ||
  228. svc_ctx->spatial_layers * svc_ctx->temporal_layers > 4))
  229. res = VPX_CODEC_INVALID_PARAM;
  230. for (i = 0; i < svc_ctx->spatial_layers; ++i)
  231. alt_ref_enabled += si->enable_auto_alt_ref[i];
  232. if (alt_ref_enabled > REF_FRAMES - svc_ctx->spatial_layers) {
  233. svc_log(svc_ctx, SVC_LOG_ERROR,
  234. "svc: auto alt ref: Maxinum %d(REF_FRAMES - layers) layers could"
  235. "enabled auto alt reference frame, but % layers are enabled\n",
  236. REF_FRAMES - svc_ctx->spatial_layers, alt_ref_enabled);
  237. res = VPX_CODEC_INVALID_PARAM;
  238. }
  239. return res;
  240. }
  241. vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) {
  242. SvcInternal_t *const si = get_svc_internal(svc_ctx);
  243. if (svc_ctx == NULL || options == NULL || si == NULL) {
  244. return VPX_CODEC_INVALID_PARAM;
  245. }
  246. strncpy(si->options, options, sizeof(si->options));
  247. si->options[sizeof(si->options) - 1] = '\0';
  248. return VPX_CODEC_OK;
  249. }
  250. static vpx_codec_err_t assign_layer_bitrates(
  251. const SvcContext *svc_ctx, vpx_codec_enc_cfg_t *const enc_cfg) {
  252. int i;
  253. const SvcInternal_t *const si = get_const_svc_internal(svc_ctx);
  254. int sl, tl, spatial_layer_target;
  255. if (svc_ctx->temporal_layering_mode != 0) {
  256. if (si->bitrates[0] != 0) {
  257. unsigned int total_bitrate = 0;
  258. for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
  259. total_bitrate += si->bitrates[sl * svc_ctx->temporal_layers +
  260. svc_ctx->temporal_layers - 1];
  261. for (tl = 0; tl < svc_ctx->temporal_layers; ++tl) {
  262. enc_cfg->ss_target_bitrate[sl * svc_ctx->temporal_layers] +=
  263. (unsigned int)si->bitrates[sl * svc_ctx->temporal_layers + tl];
  264. enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + tl] =
  265. si->bitrates[sl * svc_ctx->temporal_layers + tl];
  266. if (tl > 0 && (si->bitrates[sl * svc_ctx->temporal_layers + tl] <=
  267. si->bitrates[sl * svc_ctx->temporal_layers + tl - 1]))
  268. return VPX_CODEC_INVALID_PARAM;
  269. }
  270. }
  271. if (total_bitrate != enc_cfg->rc_target_bitrate)
  272. return VPX_CODEC_INVALID_PARAM;
  273. } else {
  274. float total = 0;
  275. float alloc_ratio[VPX_MAX_LAYERS] = { 0 };
  276. for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
  277. if (si->svc_params.scaling_factor_den[sl] > 0) {
  278. alloc_ratio[sl] = (float)(pow(2, sl));
  279. total += alloc_ratio[sl];
  280. }
  281. }
  282. for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
  283. enc_cfg->ss_target_bitrate[sl] = spatial_layer_target =
  284. (unsigned int)(enc_cfg->rc_target_bitrate * alloc_ratio[sl] /
  285. total);
  286. if (svc_ctx->temporal_layering_mode == 3) {
  287. enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers] =
  288. (spatial_layer_target * 6) / 10; // 60%
  289. enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + 1] =
  290. (spatial_layer_target * 8) / 10; // 80%
  291. enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + 2] =
  292. spatial_layer_target;
  293. } else if (svc_ctx->temporal_layering_mode == 2 ||
  294. svc_ctx->temporal_layering_mode == 1) {
  295. enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers] =
  296. spatial_layer_target * 2 / 3;
  297. enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + 1] =
  298. spatial_layer_target;
  299. } else {
  300. // User should explicitly assign bitrates in this case.
  301. assert(0);
  302. }
  303. }
  304. }
  305. } else {
  306. if (si->bitrates[0] != 0) {
  307. unsigned int total_bitrate = 0;
  308. for (i = 0; i < svc_ctx->spatial_layers; ++i) {
  309. enc_cfg->ss_target_bitrate[i] = (unsigned int)si->bitrates[i];
  310. enc_cfg->layer_target_bitrate[i] = (unsigned int)si->bitrates[i];
  311. total_bitrate += si->bitrates[i];
  312. }
  313. if (total_bitrate != enc_cfg->rc_target_bitrate)
  314. return VPX_CODEC_INVALID_PARAM;
  315. } else {
  316. float total = 0;
  317. float alloc_ratio[VPX_MAX_LAYERS] = { 0 };
  318. for (i = 0; i < svc_ctx->spatial_layers; ++i) {
  319. if (si->svc_params.scaling_factor_den[i] > 0) {
  320. alloc_ratio[i] = (float)(si->svc_params.scaling_factor_num[i] * 1.0 /
  321. si->svc_params.scaling_factor_den[i]);
  322. alloc_ratio[i] *= alloc_ratio[i];
  323. total += alloc_ratio[i];
  324. }
  325. }
  326. for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) {
  327. if (total > 0) {
  328. enc_cfg->layer_target_bitrate[i] =
  329. (unsigned int)(enc_cfg->rc_target_bitrate * alloc_ratio[i] /
  330. total);
  331. }
  332. }
  333. }
  334. }
  335. return VPX_CODEC_OK;
  336. }
  337. vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
  338. vpx_codec_iface_t *iface,
  339. vpx_codec_enc_cfg_t *enc_cfg) {
  340. vpx_codec_err_t res;
  341. int i, sl, tl;
  342. SvcInternal_t *const si = get_svc_internal(svc_ctx);
  343. if (svc_ctx == NULL || codec_ctx == NULL || iface == NULL ||
  344. enc_cfg == NULL) {
  345. return VPX_CODEC_INVALID_PARAM;
  346. }
  347. if (si == NULL) return VPX_CODEC_MEM_ERROR;
  348. si->codec_ctx = codec_ctx;
  349. si->width = enc_cfg->g_w;
  350. si->height = enc_cfg->g_h;
  351. si->kf_dist = enc_cfg->kf_max_dist;
  352. if (svc_ctx->spatial_layers == 0)
  353. svc_ctx->spatial_layers = VPX_SS_DEFAULT_LAYERS;
  354. if (svc_ctx->spatial_layers < 1 ||
  355. svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) {
  356. svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n",
  357. svc_ctx->spatial_layers);
  358. return VPX_CODEC_INVALID_PARAM;
  359. }
  360. // Note: temporal_layering_mode only applies to one-pass CBR
  361. // si->svc_params.temporal_layering_mode = svc_ctx->temporal_layering_mode;
  362. if (svc_ctx->temporal_layering_mode == 3) {
  363. svc_ctx->temporal_layers = 3;
  364. } else if (svc_ctx->temporal_layering_mode == 2 ||
  365. svc_ctx->temporal_layering_mode == 1) {
  366. svc_ctx->temporal_layers = 2;
  367. }
  368. for (sl = 0; sl < VPX_SS_MAX_LAYERS; ++sl) {
  369. si->svc_params.scaling_factor_num[sl] = DEFAULT_SCALE_FACTORS_NUM[sl];
  370. si->svc_params.scaling_factor_den[sl] = DEFAULT_SCALE_FACTORS_DEN[sl];
  371. si->svc_params.speed_per_layer[sl] = svc_ctx->speed;
  372. }
  373. if (enc_cfg->rc_end_usage == VPX_CBR && enc_cfg->g_pass == VPX_RC_ONE_PASS &&
  374. svc_ctx->spatial_layers <= 3) {
  375. for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
  376. int sl2 = (svc_ctx->spatial_layers == 2) ? sl + 1 : sl;
  377. si->svc_params.scaling_factor_num[sl] = DEFAULT_SCALE_FACTORS_NUM_2x[sl2];
  378. si->svc_params.scaling_factor_den[sl] = DEFAULT_SCALE_FACTORS_DEN_2x[sl2];
  379. }
  380. if (svc_ctx->spatial_layers == 1) {
  381. si->svc_params.scaling_factor_num[0] = 1;
  382. si->svc_params.scaling_factor_den[0] = 1;
  383. }
  384. }
  385. for (tl = 0; tl < svc_ctx->temporal_layers; ++tl) {
  386. for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
  387. i = sl * svc_ctx->temporal_layers + tl;
  388. si->svc_params.max_quantizers[i] = MAX_QUANTIZER;
  389. si->svc_params.min_quantizers[i] = 0;
  390. if (enc_cfg->rc_end_usage == VPX_CBR &&
  391. enc_cfg->g_pass == VPX_RC_ONE_PASS) {
  392. si->svc_params.max_quantizers[i] = 56;
  393. si->svc_params.min_quantizers[i] = 2;
  394. }
  395. }
  396. }
  397. // Parse aggregate command line options. Options must start with
  398. // "layers=xx" then followed by other options
  399. res = parse_options(svc_ctx, si->options);
  400. if (res != VPX_CODEC_OK) return res;
  401. if (svc_ctx->spatial_layers < 1) svc_ctx->spatial_layers = 1;
  402. if (svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS)
  403. svc_ctx->spatial_layers = VPX_SS_MAX_LAYERS;
  404. if (svc_ctx->temporal_layers < 1) svc_ctx->temporal_layers = 1;
  405. if (svc_ctx->temporal_layers > VPX_TS_MAX_LAYERS)
  406. svc_ctx->temporal_layers = VPX_TS_MAX_LAYERS;
  407. if (svc_ctx->temporal_layers * svc_ctx->spatial_layers > VPX_MAX_LAYERS) {
  408. svc_log(svc_ctx, SVC_LOG_ERROR,
  409. "spatial layers * temporal layers exceeds the maximum number of "
  410. "allowed layers of %d\n",
  411. svc_ctx->spatial_layers * svc_ctx->temporal_layers, VPX_MAX_LAYERS);
  412. return VPX_CODEC_INVALID_PARAM;
  413. }
  414. res = assign_layer_bitrates(svc_ctx, enc_cfg);
  415. if (res != VPX_CODEC_OK) {
  416. svc_log(svc_ctx, SVC_LOG_ERROR,
  417. "layer bitrates incorrect: \n"
  418. "1) spatial layer bitrates should sum up to target \n"
  419. "2) temporal layer bitrates should be increasing within \n"
  420. "a spatial layer \n");
  421. return VPX_CODEC_INVALID_PARAM;
  422. }
  423. if (svc_ctx->temporal_layers > 1) {
  424. int i;
  425. for (i = 0; i < svc_ctx->temporal_layers; ++i) {
  426. enc_cfg->ts_target_bitrate[i] =
  427. enc_cfg->rc_target_bitrate / svc_ctx->temporal_layers;
  428. enc_cfg->ts_rate_decimator[i] = 1 << (svc_ctx->temporal_layers - 1 - i);
  429. }
  430. }
  431. if (svc_ctx->threads) enc_cfg->g_threads = svc_ctx->threads;
  432. // Modify encoder configuration
  433. enc_cfg->ss_number_layers = svc_ctx->spatial_layers;
  434. enc_cfg->ts_number_layers = svc_ctx->temporal_layers;
  435. if (enc_cfg->rc_end_usage == VPX_CBR) {
  436. enc_cfg->rc_resize_allowed = 0;
  437. enc_cfg->rc_min_quantizer = 2;
  438. enc_cfg->rc_max_quantizer = 56;
  439. enc_cfg->rc_undershoot_pct = 50;
  440. enc_cfg->rc_overshoot_pct = 50;
  441. enc_cfg->rc_buf_initial_sz = 500;
  442. enc_cfg->rc_buf_optimal_sz = 600;
  443. enc_cfg->rc_buf_sz = 1000;
  444. }
  445. for (tl = 0; tl < svc_ctx->temporal_layers; ++tl) {
  446. for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
  447. i = sl * svc_ctx->temporal_layers + tl;
  448. if (enc_cfg->rc_end_usage == VPX_CBR &&
  449. enc_cfg->g_pass == VPX_RC_ONE_PASS) {
  450. si->svc_params.max_quantizers[i] = enc_cfg->rc_max_quantizer;
  451. si->svc_params.min_quantizers[i] = enc_cfg->rc_min_quantizer;
  452. }
  453. }
  454. }
  455. if (enc_cfg->g_error_resilient == 0 && si->use_multiple_frame_contexts == 0)
  456. enc_cfg->g_error_resilient = 1;
  457. // Initialize codec
  458. res = vpx_codec_enc_init(codec_ctx, iface, enc_cfg, VPX_CODEC_USE_PSNR);
  459. if (res != VPX_CODEC_OK) {
  460. svc_log(svc_ctx, SVC_LOG_ERROR, "svc_enc_init error\n");
  461. return res;
  462. }
  463. if (svc_ctx->spatial_layers > 1 || svc_ctx->temporal_layers > 1) {
  464. vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1);
  465. vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &si->svc_params);
  466. }
  467. return VPX_CODEC_OK;
  468. }
  469. /**
  470. * Encode a frame into multiple layers
  471. * Create a superframe containing the individual layers
  472. */
  473. vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
  474. struct vpx_image *rawimg, vpx_codec_pts_t pts,
  475. int64_t duration, int deadline) {
  476. vpx_codec_err_t res;
  477. vpx_codec_iter_t iter;
  478. const vpx_codec_cx_pkt_t *cx_pkt;
  479. SvcInternal_t *const si = get_svc_internal(svc_ctx);
  480. if (svc_ctx == NULL || codec_ctx == NULL || si == NULL) {
  481. return VPX_CODEC_INVALID_PARAM;
  482. }
  483. res =
  484. vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration, 0, deadline);
  485. if (res != VPX_CODEC_OK) {
  486. return res;
  487. }
  488. // save compressed data
  489. iter = NULL;
  490. while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) {
  491. switch (cx_pkt->kind) {
  492. case VPX_CODEC_PSNR_PKT: {
  493. }
  494. ++si->psnr_pkt_received;
  495. break;
  496. default: { break; }
  497. }
  498. }
  499. return VPX_CODEC_OK;
  500. }
  501. static double calc_psnr(double d) {
  502. if (d == 0) return 100;
  503. return -10.0 * log(d) / log(10.0);
  504. }
  505. // dump accumulated statistics and reset accumulated values
  506. void vpx_svc_dump_statistics(SvcContext *svc_ctx) {
  507. int number_of_frames;
  508. int i, j;
  509. uint32_t bytes_total = 0;
  510. double scale[COMPONENTS];
  511. double psnr[COMPONENTS];
  512. double mse[COMPONENTS];
  513. double y_scale;
  514. SvcInternal_t *const si = get_svc_internal(svc_ctx);
  515. if (svc_ctx == NULL || si == NULL) return;
  516. number_of_frames = si->psnr_pkt_received;
  517. if (number_of_frames <= 0) return;
  518. svc_log(svc_ctx, SVC_LOG_INFO, "\n");
  519. for (i = 0; i < svc_ctx->spatial_layers; ++i) {
  520. svc_log(svc_ctx, SVC_LOG_INFO,
  521. "Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n",
  522. i, si->psnr_sum[i][0] / number_of_frames,
  523. si->psnr_sum[i][1] / number_of_frames,
  524. si->psnr_sum[i][2] / number_of_frames,
  525. si->psnr_sum[i][3] / number_of_frames, si->bytes_sum[i]);
  526. // the following psnr calculation is deduced from ffmpeg.c#print_report
  527. y_scale = si->width * si->height * 255.0 * 255.0 * number_of_frames;
  528. scale[1] = y_scale;
  529. scale[2] = scale[3] = y_scale / 4; // U or V
  530. scale[0] = y_scale * 1.5; // total
  531. for (j = 0; j < COMPONENTS; j++) {
  532. psnr[j] = calc_psnr(si->sse_sum[i][j] / scale[j]);
  533. mse[j] = si->sse_sum[i][j] * 255.0 * 255.0 / scale[j];
  534. }
  535. svc_log(svc_ctx, SVC_LOG_INFO,
  536. "Layer %d Overall PSNR=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, psnr[0],
  537. psnr[1], psnr[2], psnr[3]);
  538. svc_log(svc_ctx, SVC_LOG_INFO,
  539. "Layer %d Overall MSE=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, mse[0],
  540. mse[1], mse[2], mse[3]);
  541. bytes_total += si->bytes_sum[i];
  542. // Clear sums for next time.
  543. si->bytes_sum[i] = 0;
  544. for (j = 0; j < COMPONENTS; ++j) {
  545. si->psnr_sum[i][j] = 0;
  546. si->sse_sum[i][j] = 0;
  547. }
  548. }
  549. // only display statistics once
  550. si->psnr_pkt_received = 0;
  551. svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total);
  552. }
  553. void vpx_svc_release(SvcContext *svc_ctx) {
  554. SvcInternal_t *si;
  555. if (svc_ctx == NULL) return;
  556. // do not use get_svc_internal as it will unnecessarily allocate an
  557. // SvcInternal_t if it was not already allocated
  558. si = (SvcInternal_t *)svc_ctx->internal;
  559. if (si != NULL) {
  560. free(si);
  561. svc_ctx->internal = NULL;
  562. }
  563. }