/src/ffmpeg/libavcodec/bsf/vp9_superframe.c
Line | Count | Source |
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 FFmpeg. |
6 | | * |
7 | | * FFmpeg 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 | | * FFmpeg 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 FFmpeg; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | #include "libavutil/avassert.h" |
23 | | |
24 | | #include "bsf.h" |
25 | | #include "bsf_internal.h" |
26 | | #include "get_bits.h" |
27 | | |
28 | 13.6k | #define MAX_CACHE 8 |
29 | | typedef struct VP9BSFContext { |
30 | | int n_cache; |
31 | | AVPacket *cache[MAX_CACHE]; |
32 | | } VP9BSFContext; |
33 | | |
34 | | static void stats(AVPacket * const *in, int n_in, |
35 | | unsigned *_max, unsigned *_sum) |
36 | 1.07k | { |
37 | 1.07k | int n; |
38 | 1.07k | unsigned max = 0, sum = 0; |
39 | | |
40 | 4.12k | for (n = 0; n < n_in; n++) { |
41 | 3.05k | unsigned sz = in[n]->size; |
42 | | |
43 | 3.05k | if (sz > max) |
44 | 1.48k | max = sz; |
45 | 3.05k | sum += sz; |
46 | 3.05k | } |
47 | | |
48 | 1.07k | *_max = max; |
49 | 1.07k | *_sum = sum; |
50 | 1.07k | } |
51 | | |
52 | | static int merge_superframe(AVPacket * const *in, int n_in, AVPacket *out) |
53 | 1.07k | { |
54 | 1.07k | unsigned max, sum, mag, marker, n, sz; |
55 | 1.07k | uint8_t *ptr; |
56 | 1.07k | int res; |
57 | | |
58 | 1.07k | stats(in, n_in, &max, &sum); |
59 | 1.07k | mag = av_log2(max) >> 3; |
60 | 1.07k | marker = 0xC0 + (mag << 3) + (n_in - 1); |
61 | 1.07k | sz = sum + 2 + (mag + 1) * n_in; |
62 | 1.07k | res = av_new_packet(out, sz); |
63 | 1.07k | if (res < 0) |
64 | 0 | return res; |
65 | 1.07k | ptr = out->data; |
66 | 4.12k | for (n = 0; n < n_in; n++) { |
67 | 3.05k | memcpy(ptr, in[n]->data, in[n]->size); |
68 | 3.05k | ptr += in[n]->size; |
69 | 3.05k | } |
70 | | |
71 | 1.07k | #define wloop(mag, wr) \ |
72 | 1.07k | do { \ |
73 | 4.12k | for (n = 0; n < n_in; n++) { \ |
74 | 3.05k | wr; \ |
75 | 3.05k | ptr += mag + 1; \ |
76 | 3.05k | } \ |
77 | 1.07k | } while (0) |
78 | | |
79 | | // write superframe with marker 110[mag:2][nframes:3] |
80 | 1.07k | *ptr++ = marker; |
81 | 1.07k | switch (mag) { |
82 | 633 | case 0: |
83 | 633 | wloop(mag, *ptr = in[n]->size); |
84 | 633 | break; |
85 | 387 | case 1: |
86 | 387 | wloop(mag, AV_WL16(ptr, in[n]->size)); |
87 | 387 | break; |
88 | 51 | case 2: |
89 | 51 | wloop(mag, AV_WL24(ptr, in[n]->size)); |
90 | 51 | break; |
91 | 0 | case 3: |
92 | 0 | wloop(mag, AV_WL32(ptr, in[n]->size)); |
93 | 0 | break; |
94 | 1.07k | } |
95 | 1.07k | *ptr++ = marker; |
96 | 1.07k | av_assert0(ptr == &out->data[out->size]); |
97 | | |
98 | 1.07k | return 0; |
99 | 1.07k | } |
100 | | |
101 | | static int vp9_superframe_filter(AVBSFContext *ctx, AVPacket *pkt) |
102 | 18.8k | { |
103 | 18.8k | GetBitContext gb; |
104 | 18.8k | VP9BSFContext *s = ctx->priv_data; |
105 | 18.8k | int res, invisible, profile, marker, uses_superframe_syntax = 0, n; |
106 | | |
107 | 18.8k | res = ff_bsf_get_packet_ref(ctx, pkt); |
108 | 18.8k | if (res < 0) |
109 | 6.42k | return res; |
110 | | |
111 | 12.4k | if (!pkt->size) { |
112 | | /* In case the cache is empty we can pass side-data-only packets |
113 | | * through unchanged. Otherwise, such a packet makes no sense. */ |
114 | 2.60k | if (!s->n_cache) |
115 | 2.11k | return 0; |
116 | 491 | res = AVERROR_INVALIDDATA; |
117 | 491 | goto done; |
118 | 2.60k | } |
119 | | |
120 | 9.80k | marker = pkt->data[pkt->size - 1]; |
121 | 9.80k | if ((marker & 0xe0) == 0xc0) { |
122 | 1.84k | int nbytes = 1 + ((marker >> 3) & 0x3); |
123 | 1.84k | int n_frames = 1 + (marker & 0x7), idx_sz = 2 + n_frames * nbytes; |
124 | | |
125 | 1.84k | uses_superframe_syntax = pkt->size >= idx_sz && pkt->data[pkt->size - idx_sz] == marker; |
126 | 1.84k | } |
127 | | |
128 | 9.80k | if ((res = init_get_bits8(&gb, pkt->data, pkt->size)) < 0) |
129 | 0 | goto done; |
130 | | |
131 | 9.80k | get_bits(&gb, 2); // frame marker |
132 | 9.80k | profile = get_bits1(&gb); |
133 | 9.80k | profile |= get_bits1(&gb) << 1; |
134 | 9.80k | if (profile == 3) profile += get_bits1(&gb); |
135 | | |
136 | 9.80k | if (get_bits1(&gb)) { |
137 | 1.95k | invisible = 0; |
138 | 7.84k | } else { |
139 | 7.84k | get_bits1(&gb); // keyframe |
140 | 7.84k | invisible = !get_bits1(&gb); |
141 | 7.84k | } |
142 | | |
143 | 9.80k | if (uses_superframe_syntax && s->n_cache > 0) { |
144 | 296 | av_log(ctx, AV_LOG_ERROR, |
145 | 296 | "Mixing of superframe syntax and naked VP9 frames not supported\n"); |
146 | 296 | res = AVERROR(ENOSYS); |
147 | 296 | goto done; |
148 | 9.50k | } else if ((!invisible || uses_superframe_syntax) && !s->n_cache) { |
149 | | // passthrough |
150 | 2.86k | return 0; |
151 | 6.63k | } else if (s->n_cache + 1 >= MAX_CACHE) { |
152 | 581 | av_log(ctx, AV_LOG_ERROR, |
153 | 581 | "Too many invisible frames\n"); |
154 | 581 | res = AVERROR_INVALIDDATA; |
155 | 581 | goto done; |
156 | 581 | } |
157 | | |
158 | 6.05k | av_packet_move_ref(s->cache[s->n_cache++], pkt); |
159 | | |
160 | 6.05k | if (invisible) { |
161 | 4.98k | return AVERROR(EAGAIN); |
162 | 4.98k | } |
163 | 1.07k | av_assert0(s->n_cache > 0); |
164 | | |
165 | | // build superframe |
166 | 1.07k | if ((res = merge_superframe(s->cache, s->n_cache, pkt)) < 0) |
167 | 0 | goto done; |
168 | | |
169 | 1.07k | res = av_packet_copy_props(pkt, s->cache[s->n_cache - 1]); |
170 | 1.07k | if (res < 0) |
171 | 0 | goto done; |
172 | | |
173 | 4.12k | for (n = 0; n < s->n_cache; n++) |
174 | 3.05k | av_packet_unref(s->cache[n]); |
175 | 1.07k | s->n_cache = 0; |
176 | | |
177 | 2.43k | done: |
178 | 2.43k | if (res < 0) |
179 | 1.36k | av_packet_unref(pkt); |
180 | 2.43k | return res; |
181 | 1.07k | } |
182 | | |
183 | | static int vp9_superframe_init(AVBSFContext *ctx) |
184 | 382 | { |
185 | 382 | VP9BSFContext *s = ctx->priv_data; |
186 | 382 | int n; |
187 | | |
188 | | // alloc cache packets |
189 | 3.43k | for (n = 0; n < MAX_CACHE; n++) { |
190 | 3.05k | s->cache[n] = av_packet_alloc(); |
191 | 3.05k | if (!s->cache[n]) |
192 | 0 | return AVERROR(ENOMEM); |
193 | 3.05k | } |
194 | | |
195 | 382 | return 0; |
196 | 382 | } |
197 | | |
198 | | static void vp9_superframe_flush(AVBSFContext *ctx) |
199 | 3.35k | { |
200 | 3.35k | VP9BSFContext *s = ctx->priv_data; |
201 | 3.35k | int n; |
202 | | |
203 | | // unref cached data |
204 | 6.05k | for (n = 0; n < s->n_cache; n++) |
205 | 2.70k | av_packet_unref(s->cache[n]); |
206 | 3.35k | s->n_cache = 0; |
207 | 3.35k | } |
208 | | |
209 | | static void vp9_superframe_close(AVBSFContext *ctx) |
210 | 402 | { |
211 | 402 | VP9BSFContext *s = ctx->priv_data; |
212 | 402 | int n; |
213 | | |
214 | | // free cached data |
215 | 3.61k | for (n = 0; n < MAX_CACHE; n++) |
216 | 3.21k | av_packet_free(&s->cache[n]); |
217 | 402 | } |
218 | | |
219 | | static const enum AVCodecID codec_ids[] = { |
220 | | AV_CODEC_ID_VP9, AV_CODEC_ID_NONE, |
221 | | }; |
222 | | |
223 | | const FFBitStreamFilter ff_vp9_superframe_bsf = { |
224 | | .p.name = "vp9_superframe", |
225 | | .p.codec_ids = codec_ids, |
226 | | .priv_data_size = sizeof(VP9BSFContext), |
227 | | .filter = vp9_superframe_filter, |
228 | | .init = vp9_superframe_init, |
229 | | .flush = vp9_superframe_flush, |
230 | | .close = vp9_superframe_close, |
231 | | }; |