mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2026-04-18 16:40:23 +00:00
avcodec/bsf/extract_extradata: add support for LCEVC
Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
parent
4e32fb4c2a
commit
3dba9eb806
2 changed files with 264 additions and 0 deletions
|
|
@ -29,6 +29,7 @@
|
|||
#include "bytestream.h"
|
||||
#include "h2645_parse.h"
|
||||
#include "h264.h"
|
||||
#include "lcevc.h"
|
||||
#include "startcode.h"
|
||||
#include "vc1_common.h"
|
||||
#include "vvc.h"
|
||||
|
|
@ -167,6 +168,9 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
|
|||
static const int extradata_nal_types_vvc[] = {
|
||||
VVC_VPS_NUT, VVC_SPS_NUT, VVC_PPS_NUT,
|
||||
};
|
||||
static const int extradata_nal_types_lcevc[] = {
|
||||
LCEVC_IDR_NUT, LCEVC_NON_IDR_NUT,
|
||||
};
|
||||
static const int extradata_nal_types_hevc[] = {
|
||||
HEVC_NAL_VPS, HEVC_NAL_SPS, HEVC_NAL_PPS,
|
||||
};
|
||||
|
|
@ -184,6 +188,9 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
|
|||
if (ctx->par_in->codec_id == AV_CODEC_ID_VVC) {
|
||||
extradata_nal_types = extradata_nal_types_vvc;
|
||||
nb_extradata_nal_types = FF_ARRAY_ELEMS(extradata_nal_types_vvc);
|
||||
} else if (ctx->par_in->codec_id == AV_CODEC_ID_LCEVC) {
|
||||
extradata_nal_types = extradata_nal_types_lcevc;
|
||||
nb_extradata_nal_types = FF_ARRAY_ELEMS(extradata_nal_types_lcevc);
|
||||
} else if (ctx->par_in->codec_id == AV_CODEC_ID_HEVC) {
|
||||
extradata_nal_types = extradata_nal_types_hevc;
|
||||
nb_extradata_nal_types = FF_ARRAY_ELEMS(extradata_nal_types_hevc);
|
||||
|
|
@ -207,6 +214,8 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
|
|||
} else if (ctx->par_in->codec_id == AV_CODEC_ID_HEVC) {
|
||||
if (nal->type == HEVC_NAL_SPS) has_sps = 1;
|
||||
if (nal->type == HEVC_NAL_VPS) has_vps = 1;
|
||||
} else if (ctx->par_in->codec_id == AV_CODEC_ID_LCEVC) {
|
||||
has_sps = 1;
|
||||
} else {
|
||||
if (nal->type == H264_NAL_SPS) has_sps = 1;
|
||||
}
|
||||
|
|
@ -217,6 +226,7 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
|
|||
|
||||
if (extradata_size &&
|
||||
((ctx->par_in->codec_id == AV_CODEC_ID_VVC && has_sps) ||
|
||||
(ctx->par_in->codec_id == AV_CODEC_ID_LCEVC && has_sps) ||
|
||||
(ctx->par_in->codec_id == AV_CODEC_ID_HEVC && has_sps && has_vps) ||
|
||||
(ctx->par_in->codec_id == AV_CODEC_ID_H264 && has_sps))) {
|
||||
AVBufferRef *filtered_buf = NULL;
|
||||
|
|
@ -267,6 +277,174 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline uint64_t get_mb(GetBitContext *s) {
|
||||
int more, i = 0;
|
||||
uint64_t mb = 0;
|
||||
|
||||
do {
|
||||
int byte = get_bits(s, 8);
|
||||
unsigned bits = byte & 0x7f;
|
||||
more = byte & 0x80;
|
||||
mb = (mb << 7) | bits;
|
||||
if (++i == 10)
|
||||
break;
|
||||
} while (more);
|
||||
|
||||
return mb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrite the NALu stripping the unneeded blocks.
|
||||
* Given that length fields coded inside the NALu are not aware of any emulation_3bytes
|
||||
* present in the bitstream, we need to keep track of the raw buffer as we navigate
|
||||
* the stripped buffer.
|
||||
*/
|
||||
static int write_lcevc_nalu(AVBSFContext *ctx, PutByteContext *pbc, const H2645NAL *nal)
|
||||
{
|
||||
GetByteContext gbc, raw_gbc;
|
||||
int sc = 0, gc = 0;
|
||||
int skipped_byte_pos = 0;
|
||||
|
||||
bytestream2_init(&gbc, nal->data, nal->size);
|
||||
bytestream2_init(&raw_gbc, nal->raw_data, nal->raw_size);
|
||||
bytestream2_put_be16(pbc, bytestream2_get_be16(&gbc));
|
||||
bytestream2_skip(&raw_gbc, 2);
|
||||
|
||||
while (bytestream2_get_bytes_left(&gbc) > 1) {
|
||||
GetBitContext gb;
|
||||
int payload_size_type, payload_type, payload_size;
|
||||
int block_size, raw_block_size, block_end;
|
||||
|
||||
init_get_bits8(&gb, gbc.buffer, bytestream2_get_bytes_left(&gbc));
|
||||
|
||||
payload_size_type = get_bits(&gb, 3);
|
||||
payload_type = get_bits(&gb, 5);
|
||||
payload_size = payload_size_type;
|
||||
if (payload_size_type == 6)
|
||||
return AVERROR_PATCHWELCOME;
|
||||
if (payload_size_type == 7)
|
||||
payload_size = get_mb(&gb);
|
||||
|
||||
block_size = raw_block_size = payload_size + (get_bits_count(&gb) >> 3);
|
||||
if (block_size >= bytestream2_get_bytes_left(&gbc))
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
block_end = bytestream2_tell(&gbc) + block_size;
|
||||
// Take into account removed emulation 3bytes, as payload_size in
|
||||
// the bitstream is not aware of them.
|
||||
for (; skipped_byte_pos < nal->skipped_bytes; skipped_byte_pos++) {
|
||||
if (nal->skipped_bytes_pos[skipped_byte_pos] >= block_end)
|
||||
break;
|
||||
raw_block_size++;
|
||||
}
|
||||
|
||||
switch (payload_type) {
|
||||
case 0:
|
||||
bytestream2_put_buffer(pbc, raw_gbc.buffer, raw_block_size);
|
||||
sc = 1;
|
||||
break;
|
||||
case 1:
|
||||
bytestream2_put_buffer(pbc, raw_gbc.buffer, raw_block_size);
|
||||
gc = 1;
|
||||
break;
|
||||
case 5:
|
||||
bytestream2_put_buffer(pbc, raw_gbc.buffer, raw_block_size);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
bytestream2_skip(&gbc, block_size);
|
||||
bytestream2_skip(&raw_gbc, raw_block_size);
|
||||
}
|
||||
|
||||
if (!sc && !gc)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
bytestream2_put_byte(pbc, 0x80); // rbsp_alignment bits
|
||||
|
||||
return bytestream2_tell_p(pbc);
|
||||
}
|
||||
|
||||
static int extract_extradata_lcevc(AVBSFContext *ctx, AVPacket *pkt,
|
||||
uint8_t **data, int *size)
|
||||
{
|
||||
static const int extradata_nal_types[] = {
|
||||
LCEVC_IDR_NUT, LCEVC_NON_IDR_NUT,
|
||||
};
|
||||
|
||||
ExtractExtradataContext *s = ctx->priv_data;
|
||||
PutByteContext pb_extradata;
|
||||
int extradata_size = 0, filtered_size = 0;
|
||||
size_t nb_extradata_nal_types = FF_ARRAY_ELEMS(extradata_nal_types);
|
||||
int i, ret = 0;
|
||||
|
||||
ret = ff_h2645_packet_split(&s->h2645_pkt, pkt->data, pkt->size,
|
||||
ctx, 0, ctx->par_in->codec_id, H2645_FLAG_SMALL_PADDING);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < s->h2645_pkt.nb_nals; i++) {
|
||||
H2645NAL *nal = &s->h2645_pkt.nals[i];
|
||||
if (val_in_array(extradata_nal_types, nb_extradata_nal_types, nal->type)) {
|
||||
bytestream2_init_writer(&pb_extradata, NULL, 0);
|
||||
// dummy pass to find sc, gc or ai
|
||||
if (!write_lcevc_nalu(ctx, &pb_extradata, nal))
|
||||
extradata_size += nal->raw_size + 3;
|
||||
} else if (s->remove) {
|
||||
filtered_size += nal->raw_size + 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (extradata_size) {
|
||||
AVBufferRef *filtered_buf = NULL;
|
||||
PutByteContext pb_filtered_data;
|
||||
uint8_t *extradata;
|
||||
|
||||
if (s->remove) {
|
||||
filtered_buf = av_buffer_alloc(filtered_size + AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
if (!filtered_buf) {
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
memset(filtered_buf->data + filtered_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
}
|
||||
|
||||
extradata = av_malloc(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
if (!extradata) {
|
||||
av_buffer_unref(&filtered_buf);
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
*data = extradata;
|
||||
*size = extradata_size;
|
||||
|
||||
bytestream2_init_writer(&pb_extradata, extradata, extradata_size);
|
||||
if (s->remove)
|
||||
bytestream2_init_writer(&pb_filtered_data, filtered_buf->data, filtered_size);
|
||||
|
||||
for (i = 0; i < s->h2645_pkt.nb_nals; i++) {
|
||||
H2645NAL *nal = &s->h2645_pkt.nals[i];
|
||||
if (val_in_array(extradata_nal_types, nb_extradata_nal_types,
|
||||
nal->type)) {
|
||||
bytestream2_put_be24(&pb_extradata, 1); //startcode
|
||||
*size = write_lcevc_nalu(ctx, &pb_extradata, nal);
|
||||
} else if (s->remove) {
|
||||
bytestream2_put_be24(&pb_filtered_data, 1); //startcode
|
||||
*size = write_lcevc_nalu(ctx, &pb_filtered_data, nal);
|
||||
}
|
||||
}
|
||||
|
||||
if (s->remove) {
|
||||
av_buffer_unref(&pkt->buf);
|
||||
pkt->buf = filtered_buf;
|
||||
pkt->data = filtered_buf->data;
|
||||
pkt->size = filtered_size;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int extract_extradata_vc1(AVBSFContext *ctx, AVPacket *pkt,
|
||||
uint8_t **data, int *size)
|
||||
{
|
||||
|
|
@ -371,6 +549,7 @@ static const struct {
|
|||
{ AV_CODEC_ID_CAVS, extract_extradata_mpeg4 },
|
||||
{ AV_CODEC_ID_H264, extract_extradata_h2645 },
|
||||
{ AV_CODEC_ID_HEVC, extract_extradata_h2645 },
|
||||
{ AV_CODEC_ID_LCEVC, extract_extradata_lcevc },
|
||||
{ AV_CODEC_ID_MPEG1VIDEO, extract_extradata_mpeg12 },
|
||||
{ AV_CODEC_ID_MPEG2VIDEO, extract_extradata_mpeg12 },
|
||||
{ AV_CODEC_ID_MPEG4, extract_extradata_mpeg4 },
|
||||
|
|
@ -441,6 +620,7 @@ static const enum AVCodecID codec_ids[] = {
|
|||
AV_CODEC_ID_CAVS,
|
||||
AV_CODEC_ID_H264,
|
||||
AV_CODEC_ID_HEVC,
|
||||
AV_CODEC_ID_LCEVC,
|
||||
AV_CODEC_ID_MPEG1VIDEO,
|
||||
AV_CODEC_ID_MPEG2VIDEO,
|
||||
AV_CODEC_ID_MPEG4,
|
||||
|
|
|
|||
84
libavcodec/lcevc.h
Normal file
84
libavcodec/lcevc.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* LCEVC common definitions
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_LCEVC_H
|
||||
#define AVCODEC_LCEVC_H
|
||||
|
||||
/*
|
||||
* Table 17 — NAL unit type codes and NAL unit type classes in
|
||||
* ISO/IEC 23094-2:2021
|
||||
*/
|
||||
enum {
|
||||
LCEVC_UNSPEC0_NUT = 0,
|
||||
LCEVC_UNSPEC1_NUT = 1,
|
||||
LCEVC_UNSPEC2_NUT = 2,
|
||||
LCEVC_UNSPEC3_NUT = 3,
|
||||
LCEVC_UNSPEC4_NUT = 4,
|
||||
LCEVC_UNSPEC5_NUT = 5,
|
||||
LCEVC_UNSPEC6_NUT = 6,
|
||||
LCEVC_UNSPEC7_NUT = 7,
|
||||
LCEVC_UNSPEC8_NUT = 8,
|
||||
LCEVC_UNSPEC9_NUT = 9,
|
||||
LCEVC_UNSPEC10_NUT = 10,
|
||||
LCEVC_UNSPEC11_NUT = 11,
|
||||
LCEVC_UNSPEC12_NUT = 12,
|
||||
LCEVC_UNSPEC13_NUT = 13,
|
||||
LCEVC_UNSPEC14_NUT = 14,
|
||||
LCEVC_UNSPEC15_NUT = 15,
|
||||
LCEVC_UNSPEC16_NUT = 16,
|
||||
LCEVC_UNSPEC17_NUT = 17,
|
||||
LCEVC_UNSPEC18_NUT = 18,
|
||||
LCEVC_UNSPEC19_NUT = 19,
|
||||
LCEVC_UNSPEC20_NUT = 20,
|
||||
LCEVC_UNSPEC21_NUT = 21,
|
||||
LCEVC_UNSPEC22_NUT = 22,
|
||||
LCEVC_UNSPEC23_NUT = 23,
|
||||
LCEVC_UNSPEC24_NUT = 24,
|
||||
LCEVC_UNSPEC25_NUT = 25,
|
||||
LCEVC_UNSPEC26_NUT = 26,
|
||||
LCEVC_UNSPEC27_NUT = 27,
|
||||
LCEVC_NON_IDR_NUT = 28,
|
||||
LCEVC_IDR_NUT = 29,
|
||||
LCEVC_RSV_NUT = 30,
|
||||
LCEVC_UNSPEC31_NUT = 31,
|
||||
};
|
||||
|
||||
/*
|
||||
* Table 19 — Content of payload
|
||||
*/
|
||||
enum {
|
||||
LCEVC_PAYLOAD_TYPE_SEQUENCE_CONFIG = 0,
|
||||
LCEVC_PAYLOAD_TYPE_GLOBAL_CONFIG = 1,
|
||||
LCEVC_PAYLOAD_TYPE_PICTURE_CONFIG = 2,
|
||||
LCEVC_PAYLOAD_TYPE_ENCODED_DATA = 3,
|
||||
LCEVC_PAYLOAD_TYPE_ENCODED_DATA_TILED = 4,
|
||||
LCEVC_PAYLOAD_TYPE_ADDITIONAL_INFO = 5,
|
||||
LCEVC_PAYLOAD_TYPE_FILLER = 6,
|
||||
};
|
||||
|
||||
enum {
|
||||
LCEVC_ADDITIONAL_INFO_TYPE_SEI = 0,
|
||||
LCEVC_ADDITIONAL_INFO_TYPE_VUI = 1,
|
||||
};
|
||||
|
||||
#endif /* AVCODEC_LCEVC_H */
|
||||
Loading…
Add table
Add a link
Reference in a new issue