avcodec/decode: Avoid stack packets when decoding subtitles
Use AVCodecInternal.buffer_pkt (previously only used in avcodec_send_packet) instead of stack packets when decoding subtitles. Also stop sharing side-data between packets and use the user-supplied packet directly for decoding when possible (no subtitle decoder ever modifies the packet it is given). Reusing AVCodecInternal.buffer_pkt is based upon an idea from James Almer. Reviewed-by: James Almer <jamrial@gmail.com> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
This commit is contained in:
parent
f0dc8faeb1
commit
e12923f683
|
@ -869,19 +869,20 @@ static void get_subtitle_defaults(AVSubtitle *sub)
|
|||
}
|
||||
|
||||
#define UTF8_MAX_BYTES 4 /* 5 and 6 bytes sequences should not be used */
|
||||
static int recode_subtitle(AVCodecContext *avctx,
|
||||
AVPacket *outpkt, const AVPacket *inpkt)
|
||||
static int recode_subtitle(AVCodecContext *avctx, AVPacket **outpkt,
|
||||
AVPacket *inpkt, AVPacket *buf_pkt)
|
||||
{
|
||||
#if CONFIG_ICONV
|
||||
iconv_t cd = (iconv_t)-1;
|
||||
int ret = 0;
|
||||
char *inb, *outb;
|
||||
size_t inl, outl;
|
||||
AVPacket tmp;
|
||||
#endif
|
||||
|
||||
if (avctx->sub_charenc_mode != FF_SUB_CHARENC_MODE_PRE_DECODER || inpkt->size == 0)
|
||||
if (avctx->sub_charenc_mode != FF_SUB_CHARENC_MODE_PRE_DECODER || inpkt->size == 0) {
|
||||
*outpkt = inpkt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_ICONV
|
||||
inb = inpkt->data;
|
||||
|
@ -895,28 +896,31 @@ static int recode_subtitle(AVCodecContext *avctx,
|
|||
cd = iconv_open("UTF-8", avctx->sub_charenc);
|
||||
av_assert0(cd != (iconv_t)-1);
|
||||
|
||||
ret = av_new_packet(&tmp, inl * UTF8_MAX_BYTES);
|
||||
ret = av_new_packet(buf_pkt, inl * UTF8_MAX_BYTES);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
outpkt->buf = tmp.buf;
|
||||
outpkt->data = tmp.data;
|
||||
outpkt->size = tmp.size;
|
||||
outb = outpkt->data;
|
||||
outl = outpkt->size;
|
||||
ret = av_packet_copy_props(buf_pkt, inpkt);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
outb = buf_pkt->data;
|
||||
outl = buf_pkt->size;
|
||||
|
||||
if (iconv(cd, &inb, &inl, &outb, &outl) == (size_t)-1 ||
|
||||
iconv(cd, NULL, NULL, &outb, &outl) == (size_t)-1 ||
|
||||
outl >= outpkt->size || inl != 0) {
|
||||
outl >= buf_pkt->size || inl != 0) {
|
||||
ret = FFMIN(AVERROR(errno), -1);
|
||||
av_log(avctx, AV_LOG_ERROR, "Unable to recode subtitle event \"%s\" "
|
||||
"from %s to UTF-8\n", inpkt->data, avctx->sub_charenc);
|
||||
av_packet_unref(&tmp);
|
||||
goto end;
|
||||
}
|
||||
outpkt->size -= outl;
|
||||
memset(outpkt->data + outpkt->size, 0, outl);
|
||||
buf_pkt->size -= outl;
|
||||
memset(buf_pkt->data + buf_pkt->size, 0, outl);
|
||||
*outpkt = buf_pkt;
|
||||
|
||||
ret = 0;
|
||||
end:
|
||||
if (ret < 0)
|
||||
av_packet_unref(buf_pkt);
|
||||
if (cd != (iconv_t)-1)
|
||||
iconv_close(cd);
|
||||
return ret;
|
||||
|
@ -1039,20 +1043,21 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
|
|||
get_subtitle_defaults(sub);
|
||||
|
||||
if ((avctx->codec->capabilities & AV_CODEC_CAP_DELAY) || avpkt->size) {
|
||||
AVPacket pkt_recoded = *avpkt;
|
||||
AVCodecInternal *avci = avctx->internal;
|
||||
AVPacket *pkt;
|
||||
|
||||
ret = recode_subtitle(avctx, &pkt_recoded, avpkt);
|
||||
ret = recode_subtitle(avctx, &pkt, avpkt, avci->buffer_pkt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = extract_packet_props(avctx->internal, &pkt_recoded);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = extract_packet_props(avctx->internal, pkt);
|
||||
if (ret < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (avctx->pkt_timebase.num && avpkt->pts != AV_NOPTS_VALUE)
|
||||
sub->pts = av_rescale_q(avpkt->pts,
|
||||
avctx->pkt_timebase, AV_TIME_BASE_Q);
|
||||
ret = avctx->codec->decode(avctx, sub, got_sub_ptr, &pkt_recoded);
|
||||
ret = avctx->codec->decode(avctx, sub, got_sub_ptr, pkt);
|
||||
av_assert1((ret >= 0) >= !!*got_sub_ptr &&
|
||||
!!*got_sub_ptr >= !!sub->num_rects);
|
||||
|
||||
|
@ -1091,16 +1096,12 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
|
|||
}
|
||||
}
|
||||
|
||||
if (avpkt->data != pkt_recoded.data) { // did we recode?
|
||||
/* prevent from destroying side data from original packet */
|
||||
pkt_recoded.side_data = NULL;
|
||||
pkt_recoded.side_data_elems = 0;
|
||||
|
||||
av_packet_unref(&pkt_recoded);
|
||||
}
|
||||
|
||||
if (*got_sub_ptr)
|
||||
avctx->frame_number++;
|
||||
|
||||
cleanup:
|
||||
if (pkt == avci->buffer_pkt) // did we recode?
|
||||
av_packet_unref(avci->buffer_pkt);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
Loading…
Reference in New Issue
Block a user