blob: b686adbe1673f564d252a30cff11c5895a9a3b55
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 | #include "avcodec.h" |
24 | #include "bsf.h" |
25 | #include "get_bits.h" |
26 | |
27 | #define MAX_CACHE 8 |
28 | typedef struct VP9BSFContext { |
29 | int n_cache; |
30 | struct CachedBuf { |
31 | uint8_t *data; |
32 | int size; |
33 | } cache[MAX_CACHE]; |
34 | } VP9BSFContext; |
35 | |
36 | static void stats(const struct CachedBuf *in, int n_in, |
37 | unsigned *_max, unsigned *_sum) |
38 | { |
39 | int n; |
40 | unsigned max = 0, sum = 0; |
41 | |
42 | for (n = 0; n < n_in; n++) { |
43 | unsigned sz = in[n].size; |
44 | |
45 | if (sz > max) |
46 | max = sz; |
47 | sum += sz; |
48 | } |
49 | |
50 | *_max = max; |
51 | *_sum = sum; |
52 | } |
53 | |
54 | static int merge_superframe(const struct CachedBuf *in, int n_in, AVPacket *out) |
55 | { |
56 | unsigned max, sum, mag, marker, n, sz; |
57 | uint8_t *ptr; |
58 | int res; |
59 | |
60 | stats(in, n_in, &max, &sum); |
61 | mag = av_log2(max) >> 3; |
62 | marker = 0xC0 + (mag << 3) + (n_in - 1); |
63 | sz = sum + 2 + (mag + 1) * n_in; |
64 | res = av_new_packet(out, sz); |
65 | if (res < 0) |
66 | return res; |
67 | ptr = out->data; |
68 | for (n = 0; n < n_in; n++) { |
69 | memcpy(ptr, in[n].data, in[n].size); |
70 | ptr += in[n].size; |
71 | } |
72 | |
73 | #define wloop(mag, wr) \ |
74 | for (n = 0; n < n_in; n++) { \ |
75 | wr; \ |
76 | ptr += mag + 1; \ |
77 | } |
78 | |
79 | // write superframe with marker 110[mag:2][nframes:3] |
80 | *ptr++ = marker; |
81 | switch (mag) { |
82 | case 0: |
83 | wloop(mag, *ptr = in[n].size); |
84 | break; |
85 | case 1: |
86 | wloop(mag, AV_WL16(ptr, in[n].size)); |
87 | break; |
88 | case 2: |
89 | wloop(mag, AV_WL24(ptr, in[n].size)); |
90 | break; |
91 | case 3: |
92 | wloop(mag, AV_WL32(ptr, in[n].size)); |
93 | break; |
94 | } |
95 | *ptr++ = marker; |
96 | av_assert0(ptr == &out->data[out->size]); |
97 | |
98 | return 0; |
99 | } |
100 | |
101 | static int vp9_superframe_filter(AVBSFContext *ctx, AVPacket *out) |
102 | { |
103 | GetBitContext gb; |
104 | VP9BSFContext *s = ctx->priv_data; |
105 | AVPacket *in; |
106 | int res, invisible, profile, marker, uses_superframe_syntax = 0, n; |
107 | |
108 | res = ff_bsf_get_packet(ctx, &in); |
109 | if (res < 0) |
110 | return res; |
111 | |
112 | marker = in->data[in->size - 1]; |
113 | if ((marker & 0xe0) == 0xc0) { |
114 | int nbytes = 1 + ((marker >> 3) & 0x3); |
115 | int n_frames = 1 + (marker & 0x7), idx_sz = 2 + n_frames * nbytes; |
116 | |
117 | uses_superframe_syntax = in->size >= idx_sz && in->data[in->size - idx_sz] == marker; |
118 | } |
119 | |
120 | if ((res = init_get_bits8(&gb, in->data, in->size)) < 0) |
121 | goto done; |
122 | |
123 | get_bits(&gb, 2); // frame marker |
124 | profile = get_bits1(&gb); |
125 | profile |= get_bits1(&gb) << 1; |
126 | if (profile == 3) profile += get_bits1(&gb); |
127 | |
128 | if (get_bits1(&gb)) { |
129 | invisible = 0; |
130 | } else { |
131 | get_bits1(&gb); // keyframe |
132 | invisible = !get_bits1(&gb); |
133 | } |
134 | |
135 | if (uses_superframe_syntax && s->n_cache > 0) { |
136 | av_log(ctx, AV_LOG_ERROR, |
137 | "Mixing of superframe syntax and naked VP9 frames not supported"); |
138 | res = AVERROR_INVALIDDATA; |
139 | goto done; |
140 | } else if ((!invisible || uses_superframe_syntax) && !s->n_cache) { |
141 | // passthrough |
142 | av_packet_move_ref(out, in); |
143 | goto done; |
144 | } else if (s->n_cache + 1 >= MAX_CACHE) { |
145 | av_log(ctx, AV_LOG_ERROR, |
146 | "Too many invisible frames"); |
147 | res = AVERROR_INVALIDDATA; |
148 | goto done; |
149 | } |
150 | |
151 | s->cache[s->n_cache].size = in->size; |
152 | if (invisible && !uses_superframe_syntax) { |
153 | s->cache[s->n_cache].data = av_malloc(in->size); |
154 | if (!s->cache[s->n_cache].data) { |
155 | res = AVERROR(ENOMEM); |
156 | goto done; |
157 | } |
158 | memcpy(s->cache[s->n_cache++].data, in->data, in->size); |
159 | res = AVERROR(EAGAIN); |
160 | goto done; |
161 | } |
162 | av_assert0(s->n_cache > 0); |
163 | |
164 | s->cache[s->n_cache].data = in->data; |
165 | |
166 | // build superframe |
167 | if ((res = merge_superframe(s->cache, s->n_cache + 1, out)) < 0) |
168 | goto done; |
169 | |
170 | for (n = 0; n < s->n_cache; n++) |
171 | av_freep(&s->cache[n].data); |
172 | s->n_cache = 0; |
173 | |
174 | res = av_packet_copy_props(out, in); |
175 | if (res < 0) |
176 | goto done; |
177 | |
178 | done: |
179 | if (res < 0) |
180 | av_packet_unref(out); |
181 | av_packet_free(&in); |
182 | return res; |
183 | } |
184 | |
185 | static void vp9_superframe_close(AVBSFContext *ctx) |
186 | { |
187 | VP9BSFContext *s = ctx->priv_data; |
188 | int n; |
189 | |
190 | // free cached data |
191 | for (n = 0; n < s->n_cache; n++) |
192 | av_freep(&s->cache[n].data); |
193 | } |
194 | |
195 | static const enum AVCodecID codec_ids[] = { |
196 | AV_CODEC_ID_VP9, AV_CODEC_ID_NONE, |
197 | }; |
198 | |
199 | const AVBitStreamFilter ff_vp9_superframe_bsf = { |
200 | .name = "vp9_superframe", |
201 | .priv_data_size = sizeof(VP9BSFContext), |
202 | .filter = vp9_superframe_filter, |
203 | .close = vp9_superframe_close, |
204 | .codec_ids = codec_ids, |
205 | }; |
206 |