1/* 2 * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> 3 * 4 * This file is part of FFmpeg. 5 * 6 * FFmpeg is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * FFmpeg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with FFmpeg; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21#include "libavutil/log.h" 22#include "libavutil/opt.h" 23 24#include "av1_parse.h" 25#include "bsf.h" 26#include "bsf_internal.h" 27#include "h264.h" 28#include "hevc.h" 29#include "startcode.h" 30#include "vc1_common.h" 31 32enum RemoveFreq { 33 REMOVE_FREQ_KEYFRAME, 34 REMOVE_FREQ_ALL, 35 REMOVE_FREQ_NONKEYFRAME, 36}; 37 38#define START_CODE 0x000001 39 40typedef struct RemoveExtradataContext { 41 const AVClass *class; 42 int freq; 43} RemoveExtradataContext; 44 45static int av1_split(const uint8_t *buf, int buf_size, void *logctx) 46{ 47 AV1OBU obu; 48 const uint8_t *ptr = buf, *end = buf + buf_size; 49 50 while (ptr < end) { 51 int len = ff_av1_extract_obu(&obu, ptr, buf_size, logctx); 52 if (len < 0) 53 break; 54 55 if (obu.type == AV1_OBU_FRAME_HEADER || 56 obu.type == AV1_OBU_FRAME) { 57 return ptr - buf; 58 } 59 ptr += len; 60 buf_size -= len; 61 } 62 63 return 0; 64} 65 66static int h264_split(const uint8_t *buf, int buf_size) 67{ 68 const uint8_t *ptr = buf, *end = buf + buf_size; 69 uint32_t state = -1; 70 int has_sps = 0; 71 int has_pps = 0; 72 int nalu_type; 73 74 while (ptr < end) { 75 ptr = avpriv_find_start_code(ptr, end, &state); 76 if ((state & 0xFFFFFF00) != 0x100) 77 break; 78 nalu_type = state & 0x1F; 79 if (nalu_type == H264_NAL_SPS) { 80 has_sps = 1; 81 } else if (nalu_type == H264_NAL_PPS) 82 has_pps = 1; 83 /* else if (nalu_type == 0x01 || 84 * nalu_type == 0x02 || 85 * nalu_type == 0x05) { 86 * } 87 */ 88 else if ((nalu_type != H264_NAL_SEI || has_pps) && 89 nalu_type != H264_NAL_AUD && nalu_type != H264_NAL_SPS_EXT && 90 nalu_type != 0x0f) { 91 if (has_sps) { 92 while (ptr - 4 > buf && ptr[-5] == 0) 93 ptr--; 94 return ptr - 4 - buf; 95 } 96 } 97 } 98 99 return 0; 100} 101 102// Split after the parameter sets at the beginning of the stream if they exist. 103static int hevc_split(const uint8_t *buf, int buf_size) 104{ 105 const uint8_t *ptr = buf, *end = buf + buf_size; 106 uint32_t state = -1; 107 int has_vps = 0; 108 int has_sps = 0; 109 int has_pps = 0; 110 int nut; 111 112 while (ptr < end) { 113 ptr = avpriv_find_start_code(ptr, end, &state); 114 if ((state >> 8) != START_CODE) 115 break; 116 nut = (state >> 1) & 0x3F; 117 if (nut == HEVC_NAL_VPS) 118 has_vps = 1; 119 else if (nut == HEVC_NAL_SPS) 120 has_sps = 1; 121 else if (nut == HEVC_NAL_PPS) 122 has_pps = 1; 123 else if ((nut != HEVC_NAL_SEI_PREFIX || has_pps) && 124 nut != HEVC_NAL_AUD) { 125 if (has_vps && has_sps) { 126 while (ptr - 4 > buf && ptr[-5] == 0) 127 ptr--; 128 return ptr - 4 - buf; 129 } 130 } 131 } 132 return 0; 133} 134 135static int mpegvideo_split(const uint8_t *buf, int buf_size) 136{ 137 uint32_t state = -1; 138 int found = 0; 139 140 for (int i = 0; i < buf_size; i++) { 141 state = (state << 8) | buf[i]; 142 if (state == 0x1B3) { 143 found = 1; 144 } else if (found && state != 0x1B5 && state < 0x200 && state >= 0x100) 145 return i - 3; 146 } 147 return 0; 148} 149 150static int mpeg4video_split(const uint8_t *buf, int buf_size) 151{ 152 const uint8_t *ptr = buf, *end = buf + buf_size; 153 uint32_t state = -1; 154 155 while (ptr < end) { 156 ptr = avpriv_find_start_code(ptr, end, &state); 157 if (state == 0x1B3 || state == 0x1B6) 158 return ptr - 4 - buf; 159 } 160 161 return 0; 162} 163 164static int vc1_split(const uint8_t *buf, int buf_size) 165{ 166 const uint8_t *ptr = buf, *end = buf + buf_size; 167 uint32_t state = -1; 168 int charged = 0; 169 170 while (ptr < end) { 171 ptr = avpriv_find_start_code(ptr, end, &state); 172 if (state == VC1_CODE_SEQHDR || state == VC1_CODE_ENTRYPOINT) { 173 charged = 1; 174 } else if (charged && IS_MARKER(state)) 175 return ptr - 4 - buf; 176 } 177 178 return 0; 179} 180 181static int remove_extradata(AVBSFContext *ctx, AVPacket *pkt) 182{ 183 RemoveExtradataContext *s = ctx->priv_data; 184 185 int ret; 186 187 ret = ff_bsf_get_packet_ref(ctx, pkt); 188 if (ret < 0) 189 return ret; 190 191 if (s->freq == REMOVE_FREQ_ALL || 192 (s->freq == REMOVE_FREQ_NONKEYFRAME && !(pkt->flags & AV_PKT_FLAG_KEY)) || 193 (s->freq == REMOVE_FREQ_KEYFRAME && pkt->flags & AV_PKT_FLAG_KEY)) { 194 int i; 195 196 switch (ctx->par_in->codec_id) { 197 case AV_CODEC_ID_AV1: 198 i = av1_split(pkt->data, pkt->size, ctx); 199 break; 200 case AV_CODEC_ID_AVS2: 201 case AV_CODEC_ID_AVS3: 202 case AV_CODEC_ID_CAVS: 203 case AV_CODEC_ID_MPEG4: 204 i = mpeg4video_split(pkt->data, pkt->size); 205 break; 206 case AV_CODEC_ID_H264: 207 i = h264_split(pkt->data, pkt->size); 208 break; 209 case AV_CODEC_ID_HEVC: 210 i = hevc_split(pkt->data, pkt->size); 211 break; 212 case AV_CODEC_ID_MPEG1VIDEO: 213 case AV_CODEC_ID_MPEG2VIDEO: 214 i = mpegvideo_split(pkt->data, pkt->size); 215 break; 216 case AV_CODEC_ID_VC1: 217 i = vc1_split(pkt->data, pkt->size); 218 break; 219 default: 220 i = 0; 221 } 222 223 pkt->data += i; 224 pkt->size -= i; 225 } 226 227 return 0; 228} 229 230#define OFFSET(x) offsetof(RemoveExtradataContext, x) 231#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM) 232static const AVOption options[] = { 233 { "freq", NULL, OFFSET(freq), AV_OPT_TYPE_INT, { .i64 = REMOVE_FREQ_KEYFRAME }, REMOVE_FREQ_KEYFRAME, REMOVE_FREQ_NONKEYFRAME, FLAGS, "freq" }, 234 { "k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_NONKEYFRAME }, .flags = FLAGS, .unit = "freq" }, 235 { "keyframe", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_KEYFRAME }, .flags = FLAGS, .unit = "freq" }, 236 { "e", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_ALL }, .flags = FLAGS, .unit = "freq" }, 237 { "all", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_ALL }, .flags = FLAGS, .unit = "freq" }, 238 { NULL }, 239}; 240 241static const AVClass remove_extradata_class = { 242 .class_name = "remove_extradata", 243 .item_name = av_default_item_name, 244 .option = options, 245 .version = LIBAVUTIL_VERSION_INT, 246}; 247 248const FFBitStreamFilter ff_remove_extradata_bsf = { 249 .p.name = "remove_extra", 250 .p.priv_class = &remove_extradata_class, 251 .priv_data_size = sizeof(RemoveExtradataContext), 252 .filter = remove_extradata, 253}; 254