[FFmpeg-devel] [PATCH] Suggested Patch for "Memory" Protocol
Michel Bardiaux
mbardiaux
Wed May 2 17:55:37 CEST 2007
Lagrange Multiplier wrote:
> Greetings,
>
> Would the ffmpeg development team consider including the following patch to support a "mem" protocol? The "mem" protocol simply uses RAM as a source for input multimedia data, akin to how the "file" and "pipe" protocols use filesystem files and pipes as sources.
>
> While this patch would be particularly useful for embedded systems (in particular, ones with DSPs that partially or fully encode multimedia data rather than "frame-grabber"-type systems), I'm sure one can see the general applicability as well... The modifications consist mostly of the addition of libavformat/mem.c, but I've included some C++ compatability wrapping for some of the internal headers as well.
>
> Thanks for your time...
>
> - LM
Apart from technical remarks below, there is a general problem: most
embedded systems, and many apps, will *already* have their own
memory-buffer system, probly incompatible with, and much more developped
than, the minimal one proposed. I have been using a mem protocol since
2003, but exactly for that reason I have never proposed it for inclusion.
> ------------------------------------------------------------------------
>
> diff -Naur before/ffmpeg/libavcodec/opt.h after/ffmpeg/libavcodec/opt.h
> --- before/ffmpeg/libavcodec/opt.h 2007-01-21 07:32:01.000000000 -0500
> +++ after/ffmpeg/libavcodec/opt.h 2007-01-29 09:32:45.000000000 -0500
> @@ -22,6 +22,10 @@
> #ifndef AVOPT_H
> #define AVOPT_H
>
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
Please remove all these. They are actually irrelevant to the topic, so
they should be moved to an entirely separate patch.
[snip]
> diff -Naur before/ffmpeg/libavformat/avio.h after/ffmpeg/libavformat/avio.h
> --- before/ffmpeg/libavformat/avio.h 2007-01-14 17:07:19.000000000 -0500
> +++ after/ffmpeg/libavformat/avio.h 2007-01-29 09:15:40.000000000 -0500
> @@ -196,6 +196,18 @@
> extern URLProtocol file_protocol;
> extern URLProtocol pipe_protocol;
>
> +/* mem.c */
> +extern URLProtocol mem_protocol;
> +
> +#define MEMORY_TRANSFER_METHOD "mem:"
> +
> +typedef struct
> +{
> + char transferMethod[4];
> + char* buffer;
> + unsigned int length;
> +} MemoryBufferSpecifier;
This should be strictly private to mem.c, I think.
> +
> /* udp.c */
> extern URLProtocol udp_protocol;
> int udp_set_remote_url(URLContext *h, const char *uri);
[snip]
> diff -Naur before/ffmpeg/libavformat/Makefile after/ffmpeg/libavformat/Makefile
> --- before/ffmpeg/libavformat/Makefile 2007-01-24 19:34:38.000000000 -0500
> +++ after/ffmpeg/libavformat/Makefile 2007-01-29 09:16:16.000000000 -0500
> @@ -159,7 +159,7 @@
> OBJS+= avio.o aviobuf.o
>
> ifeq ($(CONFIG_PROTOCOLS),yes)
> -OBJS+= file.o
> +OBJS+= file.o mem.o
> ifeq ($(CONFIG_NETWORK),yes)
> OBJS+= udp.o tcp.o http.o rtsp.o rtp.o rtpproto.o mpegts.o base64.o rtp_h264.o
> endif
> diff -Naur before/ffmpeg/libavformat/mem.c after/ffmpeg/libavformat/mem.c
> --- before/ffmpeg/libavformat/mem.c 1969-12-31 19:00:00.000000000 -0500
> +++ after/ffmpeg/libavformat/mem.c 2007-01-29 10:11:26.000000000 -0500
> @@ -0,0 +1,161 @@
> +/*
> + * Buffered mem io for ffmpeg system
> + */
> +#include "avformat.h"
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <sys/time.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <errno.h>
> +
> +#define DEBUG 0
> +
> +typedef struct
> +{
> + void* which;
> + char* start;
> + char* end;
> + char* last;
> + int flags;
> +} MemoryBuffer;
> +
> +static int mem_open(URLContext *h, const char *filename, int flags)
> +{
> + MemoryBuffer* b = av_malloc(sizeof(MemoryBuffer));
> + MemoryBufferSpecifier* s = filename;
> +
> +#if DEBUG
> + fprintf(stderr, "mem_open(%p, %p, %d)\n", h, s->buffer, s->length);
> +#endif
This is NOT the correct way to print info, av_log has to be used.
> + b->which = h;
> + b->start = s->buffer;
> + b->end = &s->buffer[s->length];
> + b->last = b->start;
> + b->flags = flags;
> + h->priv_data = b;
> + return 0;
> +}
> +
> +static int mem_read(URLContext *h, unsigned char *buf, int size)
> +{
> + MemoryBuffer* b = (MemoryBuffer*) h->priv_data;
> + int bytes;
> +
> + if ((b->flags != URL_RDONLY) && (b->flags != URL_RDWR))
> + {
> + errno = EBADF;
> + return -1;
> + }
> + bytes = size;
> + if (&b->last[bytes] > b->end)
> + {
> + bytes = b->end - b->last;
> + }
> + memcpy(buf, b->last, bytes);
> + b->last = &b->last[bytes];
> +#if DEBUG
> + fprintf(stderr, "%d <- mem_read(%p, %d)\n", bytes, b->which, size);
> +#endif
> + return bytes;
> +}
> +
> +static int mem_write(URLContext *h, unsigned char *buf, int size)
> +{
> + MemoryBuffer* b = (MemoryBuffer*) h->priv_data;
> + int bytes;
> +
> + if ((b->flags != URL_WRONLY) && (b->flags != URL_RDWR))
> + {
> + errno = EBADF;
> + return -1;
> + }
> + bytes = size;
> + if (&b->last[bytes] > b->end)
> + {
> +#if DEBUG
> + fprintf(stderr, "NOSPC <- mem_write(%p, %d) into buffer of %d\n",
> + b->which,
> + size,
> + b->end - b->last);
> +#endif
> + errno = ENOSPC;
> + return -1;
> + }
> + memcpy(b->last, buf, bytes);
> + b->last = &b->last[bytes];
> +#if DEBUG
> + fprintf(stderr, "%d <- mem_write(%p, %d)\n", bytes, b->which, size);
> +#endif
> + return size;
> +}
With no option to automatically extend the buffer when needed?
> +
> +static offset_t mem_seek(URLContext *h, offset_t pos, int whence)
> +{
> + MemoryBuffer* b = (MemoryBuffer*) h->priv_data;
> + char* end;
> +
> + switch(whence)
> + {
> + case SEEK_SET:
> + end = &b->start[pos];
> + break;
> + case SEEK_CUR:
> + end = &b->last[pos];
> + break;
> + case SEEK_END:
> + end = &b->end[pos];
> + break;
> + default:
> + errno = EINVAL;
> + return -1;
> + }
> + if (end < b->start)
> + {
> + end = b->start;
> + }
> + if (end > b->end)
> + {
> + end = b->end;
> + }
> + b->last = end;
> +#if DEBUG
> + fprintf(stderr, "%d <- mem_seek(%p, %lld, %d)\n", b->last - b->start, b->which, pos, whence);
> +#endif
> + return b->last - b->start;
> +}
> +
> +static int mem_close(URLContext *h)
> +{
> + MemoryBuffer* b = (MemoryBuffer*) h->priv_data;
> +
> +#if DEBUG
> + fprintf(stderr, "mem_close(%p, %p/%p/%p)\n", b->which, b->start, b->last, b->end);
> +#endif
> + av_free(h->priv_data);
> + return 0;
> +}
> +
> +int mem_replenish(URLContext *h, const char *filename)
> +{
> + MemoryBuffer* b = (MemoryBuffer*) h->priv_data;
> + MemoryBufferSpecifier* s = filename;
> +
> +#if DEBUG
> + fprintf(stderr, "mem_replenish(%p, %p, %d)\n", h, s->buffer, s->length);
> +#endif
> + b->which = h;
> + b->start = s->buffer;
> + b->end = &s->buffer[s->length];
> + b->last = b->start;
> + return 0;
> +}
This is the most critical part, how the user fills buffers for ffmpeg,
or reads from buffers from ffmpeg. No documentation, and deliberately
unreadable code. If 'filename' is actually a pointer to user data, why
declare it char* filename instead of void* userdata, for Turing's sake?
> +
> +URLProtocol mem_protocol = {
> + "mem",
> + mem_open,
> + mem_read,
> + mem_write,
> + mem_seek,
> + mem_close,
> +};
> diff -Naur before/ffmpeg/libavutil/common.h after/ffmpeg/libavutil/common.h
> --- before/ffmpeg/libavutil/common.h 2007-01-12 23:01:35.000000000 -0500
> +++ after/ffmpeg/libavutil/common.h 2007-01-29 10:58:55.000000000 -0500
> @@ -23,8 +23,8 @@
> * common internal and external api header.
> */
>
> -#ifndef COMMON_H
> -#define COMMON_H
> +#ifndef FFMPEG_COMMON_H
> +#define FFMPEG_COMMON_H
Separate patch please.
>
> #include <inttypes.h>
>
> @@ -345,4 +345,4 @@
> char *av_strdup(const char *s);
> void av_freep(void *ptr);
>
> -#endif /* COMMON_H */
> +#endif /* FFMPEG_COMMON_H */
--
Michel Bardiaux
R&D Director
T +32 [0] 2 790 29 41
F +32 [0] 2 790 29 02
E mailto:mbardiaux at mediaxim.be
Mediaxim NV/SA
Vorstlaan 191 Boulevard du Souverain
Brussel 1160 Bruxelles
http://www.mediaxim.com/
More information about the ffmpeg-devel
mailing list