/src/ffmpeg/libavcodec/bsf/av1_frame_merge.c
Line | Count | Source |
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 | | #include "bsf.h" |
22 | | #include "bsf_internal.h" |
23 | | #include "cbs.h" |
24 | | #include "cbs_av1.h" |
25 | | |
26 | | typedef struct AV1FMergeContext { |
27 | | CodedBitstreamContext *input; |
28 | | CodedBitstreamContext *output; |
29 | | CodedBitstreamFragment frag[2]; |
30 | | AVPacket *pkt, *in; |
31 | | int idx; |
32 | | } AV1FMergeContext; |
33 | | |
34 | | static void av1_frame_merge_flush(AVBSFContext *bsf) |
35 | 184k | { |
36 | 184k | AV1FMergeContext *ctx = bsf->priv_data; |
37 | | |
38 | 184k | ff_cbs_fragment_reset(&ctx->frag[0]); |
39 | 184k | ff_cbs_fragment_reset(&ctx->frag[1]); |
40 | 184k | av_packet_unref(ctx->in); |
41 | 184k | av_packet_unref(ctx->pkt); |
42 | 184k | } |
43 | | |
44 | | static int av1_frame_merge_filter(AVBSFContext *bsf, AVPacket *out) |
45 | 2.86M | { |
46 | 2.86M | AV1FMergeContext *ctx = bsf->priv_data; |
47 | 2.86M | CodedBitstreamFragment *frag = &ctx->frag[ctx->idx], *tu = &ctx->frag[!ctx->idx]; |
48 | 2.86M | AVPacket *in = ctx->in, *buffer_pkt = ctx->pkt; |
49 | 2.86M | int err, i; |
50 | | |
51 | 2.86M | err = ff_bsf_get_packet_ref(bsf, in); |
52 | 2.86M | if (err < 0) { |
53 | 37.2k | if (err == AVERROR_EOF && tu->nb_units > 0) |
54 | 10.3k | goto eof; |
55 | 26.8k | return err; |
56 | 37.2k | } |
57 | | |
58 | 2.82M | err = ff_cbs_read_packet(ctx->input, frag, in); |
59 | 2.82M | if (err < 0) { |
60 | 125k | av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); |
61 | 125k | goto fail; |
62 | 125k | } |
63 | | |
64 | 2.69M | if (frag->nb_units == 0) { |
65 | 1.45k | av_log(bsf, AV_LOG_ERROR, "No OBU in packet.\n"); |
66 | 1.45k | err = AVERROR_INVALIDDATA; |
67 | 1.45k | goto fail; |
68 | 1.45k | } |
69 | | |
70 | 2.69M | if (tu->nb_units == 0 && frag->units[0].type != AV1_OBU_TEMPORAL_DELIMITER) { |
71 | 6.31k | av_log(bsf, AV_LOG_ERROR, "Missing Temporal Delimiter.\n"); |
72 | 6.31k | err = AVERROR_INVALIDDATA; |
73 | 6.31k | goto fail; |
74 | 6.31k | } |
75 | | |
76 | 4.99M | for (i = 1; i < frag->nb_units; i++) { |
77 | 2.30M | if (frag->units[i].type == AV1_OBU_TEMPORAL_DELIMITER) { |
78 | 299 | av_log(bsf, AV_LOG_ERROR, "Temporal Delimiter in the middle of a packet.\n"); |
79 | 299 | err = AVERROR_INVALIDDATA; |
80 | 299 | goto fail; |
81 | 299 | } |
82 | 2.30M | } |
83 | | |
84 | 2.69M | if (tu->nb_units > 0 && frag->units[0].type == AV1_OBU_TEMPORAL_DELIMITER) { |
85 | 333k | eof: |
86 | 333k | err = ff_cbs_write_packet(ctx->output, buffer_pkt, tu); |
87 | 333k | if (err < 0) { |
88 | 18.9k | av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n"); |
89 | 18.9k | goto fail; |
90 | 18.9k | } |
91 | 314k | av_packet_move_ref(out, buffer_pkt); |
92 | | |
93 | | // Swap fragment index, to avoid copying fragment references. |
94 | 314k | ctx->idx = !ctx->idx; |
95 | 2.36M | } else { |
96 | 6.98M | for (i = 0; i < frag->nb_units; i++) { |
97 | 4.61M | err = ff_cbs_insert_unit_content(tu, -1, frag->units[i].type, |
98 | 4.61M | frag->units[i].content, frag->units[i].content_ref); |
99 | 4.61M | if (err < 0) |
100 | 0 | goto fail; |
101 | 4.61M | } |
102 | | |
103 | 2.36M | err = AVERROR(EAGAIN); |
104 | 2.36M | } |
105 | | |
106 | | /* Buffer packets with timestamps (there should be at most one per TU) |
107 | | * or any packet if buffer_pkt is empty. The latter is needed to |
108 | | * passthrough positions in case there are no timestamps like with |
109 | | * the raw OBU demuxer. */ |
110 | 2.68M | if (!buffer_pkt->data || |
111 | 2.32M | in->pts != AV_NOPTS_VALUE && buffer_pkt->pts == AV_NOPTS_VALUE) { |
112 | 355k | av_packet_unref(buffer_pkt); |
113 | 355k | av_packet_move_ref(buffer_pkt, in); |
114 | 355k | } else |
115 | 2.32M | av_packet_unref(in); |
116 | | |
117 | 2.68M | ff_cbs_fragment_reset(&ctx->frag[ctx->idx]); |
118 | | |
119 | 2.83M | fail: |
120 | 2.83M | if (err < 0 && err != AVERROR(EAGAIN)) |
121 | 152k | av1_frame_merge_flush(bsf); |
122 | | |
123 | 2.83M | return err; |
124 | 2.68M | } |
125 | | |
126 | | static int av1_frame_merge_init(AVBSFContext *bsf) |
127 | 21.3k | { |
128 | 21.3k | AV1FMergeContext *ctx = bsf->priv_data; |
129 | 21.3k | int err; |
130 | | |
131 | 21.3k | ctx->in = av_packet_alloc(); |
132 | 21.3k | ctx->pkt = av_packet_alloc(); |
133 | 21.3k | if (!ctx->in || !ctx->pkt) |
134 | 0 | return AVERROR(ENOMEM); |
135 | | |
136 | 21.3k | err = ff_cbs_init(&ctx->input, AV_CODEC_ID_AV1, bsf); |
137 | 21.3k | if (err < 0) |
138 | 0 | return err; |
139 | | |
140 | 21.3k | return ff_cbs_init(&ctx->output, AV_CODEC_ID_AV1, bsf); |
141 | 21.3k | } |
142 | | |
143 | | static void av1_frame_merge_close(AVBSFContext *bsf) |
144 | 21.3k | { |
145 | 21.3k | AV1FMergeContext *ctx = bsf->priv_data; |
146 | | |
147 | 21.3k | ff_cbs_fragment_free(&ctx->frag[0]); |
148 | 21.3k | ff_cbs_fragment_free(&ctx->frag[1]); |
149 | 21.3k | av_packet_free(&ctx->in); |
150 | 21.3k | av_packet_free(&ctx->pkt); |
151 | 21.3k | ff_cbs_close(&ctx->input); |
152 | 21.3k | ff_cbs_close(&ctx->output); |
153 | 21.3k | } |
154 | | |
155 | | static const enum AVCodecID av1_frame_merge_codec_ids[] = { |
156 | | AV_CODEC_ID_AV1, AV_CODEC_ID_NONE, |
157 | | }; |
158 | | |
159 | | const FFBitStreamFilter ff_av1_frame_merge_bsf = { |
160 | | .p.name = "av1_frame_merge", |
161 | | .p.codec_ids = av1_frame_merge_codec_ids, |
162 | | .priv_data_size = sizeof(AV1FMergeContext), |
163 | | .init = av1_frame_merge_init, |
164 | | .flush = av1_frame_merge_flush, |
165 | | .close = av1_frame_merge_close, |
166 | | .filter = av1_frame_merge_filter, |
167 | | }; |