ffmpeg | branch: master | Jorge Ramirez-Ortiz <jorge.ramirez-or...@linaro.org> | Tue Jan 9 23:56:42 2018 +0100| [5d5de3eba4c7890c2e8077f5b4ae569671d11cf8] | committer: Mark Thompson
avcodec: v4l2_m2m: remove unnecessary timeout. Qualcomm's db410c/db820 Venus driver currently present in mainline kernel has a bug which mishandles the CMD_STOP requests causing the decoder to block while draining [1]. This patch removes the workaround that was used to prevent that situation. Encoding/Decoding tested on db820c. [1] on CMD_STOP, the driver is flushing all buffers and never raising IPIPE which ends up in blocking on poll. > http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=5d5de3eba4c7890c2e8077f5b4ae569671d11cf8 --- libavcodec/v4l2_buffers.c | 10 ++++++-- libavcodec/v4l2_context.c | 61 ++++++++++++++++++++++++++++------------------- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c index 4e68f901b3..8e4d4d1c9f 100644 --- a/libavcodec/v4l2_buffers.c +++ b/libavcodec/v4l2_buffers.c @@ -213,8 +213,14 @@ static void v4l2_free_buffer(void *opaque, uint8_t *unused) if (s->reinit) { if (!atomic_load(&s->refcount)) sem_post(&s->refsync); - } else if (avbuf->context->streamon) - ff_v4l2_buffer_enqueue(avbuf); + } else { + if (s->draining) { + /* no need to queue more buffers to the driver */ + avbuf->status = V4L2BUF_AVAILABLE; + } + else if (avbuf->context->streamon) + ff_v4l2_buffer_enqueue(avbuf); + } av_buffer_unref(&avbuf->context_ref); } diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c index 4c169928fa..dde97d0d1f 100644 --- a/libavcodec/v4l2_context.c +++ b/libavcodec/v4l2_context.c @@ -217,6 +217,7 @@ static int v4l2_stop_decode(V4L2Context *ctx) { struct v4l2_decoder_cmd cmd = { .cmd = V4L2_DEC_CMD_STOP, + .flags = 0, }; int ret; @@ -234,6 +235,7 @@ static int v4l2_stop_encode(V4L2Context *ctx) { struct v4l2_encoder_cmd cmd = { .cmd = V4L2_ENC_CMD_STOP, + .flags = 0, }; int ret; @@ -256,10 +258,26 @@ static V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout) .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM, /* default blocking capture */ .fd = ctx_to_m2mctx(ctx)->fd, }; - int ret; + int i, ret; + + /* if we are draining and there are no more capture buffers queued in the driver we are done */ + if (!V4L2_TYPE_IS_OUTPUT(ctx->type) && ctx_to_m2mctx(ctx)->draining) { + for (i = 0; i < ctx->num_buffers; i++) { + if (ctx->buffers[i].status == V4L2BUF_IN_DRIVER) + goto start; + } + ctx->done = 1; + return NULL; + } +start: if (V4L2_TYPE_IS_OUTPUT(ctx->type)) pfd.events = POLLOUT | POLLWRNORM; + else { + /* no need to listen to requests for more input while draining */ + if (ctx_to_m2mctx(ctx)->draining) + pfd.events = POLLIN | POLLRDNORM | POLLPRI; + } for (;;) { ret = poll(&pfd, 1, timeout); @@ -267,11 +285,6 @@ static V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout) break; if (errno == EINTR) continue; - - /* timeout is being used to indicate last valid bufer when draining */ - if (ctx_to_m2mctx(ctx)->draining) - ctx->done = 1; - return NULL; } @@ -286,7 +299,7 @@ static V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout) ret = v4l2_handle_event(ctx); if (ret < 0) { /* if re-init failed, abort */ - ctx->done = EINVAL; + ctx->done = 1; return NULL; } if (ret) { @@ -325,23 +338,25 @@ dequeue: ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_DQBUF, &buf); if (ret) { if (errno != EAGAIN) { - ctx->done = errno; + ctx->done = 1; if (errno != EPIPE) av_log(logger(ctx), AV_LOG_DEBUG, "%s VIDIOC_DQBUF, errno (%s)\n", ctx->name, av_err2str(AVERROR(errno))); } - } else { - avbuf = &ctx->buffers[buf.index]; - avbuf->status = V4L2BUF_AVAILABLE; - avbuf->buf = buf; - if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { - memcpy(avbuf->planes, planes, sizeof(planes)); - avbuf->buf.m.planes = avbuf->planes; - } + return NULL; } + + avbuf = &ctx->buffers[buf.index]; + avbuf->status = V4L2BUF_AVAILABLE; + avbuf->buf = buf; + if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { + memcpy(avbuf->planes, planes, sizeof(planes)); + avbuf->buf.m.planes = avbuf->planes; + } + return avbuf; } - return avbuf; + return NULL; } static V4L2Buffer* v4l2_getfree_v4l2buf(V4L2Context *ctx) @@ -552,14 +567,12 @@ int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* frame) { V4L2Buffer* avbuf = NULL; - /* if we are draining, we are no longer inputing data, therefore enable a - * timeout so we can dequeue and flag the last valid buffer. - * + /* * blocks until: * 1. decoded frame available * 2. an input buffer is ready to be dequeued */ - avbuf = v4l2_dequeue_v4l2buf(ctx, ctx_to_m2mctx(ctx)->draining ? 200 : -1); + avbuf = v4l2_dequeue_v4l2buf(ctx, -1); if (!avbuf) { if (ctx->done) return AVERROR_EOF; @@ -574,14 +587,12 @@ int ff_v4l2_context_dequeue_packet(V4L2Context* ctx, AVPacket* pkt) { V4L2Buffer* avbuf = NULL; - /* if we are draining, we are no longer inputing data, therefore enable a - * timeout so we can dequeue and flag the last valid buffer. - * + /* * blocks until: * 1. encoded packet available * 2. an input buffer ready to be dequeued */ - avbuf = v4l2_dequeue_v4l2buf(ctx, ctx_to_m2mctx(ctx)->draining ? 200 : -1); + avbuf = v4l2_dequeue_v4l2buf(ctx, -1); if (!avbuf) { if (ctx->done) return AVERROR_EOF; _______________________________________________ ffmpeg-cvslog mailing list ffmpeg-cvslog@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-cvslog