diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2013-03-08 17:28:42 +0100 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2013-03-08 19:12:03 +0100 |
commit | 2653e125204569b1e9439ee2671c6ebb23a94b80 (patch) | |
tree | 4176f76bccc8cdd1c85b9d329a82867eda37d397 /libavdevice | |
parent | 532f31a695c9530ce67a847be00d72e6e8acfd11 (diff) | |
parent | 1afddbe59e96af75f1c07605afc95615569f388f (diff) | |
download | ffmpeg-2653e125204569b1e9439ee2671c6ebb23a94b80.tar.gz |
Merge commit '1afddbe59e96af75f1c07605afc95615569f388f'
* commit '1afddbe59e96af75f1c07605afc95615569f388f':
avpacket: use AVBuffer to allow refcounting the packets.
Conflicts:
libavcodec/avpacket.c
libavcodec/utils.c
libavdevice/v4l2.c
libavformat/avidec.c
libavformat/flacdec.c
libavformat/id3v2.c
libavformat/matroskaenc.c
libavformat/mux.c
libavformat/utils.c
Merged-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavdevice')
-rw-r--r-- | libavdevice/v4l2.c | 147 |
1 files changed, 75 insertions, 72 deletions
diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c index 6726b0b89f..14306bd1a2 100644 --- a/libavdevice/v4l2.c +++ b/libavdevice/v4l2.c @@ -46,6 +46,7 @@ #endif #include <linux/videodev2.h> #endif +#include "libavutil/atomic.h" #include "libavutil/avassert.h" #include "libavutil/imgutils.h" #include "libavutil/log.h" @@ -109,9 +110,9 @@ struct video_data { int64_t last_time_m; int buffers; + volatile int buffers_queued; void **buf_start; unsigned int *buf_len; - int *buf_dequeued; char *standard; v4l2_std_id std_id; int channel; @@ -122,9 +123,9 @@ struct video_data { }; struct buff_data { + struct video_data *s; int index; int fd; - int *buf_dequeued; }; struct fmt_map { @@ -438,11 +439,6 @@ static int mmap_init(AVFormatContext *ctx) av_free(s->buf_start); return AVERROR(ENOMEM); } - s->buf_dequeued = av_mallocz(sizeof(int) * s->buffers); - if (s->buf_dequeued == NULL) { - av_log(ctx, AV_LOG_ERROR, "Cannot allocate buffer array\n"); - return AVERROR(ENOMEM); - } for (i = 0; i < req.count; i++) { struct v4l2_buffer buf = { @@ -477,40 +473,33 @@ static int mmap_init(AVFormatContext *ctx) return 0; } -static int enqueue_buffer(int fd, int index) +#if FF_API_DESTRUCT_PACKET +static void dummy_release_buffer(AVPacket *pkt) +{ + av_assert0(0); +} +#endif + +static void mmap_release_buffer(void *opaque, uint8_t *data) { - int res; struct v4l2_buffer buf = { 0 }; + int res, fd; + struct buff_data *buf_descriptor = opaque; + struct video_data *s = buf_descriptor->s; - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; - buf.index = index; + buf.index = buf_descriptor->index; + fd = buf_descriptor->fd; + av_free(buf_descriptor); if (v4l2_ioctl(fd, VIDIOC_QBUF, &buf) < 0) { res = AVERROR(errno); - av_log(NULL, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n", av_err2str(res)); - return res; + av_log(NULL, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n", + av_err2str(res)); } - return 0; -} -static void mmap_release_buffer(AVPacket *pkt) -{ - struct buff_data *buf_descriptor = pkt->priv; - - if (pkt->data == NULL) - return; - - if (buf_descriptor->index == -1) { - av_free(pkt->data); - } else { - if (!enqueue_buffer(buf_descriptor->fd, buf_descriptor->index)) - buf_descriptor->buf_dequeued[buf_descriptor->index] = 0; - } - av_free(buf_descriptor); - - pkt->data = NULL; - pkt->size = 0; + avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1); } #if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC) @@ -580,14 +569,15 @@ static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt) .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .memory = V4L2_MEMORY_MMAP }; - struct buff_data *buf_descriptor; - int res, i, free_buffers; + int res; /* FIXME: Some special treatment might be needed in case of loss of signal... */ while ((res = v4l2_ioctl(s->fd, VIDIOC_DQBUF, &buf)) < 0 && (errno == EINTR)); if (res < 0) { - if (errno == EAGAIN) + if (errno == EAGAIN) { + pkt->size = 0; return AVERROR(EAGAIN); + } res = AVERROR(errno); av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_DQBUF): %s\n", av_err2str(res)); return res; @@ -597,6 +587,9 @@ static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt) av_log(ctx, AV_LOG_ERROR, "Invalid buffer index received.\n"); return AVERROR(EINVAL); } + avpriv_atomic_int_add_and_fetch(&s->buffers_queued, -1); + // always keep at least one buffer queued + av_assert0(avpriv_atomic_int_get(&s->buffers_queued) >= 1); /* CPIA is a compressed format and we don't know the exact number of bytes * used by a frame, so set it here as the driver announces it. @@ -608,50 +601,58 @@ static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt) av_log(ctx, AV_LOG_ERROR, "The v4l2 frame is %d bytes, but %d bytes are expected\n", buf.bytesused, s->frame_size); - enqueue_buffer(s->fd, buf.index); return AVERROR_INVALIDDATA; } - buf_descriptor = av_malloc(sizeof(struct buff_data)); - if (buf_descriptor == NULL) { - /* Something went wrong... Since av_malloc() failed, we cannot even - * allocate a buffer for memcopying into it - */ - av_log(ctx, AV_LOG_ERROR, "Failed to allocate a buffer descriptor\n"); - res = v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf); - return AVERROR(ENOMEM); - } - buf_descriptor->fd = s->fd; - buf_descriptor->buf_dequeued = s->buf_dequeued; - - free_buffers = -1; /* start from -1 because we just dequeued a buffer */ - for (i = 0; i < s->buffers; i++) - if (s->buf_dequeued[i] == 0) - free_buffers++; - - if (free_buffers == 0) { - if ((res = av_new_packet(pkt, buf.bytesused)) < 0) { - enqueue_buffer(s->fd, buf.index); + /* 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 */ + res = av_new_packet(pkt, buf.bytesused); + if (res < 0) { + av_log(ctx, AV_LOG_ERROR, "Error allocating a packet.\n"); return res; } memcpy(pkt->data, s->buf_start[buf.index], buf.bytesused); - enqueue_buffer(s->fd, buf.index); - buf_descriptor->index = -1; + + res = v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf); + if (res < 0) { + av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF)\n"); + av_free_packet(pkt); + return AVERROR(errno); + } + avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1); } else { - /* Image is at s->buff_start[buf.index] */ - pkt->data = s->buf_start[buf.index]; + struct buff_data *buf_descriptor; + + pkt->data = s->buf_start[buf.index]; + pkt->size = buf.bytesused; +#if FF_API_DESTRUCT_PACKET + pkt->destruct = dummy_release_buffer; +#endif + + buf_descriptor = av_malloc(sizeof(struct buff_data)); + if (buf_descriptor == NULL) { + /* Something went wrong... Since av_malloc() failed, we cannot even + * allocate a buffer for memcpying into it + */ + av_log(ctx, AV_LOG_ERROR, "Failed to allocate a buffer descriptor\n"); + res = v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf); + + return AVERROR(ENOMEM); + } + buf_descriptor->fd = s->fd; buf_descriptor->index = buf.index; - buf_descriptor->buf_dequeued[buf.index] = 1; + buf_descriptor->s = s; + + pkt->buf = av_buffer_create(pkt->data, pkt->size, mmap_release_buffer, + buf_descriptor, 0); + if (!pkt->buf) { + av_freep(&buf_descriptor); + return AVERROR(ENOMEM); + } } - pkt->size = buf.bytesused; - pkt->priv = buf_descriptor; - pkt->destruct = mmap_release_buffer; pkt->pts = buf.timestamp.tv_sec * INT64_C(1000000) + buf.timestamp.tv_usec; - res = convert_timestamp(ctx, &pkt->pts); - if (res < 0) { - mmap_release_buffer(pkt); - return res; - } + convert_timestamp(ctx, &pkt->pts); return s->buf_len[buf.index]; } @@ -675,6 +676,7 @@ static int mmap_start(AVFormatContext *ctx) return res; } } + s->buffers_queued = s->buffers; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (v4l2_ioctl(s->fd, VIDIOC_STREAMON, &type) < 0) { @@ -701,7 +703,6 @@ static void mmap_close(struct video_data *s) } av_free(s->buf_start); av_free(s->buf_len); - av_free(s->buf_dequeued); } static int v4l2_set_parameters(AVFormatContext *s1) @@ -1003,8 +1004,6 @@ static int v4l2_read_packet(AVFormatContext *s1, AVPacket *pkt) int res; av_init_packet(pkt); - pkt->data = NULL; - pkt->size = 0; if ((res = mmap_read_frame(s1, pkt)) < 0) { return res; } @@ -1021,6 +1020,10 @@ static int v4l2_read_close(AVFormatContext *s1) { struct video_data *s = s1->priv_data; + if (avpriv_atomic_int_get(&s->buffers_queued) != s->buffers) + av_log(s1, AV_LOG_WARNING, "Some buffers are still owned by the caller on " + "close.\n"); + mmap_close(s); v4l2_close(s->fd); |