Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 2013 Clément Bœsch
  3.  *
  4.  * This file is part of FFmpeg.
  5.  *
  6.  * FFmpeg is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2.1 of the License, or (at your option) any later version.
  10.  *
  11.  * FFmpeg is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with FFmpeg; if not, write to the Free Software
  18.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19.  */
  20.  
  21. #include "v4l2-common.h"
  22. #include "avdevice.h"
  23.  
  24. typedef struct {
  25.     AVClass *class;
  26.     int fd;
  27. } V4L2Context;
  28.  
  29. static av_cold int write_header(AVFormatContext *s1)
  30. {
  31.     int res = 0, flags = O_RDWR;
  32.     struct v4l2_format fmt = {
  33.         .type = V4L2_BUF_TYPE_VIDEO_OUTPUT
  34.     };
  35.     V4L2Context *s = s1->priv_data;
  36.     AVCodecContext *enc_ctx;
  37.     uint32_t v4l2_pixfmt;
  38.  
  39.     if (s1->flags & AVFMT_FLAG_NONBLOCK)
  40.         flags |= O_NONBLOCK;
  41.  
  42.     s->fd = open(s1->filename, flags);
  43.     if (s->fd < 0) {
  44.         res = AVERROR(errno);
  45.         av_log(s1, AV_LOG_ERROR, "Unable to open V4L2 device '%s'\n", s1->filename);
  46.         return res;
  47.     }
  48.  
  49.     if (s1->nb_streams != 1 ||
  50.         s1->streams[0]->codec->codec_type != AVMEDIA_TYPE_VIDEO ||
  51.         s1->streams[0]->codec->codec_id   != AV_CODEC_ID_RAWVIDEO) {
  52.         av_log(s1, AV_LOG_ERROR,
  53.                "V4L2 output device supports only a single raw video stream\n");
  54.         return AVERROR(EINVAL);
  55.     }
  56.  
  57.     enc_ctx = s1->streams[0]->codec;
  58.  
  59.     v4l2_pixfmt = ff_fmt_ff2v4l(enc_ctx->pix_fmt, AV_CODEC_ID_RAWVIDEO);
  60.     if (!v4l2_pixfmt) { // XXX: try to force them one by one?
  61.         av_log(s1, AV_LOG_ERROR, "Unknown V4L2 pixel format equivalent for %s\n",
  62.                av_get_pix_fmt_name(enc_ctx->pix_fmt));
  63.         return AVERROR(EINVAL);
  64.     }
  65.  
  66.     if (ioctl(s->fd, VIDIOC_G_FMT, &fmt) < 0) {
  67.         res = AVERROR(errno);
  68.         av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_G_FMT): %s\n", av_err2str(res));
  69.         return res;
  70.     }
  71.  
  72.     fmt.fmt.pix.width       = enc_ctx->width;
  73.     fmt.fmt.pix.height      = enc_ctx->height;
  74.     fmt.fmt.pix.pixelformat = v4l2_pixfmt;
  75.     fmt.fmt.pix.sizeimage   = av_image_get_buffer_size(enc_ctx->pix_fmt, enc_ctx->width, enc_ctx->height, 1);
  76.  
  77.     if (ioctl(s->fd, VIDIOC_S_FMT, &fmt) < 0) {
  78.         res = AVERROR(errno);
  79.         av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_S_FMT): %s\n", av_err2str(res));
  80.         return res;
  81.     }
  82.  
  83.     return res;
  84. }
  85.  
  86. static int write_packet(AVFormatContext *s1, AVPacket *pkt)
  87. {
  88.     const V4L2Context *s = s1->priv_data;
  89.     if (write(s->fd, pkt->data, pkt->size) == -1)
  90.         return AVERROR(errno);
  91.     return 0;
  92. }
  93.  
  94. static int write_trailer(AVFormatContext *s1)
  95. {
  96.     const V4L2Context *s = s1->priv_data;
  97.     close(s->fd);
  98.     return 0;
  99. }
  100.  
  101. static const AVClass v4l2_class = {
  102.     .class_name = "V4L2 outdev",
  103.     .item_name  = av_default_item_name,
  104.     .version    = LIBAVUTIL_VERSION_INT,
  105.     .category   = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT,
  106. };
  107.  
  108. AVOutputFormat ff_v4l2_muxer = {
  109.     .name           = "v4l2",
  110.     .long_name      = NULL_IF_CONFIG_SMALL("Video4Linux2 output device"),
  111.     .priv_data_size = sizeof(V4L2Context),
  112.     .audio_codec    = AV_CODEC_ID_NONE,
  113.     .video_codec    = AV_CODEC_ID_RAWVIDEO,
  114.     .write_header   = write_header,
  115.     .write_packet   = write_packet,
  116.     .write_trailer  = write_trailer,
  117.     .flags          = AVFMT_NOFILE,
  118.     .priv_class     = &v4l2_class,
  119. };
  120.