2 * Copyright (c) 2011 Stefano Sabatini
3 * Copyright (c) 2009 Giliard B. de Freitas <giliarde@gmail.com>
4 * Copyright (C) 2002 Gunnar Monell <gmo@linux.nu>
6 * This file is part of FFmpeg.
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 * Linux framebuffer input device,
26 * inspired by code from fbgrab.c by Gunnar Monell.
27 * @see http://linux-fbdev.sourceforge.net/
32 #include <sys/ioctl.h>
37 #include "libavutil/internal.h"
38 #include "libavutil/log.h"
39 #include "libavutil/mem.h"
40 #include "libavutil/opt.h"
41 #include "libavutil/time.h"
42 #include "libavutil/parseutils.h"
43 #include "libavutil/pixdesc.h"
44 #include "libavformat/internal.h"
46 #include "fbdev_common.h"
48 typedef struct FBDevContext
{
49 AVClass
*class; ///< class for private options
50 int frame_size
; ///< size in bytes of a grabbed frame
51 AVRational framerate_q
; ///< framerate
52 int64_t time_frame
; ///< time for the next frame to output (in 1/1000000 units)
54 int fd
; ///< framebuffer device file descriptor
55 int width
, height
; ///< assumed frame resolution
56 int frame_linesize
; ///< linesize of the output frame, it is assumed to be constant
59 struct fb_var_screeninfo varinfo
; ///< variable info;
60 struct fb_fix_screeninfo fixinfo
; ///< fixed info;
62 uint8_t *data
; ///< framebuffer data
65 static av_cold
int fbdev_read_header(AVFormatContext
*avctx
)
67 FBDevContext
*fbdev
= avctx
->priv_data
;
69 enum AVPixelFormat pix_fmt
;
70 int ret
, flags
= O_RDONLY
;
72 if (!(st
= avformat_new_stream(avctx
, NULL
)))
73 return AVERROR(ENOMEM
);
74 avpriv_set_pts_info(st
, 64, 1, 1000000); /* 64 bits pts in microseconds */
76 /* NONBLOCK is ignored by the fbdev driver, only set for consistency */
77 if (avctx
->flags
& AVFMT_FLAG_NONBLOCK
)
80 if ((fbdev
->fd
= avpriv_open(avctx
->filename
, flags
)) == -1) {
82 av_log(avctx
, AV_LOG_ERROR
,
83 "Could not open framebuffer device '%s': %s\n",
84 avctx
->filename
, av_err2str(ret
));
88 if (ioctl(fbdev
->fd
, FBIOGET_VSCREENINFO
, &fbdev
->varinfo
) < 0) {
90 av_log(avctx
, AV_LOG_ERROR
,
91 "FBIOGET_VSCREENINFO: %s\n", av_err2str(ret
));
95 if (ioctl(fbdev
->fd
, FBIOGET_FSCREENINFO
, &fbdev
->fixinfo
) < 0) {
97 av_log(avctx
, AV_LOG_ERROR
,
98 "FBIOGET_FSCREENINFO: %s\n", av_err2str(ret
));
102 pix_fmt
= ff_get_pixfmt_from_fb_varinfo(&fbdev
->varinfo
);
103 if (pix_fmt
== AV_PIX_FMT_NONE
) {
104 ret
= AVERROR(EINVAL
);
105 av_log(avctx
, AV_LOG_ERROR
,
106 "Framebuffer pixel format not supported.\n");
110 fbdev
->width
= fbdev
->varinfo
.xres
;
111 fbdev
->height
= fbdev
->varinfo
.yres
;
112 fbdev
->bytes_per_pixel
= (fbdev
->varinfo
.bits_per_pixel
+ 7) >> 3;
113 fbdev
->frame_linesize
= fbdev
->width
* fbdev
->bytes_per_pixel
;
114 fbdev
->frame_size
= fbdev
->frame_linesize
* fbdev
->height
;
115 fbdev
->time_frame
= AV_NOPTS_VALUE
;
116 fbdev
->data
= mmap(NULL
, fbdev
->fixinfo
.smem_len
, PROT_READ
, MAP_SHARED
, fbdev
->fd
, 0);
117 if (fbdev
->data
== MAP_FAILED
) {
118 ret
= AVERROR(errno
);
119 av_log(avctx
, AV_LOG_ERROR
, "Error in mmap(): %s\n", av_err2str(ret
));
123 st
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
124 st
->codec
->codec_id
= AV_CODEC_ID_RAWVIDEO
;
125 st
->codec
->width
= fbdev
->width
;
126 st
->codec
->height
= fbdev
->height
;
127 st
->codec
->pix_fmt
= pix_fmt
;
128 st
->codec
->time_base
= av_inv_q(fbdev
->framerate_q
);
129 st
->codec
->bit_rate
=
130 fbdev
->width
* fbdev
->height
* fbdev
->bytes_per_pixel
* av_q2d(fbdev
->framerate_q
) * 8;
132 av_log(avctx
, AV_LOG_INFO
,
133 "w:%d h:%d bpp:%d pixfmt:%s fps:%d/%d bit_rate:%d\n",
134 fbdev
->width
, fbdev
->height
, fbdev
->varinfo
.bits_per_pixel
,
135 av_get_pix_fmt_name(pix_fmt
),
136 fbdev
->framerate_q
.num
, fbdev
->framerate_q
.den
,
137 st
->codec
->bit_rate
);
145 static int fbdev_read_packet(AVFormatContext
*avctx
, AVPacket
*pkt
)
147 FBDevContext
*fbdev
= avctx
->priv_data
;
148 int64_t curtime
, delay
;
153 if (fbdev
->time_frame
== AV_NOPTS_VALUE
)
154 fbdev
->time_frame
= av_gettime();
156 /* wait based on the frame rate */
158 curtime
= av_gettime();
159 delay
= fbdev
->time_frame
- curtime
;
161 "time_frame:%"PRId64
" curtime:%"PRId64
" delay:%"PRId64
"\n",
162 fbdev
->time_frame
, curtime
, delay
);
164 fbdev
->time_frame
+= INT64_C(1000000) / av_q2d(fbdev
->framerate_q
);
167 if (avctx
->flags
& AVFMT_FLAG_NONBLOCK
)
168 return AVERROR(EAGAIN
);
169 ts
.tv_sec
= delay
/ 1000000;
170 ts
.tv_nsec
= (delay
% 1000000) * 1000;
171 while (nanosleep(&ts
, &ts
) < 0 && errno
== EINTR
);
174 if ((ret
= av_new_packet(pkt
, fbdev
->frame_size
)) < 0)
177 /* refresh fbdev->varinfo, visible data position may change at each call */
178 if (ioctl(fbdev
->fd
, FBIOGET_VSCREENINFO
, &fbdev
->varinfo
) < 0)
179 av_log(avctx
, AV_LOG_WARNING
,
180 "Error refreshing variable info: %s\n", av_err2str(ret
));
184 /* compute visible data offset */
185 pin
= fbdev
->data
+ fbdev
->bytes_per_pixel
* fbdev
->varinfo
.xoffset
+
186 fbdev
->varinfo
.yoffset
* fbdev
->fixinfo
.line_length
;
189 for (i
= 0; i
< fbdev
->height
; i
++) {
190 memcpy(pout
, pin
, fbdev
->frame_linesize
);
191 pin
+= fbdev
->fixinfo
.line_length
;
192 pout
+= fbdev
->frame_linesize
;
195 return fbdev
->frame_size
;
198 static av_cold
int fbdev_read_close(AVFormatContext
*avctx
)
200 FBDevContext
*fbdev
= avctx
->priv_data
;
202 munmap(fbdev
->data
, fbdev
->fixinfo
.smem_len
);
208 static int fbdev_get_device_list(AVFormatContext
*s
, AVDeviceInfoList
*device_list
)
210 return ff_fbdev_get_device_list(device_list
);
213 #define OFFSET(x) offsetof(FBDevContext, x)
214 #define DEC AV_OPT_FLAG_DECODING_PARAM
215 static const AVOption options
[] = {
216 { "framerate","", OFFSET(framerate_q
), AV_OPT_TYPE_VIDEO_RATE
, {.str
= "25"}, 0, 0, DEC
},
220 static const AVClass fbdev_class
= {
221 .class_name
= "fbdev indev",
222 .item_name
= av_default_item_name
,
224 .version
= LIBAVUTIL_VERSION_INT
,
225 .category
= AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT
,
228 AVInputFormat ff_fbdev_demuxer
= {
230 .long_name
= NULL_IF_CONFIG_SMALL("Linux framebuffer"),
231 .priv_data_size
= sizeof(FBDevContext
),
232 .read_header
= fbdev_read_header
,
233 .read_packet
= fbdev_read_packet
,
234 .read_close
= fbdev_read_close
,
235 .get_device_list
= fbdev_get_device_list
,
236 .flags
= AVFMT_NOFILE
,
237 .priv_class
= &fbdev_class
,