2 * *BSD video grab interface
3 * Copyright (c) 2002 Steve O'Hara-Smith
5 * Linux video grab interface
6 * Copyright (c) 2000, 2001 Fabrice Bellard
8 * simple_grab.c Copyright (c) 1999 Roger Hardiman
10 * This file is part of FFmpeg.
12 * FFmpeg is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * FFmpeg is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with FFmpeg; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "libavformat/internal.h"
28 #include "libavutil/internal.h"
29 #include "libavutil/log.h"
30 #include "libavutil/opt.h"
31 #include "libavutil/parseutils.h"
32 #include "libavutil/time.h"
33 #if HAVE_DEV_BKTR_IOCTL_METEOR_H && HAVE_DEV_BKTR_IOCTL_BT848_H
34 # include <dev/bktr/ioctl_meteor.h>
35 # include <dev/bktr/ioctl_bt848.h>
36 #elif HAVE_MACHINE_IOCTL_METEOR_H && HAVE_MACHINE_IOCTL_BT848_H
37 # include <machine/ioctl_meteor.h>
38 # include <machine/ioctl_bt848.h>
39 #elif HAVE_DEV_VIDEO_METEOR_IOCTL_METEOR_H && HAVE_DEV_VIDEO_BKTR_IOCTL_BT848_H
40 # include <dev/video/meteor/ioctl_meteor.h>
41 # include <dev/video/bktr/ioctl_bt848.h>
42 #elif HAVE_DEV_IC_BT8XX_H
43 # include <dev/ic/bt8xx.h>
47 #include <sys/ioctl.h>
54 typedef struct VideoData
{
61 char *framerate
; /**< Set by a private option. */
74 /* PAL is 768 x 576. NTSC is 640 x 480 */
75 #define PAL_HEIGHT 576
76 #define SECAM_HEIGHT 576
77 #define NTSC_HEIGHT 480
80 #define VIDEO_FORMAT NTSC
83 static const int bktr_dev
[] = { METEOR_DEV0
, METEOR_DEV1
, METEOR_DEV2
,
84 METEOR_DEV3
, METEOR_DEV_SVIDEO
};
87 size_t video_buf_size
;
88 uint64_t last_frame_time
;
89 volatile sig_atomic_t nsignals
;
92 static void catchsignal(int signal
)
98 static av_cold
int bktr_init(const char *video_device
, int width
, int height
,
99 int format
, int *video_fd
, int *tuner_fd
, int idev
, double frequency
)
101 struct meteor_geomet geo
;
103 long ioctl_frequency
;
106 struct sigaction act
= { {0} }, old
;
108 if (idev
< 0 || idev
> 4)
110 arg
= getenv ("BKTR_DEV");
113 if (idev
< 0 || idev
> 4)
117 if (format
< 1 || format
> 6)
119 arg
= getenv ("BKTR_FORMAT");
122 if (format
< 1 || format
> 6)
123 format
= VIDEO_FORMAT
;
128 arg
= getenv ("BKTR_FREQUENCY");
130 frequency
= atof (arg
);
135 sigemptyset(&act
.sa_mask
);
136 act
.sa_handler
= catchsignal
;
137 sigaction(SIGUSR1
, &act
, &old
);
139 *tuner_fd
= avpriv_open("/dev/tuner0", O_RDONLY
);
141 av_log(NULL
, AV_LOG_ERROR
, "Warning. Tuner not opened, continuing: %s\n", strerror(errno
));
143 *video_fd
= avpriv_open(video_device
, O_RDONLY
);
145 av_log(NULL
, AV_LOG_ERROR
, "%s: %s\n", video_device
, strerror(errno
));
152 geo
.oformat
= METEOR_GEO_YUV_422
| METEOR_GEO_YUV_12
;
155 case PAL
: h_max
= PAL_HEIGHT
; c
= BT848_IFORM_F_PALBDGHI
; break;
156 case PALN
: h_max
= PAL_HEIGHT
; c
= BT848_IFORM_F_PALN
; break;
157 case PALM
: h_max
= PAL_HEIGHT
; c
= BT848_IFORM_F_PALM
; break;
158 case SECAM
: h_max
= SECAM_HEIGHT
; c
= BT848_IFORM_F_SECAM
; break;
159 case NTSC
: h_max
= NTSC_HEIGHT
; c
= BT848_IFORM_F_NTSCM
; break;
160 case NTSCJ
: h_max
= NTSC_HEIGHT
; c
= BT848_IFORM_F_NTSCJ
; break;
161 default: h_max
= PAL_HEIGHT
; c
= BT848_IFORM_F_PALBDGHI
; break;
164 if (height
<= h_max
/ 2)
165 geo
.oformat
|= METEOR_GEO_EVEN_ONLY
;
167 if (ioctl(*video_fd
, METEORSETGEO
, &geo
) < 0) {
168 av_log(NULL
, AV_LOG_ERROR
, "METEORSETGEO: %s\n", strerror(errno
));
172 if (ioctl(*video_fd
, BT848SFMT
, &c
) < 0) {
173 av_log(NULL
, AV_LOG_ERROR
, "BT848SFMT: %s\n", strerror(errno
));
178 if (ioctl(*video_fd
, METEORSINPUT
, &c
) < 0) {
179 av_log(NULL
, AV_LOG_ERROR
, "METEORSINPUT: %s\n", strerror(errno
));
183 video_buf_size
= width
* height
* 12 / 8;
185 video_buf
= (uint8_t *)mmap((caddr_t
)0, video_buf_size
,
186 PROT_READ
, MAP_SHARED
, *video_fd
, (off_t
)0);
187 if (video_buf
== MAP_FAILED
) {
188 av_log(NULL
, AV_LOG_ERROR
, "mmap: %s\n", strerror(errno
));
192 if (frequency
!= 0.0) {
193 ioctl_frequency
= (unsigned long)(frequency
*16);
194 if (ioctl(*tuner_fd
, TVTUNER_SETFREQ
, &ioctl_frequency
) < 0)
195 av_log(NULL
, AV_LOG_ERROR
, "TVTUNER_SETFREQ: %s\n", strerror(errno
));
199 if (ioctl(*tuner_fd
, BT848_SAUDIO
, &c
) < 0)
200 av_log(NULL
, AV_LOG_ERROR
, "TVTUNER_SAUDIO: %s\n", strerror(errno
));
202 c
= METEOR_CAP_CONTINOUS
;
203 ioctl(*video_fd
, METEORCAPTUR
, &c
);
206 ioctl(*video_fd
, METEORSSIGNAL
, &c
);
211 static void bktr_getframe(uint64_t per_frame
)
215 curtime
= av_gettime();
217 || ((last_frame_time
+ per_frame
) > curtime
)) {
218 if (!usleep(last_frame_time
+ per_frame
+ per_frame
/ 8 - curtime
)) {
220 av_log(NULL
, AV_LOG_INFO
,
221 "SLEPT NO signals - %d microseconds late\n",
222 (int)(av_gettime() - last_frame_time
- per_frame
));
226 last_frame_time
= curtime
;
230 /* note: we support only one picture read at a time */
231 static int grab_read_packet(AVFormatContext
*s1
, AVPacket
*pkt
)
233 VideoData
*s
= s1
->priv_data
;
235 if (av_new_packet(pkt
, video_buf_size
) < 0)
238 bktr_getframe(s
->per_frame
);
240 pkt
->pts
= av_gettime();
241 memcpy(pkt
->data
, video_buf
, video_buf_size
);
243 return video_buf_size
;
246 static int grab_read_header(AVFormatContext
*s1
)
248 VideoData
*s
= s1
->priv_data
;
250 AVRational framerate
;
254 switch (s
->standard
) {
255 case PAL
: s
->framerate
= av_strdup("pal"); break;
256 case NTSC
: s
->framerate
= av_strdup("ntsc"); break;
257 case SECAM
: s
->framerate
= av_strdup("25"); break;
259 av_log(s1
, AV_LOG_ERROR
, "Unknown standard.\n");
260 ret
= AVERROR(EINVAL
);
263 if ((ret
= av_parse_video_rate(&framerate
, s
->framerate
)) < 0) {
264 av_log(s1
, AV_LOG_ERROR
, "Could not parse framerate '%s'.\n", s
->framerate
);
268 st
= avformat_new_stream(s1
, NULL
);
270 ret
= AVERROR(ENOMEM
);
273 avpriv_set_pts_info(st
, 64, 1, 1000000); /* 64 bits pts in use */
275 s
->per_frame
= ((uint64_t)1000000 * framerate
.den
) / framerate
.num
;
277 st
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
278 st
->codec
->pix_fmt
= AV_PIX_FMT_YUV420P
;
279 st
->codec
->codec_id
= AV_CODEC_ID_RAWVIDEO
;
280 st
->codec
->width
= s
->width
;
281 st
->codec
->height
= s
->height
;
282 st
->codec
->time_base
.den
= framerate
.num
;
283 st
->codec
->time_base
.num
= framerate
.den
;
286 if (bktr_init(s1
->filename
, s
->width
, s
->height
, s
->standard
,
287 &s
->video_fd
, &s
->tuner_fd
, -1, 0.0) < 0) {
299 static int grab_read_close(AVFormatContext
*s1
)
301 VideoData
*s
= s1
->priv_data
;
304 c
= METEOR_CAP_STOP_CONT
;
305 ioctl(s
->video_fd
, METEORCAPTUR
, &c
);
309 ioctl(s
->tuner_fd
, BT848_SAUDIO
, &c
);
312 munmap((caddr_t
)video_buf
, video_buf_size
);
317 #define OFFSET(x) offsetof(VideoData, x)
318 #define DEC AV_OPT_FLAG_DECODING_PARAM
319 static const AVOption options
[] = {
320 { "standard", "", offsetof(VideoData
, standard
), AV_OPT_TYPE_INT
, {.i64
= VIDEO_FORMAT
}, PAL
, NTSCJ
, AV_OPT_FLAG_DECODING_PARAM
, "standard" },
321 { "PAL", "", 0, AV_OPT_TYPE_CONST
, {.i64
= PAL
}, 0, 0, AV_OPT_FLAG_DECODING_PARAM
, "standard" },
322 { "NTSC", "", 0, AV_OPT_TYPE_CONST
, {.i64
= NTSC
}, 0, 0, AV_OPT_FLAG_DECODING_PARAM
, "standard" },
323 { "SECAM", "", 0, AV_OPT_TYPE_CONST
, {.i64
= SECAM
}, 0, 0, AV_OPT_FLAG_DECODING_PARAM
, "standard" },
324 { "PALN", "", 0, AV_OPT_TYPE_CONST
, {.i64
= PALN
}, 0, 0, AV_OPT_FLAG_DECODING_PARAM
, "standard" },
325 { "PALM", "", 0, AV_OPT_TYPE_CONST
, {.i64
= PALM
}, 0, 0, AV_OPT_FLAG_DECODING_PARAM
, "standard" },
326 { "NTSCJ", "", 0, AV_OPT_TYPE_CONST
, {.i64
= NTSCJ
}, 0, 0, AV_OPT_FLAG_DECODING_PARAM
, "standard" },
327 { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(width
), AV_OPT_TYPE_IMAGE_SIZE
, {.str
= "vga"}, 0, 0, DEC
},
328 { "framerate", "", OFFSET(framerate
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, DEC
},
332 static const AVClass bktr_class
= {
333 .class_name
= "BKTR grab interface",
334 .item_name
= av_default_item_name
,
336 .version
= LIBAVUTIL_VERSION_INT
,
337 .category
= AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT
,
340 AVInputFormat ff_bktr_demuxer
= {
342 .long_name
= NULL_IF_CONFIG_SMALL("video grab"),
343 .priv_data_size
= sizeof(VideoData
),
344 .read_header
= grab_read_header
,
345 .read_packet
= grab_read_packet
,
346 .read_close
= grab_read_close
,
347 .flags
= AVFMT_NOFILE
,
348 .priv_class
= &bktr_class
,