tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

vp9_superframe_split.c (5002B)


      1 /*
      2 * This file is part of FFmpeg.
      3 *
      4 * FFmpeg is free software; you can redistribute it and/or
      5 * modify it under the terms of the GNU Lesser General Public
      6 * License as published by the Free Software Foundation; either
      7 * version 2.1 of the License, or (at your option) any later version.
      8 *
      9 * FFmpeg is distributed in the hope that it will be useful,
     10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12 * Lesser General Public License for more details.
     13 *
     14 * You should have received a copy of the GNU Lesser General Public
     15 * License along with FFmpeg; if not, write to the Free Software
     16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     17 */
     18 
     19 /**
     20 * @file
     21 * This bitstream filter splits VP9 superframes into packets containing
     22 * just one frame.
     23 */
     24 
     25 #include <stddef.h>
     26 
     27 #include "bsf.h"
     28 #include "bsf_internal.h"
     29 #include "bytestream.h"
     30 #include "get_bits.h"
     31 
     32 typedef struct VP9SFSplitContext {
     33    AVPacket *buffer_pkt;
     34 
     35    int nb_frames;
     36    int next_frame;
     37    size_t next_frame_offset;
     38    int sizes[8];
     39 } VP9SFSplitContext;
     40 
     41 static int vp9_superframe_split_filter(AVBSFContext *ctx, AVPacket *out)
     42 {
     43    VP9SFSplitContext *s = ctx->priv_data;
     44    AVPacket *in;
     45    int i, j, ret, marker;
     46    int is_superframe = !!s->buffer_pkt->data;
     47 
     48    if (!s->buffer_pkt->data) {
     49        ret = ff_bsf_get_packet_ref(ctx, s->buffer_pkt);
     50        if (ret < 0)
     51            return ret;
     52        in = s->buffer_pkt;
     53 
     54        if (!in->size)
     55            goto passthrough;
     56 
     57        marker = in->data[in->size - 1];
     58        if ((marker & 0xe0) == 0xc0) {
     59            int length_size = 1 + ((marker >> 3) & 0x3);
     60            int   nb_frames = 1 + (marker & 0x7);
     61            int    idx_size = 2 + nb_frames * length_size;
     62 
     63            if (in->size >= idx_size && in->data[in->size - idx_size] == marker) {
     64                GetByteContext bc;
     65                int64_t total_size = 0;
     66 
     67                bytestream2_init(&bc, in->data + in->size + 1 - idx_size,
     68                                 nb_frames * length_size);
     69 
     70                for (i = 0; i < nb_frames; i++) {
     71                    int frame_size = 0;
     72                    for (j = 0; j < length_size; j++)
     73                        frame_size |= bytestream2_get_byte(&bc) << (j * 8);
     74 
     75                    total_size += frame_size;
     76                    if (frame_size <= 0 || total_size > in->size - idx_size) {
     77                        av_log(ctx, AV_LOG_ERROR,
     78                               "Invalid frame size in a superframe: %d\n", frame_size);
     79                        ret = AVERROR(EINVAL);
     80                        goto fail;
     81                    }
     82                    s->sizes[i] = frame_size;
     83                }
     84                s->nb_frames         = nb_frames;
     85                s->next_frame        = 0;
     86                s->next_frame_offset = 0;
     87                is_superframe        = 1;
     88            }
     89        }
     90    }
     91 
     92    if (is_superframe) {
     93        GetBitContext gb;
     94        int profile, invisible = 0;
     95 
     96        ret = av_packet_ref(out, s->buffer_pkt);
     97        if (ret < 0)
     98            goto fail;
     99 
    100        out->data += s->next_frame_offset;
    101        out->size  = s->sizes[s->next_frame];
    102 
    103        s->next_frame_offset += out->size;
    104        s->next_frame++;
    105 
    106        if (s->next_frame >= s->nb_frames)
    107            av_packet_unref(s->buffer_pkt);
    108 
    109        ret = init_get_bits8(&gb, out->data, out->size);
    110        if (ret < 0)
    111            goto fail;
    112 
    113        get_bits(&gb, 2); // frame_marker
    114        profile  = get_bits1(&gb);
    115        profile |= get_bits1(&gb) << 1;
    116        if (profile == 3)
    117            get_bits1(&gb);
    118        if (!get_bits1(&gb)) {
    119            get_bits1(&gb);
    120            invisible = !get_bits1(&gb);
    121        }
    122 
    123        if (invisible)
    124            out->pts = AV_NOPTS_VALUE;
    125 
    126    } else {
    127 passthrough:
    128        av_packet_move_ref(out, s->buffer_pkt);
    129    }
    130 
    131    return 0;
    132 fail:
    133    if (ret < 0)
    134        av_packet_unref(out);
    135    av_packet_unref(s->buffer_pkt);
    136    return ret;
    137 }
    138 
    139 static int vp9_superframe_split_init(AVBSFContext *ctx)
    140 {
    141    VP9SFSplitContext *s = ctx->priv_data;
    142 
    143    s->buffer_pkt = av_packet_alloc();
    144    if (!s->buffer_pkt)
    145        return AVERROR(ENOMEM);
    146 
    147    return 0;
    148 }
    149 
    150 static void vp9_superframe_split_flush(AVBSFContext *ctx)
    151 {
    152    VP9SFSplitContext *s = ctx->priv_data;
    153    av_packet_unref(s->buffer_pkt);
    154 }
    155 
    156 static void vp9_superframe_split_uninit(AVBSFContext *ctx)
    157 {
    158    VP9SFSplitContext *s = ctx->priv_data;
    159    av_packet_free(&s->buffer_pkt);
    160 }
    161 
    162 const FFBitStreamFilter ff_vp9_superframe_split_bsf = {
    163    .p.name         = "vp9_superframe_split",
    164    .p.codec_ids    = (const enum AVCodecID []){ AV_CODEC_ID_VP9, AV_CODEC_ID_NONE },
    165    .priv_data_size = sizeof(VP9SFSplitContext),
    166    .init           = vp9_superframe_split_init,
    167    .flush          = vp9_superframe_split_flush,
    168    .close          = vp9_superframe_split_uninit,
    169    .filter         = vp9_superframe_split_filter,
    170 };