LCOV - code coverage report
Current view: top level - libavcodec - v4l2_context.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 352 0.0 %
Date: 2018-02-24 03:21: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             :         .flags = 0,
     221             :     };
     222             :     int ret;
     223             : 
     224           0 :     ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_DECODER_CMD, &cmd);
     225           0 :     if (ret) {
     226             :         /* DECODER_CMD is optional */
     227           0 :         if (errno == ENOTTY)
     228           0 :             return ff_v4l2_context_set_status(ctx, VIDIOC_STREAMOFF);
     229             :     }
     230             : 
     231           0 :     return 0;
     232             : }
     233             : 
     234           0 : static int v4l2_stop_encode(V4L2Context *ctx)
     235             : {
     236           0 :     struct v4l2_encoder_cmd cmd = {
     237             :         .cmd = V4L2_ENC_CMD_STOP,
     238             :         .flags = 0,
     239             :     };
     240             :     int ret;
     241             : 
     242           0 :     ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_ENCODER_CMD, &cmd);
     243           0 :     if (ret) {
     244             :         /* ENCODER_CMD is optional */
     245           0 :         if (errno == ENOTTY)
     246           0 :             return ff_v4l2_context_set_status(ctx, VIDIOC_STREAMOFF);
     247             :     }
     248             : 
     249           0 :     return 0;
     250             : }
     251             : 
     252           0 : static V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout)
     253             : {
     254             :     struct v4l2_plane planes[VIDEO_MAX_PLANES];
     255           0 :     struct v4l2_buffer buf = { 0 };
     256           0 :     V4L2Buffer* avbuf = NULL;
     257           0 :     struct pollfd pfd = {
     258             :         .events =  POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM, /* default blocking capture */
     259           0 :         .fd = ctx_to_m2mctx(ctx)->fd,
     260             :     };
     261             :     int i, ret;
     262             : 
     263             :     /* if we are draining and there are no more capture buffers queued in the driver we are done */
     264           0 :     if (!V4L2_TYPE_IS_OUTPUT(ctx->type) && ctx_to_m2mctx(ctx)->draining) {
     265           0 :         for (i = 0; i < ctx->num_buffers; i++) {
     266           0 :             if (ctx->buffers[i].status == V4L2BUF_IN_DRIVER)
     267           0 :                 goto start;
     268             :         }
     269           0 :         ctx->done = 1;
     270           0 :         return NULL;
     271             :     }
     272             : 
     273           0 : start:
     274           0 :     if (V4L2_TYPE_IS_OUTPUT(ctx->type))
     275           0 :         pfd.events =  POLLOUT | POLLWRNORM;
     276             :     else {
     277             :         /* no need to listen to requests for more input while draining */
     278           0 :         if (ctx_to_m2mctx(ctx)->draining)
     279           0 :             pfd.events =  POLLIN | POLLRDNORM | POLLPRI;
     280             :     }
     281             : 
     282             :     for (;;) {
     283           0 :         ret = poll(&pfd, 1, timeout);
     284           0 :         if (ret > 0)
     285           0 :             break;
     286           0 :         if (errno == EINTR)
     287           0 :             continue;
     288           0 :         return NULL;
     289             :     }
     290             : 
     291             :     /* 0. handle errors */
     292           0 :     if (pfd.revents & POLLERR) {
     293             :         /* if we are trying to get free buffers but none have been queued yet
     294             :            no need to raise a warning */
     295           0 :         if (timeout == 0) {
     296           0 :             for (i = 0; i < ctx->num_buffers; i++) {
     297           0 :                 if (ctx->buffers[i].status != V4L2BUF_AVAILABLE)
     298           0 :                     av_log(logger(ctx), AV_LOG_WARNING, "%s POLLERR\n", ctx->name);
     299             :             }
     300             :         }
     301             :         else
     302           0 :             av_log(logger(ctx), AV_LOG_WARNING, "%s POLLERR\n", ctx->name);
     303             : 
     304           0 :         return NULL;
     305             :     }
     306             : 
     307             :     /* 1. handle resolution changes */
     308           0 :     if (pfd.revents & POLLPRI) {
     309           0 :         ret = v4l2_handle_event(ctx);
     310           0 :         if (ret < 0) {
     311             :             /* if re-init failed, abort */
     312           0 :             ctx->done = 1;
     313           0 :             return NULL;
     314             :         }
     315           0 :         if (ret) {
     316             :             /* if re-init was successful drop the buffer (if there was one)
     317             :              * since we had to reconfigure capture (unmap all buffers)
     318             :              */
     319           0 :             return NULL;
     320             :         }
     321             :     }
     322             : 
     323             :     /* 2. dequeue the buffer */
     324           0 :     if (pfd.revents & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM)) {
     325             : 
     326           0 :         if (!V4L2_TYPE_IS_OUTPUT(ctx->type)) {
     327             :             /* there is a capture buffer ready */
     328           0 :             if (pfd.revents & (POLLIN | POLLRDNORM))
     329           0 :                 goto dequeue;
     330             : 
     331             :             /* the driver is ready to accept more input; instead of waiting for the capture
     332             :              * buffer to complete we return NULL so input can proceed (we are single threaded)
     333             :              */
     334           0 :             if (pfd.revents & (POLLOUT | POLLWRNORM))
     335           0 :                 return NULL;
     336             :         }
     337             : 
     338           0 : dequeue:
     339           0 :         memset(&buf, 0, sizeof(buf));
     340           0 :         buf.memory = V4L2_MEMORY_MMAP;
     341           0 :         buf.type = ctx->type;
     342           0 :         if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
     343           0 :             memset(planes, 0, sizeof(planes));
     344           0 :             buf.length = VIDEO_MAX_PLANES;
     345           0 :             buf.m.planes = planes;
     346             :         }
     347             : 
     348           0 :         ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_DQBUF, &buf);
     349           0 :         if (ret) {
     350           0 :             if (errno != EAGAIN) {
     351           0 :                 ctx->done = 1;
     352           0 :                 if (errno != EPIPE)
     353           0 :                     av_log(logger(ctx), AV_LOG_DEBUG, "%s VIDIOC_DQBUF, errno (%s)\n",
     354           0 :                         ctx->name, av_err2str(AVERROR(errno)));
     355             :             }
     356           0 :             return NULL;
     357             :         }
     358             : 
     359           0 :         avbuf = &ctx->buffers[buf.index];
     360           0 :         avbuf->status = V4L2BUF_AVAILABLE;
     361           0 :         avbuf->buf = buf;
     362           0 :         if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
     363           0 :             memcpy(avbuf->planes, planes, sizeof(planes));
     364           0 :             avbuf->buf.m.planes = avbuf->planes;
     365             :         }
     366           0 :         return avbuf;
     367             :     }
     368             : 
     369           0 :     return NULL;
     370             : }
     371             : 
     372           0 : static V4L2Buffer* v4l2_getfree_v4l2buf(V4L2Context *ctx)
     373             : {
     374           0 :     int timeout = 0; /* return when no more buffers to dequeue */
     375             :     int i;
     376             : 
     377             :     /* get back as many output buffers as possible */
     378           0 :     if (V4L2_TYPE_IS_OUTPUT(ctx->type)) {
     379             :           do {
     380           0 :           } while (v4l2_dequeue_v4l2buf(ctx, timeout));
     381             :     }
     382             : 
     383           0 :     for (i = 0; i < ctx->num_buffers; i++) {
     384           0 :         if (ctx->buffers[i].status == V4L2BUF_AVAILABLE)
     385           0 :             return &ctx->buffers[i];
     386             :     }
     387             : 
     388           0 :     return NULL;
     389             : }
     390             : 
     391           0 : static int v4l2_release_buffers(V4L2Context* ctx)
     392             : {
     393           0 :     struct v4l2_requestbuffers req = {
     394             :         .memory = V4L2_MEMORY_MMAP,
     395           0 :         .type = ctx->type,
     396             :         .count = 0, /* 0 -> unmaps buffers from the driver */
     397             :     };
     398             :     int i, j;
     399             : 
     400           0 :     for (i = 0; i < ctx->num_buffers; i++) {
     401           0 :         V4L2Buffer *buffer = &ctx->buffers[i];
     402             : 
     403           0 :         for (j = 0; j < buffer->num_planes; j++) {
     404           0 :             struct V4L2Plane_info *p = &buffer->plane_info[j];
     405           0 :             if (p->mm_addr && p->length)
     406           0 :                 if (munmap(p->mm_addr, p->length) < 0)
     407           0 :                     av_log(logger(ctx), AV_LOG_ERROR, "%s unmap plane (%s))\n", ctx->name, av_err2str(AVERROR(errno)));
     408             :         }
     409             :     }
     410             : 
     411           0 :     return ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_REQBUFS, &req);
     412             : }
     413             : 
     414           0 : static inline int v4l2_try_raw_format(V4L2Context* ctx, enum AVPixelFormat pixfmt)
     415             : {
     416           0 :     struct v4l2_format *fmt = &ctx->format;
     417             :     uint32_t v4l2_fmt;
     418             :     int ret;
     419             : 
     420           0 :     v4l2_fmt = ff_v4l2_format_avfmt_to_v4l2(pixfmt);
     421           0 :     if (!v4l2_fmt)
     422           0 :         return AVERROR(EINVAL);
     423             : 
     424           0 :     if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type))
     425           0 :         fmt->fmt.pix_mp.pixelformat = v4l2_fmt;
     426             :     else
     427           0 :         fmt->fmt.pix.pixelformat = v4l2_fmt;
     428             : 
     429           0 :     fmt->type = ctx->type;
     430             : 
     431           0 :     ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_TRY_FMT, fmt);
     432           0 :     if (ret)
     433           0 :         return AVERROR(EINVAL);
     434             : 
     435           0 :     return 0;
     436             : }
     437             : 
     438           0 : static int v4l2_get_raw_format(V4L2Context* ctx, enum AVPixelFormat *p)
     439             : {
     440           0 :     enum AVPixelFormat pixfmt = ctx->av_pix_fmt;
     441             :     struct v4l2_fmtdesc fdesc;
     442             :     int ret;
     443             : 
     444           0 :     memset(&fdesc, 0, sizeof(fdesc));
     445           0 :     fdesc.type = ctx->type;
     446             : 
     447           0 :     if (pixfmt != AV_PIX_FMT_NONE) {
     448           0 :         ret = v4l2_try_raw_format(ctx, pixfmt);
     449           0 :         if (!ret)
     450           0 :             return 0;
     451             :     }
     452             : 
     453             :     for (;;) {
     454           0 :         ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_ENUM_FMT, &fdesc);
     455           0 :         if (ret)
     456           0 :             return AVERROR(EINVAL);
     457             : 
     458           0 :         pixfmt = ff_v4l2_format_v4l2_to_avfmt(fdesc.pixelformat, AV_CODEC_ID_RAWVIDEO);
     459           0 :         ret = v4l2_try_raw_format(ctx, pixfmt);
     460           0 :         if (ret){
     461           0 :             fdesc.index++;
     462           0 :             continue;
     463             :         }
     464             : 
     465           0 :         *p = pixfmt;
     466             : 
     467           0 :         return 0;
     468             :     }
     469             : 
     470             :     return AVERROR(EINVAL);
     471             : }
     472             : 
     473           0 : static int v4l2_get_coded_format(V4L2Context* ctx, uint32_t *p)
     474             : {
     475             :     struct v4l2_fmtdesc fdesc;
     476             :     uint32_t v4l2_fmt;
     477             :     int ret;
     478             : 
     479             :     /* translate to a valid v4l2 format */
     480           0 :     v4l2_fmt = ff_v4l2_format_avcodec_to_v4l2(ctx->av_codec_id);
     481           0 :     if (!v4l2_fmt)
     482           0 :         return AVERROR(EINVAL);
     483             : 
     484             :     /* check if the driver supports this format */
     485           0 :     memset(&fdesc, 0, sizeof(fdesc));
     486           0 :     fdesc.type = ctx->type;
     487             : 
     488             :     for (;;) {
     489           0 :         ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_ENUM_FMT, &fdesc);
     490           0 :         if (ret)
     491           0 :             return AVERROR(EINVAL);
     492             : 
     493           0 :         if (fdesc.pixelformat == v4l2_fmt)
     494           0 :             break;
     495             : 
     496           0 :         fdesc.index++;
     497             :     }
     498             : 
     499           0 :     *p = v4l2_fmt;
     500             : 
     501           0 :     return 0;
     502             : }
     503             : 
     504             :  /*****************************************************************************
     505             :   *
     506             :   *             V4L2 Context Interface
     507             :   *
     508             :   *****************************************************************************/
     509             : 
     510           0 : int ff_v4l2_context_set_status(V4L2Context* ctx, uint32_t cmd)
     511             : {
     512           0 :     int type = ctx->type;
     513             :     int ret;
     514             : 
     515           0 :     ret = ioctl(ctx_to_m2mctx(ctx)->fd, cmd, &type);
     516           0 :     if (ret < 0)
     517           0 :         return AVERROR(errno);
     518             : 
     519           0 :     ctx->streamon = (cmd == VIDIOC_STREAMON);
     520             : 
     521           0 :     return 0;
     522             : }
     523             : 
     524           0 : int ff_v4l2_context_enqueue_frame(V4L2Context* ctx, const AVFrame* frame)
     525             : {
     526           0 :     V4L2m2mContext *s = ctx_to_m2mctx(ctx);
     527             :     V4L2Buffer* avbuf;
     528             :     int ret;
     529             : 
     530           0 :     if (!frame) {
     531           0 :         ret = v4l2_stop_encode(ctx);
     532           0 :         if (ret)
     533           0 :             av_log(logger(ctx), AV_LOG_ERROR, "%s stop_encode\n", ctx->name);
     534           0 :         s->draining= 1;
     535           0 :         return 0;
     536             :     }
     537             : 
     538           0 :     avbuf = v4l2_getfree_v4l2buf(ctx);
     539           0 :     if (!avbuf)
     540           0 :         return AVERROR(ENOMEM);
     541             : 
     542           0 :     ret = ff_v4l2_buffer_avframe_to_buf(frame, avbuf);
     543           0 :     if (ret)
     544           0 :         return ret;
     545             : 
     546           0 :     return ff_v4l2_buffer_enqueue(avbuf);
     547             : }
     548             : 
     549           0 : int ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt)
     550             : {
     551           0 :     V4L2m2mContext *s = ctx_to_m2mctx(ctx);
     552             :     V4L2Buffer* avbuf;
     553             :     int ret;
     554             : 
     555           0 :     if (!pkt->size) {
     556           0 :         ret = v4l2_stop_decode(ctx);
     557           0 :         if (ret)
     558           0 :             av_log(logger(ctx), AV_LOG_ERROR, "%s stop_decode\n", ctx->name);
     559           0 :         s->draining = 1;
     560           0 :         return 0;
     561             :     }
     562             : 
     563           0 :     avbuf = v4l2_getfree_v4l2buf(ctx);
     564           0 :     if (!avbuf)
     565           0 :         return AVERROR(ENOMEM);
     566             : 
     567           0 :     ret = ff_v4l2_buffer_avpkt_to_buf(pkt, avbuf);
     568           0 :     if (ret)
     569           0 :         return ret;
     570             : 
     571           0 :     return ff_v4l2_buffer_enqueue(avbuf);
     572             : }
     573             : 
     574           0 : int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* frame)
     575             : {
     576           0 :     V4L2Buffer* avbuf = NULL;
     577             : 
     578             :     /*
     579             :      * blocks until:
     580             :      *  1. decoded frame available
     581             :      *  2. an input buffer is ready to be dequeued
     582             :      */
     583           0 :     avbuf = v4l2_dequeue_v4l2buf(ctx, -1);
     584           0 :     if (!avbuf) {
     585           0 :         if (ctx->done)
     586           0 :             return AVERROR_EOF;
     587             : 
     588           0 :         return AVERROR(EAGAIN);
     589             :     }
     590             : 
     591           0 :     return ff_v4l2_buffer_buf_to_avframe(frame, avbuf);
     592             : }
     593             : 
     594           0 : int ff_v4l2_context_dequeue_packet(V4L2Context* ctx, AVPacket* pkt)
     595             : {
     596           0 :     V4L2Buffer* avbuf = NULL;
     597             : 
     598             :     /*
     599             :      * blocks until:
     600             :      *  1. encoded packet available
     601             :      *  2. an input buffer ready to be dequeued
     602             :      */
     603           0 :     avbuf = v4l2_dequeue_v4l2buf(ctx, -1);
     604           0 :     if (!avbuf) {
     605           0 :         if (ctx->done)
     606           0 :             return AVERROR_EOF;
     607             : 
     608           0 :         return AVERROR(EAGAIN);
     609             :     }
     610             : 
     611           0 :     return ff_v4l2_buffer_buf_to_avpkt(pkt, avbuf);
     612             : }
     613             : 
     614           0 : int ff_v4l2_context_get_format(V4L2Context* ctx)
     615             : {
     616           0 :     struct v4l2_format_update fmt = { 0 };
     617             :     int ret;
     618             : 
     619           0 :     if  (ctx->av_codec_id == AV_CODEC_ID_RAWVIDEO) {
     620           0 :         ret = v4l2_get_raw_format(ctx, &fmt.av_fmt);
     621           0 :         if (ret)
     622           0 :             return ret;
     623             : 
     624           0 :         fmt.update_avfmt = 1;
     625           0 :         v4l2_save_to_context(ctx, &fmt);
     626             : 
     627             :         /* format has been tried already */
     628           0 :         return ret;
     629             :     }
     630             : 
     631           0 :     ret = v4l2_get_coded_format(ctx, &fmt.v4l2_fmt);
     632           0 :     if (ret)
     633           0 :         return ret;
     634             : 
     635           0 :     fmt.update_v4l2 = 1;
     636           0 :     v4l2_save_to_context(ctx, &fmt);
     637             : 
     638           0 :     return ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_TRY_FMT, &ctx->format);
     639             : }
     640             : 
     641           0 : int ff_v4l2_context_set_format(V4L2Context* ctx)
     642             : {
     643           0 :     return ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_S_FMT, &ctx->format);
     644             : }
     645             : 
     646           0 : void ff_v4l2_context_release(V4L2Context* ctx)
     647             : {
     648             :     int ret;
     649             : 
     650           0 :     if (!ctx->buffers)
     651           0 :         return;
     652             : 
     653           0 :     ret = v4l2_release_buffers(ctx);
     654           0 :     if (ret)
     655           0 :         av_log(logger(ctx), AV_LOG_WARNING, "V4L2 failed to unmap the %s buffers\n", ctx->name);
     656             : 
     657           0 :     av_free(ctx->buffers);
     658           0 :     ctx->buffers = NULL;
     659             : }
     660             : 
     661           0 : int ff_v4l2_context_init(V4L2Context* ctx)
     662             : {
     663           0 :     V4L2m2mContext *s = ctx_to_m2mctx(ctx);
     664             :     struct v4l2_requestbuffers req;
     665             :     int ret, i;
     666             : 
     667           0 :     if (!v4l2_type_supported(ctx)) {
     668           0 :         av_log(logger(ctx), AV_LOG_ERROR, "type %i not supported\n", ctx->type);
     669           0 :         return AVERROR_PATCHWELCOME;
     670             :     }
     671             : 
     672           0 :     ret = ioctl(s->fd, VIDIOC_G_FMT, &ctx->format);
     673           0 :     if (ret)
     674           0 :         av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_G_FMT failed\n", ctx->name);
     675             : 
     676           0 :     memset(&req, 0, sizeof(req));
     677           0 :     req.count = ctx->num_buffers;
     678           0 :     req.memory = V4L2_MEMORY_MMAP;
     679           0 :     req.type = ctx->type;
     680           0 :     ret = ioctl(s->fd, VIDIOC_REQBUFS, &req);
     681           0 :     if (ret < 0)
     682           0 :         return AVERROR(errno);
     683             : 
     684           0 :     ctx->num_buffers = req.count;
     685           0 :     ctx->buffers = av_mallocz(ctx->num_buffers * sizeof(V4L2Buffer));
     686           0 :     if (!ctx->buffers) {
     687           0 :             av_log(logger(ctx), AV_LOG_ERROR, "%s malloc enomem\n", ctx->name);
     688           0 :             return AVERROR(ENOMEM);
     689             :     }
     690             : 
     691           0 :     for (i = 0; i < req.count; i++) {
     692           0 :         ctx->buffers[i].context = ctx;
     693           0 :         ret = ff_v4l2_buffer_initialize(&ctx->buffers[i], i);
     694           0 :         if (ret < 0) {
     695           0 :             av_log(logger(ctx), AV_LOG_ERROR, "%s buffer initialization (%s)\n", ctx->name, av_err2str(ret));
     696           0 :             av_free(ctx->buffers);
     697           0 :             return ret;
     698             :         }
     699             :     }
     700             : 
     701           0 :     av_log(logger(ctx), AV_LOG_DEBUG, "%s: %s %02d buffers initialized: %04ux%04u, sizeimage %08u, bytesperline %08u\n", ctx->name,
     702           0 :         V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? av_fourcc2str(ctx->format.fmt.pix_mp.pixelformat) : av_fourcc2str(ctx->format.fmt.pix.pixelformat),
     703             :         req.count,
     704             :         v4l2_get_width(&ctx->format),
     705             :         v4l2_get_height(&ctx->format),
     706           0 :         V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? ctx->format.fmt.pix_mp.plane_fmt[0].sizeimage : ctx->format.fmt.pix.sizeimage,
     707           0 :         V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? ctx->format.fmt.pix_mp.plane_fmt[0].bytesperline : ctx->format.fmt.pix.bytesperline);
     708             : 
     709           0 :     return 0;
     710             : }

Generated by: LCOV version 1.13