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 #define MAX_CACHE 8
29 typedef struct VP9BSFContext {
30     int n_cache;
31     AVPacket *cache[MAX_CACHE];
32 } VP9BSFContext;
33 
stats(AVPacket * const *in, int n_in, unsigned *_max, unsigned *_sum)34 static void stats(AVPacket * const *in, int n_in,
35                   unsigned *_max, unsigned *_sum)
36 {
37     int n;
38     unsigned max = 0, sum = 0;
39 
40     for (n = 0; n < n_in; n++) {
41         unsigned sz = in[n]->size;
42 
43         if (sz > max)
44             max = sz;
45         sum += sz;
46     }
47 
48     *_max = max;
49     *_sum = sum;
50 }
51 
merge_superframe(AVPacket * const *in, int n_in, AVPacket *out)52 static int merge_superframe(AVPacket * const *in, int n_in, AVPacket *out)
53 {
54     unsigned max, sum, mag, marker, n, sz;
55     uint8_t *ptr;
56     int res;
57 
58     stats(in, n_in, &max, &sum);
59     mag = av_log2(max) >> 3;
60     marker = 0xC0 + (mag << 3) + (n_in - 1);
61     sz = sum + 2 + (mag + 1) * n_in;
62     res = av_new_packet(out, sz);
63     if (res < 0)
64         return res;
65     ptr = out->data;
66     for (n = 0; n < n_in; n++) {
67         memcpy(ptr, in[n]->data, in[n]->size);
68         ptr += in[n]->size;
69     }
70 
71 #define wloop(mag, wr) \
72     do { \
73         for (n = 0; n < n_in; n++) { \
74             wr; \
75             ptr += mag + 1; \
76         } \
77     } while (0)
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 
vp9_superframe_filter(AVBSFContext *ctx, AVPacket *pkt)101 static int vp9_superframe_filter(AVBSFContext *ctx, AVPacket *pkt)
102 {
103     GetBitContext gb;
104     VP9BSFContext *s = ctx->priv_data;
105     int res, invisible, profile, marker, uses_superframe_syntax = 0, n;
106 
107     res = ff_bsf_get_packet_ref(ctx, pkt);
108     if (res < 0)
109         return res;
110 
111     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         if (!s->n_cache)
115             return 0;
116         res = AVERROR_INVALIDDATA;
117         goto done;
118     }
119 
120     marker = pkt->data[pkt->size - 1];
121     if ((marker & 0xe0) == 0xc0) {
122         int nbytes = 1 + ((marker >> 3) & 0x3);
123         int n_frames = 1 + (marker & 0x7), idx_sz = 2 + n_frames * nbytes;
124 
125         uses_superframe_syntax = pkt->size >= idx_sz && pkt->data[pkt->size - idx_sz] == marker;
126     }
127 
128     if ((res = init_get_bits8(&gb, pkt->data, pkt->size)) < 0)
129         goto done;
130 
131     get_bits(&gb, 2); // frame marker
132     profile  = get_bits1(&gb);
133     profile |= get_bits1(&gb) << 1;
134     if (profile == 3) profile += get_bits1(&gb);
135 
136     if (get_bits1(&gb)) {
137         invisible = 0;
138     } else {
139         get_bits1(&gb); // keyframe
140         invisible = !get_bits1(&gb);
141     }
142 
143     if (uses_superframe_syntax && s->n_cache > 0) {
144         av_log(ctx, AV_LOG_ERROR,
145                "Mixing of superframe syntax and naked VP9 frames not supported\n");
146         res = AVERROR(ENOSYS);
147         goto done;
148     } else if ((!invisible || uses_superframe_syntax) && !s->n_cache) {
149         // passthrough
150         return 0;
151     } else if (s->n_cache + 1 >= MAX_CACHE) {
152         av_log(ctx, AV_LOG_ERROR,
153                "Too many invisible frames\n");
154         res = AVERROR_INVALIDDATA;
155         goto done;
156     }
157 
158     av_packet_move_ref(s->cache[s->n_cache++], pkt);
159 
160     if (invisible) {
161         return AVERROR(EAGAIN);
162     }
163     av_assert0(s->n_cache > 0);
164 
165     // build superframe
166     if ((res = merge_superframe(s->cache, s->n_cache, pkt)) < 0)
167         goto done;
168 
169     res = av_packet_copy_props(pkt, s->cache[s->n_cache - 1]);
170     if (res < 0)
171         goto done;
172 
173     for (n = 0; n < s->n_cache; n++)
174         av_packet_unref(s->cache[n]);
175     s->n_cache = 0;
176 
177 done:
178     if (res < 0)
179         av_packet_unref(pkt);
180     return res;
181 }
182 
vp9_superframe_init(AVBSFContext *ctx)183 static int vp9_superframe_init(AVBSFContext *ctx)
184 {
185     VP9BSFContext *s = ctx->priv_data;
186     int n;
187 
188     // alloc cache packets
189     for (n = 0; n < MAX_CACHE; n++) {
190         s->cache[n] = av_packet_alloc();
191         if (!s->cache[n])
192             return AVERROR(ENOMEM);
193     }
194 
195     return 0;
196 }
197 
vp9_superframe_flush(AVBSFContext *ctx)198 static void vp9_superframe_flush(AVBSFContext *ctx)
199 {
200     VP9BSFContext *s = ctx->priv_data;
201     int n;
202 
203     // unref cached data
204     for (n = 0; n < s->n_cache; n++)
205         av_packet_unref(s->cache[n]);
206     s->n_cache = 0;
207 }
208 
vp9_superframe_close(AVBSFContext *ctx)209 static void vp9_superframe_close(AVBSFContext *ctx)
210 {
211     VP9BSFContext *s = ctx->priv_data;
212     int n;
213 
214     // free cached data
215     for (n = 0; n < MAX_CACHE; n++)
216         av_packet_free(&s->cache[n]);
217 }
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 };
232