X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fremove_extradata_bsf.c;h=1d5f193f89de32ee5d4f1d1271052d196660cbec;hb=e5af9203098a889f36b759652615046254d45102;hp=5783b075f017a2d4fcbeace2000956307639f9b5;hpb=e625ae609206e0550ff733965c6f5447579320aa;p=ffmpeg diff --git a/libavcodec/remove_extradata_bsf.c b/libavcodec/remove_extradata_bsf.c index 5783b075f01..1d5f193f89d 100644 --- a/libavcodec/remove_extradata_bsf.c +++ b/libavcodec/remove_extradata_bsf.c @@ -21,9 +21,13 @@ #include "libavutil/log.h" #include "libavutil/opt.h" -#include "avcodec.h" +#include "av1_parse.h" #include "bsf.h" #include "bsf_internal.h" +#include "h264.h" +#include "hevc.h" +#include "internal.h" +#include "vc1_common.h" enum RemoveFreq { REMOVE_FREQ_KEYFRAME, @@ -31,63 +35,196 @@ enum RemoveFreq { REMOVE_FREQ_NONKEYFRAME, }; +#define START_CODE 0x000001 + typedef struct RemoveExtradataContext { const AVClass *class; int freq; - - AVCodecParserContext *parser; - AVCodecContext *avctx; } RemoveExtradataContext; -static int remove_extradata(AVBSFContext *ctx, AVPacket *pkt) +static int av1_split(const uint8_t *buf, int buf_size, void *logctx) { - RemoveExtradataContext *s = ctx->priv_data; + AV1OBU obu; + const uint8_t *ptr = buf, *end = buf + buf_size; - int ret; + while (ptr < end) { + int len = ff_av1_extract_obu(&obu, ptr, buf_size, logctx); + if (len < 0) + break; - ret = ff_bsf_get_packet_ref(ctx, pkt); - if (ret < 0) - return ret; + if (obu.type == AV1_OBU_FRAME_HEADER || + obu.type == AV1_OBU_FRAME) { + return ptr - buf; + } + ptr += len; + buf_size -= len; + } + + return 0; +} - if (s->parser && s->parser->parser->split) { - if (s->freq == REMOVE_FREQ_ALL || - (s->freq == REMOVE_FREQ_NONKEYFRAME && !(pkt->flags & AV_PKT_FLAG_KEY)) || - (s->freq == REMOVE_FREQ_KEYFRAME && pkt->flags & AV_PKT_FLAG_KEY)) { - int i = s->parser->parser->split(s->avctx, pkt->data, pkt->size); - pkt->data += i; - pkt->size -= i; +static int h264_split(const uint8_t *buf, int buf_size) +{ + const uint8_t *ptr = buf, *end = buf + buf_size; + uint32_t state = -1; + int has_sps = 0; + int has_pps = 0; + int nalu_type; + + while (ptr < end) { + ptr = avpriv_find_start_code(ptr, end, &state); + if ((state & 0xFFFFFF00) != 0x100) + break; + nalu_type = state & 0x1F; + if (nalu_type == H264_NAL_SPS) { + has_sps = 1; + } else if (nalu_type == H264_NAL_PPS) + has_pps = 1; + /* else if (nalu_type == 0x01 || + * nalu_type == 0x02 || + * nalu_type == 0x05) { + * } + */ + else if ((nalu_type != H264_NAL_SEI || has_pps) && + nalu_type != H264_NAL_AUD && nalu_type != H264_NAL_SPS_EXT && + nalu_type != 0x0f) { + if (has_sps) { + while (ptr - 4 > buf && ptr[-5] == 0) + ptr--; + return ptr - 4 - buf; + } } } return 0; } -static int remove_extradata_init(AVBSFContext *ctx) +// Split after the parameter sets at the beginning of the stream if they exist. +static int hevc_split(const uint8_t *buf, int buf_size) { - RemoveExtradataContext *s = ctx->priv_data; - int ret; + const uint8_t *ptr = buf, *end = buf + buf_size; + uint32_t state = -1; + int has_vps = 0; + int has_sps = 0; + int has_pps = 0; + int nut; + + while (ptr < end) { + ptr = avpriv_find_start_code(ptr, end, &state); + if ((state >> 8) != START_CODE) + break; + nut = (state >> 1) & 0x3F; + if (nut == HEVC_NAL_VPS) + has_vps = 1; + else if (nut == HEVC_NAL_SPS) + has_sps = 1; + else if (nut == HEVC_NAL_PPS) + has_pps = 1; + else if ((nut != HEVC_NAL_SEI_PREFIX || has_pps) && + nut != HEVC_NAL_AUD) { + if (has_vps && has_sps) { + while (ptr - 4 > buf && ptr[-5] == 0) + ptr--; + return ptr - 4 - buf; + } + } + } + return 0; +} - s->parser = av_parser_init(ctx->par_in->codec_id); +static int mpegvideo_split(const uint8_t *buf, int buf_size) +{ + uint32_t state = -1; + int found = 0; + + for (int i = 0; i < buf_size; i++) { + state = (state << 8) | buf[i]; + if (state == 0x1B3) { + found = 1; + } else if (found && state != 0x1B5 && state < 0x200 && state >= 0x100) + return i - 3; + } + return 0; +} - if (s->parser) { - s->avctx = avcodec_alloc_context3(NULL); - if (!s->avctx) - return AVERROR(ENOMEM); +static int mpeg4video_split(const uint8_t *buf, int buf_size) +{ + const uint8_t *ptr = buf, *end = buf + buf_size; + uint32_t state = -1; - ret = avcodec_parameters_to_context(s->avctx, ctx->par_in); - if (ret < 0) - return ret; + while (ptr < end) { + ptr = avpriv_find_start_code(ptr, end, &state); + if (state == 0x1B3 || state == 0x1B6) + return ptr - 4 - buf; } return 0; } -static void remove_extradata_close(AVBSFContext *ctx) +static int vc1_split(const uint8_t *buf, int buf_size) +{ + const uint8_t *ptr = buf, *end = buf + buf_size; + uint32_t state = -1; + int charged = 0; + + while (ptr < end) { + ptr = avpriv_find_start_code(ptr, end, &state); + if (state == VC1_CODE_SEQHDR || state == VC1_CODE_ENTRYPOINT) { + charged = 1; + } else if (charged && IS_MARKER(state)) + return ptr - 4 - buf; + } + + return 0; +} + +static int remove_extradata(AVBSFContext *ctx, AVPacket *pkt) { RemoveExtradataContext *s = ctx->priv_data; - avcodec_free_context(&s->avctx); - av_parser_close(s->parser); + int ret; + + ret = ff_bsf_get_packet_ref(ctx, pkt); + if (ret < 0) + return ret; + + if (s->freq == REMOVE_FREQ_ALL || + (s->freq == REMOVE_FREQ_NONKEYFRAME && !(pkt->flags & AV_PKT_FLAG_KEY)) || + (s->freq == REMOVE_FREQ_KEYFRAME && pkt->flags & AV_PKT_FLAG_KEY)) { + int i; + + switch (ctx->par_in->codec_id) { + case AV_CODEC_ID_AV1: + i = av1_split(pkt->data, pkt->size, ctx); + break; + case AV_CODEC_ID_AVS2: + case AV_CODEC_ID_AVS3: + case AV_CODEC_ID_CAVS: + case AV_CODEC_ID_MPEG4: + i = mpeg4video_split(pkt->data, pkt->size); + break; + case AV_CODEC_ID_H264: + i = h264_split(pkt->data, pkt->size); + break; + case AV_CODEC_ID_HEVC: + i = hevc_split(pkt->data, pkt->size); + break; + case AV_CODEC_ID_MPEG1VIDEO: + case AV_CODEC_ID_MPEG2VIDEO: + i = mpegvideo_split(pkt->data, pkt->size); + break; + case AV_CODEC_ID_VC1: + i = vc1_split(pkt->data, pkt->size); + break; + default: + i = 0; + } + + pkt->data += i; + pkt->size -= i; + } + + return 0; } #define OFFSET(x) offsetof(RemoveExtradataContext, x) @@ -112,7 +249,5 @@ const AVBitStreamFilter ff_remove_extradata_bsf = { .name = "remove_extra", .priv_data_size = sizeof(RemoveExtradataContext), .priv_class = &remove_extradata_class, - .init = remove_extradata_init, - .close = remove_extradata_close, .filter = remove_extradata, };