Commit de6d9b64 authored by Fabrice Bellard's avatar Fabrice Bellard

Initial revision


Originally committed as revision 5 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent 1b58d58d
version 0.4.5:
- some header fixes (Zdenek Kabelac <kabi@informatics.muni.cz>).
- many MMX optimizations (Nick Kurshev <nickols_k@mail.ru>).
- added configure system (actually a small shell script).
- added mpeg audio layer 1/2/3 decoding using LGPL'ed mpglib by
Michael Hipp (temporary solution - waiting for integer only
decoder).
- fixed VIDIOCSYNC interrupt.
- added Intel H263 decoding support ('I263' avi fourCC)
- added Real Video 1.0 decoding (needs further testing).
- simplified image formats again. Added PGM format (=grey
pgm). Renamed old PGM to PGMYUV.
- fixed msmpeg4 slice issues (tell me if you still find problems).
- fixed opendivx bugs with newer versions (added VOL header decoding).
- added support for mplayer interface.
version 0.4.4:
- fixed some std header definitions (Bjorn Lindgren
<bjorn.e.lindgren@telia.com>).
- added mpeg demux (mpeg 1 and 2 compatible).
- added ASF demux.
- added prototype RM demux.
- added AC3 decoding (done with libac3 by Aaron Holtzman).
- added decoding codec parameter guessing (.e.g. for mpeg, because the
header does not include them).
- fixed header generation in mpeg1, AVI and ASF mux : wmplayer can now
play them (only tested video).
- fixed h263 white bug.
- fixed phase rounding in img resample filter.
- add mmx code for polyphase img resample filter.
- added CPU autodetect.
- added generic title/author/copyright/comment string handling (ASF and RM use them).
- added SWF demux to extract MP3 track (not usable yet because no MP3
decoder).
- added fractional frame rate support.
- codecs are no longer searched by read_header() (should fix ffserver
segfault).
version 0.4.3:
- BGR24 patch (initial patch by Jeroen Vreeken <pe1rxq@amsat.org>).
- fixed raw yuv output.
- added motion rounding support in MPEG4.
- fixed motion bug rounding in MSMPEG4.
- added B frame handling in video core.
- added full MPEG1 decoding support.
- added partial (frame only) MPEG2 support.
- changed the FOURCC code for H.263 to "U263" to be able to see the
+AVI/H.263 file with the UB Video H.263+ decoder. MPlayer works with
this +codec ;) (JuanJo).
- Halfpel motion estimation after mb type selection (JuanJo).
- added pgm and .Y.U.V output format.
- suppressed 'img:' protocol. Simply use: /tmp/test%d.[pgm|Y] as input or
output.
- added pgmpipe I/O format (original patch from Martin Aumueller
<lists@reserv.at>, but changed completely since we use a format
instead of a protocol).
version 0.4.2:
- added H263/MPEG4/MSMPEG4 decoding support. MPEG4 decoding support
(for openDIVX) is almost complete: 8x8 MVs and rounding are
missing. MSMPEG4 support is complete.
- added prototype MPEG1 decoder. Only I and P frames handled yet (it
can decode ffmpeg mpegs :-)).
- added libavcodec API documentation (see apiexample.c).
- fixed image polyphase bug (the bottom of some images could be
greenish).
- added support for non clipped motion vectors (decoding only)
and image sizes non multiple of 16.
- added support for AC prediction (decoding only).
- added file overwrite confirmation (can be disabled with -y).
- Added custom size picture to H.263 using H.263+ (Juanjo).
version 0.4.1:
- added MSMPEG4 (aka DIVX) compatible encoder. Changed default codec
of avi and asf to DIV3.
- added -me option to set motion estimation method
(default=log). suppressed redundant -hq option.
- added options -acodec and -vcodec to force a given codec (useful for
AVI for example).
- fixed -an option.
- improved dct_quantize speed.
- factorized some motion estimation code.
version 0.4.0:
- removing grab code from ffserver and moved it to ffmpeg. Added multi
stream support to ffmpeg.
- added timeshifting support for live feeds (option ?date=xxx in the
URL).
- added high quality image resize code with polyphase filter (need
mmx/see optimisation). Enable multiple image size support in ffserver.
- added multi live feed support in ffserver.
- suppressed master feature from ffserver (it should be done with an
external program which opens the .ffm url and writes it to another
ffserver).
- added preliminary support for video stream parsing (wav and avi half
done). Added proper support for audio/video file convertion in
ffmpeg.
- added preliminary support for video file sending from ffserver.
- redesigning I/O subsystem : now using URL based input and output
(see avio.h).
- added wav format support.
- added "tty user interface" to ffmpeg to stop grabbing gracefully.
- added MMX/SSE optimizations to SAD (Sums of Absolutes Diferences)
(Juan J. Sierralta P. a.k.a. "Juanjo" <juanjo@atmlab.utfsm.cl>).
- added MMX DCT from mpeg2_movie 1.5 (Juanjo).
- added new motion estimation algorithms, log and phods (Juanjo).
- changed directories : libav for format handling, libavcodec for
codecs.
version 0.3.4:
- added stereo in mpeg audio encoder.
version 0.3.3:
- added 'high quality' mode which use motion vectors. It can be used in
real time at low resolution.
- fixed rounding problems which caused quality problems at high
bitrates and large gop size.
version 0.3.2: small fixes
- asf fixes
- put_seek bug fix
version 0.3.1: added avi/divx support
- added avi support
- added mpeg4 codec compatible with open divx. It is based on the h263
codec.
- added sound for flash format (not tested)
version 0.3: initial public release
1) Type './configure' create the configuration (use './configure
--help' to have the configure options).
2) Then type 'make' to build ffmpeg.
3) Type 'make install' to install ffmpeg and ffserver in
/usr/local/bin.
#!/bin/sh
# default parameters
prefix="/usr/local"
cc="gcc"
ar="ar"
cpu=`uname -m`
case "$cpu" in
i386|i486|i586|i686)
cpu="x86"
mmx="yes"
;;
*)
mmx="no"
;;
esac
gprof="no"
if [ "$1" = "-h" -o "$1" = "--help" ] ; then
cat << EOF
Usage: configure [options]
Options: [defaults in brackets after descriptions]
--help print this message
EOF
echo " --prefix=PREFIX install in PREFIX [$prefix]"
echo " --cc=CC use C compiler CC [$cc]"
echo " --cpu=CPU force cpu to CPU [$cpu]"
echo " --disable-mmx disable mmx usage"
echo " --enable-gprof enable profiling with gprof [$gprof]"
exit 1
fi
for opt do
case "$opt" in
--prefix=*) prefix=`echo $opt | cut -d '=' -f 2`
;;
--cc=*) cc=`echo $opt | cut -d '=' -f 2`
;;
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
;;
--disable-mmx) mmx="no"
;;
--enable-gprof) gprof="yes"
;;
esac
done
echo "Install prefix $prefix"
echo "C compiler $cc"
echo "CPU $cpu"
echo "MMX enabled $mmx"
echo "gprof enabled $gprof"
echo "Creating config.mk and config.h"
echo "# Automatically generated by configure - do not modify" > config.mk
echo "/* Automatically generated by configure - do not modify */" > config.h
echo "PREFIX=$prefix" >> config.mk
echo "CC=$cc" >> config.mk
echo "AR=$ar" >> config.mk
if [ "$cpu" = "x86" ] ; then
echo "CONFIG_CPU_X86=y" >> config.mk
echo "#define CONFIG_CPU_X86 1" >> config.h
fi
if [ "$mmx" = "yes" ] ; then
echo "CONFIG_MMX=y" >> config.mk
echo "#define CONFIG_MMX 1" >> config.h
fi
if [ "$gprof" = "yes" ] ; then
echo "CONFIG_GPROF=y" >> config.mk
echo "#define CONFIG_GPROF 1" >> config.h
fi
1) API
------
* libavcodec is the library containing the codecs (both encoding and
decoding). See libavcodec/apiexample.c to see how to use it.
* libav is the library containing the file formats handling (mux and
demux code for several formats). (no example yet, the API is likely
to evolve).
2) Coding Rules
---------------
ffmpeg is programmed in ANSI C language. GCC extension are
tolerated. TAB size is 4. The identation is the one specified by
'indent -i4 -kr'.
Main priority in ffmpeg is simplicity and small code size (=less
bugs).
source: MarsAttack, divx, 800 kbit/s
q=10 constant:
* full motion search, fcode=1, half pel:
Video: opendivx (hq), 640x352, 25 fps, 200 kb/s
frame= 500 q=10 size= 1815kB time=20.0 bitrate= 743.6kbits/s
* log motion search:
Video: opendivx (hq), 640x352, 25 fps, 200 kb/s
frame= 500 q=10 size= 1995kB time=20.0 bitrate= 817.2kbits/s
* no motion search:
Video: opendivx, 640x352, 25 fps, 200 kb/s
frame= 500 size= 3197kB time=20.0 fps=25.0 bitrate=1309.6kbits/s q=10
* log motion search:
Video: opendivx (hq), 640x352, 25 fps, 200 kb/s
frame= 500 q=10 size= 1995kB time=20.0 bitrate= 817.2kbits/s
./ffmpeg -me log -t 20 -g 100 -qscale 10 -i img:%d.pgm -an /tmp/b.avi
Stream #0.0: Video: msmpeg4, 640x352, 25 fps, 200 kb/s
frame= 500 q=10 size= 1833kB time=20.0 bitrate= 750.9kbits/s
./ffmpeg -me full -t 20 -g 100 -qscale 10 -i img:%d.pgm -an /tmp/b.avi
Stream #0.0: Video: msmpeg4, 640x352, 25 fps, 200 kb/s
frame= 500 q=10 size= 1793kB time=20.0 bitrate= 734.8kbits/s
-------------------------------------------
* with -sameq, -me log
./ffmpeg -g 100 -t 20 -sameq -i MarsAttacks_f800.avi -an /tmp/a.avi
Stream #0.0: Video: msmpeg4, 640x352, 25 fps, 200 kb/s
frame= 500 q= 5 size= 2605kB time=20.0 bitrate=1067.1kbits/s
./ffmpeg -g 100 -t 20 -sameq -i MarsAttacks_f800.avi -f mpeg1video -an /tmp/a.mpg
Stream #0.0: Video: mpeg1video, 640x352, 25 fps, 200 kb/s
frame= 500 q= 5 size= 2655kB time=20.0 bitrate=1087.7kbits/s
./ffmpeg -g 100 -t 20 -sameq -i MarsAttacks_f800.avi -vcodec opendivx -an /tmp/a.avi
frame= 500 q= 5 size= 2774kB time=20.0 bitrate=1136.2kbits/s
the matrix, complete, video only:
source=14147kB
ffmpeg:
mpeg1 17154kB (20%)
msmpeg4 17229kB
*************** FFserver live broadcast server *****************
0) Introduction
ffserver is a streaming server for both audio and video. It supports
several live feeds, streaming from files and time shifting on live
feeds (you can seek to positions in the past on each live feed,
provided you specify a big enough feed storage in ffserver.conf).
1) Quick help
- First you must ensure that your grab system is OK. Verify with
'xawtv' that your TV card is tuned on a correct video source.
- Try with ffmpeg that you can record correctly. For example:
ffmpeg /tmp/a.mpg
will record a ten seconds mpeg file from your TV card and audio
card. Use for example the mpegtv player or MPlayer to view the created
MPEG file.
- Launch ffserver on your PC with the sample config file:
ffserver -f doc/ffserver.conf
- Verify with your browser that ffserver is working correctly. For
that purpose, explore: http://localhost:8090/stat.html .
- Now launch ffmpeg to do real time encoding :
ffmpeg http://localhost:8090/feed1.ffm
- Then, use your favorite players to see each generated stream:
mtvp http://localhost:8090/test1.mpg
mpg123 http://localhost:8090/test.mp2
netscape http://localhost:8090/test.swf
realplayer http://localhost:8090/test.rm
etc...
Note that ffserver generate multiple streams in multiple formats AT
THE SAME TIME. It should be able to handle hundreds of users at the
same time if you internet connection is fast enough.
- Now you can configure ffserver for your real needs. Edit the
ffserver.conf file to use only the formats you want. Read the ffmpeg
documentation (ffmpeg.txt) to learn more about the codec and format
stuff.
- Report any bug you find (and the fix if you have it!).
2) URL Format
ffserver supports that you seek in some formats. The syntax is to
add a '?' option to the URL. Only the 'date' option is supported.
The date format is [YYYY-MM-DDT][[HH:]MM:]SS[.m...] (clost to ISO
date format). For live streams, the date is absolute and give in
GMT. If the day is not specified, the current day is used.
example:
mpg123 http://localhost:8090/test.mp2?date=10:00
play the stream starting at 10:00 AM GMT today.
mpg123 http://localhost:8090/test.mp2?date=2001-06-23T23:00
is also a valid date.
For file streams, the date is relative to the start of the file. No
day can be specified.
This diff is collapsed.
/*
* Linux audio play and grab interface
* Copyright (c) 2000, 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <linux/soundcard.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <errno.h>
#include <sys/time.h>
#include "avformat.h"
const char *audio_device = "/dev/dsp";
typedef struct {
int fd;
int rate;
int channels;
} AudioData;
#define AUDIO_BLOCK_SIZE 4096
/* audio read support */
static int audio_read(URLContext *h, UINT8 *buf, int size)
{
AudioData *s = h->priv_data;
int ret;
ret = read(s->fd, buf, size);
if (ret < 0)
return -errno;
else
return ret;
}
static int audio_write(URLContext *h, UINT8 *buf, int size)
{
AudioData *s = h->priv_data;
int ret;
ret = write(s->fd, buf, size);
if (ret < 0)
return -errno;
else
return ret;
}
static int audio_get_format(URLContext *h, URLFormat *f)
{
AudioData *s = h->priv_data;
strcpy(f->format_name, "pcm");
f->sample_rate = s->rate;
f->channels = s->channels;
return 0;
}
/* URI syntax: 'audio:[rate[,channels]]'
default: rate=44100, channels=2
*/
static int audio_open(URLContext *h, const char *uri, int flags)
{
AudioData *s;
const char *p;
int freq, channels, audio_fd;
int tmp, err;
h->is_streamed = 1;
h->packet_size = AUDIO_BLOCK_SIZE;
s = malloc(sizeof(AudioData));
if (!s)
return -ENOMEM;
h->priv_data = s;
/* extract parameters */
p = uri;
strstart(p, "audio:", &p);
freq = strtol(p, (char **)&p, 0);
if (freq <= 0)
freq = 44100;
if (*p == ',')
p++;
channels = strtol(p, (char **)&p, 0);
if (channels <= 0)
channels = 2;
s->rate = freq;
s->channels = channels;
/* open linux audio device */
if (flags & URL_WRONLY)
audio_fd = open(audio_device,O_WRONLY);
else
audio_fd = open(audio_device,O_RDONLY);
if (audio_fd < 0) {
perror(audio_device);
return -EIO;
}
/* non blocking mode */
fcntl(audio_fd, F_SETFL, O_NONBLOCK);
#if 0
tmp=(NB_FRAGMENTS << 16) | FRAGMENT_BITS;
err=ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &tmp);
if (err < 0) {
perror("SNDCTL_DSP_SETFRAGMENT");
}
#endif
tmp=AFMT_S16_LE;
err=ioctl(audio_fd,SNDCTL_DSP_SETFMT,&tmp);
if (err < 0) {
perror("SNDCTL_DSP_SETFMT");
goto fail;
}
tmp= (channels == 2);
err=ioctl(audio_fd,SNDCTL_DSP_STEREO,&tmp);
if (err < 0) {
perror("SNDCTL_DSP_STEREO");
goto fail;
}
tmp = freq;
err=ioctl(audio_fd, SNDCTL_DSP_SPEED, &tmp);
if (err < 0) {
perror("SNDCTL_DSP_SPEED");
goto fail;
}
s->rate = tmp;
s->fd = audio_fd;
return 0;
fail:
close(audio_fd);
free(s);
return -EIO;
}
static int audio_close(URLContext *h)
{
AudioData *s = h->priv_data;
close(s->fd);
free(s);
return 0;
}
URLProtocol audio_protocol = {
"audio",
audio_open,
audio_read,
audio_write,
NULL, /* seek */
audio_close,
audio_get_format,
};
#include "avcodec.h"
#define FFMPEG_VERSION "0.4.5"
#include "avio.h"
/* packet functions */
typedef struct AVPacket {
INT64 pts;
UINT8 *data;
int size;
int stream_index;
int flags;
#define PKT_FLAG_KEY 0x0001
} AVPacket;
int av_new_packet(AVPacket *pkt, int size);
void av_free_packet(AVPacket *pkt);
/*************************************************/
/* output formats */
struct AVFormatContext;
struct AVFormatInputContext;
typedef struct AVFormatParameters {
int frame_rate;
int sample_rate;
int channels;
int width;
int height;
int pix_fmt;
} AVFormatParameters;
typedef struct AVFormat {
const char *name;
const char *long_name;
const char *mime_type;
const char *extensions; /* comma separated extensions */
/* output support */
enum CodecID audio_codec; /* default audio codec */
enum CodecID video_codec; /* default video codec */
int (*write_header)(struct AVFormatContext *);
int (*write_packet)(struct AVFormatContext *,
int stream_index,
unsigned char *buf, int size);
int (*write_trailer)(struct AVFormatContext *);
/* optional input support */
/* read the format header and initialize the AVFormatInputContext
structure. Return 0 if OK. 'ap' if non NULL contains
additionnal paramters. Only used in raw format right now */
int (*read_header)(struct AVFormatContext *,
AVFormatParameters *ap);
/* read one packet and put it in 'pkt'. pts and flags are also set */
int (*read_packet)(struct AVFormatContext *, AVPacket *pkt);
/* close the stream. The AVFormatContext and AVStreams are not
freed by this function */
int (*read_close)(struct AVFormatContext *);
/* seek at or before a given pts (given in microsecond). The pts
origin is defined by the stream */
int (*read_seek)(struct AVFormatContext *, INT64 pts);
int flags;
#define AVFMT_NOFILE 0x0001 /* no file should be opened */
struct AVFormat *next;
} AVFormat;
typedef struct AVStream {
int id; /* internal stream id */
AVCodecContext codec; /* codec context */
void *priv_data;
} AVStream;
#define MAX_STREAMS 20
/* format I/O context */
typedef struct AVFormatContext {
struct AVFormat *format;
void *priv_data;
ByteIOContext pb;
int nb_streams;
AVStream *streams[MAX_STREAMS];
char filename[1024]; /* input or output filename */
/* stream info */
char title[512];
char author[512];
char copyright[512];
char comment[512];
/* This buffer is only needed when packets were already buffered but
not decoded, for example to get the codec parameters in mpeg
streams */
struct AVPacketList *packet_buffer;
} AVFormatContext;
typedef struct AVPacketList {
AVPacket pkt;
struct AVPacketList *next;
} AVPacketList;
extern AVFormat *first_format;
/* rv10enc.c */
extern AVFormat rm_format;
/* mpegmux.c */
extern AVFormat mpeg_mux_format;
/* asfenc.c */
extern AVFormat asf_format;
/* avienc.c */
extern AVFormat avi_format;
/* jpegenc.c */
extern AVFormat mpjpeg_format;
extern AVFormat jpeg_format;
/* swfenc.c */
extern AVFormat swf_format;
/* wav.c */
extern AVFormat wav_format;
/* img.c */
extern AVFormat pgm_format;
extern AVFormat pgmyuv_format;
extern AVFormat imgyuv_format;
extern AVFormat pgmpipe_format;
/* raw.c */
extern AVFormat mp2_format;
extern AVFormat ac3_format;
extern AVFormat h263_format;
extern AVFormat mpeg1video_format;
extern AVFormat pcm_format;
extern AVFormat rawvideo_format;
/* ffm.c */
extern AVFormat ffm_format;
/* formats.c */
#define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
#define MKBETAG(a,b,c,d) (d | (c << 8) | (b << 16) | (a << 24))
void register_avformat(AVFormat *format);
AVFormat *guess_format(const char *short_name, const char *filename, const char *mime_type);
int strstart(const char *str, const char *val, const char **ptr);
void nstrcpy(char *buf, int buf_size, const char *str);
int match_ext(const char *filename, const char *extensions);
void register_all(void);
INT64 gettime(void);
typedef struct FifoBuffer {
UINT8 *buffer;
UINT8 *rptr, *wptr, *end;
} FifoBuffer;
int fifo_init(FifoBuffer *f, int size);
void fifo_free(FifoBuffer *f);
int fifo_size(FifoBuffer *f, UINT8 *rptr);
int fifo_read(FifoBuffer *f, UINT8 *buf, int buf_size, UINT8 **rptr_ptr);
void fifo_write(FifoBuffer *f, UINT8 *buf, int size, UINT8 **wptr_ptr);
AVFormatContext *av_open_input_file(const char *filename, int buf_size);
int av_read_packet(AVFormatContext *s, AVPacket *pkt);
void av_close_input_file(AVFormatContext *s);
int av_write_packet(AVFormatContext *s, AVPacket *pkt);
void dump_format(AVFormatContext *ic,
int index,
const char *url,
int is_output);
int parse_image_size(int *width_ptr, int *height_ptr, const char *str);
INT64 gettime(void);
INT64 parse_date(const char *datestr, int duration);
/* ffm specific for ffserver */
#define FFM_PACKET_SIZE 4096
offset_t ffm_read_write_index(int fd);
void ffm_write_write_index(int fd, offset_t pos);
void ffm_set_write_index(AVFormatContext *s, offset_t pos, offset_t file_size);
int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info);
#define AVIF_HASINDEX 0x00000010 // Index at end of file?
#define AVIF_MUSTUSEINDEX 0x00000020
#define AVIF_ISINTERLEAVED 0x00000100
#define AVIF_TRUSTCKTYPE 0x00000800 // Use CKType to find key frames?
#define AVIF_WASCAPTUREFILE 0x00010000
#define AVIF_COPYRIGHTED 0x00020000
offset_t start_tag(ByteIOContext *pb, char *tag);
void end_tag(ByteIOContext *pb, offset_t start);
void put_bmp_header(ByteIOContext *pb, AVCodecContext *enc);
void put_wav_header(ByteIOContext *pb, AVCodecContext *enc);
typedef struct CodecTag {
int id;
unsigned int tag;
} CodecTag;
extern CodecTag codec_bmp_tags[];
extern CodecTag codec_wav_tags[];
unsigned int codec_get_tag(CodecTag *tags, int id);
int codec_get_id(CodecTag *tags, unsigned int tag);
/* avidec.c */
int avi_read_header(AVFormatContext *s, AVFormatParameters *ap);
int avi_read_packet(AVFormatContext *s, AVPacket *pkt);
int avi_read_close(AVFormatContext *s);
/*
* AVI decoder.
* Copyright (c) 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include "avformat.h"
#include "avi.h"
//#define DEBUG
typedef struct AVIIndex {
unsigned char tag[4];
unsigned int flags, pos, len;
struct AVIIndex *next;
} AVIIndex;
typedef struct {
INT64 movi_end;
offset_t movi_list;
AVIIndex *first, *last;
} AVIContext;
#ifdef DEBUG
void print_tag(const char *str, unsigned int tag, int size)
{
printf("%s: tag=%c%c%c%c size=0x%x\n",
str, tag & 0xff,
(tag >> 8) & 0xff,
(tag >> 16) & 0xff,
(tag >> 24) & 0xff,
size);
}
#endif
int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
AVIContext *avi;
ByteIOContext *pb = &s->pb;
UINT32 tag, tag1;
int codec_type, stream_index, size, frame_period, bit_rate;
int i;
AVStream *st;
avi = malloc(sizeof(AVIContext));
if (!avi)
return -1;
memset(avi, 0, sizeof(AVIContext));
s->priv_data = avi;
/* check RIFF header */
tag = get_le32(pb);
if (tag != MKTAG('R', 'I', 'F', 'F'))
return -1;
get_le32(pb); /* file size */
tag = get_le32(pb);
if (tag != MKTAG('A', 'V', 'I', ' '))
return -1;
/* first list tag */
stream_index = -1;
codec_type = -1;
frame_period = 0;
for(;;) {
if (url_feof(pb))
goto fail;
tag = get_le32(pb);
size = get_le32(pb);
#ifdef DEBUG
print_tag("tag", tag, size);
#endif
switch(tag) {
case MKTAG('L', 'I', 'S', 'T'):
/* ignored, except when start of video packets */
tag1 = get_le32(pb);
#ifdef DEBUG
print_tag("list", tag1, 0);
#endif
if (tag1 == MKTAG('m', 'o', 'v', 'i')) {
avi->movi_end = url_ftell(pb) + size - 4;
#ifdef DEBUG
printf("movi end=%Lx\n", avi->movi_end);
#endif
goto end_of_header;
}
break;
case MKTAG('a', 'v', 'i', 'h'):
/* avi header */
frame_period = get_le32(pb);
bit_rate = get_le32(pb) * 8;
url_fskip(pb, 4 * 4);
s->nb_streams = get_le32(pb);
for(i=0;i<s->nb_streams;i++) {
AVStream *st;
st = malloc(sizeof(AVStream));
if (!st)
goto fail;
memset(st, 0, sizeof(AVStream));
s->streams[i] = st;
}
url_fskip(pb, size - 7 * 4);
break;
case MKTAG('s', 't', 'r', 'h'):
/* stream header */
stream_index++;
tag1 = get_le32(pb);
switch(tag1) {
case MKTAG('v', 'i', 'd', 's'):
codec_type = CODEC_TYPE_VIDEO;
get_le32(pb); /* codec tag */
get_le32(pb); /* flags */
get_le16(pb); /* priority */
get_le16(pb); /* language */
get_le32(pb); /* XXX: initial frame ? */
get_le32(pb); /* scale */
get_le32(pb); /* rate */
url_fskip(pb, size - 7 * 4);
break;
case MKTAG('a', 'u', 'd', 's'):
codec_type = CODEC_TYPE_AUDIO;
/* nothing really useful */
url_fskip(pb, size - 4);
break;
default:
goto fail;
}
break;
case MKTAG('s', 't', 'r', 'f'):
/* stream header */
if (stream_index >= s->nb_streams) {
url_fskip(pb, size);
} else {
st = s->streams[stream_index];
switch(codec_type) {
case CODEC_TYPE_VIDEO:
get_le32(pb); /* size */
st->codec.width = get_le32(pb);
st->codec.height = get_le32(pb);
if (frame_period)
st->codec.frame_rate = (1000000LL * FRAME_RATE_BASE) / frame_period;
else
st->codec.frame_rate = 25 * FRAME_RATE_BASE;
get_le16(pb); /* panes */
get_le16(pb); /* depth */
tag1 = get_le32(pb);
#ifdef DEBUG
print_tag("video", tag1, 0);
#endif
st->codec.codec_type = CODEC_TYPE_VIDEO;
st->codec.codec_tag = tag1;
st->codec.codec_id = codec_get_id(codec_bmp_tags, tag1);
url_fskip(pb, size - 5 * 4);
break;
case CODEC_TYPE_AUDIO:
tag1 = get_le16(pb);
st->codec.codec_type = CODEC_TYPE_AUDIO;
st->codec.codec_tag = tag1;
st->codec.codec_id = codec_get_id(codec_wav_tags, tag1);
#ifdef DEBUG
printf("audio: 0x%x\n", tag1);
#endif
st->codec.channels = get_le16(pb);
st->codec.sample_rate = get_le32(pb);
st->codec.bit_rate = get_le32(pb) * 8;
url_fskip(pb, size - 3 * 4);
break;
default:
url_fskip(pb, size);
break;
}
}
break;
default:
/* skip tag */
size += (size & 1);
url_fskip(pb, size);
break;
}
}
end_of_header:
/* check stream number */
if (stream_index != s->nb_streams - 1) {
fail:
for(i=0;i<s->nb_streams;i++) {
if (s->streams[i])
free(s->streams[i]);
}
return -1;
}
return 0;
}
int avi_read_packet(AVFormatContext *s, AVPacket *pkt)
{
AVIContext *avi = s->priv_data;
ByteIOContext *pb = &s->pb;
int n, d1, d2, size;
find_next:
if (url_feof(pb) || url_ftell(pb) >= avi->movi_end)
return -1;
d1 = get_byte(pb);
if (d1 < '0' || d1 > '9')
goto find_next;
d2 = get_byte(pb);
if (d2 < '0' || d2 > '9')
goto find_next;
n = (d1 - '0') * 10 + (d2 - '0');
if (n < 0 || n >= s->nb_streams)
goto find_next;
d1 = get_byte(pb);
d2 = get_byte(pb);
if ((d1 != 'd' && d2 != 'c') &&
(d1 != 'w' && d2 != 'b'))
goto find_next;
size = get_le32(pb);
av_new_packet(pkt, size);
pkt->stream_index = n;
get_buffer(pb, pkt->data, pkt->size);
if (size & 1)
get_byte(pb);
return 0;
}
int avi_read_close(AVFormatContext *s)
{
AVIContext *avi = s->priv_data;
free(avi);
return 0;
}
This diff is collapsed.
/*
* Unbuffered io for ffmpeg system
* Copyright (c) 2001 Gerard Lantau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "avformat.h"
URLProtocol *first_protocol = NULL;
int register_protocol(URLProtocol *protocol)
{
URLProtocol **p;
p = &first_protocol;
while (*p != NULL) p = &(*p)->next;
*p = protocol;
protocol->next = NULL;
return 0;
}
int url_open(URLContext **puc, const char *filename, int flags)
{
URLContext *uc;
URLProtocol *up;
const char *p;
char proto_str[128], *q;
int err;
p = filename;
q = proto_str;
while (*p != '\0' && *p != ':') {
if ((q - proto_str) < sizeof(proto_str) - 1)
*q++ = *p;
p++;
}
if (*p == '\0') {
strcpy(proto_str, "file");
} else {
*q = '\0';
}
up = first_protocol;
while (up != NULL) {
if (!strcmp(proto_str, up->name))
goto found;
up = up->next;
}
return -ENOENT;
found:
uc = malloc(sizeof(URLContext));
if (!uc)
return -ENOMEM;
uc->prot = up;
uc->flags = flags;
uc->is_streamed = 0; /* default = not streamed */
uc->packet_size = 1; /* default packet size */
err = up->url_open(uc, filename, flags);
if (err < 0) {
free(uc);
*puc = NULL;
return err;
}
*puc = uc;
return 0;
}
int url_read(URLContext *h, unsigned char *buf, int size)
{
int ret;
if (h->flags & URL_WRONLY)
return -EIO;
ret = h->prot->url_read(h, buf, size);
return ret;
}
int url_write(URLContext *h, unsigned char *buf, int size)
{
int ret;
if (!(h->flags & URL_WRONLY))
return -EIO;
ret = h->prot->url_write(h, buf, size);
return ret;
}
offset_t url_seek(URLContext *h, offset_t pos, int whence)
{
offset_t ret;
if (!h->prot->url_seek)
return -EPIPE;
ret = h->prot->url_seek(h, pos, whence);
return ret;
}
int url_getformat(URLContext *h, URLFormat *f)
{
memset(f, 0, sizeof(*f));
if (!h->prot->url_getformat)
return -ENODATA;
return h->prot->url_getformat(h, f);
}
int url_close(URLContext *h)
{
int ret;
ret = h->prot->url_close(h);
free(h);
return ret;
}
int url_exist(const char *filename)
{
URLContext *h;
if (url_open(&h, filename, URL_RDONLY) < 0)
return 0;
url_close(h);
return 1;
}
offset_t url_filesize(URLContext *h)
{
offset_t pos, size;
pos = url_seek(h, 0, SEEK_CUR);
size = url_seek(h, 0, SEEK_END);
url_seek(h, pos, SEEK_SET);
return size;
}
/* output byte stream handling */
typedef long long offset_t;
/* unbuffered I/O */
struct URLContext {
struct URLProtocol *prot;
int flags;
int is_streamed; /* true if streamed (no seek possible), default = false */
int packet_size;
void *priv_data;
};
typedef struct URLFormat {
char format_name[32];
int sample_rate;
int frame_rate;
int channels;
int height;
int width;
int pix_fmt;
} URLFormat;
typedef struct URLContext URLContext;
typedef struct URLPollEntry {
URLContext *handle;
int events;
int revents;
} URLPollEntry;
#define URL_RDONLY 0
#define URL_WRONLY 1
int url_open(URLContext **h, const char *filename, int flags);
int url_read(URLContext *h, unsigned char *buf, int size);
int url_write(URLContext *h, unsigned char *buf, int size);
offset_t url_seek(URLContext *h, offset_t pos, int whence);
int url_getformat(URLContext *h, URLFormat *f);
int url_close(URLContext *h);
int url_exist(const char *filename);
offset_t url_filesize(URLContext *h);
/* not implemented */
int url_poll(URLPollEntry *poll_table, int n, int timeout);
typedef struct URLProtocol {
const char *name;
int (*url_open)(URLContext *h, const char *filename, int flags);
int (*url_read)(URLContext *h, unsigned char *buf, int size);
int (*url_write)(URLContext *h, unsigned char *buf, int size);
offset_t (*url_seek)(URLContext *h, offset_t pos, int whence);
int (*url_close)(URLContext *h);
/* get precise information about the format, if available. return
-ENODATA if not available */
int (*url_getformat)(URLContext *h, URLFormat *f);
struct URLProtocol *next;
} URLProtocol;
extern URLProtocol *first_protocol;
int register_protocol(URLProtocol *protocol);
typedef struct {
unsigned char *buffer;
int buffer_size;
unsigned char *buf_ptr, *buf_end;
void *opaque;
int (*read_packet)(void *opaque, UINT8 *buf, int buf_size);
void (*write_packet)(void *opaque, UINT8 *buf, int buf_size);
int (*seek)(void *opaque, offset_t offset, int whence);
offset_t pos; /* position in the file of the current buffer */
int must_flush; /* true if the next seek should flush */
int eof_reached; /* true if eof reached */
int write_flag; /* true if open for writing */
int is_streamed;
int packet_size;
} ByteIOContext;
int init_put_byte(ByteIOContext *s,
unsigned char *buffer,
int buffer_size,
int write_flag,
void *opaque,
int (*read_packet)(void *opaque, UINT8 *buf, int buf_size),
void (*write_packet)(void *opaque, UINT8 *buf, int buf_size),
int (*seek)(void *opaque, offset_t offset, int whence));
void put_byte(ByteIOContext *s, int b);
void put_buffer(ByteIOContext *s, unsigned char *buf, int size);
void put_le64(ByteIOContext *s, unsigned long long val);
void put_be64(ByteIOContext *s, unsigned long long val);
void put_le32(ByteIOContext *s, unsigned int val);
void put_be32(ByteIOContext *s, unsigned int val);
void put_le16(ByteIOContext *s, unsigned int val);
void put_be16(ByteIOContext *s, unsigned int val);
void put_tag(ByteIOContext *s, char *tag);
offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence);
void url_fskip(ByteIOContext *s, offset_t offset);
offset_t url_ftell(ByteIOContext *s);
int url_feof(ByteIOContext *s);
void put_flush_packet(ByteIOContext *s);
int get_buffer(ByteIOContext *s, unsigned char *buf, int size);
int get_byte(ByteIOContext *s);
unsigned int get_le32(ByteIOContext *s);
unsigned long long get_le64(ByteIOContext *s);
unsigned int get_le16(ByteIOContext *s);
unsigned int get_be16(ByteIOContext *s);
unsigned int get_be32(ByteIOContext *s);
unsigned long long get_be64(ByteIOContext *s);
extern inline int url_is_streamed(ByteIOContext *s)
{
return s->is_streamed;
}
/* get the prefered packet size of the device. All I/Os should be done
by multiple of this size */
extern inline int url_get_packet_size(ByteIOContext *s)
{
return s->packet_size;
}
int url_fdopen(ByteIOContext *s, URLContext *h);
int url_setbufsize(ByteIOContext *s, int buf_size);
int url_fopen(ByteIOContext *s, const char *filename, int flags);
int url_fclose(ByteIOContext *s);
URLContext *url_fileno(ByteIOContext *s);
int url_open_buf(ByteIOContext *s, UINT8 *buf, int buf_size, int flags);
int url_close_buf(ByteIOContext *s);
/* file.c */
extern URLProtocol file_protocol;
extern URLProtocol pipe_protocol;
/* udp.c */
extern URLProtocol udp_protocol;
/* http.c */
extern URLProtocol http_protocol;
/* audio.c */
extern const char *audio_device;
extern URLProtocol audio_protocol;
/* grab.c */
extern const char *v4l_device;
extern URLProtocol video_protocol;
This diff is collapsed.
This diff is collapsed.
/*
* Buffered file io for ffmpeg system
* Copyright (c) 2001 Gerard Lantau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <sys/time.h>
#include "avformat.h"
/* standard file protocol */
static int file_open(URLContext *h, const char *filename, int flags)
{
int access;
int fd;
if (flags & URL_WRONLY) {
access = O_CREAT | O_TRUNC | O_WRONLY;
} else {
access = O_RDONLY;
}
fd = open(filename, access, 0666);
if (fd < 0)
return -ENOENT;
h->priv_data = (void *)fd;
return 0;
}
static int file_read(URLContext *h, unsigned char *buf, int size)
{
int fd = (int)h->priv_data;
return read(fd, buf, size);
}
static int file_write(URLContext *h, unsigned char *buf, int size)
{
int fd = (int)h->priv_data;
return write(fd, buf, size);
}
/* XXX: use llseek */
static offset_t file_seek(URLContext *h, offset_t pos, int whence)
{
int fd = (int)h->priv_data;
return lseek(fd, pos, whence);
}
static int file_close(URLContext *h)
{
int fd = (int)h->priv_data;
return close(fd);
}
URLProtocol file_protocol = {
"file",
file_open,
file_read,
file_write,
file_seek,
file_close,
};
/* pipe protocol */
static int pipe_open(URLContext *h, const char *filename, int flags)
{
int fd;
if (flags & URL_WRONLY) {
fd = 1;
} else {
fd = 0;
}
h->priv_data = (void *)fd;
return 0;
}
static int pipe_read(URLContext *h, unsigned char *buf, int size)
{
int fd = (int)h->priv_data;
return read(fd, buf, size);
}
static int pipe_write(URLContext *h, unsigned char *buf, int size)
{
int fd = (int)h->priv_data;
return write(fd, buf, size);
}
static int pipe_close(URLContext *h)
{
return 0;
}
URLProtocol pipe_protocol = {
"pipe",
pipe_open,
pipe_read,
pipe_write,
NULL,
pipe_close,
};
/*
* Linux video grab interface
* Copyright (c) 2000,2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <linux/videodev.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <errno.h>
#include <sys/time.h>
#include "avformat.h"
typedef struct {
int fd;
int frame_format; /* see VIDEO_PALETTE_xxx */
int use_mmap;
int width, height;
float rate;
INT64 time_frame;
} VideoData;
const char *v4l_device = "/dev/video";
/* XXX: move all that to the context */
static struct video_capability video_cap;
static UINT8 *video_buf;
static struct video_mbuf gb_buffers;
static struct video_mmap gb_buf;
static struct video_audio audio;
static int gb_frame = 0;
static int v4l_init(URLContext *h)
{
VideoData *s = h->priv_data;
int width, height;
int ret;
int video_fd, frame_size;
width = s->width;
height = s->height;
video_fd = open(v4l_device, O_RDWR);
if (video_fd < 0) {
perror(v4l_device);
return -EIO;
}
if (ioctl(video_fd,VIDIOCGCAP,&video_cap) < 0) {
perror("VIDIOCGCAP");
goto fail;
}
if (!(video_cap.type & VID_TYPE_CAPTURE)) {
fprintf(stderr, "Fatal: grab device does not handle capture\n");
goto fail;
}
/* unmute audio */
ioctl(video_fd, VIDIOCGAUDIO, &audio);
audio.flags &= ~VIDEO_AUDIO_MUTE;
ioctl(video_fd, VIDIOCSAUDIO, &audio);
ret = ioctl(video_fd,VIDIOCGMBUF,&gb_buffers);
if (ret < 0) {
/* try to use read based access */
struct video_window win;
struct video_picture pict;
int val;
win.x = 0;
win.y = 0;
win.width = width;
win.height = height;
win.chromakey = -1;
win.flags = 0;
ioctl(video_fd, VIDIOCSWIN, &win);
ioctl(video_fd, VIDIOCGPICT, &pict);
#if 0
printf("v4l: colour=%d hue=%d brightness=%d constrast=%d whiteness=%d\n",
pict.colour,
pict.hue,
pict.brightness,
pict.contrast,
pict.whiteness);
#endif
/* try to choose a suitable video format */
pict.palette=VIDEO_PALETTE_YUV420P;
ret = ioctl(video_fd, VIDIOCSPICT, &pict);
if (ret < 0) {
pict.palette=VIDEO_PALETTE_YUV422;
ret = ioctl(video_fd, VIDIOCSPICT, &pict);
if (ret < 0) {
pict.palette=VIDEO_PALETTE_RGB24;
ret = ioctl(video_fd, VIDIOCSPICT, &pict);
if (ret < 0)
goto fail1;
}
}
s->frame_format = pict.palette;
val = 1;
ioctl(video_fd, VIDIOCCAPTURE, &val);
s->time_frame = gettime();
s->use_mmap = 0;
} else {
video_buf = mmap(0,gb_buffers.size,PROT_READ|PROT_WRITE,MAP_SHARED,video_fd,0);
if ((unsigned char*)-1 == video_buf) {
perror("mmap");
goto fail;
}
gb_frame = 0;
s->time_frame = gettime();
/* start to grab the first frame */
gb_buf.frame = 1 - gb_frame;
gb_buf.height = height;
gb_buf.width = width;
gb_buf.format = VIDEO_PALETTE_YUV420P;
ret = ioctl(video_fd, VIDIOCMCAPTURE, &gb_buf);
if (ret < 0 && errno != EAGAIN) {
/* try YUV422 */
gb_buf.format = VIDEO_PALETTE_YUV422;
ret = ioctl(video_fd, VIDIOCMCAPTURE, &gb_buf);
if (ret < 0 && errno != EAGAIN) {
/* try RGB24 */
gb_buf.format = VIDEO_PALETTE_RGB24;
ret = ioctl(video_fd, VIDIOCMCAPTURE, &gb_buf);
}
}
if (ret < 0) {
if (errno != EAGAIN) {
fail1:
fprintf(stderr, "Fatal: grab device does not support suitable format\n");
} else {
fprintf(stderr,"Fatal: grab device does not receive any video signal\n");
}
goto fail;
}
s->frame_format = gb_buf.format;
s->use_mmap = 1;
}
switch(s->frame_format) {
case VIDEO_PALETTE_YUV420P:
frame_size = (width * height * 3) / 2;
break;
case VIDEO_PALETTE_YUV422:
frame_size = width * height * 2;
break;
case VIDEO_PALETTE_RGB24:
frame_size = width * height * 3;
break;
default:
goto fail;
}
s->fd = video_fd;
h->packet_size = frame_size;
return 0;
fail:
close(video_fd);
return -EIO;
}
static int v4l_mm_read_picture(URLContext *h, UINT8 *buf)
{
VideoData *s = h->priv_data;
UINT8 *ptr;
gb_buf.frame = gb_frame;
if (ioctl(s->fd, VIDIOCMCAPTURE, &gb_buf) < 0) {
if (errno == EAGAIN)
fprintf(stderr,"Cannot Sync\n");
else
perror("VIDIOCMCAPTURE");
return -EIO;
}
gb_frame = 1 - gb_frame;
while (ioctl(s->fd, VIDIOCSYNC, &gb_frame) < 0 &&
(errno == EAGAIN || errno == EINTR));
ptr = video_buf + gb_buffers.offsets[gb_frame];
memcpy(buf, ptr, h->packet_size);
return h->packet_size;
}
/* note: we support only one picture read at a time */
static int video_read(URLContext *h, UINT8 *buf, int size)
{
VideoData *s = h->priv_data;
INT64 curtime;
if (size != h->packet_size)
return -EINVAL;
/* wait based on the frame rate */
s->time_frame += (int)(1000000 / s->rate);
do {
curtime = gettime();
} while (curtime < s->time_frame);
/* read one frame */
if (s->use_mmap) {
return v4l_mm_read_picture(h, buf);
} else {
if (read(s->fd, buf, size) != size)
return -EIO;
return h->packet_size;
}
}
static int video_get_format(URLContext *h, URLFormat *f)
{
VideoData *s = h->priv_data;
f->width = s->width;
f->height = s->height;
f->frame_rate = (int)(s->rate * FRAME_RATE_BASE);
strcpy(f->format_name, "rawvideo");
switch(s->frame_format) {
case VIDEO_PALETTE_YUV420P:
f->pix_fmt = PIX_FMT_YUV420P;
break;
case VIDEO_PALETTE_YUV422:
f->pix_fmt = PIX_FMT_YUV422;
break;
case VIDEO_PALETTE_RGB24:
f->pix_fmt = PIX_FMT_BGR24; /* NOTE: v4l uses BGR24, not RGB24 ! */
break;
default:
abort();
}
return 0;
}
/* URI syntax: 'video:width,height,rate'
*/
static int video_open(URLContext *h, const char *uri, int flags)
{
VideoData *s;
const char *p;
int width, height;
int ret;
float rate;
/* extract parameters */
p = uri;
strstart(p, "video:", &p);
width = strtol(p, (char **)&p, 0);
if (width <= 0)
return -EINVAL;
if (*p == ',')
p++;
height = strtol(p, (char **)&p, 0);
if (height <= 0)
return -EINVAL;
if (*p == ',')
p++;
rate = strtod(p, (char **)&p);
if (rate <= 0)
return -EINVAL;
s = malloc(sizeof(VideoData));
if (!s)
return -ENOMEM;
h->priv_data = s;
h->is_streamed = 1;
s->width = width;
s->height = height;
s->rate = rate;
ret = v4l_init(h);
if (ret)
free(s);
return ret;
}
static int video_close(URLContext *h)
{
VideoData *s = h->priv_data;
close(s->fd);
free(s);
return 0;
}
URLProtocol video_protocol = {
"video",
video_open,
video_read,
NULL,
NULL, /* seek */
video_close,
video_get_format,
};
/*
* HTTP protocol for ffmpeg client
* Copyright (c) 2000, 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "avformat.h"
/* XXX: POST protocol is not completly implemented because ffmpeg use
only a subset of it */
//#define DEBUG
/* used for protocol handling */
#define BUFFER_SIZE 1024
#define URL_SIZE 4096
typedef struct {
int fd;
unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end;
int line_count;
int http_code;
char location[URL_SIZE];
} HTTPContext;
static int http_connect(URLContext *h, const char *path);
static int http_write(URLContext *h, UINT8 *buf, int size);
/* return non zero if error */
static int http_open(URLContext *h, const char *uri, int flags)
{
struct sockaddr_in dest_addr;
const char *p, *path, *proxy_path;
char hostname[1024], *q;
int port, fd = -1, use_proxy;
struct hostent *hp;
HTTPContext *s;
h->is_streamed = 1;
s = malloc(sizeof(HTTPContext));
if (!s) {
return -ENOMEM;
}
h->priv_data = s;
proxy_path = getenv("http_proxy");
use_proxy = (proxy_path != NULL) && !getenv("no_proxy");
/* fill the dest addr */
redo:
if (use_proxy) {
p = proxy_path;
} else {
p = uri;
}
if (!strstart(p, "http://", &p))
goto fail;
q = hostname;
while (*p != ':' && *p != '/' && *p != '\0') {
if ((q - hostname) < sizeof(hostname) - 1)
*q++ = *p;
p++;
}
*q = '\0';
port = 80;
if (*p == ':') {
p++;
port = strtoul(p, (char **)&p, 10);
}
if (port <= 0)
goto fail;
if (use_proxy) {
path = uri;
} else {
if (*p == '\0')
path = "/";
else
path = p;
}
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port);
if ((inet_aton(hostname, &dest_addr.sin_addr)) == 0) {
hp = gethostbyname(hostname);
if (!hp)
goto fail;
memcpy (&dest_addr.sin_addr, hp->h_addr, sizeof(dest_addr.sin_addr));
}
fd = socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0)
goto fail;
if (connect(fd, (struct sockaddr *)&dest_addr,
sizeof(dest_addr)) < 0)
goto fail;
s->fd = fd;
if (http_connect(h, path) < 0)
goto fail;
if (s->http_code == 303 && s->location[0] != '\0') {
/* url moved, get next */
uri = s->location;
goto redo;
}
return 0;
fail:
if (fd >= 0)
close(fd);
free(s);
return -EIO;
}
static int http_getc(HTTPContext *s)
{
int len;
if (s->buf_ptr >= s->buf_end) {
redo:
len = read(s->fd, s->buffer, BUFFER_SIZE);
if (len < 0) {
if (errno == EAGAIN || errno == EINTR)
goto redo;
return -EIO;
} else if (len == 0) {
return -1;
} else {
s->buf_ptr = s->buffer;
s->buf_end = s->buffer + len;
}
}
return *s->buf_ptr++;
}
static int process_line(HTTPContext *s, char *line, int line_count)
{
char *tag, *p;
/* end of header */
if (line[0] == '\0')
return 0;
p = line;
if (line_count == 0) {
while (!isspace(*p) && *p != '\0')
p++;
while (isspace(*p))
p++;
s->http_code = strtol(p, NULL, 10);
#ifdef DEBUG
printf("http_code=%d\n", s->http_code);
#endif
} else {
while (*p != '\0' && *p != ':')
p++;
if (*p != ':')
return 1;
*p = '\0';
tag = line;
p++;
while (isspace(*p))
p++;
if (!strcmp(tag, "Location")) {
strcpy(s->location, p);
}
}
return 1;
}
static int http_connect(URLContext *h, const char *path)
{
HTTPContext *s = h->priv_data;
int post, err, ch;
char line[1024], *q;
/* send http header */
post = h->flags & URL_WRONLY;
snprintf(s->buffer, sizeof(s->buffer),
"%s %s HTTP/1.0\n"
"User-Agent: FFmpeg %s\n"
"Accept: */*\n"
"\n",
post ? "POST" : "GET",
path,
FFMPEG_VERSION
);
if (http_write(h, s->buffer, strlen(s->buffer)) < 0)
return -EIO;
/* init input buffer */
s->buf_ptr = s->buffer;
s->buf_end = s->buffer;
s->line_count = 0;
s->location[0] = '\0';
if (post)
return 0;
/* wait for header */
q = line;
for(;;) {
ch = http_getc(s);
if (ch < 0)
return -EIO;
if (ch == '\n') {
/* process line */
if (q > line && q[-1] == '\r')
q--;
*q = '\0';
#ifdef DEBUG
printf("header='%s'\n", line);
#endif
err = process_line(s, line, s->line_count);
if (err < 0)
return err;
if (err == 0)
return 0;
s->line_count++;
q = line;
} else {
if ((q - line) < sizeof(line) - 1)
*q++ = ch;
}
}
}
static int http_read(URLContext *h, UINT8 *buf, int size)
{
HTTPContext *s = h->priv_data;
int size1, len;
size1 = size;
while (size > 0) {
/* read bytes from input buffer first */
len = s->buf_end - s->buf_ptr;
if (len > 0) {
if (len > size)
len = size;
memcpy(buf, s->buf_ptr, len);
s->buf_ptr += len;
} else {
len = read (s->fd, buf, size);
if (len < 0) {
if (errno != EINTR && errno != EAGAIN)
return -errno;
else
continue;
} else if (len == 0) {
break;
}
}
size -= len;
buf += len;
}
return size1 - size;
}
/* used only when posting data */
static int http_write(URLContext *h, UINT8 *buf, int size)
{
HTTPContext *s = h->priv_data;
int ret, size1;
size1 = size;
while (size > 0) {
ret = write (s->fd, buf, size);
if (ret < 0 && errno != EINTR && errno != EAGAIN)
return -errno;
size -= ret;
buf += ret;
}
return size1 - size;
}
static int http_close(URLContext *h)
{
HTTPContext *s = h->priv_data;
close(s->fd);
return 0;
}
URLProtocol http_protocol = {
"http",
http_open,
http_read,
http_write,
NULL, /* seek */
http_close,
};
This diff is collapsed.
/*
* Miscellaneous MJPEG based formats
* Copyright (c) 2000 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
#include "avformat.h"
/* Multipart JPEG */
#define BOUNDARY_TAG "ffserver"
static int mpjpeg_write_header(AVFormatContext *s)
{
UINT8 buf1[256];
snprintf(buf1, sizeof(buf1), "--%s\n", BOUNDARY_TAG);
put_buffer(&s->pb, buf1, strlen(buf1));
put_flush_packet(&s->pb);
return 0;
}
static int mpjpeg_write_packet(AVFormatContext *s,
int stream_index, UINT8 *buf, int size)
{
UINT8 buf1[256];
snprintf(buf1, sizeof(buf1), "Content-type: image/jpeg\n\n");
put_buffer(&s->pb, buf1, strlen(buf1));
put_buffer(&s->pb, buf, size);
snprintf(buf1, sizeof(buf1), "\n--%s\n", BOUNDARY_TAG);
put_buffer(&s->pb, buf1, strlen(buf1));
put_flush_packet(&s->pb);
return 0;
}
static int mpjpeg_write_trailer(AVFormatContext *s)
{
return 0;
}
AVFormat mpjpeg_format = {
"mpjpeg",
"Mime multipart JPEG format",
"multipart/x-mixed-replace;boundary=" BOUNDARY_TAG,
"mjpg",
CODEC_ID_NONE,
CODEC_ID_MJPEG,
mpjpeg_write_header,
mpjpeg_write_packet,
mpjpeg_write_trailer,
};
/* single frame JPEG */
static int jpeg_write_header(AVFormatContext *s)
{
return 0;
}
static int jpeg_write_packet(AVFormatContext *s, int stream_index,
UINT8 *buf, int size)
{
put_buffer(&s->pb, buf, size);
put_flush_packet(&s->pb);
return 1; /* no more data can be sent */
}
static int jpeg_write_trailer(AVFormatContext *s)
{
return 0;
}
AVFormat jpeg_format = {
"jpeg",
"JPEG image",
"image/jpeg",
"jpg,jpeg",
CODEC_ID_NONE,
CODEC_ID_MJPEG,
jpeg_write_header,
jpeg_write_packet,
jpeg_write_trailer,
};
This diff is collapsed.
/*
* RAW encoder and decoder
* Copyright (c) 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include "avformat.h"
/* simple formats */
int raw_write_header(struct AVFormatContext *s)
{
return 0;
}
int raw_write_packet(struct AVFormatContext *s,
int stream_index,
unsigned char *buf, int size)
{
put_buffer(&s->pb, buf, size);
put_flush_packet(&s->pb);
return 0;
}
int raw_write_trailer(struct AVFormatContext *s)
{
return 0;
}
/* raw input */
static int raw_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
AVStream *st;
st = malloc(sizeof(AVStream));
if (!st)
return -1;
s->nb_streams = 1;
s->streams[0] = st;
st->id = 0;
if (ap) {
if (s->format->audio_codec != CODEC_ID_NONE) {
st->codec.codec_type = CODEC_TYPE_AUDIO;
st->codec.codec_id = s->format->audio_codec;
} else if (s->format->video_codec != CODEC_ID_NONE) {
st->codec.codec_type = CODEC_TYPE_VIDEO;
st->codec.codec_id = s->format->video_codec;
} else {
free(st);
return -1;
}
switch(st->codec.codec_type) {
case CODEC_TYPE_AUDIO:
st->codec.sample_rate = ap->sample_rate;
st->codec.channels = ap->channels;
/* XXX: endianness */
break;
case CODEC_TYPE_VIDEO:
st->codec.frame_rate = ap->frame_rate;
st->codec.width = ap->width;
st->codec.height = ap->height;
break;
default:
abort();
break;
}
} else {
abort();
}
return 0;
}
#define MIN_SIZE 1024
int raw_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
int packet_size, n, ret;
if (url_feof(&s->pb))
return -EIO;
packet_size = url_get_packet_size(&s->pb);
n = MIN_SIZE / packet_size;
if (n <= 0)
n = 1;
if (av_new_packet(pkt, n * packet_size) < 0)
return -EIO;
pkt->stream_index = 0;
ret = get_buffer(&s->pb, pkt->data, pkt->size);
if (ret < 0)
av_free_packet(pkt);
return ret;
}
int raw_read_close(AVFormatContext *s)
{
return 0;
}
/* mp3 read */
static int mp3_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
AVStream *st;
st = malloc(sizeof(AVStream));
if (!st)
return -1;
s->nb_streams = 1;
s->streams[0] = st;
st->id = 0;
st->codec.codec_type = CODEC_TYPE_AUDIO;
st->codec.codec_id = CODEC_ID_MP2;
/* XXX: read the first frame and extract rate and channels */
st->codec.sample_rate = 44100;
st->codec.channels = 2;
return 0;
}
/* mpeg1/h263 input */
static int video_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
AVStream *st;
st = av_mallocz(sizeof(AVStream));
if (!st)
return -1;
s->nb_streams = 1;
s->streams[0] = st;
st->codec.codec_type = CODEC_TYPE_VIDEO;
st->codec.codec_id = s->format->video_codec;
return 0;
}
AVFormat mp2_format = {
"mp2",
"MPEG audio",
"audio/x-mpeg",
"mp2,mp3",
CODEC_ID_MP2,
0,
raw_write_header,
raw_write_packet,
raw_write_trailer,
mp3_read_header,
raw_read_packet,
raw_read_close,
};
AVFormat ac3_format = {
"ac3",
"raw ac3",
"audio/x-ac3",
"ac3",
CODEC_ID_AC3,
0,
raw_write_header,
raw_write_packet,
raw_write_trailer,
};
AVFormat h263_format = {
"h263",
"raw h263",
"video/x-h263",
"h263",
0,
CODEC_ID_H263,
raw_write_header,
raw_write_packet,
raw_write_trailer,
video_read_header,
raw_read_packet,
raw_read_close,
};
AVFormat mpeg1video_format = {
"mpegvideo",
"MPEG video",
"video/x-mpeg",
"mpg,mpeg",
0,
CODEC_ID_MPEG1VIDEO,
raw_write_header,
raw_write_packet,
raw_write_trailer,
video_read_header,
raw_read_packet,
raw_read_close,
};
AVFormat pcm_format = {
"pcm",
"pcm raw format",
NULL,
"sw",
CODEC_ID_PCM,
0,
raw_write_header,
raw_write_packet,
raw_write_trailer,
raw_read_header,
raw_read_packet,
raw_read_close,
};
int rawvideo_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
int packet_size, ret, width, height;
AVStream *st = s->streams[0];
width = st->codec.width;
height = st->codec.height;
switch(st->codec.pix_fmt) {
case PIX_FMT_YUV420P:
packet_size = (width * height * 3) / 2;
break;
case PIX_FMT_YUV422:
packet_size = (width * height * 2);
break;
case PIX_FMT_BGR24:
case PIX_FMT_RGB24:
packet_size = (width * height * 3);
break;
default:
abort();
break;
}
if (av_new_packet(pkt, packet_size) < 0)
return -EIO;
pkt->stream_index = 0;
/* bypass buffered I/O */
ret = url_read(url_fileno(&s->pb), pkt->data, pkt->size);
if (ret != pkt->size) {
av_free_packet(pkt);
return -EIO;
} else {
return 0;
}
}
AVFormat rawvideo_format = {
"rawvideo",
"raw video format",
NULL,
"yuv",
CODEC_ID_NONE,
CODEC_ID_RAWVIDEO,
raw_write_header,
raw_write_packet,
raw_write_trailer,
raw_read_header,
rawvideo_read_packet,
raw_read_close,
};
This diff is collapsed.
This diff is collapsed.
/*
* UDP prototype streaming system
* Copyright (c) 2000 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "avformat.h"
typedef struct {
int udp_socket;
int max_payload_size; /* in bytes */
} UDPContext;
#define UDP_TX_BUF_SIZE 32768
/* put it in UDP context */
static struct sockaddr_in dest_addr;
/* return non zero if error */
static int udp_open(URLContext *h, const char *uri, int flags)
{
int local_port = 0;
struct sockaddr_in my_addr;
const char *p, *q;
char hostname[1024];
int port, udp_socket, tmp;
struct hostent *hp;
UDPContext *s;
h->is_streamed = 1;
if (!(flags & URL_WRONLY))
return -EIO;
/* fill the dest addr */
p = uri;
if (!strstart(p, "udp:", &p))
return -1;
q = strchr(p, ':');
if (!q)
return -1;
memcpy(hostname, p, q - p);
hostname[q - p] = '\0';
port = strtol(q+1, NULL, 10);
if (port <= 0)
return -1;
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port);
if ((inet_aton(hostname, &dest_addr.sin_addr)) == 0) {
hp = gethostbyname(hostname);
if (!hp)
return -1;
memcpy ((char *) &dest_addr.sin_addr, hp->h_addr, hp->h_length);
}
udp_socket = socket(PF_INET, SOCK_DGRAM, 0);
if (udp_socket < 0)
return -1;
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(local_port);
my_addr.sin_addr.s_addr = htonl (INADDR_ANY);
/* the bind is needed to give a port to the socket now */
if (bind(udp_socket,(struct sockaddr *)&my_addr, sizeof(my_addr)) < 0)
goto fail;
/* limit the tx buf size to limit latency */
tmp = UDP_TX_BUF_SIZE;
if (setsockopt(udp_socket, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) {
perror("setsockopt sndbuf");
goto fail;
}
s = malloc(sizeof(UDPContext));
if (!s)
return -ENOMEM;
h->priv_data = s;
s->udp_socket = udp_socket;
h->packet_size = 1500;
return 0;
fail:
return -EIO;
}
int udp_close(URLContext *h)
{
UDPContext *s = h->priv_data;
close(s->udp_socket);
return 0;
}
int udp_write(URLContext *h, UINT8 *buf, int size)
{
UDPContext *s = h->priv_data;
int ret, len, size1;
/* primitive way to avoid big packets */
size1 = size;
while (size > 0) {
len = size;
if (len > h->packet_size)
len = h->packet_size;
ret = sendto (s->udp_socket, buf, len, 0,
(struct sockaddr *) &dest_addr,
sizeof (dest_addr));
if (ret < 0)
perror("sendto");
buf += len;
size -= len;
}
return size1 - size;
}
URLProtocol udp_protocol = {
"udp",
udp_open,
NULL, /* read */
udp_write,
NULL, /* seek */
udp_close,
};
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment