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 29typedef struct VP9BSFContext { 30 int n_cache; 31 AVPacket *cache[MAX_CACHE]; 32} VP9BSFContext; 33 34static 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 52static 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 101static 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 177done: 178 if (res < 0) 179 av_packet_unref(pkt); 180 return res; 181} 182 183static 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 198static 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 209static 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 219static const enum AVCodecID codec_ids[] = { 220 AV_CODEC_ID_VP9, AV_CODEC_ID_NONE, 221}; 222 223const 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