diff options
| author | Tim Redfern <tim@eclectronics.org> | 2013-12-29 12:19:38 +0000 |
|---|---|---|
| committer | Tim Redfern <tim@eclectronics.org> | 2013-12-29 12:19:38 +0000 |
| commit | f7813a5324be39d13ab536c245d15dfc602a7849 (patch) | |
| tree | fad99148b88823d34a5df2f0a25881a002eb291b /ffmpeg/libavdevice/v4l2.c | |
| parent | b7a5a477b8ff4d4e3028b9dfb9a9df0a41463f92 (diff) | |
basic type mechanism working
Diffstat (limited to 'ffmpeg/libavdevice/v4l2.c')
| -rw-r--r-- | ffmpeg/libavdevice/v4l2.c | 248 |
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 }, }; |
