LCOV - code coverage report
Current view: top level - libavcodec - v4l2_buffers.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 244 0.0 %
Date: 2017-12-17 04:34:43 Functions: 0 17 0.0 %

          Line data    Source code
       1             : /*
       2             :  * V4L2 buffer 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_context.h"
      33             : #include "v4l2_buffers.h"
      34             : #include "v4l2_m2m.h"
      35             : 
      36             : #define USEC_PER_SEC 1000000
      37             : 
      38           0 : static inline V4L2m2mContext *buf_to_m2mctx(V4L2Buffer *buf)
      39             : {
      40           0 :     return V4L2_TYPE_IS_OUTPUT(buf->context->type) ?
      41           0 :         container_of(buf->context, V4L2m2mContext, output) :
      42           0 :         container_of(buf->context, V4L2m2mContext, capture);
      43             : }
      44             : 
      45           0 : static inline AVCodecContext *logger(V4L2Buffer *buf)
      46             : {
      47           0 :     return buf_to_m2mctx(buf)->avctx;
      48             : }
      49             : 
      50           0 : static inline void v4l2_set_pts(V4L2Buffer *out, int64_t pts)
      51             : {
      52           0 :     V4L2m2mContext *s = buf_to_m2mctx(out);
      53           0 :     AVRational v4l2_timebase = { 1, USEC_PER_SEC };
      54             :     int64_t v4l2_pts;
      55             : 
      56           0 :     if (pts == AV_NOPTS_VALUE)
      57           0 :         pts = 0;
      58             : 
      59             :     /* convert pts to v4l2 timebase */
      60           0 :     v4l2_pts = av_rescale_q(pts, s->avctx->time_base, v4l2_timebase);
      61           0 :     out->buf.timestamp.tv_usec = v4l2_pts % USEC_PER_SEC;
      62           0 :     out->buf.timestamp.tv_sec = v4l2_pts / USEC_PER_SEC;
      63           0 : }
      64             : 
      65           0 : static inline uint64_t v4l2_get_pts(V4L2Buffer *avbuf)
      66             : {
      67           0 :     V4L2m2mContext *s = buf_to_m2mctx(avbuf);
      68           0 :     AVRational v4l2_timebase = { 1, USEC_PER_SEC };
      69             :     int64_t v4l2_pts;
      70             : 
      71             :     /* convert pts back to encoder timebase */
      72           0 :     v4l2_pts = avbuf->buf.timestamp.tv_sec * USEC_PER_SEC + avbuf->buf.timestamp.tv_usec;
      73             : 
      74           0 :     return av_rescale_q(v4l2_pts, v4l2_timebase, s->avctx->time_base);
      75             : }
      76             : 
      77           0 : static enum AVColorPrimaries v4l2_get_color_primaries(V4L2Buffer *buf)
      78             : {
      79             :     enum v4l2_ycbcr_encoding ycbcr;
      80             :     enum v4l2_colorspace cs;
      81             : 
      82           0 :     cs = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ?
      83           0 :         buf->context->format.fmt.pix_mp.colorspace :
      84           0 :         buf->context->format.fmt.pix.colorspace;
      85             : 
      86           0 :     ycbcr = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ?
      87           0 :         buf->context->format.fmt.pix_mp.ycbcr_enc:
      88           0 :         buf->context->format.fmt.pix.ycbcr_enc;
      89             : 
      90           0 :     switch(ycbcr) {
      91           0 :     case V4L2_YCBCR_ENC_XV709:
      92           0 :     case V4L2_YCBCR_ENC_709: return AVCOL_PRI_BT709;
      93           0 :     case V4L2_YCBCR_ENC_XV601:
      94           0 :     case V4L2_YCBCR_ENC_601:return AVCOL_PRI_BT470M;
      95           0 :     default:
      96           0 :         break;
      97             :     }
      98             : 
      99           0 :     switch(cs) {
     100           0 :     case V4L2_COLORSPACE_470_SYSTEM_BG: return AVCOL_PRI_BT470BG;
     101           0 :     case V4L2_COLORSPACE_SMPTE170M: return AVCOL_PRI_SMPTE170M;
     102           0 :     case V4L2_COLORSPACE_SMPTE240M: return AVCOL_PRI_SMPTE240M;
     103           0 :     case V4L2_COLORSPACE_BT2020: return AVCOL_PRI_BT2020;
     104           0 :     default:
     105           0 :         break;
     106             :     }
     107             : 
     108           0 :     return AVCOL_PRI_UNSPECIFIED;
     109             : }
     110             : 
     111           0 : static enum AVColorRange v4l2_get_color_range(V4L2Buffer *buf)
     112             : {
     113             :     enum v4l2_quantization qt;
     114             : 
     115           0 :     qt = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ?
     116           0 :         buf->context->format.fmt.pix_mp.quantization :
     117           0 :         buf->context->format.fmt.pix.quantization;
     118             : 
     119           0 :     switch (qt) {
     120           0 :     case V4L2_QUANTIZATION_LIM_RANGE: return AVCOL_RANGE_MPEG;
     121           0 :     case V4L2_QUANTIZATION_FULL_RANGE: return AVCOL_RANGE_JPEG;
     122           0 :     default:
     123           0 :         break;
     124             :     }
     125             : 
     126           0 :      return AVCOL_RANGE_UNSPECIFIED;
     127             : }
     128             : 
     129           0 : static enum AVColorSpace v4l2_get_color_space(V4L2Buffer *buf)
     130             : {
     131             :     enum v4l2_ycbcr_encoding ycbcr;
     132             :     enum v4l2_colorspace cs;
     133             : 
     134           0 :     cs = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ?
     135           0 :         buf->context->format.fmt.pix_mp.colorspace :
     136           0 :         buf->context->format.fmt.pix.colorspace;
     137             : 
     138           0 :     ycbcr = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ?
     139           0 :         buf->context->format.fmt.pix_mp.ycbcr_enc:
     140           0 :         buf->context->format.fmt.pix.ycbcr_enc;
     141             : 
     142           0 :     switch(cs) {
     143           0 :     case V4L2_COLORSPACE_SRGB: return AVCOL_SPC_RGB;
     144           0 :     case V4L2_COLORSPACE_REC709: return AVCOL_SPC_BT709;
     145           0 :     case V4L2_COLORSPACE_470_SYSTEM_M: return AVCOL_SPC_FCC;
     146           0 :     case V4L2_COLORSPACE_470_SYSTEM_BG: return AVCOL_SPC_BT470BG;
     147           0 :     case V4L2_COLORSPACE_SMPTE170M: return AVCOL_SPC_SMPTE170M;
     148           0 :     case V4L2_COLORSPACE_SMPTE240M: return AVCOL_SPC_SMPTE240M;
     149           0 :     case V4L2_COLORSPACE_BT2020:
     150           0 :         if (ycbcr == V4L2_YCBCR_ENC_BT2020_CONST_LUM)
     151           0 :             return AVCOL_SPC_BT2020_CL;
     152             :         else
     153           0 :              return AVCOL_SPC_BT2020_NCL;
     154           0 :     default:
     155           0 :         break;
     156             :     }
     157             : 
     158           0 :     return AVCOL_SPC_UNSPECIFIED;
     159             : }
     160             : 
     161           0 : static enum AVColorTransferCharacteristic v4l2_get_color_trc(V4L2Buffer *buf)
     162             : {
     163             :     enum v4l2_ycbcr_encoding ycbcr;
     164             :     enum v4l2_xfer_func xfer;
     165             :     enum v4l2_colorspace cs;
     166             : 
     167           0 :     cs = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ?
     168           0 :         buf->context->format.fmt.pix_mp.colorspace :
     169           0 :         buf->context->format.fmt.pix.colorspace;
     170             : 
     171           0 :     ycbcr = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ?
     172           0 :         buf->context->format.fmt.pix_mp.ycbcr_enc:
     173           0 :         buf->context->format.fmt.pix.ycbcr_enc;
     174             : 
     175           0 :     xfer = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ?
     176           0 :         buf->context->format.fmt.pix_mp.xfer_func:
     177           0 :         buf->context->format.fmt.pix.xfer_func;
     178             : 
     179           0 :     switch (xfer) {
     180           0 :     case V4L2_XFER_FUNC_709: return AVCOL_TRC_BT709;
     181           0 :     case V4L2_XFER_FUNC_SRGB: return AVCOL_TRC_IEC61966_2_1;
     182           0 :     default:
     183           0 :         break;
     184             :     }
     185             : 
     186           0 :     switch (cs) {
     187           0 :     case V4L2_COLORSPACE_470_SYSTEM_M: return AVCOL_TRC_GAMMA22;
     188           0 :     case V4L2_COLORSPACE_470_SYSTEM_BG: return AVCOL_TRC_GAMMA28;
     189           0 :     case V4L2_COLORSPACE_SMPTE170M: return AVCOL_TRC_SMPTE170M;
     190           0 :     case V4L2_COLORSPACE_SMPTE240M: return AVCOL_TRC_SMPTE240M;
     191           0 :     default:
     192           0 :         break;
     193             :     }
     194             : 
     195           0 :     switch (ycbcr) {
     196           0 :     case V4L2_YCBCR_ENC_XV709:
     197           0 :     case V4L2_YCBCR_ENC_XV601: return AVCOL_TRC_BT1361_ECG;
     198           0 :     default:
     199           0 :         break;
     200             :     }
     201             : 
     202           0 :     return AVCOL_TRC_UNSPECIFIED;
     203             : }
     204             : 
     205           0 : static void v4l2_free_buffer(void *opaque, uint8_t *unused)
     206             : {
     207           0 :     V4L2Buffer* avbuf = opaque;
     208           0 :     V4L2m2mContext *s = buf_to_m2mctx(avbuf);
     209             : 
     210           0 :     atomic_fetch_sub_explicit(&s->refcount, 1, memory_order_acq_rel);
     211           0 :     if (s->reinit) {
     212           0 :         if (!atomic_load(&s->refcount))
     213           0 :             sem_post(&s->refsync);
     214           0 :         return;
     215             :     }
     216             : 
     217           0 :     if (avbuf->context->streamon) {
     218           0 :         ff_v4l2_buffer_enqueue(avbuf);
     219           0 :         return;
     220             :     }
     221             : 
     222           0 :     if (!atomic_load(&s->refcount))
     223           0 :         ff_v4l2_m2m_codec_end(s->avctx);
     224             : }
     225             : 
     226           0 : static int v4l2_buf_to_bufref(V4L2Buffer *in, int plane, AVBufferRef **buf)
     227             : {
     228           0 :     V4L2m2mContext *s = buf_to_m2mctx(in);
     229             : 
     230           0 :     if (plane >= in->num_planes)
     231           0 :         return AVERROR(EINVAL);
     232             : 
     233             :     /* even though most encoders return 0 in data_offset encoding vp8 does require this value */
     234           0 :     *buf = av_buffer_create((char *)in->plane_info[plane].mm_addr + in->planes[plane].data_offset,
     235           0 :                             in->plane_info[plane].length, v4l2_free_buffer, in, 0);
     236           0 :     if (!*buf)
     237           0 :         return AVERROR(ENOMEM);
     238             : 
     239           0 :     in->status = V4L2BUF_RET_USER;
     240           0 :     atomic_fetch_add_explicit(&s->refcount, 1, memory_order_relaxed);
     241             : 
     242           0 :     return 0;
     243             : }
     244             : 
     245           0 : static int v4l2_bufref_to_buf(V4L2Buffer *out, int plane, const uint8_t* data, int size, AVBufferRef* bref)
     246             : {
     247             :     unsigned int bytesused, length;
     248             : 
     249           0 :     if (plane >= out->num_planes)
     250           0 :         return AVERROR(EINVAL);
     251             : 
     252           0 :     bytesused = FFMIN(size, out->plane_info[plane].length);
     253           0 :     length = out->plane_info[plane].length;
     254             : 
     255           0 :     memcpy(out->plane_info[plane].mm_addr, data, FFMIN(size, out->plane_info[plane].length));
     256             : 
     257           0 :     if (V4L2_TYPE_IS_MULTIPLANAR(out->buf.type)) {
     258           0 :         out->planes[plane].bytesused = bytesused;
     259           0 :         out->planes[plane].length = length;
     260             :     } else {
     261           0 :         out->buf.bytesused = bytesused;
     262           0 :         out->buf.length = length;
     263             :     }
     264             : 
     265           0 :     return 0;
     266             : }
     267             : 
     268             : /******************************************************************************
     269             :  *
     270             :  *              V4L2uffer interface
     271             :  *
     272             :  ******************************************************************************/
     273             : 
     274           0 : int ff_v4l2_buffer_avframe_to_buf(const AVFrame *frame, V4L2Buffer* out)
     275             : {
     276             :     int i, ret;
     277             : 
     278           0 :     for(i = 0; i < out->num_planes; i++) {
     279           0 :         ret = v4l2_bufref_to_buf(out, i, frame->buf[i]->data, frame->buf[i]->size, frame->buf[i]);
     280           0 :         if (ret)
     281           0 :             return ret;
     282             :     }
     283             : 
     284           0 :     v4l2_set_pts(out, frame->pts);
     285             : 
     286           0 :     return 0;
     287             : }
     288             : 
     289           0 : int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *avbuf)
     290             : {
     291           0 :     V4L2m2mContext *s = buf_to_m2mctx(avbuf);
     292             :     int i, ret;
     293             : 
     294           0 :     av_frame_unref(frame);
     295             : 
     296             :     /* 1. get references to the actual data */
     297           0 :     for (i = 0; i < avbuf->num_planes; i++) {
     298           0 :         ret = v4l2_buf_to_bufref(avbuf, i, &frame->buf[i]);
     299           0 :         if (ret)
     300           0 :             return ret;
     301             : 
     302           0 :         frame->linesize[i] = avbuf->plane_info[i].bytesperline;
     303           0 :         frame->data[i] = frame->buf[i]->data;
     304             :     }
     305             : 
     306             :     /* 1.1 fixup special cases */
     307           0 :     switch (avbuf->context->av_pix_fmt) {
     308           0 :     case AV_PIX_FMT_NV12:
     309           0 :         if (avbuf->num_planes > 1)
     310           0 :             break;
     311           0 :         frame->linesize[1] = avbuf->plane_info[0].bytesperline;
     312           0 :         frame->data[1] = frame->buf[0]->data + avbuf->plane_info[0].bytesperline * avbuf->context->format.fmt.pix_mp.height;
     313           0 :         break;
     314           0 :     default:
     315           0 :         break;
     316             :     }
     317             : 
     318             :     /* 2. get frame information */
     319           0 :     frame->key_frame = !!(avbuf->buf.flags & V4L2_BUF_FLAG_KEYFRAME);
     320           0 :     frame->format = avbuf->context->av_pix_fmt;
     321           0 :     frame->color_primaries = v4l2_get_color_primaries(avbuf);
     322           0 :     frame->colorspace = v4l2_get_color_space(avbuf);
     323           0 :     frame->color_range = v4l2_get_color_range(avbuf);
     324           0 :     frame->color_trc = v4l2_get_color_trc(avbuf);
     325           0 :     frame->pts = v4l2_get_pts(avbuf);
     326             : 
     327             :     /* these two values are updated also during re-init in v4l2_process_driver_event */
     328           0 :     frame->height = s->output.height;
     329           0 :     frame->width = s->output.width;
     330             : 
     331             :     /* 3. report errors upstream */
     332           0 :     if (avbuf->buf.flags & V4L2_BUF_FLAG_ERROR) {
     333           0 :         av_log(logger(avbuf), AV_LOG_ERROR, "%s: driver decode error\n", avbuf->context->name);
     334           0 :         frame->decode_error_flags |= FF_DECODE_ERROR_INVALID_BITSTREAM;
     335             :     }
     336             : 
     337           0 :     return 0;
     338             : }
     339             : 
     340           0 : int ff_v4l2_buffer_buf_to_avpkt(AVPacket *pkt, V4L2Buffer *avbuf)
     341             : {
     342             :     int ret;
     343             : 
     344           0 :     av_packet_unref(pkt);
     345           0 :     ret = v4l2_buf_to_bufref(avbuf, 0, &pkt->buf);
     346           0 :     if (ret)
     347           0 :         return ret;
     348             : 
     349           0 :     pkt->size = V4L2_TYPE_IS_MULTIPLANAR(avbuf->buf.type) ? avbuf->buf.m.planes[0].bytesused : avbuf->buf.bytesused;
     350           0 :     pkt->data = pkt->buf->data;
     351             : 
     352           0 :     if (avbuf->buf.flags & V4L2_BUF_FLAG_KEYFRAME)
     353           0 :         pkt->flags |= AV_PKT_FLAG_KEY;
     354             : 
     355           0 :     if (avbuf->buf.flags & V4L2_BUF_FLAG_ERROR) {
     356           0 :         av_log(logger(avbuf), AV_LOG_ERROR, "%s driver encode error\n", avbuf->context->name);
     357           0 :         pkt->flags |= AV_PKT_FLAG_CORRUPT;
     358             :     }
     359             : 
     360           0 :     pkt->dts = pkt->pts = v4l2_get_pts(avbuf);
     361             : 
     362           0 :     return 0;
     363             : }
     364             : 
     365           0 : int ff_v4l2_buffer_avpkt_to_buf(const AVPacket *pkt, V4L2Buffer *out)
     366             : {
     367             :     int ret;
     368             : 
     369           0 :     ret = v4l2_bufref_to_buf(out, 0, pkt->data, pkt->size, pkt->buf);
     370           0 :     if (ret)
     371           0 :         return ret;
     372             : 
     373           0 :     v4l2_set_pts(out, pkt->pts);
     374             : 
     375           0 :     if (pkt->flags & AV_PKT_FLAG_KEY)
     376           0 :         out->flags = V4L2_BUF_FLAG_KEYFRAME;
     377             : 
     378           0 :     return 0;
     379             : }
     380             : 
     381           0 : int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index)
     382             : {
     383           0 :     V4L2Context *ctx = avbuf->context;
     384             :     int ret, i;
     385             : 
     386           0 :     avbuf->buf.memory = V4L2_MEMORY_MMAP;
     387           0 :     avbuf->buf.type = ctx->type;
     388           0 :     avbuf->buf.index = index;
     389             : 
     390           0 :     if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
     391           0 :         avbuf->buf.length = VIDEO_MAX_PLANES;
     392           0 :         avbuf->buf.m.planes = avbuf->planes;
     393             :     }
     394             : 
     395           0 :     ret = ioctl(buf_to_m2mctx(avbuf)->fd, VIDIOC_QUERYBUF, &avbuf->buf);
     396           0 :     if (ret < 0)
     397           0 :         return AVERROR(errno);
     398             : 
     399           0 :     if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
     400           0 :         avbuf->num_planes = 0;
     401             :         for (;;) {
     402             :             /* in MP, the V4L2 API states that buf.length means num_planes */
     403           0 :             if (avbuf->num_planes >= avbuf->buf.length)
     404           0 :                 break;
     405           0 :             if (avbuf->buf.m.planes[avbuf->num_planes].length)
     406           0 :                 avbuf->num_planes++;
     407             :         }
     408             :     } else
     409           0 :         avbuf->num_planes = 1;
     410             : 
     411           0 :     for (i = 0; i < avbuf->num_planes; i++) {
     412             : 
     413           0 :         avbuf->plane_info[i].bytesperline = V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ?
     414           0 :             ctx->format.fmt.pix_mp.plane_fmt[i].bytesperline :
     415           0 :             ctx->format.fmt.pix.bytesperline;
     416             : 
     417           0 :         if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
     418           0 :             avbuf->plane_info[i].length = avbuf->buf.m.planes[i].length;
     419           0 :             avbuf->plane_info[i].mm_addr = mmap(NULL, avbuf->buf.m.planes[i].length,
     420             :                                            PROT_READ | PROT_WRITE, MAP_SHARED,
     421           0 :                                            buf_to_m2mctx(avbuf)->fd, avbuf->buf.m.planes[i].m.mem_offset);
     422             :         } else {
     423           0 :             avbuf->plane_info[i].length = avbuf->buf.length;
     424           0 :             avbuf->plane_info[i].mm_addr = mmap(NULL, avbuf->buf.length,
     425             :                                           PROT_READ | PROT_WRITE, MAP_SHARED,
     426           0 :                                           buf_to_m2mctx(avbuf)->fd, avbuf->buf.m.offset);
     427             :         }
     428             : 
     429           0 :         if (avbuf->plane_info[i].mm_addr == MAP_FAILED)
     430           0 :             return AVERROR(ENOMEM);
     431             :     }
     432             : 
     433           0 :     avbuf->status = V4L2BUF_AVAILABLE;
     434             : 
     435           0 :     if (V4L2_TYPE_IS_OUTPUT(ctx->type))
     436           0 :         return 0;
     437             : 
     438           0 :     if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
     439           0 :         avbuf->buf.m.planes = avbuf->planes;
     440           0 :         avbuf->buf.length   = avbuf->num_planes;
     441             : 
     442             :     } else {
     443           0 :         avbuf->buf.bytesused = avbuf->planes[0].bytesused;
     444           0 :         avbuf->buf.length    = avbuf->planes[0].length;
     445             :     }
     446             : 
     447           0 :     return ff_v4l2_buffer_enqueue(avbuf);
     448             : }
     449             : 
     450           0 : int ff_v4l2_buffer_enqueue(V4L2Buffer* avbuf)
     451             : {
     452             :     int ret;
     453             : 
     454           0 :     avbuf->buf.flags = avbuf->flags;
     455             : 
     456           0 :     ret = ioctl(buf_to_m2mctx(avbuf)->fd, VIDIOC_QBUF, &avbuf->buf);
     457           0 :     if (ret < 0)
     458           0 :         return AVERROR(errno);
     459             : 
     460           0 :     avbuf->status = V4L2BUF_IN_DRIVER;
     461             : 
     462           0 :     return 0;
     463             : }

Generated by: LCOV version 1.13