You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

228 lines
5.8KB

  1. /*
  2. * VP9 invisible (alt-ref) frame to superframe merge bitstream filter
  3. * Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com>
  4. *
  5. * This file is part of Libav.
  6. *
  7. * Libav is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * Libav is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with Libav; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include "libavutil/avassert.h"
  22. #include "avcodec.h"
  23. #include "bitstream.h"
  24. #include "bsf.h"
  25. #define MAX_CACHE 8
  26. typedef struct VP9BSFContext {
  27. int n_cache;
  28. AVPacket *cache[MAX_CACHE];
  29. } VP9BSFContext;
  30. static void stats(AVPacket * const *in, int n_in,
  31. unsigned *_max, unsigned *_sum)
  32. {
  33. int n;
  34. unsigned max = 0, sum = 0;
  35. for (n = 0; n < n_in; n++) {
  36. unsigned sz = in[n]->size;
  37. if (sz > max)
  38. max = sz;
  39. sum += sz;
  40. }
  41. *_max = max;
  42. *_sum = sum;
  43. }
  44. static int merge_superframe(AVPacket * const *in, int n_in, AVPacket *out)
  45. {
  46. unsigned max, sum, mag, marker, n, sz;
  47. uint8_t *ptr;
  48. int res;
  49. stats(in, n_in, &max, &sum);
  50. mag = av_log2(max) >> 3;
  51. marker = 0xC0 + (mag << 3) + (n_in - 1);
  52. sz = sum + 2 + (mag + 1) * n_in;
  53. res = av_new_packet(out, sz);
  54. if (res < 0)
  55. return res;
  56. ptr = out->data;
  57. for (n = 0; n < n_in; n++) {
  58. memcpy(ptr, in[n]->data, in[n]->size);
  59. ptr += in[n]->size;
  60. }
  61. #define wloop(mag, wr) do { \
  62. for (n = 0; n < n_in; n++) { \
  63. wr; \
  64. ptr += mag + 1; \
  65. } \
  66. } while (0)
  67. // write superframe with marker 110[mag:2][nframes:3]
  68. *ptr++ = marker;
  69. switch (mag) {
  70. case 0:
  71. wloop(mag, *ptr = in[n]->size);
  72. break;
  73. case 1:
  74. wloop(mag, AV_WL16(ptr, in[n]->size));
  75. break;
  76. case 2:
  77. wloop(mag, AV_WL24(ptr, in[n]->size));
  78. break;
  79. case 3:
  80. wloop(mag, AV_WL32(ptr, in[n]->size));
  81. break;
  82. }
  83. *ptr++ = marker;
  84. av_assert0(ptr == &out->data[out->size]);
  85. return 0;
  86. }
  87. static int vp9_superframe_filter(AVBSFContext *ctx, AVPacket *out)
  88. {
  89. BitstreamContext bc;
  90. VP9BSFContext *s = ctx->priv_data;
  91. AVPacket *in;
  92. int res, invisible, profile, marker, uses_superframe_syntax = 0, n;
  93. res = ff_bsf_get_packet(ctx, &in);
  94. if (res < 0)
  95. return res;
  96. marker = in->data[in->size - 1];
  97. if ((marker & 0xe0) == 0xc0) {
  98. int nbytes = 1 + ((marker >> 3) & 0x3);
  99. int n_frames = 1 + (marker & 0x7), idx_sz = 2 + n_frames * nbytes;
  100. uses_superframe_syntax = in->size >= idx_sz && in->data[in->size - idx_sz] == marker;
  101. }
  102. res = bitstream_init8(&bc, in->data, in->size);
  103. if (res < 0)
  104. goto done;
  105. bitstream_read(&bc, 2); // frame marker
  106. profile = bitstream_read(&bc, 1);
  107. profile |= bitstream_read(&bc, 1) << 1;
  108. if (profile == 3)
  109. profile += bitstream_read(&bc, 1);
  110. if (bitstream_read(&bc, 1)) {
  111. invisible = 0;
  112. } else {
  113. bitstream_read(&bc, 1); // keyframe
  114. invisible = !bitstream_read(&bc, 1);
  115. }
  116. if (uses_superframe_syntax && s->n_cache > 0) {
  117. av_log(ctx, AV_LOG_ERROR,
  118. "Mixing of superframe syntax and naked VP9 frames not supported");
  119. res = AVERROR(ENOSYS);
  120. goto done;
  121. } else if ((!invisible || uses_superframe_syntax) && !s->n_cache) {
  122. // passthrough
  123. av_packet_move_ref(out, in);
  124. goto done;
  125. } else if (s->n_cache + 1 >= MAX_CACHE) {
  126. av_log(ctx, AV_LOG_ERROR,
  127. "Too many invisible frames");
  128. res = AVERROR_INVALIDDATA;
  129. goto done;
  130. }
  131. res = av_packet_ref(s->cache[s->n_cache++], in);
  132. if (res < 0)
  133. goto done;
  134. if (invisible) {
  135. res = AVERROR(EAGAIN);
  136. goto done;
  137. }
  138. av_assert0(s->n_cache > 0);
  139. // build superframe
  140. if ((res = merge_superframe(s->cache, s->n_cache, out)) < 0)
  141. goto done;
  142. res = av_packet_copy_props(out, s->cache[s->n_cache - 1]);
  143. if (res < 0)
  144. goto done;
  145. for (n = 0; n < s->n_cache; n++)
  146. av_packet_unref(s->cache[n]);
  147. s->n_cache = 0;
  148. done:
  149. if (res < 0)
  150. av_packet_unref(out);
  151. av_packet_free(&in);
  152. return res;
  153. }
  154. static int vp9_superframe_init(AVBSFContext *ctx)
  155. {
  156. VP9BSFContext *s = ctx->priv_data;
  157. int n;
  158. // alloc cache packets
  159. for (n = 0; n < MAX_CACHE; n++) {
  160. s->cache[n] = av_packet_alloc();
  161. if (!s->cache[n])
  162. return AVERROR(ENOMEM);
  163. }
  164. return 0;
  165. }
  166. static void vp9_superframe_flush(AVBSFContext *ctx)
  167. {
  168. VP9BSFContext *s = ctx->priv_data;
  169. int n;
  170. // unref cached data
  171. for (n = 0; n < s->n_cache; n++)
  172. av_packet_unref(s->cache[n]);
  173. s->n_cache = 0;
  174. }
  175. static void vp9_superframe_close(AVBSFContext *ctx)
  176. {
  177. VP9BSFContext *s = ctx->priv_data;
  178. int n;
  179. // free cached data
  180. for (n = 0; n < MAX_CACHE; n++)
  181. av_packet_free(&s->cache[n]);
  182. }
  183. static const enum AVCodecID codec_ids[] = {
  184. AV_CODEC_ID_VP9, AV_CODEC_ID_NONE,
  185. };
  186. const AVBitStreamFilter ff_vp9_superframe_bsf = {
  187. .name = "vp9_superframe",
  188. .priv_data_size = sizeof(VP9BSFContext),
  189. .filter = vp9_superframe_filter,
  190. .init = vp9_superframe_init,
  191. .flush = vp9_superframe_flush,
  192. .close = vp9_superframe_close,
  193. .codec_ids = codec_ids,
  194. };