Commit 9aeeeb63 authored by Fabrice Bellard's avatar Fabrice Bellard

Initial revision


Originally committed as revision 2 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent 77bb6835
This diff is collapsed.
CFLAGS= -O2 -Wall -g -I./libav
LDFLAGS= -g -L./libav
PROG= ffmpeg ffserver
all: lib $(PROG)
lib:
make -C libav all
ffmpeg: rmenc.o mpegmux.o asfenc.o jpegenc.o swfenc.o udp.o formats.o grab.o ffmpeg.o libav/libav.a
gcc $(LDFLAGS) -o $@ $^ -lav -lm
ffserver: rmenc.o mpegmux.o asfenc.o jpegenc.o swfenc.o formats.o grab.o ffserver.o libav/libav.a
gcc $(LDFLAGS) -o $@ $^ -lav -lpthread -lm
%.o: %.c
gcc $(CFLAGS) -c -o $@ $<
clean:
make -C libav clean
rm -f *.o *~ gmon.out TAGS $(PROG)
etags:
etags *.[ch] libav/*.[ch]
tar:
(cd .. ; tar zcvf ffmpeg-0.3.tgz ffmpeg --exclude CVS --exclude TAGS )
FFmpeg version 0.9 - (c) 2000 Gerard Lantau.
1) Introduction
---------------
ffmpeg is a hyper fast realtime audio/video encoder and streaming
server. It can grab from a standard Video4Linux video source and
convert it into several file formats based on DCT/motion compensation
encoding. Sound is compressed in MPEG audio layer 2 or using an AC3
compatible stream.
What makes ffmpeg interesting ?
- Innovative streaming technology : multiformat, real time encoding,
simple configuration.
- Simple and efficient video encoder: outputs MPEG1, H263 and Real
Video(tm) compatible bitstreams using the same encoder core.
- Real time encoding (25 fps in 352x288 on a K6 500) using the video4linux API.
- Generates I and P frames, which means it is far better than a MJPEG
encoder.
- Hyper fast MPEG audio layer 2 compression (50 times faster than
realtime on a K6 500).
- Hyper fast AC3 compatible encoder.
- simple and very small portable C source code, easy to understand and
to modify. It be may the smallest decent MPEG encoder :-)
ffmpeg is made of two programs:
* ffmpeg: soft VCR which encodes in real time to several formats.
* ffserver: live broadcast streaming server based on the ffmpeg core
encoders.
2) Documentation
----------------
read doc/ffmpeg.txt and doc/ffserver.txt to learn the basic features.
read ffmpeg
3) Licensing:
------------
* See the file COPYING. ffmpeg is licensed under the GNU General
Public License.
* Source code from third parties: The DCT code comes from the Berkeley
MPEG decoder and the JPEG encoder.
* This code should be patent free since it is very simple. I took care
to use the same video encoder core for all formats to show that they
really ARE THE SAME except for the encoding huffman codes.
Gerard Lantau (glantau@users.sourceforge.net).
This diff is collapsed.
- Sound is only handled in mono. The fixed psycho acoustic model is
very bad, although the quality is surpringly good for such a model !
- the bit rate control is really not correct.
- Only frame size multiple of 16 are handled.
- If you want a specific format to be added (I am thinking about
MJPEG, H261) please tell me. Of course, the format you choose should
be based on MPEG to be easily integrated
- ffmpeg can be used to generate streaming audio/video on a
server. Please tell me if you are interested.
Technical notes:
---------------
- To increase speed, only motion vectors (0,0) are tested
- The decision intra/predicted macroblock is the algorithm suggested
by the mpeg 1 specification.
- only Huffman based H263 is supported, mainly because of patent
issues.
- Many options can be modified only in the source code.
- I rewrote the mpeg audio layer 2 compatible encoder from scratch. It
is one of the simplest encoder you can imagine (800 lines of C code
!). It is also one of the fastest because of its simplicity. They
are still some problems of overflow. A minimal psycho acoustic model
could be added. Only mono stream can be generated. I may add stereo
if needed.
- I rewrote the AC3 audio encoder from scratch. It is fairly naive,
but the result are quiet interesting at 64 kbit/s. It includes
extensions for low sampling rates used in some Internet
formats. Differential and coupled stereo is not handled. Stereo
channels are simply handled as two mono channels.
ffmpeg TODO list:
- Add ASF format.
- add MJPEG codec.
- fix skip frame bug in mpeg video
- fix G2 audio problem (bad volume in AC3 ?)
- use non zero motion vectors.
- test fifo & master handling
- deny & allow + password.
- Improve psycho acoustic model for AC3 & mpeg audio.
- Improve the bit rate control for video codecs.
* ffmpeg can use YUV files as input :
ffmpeg /tmp/out.mpg /tmp/test
If will use the files:
/tmp/test0.Y, /tmp/test0.U, /tmp/test0.V,
/tmp/test1.Y, /tmp/test1.U, /tmp/test1.V, etc...
The Y files use twice the resolution of the U and V files. They are
raw files, without header. They can be generated by all decent video
decoders.
* ffmpeg can use a video4linux compatible video source :
ffmpeg /tmp/out.mpg
Note that you must activate the right video source and channel
before launching ffmpeg. You can use any TV viewer such as xawtv by
Gerd Knorr which I find very good.
* There are some importants options to know:
-s size set frame size [160x128]
-f format set encoding format [mpeg1]
-r fps set frame rate [25]
-b bitrate set the bitrate in kbit/s [100]
-t time set recording time in seconds [10.0]
The frame size can also be: cif, qcif, sqcif and 4cif.
The encoding format can be mpeg1, h263 or rv10.
Advanced options are:
-d device set video4linux device name
-g gop_size set the group of picture size.
An 'intra' frame is generated every gop_size frames.
-i use only intra images (speed up compression, but lower quality).
-c comment set the comment string.
Comment strings are only used for Real Video(tm) encoding. Tags are
used in the comment string. A typical comment string is:
"+title=Test Video +author=FFMpeg +copyright=Free +comment=Generated by FFMpeg 1.0"
The output file can be "-" to output to a pipe. This is only possible
with mpeg1 and h263 formats.
* Tips:
- For low bit rate application, use a low frame rate and a small gop
size. This is especially true for real video where the Linux player
does not seem to be very fast, so it can miss frames. An example is:
ffmpeg -g 3 -r 3 -t 10 -b 50 -s qcif -f rv10 /tmp/b.rm
- The parameter 'q' which is displayed while encoding is the current
quantizer. The value of 1 indicates that a very good quality could
be achieved. The value of 31 indicates the worst quality. If q=31
too often, it means that the encoder cannot compress enough to meet
your bit rate. You must either increase the bit rate, decrease the
frame rate or decrease the frame size.
# Port on which the server is listening. You must select a different
# port from your standard http web server if it is running on the same
# computer.
Port 8080
# Address on which the server is bound. Only useful if you have
# several network interfaces.
BindAddress 0.0.0.0
# Host and port of the master server if you which that this server
# duplicates another existing server. Otherwise, the server does the
# audio/video grab itself. See the following options for the grab parameters
#MasterServer http://localhost:80/index.html
# Grab parameters
#AudioDevice /dev/dsp
#VideoDevice /dev/video
# Number of simultaneous requests that can be handled. Since FFServer
# is very fast, this limit is determined mainly by your Internet
# connection speed.
MaxClients 1000
# Access Log file (uses standard Apache log file format)
# '-' is the standard output
CustomLog -
##################################################################
# Now you can define each stream which will be generated from the
# original audio and video stream. Each format has a filename (here
# 'test128.mpg'). FFServer will send this stream when answering a
# request containing this filename.
<Stream test1.mpg>
# Format of the stream : you can choose among:
# mpeg1 : MPEG1 multiplexed video and audio
# mpeg1video : only MPEG1 video
# mp2 : MPEG audio layer 2
# mp3 : MPEG audio layer 3 (currently sent as layer 2)
# rm : Real Networks compatible stream. Multiplexed audio and video.
# ra : Real Networks compatible stream. Audio only.
# mpjpeg : Multipart JPEG (works with Netscape without any plugin)
# jpeg : Generate a single JPEG image.
# asf : ASF compatible stream (Windows Media Player format)
# swf : Macromedia flash(tm) compatible stream
# master : special ffmpeg stream used to duplicate a server
Format mpeg1
# Bitrate for the audio stream. Codecs usually support only a few different bitrates.
AudioBitRate 32
# Number of audio channels : 1 = mono, 2 = stereo
AudioChannels 1
# Sampling frequency for audio. When using low bitrates, you should
# lower this frequency to 22050 or 11025. The supported frequencies
# depend on the selected audio codec.
AudioSampleRate 44100
# Bitrate for the video stream.
VideoBitRate 64
# Number of frames per second
VideoFrameRate 3
# Size of the video frame : WxH
# W : width, H : height
# The following abbreviation are defined : sqcif, qcif, cif, 4cif
#VideoSize 352x240
# transmit only intra frames (useful for low bitrates)
VideoIntraOnly
# If non intra only, an intra frame is transmitted every VideoGopSize
# frames Video synchronization can only begin at an I frames.
#VideoGopSize 12
</Stream>
# second mpeg stream with high frame rate
<Stream test2.mpg>
Format mpeg1video
VideoBitRate 128
VideoFrameRate 25
#VideoSize 352x240
VideoGopSize 25
</Stream>
##################################################################
# Another stream : used to download data to another server which
# duplicates this one
<Stream master>
Format master
</Stream>
##################################################################
# Another stream : Real with audio only at 32 kbits
<Stream test.ra>
Format ra
AudioBitRate 32
</Stream>
##################################################################
# Another stream : Real with audio and video at 64 kbits
<Stream test.rm>
Format rm
AudioBitRate 32
VideoBitRate 20
VideoFrameRate 2
VideoIntraOnly
</Stream>
##################################################################
# Another stream : Mpeg audio layer 2 at 64 kbits.
<Stream test.mp2>
Format mp2
AudioBitRate 64
AudioSampleRate 44100
</Stream>
<Stream test1.mp2>
Format mp2
AudioBitRate 32
AudioSampleRate 16000
</Stream>
##################################################################
# Another stream : Multipart JPEG
<Stream test.mjpg>
Format mpjpeg
VideoFrameRate 2
VideoIntraOnly
</Stream>
##################################################################
# Another stream : Multipart JPEG
<Stream test.jpg>
Format jpeg
# the parameters are choose here to take the same output as the
# Multipart JPEG one.
VideoFrameRate 2
VideoIntraOnly
</Stream>
##################################################################
# Another stream : Flash
<Stream test.swf>
Format swf
VideoFrameRate 2
VideoIntraOnly
</Stream>
##################################################################
# Another stream : ASF compatible
<Stream test.asf>
Format asf
AudioBitRate 64
AudioSampleRate 44100
VideoFrameRate 2
VideoIntraOnly
</Stream>
##################################################################
# Another stream : server status
<Stream stat.html>
Format status
</Stream>
This diff is collapsed.
This diff is collapsed.
#include <stdlib.h>
#include <stdio.h>
#include <netinet/in.h>
#include <linux/videodev.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 <getopt.h>
#include <string.h>
#include "mpegenc.h"
AVFormat *first_format;
/* XXX: suppress it ! */
int data_out_size;
const char *comment_string =
"+title=Test Video +author=FFMpeg +copyright=Free +comment=Generated by FFMpeg 1.0";
void register_avformat(AVFormat *format)
{
AVFormat **p;
p = &first_format;
while (*p != NULL) p = &(*p)->next;
*p = format;
format->next = NULL;
}
AVFormat *guess_format(const char *short_name, const char *filename, const char *mime_type)
{
AVFormat *fmt, *fmt_found;
int score_max, score;
const char *ext, *p;
char ext1[32], *q;
/* find the proper file type */
fmt_found = NULL;
score_max = 0;
fmt = first_format;
while (fmt != NULL) {
score = 0;
if (fmt->name && short_name && !strcmp(fmt->name, short_name))
score += 100;
if (fmt->mime_type && mime_type && !strcmp(fmt->mime_type, mime_type))
score += 10;
if (filename && fmt->extensions) {
ext = strrchr(filename, '.');
if (ext) {
ext++;
p = fmt->extensions;
for(;;) {
q = ext1;
while (*p != '\0' && *p != ',')
*q++ = *p++;
*q = '\0';
if (!strcasecmp(ext1, ext)) {
score += 5;
break;
}
if (*p == '\0')
break;
p++;
}
}
}
if (score > score_max) {
score_max = score;
fmt_found = fmt;
}
fmt = fmt->next;
}
return fmt_found;
}
/* return TRUE if val is a prefix of str. If it returns TRUE, ptr is
set to the next character in 'str' after the prefix */
int strstart(const char *str, const char *val, const char **ptr)
{
const char *p, *q;
p = str;
q = val;
while (*q != '\0') {
if (*p != *q)
return 0;
p++;
q++;
}
if (ptr)
*ptr = p;
return 1;
}
/* simple formats */
int raw_write_header(struct AVFormatContext *s)
{
return 0;
}
int raw_write_audio(struct AVFormatContext *s,
unsigned char *buf, int size)
{
put_buffer(&s->pb, buf, size);
put_flush_packet(&s->pb);
return 0;
}
int raw_write_video(struct AVFormatContext *s,
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;
}
AVFormat mp2_format = {
"mp2",
"MPEG audio layer 2",
"audio/x-mpeg",
"mp2,mp3",
CODEC_ID_MP2,
0,
raw_write_header,
raw_write_audio,
NULL,
raw_write_trailer,
};
AVFormat ac3_format = {
"ac3",
"raw ac3",
"audio/x-ac3",
"ac3",
CODEC_ID_AC3,
0,
raw_write_header,
raw_write_audio,
NULL,
raw_write_trailer,
};
AVFormat h263_format = {
"h263",
"raw h263",
"video/x-h263",
"h263",
0,
CODEC_ID_H263,
raw_write_header,
NULL,
raw_write_video,
raw_write_trailer,
};
AVFormat mpeg1video_format = {
"mpeg1video",
"MPEG1 video",
"video/mpeg",
"mpg,mpeg",
0,
CODEC_ID_MPEG1VIDEO,
raw_write_header,
NULL,
raw_write_video,
raw_write_trailer,
};
/* encoder management */
AVEncoder *first_encoder;
void register_avencoder(AVEncoder *format)
{
AVEncoder **p;
p = &first_encoder;
while (*p != NULL) p = &(*p)->next;
*p = format;
format->next = NULL;
}
int avencoder_open(AVEncodeContext *avctx, AVEncoder *codec)
{
int ret;
avctx->codec = codec;
avctx->frame_number = 0;
avctx->priv_data = malloc(codec->priv_data_size);
if (!avctx->priv_data)
return -ENOMEM;
memset(avctx->priv_data, 0, codec->priv_data_size);
ret = avctx->codec->init(avctx);
if (ret < 0) {
free(avctx->priv_data);
avctx->priv_data = NULL;
return ret;
}
return 0;
}
int avencoder_encode(AVEncodeContext *avctx, UINT8 *buf, int buf_size, void *data)
{
int ret;
ret = avctx->codec->encode(avctx, buf, buf_size, data);
avctx->frame_number++;
return ret;
}
int avencoder_close(AVEncodeContext *avctx)
{
if (avctx->codec->close)
avctx->codec->close(avctx);
free(avctx->priv_data);
avctx->priv_data = NULL;
return 0;
}
AVEncoder *avencoder_find(enum CodecID id)
{
AVEncoder *p;
p = first_encoder;
while (p) {
if (p->id == id)
return p;
p = p->next;
}
return NULL;
}
void avencoder_string(char *buf, int buf_size, AVEncodeContext *enc)
{
switch(enc->codec->type) {
case CODEC_TYPE_VIDEO:
snprintf(buf, buf_size,
"Video: %s, %dx%d, %d fps, %d kb/s",
enc->codec->name, enc->width, enc->height, enc->rate, enc->bit_rate / 1000);
break;
case CODEC_TYPE_AUDIO:
snprintf(buf, buf_size,
"Audio: %s, %d Hz, %s, %d kb/s",
enc->codec->name, enc->rate,
enc->channels == 2 ? "stereo" : "mono",
enc->bit_rate / 1000);
break;
default:
abort();
}
}
/* PutByteFormat */
int init_put_byte(PutByteContext *s,
unsigned char *buffer,
int buffer_size,
void *opaque,
void (*write_packet)(void *opaque, UINT8 *buf, int buf_size),
int (*write_seek)(void *opaque, long long offset, int whence))
{
s->buffer = buffer;
s->buf_ptr = buffer;
s->buf_end = buffer + buffer_size;
s->opaque = opaque;
s->write_packet = write_packet;
s->write_seek = write_seek;
s->pos = 0;
return 0;
}
static void flush_buffer(PutByteContext *s)
{
if (s->buf_ptr > s->buffer) {
if (s->write_packet)
s->write_packet(s->opaque, s->buffer, s->buf_ptr - s->buffer);
s->pos += s->buf_ptr - s->buffer;
}
s->buf_ptr = s->buffer;
}
void put_byte(PutByteContext *s, int b)
{
*(s->buf_ptr)++ = b;
if (s->buf_ptr >= s->buf_end)
flush_buffer(s);
}
void put_buffer(PutByteContext *s, unsigned char *buf, int size)
{
int len;
while (size > 0) {
len = (s->buf_end - s->buf_ptr);
if (len > size)
len = size;
memcpy(s->buf_ptr, buf, len);
s->buf_ptr += len;
if (s->buf_ptr >= s->buf_end)
flush_buffer(s);
buf += len;
size -= len;
}
}
void put_flush_packet(PutByteContext *s)
{
flush_buffer(s);
}
/* XXX: this seek is not correct if we go after the end of the written data */
long long put_seek(PutByteContext *s, long long offset, int whence)
{
long long offset1;
if (whence != SEEK_CUR && whence != SEEK_SET)
return -1;
if (whence == SEEK_CUR)
offset += s->