mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
avcodec/v4l2_m2m_dec: remove redundant packet and fix double free
v4l2_receive_frame() uses two packets s->buf_pkt and avpkt. If avpkt cannot be enqueued, the packet is buffered in s->buf_pkt and enqueued in the next call. Currently the ownership transfer between the two packets is not properly handled. A double free occurs if ff_v4l2_context_enqueue_packet() returns EAGAIN and v4l2_try_start returns EINVAL. In fact, having two AVPackets is not needed and everything can be handled by s->buf_pkt. This commit removes the local avpkt from v4l2_receive_frame(), meaning that the ownership transfer doesn't need to be handled and the double free is fixed. Signed-off-by: Andriy Gelman <andriy.gelman@gmail.com>
This commit is contained in:
parent
660386813d
commit
a9fecb8ea1
@ -138,14 +138,10 @@ static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame)
|
||||
V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context;
|
||||
V4L2Context *const capture = &s->capture;
|
||||
V4L2Context *const output = &s->output;
|
||||
AVPacket avpkt = {0};
|
||||
int ret;
|
||||
|
||||
if (s->buf_pkt.size) {
|
||||
avpkt = s->buf_pkt;
|
||||
memset(&s->buf_pkt, 0, sizeof(AVPacket));
|
||||
} else {
|
||||
ret = ff_decode_get_packet(avctx, &avpkt);
|
||||
if (!s->buf_pkt.size) {
|
||||
ret = ff_decode_get_packet(avctx, &s->buf_pkt);
|
||||
if (ret < 0 && ret != AVERROR_EOF)
|
||||
return ret;
|
||||
}
|
||||
@ -153,32 +149,29 @@ static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame)
|
||||
if (s->draining)
|
||||
goto dequeue;
|
||||
|
||||
ret = ff_v4l2_context_enqueue_packet(output, &avpkt);
|
||||
if (ret < 0) {
|
||||
if (ret != AVERROR(EAGAIN))
|
||||
return ret;
|
||||
ret = ff_v4l2_context_enqueue_packet(output, &s->buf_pkt);
|
||||
if (ret < 0 && ret != AVERROR(EAGAIN))
|
||||
goto fail;
|
||||
|
||||
s->buf_pkt = avpkt;
|
||||
/* no input buffers available, continue dequeing */
|
||||
}
|
||||
/* if EAGAIN don't unref packet and try to enqueue in the next iteration */
|
||||
if (ret != AVERROR(EAGAIN))
|
||||
av_packet_unref(&s->buf_pkt);
|
||||
|
||||
if (avpkt.size) {
|
||||
if (!s->draining) {
|
||||
ret = v4l2_try_start(avctx);
|
||||
if (ret) {
|
||||
av_packet_unref(&avpkt);
|
||||
|
||||
/* cant recover */
|
||||
if (ret == AVERROR(ENOMEM))
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
if (ret != AVERROR(ENOMEM))
|
||||
ret = 0;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
dequeue:
|
||||
if (!s->buf_pkt.size)
|
||||
av_packet_unref(&avpkt);
|
||||
return ff_v4l2_context_dequeue_frame(capture, frame, -1);
|
||||
fail:
|
||||
av_packet_unref(&s->buf_pkt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static av_cold int v4l2_decode_init(AVCodecContext *avctx)
|
||||
|
Loading…
Reference in New Issue
Block a user