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 32typedef 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 41static 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 { 127passthrough: 128 av_packet_move_ref(out, s->buffer_pkt); 129 } 130 131 return 0; 132fail: 133 if (ret < 0) 134 av_packet_unref(out); 135 av_packet_unref(s->buffer_pkt); 136 return ret; 137} 138 139static 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 150static void vp9_superframe_split_flush(AVBSFContext *ctx) 151{ 152 VP9SFSplitContext *s = ctx->priv_data; 153 av_packet_unref(s->buffer_pkt); 154} 155 156static void vp9_superframe_split_uninit(AVBSFContext *ctx) 157{ 158 VP9SFSplitContext *s = ctx->priv_data; 159 av_packet_free(&s->buffer_pkt); 160} 161 162const 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}; 171