summaryrefslogtreecommitdiff
path: root/ffmpeg/libavdevice/v4l2.c
diff options
context:
space:
mode:
Diffstat (limited to 'ffmpeg/libavdevice/v4l2.c')
-rw-r--r--ffmpeg/libavdevice/v4l2.c248
1 files changed, 96 insertions, 152 deletions
diff --git a/ffmpeg/libavdevice/v4l2.c b/ffmpeg/libavdevice/v4l2.c
index 2d7773a..cb962b7 100644
--- a/ffmpeg/libavdevice/v4l2.c
+++ b/ffmpeg/libavdevice/v4l2.c
@@ -30,44 +30,10 @@
* V4L2_PIX_FMT_* and AV_PIX_FMT_*
*/
-#undef __STRICT_ANSI__ //workaround due to broken kernel headers
-#include "config.h"
-#include "libavformat/internal.h"
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#if HAVE_SYS_VIDEOIO_H
-#include <sys/videoio.h>
-#else
-#if HAVE_ASM_TYPES_H
-#include <asm/types.h>
-#endif
-#include <linux/videodev2.h>
-#endif
-#include "libavutil/atomic.h"
-#include "libavutil/avassert.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/log.h"
-#include "libavutil/opt.h"
-#include "avdevice.h"
-#include "timefilter.h"
-#include "libavutil/parseutils.h"
-#include "libavutil/pixdesc.h"
-#include "libavutil/time.h"
-#include "libavutil/avstring.h"
+#include "v4l2-common.h"
#if CONFIG_LIBV4L2
#include <libv4l2.h>
-#else
-#define v4l2_open open
-#define v4l2_close close
-#define v4l2_dup dup
-#define v4l2_ioctl ioctl
-#define v4l2_read read
-#define v4l2_mmap mmap
-#define v4l2_munmap munmap
#endif
static const int desired_video_buffers = 256;
@@ -121,6 +87,15 @@ struct video_data {
int list_format; /**< Set by a private option. */
int list_standard; /**< Set by a private option. */
char *framerate; /**< Set by a private option. */
+
+ int use_libv4l2;
+ int (*open_f)(const char *file, int oflag, ...);
+ int (*close_f)(int fd);
+ int (*dup_f)(int fd);
+ int (*ioctl_f)(int fd, unsigned long int request, ...);
+ ssize_t (*read_f)(int fd, void *buffer, size_t n);
+ void *(*mmap_f)(void *start, size_t length, int prot, int flags, int fd, int64_t offset);
+ int (*munmap_f)(void *_start, size_t length);
};
struct buff_data {
@@ -128,52 +103,43 @@ struct buff_data {
int index;
};
-struct fmt_map {
- enum AVPixelFormat ff_fmt;
- enum AVCodecID codec_id;
- uint32_t v4l2_fmt;
-};
-
-static struct fmt_map fmt_conversion_table[] = {
- //ff_fmt codec_id v4l2_fmt
- { AV_PIX_FMT_YUV420P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV420 },
- { AV_PIX_FMT_YUV420P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YVU420 },
- { AV_PIX_FMT_YUV422P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV422P },
- { AV_PIX_FMT_YUYV422, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUYV },
- { AV_PIX_FMT_UYVY422, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_UYVY },
- { AV_PIX_FMT_YUV411P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV411P },
- { AV_PIX_FMT_YUV410P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV410 },
- { AV_PIX_FMT_YUV410P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YVU410 },
- { AV_PIX_FMT_RGB555LE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB555 },
- { AV_PIX_FMT_RGB555BE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB555X },
- { AV_PIX_FMT_RGB565LE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB565 },
- { AV_PIX_FMT_RGB565BE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB565X },
- { AV_PIX_FMT_BGR24, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_BGR24 },
- { AV_PIX_FMT_RGB24, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB24 },
- { AV_PIX_FMT_BGR0, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_BGR32 },
- { AV_PIX_FMT_0RGB, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB32 },
- { AV_PIX_FMT_GRAY8, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_GREY },
-#ifdef V4L2_PIX_FMT_Y16
- { AV_PIX_FMT_GRAY16LE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_Y16 },
-#endif
- { AV_PIX_FMT_NV12, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_NV12 },
- { AV_PIX_FMT_NONE, AV_CODEC_ID_MJPEG, V4L2_PIX_FMT_MJPEG },
- { AV_PIX_FMT_NONE, AV_CODEC_ID_MJPEG, V4L2_PIX_FMT_JPEG },
-#ifdef V4L2_PIX_FMT_H264
- { AV_PIX_FMT_NONE, AV_CODEC_ID_H264, V4L2_PIX_FMT_H264 },
-#endif
-#ifdef V4L2_PIX_FMT_CPIA1
- { AV_PIX_FMT_NONE, AV_CODEC_ID_CPIA, V4L2_PIX_FMT_CPIA1 },
-#endif
-};
-
static int device_open(AVFormatContext *ctx)
{
+ struct video_data *s = ctx->priv_data;
struct v4l2_capability cap;
int fd;
int ret;
int flags = O_RDWR;
+#define SET_WRAPPERS(prefix) do { \
+ s->open_f = prefix ## open; \
+ s->close_f = prefix ## close; \
+ s->dup_f = prefix ## dup; \
+ s->ioctl_f = prefix ## ioctl; \
+ s->read_f = prefix ## read; \
+ s->mmap_f = prefix ## mmap; \
+ s->munmap_f = prefix ## munmap; \
+} while (0)
+
+ if (s->use_libv4l2) {
+#if CONFIG_LIBV4L2
+ SET_WRAPPERS(v4l2_);
+#else
+ av_log(ctx, AV_LOG_ERROR, "libavdevice is not build with libv4l2 support.\n");
+ return AVERROR(EINVAL);
+#endif
+ } else {
+ SET_WRAPPERS();
+ }
+
+#define v4l2_open s->open_f
+#define v4l2_close s->close_f
+#define v4l2_dup s->dup_f
+#define v4l2_ioctl s->ioctl_f
+#define v4l2_read s->read_f
+#define v4l2_mmap s->mmap_f
+#define v4l2_munmap s->munmap_f
+
if (ctx->flags & AVFMT_FLAG_NONBLOCK) {
flags |= O_NONBLOCK;
}
@@ -259,7 +225,7 @@ static int device_init(AVFormatContext *ctx, int *width, int *height,
return res;
}
-static int first_field(int fd)
+static int first_field(const struct video_data *s, int fd)
{
int res;
v4l2_std_id std;
@@ -275,55 +241,13 @@ static int first_field(int fd)
return 1;
}
-static uint32_t fmt_ff2v4l(enum AVPixelFormat pix_fmt, enum AVCodecID codec_id)
-{
- int i;
-
- for (i = 0; i < FF_ARRAY_ELEMS(fmt_conversion_table); i++) {
- if ((codec_id == AV_CODEC_ID_NONE ||
- fmt_conversion_table[i].codec_id == codec_id) &&
- (pix_fmt == AV_PIX_FMT_NONE ||
- fmt_conversion_table[i].ff_fmt == pix_fmt)) {
- return fmt_conversion_table[i].v4l2_fmt;
- }
- }
-
- return 0;
-}
-
-static enum AVPixelFormat fmt_v4l2ff(uint32_t v4l2_fmt, enum AVCodecID codec_id)
-{
- int i;
-
- for (i = 0; i < FF_ARRAY_ELEMS(fmt_conversion_table); i++) {
- if (fmt_conversion_table[i].v4l2_fmt == v4l2_fmt &&
- fmt_conversion_table[i].codec_id == codec_id) {
- return fmt_conversion_table[i].ff_fmt;
- }
- }
-
- return AV_PIX_FMT_NONE;
-}
-
-static enum AVCodecID fmt_v4l2codec(uint32_t v4l2_fmt)
-{
- int i;
-
- for (i = 0; i < FF_ARRAY_ELEMS(fmt_conversion_table); i++) {
- if (fmt_conversion_table[i].v4l2_fmt == v4l2_fmt) {
- return fmt_conversion_table[i].codec_id;
- }
- }
-
- return AV_CODEC_ID_NONE;
-}
-
#if HAVE_STRUCT_V4L2_FRMIVALENUM_DISCRETE
static void list_framesizes(AVFormatContext *ctx, int fd, uint32_t pixelformat)
{
+ const struct video_data *s = ctx->priv_data;
struct v4l2_frmsizeenum vfse = { .pixel_format = pixelformat };
- while(!ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &vfse)) {
+ while(!v4l2_ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &vfse)) {
switch (vfse.type) {
case V4L2_FRMSIZE_TYPE_DISCRETE:
av_log(ctx, AV_LOG_INFO, " %ux%u",
@@ -346,11 +270,12 @@ static void list_framesizes(AVFormatContext *ctx, int fd, uint32_t pixelformat)
static void list_formats(AVFormatContext *ctx, int fd, int type)
{
+ const struct video_data *s = ctx->priv_data;
struct v4l2_fmtdesc vfd = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
- while(!ioctl(fd, VIDIOC_ENUM_FMT, &vfd)) {
- enum AVCodecID codec_id = fmt_v4l2codec(vfd.pixelformat);
- enum AVPixelFormat pix_fmt = fmt_v4l2ff(vfd.pixelformat, codec_id);
+ while(!v4l2_ioctl(fd, VIDIOC_ENUM_FMT, &vfd)) {
+ enum AVCodecID codec_id = avpriv_fmt_v4l2codec(vfd.pixelformat);
+ enum AVPixelFormat pix_fmt = avpriv_fmt_v4l2ff(vfd.pixelformat, codec_id);
vfd.index++;
@@ -371,10 +296,8 @@ static void list_formats(AVFormatContext *ctx, int fd, int type)
}
#ifdef V4L2_FMT_FLAG_EMULATED
- if (vfd.flags & V4L2_FMT_FLAG_EMULATED) {
- av_log(ctx, AV_LOG_WARNING, "%s", "Emulated");
- continue;
- }
+ if (vfd.flags & V4L2_FMT_FLAG_EMULATED)
+ av_log(ctx, AV_LOG_INFO, " Emulated :");
#endif
#if HAVE_STRUCT_V4L2_FRMIVALENUM_DISCRETE
list_framesizes(ctx, fd, vfd.pixelformat);
@@ -402,8 +325,8 @@ static void list_standards(AVFormatContext *ctx)
return;
}
}
- av_log(ctx, AV_LOG_INFO, "%2d, %16llx, %s\n",
- standard.index, standard.id, standard.name);
+ av_log(ctx, AV_LOG_INFO, "%2d, %16"PRIx64", %s\n",
+ standard.index, (uint64_t)standard.id, standard.name);
}
}
@@ -532,6 +455,8 @@ static int init_convert_timestamp(AVFormatContext *ctx, int64_t ts)
av_log(ctx, AV_LOG_INFO, "Detected monotonic timestamps, converting\n");
/* microseconds instead of seconds, MHz instead of Hz */
s->timefilter = ff_timefilter_new(1, period, 1.0E-6);
+ if (!s->timefilter)
+ return AVERROR(ENOMEM);
s->ts_mode = V4L_TS_CONVERT_READY;
return 0;
}
@@ -605,7 +530,7 @@ static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt)
/* Image is at s->buff_start[buf.index] */
if (avpriv_atomic_int_get(&s->buffers_queued) == FFMAX(s->buffers / 8, 1)) {
- /* when we start getting low on queued buffers, fallback to copying data */
+ /* when we start getting low on queued buffers, fall back on copying data */
res = av_new_packet(pkt, buf.bytesused);
if (res < 0) {
av_log(ctx, AV_LOG_ERROR, "Error allocating a packet.\n");
@@ -628,7 +553,9 @@ static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt)
pkt->data = s->buf_start[buf.index];
pkt->size = buf.bytesused;
#if FF_API_DESTRUCT_PACKET
+FF_DISABLE_DEPRECATION_WARNINGS
pkt->destruct = dummy_release_buffer;
+FF_ENABLE_DEPRECATION_WARNINGS
#endif
buf_descriptor = av_malloc(sizeof(struct buff_data));
@@ -762,12 +689,16 @@ static int v4l2_set_parameters(AVFormatContext *s1)
standard.index = i;
if (v4l2_ioctl(s->fd, VIDIOC_ENUMSTD, &standard) < 0) {
ret = AVERROR(errno);
+ if (ret == AVERROR(EINVAL)) {
+ tpf = &streamparm.parm.capture.timeperframe;
+ break;
+ }
av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_ENUMSTD): %s\n", av_err2str(ret));
return ret;
}
if (standard.id == s->std_id) {
av_log(s1, AV_LOG_DEBUG,
- "Current standard: %s, id: %"PRIu64", frameperiod: %d/%d\n",
+ "Current standard: %s, id: %"PRIx64", frameperiod: %d/%d\n",
standard.name, (uint64_t)standard.id, tpf->numerator, tpf->denominator);
break;
}
@@ -827,7 +758,7 @@ static int device_try_init(AVFormatContext *s1,
{
int ret, i;
- *desired_format = fmt_ff2v4l(pix_fmt, s1->video_codec_id);
+ *desired_format = avpriv_fmt_ff2v4l(pix_fmt, s1->video_codec_id);
if (*desired_format) {
ret = device_init(s1, width, height, *desired_format);
@@ -839,14 +770,14 @@ static int device_try_init(AVFormatContext *s1,
}
if (!*desired_format) {
- for (i = 0; i<FF_ARRAY_ELEMS(fmt_conversion_table); i++) {
+ for (i = 0; avpriv_fmt_conversion_table[i].codec_id != AV_CODEC_ID_NONE; i++) {
if (s1->video_codec_id == AV_CODEC_ID_NONE ||
- fmt_conversion_table[i].codec_id == s1->video_codec_id) {
+ avpriv_fmt_conversion_table[i].codec_id == s1->video_codec_id) {
av_log(s1, AV_LOG_DEBUG, "Trying to set codec:%s pix_fmt:%s\n",
- avcodec_get_name(fmt_conversion_table[i].codec_id),
- (char *)av_x_if_null(av_get_pix_fmt_name(fmt_conversion_table[i].ff_fmt), "none"));
+ avcodec_get_name(avpriv_fmt_conversion_table[i].codec_id),
+ (char *)av_x_if_null(av_get_pix_fmt_name(avpriv_fmt_conversion_table[i].ff_fmt), "none"));
- *desired_format = fmt_conversion_table[i].v4l2_fmt;
+ *desired_format = avpriv_fmt_conversion_table[i].v4l2_fmt;
ret = device_init(s1, width, height, *desired_format);
if (ret >= 0)
break;
@@ -865,7 +796,7 @@ static int device_try_init(AVFormatContext *s1,
}
}
- *codec_id = fmt_v4l2codec(*desired_format);
+ *codec_id = avpriv_fmt_v4l2codec(*desired_format);
av_assert0(*codec_id != AV_CODEC_ID_NONE);
return ret;
}
@@ -887,21 +818,32 @@ static int v4l2_read_header(AVFormatContext *s1)
#if CONFIG_LIBV4L2
/* silence libv4l2 logging. if fopen() fails v4l2_log_file will be NULL
and errors will get sent to stderr */
- v4l2_log_file = fopen("/dev/null", "w");
+ if (s->use_libv4l2)
+ v4l2_log_file = fopen("/dev/null", "w");
#endif
s->fd = device_open(s1);
if (s->fd < 0)
return s->fd;
- /* set tv video input */
- av_log(s1, AV_LOG_DEBUG, "Selecting input_channel: %d\n", s->channel);
- if (v4l2_ioctl(s->fd, VIDIOC_S_INPUT, &s->channel) < 0) {
- res = AVERROR(errno);
- av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_S_INPUT): %s\n", av_err2str(res));
- return res;
+ if (s->channel != -1) {
+ /* set video input */
+ av_log(s1, AV_LOG_DEBUG, "Selecting input_channel: %d\n", s->channel);
+ if (v4l2_ioctl(s->fd, VIDIOC_S_INPUT, &s->channel) < 0) {
+ res = AVERROR(errno);
+ av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_S_INPUT): %s\n", av_err2str(res));
+ return res;
+ }
+ } else {
+ /* get current video input */
+ if (v4l2_ioctl(s->fd, VIDIOC_G_INPUT, &s->channel) < 0) {
+ res = AVERROR(errno);
+ av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_G_INPUT): %s\n", av_err2str(res));
+ return res;
+ }
}
+ /* enum input */
input.index = s->channel;
if (v4l2_ioctl(s->fd, VIDIOC_ENUMINPUT, &input) < 0) {
res = AVERROR(errno);
@@ -909,8 +851,8 @@ static int v4l2_read_header(AVFormatContext *s1)
return res;
}
s->std_id = input.std;
- av_log(s1, AV_LOG_DEBUG, "input_channel: %d, input_name: %s\n",
- s->channel, input.name);
+ av_log(s1, AV_LOG_DEBUG, "Current input_channel: %d, input_name: %s, input_std: %"PRIx64"\n",
+ s->channel, input.name, (uint64_t)input.std);
if (s->list_format) {
list_formats(s1, s->fd, s->list_format);
@@ -941,11 +883,10 @@ static int v4l2_read_header(AVFormatContext *s1)
}
if (!s->width && !s->height) {
- struct v4l2_format fmt;
+ struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
av_log(s1, AV_LOG_VERBOSE,
"Querying the device for the current frame size\n");
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (v4l2_ioctl(s->fd, VIDIOC_G_FMT, &fmt) < 0) {
res = AVERROR(errno);
av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_G_FMT): %s\n", av_err2str(res));
@@ -979,7 +920,7 @@ static int v4l2_read_header(AVFormatContext *s1)
if ((res = v4l2_set_parameters(s1)) < 0)
return res;
- st->codec->pix_fmt = fmt_v4l2ff(desired_format, codec_id);
+ st->codec->pix_fmt = avpriv_fmt_v4l2ff(desired_format, codec_id);
s->frame_size =
avpicture_get_size(st->codec->pix_fmt, s->width, s->height);
@@ -989,13 +930,16 @@ static int v4l2_read_header(AVFormatContext *s1)
return res;
}
- s->top_field_first = first_field(s->fd);
+ s->top_field_first = first_field(s, s->fd);
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = codec_id;
if (codec_id == AV_CODEC_ID_RAWVIDEO)
st->codec->codec_tag =
avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt);
+ else if (codec_id == AV_CODEC_ID_H264) {
+ st->need_parsing = AVSTREAM_PARSE_HEADERS;
+ }
if (desired_format == V4L2_PIX_FMT_YVU420)
st->codec->codec_tag = MKTAG('Y', 'V', '1', '2');
else if (desired_format == V4L2_PIX_FMT_YVU410)
@@ -1045,7 +989,7 @@ static int v4l2_read_close(AVFormatContext *s1)
static const AVOption options[] = {
{ "standard", "set TV standard, used only by analog frame grabber", OFFSET(standard), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC },
- { "channel", "set TV channel, used only by frame grabber", OFFSET(channel), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, DEC },
+ { "channel", "set TV channel, used only by frame grabber", OFFSET(channel), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, INT_MAX, DEC },
{ "video_size", "set frame size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
{ "pixel_format", "set preferred pixel format", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
{ "input_format", "set preferred pixel format (for raw video) or codec name", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
@@ -1064,7 +1008,7 @@ static const AVOption options[] = {
{ "default", "use timestamps from the kernel", OFFSET(ts_mode), AV_OPT_TYPE_CONST, {.i64 = V4L_TS_DEFAULT }, 0, 2, DEC, "timestamps" },
{ "abs", "use absolute timestamps (wall clock)", OFFSET(ts_mode), AV_OPT_TYPE_CONST, {.i64 = V4L_TS_ABS }, 0, 2, DEC, "timestamps" },
{ "mono2abs", "force conversion from monotonic to absolute timestamps", OFFSET(ts_mode), AV_OPT_TYPE_CONST, {.i64 = V4L_TS_MONO2ABS }, 0, 2, DEC, "timestamps" },
-
+ { "use_libv4l2", "use libv4l2 (v4l-utils) convertion functions", OFFSET(use_libv4l2), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC },
{ NULL },
};