Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
authorLuca Abeni <lucabe72@email.it>
Wed, 14 Feb 2007 13:25:24 +0000 (13:25 +0000)
committerLuca Abeni <lucabe72@email.it>
Wed, 14 Feb 2007 13:25:24 +0000 (13:25 +0000)
and copying the frame into it (remove a memcpy())

Originally committed as revision 7981 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavformat/v4l2.c

index b169066..5f669bd 100644 (file)
@@ -59,6 +59,11 @@ struct video_data {
     unsigned int *buf_len;
 };
 
+struct buff_data {
+    int index;
+    int fd;
+};
+
 struct fmt_map {
     enum PixelFormat ff_fmt;
     int32_t v4l2_fmt;
@@ -293,10 +298,32 @@ static int read_init(AVFormatContext *ctx)
     return -1;
 }
 
-static int mmap_read_frame(AVFormatContext *ctx, void *frame, int64_t *ts)
+static void mmap_release_buffer(AVPacket *pkt)
+{
+    struct v4l2_buffer buf;
+    int res, fd;
+    struct buff_data *buf_descriptor = pkt->priv;
+
+    memset(&buf, 0, sizeof(struct v4l2_buffer));
+    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    buf.memory = V4L2_MEMORY_MMAP;
+    buf.index = buf_descriptor->index;
+    fd = buf_descriptor->fd;
+    av_free(buf_descriptor);
+
+    res = ioctl (fd, VIDIOC_QBUF, &buf);
+    if (res < 0) {
+        av_log(NULL, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF)\n");
+    }
+    pkt->data = NULL;
+    pkt->size = 0;
+}
+
+static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt)
 {
     struct video_data *s = ctx->priv_data;
     struct v4l2_buffer buf;
+    struct buff_data *buf_descriptor;
     int res;
 
     memset(&buf, 0, sizeof(struct v4l2_buffer));
@@ -319,20 +346,28 @@ static int mmap_read_frame(AVFormatContext *ctx, void *frame, int64_t *ts)
     }
 
     /* Image is at s->buff_start[buf.index] */
-    memcpy(frame, s->buf_start[buf.index], buf.bytesused);
-    *ts = buf.timestamp.tv_sec * INT64_C(1000000) + buf.timestamp.tv_usec;
-
-    res = ioctl (s->fd, VIDIOC_QBUF, &buf);
-    if (res < 0) {
-        av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF)\n");
+    pkt->data= s->buf_start[buf.index];
+    pkt->size = buf.bytesused;
+    pkt->pts = buf.timestamp.tv_sec * INT64_C(1000000) + buf.timestamp.tv_usec;
+    pkt->destruct = mmap_release_buffer;
+    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 = ioctl (s->fd, VIDIOC_QBUF, &buf);
 
         return -1;
     }
+    buf_descriptor->fd = s->fd;
+    buf_descriptor->index = buf.index;
+    pkt->priv = buf_descriptor;
 
     return s->buf_len[buf.index];
 }
 
-static int read_frame(AVFormatContext *ctx, void *frame, int64_t *ts)
+static int read_frame(AVFormatContext *ctx, AVPacket *pkt)
 {
     return -1;
 }
@@ -500,13 +535,14 @@ static int v4l2_read_packet(AVFormatContext *s1, AVPacket *pkt)
     struct video_data *s = s1->priv_data;
     int res;
 
-    if (av_new_packet(pkt, s->frame_size) < 0)
-        return AVERROR_IO;
-
     if (s->io_method == io_mmap) {
-        res = mmap_read_frame(s1, pkt->data, &pkt->pts);
+        av_init_packet(pkt);
+        res = mmap_read_frame(s1, pkt);
     } else if (s->io_method == io_read) {
-        res = read_frame(s1, pkt->data, &pkt->pts);
+        if (av_new_packet(pkt, s->frame_size) < 0)
+            return AVERROR_IO;
+
+        res = read_frame(s1, pkt);
     } else {
         return AVERROR_IO;
     }