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.

262 lines
8.2KB

  1. /*
  2. * Copyright (c) 2019 James Almer <jamrial@gmail.com>
  3. *
  4. * This file is part of FFmpeg.
  5. *
  6. * FFmpeg is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * FFmpeg is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with FFmpeg; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. */
  20. /**
  21. * @file
  22. * This bitstream filter splits AV1 Temporal Units into packets containing
  23. * just one frame, plus any leading and trailing OBUs that may be present at
  24. * the beginning or end, respectively.
  25. *
  26. * Temporal Units already containing only one frame will be passed through
  27. * unchanged. When splitting can't be performed, the Temporal Unit will be
  28. * passed through containing only the remaining OBUs starting from the first
  29. * one after the last successfully split frame.
  30. */
  31. #include "libavutil/avassert.h"
  32. #include "avcodec.h"
  33. #include "bsf.h"
  34. #include "cbs.h"
  35. #include "cbs_av1.h"
  36. typedef struct AV1FSplitContext {
  37. AVPacket *buffer_pkt;
  38. CodedBitstreamContext *cbc;
  39. CodedBitstreamFragment temporal_unit;
  40. int nb_frames;
  41. int cur_frame;
  42. int cur_frame_idx;
  43. int last_frame_idx;
  44. } AV1FSplitContext;
  45. static int av1_frame_split_filter(AVBSFContext *ctx, AVPacket *out)
  46. {
  47. AV1FSplitContext *s = ctx->priv_data;
  48. CodedBitstreamFragment *td = &s->temporal_unit;
  49. int i, ret;
  50. int split = !!s->buffer_pkt->data;
  51. if (!s->buffer_pkt->data) {
  52. int nb_frames = 0;
  53. ret = ff_bsf_get_packet_ref(ctx, s->buffer_pkt);
  54. if (ret < 0)
  55. return ret;
  56. ret = ff_cbs_read_packet(s->cbc, td, s->buffer_pkt);
  57. if (ret < 0) {
  58. av_log(ctx, AV_LOG_WARNING, "Failed to parse temporal unit.\n");
  59. goto passthrough;
  60. }
  61. for (i = 0; i < td->nb_units; i++) {
  62. CodedBitstreamUnit *unit = &td->units[i];
  63. if (unit->type == AV1_OBU_FRAME ||
  64. unit->type == AV1_OBU_FRAME_HEADER)
  65. nb_frames++;
  66. else if (unit->type == AV1_OBU_TILE_LIST) {
  67. av_log(ctx, AV_LOG_VERBOSE, "Large scale tiles are unsupported.\n");
  68. goto passthrough;
  69. }
  70. }
  71. if (nb_frames > 1) {
  72. s->cur_frame = 0;
  73. s->cur_frame_idx = s->last_frame_idx = 0;
  74. s->nb_frames = nb_frames;
  75. split = 1;
  76. }
  77. }
  78. if (split) {
  79. AV1RawFrameHeader *frame = NULL;
  80. int cur_frame_type = -1, size = 0;
  81. for (i = s->cur_frame_idx; i < td->nb_units; i++) {
  82. CodedBitstreamUnit *unit = &td->units[i];
  83. size += unit->data_size;
  84. if (unit->type == AV1_OBU_FRAME) {
  85. AV1RawOBU *obu = unit->content;
  86. if (frame) {
  87. av_log(ctx, AV_LOG_WARNING, "Frame OBU found when Tile data for a "
  88. "previous frame was expected.\n");
  89. goto passthrough;
  90. }
  91. frame = &obu->obu.frame.header;
  92. cur_frame_type = obu->header.obu_type;
  93. s->last_frame_idx = s->cur_frame_idx;
  94. s->cur_frame_idx = i + 1;
  95. s->cur_frame++;
  96. // split here unless it's the last frame, in which case
  97. // include every trailing OBU
  98. if (s->cur_frame < s->nb_frames)
  99. break;
  100. } else if (unit->type == AV1_OBU_FRAME_HEADER) {
  101. AV1RawOBU *obu = unit->content;
  102. if (frame) {
  103. av_log(ctx, AV_LOG_WARNING, "Frame Header OBU found when Tile data for a "
  104. "previous frame was expected.\n");
  105. goto passthrough;
  106. }
  107. frame = &obu->obu.frame_header;
  108. cur_frame_type = obu->header.obu_type;
  109. s->last_frame_idx = s->cur_frame_idx;
  110. s->cur_frame++;
  111. // split here if show_existing_frame unless it's the last
  112. // frame, in which case include every trailing OBU
  113. if (frame->show_existing_frame &&
  114. s->cur_frame < s->nb_frames) {
  115. s->cur_frame_idx = i + 1;
  116. break;
  117. }
  118. } else if (unit->type == AV1_OBU_TILE_GROUP) {
  119. AV1RawOBU *obu = unit->content;
  120. AV1RawTileGroup *group = &obu->obu.tile_group;
  121. if (!frame || cur_frame_type != AV1_OBU_FRAME_HEADER) {
  122. av_log(ctx, AV_LOG_WARNING, "Unexpected Tile Group OBU found before a "
  123. "Frame Header.\n");
  124. goto passthrough;
  125. }
  126. if ((group->tg_end == (frame->tile_cols * frame->tile_rows) - 1) &&
  127. // include every trailing OBU with the last frame
  128. s->cur_frame < s->nb_frames) {
  129. s->cur_frame_idx = i + 1;
  130. break;
  131. }
  132. }
  133. }
  134. av_assert0(frame && s->cur_frame <= s->nb_frames);
  135. ret = av_packet_ref(out, s->buffer_pkt);
  136. if (ret < 0)
  137. goto fail;
  138. out->data = (uint8_t *)td->units[s->last_frame_idx].data;
  139. out->size = size;
  140. // skip the frame in the buffer packet if it's split successfully, so it's not present
  141. // if the packet is passed through in case of failure when splitting another frame.
  142. s->buffer_pkt->data += size;
  143. s->buffer_pkt->size -= size;
  144. if (!frame->show_existing_frame && !frame->show_frame)
  145. out->pts = AV_NOPTS_VALUE;
  146. if (s->cur_frame == s->nb_frames) {
  147. av_packet_unref(s->buffer_pkt);
  148. ff_cbs_fragment_reset(s->cbc, td);
  149. }
  150. return 0;
  151. }
  152. passthrough:
  153. av_packet_move_ref(out, s->buffer_pkt);
  154. ret = 0;
  155. fail:
  156. if (ret < 0) {
  157. av_packet_unref(out);
  158. av_packet_unref(s->buffer_pkt);
  159. }
  160. ff_cbs_fragment_reset(s->cbc, td);
  161. return ret;
  162. }
  163. static const CodedBitstreamUnitType decompose_unit_types[] = {
  164. AV1_OBU_TEMPORAL_DELIMITER,
  165. AV1_OBU_SEQUENCE_HEADER,
  166. AV1_OBU_FRAME_HEADER,
  167. AV1_OBU_TILE_GROUP,
  168. AV1_OBU_FRAME,
  169. };
  170. static int av1_frame_split_init(AVBSFContext *ctx)
  171. {
  172. AV1FSplitContext *s = ctx->priv_data;
  173. CodedBitstreamFragment *td = &s->temporal_unit;
  174. int ret;
  175. s->buffer_pkt = av_packet_alloc();
  176. if (!s->buffer_pkt)
  177. return AVERROR(ENOMEM);
  178. ret = ff_cbs_init(&s->cbc, AV_CODEC_ID_AV1, ctx);
  179. if (ret < 0)
  180. return ret;
  181. s->cbc->decompose_unit_types = (CodedBitstreamUnitType*)decompose_unit_types;
  182. s->cbc->nb_decompose_unit_types = FF_ARRAY_ELEMS(decompose_unit_types);
  183. if (!ctx->par_in->extradata_size)
  184. return 0;
  185. ret = ff_cbs_read_extradata(s->cbc, td, ctx->par_in);
  186. if (ret < 0)
  187. av_log(ctx, AV_LOG_WARNING, "Failed to parse extradata.\n");
  188. ff_cbs_fragment_reset(s->cbc, td);
  189. return 0;
  190. }
  191. static void av1_frame_split_flush(AVBSFContext *ctx)
  192. {
  193. AV1FSplitContext *s = ctx->priv_data;
  194. av_packet_unref(s->buffer_pkt);
  195. ff_cbs_fragment_reset(s->cbc, &s->temporal_unit);
  196. }
  197. static void av1_frame_split_close(AVBSFContext *ctx)
  198. {
  199. AV1FSplitContext *s = ctx->priv_data;
  200. av_packet_free(&s->buffer_pkt);
  201. ff_cbs_fragment_free(s->cbc, &s->temporal_unit);
  202. ff_cbs_close(&s->cbc);
  203. }
  204. static const enum AVCodecID av1_frame_split_codec_ids[] = {
  205. AV_CODEC_ID_AV1, AV_CODEC_ID_NONE,
  206. };
  207. const AVBitStreamFilter ff_av1_frame_split_bsf = {
  208. .name = "av1_frame_split",
  209. .priv_data_size = sizeof(AV1FSplitContext),
  210. .init = av1_frame_split_init,
  211. .flush = av1_frame_split_flush,
  212. .close = av1_frame_split_close,
  213. .filter = av1_frame_split_filter,
  214. .codec_ids = av1_frame_split_codec_ids,
  215. };