LCOV - code coverage report
Current view: top level - libavcodec - v4l2_context.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 340 0.0 %
Date: 2017-12-12 11:08:38 Functions: 0 26 0.0 %

          Line data    Source code
       1             : /*
       2             :  * V4L2 context helper functions.
       3             :  *
       4             :  * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
       5             :  * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
       6             :  *
       7             :  * This file is part of FFmpeg.
       8             :  *
       9             :  * FFmpeg is free software; you can redistribute it and/or
      10             :  * modify it under the terms of the GNU Lesser General Public
      11             :  * License as published by the Free Software Foundation; either
      12             :  * version 2.1 of the License, or (at your option) any later version.
      13             :  *
      14             :  * FFmpeg is distributed in the hope that it will be useful,
      15             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17             :  * Lesser General Public License for more details.
      18             :  *
      19             :  * You should have received a copy of the GNU Lesser General Public
      20             :  * License along with FFmpeg; if not, write to the Free Software
      21             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      22             :  */
      23             : 
      24             : #include <linux/videodev2.h>
      25             : #include <sys/ioctl.h>
      26             : #include <sys/mman.h>
      27             : #include <unistd.h>
      28             : #include <fcntl.h>
      29             : #include <poll.h>
      30             : #include "libavcodec/avcodec.h"
      31             : #include "libavcodec/internal.h"
      32             : #include "v4l2_buffers.h"
      33             : #include "v4l2_fmt.h"
      34             : #include "v4l2_m2m.h"
      35             : 
      36             : struct v4l2_format_update {
      37             :     uint32_t v4l2_fmt;
      38             :     int update_v4l2;
      39             : 
      40             :     enum AVPixelFormat av_fmt;
      41             :     int update_avfmt;
      42             : };
      43             : 
      44           0 : static inline V4L2m2mContext *ctx_to_m2mctx(V4L2Context *ctx)
      45             : {
      46           0 :     return V4L2_TYPE_IS_OUTPUT(ctx->type) ?
      47           0 :         container_of(ctx, V4L2m2mContext, output) :
      48           0 :         container_of(ctx, V4L2m2mContext, capture);
      49             : }
      50             : 
      51           0 : static inline AVCodecContext *logger(V4L2Context *ctx)
      52             : {
      53           0 :     return ctx_to_m2mctx(ctx)->avctx;
      54             : }
      55             : 
      56           0 : static inline unsigned int v4l2_get_width(struct v4l2_format *fmt)
      57             : {
      58           0 :     return V4L2_TYPE_IS_MULTIPLANAR(fmt->type) ? fmt->fmt.pix_mp.width : fmt->fmt.pix.width;
      59             : }
      60             : 
      61           0 : static inline unsigned int v4l2_get_height(struct v4l2_format *fmt)
      62             : {
      63           0 :     return V4L2_TYPE_IS_MULTIPLANAR(fmt->type) ? fmt->fmt.pix_mp.height : fmt->fmt.pix.height;
      64             : }
      65             : 
      66           0 : static inline unsigned int v4l2_resolution_changed(V4L2Context *ctx, struct v4l2_format *fmt2)
      67             : {
      68           0 :     struct v4l2_format *fmt1 = &ctx->format;
      69           0 :     int ret =  V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ?
      70           0 :         fmt1->fmt.pix_mp.width != fmt2->fmt.pix_mp.width ||
      71           0 :         fmt1->fmt.pix_mp.height != fmt2->fmt.pix_mp.height
      72           0 :         :
      73           0 :         fmt1->fmt.pix.width != fmt2->fmt.pix.width ||
      74           0 :         fmt1->fmt.pix.height != fmt2->fmt.pix.height;
      75             : 
      76           0 :     if (ret)
      77           0 :         av_log(logger(ctx), AV_LOG_DEBUG, "%s changed (%dx%d) -> (%dx%d)\n",
      78             :             ctx->name,
      79             :             v4l2_get_width(fmt1), v4l2_get_height(fmt1),
      80             :             v4l2_get_width(fmt2), v4l2_get_height(fmt2));
      81             : 
      82           0 :     return ret;
      83             : }
      84             : 
      85           0 : static inline int v4l2_type_supported(V4L2Context *ctx)
      86             : {
      87           0 :     return ctx->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
      88           0 :         ctx->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ||
      89           0 :         ctx->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
      90           0 :         ctx->type == V4L2_BUF_TYPE_VIDEO_OUTPUT;
      91             : }
      92             : 
      93           0 : static inline int v4l2_get_framesize_compressed(V4L2Context* ctx, int width, int height)
      94             : {
      95           0 :     V4L2m2mContext *s = ctx_to_m2mctx(ctx);
      96           0 :     const int SZ_4K = 0x1000;
      97             :     int size;
      98             : 
      99           0 :     if (av_codec_is_decoder(s->avctx->codec))
     100           0 :         return ((width * height * 3 / 2) / 2) + 128;
     101             : 
     102             :     /* encoder */
     103           0 :     size = FFALIGN(height, 32) * FFALIGN(width, 32) * 3 / 2 / 2;
     104           0 :     return FFALIGN(size, SZ_4K);
     105             : }
     106             : 
     107           0 : static inline void v4l2_save_to_context(V4L2Context* ctx, struct v4l2_format_update *fmt)
     108             : {
     109           0 :     ctx->format.type = ctx->type;
     110             : 
     111           0 :     if (fmt->update_avfmt)
     112           0 :         ctx->av_pix_fmt = fmt->av_fmt;
     113             : 
     114           0 :     if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
     115             :         /* update the sizes to handle the reconfiguration of the capture stream at runtime */
     116           0 :         ctx->format.fmt.pix_mp.height = ctx->height;
     117           0 :         ctx->format.fmt.pix_mp.width = ctx->width;
     118           0 :         if (fmt->update_v4l2) {
     119           0 :             ctx->format.fmt.pix_mp.pixelformat = fmt->v4l2_fmt;
     120             : 
     121             :             /* s5p-mfc requires the user to specify a buffer size */
     122           0 :             ctx->format.fmt.pix_mp.plane_fmt[0].sizeimage =
     123           0 :                 v4l2_get_framesize_compressed(ctx, ctx->width, ctx->height);
     124             :         }
     125             :     } else {
     126           0 :         ctx->format.fmt.pix.height = ctx->height;
     127           0 :         ctx->format.fmt.pix.width = ctx->width;
     128           0 :         if (fmt->update_v4l2) {
     129           0 :             ctx->format.fmt.pix.pixelformat = fmt->v4l2_fmt;
     130             : 
     131             :             /* s5p-mfc requires the user to specify a buffer size */
     132           0 :             ctx->format.fmt.pix.sizeimage =
     133           0 :                 v4l2_get_framesize_compressed(ctx, ctx->width, ctx->height);
     134             :         }
     135             :     }
     136           0 : }
     137             : 
     138             : /**
     139             :  * returns 1 if reinit was successful, negative if it failed
     140             :  * returns 0 if reinit was not executed
     141             :  */
     142           0 : static int v4l2_handle_event(V4L2Context *ctx)
     143             : {
     144           0 :     V4L2m2mContext *s = ctx_to_m2mctx(ctx);
     145           0 :     struct v4l2_format cap_fmt = s->capture.format;
     146           0 :     struct v4l2_format out_fmt = s->output.format;
     147           0 :     struct v4l2_event evt = { 0 };
     148             :     int full_reinit, reinit, ret;
     149             : 
     150           0 :     ret = ioctl(s->fd, VIDIOC_DQEVENT, &evt);
     151           0 :     if (ret < 0) {
     152           0 :         av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_DQEVENT\n", ctx->name);
     153           0 :         return 0;
     154             :     }
     155             : 
     156           0 :     if (evt.type != V4L2_EVENT_SOURCE_CHANGE)
     157           0 :         return 0;
     158             : 
     159           0 :     ret = ioctl(s->fd, VIDIOC_G_FMT, &out_fmt);
     160           0 :     if (ret) {
     161           0 :         av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_G_FMT\n", s->output.name);
     162           0 :         return 0;
     163             :     }
     164             : 
     165           0 :     ret = ioctl(s->fd, VIDIOC_G_FMT, &cap_fmt);
     166           0 :     if (ret) {
     167           0 :         av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_G_FMT\n", s->capture.name);
     168           0 :         return 0;
     169             :     }
     170             : 
     171           0 :     full_reinit = v4l2_resolution_changed(&s->output, &out_fmt);
     172           0 :     if (full_reinit) {
     173           0 :         s->output.height = v4l2_get_height(&out_fmt);
     174           0 :         s->output.width = v4l2_get_width(&out_fmt);
     175             :     }
     176             : 
     177           0 :     reinit = v4l2_resolution_changed(&s->capture, &cap_fmt);
     178           0 :     if (reinit) {
     179           0 :         s->capture.height = v4l2_get_height(&cap_fmt);
     180           0 :         s->capture.width = v4l2_get_width(&cap_fmt);
     181             :     }
     182             : 
     183           0 :     if (full_reinit || reinit)
     184           0 :         s->reinit = 1;
     185             : 
     186           0 :     if (full_reinit) {
     187           0 :         ret = ff_v4l2_m2m_codec_full_reinit(s);
     188           0 :         if (ret) {
     189           0 :             av_log(logger(ctx), AV_LOG_ERROR, "v4l2_m2m_codec_full_reinit\n");
     190           0 :             return -EINVAL;
     191             :         }
     192           0 :         goto reinit_run;
     193             :     }
     194             : 
     195           0 :     if (reinit) {
     196           0 :         ret = ff_set_dimensions(s->avctx, s->capture.width, s->capture.height);
     197           0 :         if (ret < 0)
     198           0 :             av_log(logger(ctx), AV_LOG_WARNING, "update avcodec height and width\n");
     199             : 
     200           0 :         ret = ff_v4l2_m2m_codec_reinit(s);
     201           0 :         if (ret) {
     202           0 :             av_log(logger(ctx), AV_LOG_ERROR, "v4l2_m2m_codec_reinit\n");
     203           0 :             return -EINVAL;
     204             :         }
     205           0 :         goto reinit_run;
     206             :     }
     207             : 
     208             :     /* dummy event received */
     209           0 :     return 0;
     210             : 
     211             :     /* reinit executed */
     212           0 : reinit_run:
     213           0 :     return 1;
     214             : }
     215             : 
     216           0 : static int v4l2_stop_decode(V4L2Context *ctx)
     217             : {
     218           0 :     struct v4l2_decoder_cmd cmd = {
     219             :         .cmd = V4L2_DEC_CMD_STOP,
     220             :     };
     221             :     int ret;
     222             : 
     223           0 :     ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_DECODER_CMD, &cmd);
     224           0 :     if (ret) {
     225             :         /* DECODER_CMD is optional */
     226           0 :         if (errno == ENOTTY)
     227           0 :             return ff_v4l2_context_set_status(ctx, VIDIOC_STREAMOFF);
     228             :     }
     229             : 
     230           0 :     return 0;
     231             : }
     232             : 
     233           0 : static int v4l2_stop_encode(V4L2Context *ctx)
     234             : {
     235           0 :     struct v4l2_encoder_cmd cmd = {
     236             :         .cmd = V4L2_ENC_CMD_STOP,
     237             :     };
     238             :     int ret;
     239             : 
     240           0 :     ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_ENCODER_CMD, &cmd);
     241           0 :     if (ret) {
     242             :         /* ENCODER_CMD is optional */
     243           0 :         if (errno == ENOTTY)
     244           0 :             return ff_v4l2_context_set_status(ctx, VIDIOC_STREAMOFF);
     245             :     }
     246             : 
     247           0 :     return 0;
     248             : }
     249             : 
     250           0 : static V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout)
     251             : {
     252             :     struct v4l2_plane planes[VIDEO_MAX_PLANES];
     253           0 :     struct v4l2_buffer buf = { 0 };
     254           0 :     V4L2Buffer* avbuf = NULL;
     255           0 :     struct pollfd pfd = {
     256             :         .events =  POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM, /* default blocking capture */
     257           0 :         .fd = ctx_to_m2mctx(ctx)->fd,
     258             :     };
     259             :     int ret;
     260             : 
     261           0 :     if (V4L2_TYPE_IS_OUTPUT(ctx->type))
     262           0 :         pfd.events =  POLLOUT | POLLWRNORM;
     263             : 
     264             :     for (;;) {
     265           0 :         ret = poll(&pfd, 1, timeout);
     266           0 :         if (ret > 0)
     267           0 :             break;
     268           0 :         if (errno == EINTR)
     269           0 :             continue;
     270             : 
     271             :         /* timeout is being used to indicate last valid bufer when draining */
     272           0 :         if (ctx_to_m2mctx(ctx)->draining)
     273           0 :             ctx->done = 1;
     274             : 
     275           0 :         return NULL;
     276             :     }
     277             : 
     278             :     /* 0. handle errors */
     279           0 :     if (pfd.revents & POLLERR) {
     280           0 :         av_log(logger(ctx), AV_LOG_WARNING, "%s POLLERR\n", ctx->name);
     281           0 :         return NULL;
     282             :     }
     283             : 
     284             :     /* 1. handle resolution changes */
     285           0 :     if (pfd.revents & POLLPRI) {
     286           0 :         ret = v4l2_handle_event(ctx);
     287           0 :         if (ret < 0) {
     288             :             /* if re-init failed, abort */
     289           0 :             ctx->done = EINVAL;
     290           0 :             return NULL;
     291             :         }
     292           0 :         if (ret) {
     293             :             /* if re-init was successful drop the buffer (if there was one)
     294             :              * since we had to reconfigure capture (unmap all buffers)
     295             :              */
     296           0 :             return NULL;
     297             :         }
     298             :     }
     299             : 
     300             :     /* 2. dequeue the buffer */
     301           0 :     if (pfd.revents & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM)) {
     302             : 
     303           0 :         if (!V4L2_TYPE_IS_OUTPUT(ctx->type)) {
     304             :             /* there is a capture buffer ready */
     305           0 :             if (pfd.revents & (POLLIN | POLLRDNORM))
     306           0 :                 goto dequeue;
     307             : 
     308             :             /* the driver is ready to accept more input; instead of waiting for the capture
     309             :              * buffer to complete we return NULL so input can proceed (we are single threaded)
     310             :              */
     311           0 :             if (pfd.revents & (POLLOUT | POLLWRNORM))
     312           0 :                 return NULL;
     313             :         }
     314             : 
     315           0 : dequeue:
     316           0 :         memset(&buf, 0, sizeof(buf));
     317           0 :         buf.memory = V4L2_MEMORY_MMAP;
     318           0 :         buf.type = ctx->type;
     319           0 :         if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
     320           0 :             memset(planes, 0, sizeof(planes));
     321           0 :             buf.length = VIDEO_MAX_PLANES;
     322           0 :             buf.m.planes = planes;
     323             :         }
     324             : 
     325           0 :         ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_DQBUF, &buf);
     326           0 :         if (ret) {
     327           0 :             if (errno != EAGAIN) {
     328           0 :                 ctx->done = errno;
     329           0 :                 if (errno != EPIPE)
     330           0 :                     av_log(logger(ctx), AV_LOG_DEBUG, "%s VIDIOC_DQBUF, errno (%s)\n",
     331           0 :                         ctx->name, av_err2str(AVERROR(errno)));
     332             :             }
     333             :         } else {
     334           0 :             avbuf = &ctx->buffers[buf.index];
     335           0 :             avbuf->status = V4L2BUF_AVAILABLE;
     336           0 :             avbuf->buf = buf;
     337           0 :             if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
     338           0 :                 memcpy(avbuf->planes, planes, sizeof(planes));
     339           0 :                 avbuf->buf.m.planes = avbuf->planes;
     340             :             }
     341             :         }
     342             :     }
     343             : 
     344           0 :     return avbuf;
     345             : }
     346             : 
     347           0 : static V4L2Buffer* v4l2_getfree_v4l2buf(V4L2Context *ctx)
     348             : {
     349           0 :     int timeout = 0; /* return when no more buffers to dequeue */
     350             :     int i;
     351             : 
     352             :     /* get back as many output buffers as possible */
     353           0 :     if (V4L2_TYPE_IS_OUTPUT(ctx->type)) {
     354             :           do {
     355           0 :           } while (v4l2_dequeue_v4l2buf(ctx, timeout));
     356             :     }
     357             : 
     358           0 :     for (i = 0; i < ctx->num_buffers; i++) {
     359           0 :         if (ctx->buffers[i].status == V4L2BUF_AVAILABLE)
     360           0 :             return &ctx->buffers[i];
     361             :     }
     362             : 
     363           0 :     return NULL;
     364             : }
     365             : 
     366           0 : static int v4l2_release_buffers(V4L2Context* ctx)
     367             : {
     368           0 :     struct v4l2_requestbuffers req = {
     369             :         .memory = V4L2_MEMORY_MMAP,
     370           0 :         .type = ctx->type,
     371             :         .count = 0, /* 0 -> unmaps buffers from the driver */
     372             :     };
     373             :     int i, j;
     374             : 
     375           0 :     for (i = 0; i < ctx->num_buffers; i++) {
     376           0 :         V4L2Buffer *buffer = &ctx->buffers[i];
     377             : 
     378           0 :         for (j = 0; j < buffer->num_planes; j++) {
     379           0 :             struct V4L2Plane_info *p = &buffer->plane_info[j];
     380           0 :             if (p->mm_addr && p->length)
     381           0 :                 if (munmap(p->mm_addr, p->length) < 0)
     382           0 :                     av_log(logger(ctx), AV_LOG_ERROR, "%s unmap plane (%s))\n", ctx->name, av_err2str(AVERROR(errno)));
     383             :         }
     384             :     }
     385             : 
     386           0 :     return ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_REQBUFS, &req);
     387             : }
     388             : 
     389           0 : static inline int v4l2_try_raw_format(V4L2Context* ctx, enum AVPixelFormat pixfmt)
     390             : {
     391           0 :     struct v4l2_format *fmt = &ctx->format;
     392             :     uint32_t v4l2_fmt;
     393             :     int ret;
     394             : 
     395           0 :     v4l2_fmt = ff_v4l2_format_avfmt_to_v4l2(pixfmt);
     396           0 :     if (!v4l2_fmt)
     397           0 :         return AVERROR(EINVAL);
     398             : 
     399           0 :     if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type))
     400           0 :         fmt->fmt.pix_mp.pixelformat = v4l2_fmt;
     401             :     else
     402           0 :         fmt->fmt.pix.pixelformat = v4l2_fmt;
     403             : 
     404           0 :     fmt->type = ctx->type;
     405             : 
     406           0 :     ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_TRY_FMT, fmt);
     407           0 :     if (ret)
     408           0 :         return AVERROR(EINVAL);
     409             : 
     410           0 :     return 0;
     411             : }
     412             : 
     413           0 : static int v4l2_get_raw_format(V4L2Context* ctx, enum AVPixelFormat *p)
     414             : {
     415           0 :     enum AVPixelFormat pixfmt = ctx->av_pix_fmt;
     416             :     struct v4l2_fmtdesc fdesc;
     417             :     int ret;
     418             : 
     419           0 :     memset(&fdesc, 0, sizeof(fdesc));
     420           0 :     fdesc.type = ctx->type;
     421             : 
     422           0 :     if (pixfmt != AV_PIX_FMT_NONE) {
     423           0 :         ret = v4l2_try_raw_format(ctx, pixfmt);
     424           0 :         if (ret)
     425           0 :             pixfmt = AV_PIX_FMT_NONE;
     426             :         else
     427           0 :             return 0;
     428             :     }
     429             : 
     430             :     for (;;) {
     431           0 :         ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_ENUM_FMT, &fdesc);
     432           0 :         if (ret)
     433           0 :             return AVERROR(EINVAL);
     434             : 
     435           0 :         pixfmt = ff_v4l2_format_v4l2_to_avfmt(fdesc.pixelformat, AV_CODEC_ID_RAWVIDEO);
     436           0 :         ret = v4l2_try_raw_format(ctx, pixfmt);
     437           0 :         if (ret){
     438           0 :             fdesc.index++;
     439           0 :             continue;
     440             :         }
     441             : 
     442           0 :         *p = pixfmt;
     443             : 
     444           0 :         return 0;
     445             :     }
     446             : 
     447             :     return AVERROR(EINVAL);
     448             : }
     449             : 
     450           0 : static int v4l2_get_coded_format(V4L2Context* ctx, uint32_t *p)
     451             : {
     452             :     struct v4l2_fmtdesc fdesc;
     453             :     uint32_t v4l2_fmt;
     454             :     int ret;
     455             : 
     456             :     /* translate to a valid v4l2 format */
     457           0 :     v4l2_fmt = ff_v4l2_format_avcodec_to_v4l2(ctx->av_codec_id);
     458           0 :     if (!v4l2_fmt)
     459           0 :         return AVERROR(EINVAL);
     460             : 
     461             :     /* check if the driver supports this format */
     462           0 :     memset(&fdesc, 0, sizeof(fdesc));
     463           0 :     fdesc.type = ctx->type;
     464             : 
     465             :     for (;;) {
     466           0 :         ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_ENUM_FMT, &fdesc);
     467           0 :         if (ret)
     468           0 :             return AVERROR(EINVAL);
     469             : 
     470           0 :         if (fdesc.pixelformat == v4l2_fmt)
     471           0 :             break;
     472             : 
     473           0 :         fdesc.index++;
     474             :     }
     475             : 
     476           0 :     *p = v4l2_fmt;
     477             : 
     478           0 :     return 0;
     479             : }
     480             : 
     481             :  /*****************************************************************************
     482             :   *
     483             :   *             V4L2 Context Interface
     484             :   *
     485             :   *****************************************************************************/
     486             : 
     487           0 : int ff_v4l2_context_set_status(V4L2Context* ctx, uint32_t cmd)
     488             : {
     489           0 :     int type = ctx->type;
     490             :     int ret;
     491             : 
     492           0 :     ret = ioctl(ctx_to_m2mctx(ctx)->fd, cmd, &type);
     493           0 :     if (ret < 0)
     494           0 :         return AVERROR(errno);
     495             : 
     496           0 :     ctx->streamon = (cmd == VIDIOC_STREAMON);
     497             : 
     498           0 :     return 0;
     499             : }
     500             : 
     501           0 : int ff_v4l2_context_enqueue_frame(V4L2Context* ctx, const AVFrame* frame)
     502             : {
     503           0 :     V4L2m2mContext *s = ctx_to_m2mctx(ctx);
     504             :     V4L2Buffer* avbuf;
     505             :     int ret;
     506             : 
     507           0 :     if (!frame) {
     508           0 :         ret = v4l2_stop_encode(ctx);
     509           0 :         if (ret)
     510           0 :             av_log(logger(ctx), AV_LOG_ERROR, "%s stop_encode\n", ctx->name);
     511           0 :         s->draining= 1;
     512           0 :         return 0;
     513             :     }
     514             : 
     515           0 :     avbuf = v4l2_getfree_v4l2buf(ctx);
     516           0 :     if (!avbuf)
     517           0 :         return AVERROR(ENOMEM);
     518             : 
     519           0 :     ret = ff_v4l2_buffer_avframe_to_buf(frame, avbuf);
     520           0 :     if (ret)
     521           0 :         return ret;
     522             : 
     523           0 :     return ff_v4l2_buffer_enqueue(avbuf);
     524             : }
     525             : 
     526           0 : int ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt)
     527             : {
     528           0 :     V4L2m2mContext *s = ctx_to_m2mctx(ctx);
     529             :     V4L2Buffer* avbuf;
     530             :     int ret;
     531             : 
     532           0 :     if (!pkt->size) {
     533           0 :         ret = v4l2_stop_decode(ctx);
     534           0 :         if (ret)
     535           0 :             av_log(logger(ctx), AV_LOG_ERROR, "%s stop_decode\n", ctx->name);
     536           0 :         s->draining = 1;
     537           0 :         return 0;
     538             :     }
     539             : 
     540           0 :     avbuf = v4l2_getfree_v4l2buf(ctx);
     541           0 :     if (!avbuf)
     542           0 :         return AVERROR(ENOMEM);
     543             : 
     544           0 :     ret = ff_v4l2_buffer_avpkt_to_buf(pkt, avbuf);
     545           0 :     if (ret)
     546           0 :         return ret;
     547             : 
     548           0 :     return ff_v4l2_buffer_enqueue(avbuf);
     549             : }
     550             : 
     551           0 : int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* frame)
     552             : {
     553           0 :     V4L2Buffer* avbuf = NULL;
     554             : 
     555             :     /* if we are draining, we are no longer inputing data, therefore enable a
     556             :      * timeout so we can dequeue and flag the last valid buffer.
     557             :      *
     558             :      * blocks until:
     559             :      *  1. decoded frame available
     560             :      *  2. an input buffer is ready to be dequeued
     561             :      */
     562           0 :     avbuf = v4l2_dequeue_v4l2buf(ctx, ctx_to_m2mctx(ctx)->draining ? 200 : -1);
     563           0 :     if (!avbuf) {
     564           0 :         if (ctx->done)
     565           0 :             return AVERROR_EOF;
     566             : 
     567           0 :         return AVERROR(EAGAIN);
     568             :     }
     569             : 
     570           0 :     return ff_v4l2_buffer_buf_to_avframe(frame, avbuf);
     571             : }
     572             : 
     573           0 : int ff_v4l2_context_dequeue_packet(V4L2Context* ctx, AVPacket* pkt)
     574             : {
     575           0 :     V4L2Buffer* avbuf = NULL;
     576             : 
     577             :     /* if we are draining, we are no longer inputing data, therefore enable a
     578             :      * timeout so we can dequeue and flag the last valid buffer.
     579             :      *
     580             :      * blocks until:
     581             :      *  1. encoded packet available
     582             :      *  2. an input buffer ready to be dequeued
     583             :      */
     584           0 :     avbuf = v4l2_dequeue_v4l2buf(ctx, ctx_to_m2mctx(ctx)->draining ? 200 : -1);
     585           0 :     if (!avbuf) {
     586           0 :         if (ctx->done)
     587           0 :             return AVERROR_EOF;
     588             : 
     589           0 :         return AVERROR(EAGAIN);
     590             :     }
     591             : 
     592           0 :     return ff_v4l2_buffer_buf_to_avpkt(pkt, avbuf);
     593             : }
     594             : 
     595           0 : int ff_v4l2_context_get_format(V4L2Context* ctx)
     596             : {
     597           0 :     struct v4l2_format_update fmt = { 0 };
     598             :     int ret;
     599             : 
     600           0 :     if  (ctx->av_codec_id == AV_CODEC_ID_RAWVIDEO) {
     601           0 :         ret = v4l2_get_raw_format(ctx, &fmt.av_fmt);
     602           0 :         if (ret)
     603           0 :             return ret;
     604             : 
     605           0 :         fmt.update_avfmt = 1;
     606           0 :         v4l2_save_to_context(ctx, &fmt);
     607             : 
     608             :         /* format has been tried already */
     609           0 :         return ret;
     610             :     }
     611             : 
     612           0 :     ret = v4l2_get_coded_format(ctx, &fmt.v4l2_fmt);
     613           0 :     if (ret)
     614           0 :         return ret;
     615             : 
     616           0 :     fmt.update_v4l2 = 1;
     617           0 :     v4l2_save_to_context(ctx, &fmt);
     618             : 
     619           0 :     return ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_TRY_FMT, &ctx->format);
     620             : }
     621             : 
     622           0 : int ff_v4l2_context_set_format(V4L2Context* ctx)
     623             : {
     624           0 :     return ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_S_FMT, &ctx->format);
     625             : }
     626             : 
     627           0 : void ff_v4l2_context_release(V4L2Context* ctx)
     628             : {
     629             :     int ret;
     630             : 
     631           0 :     if (!ctx->buffers)
     632           0 :         return;
     633             : 
     634           0 :     ret = v4l2_release_buffers(ctx);
     635           0 :     if (ret)
     636           0 :         av_log(logger(ctx), AV_LOG_WARNING, "V4L2 failed to unmap the %s buffers\n", ctx->name);
     637             : 
     638           0 :     av_free(ctx->buffers);
     639           0 :     ctx->buffers = NULL;
     640             : }
     641             : 
     642           0 : int ff_v4l2_context_init(V4L2Context* ctx)
     643             : {
     644           0 :     V4L2m2mContext *s = ctx_to_m2mctx(ctx);
     645             :     struct v4l2_requestbuffers req;
     646             :     int ret, i;
     647             : 
     648           0 :     if (!v4l2_type_supported(ctx)) {
     649           0 :         av_log(logger(ctx), AV_LOG_ERROR, "type %i not supported\n", ctx->type);
     650           0 :         return AVERROR_PATCHWELCOME;
     651             :     }
     652             : 
     653           0 :     ret = ioctl(s->fd, VIDIOC_G_FMT, &ctx->format);
     654           0 :     if (ret)
     655           0 :         av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_G_FMT failed\n", ctx->name);
     656             : 
     657           0 :     memset(&req, 0, sizeof(req));
     658           0 :     req.count = ctx->num_buffers;
     659           0 :     req.memory = V4L2_MEMORY_MMAP;
     660           0 :     req.type = ctx->type;
     661           0 :     ret = ioctl(s->fd, VIDIOC_REQBUFS, &req);
     662           0 :     if (ret < 0)
     663           0 :         return AVERROR(errno);
     664             : 
     665           0 :     ctx->num_buffers = req.count;
     666           0 :     ctx->buffers = av_mallocz(ctx->num_buffers * sizeof(V4L2Buffer));
     667           0 :     if (!ctx->buffers) {
     668           0 :             av_log(logger(ctx), AV_LOG_ERROR, "%s malloc enomem\n", ctx->name);
     669           0 :             return AVERROR(ENOMEM);
     670             :     }
     671             : 
     672           0 :     for (i = 0; i < req.count; i++) {
     673           0 :         ctx->buffers[i].context = ctx;
     674           0 :         ret = ff_v4l2_buffer_initialize(&ctx->buffers[i], i);
     675           0 :         if (ret < 0) {
     676           0 :             av_log(logger(ctx), AV_LOG_ERROR, "%s buffer initialization (%s)\n", ctx->name, av_err2str(ret));
     677           0 :             av_free(ctx->buffers);
     678           0 :             return ret;
     679             :         }
     680             :     }
     681             : 
     682           0 :     av_log(logger(ctx), AV_LOG_DEBUG, "%s: %s %02d buffers initialized: %04ux%04u, sizeimage %08u, bytesperline %08u\n", ctx->name,
     683           0 :         V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? av_fourcc2str(ctx->format.fmt.pix_mp.pixelformat) : av_fourcc2str(ctx->format.fmt.pix.pixelformat),
     684             :         req.count,
     685             :         v4l2_get_width(&ctx->format),
     686             :         v4l2_get_height(&ctx->format),
     687           0 :         V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? ctx->format.fmt.pix_mp.plane_fmt[0].sizeimage : ctx->format.fmt.pix.sizeimage,
     688           0 :         V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? ctx->format.fmt.pix_mp.plane_fmt[0].bytesperline : ctx->format.fmt.pix.bytesperline);
     689             : 
     690           0 :     return 0;
     691             : }

Generated by: LCOV version 1.13