Imported Upstream version 6.1
[platform/upstream/ffmpeg.git] / libavdevice / v4l2enc.c
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 "libavutil/imgutils.h"
22 #include "libavutil/pixdesc.h"
23 #include "libavformat/avformat.h"
24 #include "libavformat/mux.h"
25 #include "v4l2-common.h"
26
27 typedef struct {
28     AVClass *class;
29     int fd;
30 } V4L2Context;
31
32 static av_cold int write_header(AVFormatContext *s1)
33 {
34     int res = 0, flags = O_RDWR;
35     struct v4l2_format fmt = {
36         .type = V4L2_BUF_TYPE_VIDEO_OUTPUT
37     };
38     V4L2Context *s = s1->priv_data;
39     AVCodecParameters *par;
40     uint32_t v4l2_pixfmt;
41
42     if (s1->flags & AVFMT_FLAG_NONBLOCK)
43         flags |= O_NONBLOCK;
44
45     s->fd = open(s1->url, flags);
46     if (s->fd < 0) {
47         res = AVERROR(errno);
48         av_log(s1, AV_LOG_ERROR, "Unable to open V4L2 device '%s'\n", s1->url);
49         return res;
50     }
51
52     if (s1->nb_streams != 1 ||
53         s1->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) {
54         av_log(s1, AV_LOG_ERROR,
55                "V4L2 output device supports only a single raw video stream\n");
56         return AVERROR(EINVAL);
57     }
58
59     par = s1->streams[0]->codecpar;
60
61     if(par->codec_id == AV_CODEC_ID_RAWVIDEO) {
62         v4l2_pixfmt = ff_fmt_ff2v4l(par->format, AV_CODEC_ID_RAWVIDEO);
63     } else {
64         v4l2_pixfmt = ff_fmt_ff2v4l(AV_PIX_FMT_NONE, par->codec_id);
65     }
66
67     if (!v4l2_pixfmt) { // XXX: try to force them one by one?
68         av_log(s1, AV_LOG_ERROR, "Unknown V4L2 pixel format equivalent for %s\n",
69                av_get_pix_fmt_name(par->format));
70         return AVERROR(EINVAL);
71     }
72
73     if (ioctl(s->fd, VIDIOC_G_FMT, &fmt) < 0) {
74         res = AVERROR(errno);
75         av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_G_FMT): %s\n", av_err2str(res));
76         return res;
77     }
78
79     fmt.fmt.pix.width       = par->width;
80     fmt.fmt.pix.height      = par->height;
81     fmt.fmt.pix.pixelformat = v4l2_pixfmt;
82     fmt.fmt.pix.sizeimage   = av_image_get_buffer_size(par->format, par->width, par->height, 1);
83
84     if (ioctl(s->fd, VIDIOC_S_FMT, &fmt) < 0) {
85         res = AVERROR(errno);
86         av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_S_FMT): %s\n", av_err2str(res));
87         return res;
88     }
89
90     return res;
91 }
92
93 static int write_packet(AVFormatContext *s1, AVPacket *pkt)
94 {
95     const V4L2Context *s = s1->priv_data;
96     if (write(s->fd, pkt->data, pkt->size) == -1)
97         return AVERROR(errno);
98     return 0;
99 }
100
101 static int write_trailer(AVFormatContext *s1)
102 {
103     const V4L2Context *s = s1->priv_data;
104     close(s->fd);
105     return 0;
106 }
107
108 static const AVClass v4l2_class = {
109     .class_name = "V4L2 outdev",
110     .item_name  = av_default_item_name,
111     .version    = LIBAVUTIL_VERSION_INT,
112     .category   = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT,
113 };
114
115 const FFOutputFormat ff_v4l2_muxer = {
116     .p.name         = "video4linux2,v4l2",
117     .p.long_name    = NULL_IF_CONFIG_SMALL("Video4Linux2 output device"),
118     .priv_data_size = sizeof(V4L2Context),
119     .p.audio_codec  = AV_CODEC_ID_NONE,
120     .p.video_codec  = AV_CODEC_ID_RAWVIDEO,
121     .write_header   = write_header,
122     .write_packet   = write_packet,
123     .write_trailer  = write_trailer,
124     .p.flags        = AVFMT_NOFILE,
125     .p.priv_class   = &v4l2_class,
126 };