• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     marker = pkt->data[pkt->size - 1];
112     if ((marker & 0xe0) == 0xc0) {
113         int nbytes = 1 + ((marker >> 3) & 0x3);
114         int n_frames = 1 + (marker & 0x7), idx_sz = 2 + n_frames * nbytes;
115 
116         uses_superframe_syntax = pkt->size >= idx_sz && pkt->data[pkt->size - idx_sz] == marker;
117     }
118 
119     if ((res = init_get_bits8(&gb, pkt->data, pkt->size)) < 0)
120         goto done;
121 
122     get_bits(&gb, 2); // frame marker
123     profile  = get_bits1(&gb);
124     profile |= get_bits1(&gb) << 1;
125     if (profile == 3) profile += get_bits1(&gb);
126 
127     if (get_bits1(&gb)) {
128         invisible = 0;
129     } else {
130         get_bits1(&gb); // keyframe
131         invisible = !get_bits1(&gb);
132     }
133 
134     if (uses_superframe_syntax && s->n_cache > 0) {
135         av_log(ctx, AV_LOG_ERROR,
136                "Mixing of superframe syntax and naked VP9 frames not supported\n");
137         res = AVERROR(ENOSYS);
138         goto done;
139     } else if ((!invisible || uses_superframe_syntax) && !s->n_cache) {
140         // passthrough
141         return 0;
142     } else if (s->n_cache + 1 >= MAX_CACHE) {
143         av_log(ctx, AV_LOG_ERROR,
144                "Too many invisible frames\n");
145         res = AVERROR_INVALIDDATA;
146         goto done;
147     }
148 
149     av_packet_move_ref(s->cache[s->n_cache++], pkt);
150 
151     if (invisible) {
152         return AVERROR(EAGAIN);
153     }
154     av_assert0(s->n_cache > 0);
155 
156     // build superframe
157     if ((res = merge_superframe(s->cache, s->n_cache, pkt)) < 0)
158         goto done;
159 
160     res = av_packet_copy_props(pkt, s->cache[s->n_cache - 1]);
161     if (res < 0)
162         goto done;
163 
164     for (n = 0; n < s->n_cache; n++)
165         av_packet_unref(s->cache[n]);
166     s->n_cache = 0;
167 
168 done:
169     if (res < 0)
170         av_packet_unref(pkt);
171     return res;
172 }
173 
vp9_superframe_init(AVBSFContext * ctx)174 static int vp9_superframe_init(AVBSFContext *ctx)
175 {
176     VP9BSFContext *s = ctx->priv_data;
177     int n;
178 
179     // alloc cache packets
180     for (n = 0; n < MAX_CACHE; n++) {
181         s->cache[n] = av_packet_alloc();
182         if (!s->cache[n])
183             return AVERROR(ENOMEM);
184     }
185 
186     return 0;
187 }
188 
vp9_superframe_flush(AVBSFContext * ctx)189 static void vp9_superframe_flush(AVBSFContext *ctx)
190 {
191     VP9BSFContext *s = ctx->priv_data;
192     int n;
193 
194     // unref cached data
195     for (n = 0; n < s->n_cache; n++)
196         av_packet_unref(s->cache[n]);
197     s->n_cache = 0;
198 }
199 
vp9_superframe_close(AVBSFContext * ctx)200 static void vp9_superframe_close(AVBSFContext *ctx)
201 {
202     VP9BSFContext *s = ctx->priv_data;
203     int n;
204 
205     // free cached data
206     for (n = 0; n < MAX_CACHE; n++)
207         av_packet_free(&s->cache[n]);
208 }
209 
210 static const enum AVCodecID codec_ids[] = {
211     AV_CODEC_ID_VP9, AV_CODEC_ID_NONE,
212 };
213 
214 const AVBitStreamFilter ff_vp9_superframe_bsf = {
215     .name           = "vp9_superframe",
216     .priv_data_size = sizeof(VP9BSFContext),
217     .filter         = vp9_superframe_filter,
218     .init           = vp9_superframe_init,
219     .flush          = vp9_superframe_flush,
220     .close          = vp9_superframe_close,
221     .codec_ids      = codec_ids,
222 };
223