[FFmpeg-devel] Unix "fileno" libavformat module

William Ahern william
Tue Jul 10 03:05:58 CEST 2007


Attached is a provider to libavformat. It provides capabilities similar to
what once was the [independent] pipe module (I'm new to FFmpeg). But, it
supports seek() on the input and eventually will support seek() on output,
as much as is reasonably possible. Basically, rather than assuming a "pipe"
per se, it assumes a file descriptor to an entirely unknown resource type
given by the literal file descriptor number, and tries its best to provide
what's necessary. It could be a PF_LOCAL/SOCK_DGRAM socket, from which it
might--in the future--use that info for interesting purposes. (BTW,
/dev/stdin/NNNN isn't useful to me, because of chroot() and many other
issues.)

I'm currently using it to input H.263 and AMR (from decoded RTP channels)
into FFmpeg, retrieving FLV as ouput.

The URI format looks like `fileno://3'.

I can provide a proper patch (including avio.h and build diffs) once I
import my development tree into local version control.

I'll get output seeking working, as I'll need to also get 3GP and eventually
generic MPEG-4 output muxing. Those currently seem to break for me since the
"pipe" module doesn't support seeking.

Also, I put an LGPL 3 header on this file. I don't mean to start anything;
just let me know if I need to use an LGPL 2 header.

- Bill
-------------- next part --------------
/* 
 * Unix "fileno" I/O for libavformat, FFmpeg.
 *
 * Copyright (c) 2007 RemoTV, Inc. (William Ahern <wahern at remotv.com>)
 * 
 * This file is part of FFmpeg.
 * 
 * FFmpeg is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation; either version 3 of the License, or (at your
 * option) any later version.
 *                     
 * FFmpeg is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
 * more details.
 *                                     
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#if 0
#include <stdio.h>	/* stderr fputs(3) fprintf(3) */
#endif

#include <stddef.h>	/* NULL */
#include <stdlib.h>	/* strtoul(3) */

#include <limits.h>	/* INT_MAX ULONG_MAX */ 

#include <errno.h>	/* ENOMEM EINVAL ERANGE */

#include <string.h>	/* strncmp(3) */

#include <sys/param.h>	/* MIN */

#include <unistd.h>	/* read(2) write(2) close(2) */

#include "avformat.h"


#define MARK	fprintf(stderr, "@@ %d\n", __LINE__)


#define BUF_RLEN(b)	((b)->w.pos - (b)->r.pos)
#define BUF_WLEN(b)	((b)->end - (b)->w.pos)

typedef struct {
	int fd;

	struct {
		unsigned char base[65536];

		struct {
			unsigned char *pos;
		} r, w;

		unsigned char *end;
	} rbuf;
} FilenoContext;


static int fileno_open(URLContext *h, const char *uri, int flags) {
	FilenoContext *s;
	struct { const char *pos; char *end; } src;
	unsigned long lu;

	if (0 == (s = av_malloc(sizeof *s)))
		return -ENOMEM;

	s->rbuf.end	= &s->rbuf.base[sizeof s->rbuf.base];
	s->rbuf.r.pos	= s->rbuf.base;
	s->rbuf.w.pos	= s->rbuf.base;

	h->priv_data	= s;

	if (0 != strncmp(uri, "fileno://", sizeof "fileno://" - 1))
		return -EINVAL;

	src.pos	= uri + sizeof "fileno://" - 1;

	lu	= strtoul(src.pos, &src.end, 10);

	if ((lu == ULONG_MAX && errno == ERANGE) || lu > INT_MAX)
		return -EINVAL;

	s->fd	= lu;

	return 0;
} /* fileno_open() */


static int fileno_read(URLContext *h, uint8_t *buf, int size) {
	FilenoContext *s = h->priv_data;
	int n;

retry:
	/* Read from buffer. */
	if (BUF_RLEN(&s->rbuf) > 0) {
		size	= MIN(size, BUF_RLEN(&s->rbuf));

		(void)memcpy(buf, s->rbuf.r.pos, size);
		s->rbuf.r.pos	+= size;

		return size;
	}

	/* Fill buffer. */
	if  (BUF_WLEN(&s->rbuf) > 0) {
		n	= read(s->fd, s->rbuf.w.pos, BUF_WLEN(&s->rbuf));

		if (n <= 0)
			return n;

		s->rbuf.w.pos	+= n;

		goto retry;
	}

	/* We've shot past our ability to buffer. Do raw I/O, now. */
	return read(s->fd, buf, size);
} /* fileno_read() */


static int fileno_write(URLContext *h, uint8_t *buf, int size) {
	FilenoContext *s = h->priv_data;

	return write(s->fd, buf, size);
} /* fileno_write() */


static offset_t fileno_seek(URLContext *h, offset_t off, int whence) {
	const char *how[]	= {
		[SEEK_SET]	= "SEEK_SET",
		[SEEK_CUR]	= "SEEK_CUR",
		[SEEK_END]	= "SEEK_END",
		[AVSEEK_SIZE]	= "AVSEEK_SIZE",
	};

	FilenoContext *s = h->priv_data;

	if (whence == AVSEEK_SIZE)
		return -1;
	if (whence == SEEK_CUR || whence == SEEK_END)
		return -1;
	if (BUF_WLEN(&s->rbuf) == 0 && BUF_RLEN(&s->rbuf) == 0)
		return -1;	/* We've already read too far. */
	if (off > sizeof s->rbuf.base || off > (s->rbuf.w.pos - s->rbuf.base))
		return -1;	/* We can't seek past the buffer (or can we?). */
	if (off < -1)
		return -1;	/* But they specified "SEEK_SET". */

	s->rbuf.r.pos	= s->rbuf.base + off;

	return 0;
} /* fileno_seek() */


static int fileno_close(URLContext *h) {
	FilenoContext *s = h->priv_data;

	(void)close(s->fd);

	av_free(s);

	return 0;
} /* fileno_close() */


URLProtocol fileno_protocol = {
	"fileno",
	fileno_open,
	fileno_read,
	fileno_write,
	fileno_seek,
	fileno_close,
}; /* fileno_protocol */



More information about the ffmpeg-devel mailing list