mirror of https://git.ffmpeg.org/ffmpeg.git
h2645_parse: Allocate a single buffer per packet
Drastically reduces memory usage on pathological streams. Fixes ticket #6789
This commit is contained in:
parent
3357b68bc0
commit
03b82b3ab9
|
@ -31,11 +31,10 @@
|
||||||
#include "h2645_parse.h"
|
#include "h2645_parse.h"
|
||||||
|
|
||||||
int ff_h2645_extract_rbsp(const uint8_t *src, int length,
|
int ff_h2645_extract_rbsp(const uint8_t *src, int length,
|
||||||
H2645NAL *nal, int small_padding)
|
H2645RBSP *rbsp, H2645NAL *nal, int small_padding)
|
||||||
{
|
{
|
||||||
int i, si, di;
|
int i, si, di;
|
||||||
uint8_t *dst;
|
uint8_t *dst;
|
||||||
int64_t padding = small_padding ? 0 : MAX_MBPAIR_SIZE;
|
|
||||||
|
|
||||||
nal->skipped_bytes = 0;
|
nal->skipped_bytes = 0;
|
||||||
#define STARTCODE_TEST \
|
#define STARTCODE_TEST \
|
||||||
|
@ -92,11 +91,7 @@ int ff_h2645_extract_rbsp(const uint8_t *src, int length,
|
||||||
} else if (i > length)
|
} else if (i > length)
|
||||||
i = length;
|
i = length;
|
||||||
|
|
||||||
av_fast_padded_malloc(&nal->rbsp_buffer, &nal->rbsp_buffer_size,
|
nal->rbsp_buffer = &rbsp->rbsp_buffer[rbsp->rbsp_buffer_size];
|
||||||
length + padding);
|
|
||||||
if (!nal->rbsp_buffer)
|
|
||||||
return AVERROR(ENOMEM);
|
|
||||||
|
|
||||||
dst = nal->rbsp_buffer;
|
dst = nal->rbsp_buffer;
|
||||||
|
|
||||||
memcpy(dst, src, i);
|
memcpy(dst, src, i);
|
||||||
|
@ -145,6 +140,8 @@ nsc:
|
||||||
nal->size = di;
|
nal->size = di;
|
||||||
nal->raw_data = src;
|
nal->raw_data = src;
|
||||||
nal->raw_size = si;
|
nal->raw_size = si;
|
||||||
|
rbsp->rbsp_buffer_size += si;
|
||||||
|
|
||||||
return si;
|
return si;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,9 +267,14 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length,
|
||||||
GetByteContext bc;
|
GetByteContext bc;
|
||||||
int consumed, ret = 0;
|
int consumed, ret = 0;
|
||||||
int next_avc = is_nalff ? 0 : length;
|
int next_avc = is_nalff ? 0 : length;
|
||||||
|
int64_t padding = small_padding ? 0 : MAX_MBPAIR_SIZE;
|
||||||
|
|
||||||
bytestream2_init(&bc, buf, length);
|
bytestream2_init(&bc, buf, length);
|
||||||
|
av_fast_padded_malloc(&pkt->rbsp.rbsp_buffer, &pkt->rbsp.rbsp_buffer_alloc_size, length + padding);
|
||||||
|
if (!pkt->rbsp.rbsp_buffer)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
pkt->rbsp.rbsp_buffer_size = 0;
|
||||||
pkt->nb_nals = 0;
|
pkt->nb_nals = 0;
|
||||||
while (bytestream2_get_bytes_left(&bc) >= 4) {
|
while (bytestream2_get_bytes_left(&bc) >= 4) {
|
||||||
H2645NAL *nal;
|
H2645NAL *nal;
|
||||||
|
@ -341,7 +343,7 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length,
|
||||||
}
|
}
|
||||||
nal = &pkt->nals[pkt->nb_nals];
|
nal = &pkt->nals[pkt->nb_nals];
|
||||||
|
|
||||||
consumed = ff_h2645_extract_rbsp(bc.buffer, extract_length, nal, small_padding);
|
consumed = ff_h2645_extract_rbsp(bc.buffer, extract_length, &pkt->rbsp, nal, small_padding);
|
||||||
if (consumed < 0)
|
if (consumed < 0)
|
||||||
return consumed;
|
return consumed;
|
||||||
|
|
||||||
|
@ -385,9 +387,10 @@ void ff_h2645_packet_uninit(H2645Packet *pkt)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < pkt->nals_allocated; i++) {
|
for (i = 0; i < pkt->nals_allocated; i++) {
|
||||||
av_freep(&pkt->nals[i].rbsp_buffer);
|
|
||||||
av_freep(&pkt->nals[i].skipped_bytes_pos);
|
av_freep(&pkt->nals[i].skipped_bytes_pos);
|
||||||
}
|
}
|
||||||
av_freep(&pkt->nals);
|
av_freep(&pkt->nals);
|
||||||
pkt->nals_allocated = 0;
|
pkt->nals_allocated = 0;
|
||||||
|
av_freep(&pkt->rbsp.rbsp_buffer);
|
||||||
|
pkt->rbsp.rbsp_buffer_alloc_size = pkt->rbsp.rbsp_buffer_size = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
|
|
||||||
typedef struct H2645NAL {
|
typedef struct H2645NAL {
|
||||||
uint8_t *rbsp_buffer;
|
uint8_t *rbsp_buffer;
|
||||||
int rbsp_buffer_size;
|
|
||||||
|
|
||||||
int size;
|
int size;
|
||||||
const uint8_t *data;
|
const uint8_t *data;
|
||||||
|
@ -65,9 +64,16 @@ typedef struct H2645NAL {
|
||||||
int ref_idc;
|
int ref_idc;
|
||||||
} H2645NAL;
|
} H2645NAL;
|
||||||
|
|
||||||
|
typedef struct H2645RBSP {
|
||||||
|
uint8_t *rbsp_buffer;
|
||||||
|
int rbsp_buffer_alloc_size;
|
||||||
|
int rbsp_buffer_size;
|
||||||
|
} H2645RBSP;
|
||||||
|
|
||||||
/* an input packet split into unescaped NAL units */
|
/* an input packet split into unescaped NAL units */
|
||||||
typedef struct H2645Packet {
|
typedef struct H2645Packet {
|
||||||
H2645NAL *nals;
|
H2645NAL *nals;
|
||||||
|
H2645RBSP rbsp;
|
||||||
int nb_nals;
|
int nb_nals;
|
||||||
int nals_allocated;
|
int nals_allocated;
|
||||||
} H2645Packet;
|
} H2645Packet;
|
||||||
|
@ -75,7 +81,7 @@ typedef struct H2645Packet {
|
||||||
/**
|
/**
|
||||||
* Extract the raw (unescaped) bitstream.
|
* Extract the raw (unescaped) bitstream.
|
||||||
*/
|
*/
|
||||||
int ff_h2645_extract_rbsp(const uint8_t *src, int length,
|
int ff_h2645_extract_rbsp(const uint8_t *src, int length, H2645RBSP *rbsp,
|
||||||
H2645NAL *nal, int small_padding);
|
H2645NAL *nal, int small_padding);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -243,6 +243,7 @@ static inline int parse_nal_units(AVCodecParserContext *s,
|
||||||
const uint8_t * const buf, int buf_size)
|
const uint8_t * const buf, int buf_size)
|
||||||
{
|
{
|
||||||
H264ParseContext *p = s->priv_data;
|
H264ParseContext *p = s->priv_data;
|
||||||
|
H2645RBSP rbsp = { NULL };
|
||||||
H2645NAL nal = { NULL };
|
H2645NAL nal = { NULL };
|
||||||
int buf_index, next_avc;
|
int buf_index, next_avc;
|
||||||
unsigned int pps_id;
|
unsigned int pps_id;
|
||||||
|
@ -263,6 +264,10 @@ static inline int parse_nal_units(AVCodecParserContext *s,
|
||||||
if (!buf_size)
|
if (!buf_size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
av_fast_padded_malloc(&rbsp.rbsp_buffer, &rbsp.rbsp_buffer_alloc_size, buf_size);
|
||||||
|
if (!rbsp.rbsp_buffer)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
buf_index = 0;
|
buf_index = 0;
|
||||||
next_avc = p->is_avc ? 0 : buf_size;
|
next_avc = p->is_avc ? 0 : buf_size;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -300,7 +305,7 @@ static inline int parse_nal_units(AVCodecParserContext *s,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
consumed = ff_h2645_extract_rbsp(buf + buf_index, src_length, &nal, 1);
|
consumed = ff_h2645_extract_rbsp(buf + buf_index, src_length, &rbsp, &nal, 1);
|
||||||
if (consumed < 0)
|
if (consumed < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -544,18 +549,18 @@ static inline int parse_nal_units(AVCodecParserContext *s,
|
||||||
p->last_frame_num = p->poc.frame_num;
|
p->last_frame_num = p->poc.frame_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
av_freep(&nal.rbsp_buffer);
|
av_freep(&rbsp.rbsp_buffer);
|
||||||
return 0; /* no need to evaluate the rest */
|
return 0; /* no need to evaluate the rest */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (q264) {
|
if (q264) {
|
||||||
av_freep(&nal.rbsp_buffer);
|
av_freep(&rbsp.rbsp_buffer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* didn't find a picture! */
|
/* didn't find a picture! */
|
||||||
av_log(avctx, AV_LOG_ERROR, "missing picture in access unit with size %d\n", buf_size);
|
av_log(avctx, AV_LOG_ERROR, "missing picture in access unit with size %d\n", buf_size);
|
||||||
fail:
|
fail:
|
||||||
av_freep(&nal.rbsp_buffer);
|
av_freep(&rbsp.rbsp_buffer);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx)
|
||||||
PutByteContext pbc;
|
PutByteContext pbc;
|
||||||
|
|
||||||
GetBitContext gb;
|
GetBitContext gb;
|
||||||
|
H2645RBSP sps_rbsp = { NULL };
|
||||||
H2645NAL sps_nal = { NULL };
|
H2645NAL sps_nal = { NULL };
|
||||||
HEVCSPS sps = { 0 };
|
HEVCSPS sps = { 0 };
|
||||||
HEVCVPS vps = { 0 };
|
HEVCVPS vps = { 0 };
|
||||||
|
@ -69,8 +70,12 @@ static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx)
|
||||||
return AVERROR_UNKNOWN;
|
return AVERROR_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
av_fast_padded_malloc(&sps_rbsp.rbsp_buffer, &sps_rbsp.rbsp_buffer_alloc_size, avctx->extradata_size);
|
||||||
|
if (!sps_rbsp.rbsp_buffer)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
/* parse the SPS */
|
/* parse the SPS */
|
||||||
ret = ff_h2645_extract_rbsp(avctx->extradata + 4, avctx->extradata_size - 4, &sps_nal, 1);
|
ret = ff_h2645_extract_rbsp(avctx->extradata + 4, avctx->extradata_size - 4, &sps_rbsp, &sps_nal, 1);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
av_log(avctx, AV_LOG_ERROR, "Error unescaping the SPS buffer\n");
|
av_log(avctx, AV_LOG_ERROR, "Error unescaping the SPS buffer\n");
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -78,7 +83,7 @@ static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx)
|
||||||
|
|
||||||
ret = init_get_bits8(&gb, sps_nal.data, sps_nal.size);
|
ret = init_get_bits8(&gb, sps_nal.data, sps_nal.size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
av_freep(&sps_nal.rbsp_buffer);
|
av_freep(&sps_rbsp.rbsp_buffer);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,13 +92,13 @@ static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx)
|
||||||
if (type != HEVC_NAL_SPS) {
|
if (type != HEVC_NAL_SPS) {
|
||||||
av_log(avctx, AV_LOG_ERROR, "Unexpected NAL type in the extradata: %d\n",
|
av_log(avctx, AV_LOG_ERROR, "Unexpected NAL type in the extradata: %d\n",
|
||||||
type);
|
type);
|
||||||
av_freep(&sps_nal.rbsp_buffer);
|
av_freep(&sps_rbsp.rbsp_buffer);
|
||||||
return AVERROR_INVALIDDATA;
|
return AVERROR_INVALIDDATA;
|
||||||
}
|
}
|
||||||
get_bits(&gb, 9);
|
get_bits(&gb, 9);
|
||||||
|
|
||||||
ret = ff_hevc_parse_sps(&sps, &gb, &sps_id, 0, NULL, avctx);
|
ret = ff_hevc_parse_sps(&sps, &gb, &sps_id, 0, NULL, avctx);
|
||||||
av_freep(&sps_nal.rbsp_buffer);
|
av_freep(&sps_rbsp.rbsp_buffer);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
av_log(avctx, AV_LOG_ERROR, "Error parsing the SPS\n");
|
av_log(avctx, AV_LOG_ERROR, "Error parsing the SPS\n");
|
||||||
return ret;
|
return ret;
|
||||||
|
|
Loading…
Reference in New Issue