From patchwork Wed Sep 27 17:27:44 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jorge Ramirez-Ortiz X-Patchwork-Id: 5312 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.36.26 with SMTP id f26csp5283268jaa; Wed, 27 Sep 2017 10:27:57 -0700 (PDT) X-Received: by 10.28.10.142 with SMTP id 136mr870306wmk.92.1506533277145; Wed, 27 Sep 2017 10:27:57 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506533277; cv=none; d=google.com; s=arc-20160816; b=ydSrzyW7BwJqqxCID2tyYsBFGySFDlw1bn9Zm3zD6nYSqvXX5Oa48l9seizX6yhOtt EG+UH+aYBqHCjpYlbWZiLgc+P8rRiPeYt/ipq0R8KiMS/Exd5Z+xwahiM+T1jVNWGRzq qS119P6oi3vSwUgF+3dLCro4/i/ZiVHZ1Yx7t+62s5qE+2hIoE0cuIjLk4CTEPbQ7Szk 8VBdKKe2CPX6OaKaMfonsKzgUVjtRTPwNYjscXcYkd6Rmhn422UqhUxy+3zTYgYIMUWt uBAB8pzYreuX35k0S41ZLO4HXz3SFrAFupjnzZEeoB3+eI03PLVyEIZWPYAq08y720Cf 1v/w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:message-id:date:to:from:dkim-signature :delivered-to:arc-authentication-results; bh=qGEUFeCRiDAnQnMEZbZVXgfbBAcVHhjJ4mOsoe5z9XM=; b=bgrz969SPIo7rmulH1KRLexjLDg6NGaQH0Fz6GhhZ1jzIdeVHhQUN2tGJZthgOliIC 2S7Z8BpW3pSOzwqOueOT+Q4dMRPJ1Cuwk6K1jBUtCIpyuVqi5ceKiprHBxc3a2gJreM1 s1TZ4LWzM1VrNiVldoW402oHaOnOqJrFW0J0DYZWyyxvasZEuzgwYamx8JE9IYnZMKAs 3EQa+I1BaAAXZz+Cajo/NJnJiUvgEb2Zc7BEQcJwBYtqtBwXjrb/yrPAoBJQD1WFUFTh zNhUSSWYTwXF51clPyYoc5Q1UQEDIcQeS3+ml1bcuEC1W3jmSzTOfxDU1gfJmWQUU1hp yqlQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=EhL1awGG; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id y52si9903158wry.87.2017.09.27.10.27.56; Wed, 27 Sep 2017 10:27:57 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=EhL1awGG; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 4421E6899ED; Wed, 27 Sep 2017 20:27:43 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pf0-f176.google.com (mail-pf0-f176.google.com [209.85.192.176]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 1AE5F68922E for ; Wed, 27 Sep 2017 20:27:37 +0300 (EEST) Received: by mail-pf0-f176.google.com with SMTP id l188so7584594pfc.6 for ; Wed, 27 Sep 2017 10:27:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:subject:date:message-id; bh=0Oj+XN6D+sDS+d6Ga29zJ01jrgli7Uv66OOWUsV2fkE=; b=EhL1awGGDDVrtVzO2ZLiWNYccpPqLkEitq0TIzCZKGBXQ/+GJ8SgS4Xw6SsjRjTpEq SgJwn4nQkvtOn68tMNEAZj4W2GsIOBaZuIr4ZaSfM4M9l4Z8ZNAH/ymgbQ428dlySAm5 Jz4x31Q9w+KPvHAsjyaOkshIunGtw4crKt7hE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id; bh=0Oj+XN6D+sDS+d6Ga29zJ01jrgli7Uv66OOWUsV2fkE=; b=E0J0AP9F9Ktkdt/FUhYboArlMlkmSlH2XBKhI7sv9v/zPJ4OfnzDHfqSlNthdy1PRu 857YDqN6ZHE42YBIH0f6hNhhNtgf6rVpcZLUnMhggwH7qpi76gKhdFPPsu4gM780ndtK 0MYyI8jXYxFy031AFUmoQumfdzcmQpwtczsZpa6gPrUJkVvLd013hYNSOQrW0aP9F5Ym 3DlijHP1kWgpc992AeTFjnc44KElpaE+pmN28uyFcPQsv8M49gHCbdrR5XX5nbSmEkvz ZusJCYpOjrBZDbBT7g+9xIyf0mInc16eDAGd+U0TRXvP/rrQ3BdqDHigZf87pwp1rxtJ 18fw== X-Gm-Message-State: AHPjjUhJILnJfpaK1/r0jNJzZi0wIpwzNHvIo8tbxbL1ZoaZHPuF/aPa NdHFbyXKQjYoF0jKifpt1c/1VA== X-Google-Smtp-Source: AOwi7QD81bAvsrc060jegaynYhxSq3qPxGHHwZ5d8exWsHiw7e53l4AhlB1sw26BfJiuOKqVubHApw== X-Received: by 10.84.143.129 with SMTP id 1mr1876580plz.304.1506533267785; Wed, 27 Sep 2017 10:27:47 -0700 (PDT) Received: from localhost.localdomain ([70.35.39.2]) by smtp.gmail.com with ESMTPSA id d190sm25676110pgc.11.2017.09.27.10.27.46 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 27 Sep 2017 10:27:47 -0700 (PDT) From: Jorge Ramirez-Ortiz To: jorge.ramirez-ortiz@linaro.org, nfxjfg@googlemail.com, ffmpeg-devel@ffmpeg.org Date: Wed, 27 Sep 2017 10:27:44 -0700 Message-Id: <1506533264-14079-1-git-send-email-jorge.ramirez-ortiz@linaro.org> X-Mailer: git-send-email 2.7.4 Subject: [FFmpeg-devel] [PATCHv2] avcodec/v4l2_m2m: fix draining process (dequeue without input) X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Stopping the codec when no more input is available causes captured buffers that might be ready to be invalidated. This commit follows the V4L2 API more closely: 1. when ffmpeg indicates EOS (NULL frame or packet size), the v4l2_m2m codec will send a dummy buffer to the driver with the V4L2_BUF_FLAG_LAST flag. 2. the v4l2_m2m codec will then continue dequeuing captured buffers until EPIPE is raised by the driver (v4l2 EOF condition) This makes the current timeout on dequeuing capture buffers while draining unnecessary. --- libavcodec/v4l2_buffers.c | 18 +++++++ libavcodec/v4l2_context.c | 132 ++++++++++++++-------------------------------- 2 files changed, 58 insertions(+), 92 deletions(-) diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c index ef7d040..26e7b12 100644 --- a/libavcodec/v4l2_buffers.c +++ b/libavcodec/v4l2_buffers.c @@ -255,6 +255,18 @@ static int v4l2_bufref_to_buf(V4L2Buffer *out, int plane, const uint8_t* data, i return 0; } +static int v4l2_buffer_set_eos(V4L2Buffer* avbuf) +{ + /* flag that we are draining to the v4l2_m2m context */ + buf_to_m2mctx(avbuf)->draining = 1; + + /* flag to the v4l2 driver - either of these two conditions (use both to be safe on old drivers) */ + avbuf->buf.m.planes[0].bytesused = 0; + avbuf->flags |= V4L2_BUF_FLAG_LAST; + + return 0; +} + /****************************************************************************** * * V4L2uffer interface @@ -265,6 +277,9 @@ int ff_v4l2_buffer_avframe_to_buf(const AVFrame *frame, V4L2Buffer* out) { int i, ret; + if (!frame) + return v4l2_buffer_set_eos(out); + for(i = 0; i < out->num_planes; i++) { ret = v4l2_bufref_to_buf(out, i, frame->buf[i]->data, frame->buf[i]->size, frame->buf[i]); if (ret) @@ -356,6 +371,9 @@ int ff_v4l2_buffer_avpkt_to_buf(const AVPacket *pkt, V4L2Buffer *out) { int ret; + if (!pkt->size) + return v4l2_buffer_set_eos(out); + ret = v4l2_bufref_to_buf(out, 0, pkt->data, pkt->size, pkt->buf); if (ret) return ret; diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c index d675c55..ef3d263 100644 --- a/libavcodec/v4l2_context.c +++ b/libavcodec/v4l2_context.c @@ -189,40 +189,6 @@ reinit_run: return 1; } -static int v4l2_stop_decode(V4L2Context *ctx) -{ - struct v4l2_decoder_cmd cmd = { - .cmd = V4L2_DEC_CMD_STOP, - }; - int ret; - - ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_DECODER_CMD, &cmd); - if (ret) { - /* DECODER_CMD is optional */ - if (errno == ENOTTY) - return ff_v4l2_context_set_status(ctx, VIDIOC_STREAMOFF); - } - - return 0; -} - -static int v4l2_stop_encode(V4L2Context *ctx) -{ - struct v4l2_encoder_cmd cmd = { - .cmd = V4L2_ENC_CMD_STOP, - }; - int ret; - - ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_ENCODER_CMD, &cmd); - if (ret) { - /* ENCODER_CMD is optional */ - if (errno == ENOTTY) - return ff_v4l2_context_set_status(ctx, VIDIOC_STREAMOFF); - } - - return 0; -} - static V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout) { struct v4l2_plane planes[VIDEO_MAX_PLANES]; @@ -236,6 +202,13 @@ static V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout) if (V4L2_TYPE_IS_OUTPUT(ctx->type)) pfd.events = POLLOUT | POLLWRNORM; + else { + /* on the capture queue */ + if (ctx_to_m2mctx(ctx)->draining) { + /* ignore driver requests for more input and just wait for a valid frame */ + pfd.events = POLLIN | POLLRDNORM | POLLPRI; + } + } for (;;) { ret = poll(&pfd, 1, timeout); @@ -243,50 +216,45 @@ 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; } - /* 0. handle errors */ + /* handle errors */ if (pfd.revents & POLLERR) { av_log(logger(ctx), AV_LOG_WARNING, "%s POLLERR\n", ctx->name); return NULL; } - /* 1. handle resolution changes */ + /* handle resolution changes */ if (pfd.revents & POLLPRI) { ret = v4l2_handle_event(ctx); if (ret < 0) { /* if re-init failed, abort */ - ctx->done = EINVAL; + ctx->done = 1; return NULL; } if (ret) { /* if re-init was successfull drop the buffer (if there was one) - * since we had to reconfigure capture (unmap all buffers) - */ + * since we had to reconfigure capture (unmap all buffers) */ return NULL; } } - /* 2. dequeue the buffer */ + /* dequeue the buffer or provide more input */ if (pfd.revents & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM)) { - if (!V4L2_TYPE_IS_OUTPUT(ctx->type)) { - /* there is a capture buffer ready */ - if (pfd.revents & (POLLIN | POLLRDNORM)) - goto dequeue; + if (V4L2_TYPE_IS_OUTPUT(ctx->type)) + goto dequeue; - /* the driver is ready to accept more input; instead of waiting for the capture - * buffer to complete we return NULL so input can proceed (we are single threaded) - */ - if (pfd.revents & (POLLOUT | POLLWRNORM)) - return NULL; - } + /* there is a capture buffer ready */ + if (pfd.revents & (POLLIN | POLLRDNORM)) + goto dequeue; + + /* the driver is ready to accept more input: instead of waiting for + * the capture buffer to complete, return NULL so input can proceed + * (we are single threaded after all) */ + if (pfd.revents & (POLLOUT | POLLWRNORM)) + return NULL; dequeue: memset(&buf, 0, sizeof(buf)); @@ -301,23 +269,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", + av_log(logger(ctx), AV_LOG_ERROR, "%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) @@ -476,18 +446,9 @@ int ff_v4l2_context_set_status(V4L2Context* ctx, int cmd) int ff_v4l2_context_enqueue_frame(V4L2Context* ctx, const AVFrame* frame) { - V4L2m2mContext *s = ctx_to_m2mctx(ctx); V4L2Buffer* avbuf; int ret; - if (!frame) { - ret = v4l2_stop_encode(ctx); - if (ret) - av_log(logger(ctx), AV_LOG_ERROR, "%s stop_encode\n", ctx->name); - s->draining= 1; - return 0; - } - avbuf = v4l2_getfree_v4l2buf(ctx); if (!avbuf) return AVERROR(ENOMEM); @@ -501,18 +462,9 @@ int ff_v4l2_context_enqueue_frame(V4L2Context* ctx, const AVFrame* frame) int ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt) { - V4L2m2mContext *s = ctx_to_m2mctx(ctx); V4L2Buffer* avbuf; int ret; - if (!pkt->size) { - ret = v4l2_stop_decode(ctx); - if (ret) - av_log(logger(ctx), AV_LOG_ERROR, "%s stop_decode\n", ctx->name); - s->draining = 1; - return 0; - } - avbuf = v4l2_getfree_v4l2buf(ctx); if (!avbuf) return AVERROR(ENOMEM); @@ -528,14 +480,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; @@ -550,14 +500,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;