Initial revision

Originally committed as revision 2 to svn://svn.ffmpeg.org/ffmpeg/trunk
pull/126/head
Fabrice Bellard 24 years ago
parent 77bb6835ba
commit 9aeeeb63f7
  1. 339
      COPYING
  2. 28
      Makefile
  3. 60
      README
  4. 510
      asfenc.c
  5. 14
      doc/BUGS
  6. 25
      doc/README.tech
  7. 19
      doc/TODO
  8. 62
      doc/ffmpeg.txt
  9. 214
      doc/ffserver.conf
  10. 717
      ffmpeg.c
  11. 1642
      ffserver.c
  12. 373
      formats.c
  13. 258
      grab.c
  14. 102
      jpegenc.c
  15. 17
      libav/Makefile
  16. 1460
      libav/ac3enc.c
  17. 32
      libav/ac3enc.h
  18. 180
      libav/ac3tab.h
  19. 79
      libav/avcodec.h
  20. 174
      libav/common.c
  21. 68
      libav/common.h
  22. 151
      libav/h263data.h
  23. 229
      libav/h263enc.c
  24. 224
      libav/jfdctfst.c
  25. 1584
      libav/jrevdct.c
  26. 416
      libav/mjpegenc.c
  27. 754
      libav/mpegaudio.c
  28. 31
      libav/mpegaudio.h
  29. 310
      libav/mpegaudiotab.h
  30. 311
      libav/mpegencodevlc.h
  31. 1098
      libav/mpegvideo.c
  32. 94
      libav/mpegvideo.h
  33. 245
      libav/resample.c
  34. 127
      mpegenc.h
  35. 301
      mpegmux.c
  36. 498
      rmenc.c
  37. 347
      swfenc.c
  38. 123
      udp.c

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
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.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

@ -0,0 +1,28 @@
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 )

@ -0,0 +1,60 @@
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).

@ -0,0 +1,510 @@
/*
* ASF compatible encoder
* 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 "mpegenc.h"
#define PACKET_SIZE 3200
#define PACKET_HEADER_SIZE 12
#define FRAME_HEADER_SIZE 17
typedef struct {
AVEncodeContext *enc;
int num;
int seq;
} ASFStream;
typedef struct {
int is_streamed; /* true if streamed */
int seqno;
int packet_size;
ASFStream streams[2];
ASFStream *audio_stream, *video_stream;
int nb_streams;
/* non streamed additonnal info */
int file_size_offset;
int data_offset;
/* packet filling */
int packet_size_left;
int packet_timestamp_start;
int packet_timestamp_end;
int packet_nb_frames;
UINT8 packet_buf[PACKET_SIZE];
PutByteContext pb;
} ASFContext;
typedef struct {
UINT32 v1;
UINT16 v2;
UINT16 v3;
UINT8 v4[8];
} GUID;
static const GUID asf_header = {
0x75B22630, 0x668E, 0x11CF, { 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C },
};
static const GUID file_header = {
0x8CABDCA1, 0xA947, 0x11CF, { 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 },
};
static const GUID stream_header = {
0xB7DC0791, 0xA9B7, 0x11CF, { 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 },
};
static const GUID audio_stream = {
0xF8699E40, 0x5B4D, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B },
};
static const GUID audio_conceal_none = {
0x49f1a440, 0x4ece, 0x11d0, { 0xa3, 0xac, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 },
};
static const GUID video_stream = {
0xBC19EFC0, 0x5B4D, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B },
};
static const GUID video_conceal_none = {
0x20FB5700, 0x5B55, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B },
};
static const GUID comment_header = {
0x86D15240, 0x311D, 0x11D0, { 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 },
};
static const GUID data_header = {
0x75b22636, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c },
};
static const GUID packet_guid = {
0xF656CCE1, 0x03B3, 0x11D4, { 0xBE, 0xA2, 0x00, 0xA0, 0xCC, 0x3D, 0x72, 0x74 },
};
/* I am not a number !!! This GUID is the one found on the PC used to
generate the stream */
static const GUID my_guid = {
0x12345678, 0xA947, 0x11CF, { 0x31, 0x41, 0x59, 0x26, 0x20, 0x20, 0x20, 0x20 },
};
static void put_guid(PutByteContext *s, const GUID *g)
{
int i;
put_le32(s, g->v1);
put_le16(s, g->v2);
put_le16(s, g->v3);
for(i=0;i<8;i++)
put_byte(s, g->v4[i]);
}
#if 0
static void put_str16(PutByteContext *s, const char *tag)
{
put_le16(s,strlen(tag));
while (*tag) {
put_le16(s, *tag++);
}
}
#endif
/* write an asf chunk (only used in streaming case) */
static void put_chunk(AVFormatContext *s, int type, int payload_length)
{
ASFContext *asf = s->priv_data;
PutByteContext *pb = &s->pb;
int length;
length = payload_length + 8;
put_le16(pb, type);
put_le16(pb, length);
put_le32(pb, asf->seqno);
put_le16(pb, 0); /* unknown bytes */
put_le16(pb, length);
asf->seqno++;
}
static int asf_write_header(AVFormatContext *s)
{
PutByteContext *pb = &s->pb;
ASFContext *asf;
int header_size, n, extra_size, extra_size2, i, wav_extra_size;
AVEncodeContext *enc;
long long header_offset, cur_pos;
asf = malloc(sizeof(ASFContext));
if (!asf)
return -1;
memset(asf, 0, sizeof(ASFContext));
s->priv_data = asf;
asf->packet_size = PACKET_SIZE;
if (!s->is_streamed) {
put_guid(pb, &asf_header);
put_le64(pb, 0); /* header length, will be patched after */
put_le32(pb, 6); /* ??? */
put_byte(pb, 1); /* ??? */
put_byte(pb, 2); /* ??? */
} else {
put_chunk(s, 0x4824, 0); /* start of stream (length will be patched later) */
}
/* file header */
header_offset = put_pos(pb);
put_guid(pb, &file_header);
put_le64(pb, 24 + 80);
put_guid(pb, &my_guid);
asf->file_size_offset = put_pos(pb);
put_le64(pb, 0); /* file size (patched after if not streamed) */
put_le64(pb, 0); /* file time : 1601 :-) */
put_le64(pb, 0x283); /* ??? */
put_le64(pb, 0); /* stream 0 length in us */
put_le64(pb, 0); /* stream 1 length in us */
put_le32(pb, 0x0c1c); /* ??? */
put_le32(pb, 0); /* ??? */
put_le32(pb, 2); /* ??? */
put_le32(pb, asf->packet_size); /* packet size */
put_le32(pb, asf->packet_size); /* ??? */
put_le32(pb, 0x03e800); /* ??? */
/* stream headers */
n = 0;
for(i=0;i<2;i++) {
if (i == 0)
enc = s->audio_enc;
else
enc = s->video_enc;
if (!enc)
continue;
asf->streams[n].num = i;
asf->streams[n].seq = 0;
asf->streams[n].enc = enc;
switch(enc->codec->type) {
case CODEC_TYPE_AUDIO:
asf->audio_stream = &asf->streams[n];
wav_extra_size = 0;
extra_size = 18 + wav_extra_size;
extra_size2 = 0;
break;
default:
case CODEC_TYPE_VIDEO:
asf->video_stream = &asf->streams[n];
wav_extra_size = 0;
extra_size = 0x33;
extra_size2 = 0;
break;
}
put_guid(pb, &stream_header);
put_le64(pb, 24 + 16 * 2 + 22 + extra_size + extra_size2);
if (enc->codec->type == CODEC_TYPE_AUDIO) {
put_guid(pb, &audio_stream);
put_guid(pb, &audio_conceal_none);
} else {
put_guid(pb, &video_stream);
put_guid(pb, &video_conceal_none);
}
put_le64(pb, 0); /* ??? */
put_le32(pb, extra_size); /* wav header len */
put_le32(pb, extra_size2); /* additional data len */
put_le16(pb, n + 1); /* stream number */
put_le32(pb, 0); /* ??? */
if (enc->codec->type == CODEC_TYPE_AUDIO) {
/* WAVEFORMATEX header */
put_le16(pb, 0x55); /* MP3 format */
put_le16(pb, s->audio_enc->channels);
put_le32(pb, s->audio_enc->rate);
put_le32(pb, s->audio_enc->bit_rate / 8);
put_le16(pb, 1); /* block align */
put_le16(pb, 16); /* bits per sample */
put_le16(pb, wav_extra_size);
/* no addtionnal adata */
} else {
put_le32(pb, enc->width);
put_le32(pb, enc->height);
put_byte(pb, 2); /* ??? */
put_le16(pb, 40); /* size */
/* BITMAPINFOHEADER header */
put_le32(pb, 40); /* size */
put_le32(pb, enc->width);
put_le32(pb, enc->height);
put_le16(pb, 1); /* planes */
put_le16(pb, 24); /* depth */
/* compression type */
switch(enc->codec->id) {
case CODEC_ID_H263:
put_tag(pb, "I263");
break;
case CODEC_ID_MJPEG:
put_tag(pb, "MJPG");
break;
default:
put_tag(pb, "XXXX");
break;
}
put_le32(pb, enc->width * enc->height * 3);
put_le32(pb, 0);
put_le32(pb, 0);
put_le32(pb, 0);
put_le32(pb, 0);
}
n++;
}
asf->nb_streams = n;
/* XXX: should media comments */
#if 0
put_guid(pb, &comment_header);
put_le64(pb, 0);
#endif
/* patch the header size fields */
cur_pos = put_pos(pb);
header_size = cur_pos - header_offset;
if (!s->is_streamed) {
header_size += 24 + 6;
put_seek(pb, header_offset - 14, SEEK_SET);
put_le64(pb, header_size);
} else {
header_size += 8 + 50;
put_seek(pb, header_offset - 10, SEEK_SET);
put_le16(pb, header_size);
put_seek(pb, header_offset - 2, SEEK_SET);
put_le16(pb, header_size);
}
put_seek(pb, cur_pos, SEEK_SET);
/* movie chunk, followed by packets of packet_size */
asf->data_offset = cur_pos;
put_guid(pb, &data_header);
put_le64(pb, 24); /* will be patched after */
put_guid(pb, &packet_guid);
put_le64(pb, 0x283); /* ??? */
put_byte(pb, 1); /* ??? */
put_byte(pb, 1); /* ??? */
put_flush_packet(&s->pb);
asf->packet_nb_frames = 0;
asf->packet_timestamp_start = -1;
asf->packet_timestamp_end = -1;
asf->packet_size_left = asf->packet_size - PACKET_HEADER_SIZE;
init_put_byte(&asf->pb, asf->packet_buf, asf->packet_size,
NULL, NULL, NULL);
return 0;
}
/* write a fixed size packet */
static void put_packet(AVFormatContext *s,
unsigned int timestamp, unsigned int duration,
int nb_frames, int padsize)
{
ASFContext *asf = s->priv_data;
PutByteContext *pb = &s->pb;
int flags;
if (s->is_streamed) {
put_chunk(s, 0x4424, asf->packet_size);
}
put_byte(pb, 0x82);
put_le16(pb, 0);
flags = 0x01; /* nb segments present */
if (padsize > 0) {
if (padsize < 256)
flags |= 0x08;
else
flags |= 0x10;
}
put_byte(pb, flags); /* flags */
put_byte(pb, 0x5d);
if (flags & 0x10)
put_le16(pb, padsize);
if (flags & 0x08)
put_byte(pb, padsize);
put_le32(pb, timestamp);
put_le16(pb, duration);
put_byte(pb, nb_frames | 0x80);
}
static void flush_packet(AVFormatContext *s)
{
ASFContext *asf = s->priv_data;
int hdr_size, ptr;
put_packet(s, asf->packet_timestamp_start,
asf->packet_timestamp_end - asf->packet_timestamp_start,
asf->packet_nb_frames, asf->packet_size_left);
/* compute padding */
hdr_size = PACKET_HEADER_SIZE;
if (asf->packet_size_left > 0) {
/* if padding needed, don't forget to count the
padding byte in the header size */
hdr_size++;
asf->packet_size_left--;
/* XXX: I do not test again exact limit to avoid boundary problems */
if (asf->packet_size_left > 200) {
hdr_size++;
asf->packet_size_left--;
}
}
ptr = asf->packet_size - PACKET_HEADER_SIZE - asf->packet_size_left;
memset(asf->packet_buf + ptr, 0, asf->packet_size_left);
put_buffer(&s->pb, asf->packet_buf, asf->packet_size - hdr_size);
put_flush_packet(&s->pb);
asf->packet_nb_frames = 0;
asf->packet_timestamp_start = -1;
asf->packet_timestamp_end = -1;
asf->packet_size_left = asf->packet_size - PACKET_HEADER_SIZE;
init_put_byte(&asf->pb, asf->packet_buf, asf->packet_size,
NULL, NULL, NULL);
}
static void put_frame_header(AVFormatContext *s, ASFStream *stream, int timestamp,
int payload_size, int frag_offset, int frag_len)
{
ASFContext *asf = s->priv_data;
PutByteContext *pb = &asf->pb;
int val;
val = stream->num;
if (stream->enc->key_frame)
val |= 0x80;
put_byte(pb, val);
put_byte(pb, stream->seq);
put_le32(pb, frag_offset); /* fragment offset */
put_byte(pb, 0x08); /* flags */
put_le32(pb, payload_size);
put_le32(pb, timestamp);
put_le16(pb, frag_len);
}
/* Output a frame. We suppose that payload_size <= PACKET_SIZE.
It is there that you understand that the ASF format is really
crap. They have misread the MPEG Systems spec !
*/
static void put_frame(AVFormatContext *s, ASFStream *stream, int timestamp,
UINT8 *buf, int payload_size)
{
ASFContext *asf = s->priv_data;
int frag_pos, frag_len, frag_len1;
frag_pos = 0;
while (frag_pos < payload_size) {
frag_len = payload_size - frag_pos;
frag_len1 = asf->packet_size_left - FRAME_HEADER_SIZE;
if (frag_len1 > 0) {
if (frag_len > frag_len1)
frag_len = frag_len1;
put_frame_header(s, stream, timestamp, payload_size, frag_pos, frag_len);
put_buffer(&asf->pb, buf, frag_len);
asf->packet_size_left -= (frag_len + FRAME_HEADER_SIZE);
asf->packet_timestamp_end = timestamp;
if (asf->packet_timestamp_start == -1)
asf->packet_timestamp_start = timestamp;
asf->packet_nb_frames++;
} else {
frag_len = 0;
}
frag_pos += frag_len;
buf += frag_len;
/* output the frame if filled */
if (asf->packet_size_left <= FRAME_HEADER_SIZE)
flush_packet(s);
}
stream->seq++;
}
static int asf_write_audio(AVFormatContext *s, UINT8 *buf, int size)
{
ASFContext *asf = s->priv_data;
int timestamp;
timestamp = (int)((float)s->audio_enc->frame_number * s->audio_enc->frame_size * 1000.0 /
s->audio_enc->rate);
put_frame(s, asf->audio_stream, timestamp, buf, size);
return 0;
}
static int asf_write_video(AVFormatContext *s, UINT8 *buf, int size)
{
ASFContext *asf = s->priv_data;
int timestamp;
timestamp = (int)((float)s->video_enc->frame_number * 1000.0 /
s->video_enc->rate);
put_frame(s, asf->audio_stream, timestamp, buf, size);
return 0;
}
static int asf_write_trailer(AVFormatContext *s)
{
ASFContext *asf = s->priv_data;
long long file_size;
/* flush the current packet */
if (asf->pb.buf_ptr > asf->pb.buffer)
flush_packet(s);
if (s->is_streamed) {
put_chunk(s, 0x4524, 0); /* end of stream */
} else {
/* patch the various place which depends on the file size */
file_size = put_pos(&s->pb);
put_seek(&s->pb, asf->file_size_offset, SEEK_SET);
put_le64(&s->pb, file_size);
put_seek(&s->pb, asf->data_offset + 16, SEEK_SET);
put_le64(&s->pb, file_size - asf->data_offset);
}
put_flush_packet(&s->pb);
free(asf);
return 0;
}
AVFormat asf_format = {
"asf",
"asf format",
"application/octet-stream",
"asf",
CODEC_ID_MP2,
CODEC_ID_MJPEG,
asf_write_header,
asf_write_audio,
asf_write_video,
asf_write_trailer,
};

@ -0,0 +1,14 @@
- 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.

@ -0,0 +1,25 @@
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.

@ -0,0 +1,19 @@
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.

@ -0,0 +1,62 @@
* 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.

@ -0,0 +1,214 @@
# 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>

@ -0,0 +1,717 @@
/*
* Basic user interface for ffmpeg 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 <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 "mpegenc.h"
#include "mpegvideo.h"
static AVFormat *file_format;
static int frame_width = 160;
static int frame_height = 128;
static int frame_rate = 25;
static int bit_rate = 200000;
static int video_disable = 0;
static const char *video_filename, *audio_filename;
static float recording_time = 10.0;
static int nb_frames;
static int gop_size = 12;
static int intra_only = 0;
static int audio_freq = 44100;
static int audio_bit_rate = 64000;
static int audio_disable = 0;
static int audio_channels = 1;
static long long time_start;
static int file_read_picture(AVEncodeContext *s,
UINT8 *picture[3],
int width, int height,
int picture_number)
{
FILE *f;
char buf[1024];
static int init = 0;
static UINT8 *pict[3];
if (!init) {
pict[0] = malloc(width * height);
pict[1] = malloc(width * height / 4);
pict[2] = malloc(width * height / 4);
init = 1;
}
picture[0] = pict[0];
picture[1] = pict[1];
picture[2] = pict[2];
sprintf(buf, "%s%d.Y", video_filename, picture_number);
f=fopen(buf, "r");
if (!f) {
return -1;
}
fread(picture[0], 1, width * height, f);
fclose(f);
sprintf(buf, "%s%d.U", video_filename, picture_number);
f=fopen(buf, "r");
if (!f) {
perror(buf);
exit(1);
}
fread(picture[1], 1, width * height / 4, f);
fclose(f);
sprintf(buf, "%s%d.V", video_filename, picture_number);
f=fopen(buf, "r");
if (!f) {
perror(buf);
exit(1);
}
fread(picture[2], 1, width * height / 4, f);
fclose(f);
return 0;
}
static void display_stats(AVEncodeContext *video_ctx,
AVEncodeContext *audio_ctx,
int batch_mode, int the_end)
{
if (video_ctx &&
((video_ctx->frame_number % video_ctx->rate) == 0 ||
the_end)) {
float ti;
if (batch_mode) {
ti = (float)video_ctx->frame_number / video_ctx->rate;
} else {
ti = (gettime() - time_start) / 1000000.0;
if (ti < 0.1)
ti = 0.1;
}
fprintf(stderr,
"frame=%5d size=%8dkB time=%0.1f fps=%4.1f bitrate=%6.1fkbits/s q=%2d\r",
video_ctx->frame_number,
data_out_size / 1024,
ti,
video_ctx->frame_number / ti,
(data_out_size * 8 / ti / 1000),
((MpegEncContext *)video_ctx->priv_data)->qscale);
if (the_end) {
fprintf(stderr,"\n");
}
fflush(stderr);
}
#if 0
if (the_end && batch_mode && audio_ctx) {
duration = (gettime() - ti) / 1000000.0;
factor = 0;
if (ti > 0) {
factor = (float)nb_samples / s->sample_rate / duration;
}
fprintf(stderr, "%0.1f seconds compressed in %0.1f seconds (speed factor: %0.1f)\n",
(float)nb_samples / s->sample_rate,
duration,
factor);
}
#endif
}
void raw_write_data(void *opaque,
unsigned char *buf, int size)
{
FILE *outfile = opaque;
fwrite(buf, 1, size, outfile);
data_out_size += size;
}
int raw_seek(void *opaque, long long offset, int whence)
{
FILE *outfile = opaque;
fseek(outfile, offset, whence);
return 0;
}
static void av_encode(AVFormatContext *ctx,
const char *video_filename,
const char *audio_filename)
{
UINT8 audio_buffer[4096];
UINT8 video_buffer[128*1024];
char buf[256];
short *samples;
int ret;
int audio_fd;
FILE *infile;
int sample_count;
int batch_mode;
AVEncodeContext *audio_enc, *video_enc;
int frame_size, frame_bytes;
AVEncoder *audio_encoder, *video_encoder;
UINT8 *picture[3];
/* audio */
audio_enc = ctx->audio_enc;
sample_count = 0;
infile = NULL;
frame_size = 0;
samples = NULL;
audio_fd = -1;
frame_bytes = 0;
batch_mode = 0;
if (audio_filename ||
video_filename)
batch_mode = 1;
if (audio_enc) {
if (batch_mode) {
if (!audio_filename) {
fprintf(stderr, "Must give audio input file\n");
exit(1);
}
infile = fopen(audio_filename, "r");
if (!infile) {
fprintf(stderr, "Could not open '%s'\n", audio_filename);
exit(1);
}
audio_fd = -1;
} else {
audio_fd = audio_open(audio_enc->rate, audio_enc->channels);
if (audio_fd < 0) {
fprintf(stderr, "Could not open audio device\n");
exit(1);
}
}
audio_encoder = avencoder_find(ctx->format->audio_codec);
if (avencoder_open(audio_enc, audio_encoder) < 0) {
fprintf(stderr, "Audio encoder: incorrect audio frequency or bitrate\n");
exit(1);
}
avencoder_string(buf, sizeof(buf), audio_enc);
fprintf(stderr, " %s\n", buf);
frame_size = audio_enc->frame_size;
frame_bytes = frame_size * 2 * audio_enc->channels;
samples = malloc(frame_bytes);
}
/* video */
video_enc = ctx->video_enc;
if (video_enc) {
if (batch_mode) {
if (!video_filename) {
fprintf(stderr, "Must give video input file\n");
exit(1);
}
} else {
ret = v4l_init(video_enc->rate, video_enc->width, video_enc->height);
if (ret < 0) {
fprintf(stderr,"Could not init video 4 linux capture\n");
exit(1);
}
}
video_encoder = avencoder_find(ctx->format->video_codec);
if (avencoder_open(video_enc, video_encoder) < 0) {
fprintf(stderr, "Error while initializing video codec\n");
exit(1);
}
avencoder_string(buf, sizeof(buf), video_enc);
fprintf(stderr, " %s\n", buf);
}
ctx->format->write_header(ctx);
time_start = gettime();
for(;;) {
/* read & compression audio frames */
if (audio_enc) {
if (!batch_mode) {
for(;;) {
ret = read(audio_fd, samples, frame_bytes);
if (ret != frame_bytes)
break;
ret = avencoder_encode(audio_enc,
audio_buffer, sizeof(audio_buffer), samples);
ctx->format->write_audio_frame(ctx, audio_buffer, ret);
}
} else {
if (video_enc)
sample_count += audio_enc->rate / video_enc->rate;
else
sample_count += frame_size;
while (sample_count > frame_size) {
if (fread(samples, 1, frame_bytes, infile) == 0)
goto the_end;
ret = avencoder_encode(audio_enc,
audio_buffer, sizeof(audio_buffer), samples);
ctx->format->write_audio_frame(ctx, audio_buffer, ret);
sample_count -= frame_size;
}
}
}
if (video_enc) {
/* read video image */
if (batch_mode) {
ret = file_read_picture (video_enc, picture,
video_enc->width, video_enc->height,
video_enc->frame_number);
} else {
ret = v4l_read_picture (picture,
video_enc->width, video_enc->height,
video_enc->frame_number);
}
if (ret < 0)
break;
ret = avencoder_encode(video_enc, video_buffer, sizeof(video_buffer), picture);
ctx->format->write_video_picture(ctx, video_buffer, ret);
}
display_stats(video_enc, NULL, batch_mode, 0);
if (video_enc && video_enc->frame_number >= nb_frames)
break;
}
the_end:
display_stats(video_enc, NULL, batch_mode, 1);
if (video_enc)
avencoder_close(video_enc);
if (audio_enc)
avencoder_close(audio_enc);
ctx->format->write_trailer(ctx);
if (!infile) {
close(audio_fd);
} else {
fclose(infile);
}
}
typedef struct {
const char *str;
int width, height;
} SizeEntry;
SizeEntry sizes[] = {
{ "sqcif", 128, 96 },
{ "qcif", 176, 144 },
{ "cif", 352, 288 },
{ "4cif", 704, 576 },
};
enum {
OPT_AR=256,
OPT_AB,
OPT_AN,
OPT_AC,
OPT_VN,
};
struct option long_options[] =
{
{ "ar", required_argument, NULL, OPT_AR },
{ "ab", required_argument, NULL, OPT_AB },
{ "an", no_argument, NULL, OPT_AN },
{ "ac", required_argument, NULL, OPT_AC },
{ "vn", no_argument, NULL, OPT_VN },
};
enum {
OUT_FILE,
OUT_PIPE,
OUT_UDP,
};
void help(void)
{
AVFormat *f;
printf("ffmpeg version 1.0, Copyright (c) 2000 Gerard Lantau\n"
"usage: ffmpeg [options] outfile [video_infile] [audio_infile]\n"
"Hyper fast MPEG1 video/H263/RV and AC3/MPEG audio layer 2 encoder\n"
"\n"
"Main options are:\n"
"\n"
"-L print the LICENSE\n"
"-s size set frame size [%dx%d]\n"
"-f format set encoding format [%s]\n"
"-r fps set frame rate [%d]\n"
"-b bitrate set the total bitrate in kbit/s [%d]\n"
"-t time set recording time in seconds [%0.1f]\n"
"-ar freq set the audio sampling freq [%d]\n"
"-ab bitrate set the audio bitrate in kbit/s [%d]\n"
"-ac channels set the number of audio channels [%d]\n"
"-an disable audio recording [%s]\n"
"-vn disable video recording [%s]\n"
"\n"
"Frame sizes abbreviations: sqcif qcif cif 4cif\n",
frame_width, frame_height,
file_format->name,
frame_rate,
bit_rate / 1000,
recording_time,
audio_freq,
audio_bit_rate / 1000,
audio_channels,
audio_disable ? "yes" : "no",
video_disable ? "yes" : "no");
printf("Encoding video formats:");
for(f = first_format; f != NULL; f = f->next)
printf(" %s", f->name);
printf("\n");
printf("outfile can be a file name, - (pipe) or 'udp:host:port'\n"
"\n"
"Advanced options are:\n"
"-d device set video4linux device name\n"
"-g gop_size set the group of picture size [%d]\n"
"-i use only intra frames [%s]\n"
"-c comment set the comment string\n"
"\n",
gop_size,
intra_only ? "yes" : "no");
}
void licence(void)
{
printf(
"ffmpeg version 1.0\n"
"Copyright (c) 2000 Gerard Lantau\n"
"This program is free software; you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License as published by\n"
"the Free Software Foundation; either version 2 of the License, or\n"
"(at your option) any later version.\n"
"\n"
"This program is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public License for more details.\n"
"\n"
"You should have received a copy of the GNU General Public License\n"
"along with this program; if not, write to the Free Software\n"
"Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
);
}
static unsigned char output_buffer[32768];
int main(int argc, char **argv)
{
AVEncodeContext video_enc1, *video_enc = &video_enc1;
AVEncodeContext audio_enc1, *audio_enc = &audio_enc1;
UDPContext udp_ctx1, *udp_ctx = &udp_ctx1;
AVFormatContext av_ctx1, *av_ctx = &av_ctx1;
FILE *outfile;
int i, c;
char *filename;
int output_type;
int use_video, use_audio;
register_avencoder(&ac3_encoder);
register_avencoder(&mp2_encoder);
register_avencoder(&mpeg1video_encoder);
register_avencoder(&h263_encoder);
register_avencoder(&rv10_encoder);
register_avencoder(&mjpeg_encoder);
register_avformat(&mp2_format);
register_avformat(&ac3_format);
register_avformat(&mpeg1video_format);
register_avformat(&h263_format);
register_avformat(&mpeg_mux_format);
register_avformat(&ra_format);
register_avformat(&rm_format);
register_avformat(&asf_format);
register_avformat(&mpjpeg_format);
register_avformat(&swf_format);
file_format = NULL;
for(;;) {
c = getopt_long_only(argc, argv, "s:f:r:b:t:hd:g:ic:L",
long_options, NULL);
if (c == -1)
break;
switch(c) {
case 'L':
licence();
exit(1);
case 'h':
help();
exit(1);
case 's':
{
int n = sizeof(sizes) / sizeof(SizeEntry);
const char *p;
for(i=0;i<n;i++) {
if (!strcmp(sizes[i].str, optarg)) {
frame_width = sizes[i].width;
frame_height = sizes[i].height;
break;
}
}
if (i == n) {
p = optarg;
frame_width = strtol(p, (char **)&p, 10);
if (*p)
p++;
frame_height = strtol(p, (char **)&p, 10);
}
}
break;
case 'f':
{
AVFormat *f;
f = first_format;
while (f != NULL && strcmp(f->name, optarg) != 0) f = f->next;
if (f == NULL) {
fprintf(stderr, "Invalid format: %s\n", optarg);
exit(1);
}
file_format = f;
}
break;
case 'r':
{
frame_rate = atoi(optarg);
}
break;
case 'b':
{
bit_rate = atoi(optarg) * 1000;
}
break;
case 't':
{
recording_time = atof(optarg);
break;
}
/* audio specific */
case OPT_AR:
{
audio_freq = atoi(optarg);
break;
}
case OPT_AB:
{
audio_bit_rate = atoi(optarg) * 1000;
break;
}
case OPT_AN:
audio_disable = 1;
break;
case OPT_VN:
video_disable = 1;
break;
case OPT_AC:
{
audio_channels = atoi(optarg);
if (audio_channels != 1 &&
audio_channels != 2) {
fprintf(stderr, "Incorrect number of channels: %d\n", audio_channels);
exit(1);
}
}
break;
/* advanced options */
case 'd':
v4l_device = optarg;
break;
case 'g':
gop_size = atoi(optarg);
break;
case 'i':
intra_only = 1;
break;
case 'c':
comment_string = optarg;
break;
default:
exit(2);
}
}
if (optind >= argc) {
help();
exit(1);
}
filename = argv[optind++];
video_filename = NULL;
audio_filename = NULL;
/* auto detect format */
if (file_format == NULL)
file_format = guess_format(NULL, filename, NULL);
if (file_format == NULL)
file_format = &mpeg_mux_format;
/* check parameters */
if (frame_width <= 0 || frame_height <= 0) {
fprintf(stderr, "Incorrect frame size\n");
exit(1);
}
if ((frame_width % 16) != 0 || (frame_height % 16) != 0) {
fprintf(stderr, "Frame size must be a multiple of 16\n");
exit(1);
}
if (bit_rate < 5000 || bit_rate >= 10000000) {
fprintf(stderr, "Invalid bit rate\n");
exit(1);
}
if (frame_rate < 1 || frame_rate >= 60) {
fprintf(stderr, "Invalid frame rate\n");
exit(1);
}
nb_frames = (int)(recording_time * frame_rate);
if (nb_frames < 1) {
fprintf(stderr, "Invalid recording time\n");
exit(1);
}
use_video = file_format->video_codec != CODEC_ID_NONE;
use_audio = file_format->audio_codec != CODEC_ID_NONE;
if (audio_disable) {
use_audio = 0;
}
if (video_disable) {
use_video = 0;
}
if (use_video == 0 && use_audio == 0) {
fprintf(stderr, "No audio or video selected\n");
exit(1);
}
fprintf(stderr, "Recording: %s, %0.1f seconds\n",
file_format->name,
recording_time);
/* open output media */
if (strstart(filename, "udp:", NULL)) {
output_type = OUT_UDP;
outfile = NULL;
memset(udp_ctx, 0, sizeof(*udp_ctx));
if (udp_tx_open(udp_ctx, filename, 0) < 0) {
fprintf(stderr, "Could not open UDP socket\n");
exit(1);
}
} else if (!strcmp(filename, "-")) {
output_type = OUT_PIPE;
outfile = stdout;
} else {
output_type = OUT_FILE;
outfile = fopen(filename, "w");
if (!outfile) {
perror(filename);
exit(1);
}
}
av_ctx->video_enc = NULL;
av_ctx->audio_enc = NULL;
if (output_type == OUT_UDP) {
init_put_byte(&av_ctx->pb, output_buffer, sizeof(output_buffer),
udp_ctx, udp_write_data, NULL);
} else {
init_put_byte(&av_ctx->pb, output_buffer, sizeof(output_buffer),
outfile, raw_write_data, raw_seek);
}
if (use_video) {
if (optind < argc) {
video_filename = argv[optind++];
}
/* init mpeg video encoding context */
memset(video_enc, 0, sizeof(*video_enc));
video_enc->bit_rate = bit_rate;
video_enc->rate = frame_rate;
video_enc->width = frame_width;
video_enc->height = frame_height;
if (!intra_only)
video_enc->gop_size = gop_size;
else
video_enc->gop_size = 0;
av_ctx->video_enc = video_enc;
av_ctx->format = file_format;
}
if (use_audio) {
if (optind < argc) {
audio_filename = argv[optind++];
}
audio_enc->bit_rate = audio_bit_rate;
audio_enc->rate = audio_freq;
audio_enc->channels = audio_channels;
av_ctx->audio_enc = audio_enc;
}
av_ctx->format = file_format;
av_ctx->is_streamed = 0;
av_encode(av_ctx, video_filename, audio_filename);
/* close output media */
switch(output_type) {
case OUT_FILE:
fclose(outfile);
break;
case OUT_PIPE:
break;
case OUT_UDP:
udp_tx_close(udp_ctx);
break;
}
fprintf(stderr, "\n");
return 0;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,373 @@
#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->pos + s->buf_ptr - s->buffer;
offset1 = offset - s->pos;
if (offset1 >= 0 && offset1 < (s->buf_end - s->buffer)) {
/* can do the seek inside the buffer */
s->buf_ptr = s->buffer + offset1;
} else {
if (!s->write_seek)
return -1;
flush_buffer(s);
s->write_seek(s->opaque, offset, whence);
}
return offset;
}
long long put_pos(PutByteContext *s)
{
return put_seek(s, 0, SEEK_CUR);
}
void put_le32(PutByteContext *s, unsigned int val)
{
put_byte(s, val);
put_byte(s, val >> 8);
put_byte(s, val >> 16);
put_byte(s, val >> 24);
}
void put_le64(PutByteContext *s, unsigned long long val)
{
put_le32(s, val & 0xffffffff);
put_le32(s, val >> 32);
}
void put_le16(PutByteContext *s, unsigned int val)
{
put_byte(s, val);
put_byte(s, val >> 8);
}
void put_tag(PutByteContext *s, char *tag)
{
while (*tag) {
put_byte(s, *tag++);
}
}

258
grab.c

@ -0,0 +1,258 @@
/*
* Linux audio/video grab interface
* 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 <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 "mpegenc.h"
#include "mpegvideo.h"
long long gettime(void)
{
struct timeval tv;
gettimeofday(&tv,NULL);
return (long long)tv.tv_sec * 1000000 + tv.tv_usec;
}
/* v4l capture */
const char *v4l_device = "/dev/video";
static struct video_capability video_cap;
int video_fd = -1;
UINT8 *video_buf, *picture_buf;
struct video_mbuf gb_buffers;
struct video_mmap gb_buf;
struct video_audio audio;
int gb_frame = 0;
long long time_frame;
int frame_rate;
int use_mmap = 0;
int v4l_init(int rate, int width, int height)
{
frame_rate = rate;
video_fd = open(v4l_device, O_RDWR);
if (ioctl(video_fd,VIDIOCGCAP,&video_cap) < 0) {
perror("VIDIOCGCAP");
return -1;
}
/* unmute audio */
ioctl(video_fd, VIDIOCGAUDIO, &audio);
audio.flags &= ~VIDEO_AUDIO_MUTE;
ioctl(video_fd, VIDIOCSAUDIO, &audio);
if (!(video_cap.type & VID_TYPE_CAPTURE)) {
/* try to use read based access */
struct video_window win;
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);
val = 1;
ioctl(video_fd, VIDIOCCAPTURE, &val);
video_buf = malloc( width * height * 2);
picture_buf = malloc( (width * height * 3) / 2);
use_mmap = 0;
return 0;
}
if (ioctl(video_fd,VIDIOCGMBUF,&gb_buffers) < 0) {
perror("ioctl VIDIOCGMBUF");
}
video_buf = mmap(0,gb_buffers.size,PROT_READ|PROT_WRITE,MAP_SHARED,video_fd,0);
if ((unsigned char*)-1 == video_buf) {
perror("mmap");
return -1;
}
gb_frame = 0;
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;
if (ioctl(video_fd, VIDIOCMCAPTURE, &gb_buf) < 0) {
if (errno == EAGAIN)
fprintf(stderr,"Cannot Sync\n");
else
perror("VIDIOCMCAPTURE");
return -1;
}
use_mmap = 1;
return 0;
}
/* test with read call and YUV422 stream */
static int v4l_basic_read_picture(UINT8 *picture[3],
int width, int height,
int picture_number)
{
int x, y;
UINT8 *p, *lum, *cb, *cr;
if (read(video_fd, video_buf, width * height * 2) < 0)
perror("read");
picture[0] = picture_buf;
picture[1] = picture_buf + width * height;
picture[2] = picture_buf + (width * height) + (width * height) / 4;
/* XXX: optimize */
lum = picture[0];
cb = picture[1];
cr = picture[2];
p = video_buf;
for(y=0;y<height;y+=2) {
for(x=0;x<width;x+=2) {
lum[0] = p[0];
cb[0] = p[1];
lum[1] = p[2];
cr[0] = p[3];
p += 4;
lum += 2;
cb++;
cr++;
}
for(x=0;x<width;x+=2) {
lum[0] = p[0];
lum[1] = p[2];
p += 4;
lum += 2;
}
}
return 0;
}
static int v4l_mm_read_picture(UINT8 *picture[3],
int width, int height,
int picture_number)
{
UINT8 *ptr;
int size;
long long curtime;
/* wait based on the frame rate */
time_frame += 1000000 / frame_rate;
do {
curtime = gettime();
} while (curtime < time_frame);
gb_buf.frame = gb_frame;
if (ioctl(video_fd, VIDIOCMCAPTURE, &gb_buf) < 0) {
if (errno == EAGAIN)
fprintf(stderr,"Cannot Sync\n");
else
perror("VIDIOCMCAPTURE");
return -1;
}
gb_frame = 1 - gb_frame;
if (ioctl(video_fd, VIDIOCSYNC, &gb_frame) < 0) {
if (errno != EAGAIN) {
perror("VIDIOCSYNC");
}
}
size = width * height;
ptr = video_buf + gb_buffers.offsets[gb_frame];
picture[0] = ptr;
picture[1] = ptr + size;
picture[2] = ptr + size + (size / 4);
return 0;
}
int v4l_read_picture(UINT8 *picture[3],
int width, int height,
int picture_number)
{
if (use_mmap) {
return v4l_mm_read_picture(picture, width, height, picture_number);
} else {
return v4l_basic_read_picture(picture, width, height, picture_number);
}
}
/* open audio device */
int audio_open(int freq, int channels)
{
int audio_fd, tmp, err;
audio_fd = open("/dev/dsp",O_RDONLY);
if (audio_fd == -1) {
perror("/dev/dsp");
return -1;
}
/* 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
/* always set to this size */
/* XXX: incorrect if big endian */
tmp=AFMT_S16_LE;
err=ioctl(audio_fd,SNDCTL_DSP_SETFMT,&tmp);
if (err < 0) {
perror("SNDCTL_DSP_SETFMT");
}
tmp= (channels == 2);
err=ioctl(audio_fd,SNDCTL_DSP_STEREO,&tmp);
if (err < 0) {
perror("SNDCTL_DSP_STEREO");
}
/* should be last */
tmp = freq;
err=ioctl(audio_fd, SNDCTL_DSP_SPEED, &tmp);
if (err < 0) {
perror("SNDCTL_DSP_SPEED");
}
return audio_fd;
}

@ -0,0 +1,102 @@
/*
* 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 "mpegenc.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_video(AVFormatContext *s, 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,
NULL,
mpjpeg_write_video,
mpjpeg_write_trailer,
};
/* single frame JPEG */
static int jpeg_write_header(AVFormatContext *s)
{
return 0;
}
static int jpeg_write_video(AVFormatContext *s, 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,
NULL,
jpeg_write_video,
jpeg_write_trailer,
};

@ -0,0 +1,17 @@
CFLAGS= -O2 -Wall -g
LDFLAGS= -g
OBJS= common.o mpegvideo.o h263enc.o jrevdct.o jfdctfst.o \
mpegaudio.o ac3enc.o mjpegenc.o resample.o
LIB= libav.a
all: $(LIB)
$(LIB): $(OBJS)
ar rcs $@ $(OBJS)
%.o: %.c
gcc $(CFLAGS) -c -o $@ $<
clean:
rm -f *.o *~ *.a

File diff suppressed because it is too large Load Diff

@ -0,0 +1,32 @@
#define AC3_FRAME_SIZE (6*256)
#define AC3_MAX_CODED_FRAME_SIZE 3840 /* in bytes */
#define AC3_MAX_CHANNELS 2 /* we handle at most two channels, although
AC3 allows 6 channels */
typedef struct AC3EncodeContext {
PutBitContext pb;
int nb_channels;
int bit_rate;
int sample_rate;
int bsid;
int frame_size_min; /* minimum frame size in case rounding is necessary */
int frame_size; /* current frame size in words */
int halfratecod;
int frmsizecod;
int fscod; /* frequency */
int acmod;
int bsmod;
short last_samples[AC3_MAX_CHANNELS][256];
int chbwcod[AC3_MAX_CHANNELS];
int nb_coefs[AC3_MAX_CHANNELS];
/* bitrate allocation control */
int sgaincod, sdecaycod, fdecaycod, dbkneecod, floorcod;
int sgain, sdecay, fdecay, dbknee, floor;
int csnroffst;
int fgaincod[AC3_MAX_CHANNELS];
int fsnroffst[AC3_MAX_CHANNELS];
/* mantissa encoding */
int mant1_cnt, mant2_cnt, mant4_cnt;
} AC3EncodeContext;

@ -0,0 +1,180 @@
/* tables taken directly from AC3 spec */
/* possible bitrates */
static const UINT16 bitratetab[19] = {
32, 40, 48, 56, 64, 80, 96, 112, 128,
160, 192, 224, 256, 320, 384, 448, 512, 576, 640
};
/* AC3 MDCT window */
/* MDCT window */
static const INT16 ac3_window[256]= {
4, 7, 12, 16, 21, 28, 34, 42,
51, 61, 72, 84, 97, 111, 127, 145,
164, 184, 207, 231, 257, 285, 315, 347,
382, 419, 458, 500, 544, 591, 641, 694,
750, 810, 872, 937, 1007, 1079, 1155, 1235,
1318, 1406, 1497, 1593, 1692, 1796, 1903, 2016,
2132, 2253, 2379, 2509, 2644, 2783, 2927, 3076,
3230, 3389, 3552, 3721, 3894, 4072, 4255, 4444,
4637, 4835, 5038, 5246, 5459, 5677, 5899, 6127,
6359, 6596, 6837, 7083, 7334, 7589, 7848, 8112,
8380, 8652, 8927, 9207, 9491, 9778,10069,10363,
10660,10960,11264,11570,11879,12190,12504,12820,
13138,13458,13780,14103,14427,14753,15079,15407,
15735,16063,16392,16720,17049,17377,17705,18032,
18358,18683,19007,19330,19651,19970,20287,20602,
20914,21225,21532,21837,22139,22438,22733,23025,
23314,23599,23880,24157,24430,24699,24964,25225,
25481,25732,25979,26221,26459,26691,26919,27142,
27359,27572,27780,27983,28180,28373,28560,28742,
28919,29091,29258,29420,29577,29729,29876,30018,
30155,30288,30415,30538,30657,30771,30880,30985,
31086,31182,31274,31363,31447,31528,31605,31678,
31747,31814,31877,31936,31993,32046,32097,32145,
32190,32232,32272,32310,32345,32378,32409,32438,
32465,32490,32513,32535,32556,32574,32592,32608,
32623,32636,32649,32661,32671,32681,32690,32698,
32705,32712,32718,32724,32729,32733,32737,32741,
32744,32747,32750,32752,32754,32756,32757,32759,
32760,32761,32762,32763,32764,32764,32765,32765,
32766,32766,32766,32766,32767,32767,32767,32767,
32767,32767,32767,32767,32767,32767,32767,32767,
32767,32767,32767,32767,32767,32767,32767,32767,
};
static UINT8 masktab[253];
static const UINT8 latab[260]= {
0x0040,0x003f,0x003e,0x003d,0x003c,0x003b,0x003a,0x0039,0x0038,0x0037,
0x0036,0x0035,0x0034,0x0034,0x0033,0x0032,0x0031,0x0030,0x002f,0x002f,
0x002e,0x002d,0x002c,0x002c,0x002b,0x002a,0x0029,0x0029,0x0028,0x0027,
0x0026,0x0026,0x0025,0x0024,0x0024,0x0023,0x0023,0x0022,0x0021,0x0021,
0x0020,0x0020,0x001f,0x001e,0x001e,0x001d,0x001d,0x001c,0x001c,0x001b,
0x001b,0x001a,0x001a,0x0019,0x0019,0x0018,0x0018,0x0017,0x0017,0x0016,
0x0016,0x0015,0x0015,0x0015,0x0014,0x0014,0x0013,0x0013,0x0013,0x0012,
0x0012,0x0012,0x0011,0x0011,0x0011,0x0010,0x0010,0x0010,0x000f,0x000f,
0x000f,0x000e,0x000e,0x000e,0x000d,0x000d,0x000d,0x000d,0x000c,0x000c,
0x000c,0x000c,0x000b,0x000b,0x000b,0x000b,0x000a,0x000a,0x000a,0x000a,
0x000a,0x0009,0x0009,0x0009,0x0009,0x0009,0x0008,0x0008,0x0008,0x0008,
0x0008,0x0008,0x0007,0x0007,0x0007,0x0007,0x0007,0x0007,0x0006,0x0006,
0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0005,0x0005,0x0005,0x0005,
0x0005,0x0005,0x0005,0x0005,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,
0x0004,0x0004,0x0004,0x0004,0x0004,0x0003,0x0003,0x0003,0x0003,0x0003,
0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0002,
0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,
0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0001,0x0001,
0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,
0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,
0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
};
static const UINT16 hth[50][3]= {
{ 0x04d0,0x04f0,0x0580 },
{ 0x04d0,0x04f0,0x0580 },
{ 0x0440,0x0460,0x04b0 },
{ 0x0400,0x0410,0x0450 },
{ 0x03e0,0x03e0,0x0420 },
{ 0x03c0,0x03d0,0x03f0 },
{ 0x03b0,0x03c0,0x03e0 },
{ 0x03b0,0x03b0,0x03d0 },
{ 0x03a0,0x03b0,0x03c0 },
{ 0x03a0,0x03a0,0x03b0 },
{ 0x03a0,0x03a0,0x03b0 },
{ 0x03a0,0x03a0,0x03b0 },
{ 0x03a0,0x03a0,0x03a0 },
{ 0x0390,0x03a0,0x03a0 },
{ 0x0390,0x0390,0x03a0 },
{ 0x0390,0x0390,0x03a0 },
{ 0x0380,0x0390,0x03a0 },
{ 0x0380,0x0380,0x03a0 },
{ 0x0370,0x0380,0x03a0 },
{ 0x0370,0x0380,0x03a0 },
{ 0x0360,0x0370,0x0390 },
{ 0x0360,0x0370,0x0390 },
{ 0x0350,0x0360,0x0390 },
{ 0x0350,0x0360,0x0390 },
{ 0x0340,0x0350,0x0380 },
{ 0x0340,0x0350,0x0380 },
{ 0x0330,0x0340,0x0380 },
{ 0x0320,0x0340,0x0370 },
{ 0x0310,0x0320,0x0360 },
{ 0x0300,0x0310,0x0350 },
{ 0x02f0,0x0300,0x0340 },
{ 0x02f0,0x02f0,0x0330 },
{ 0x02f0,0x02f0,0x0320 },
{ 0x02f0,0x02f0,0x0310 },
{ 0x0300,0x02f0,0x0300 },
{ 0x0310,0x0300,0x02f0 },
{ 0x0340,0x0320,0x02f0 },
{ 0x0390,0x0350,0x02f0 },
{ 0x03e0,0x0390,0x0300 },
{ 0x0420,0x03e0,0x0310 },
{ 0x0460,0x0420,0x0330 },
{ 0x0490,0x0450,0x0350 },
{ 0x04a0,0x04a0,0x03c0 },
{ 0x0460,0x0490,0x0410 },
{ 0x0440,0x0460,0x0470 },
{ 0x0440,0x0440,0x04a0 },
{ 0x0520,0x0480,0x0460 },
{ 0x0800,0x0630,0x0440 },
{ 0x0840,0x0840,0x0450 },
{ 0x0840,0x0840,0x04e0 },
};
static const UINT8 baptab[64]= {
0, 1, 1, 1, 1, 1, 2, 2, 3, 3,
3, 4, 4, 5, 5, 6, 6, 6, 6, 7,
7, 7, 7, 8, 8, 8, 8, 9, 9, 9,
9, 10, 10, 10, 10, 11, 11, 11, 11, 12,
12, 12, 12, 13, 13, 13, 13, 14, 14, 14,
14, 14, 14, 14, 14, 15, 15, 15, 15, 15,
15, 15, 15, 15,
};
static const UINT8 sdecaytab[4]={
0x0f, 0x11, 0x13, 0x15,
};
static const UINT8 fdecaytab[4]={
0x3f, 0x53, 0x67, 0x7b,
};
static const UINT16 sgaintab[4]= {
0x540, 0x4d8, 0x478, 0x410,
};
static const UINT16 dbkneetab[4]= {
0x000, 0x700, 0x900, 0xb00,
};
static const UINT16 floortab[8]= {
0x2f0, 0x2b0, 0x270, 0x230, 0x1f0, 0x170, 0x0f0, 0xf800,
};
static const UINT16 fgaintab[8]= {
0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x400,
};
static const UINT8 bndsz[50]={
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3,
3, 6, 6, 6, 6, 6, 6, 12, 12, 12, 12, 24, 24, 24, 24, 24
};
static UINT8 bndtab[51];
/* fft & mdct sin cos tables */
static INT16 costab[64];
static INT16 sintab[64];
static INT16 fft_rev[512];
static INT16 xcos1[128];
static INT16 xsin1[128];
static UINT16 crc_table[256];

@ -0,0 +1,79 @@
#include "common.h"
enum CodecID {
CODEC_ID_NONE,
CODEC_ID_MPEG1VIDEO,
CODEC_ID_H263,
CODEC_ID_RV10,
CODEC_ID_MP2,
CODEC_ID_AC3,
CODEC_ID_MJPEG,
};
enum CodecType {
CODEC_TYPE_VIDEO,
CODEC_TYPE_AUDIO,
};
typedef struct AVEncodeContext {
int bit_rate;
int rate; /* frames per sec or samples per sec */
/* video only */
int width, height;
int gop_size; /* 0 = intra only */
/* audio only */
int channels;
/* the following data should not be initialized */
int frame_size; /* in samples, initialized when calling 'init' */
int frame_number; /* audio or video frame number */
int key_frame; /* true if the previous compressed frame was
a key frame (intra, or seekable) */
struct AVEncoder *codec;
void *priv_data;
} AVEncodeContext;
typedef struct AVEncoder {
char *name;
int type;
int id;
int priv_data_size;
int (*init)(AVEncodeContext *);
int (*encode)(AVEncodeContext *, UINT8 *buf, int buf_size, void *data);
int (*close)(AVEncodeContext *);
struct AVEncoder *next;
} AVEncoder;
extern AVEncoder ac3_encoder;
extern AVEncoder mp2_encoder;
extern AVEncoder mpeg1video_encoder;
extern AVEncoder h263_encoder;
extern AVEncoder rv10_encoder;
extern AVEncoder mjpeg_encoder;
/* resample.c */
typedef struct {
/* fractional resampling */
UINT32 incr; /* fractional increment */
UINT32 frac;
int last_sample;
/* integer down sample */
int iratio; /* integer divison ratio */
int icount, isum;
int inv;
} ReSampleChannelContext;
typedef struct {
ReSampleChannelContext channel_ctx[2];
float ratio;
/* channel convert */
int input_channels, output_channels;
} ReSampleContext;
int audio_resample_init(ReSampleContext *s,
int output_channels, int input_channels,
int output_rate, int input_rate);
int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples);

@ -0,0 +1,174 @@
/*
* Common bit/dsp utils
* 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 <netinet/in.h>
#include <math.h>
#include "common.h"
#define NDEBUG
#include <assert.h>
void init_put_bits(PutBitContext *s,
UINT8 *buffer, int buffer_size,
void *opaque,
void (*write_data)(void *, UINT8 *, int))
{
s->buf = buffer;
s->buf_ptr = s->buf;
s->buf_end = s->buf + buffer_size;
s->bit_cnt=0;
s->bit_buf=0;
s->data_out_size = 0;
s->write_data = write_data;
s->opaque = opaque;
}
static void flush_buffer(PutBitContext *s)
{
int size;
if (s->write_data) {
size = s->buf_ptr - s->buf;
if (size > 0)
s->write_data(s->opaque, s->buf, size);
s->buf_ptr = s->buf;
s->data_out_size += size;
}
}
void put_bits(PutBitContext *s, int n, unsigned int value)
{
unsigned int bit_buf;
int bit_cnt;
assert(n == 32 || value < (1U << n));
bit_buf = s->bit_buf;
bit_cnt = s->bit_cnt;
// printf("n=%d value=%x cnt=%d buf=%x\n", n, value, bit_cnt, bit_buf);
/* XXX: optimize */
if (n < (32-bit_cnt)) {
bit_buf |= value << (32 - n - bit_cnt);
bit_cnt+=n;
} else {
bit_buf |= value >> (n + bit_cnt - 32);
*(UINT32 *)s->buf_ptr = htonl(bit_buf);
//printf("bitbuf = %08x\n", bit_buf);
s->buf_ptr+=4;
if (s->buf_ptr >= s->buf_end)
flush_buffer(s);
bit_cnt=bit_cnt + n - 32;
if (bit_cnt == 0) {
bit_buf = 0;
} else {
bit_buf = value << (32 - bit_cnt);
}
}
s->bit_buf = bit_buf;
s->bit_cnt = bit_cnt;
}
/* return the number of bits output */
long long get_bit_count(PutBitContext *s)
{
return (s->buf_ptr - s->buf + s->data_out_size) * 8 + (long long)s->bit_cnt;
}
void align_put_bits(PutBitContext *s)
{
put_bits(s,(8 - s->bit_cnt) & 7,0);
}
/* pad the end of the output stream with zeros */
void flush_put_bits(PutBitContext *s)
{
while (s->bit_cnt > 0) {
/* XXX: should test end of buffer */
*s->buf_ptr++=s->bit_buf >> 24;
s->bit_buf<<=8;
s->bit_cnt-=8;
}
flush_buffer(s);
s->bit_cnt=0;
s->bit_buf=0;
}
/* for jpeg : espace 0xff with 0x00 after it */
void jput_bits(PutBitContext *s, int n, unsigned int value)
{
unsigned int bit_buf, b;
int bit_cnt, i;
assert(n == 32 || value < (1U << n));
bit_buf = s->bit_buf;
bit_cnt = s->bit_cnt;
//printf("n=%d value=%x cnt=%d buf=%x\n", n, value, bit_cnt, bit_buf);
/* XXX: optimize */
if (n < (32-bit_cnt)) {
bit_buf |= value << (32 - n - bit_cnt);
bit_cnt+=n;
} else {
bit_buf |= value >> (n + bit_cnt - 32);
/* handle escape */
for(i=0;i<4;i++) {
b = (bit_buf >> 24);
*(s->buf_ptr++) = b;
if (b == 0xff)
*(s->buf_ptr++) = 0;
bit_buf <<= 8;
}
/* we flush the buffer sooner to handle worst case */
if (s->buf_ptr >= (s->buf_end - 8))
flush_buffer(s);
bit_cnt=bit_cnt + n - 32;
if (bit_cnt == 0) {
bit_buf = 0;
} else {
bit_buf = value << (32 - bit_cnt);
}
}
s->bit_buf = bit_buf;
s->bit_cnt = bit_cnt;
}
/* pad the end of the output stream with zeros */
void jflush_put_bits(PutBitContext *s)
{
unsigned int b;
while (s->bit_cnt > 0) {
b = s->bit_buf >> 24;
*s->buf_ptr++ = b;
if (b == 0xff)
*s->buf_ptr++ = 0;
s->bit_buf<<=8;
s->bit_cnt-=8;
}
flush_buffer(s);
s->bit_cnt=0;
s->bit_buf=0;
}

@ -0,0 +1,68 @@
#ifndef COMMON_H
#define COMMON_H
typedef unsigned char UINT8;
typedef unsigned short UINT16;
typedef unsigned int UINT32;
typedef signed char INT8;
typedef signed short INT16;
typedef signed int INT32;
/* bit I/O */
struct PutBitContext;
typedef void (*WriteDataFunc)(void *, UINT8 *, int);
typedef struct PutBitContext {
UINT8 *buf, *buf_ptr, *buf_end;
int bit_cnt;
UINT32 bit_buf;
long long data_out_size; /* in bytes */
void *opaque;
WriteDataFunc write_data;
} PutBitContext;
void init_put_bits(PutBitContext *s,
UINT8 *buffer, int buffer_size,
void *opaque,
void (*write_data)(void *, UINT8 *, int));
void put_bits(PutBitContext *s, int n, unsigned int value);
long long get_bit_count(PutBitContext *s);
void align_put_bits(PutBitContext *s);
void flush_put_bits(PutBitContext *s);
/* jpeg specific put_bits */
void jput_bits(PutBitContext *s, int n, unsigned int value);
void jflush_put_bits(PutBitContext *s);
/* misc math functions */
extern inline int log2(unsigned int v)
{
int n;
n = 0;
if (v & 0xffff0000) {
v >>= 16;
n += 16;
}
if (v & 0xff00) {
v >>= 8;
n += 8;
}
if (v & 0xf0) {
v >>= 4;
n += 4;
}
if (v & 0xc) {
v >>= 2;
n += 2;
}
if (v & 0x2) {
n++;
}
return n;
}
#endif

@ -0,0 +1,151 @@
/* DCT coefficients. Four tables, two for last = 0, two for last = 1.
the sign bit must be added afterwards. */
/* first part of coeffs for last = 0. Indexed by [run][level-1] */
static const UINT8 coeff_tab0[2][12][2] =
{
/* run = 0 */
{
{0x02, 2}, {0x0f, 4}, {0x15, 6}, {0x17, 7},
{0x1f, 8}, {0x25, 9}, {0x24, 9}, {0x21,10},
{0x20,10}, {0x07,11}, {0x06,11}, {0x20,11}
},
/* run = 1 */
{
{0x06, 3}, {0x14, 6}, {0x1e, 8}, {0x0f,10},
{0x21,11}, {0x50,12}, {0x00, 0}, {0x00, 0},
{0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}
}
};
/* rest of coeffs for last = 0. indexing by [run-2][level-1] */
static const UINT8 coeff_tab1[25][4][2] =
{
/* run = 2 */
{
{0x0e, 4}, {0x1d, 8}, {0x0e,10}, {0x51,12}
},
/* run = 3 */
{
{0x0d, 5}, {0x23, 9}, {0x0d,10}, {0x00, 0}
},
/* run = 4-26 */
{
{0x0c, 5}, {0x22, 9}, {0x52,12}, {0x00, 0}
},
{
{0x0b, 5}, {0x0c,10}, {0x53,12}, {0x00, 0}
},
{
{0x13, 6}, {0x0b,10}, {0x54,12}, {0x00, 0}
},
{
{0x12, 6}, {0x0a,10}, {0x00, 0}, {0x00, 0}
},
{
{0x11, 6}, {0x09,10}, {0x00, 0}, {0x00, 0}
},
{
{0x10, 6}, {0x08,10}, {0x00, 0}, {0x00, 0}
},
{
{0x16, 7}, {0x55,12}, {0x00, 0}, {0x00, 0}
},
{
{0x15, 7}, {0x00, 0}, {0x00, 0}, {0x00, 0}
},
{
{0x14, 7}, {0x00, 0}, {0x00, 0}, {0x00, 0}
},
{
{0x1c, 8}, {0x00, 0}, {0x00, 0}, {0x00, 0}
},
{
{0x1b, 8}, {0x00, 0}, {0x00, 0}, {0x00, 0}
},
{
{0x21, 9}, {0x00, 0}, {0x00, 0}, {0x00, 0}
},
{
{0x20, 9}, {0x00, 0}, {0x00, 0}, {0x00, 0}
},
{
{0x1f, 9}, {0x00, 0}, {0x00, 0}, {0x00, 0}
},
{
{0x1e, 9}, {0x00, 0}, {0x00, 0}, {0x00, 0}
},
{
{0x1d, 9}, {0x00, 0}, {0x00, 0}, {0x00, 0}
},
{
{0x1c, 9}, {0x00, 0}, {0x00, 0}, {0x00, 0}
},
{
{0x1b, 9}, {0x00, 0}, {0x00, 0}, {0x00, 0}
},
{
{0x1a, 9}, {0x00, 0}, {0x00, 0}, {0x00, 0}
},
{
{0x22,11}, {0x00, 0}, {0x00, 0}, {0x00, 0}
},
{
{0x23,11}, {0x00, 0}, {0x00, 0}, {0x00, 0}
},
{
{0x56,12}, {0x00, 0}, {0x00, 0}, {0x00, 0}
},
{
{0x57,12}, {0x00, 0}, {0x00, 0}, {0x00, 0}
}
};
/* first coeffs of last = 1. indexing by [run][level-1] */
static const UINT8 coeff_tab2[2][3][2] =
{
/* run = 0 */
{
{0x07, 4}, {0x19, 9}, {0x05,11}
},
/* run = 1 */
{
{0x0f, 6}, {0x04,11}, {0x00, 0}
}
};
/* rest of coeffs for last = 1. indexing by [run-2] */
static const UINT8 coeff_tab3[40][2] =
{
{0x0e, 6}, {0x0d, 6}, {0x0c, 6},
{0x13, 7}, {0x12, 7}, {0x11, 7}, {0x10, 7},
{0x1a, 8}, {0x19, 8}, {0x18, 8}, {0x17, 8},
{0x16, 8}, {0x15, 8}, {0x14, 8}, {0x13, 8},
{0x18, 9}, {0x17, 9}, {0x16, 9}, {0x15, 9},
{0x14, 9}, {0x13, 9}, {0x12, 9}, {0x11, 9},
{0x07,10}, {0x06,10}, {0x05,10}, {0x04,10},
{0x24,11}, {0x25,11}, {0x26,11}, {0x27,11},
{0x58,12}, {0x59,12}, {0x5a,12}, {0x5b,12},
{0x5c,12}, {0x5d,12}, {0x5e,12}, {0x5f,12},
{0x00, 0}
};
/* intra MCBPC, mb_type = 3 */
static UINT8 intra_MCBPC_code[4] = { 1, 1, 2, 3 };
static UINT8 intra_MCBPC_bits[4] = { 1, 3, 3, 3 };
/* inter MCBPC, mb_type = 0 then 3 */
static UINT8 inter_MCBPC_code[8] = { 1, 3, 2, 5, 3, 4, 3, 3 };
static UINT8 inter_MCBPC_bits[8] = { 1, 4, 4, 6, 5, 8, 8, 7 };
static UINT8 cbpy_tab[16][2] =
{
{3,4}, {5,5}, {4,5}, {9,4}, {3,5}, {7,4}, {2,6}, {11,4},
{2,5}, {3,6}, {5,4}, {10,4}, {4,4}, {8,4}, {6,4}, {3,2}
};

@ -0,0 +1,229 @@
/*
* H263 backend for ffmpeg encoder
* 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 "common.h"
#include "mpegvideo.h"
#include "h263data.h"
void h263_picture_header(MpegEncContext *s, int picture_number)
{
int format;
align_put_bits(&s->pb);
put_bits(&s->pb, 22, 0x20);
put_bits(&s->pb, 8, ((s->picture_number * 30) / s->frame_rate) & 0xff);
put_bits(&s->pb, 1, 1); /* marker */
put_bits(&s->pb, 1, 0); /* h263 id */
put_bits(&s->pb, 1, 0); /* split screen off */
put_bits(&s->pb, 1, 0); /* camera off */
put_bits(&s->pb, 1, 0); /* freeze picture release off */
if (s->width == 128 && s->height == 96)
format = 1;
else if (s->width == 176 && s->height == 144)
format = 2;
else if (s->width == 352 && s->height == 288)
format = 3;
else if (s->width == 704 && s->height == 576)
format = 4;
else if (s->width == 1408 && s->height == 1152)
format = 5;
else
abort();
put_bits(&s->pb, 3, format);
put_bits(&s->pb, 1, (s->pict_type == P_TYPE));
put_bits(&s->pb, 1, 0); /* unrestricted motion vector: off */
put_bits(&s->pb, 1, 0); /* SAC: off */
put_bits(&s->pb, 1, 0); /* advanced prediction mode: off */
put_bits(&s->pb, 1, 0); /* not PB frame */
put_bits(&s->pb, 5, s->qscale);
put_bits(&s->pb, 1, 0); /* Continuous Presence Multipoint mode: off */
put_bits(&s->pb, 1, 0); /* no PEI */
}
static void h263_encode_block(MpegEncContext *s, DCTELEM *block,
int n);
void h263_encode_mb(MpegEncContext *s,
DCTELEM block[6][64],
int motion_x, int motion_y)
{
int cbpc, cbpy, i, cbp;
if (!s->mb_intra) {
/* compute cbp */
cbp = 0;
for(i=0;i<6;i++) {
if (s->block_last_index[i] >= 0)
cbp |= 1 << (5 - i);
}
if ((cbp | motion_x | motion_y) == 0) {
/* skip macroblock */
put_bits(&s->pb, 1, 1);
return;
}
put_bits(&s->pb, 1, 0); /* mb coded */
cbpc = cbp & 3;
put_bits(&s->pb,
inter_MCBPC_bits[cbpc],
inter_MCBPC_code[cbpc]);
cbpy = cbp >> 2;
cbpy ^= 0xf;
put_bits(&s->pb, cbpy_tab[cbpy][1], cbpy_tab[cbpy][0]);
/* motion vectors: zero */
put_bits(&s->pb, 1, 1);
put_bits(&s->pb, 1, 1);
} else {
/* compute cbp */
cbp = 0;
for(i=0;i<6;i++) {
if (s->block_last_index[i] >= 1)
cbp |= 1 << (5 - i);
}
cbpc = cbp & 3;
if (s->pict_type == I_TYPE) {
put_bits(&s->pb,
intra_MCBPC_bits[cbpc],
intra_MCBPC_code[cbpc]);
} else {
put_bits(&s->pb, 1, 0); /* mb coded */
put_bits(&s->pb,
inter_MCBPC_bits[cbpc + 4],
inter_MCBPC_code[cbpc + 4]);
}
cbpy = cbp >> 2;
put_bits(&s->pb, cbpy_tab[cbpy][1], cbpy_tab[cbpy][0]);
}
/* encode each block */
for(i=0;i<6;i++) {
h263_encode_block(s, block[i], i);
}
}
static void h263_encode_block(MpegEncContext *s, DCTELEM *block, int n)
{
int level, run, last, i, j, last_index, last_non_zero, sign, alevel;
int code, len;
if (s->mb_intra) {
/* DC coef */
level = block[0];
if (level == 128)
put_bits(&s->pb, 8, 0xff);
else
put_bits(&s->pb, 8, level & 0xff);
i = 1;
} else {
i = 0;
}
/* AC coefs */
last_index = s->block_last_index[n];
last_non_zero = i - 1;
for(;i<=last_index;i++) {
j = zigzag_direct[i];
level = block[j];
if (level) {
run = i - last_non_zero - 1;
last = (i == last_index);
sign = 0;
alevel = level;
if (level < 0) {
sign = 1;
alevel = -level;
}
len = 0;
code = 0; /* only to disable warning */
if (last == 0) {
if (run < 2 && alevel < 13 ) {
len = coeff_tab0[run][alevel-1][1];
code = coeff_tab0[run][alevel-1][0];
} else if (run >= 2 && run < 27 && alevel < 5) {
len = coeff_tab1[run-2][alevel-1][1];
code = coeff_tab1[run-2][alevel-1][0];
}
} else {
if (run < 2 && alevel < 4) {
len = coeff_tab2[run][alevel-1][1];
code = coeff_tab2[run][alevel-1][0];
} else if (run >= 2 && run < 42 && alevel == 1) {
len = coeff_tab3[run-2][1];
code = coeff_tab3[run-2][0];
}
}
if (len != 0) {
code = (code << 1) | sign;
put_bits(&s->pb, len + 1, code);
} else {
/* escape */
put_bits(&s->pb, 7, 3);
put_bits(&s->pb, 1, last);
put_bits(&s->pb, 6, run);
put_bits(&s->pb, 8, level & 0xff);
}
last_non_zero = i;
}
}
}
/* write RV 1.0 compatible frame header */
void rv10_encode_picture_header(MpegEncContext *s, int picture_number)
{
align_put_bits(&s->pb);
put_bits(&s->pb, 1, 1); /* marker */
put_bits(&s->pb, 1, (s->pict_type == P_TYPE));
put_bits(&s->pb, 1, 0); /* not PB frame */
put_bits(&s->pb, 5, s->qscale);
if (s->pict_type == I_TYPE) {
/* specific MPEG like DC coding not used */
}
/* if multiple packets per frame are sent, the position at which
to display the macro blocks is coded here */
put_bits(&s->pb, 6, 0); /* mb_x */
put_bits(&s->pb, 6, 0); /* mb_y */
put_bits(&s->pb, 12, s->mb_width * s->mb_height);
put_bits(&s->pb, 3, 0); /* ignored */
}

@ -0,0 +1,224 @@
/*
* jfdctfst.c
*
* Copyright (C) 1994-1996, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains a fast, not so accurate integer implementation of the
* forward DCT (Discrete Cosine Transform).
*
* A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
* on each column. Direct algorithms are also available, but they are
* much more complex and seem not to be any faster when reduced to code.
*
* This implementation is based on Arai, Agui, and Nakajima's algorithm for
* scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
* Japanese, but the algorithm is described in the Pennebaker & Mitchell
* JPEG textbook (see REFERENCES section in file README). The following code
* is based directly on figure 4-8 in P&M.
* While an 8-point DCT cannot be done in less than 11 multiplies, it is
* possible to arrange the computation so that many of the multiplies are
* simple scalings of the final outputs. These multiplies can then be
* folded into the multiplications or divisions by the JPEG quantization
* table entries. The AA&N method leaves only 5 multiplies and 29 adds
* to be done in the DCT itself.
* The primary disadvantage of this method is that with fixed-point math,
* accuracy is lost due to imprecise representation of the scaled
* quantization values. The smaller the quantization table entry, the less
* precise the scaled value, so this implementation does worse with high-
* quality-setting files than with low-quality ones.
*/
#include <stdlib.h>
#include <stdio.h>
#include "common.h"
#include "mpegvideo.h"
#define DCTSIZE 8
#define GLOBAL(x) x
#define RIGHT_SHIFT(x, n) ((x) >> (n))
#define SHIFT_TEMPS
/*
* This module is specialized to the case DCTSIZE = 8.
*/
#if DCTSIZE != 8
Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
#endif
/* Scaling decisions are generally the same as in the LL&M algorithm;
* see jfdctint.c for more details. However, we choose to descale
* (right shift) multiplication products as soon as they are formed,
* rather than carrying additional fractional bits into subsequent additions.
* This compromises accuracy slightly, but it lets us save a few shifts.
* More importantly, 16-bit arithmetic is then adequate (for 8-bit samples)
* everywhere except in the multiplications proper; this saves a good deal
* of work on 16-bit-int machines.
*
* Again to save a few shifts, the intermediate results between pass 1 and
* pass 2 are not upscaled, but are represented only to integral precision.
*
* A final compromise is to represent the multiplicative constants to only
* 8 fractional bits, rather than 13. This saves some shifting work on some
* machines, and may also reduce the cost of multiplication (since there
* are fewer one-bits in the constants).
*/
#define CONST_BITS 8
/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
* causing a lot of useless floating-point operations at run time.
* To get around this we use the following pre-calculated constants.
* If you change CONST_BITS you may want to add appropriate values.
* (With a reasonable C compiler, you can just rely on the FIX() macro...)
*/
#if CONST_BITS == 8
#define FIX_0_382683433 ((INT32) 98) /* FIX(0.382683433) */
#define FIX_0_541196100 ((INT32) 139) /* FIX(0.541196100) */
#define FIX_0_707106781 ((INT32) 181) /* FIX(0.707106781) */
#define FIX_1_306562965 ((INT32) 334) /* FIX(1.306562965) */
#else
#define FIX_0_382683433 FIX(0.382683433)
#define FIX_0_541196100 FIX(0.541196100)
#define FIX_0_707106781 FIX(0.707106781)
#define FIX_1_306562965 FIX(1.306562965)
#endif
/* We can gain a little more speed, with a further compromise in accuracy,
* by omitting the addition in a descaling shift. This yields an incorrectly
* rounded result half the time...
*/
#ifndef USE_ACCURATE_ROUNDING
#undef DESCALE
#define DESCALE(x,n) RIGHT_SHIFT(x, n)
#endif
/* Multiply a DCTELEM variable by an INT32 constant, and immediately
* descale to yield a DCTELEM result.
*/
#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS))
/*
* Perform the forward DCT on one block of samples.
*/
GLOBAL(void)
jpeg_fdct_ifast (DCTELEM * data)
{
DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
DCTELEM tmp10, tmp11, tmp12, tmp13;
DCTELEM z1, z2, z3, z4, z5, z11, z13;
DCTELEM *dataptr;
int ctr;
SHIFT_TEMPS
/* Pass 1: process rows. */
dataptr = data;
for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
tmp0 = dataptr[0] + dataptr[7];
tmp7 = dataptr[0] - dataptr[7];
tmp1 = dataptr[1] + dataptr[6];
tmp6 = dataptr[1] - dataptr[6];
tmp2 = dataptr[2] + dataptr[5];
tmp5 = dataptr[2] - dataptr[5];
tmp3 = dataptr[3] + dataptr[4];
tmp4 = dataptr[3] - dataptr[4];
/* Even part */
tmp10 = tmp0 + tmp3; /* phase 2 */
tmp13 = tmp0 - tmp3;
tmp11 = tmp1 + tmp2;
tmp12 = tmp1 - tmp2;
dataptr[0] = tmp10 + tmp11; /* phase 3 */
dataptr[4] = tmp10 - tmp11;
z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */
dataptr[2] = tmp13 + z1; /* phase 5 */
dataptr[6] = tmp13 - z1;
/* Odd part */
tmp10 = tmp4 + tmp5; /* phase 2 */
tmp11 = tmp5 + tmp6;
tmp12 = tmp6 + tmp7;
/* The rotator is modified from fig 4-8 to avoid extra negations. */
z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */
z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */
z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */
z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */
z11 = tmp7 + z3; /* phase 5 */
z13 = tmp7 - z3;
dataptr[5] = z13 + z2; /* phase 6 */
dataptr[3] = z13 - z2;
dataptr[1] = z11 + z4;
dataptr[7] = z11 - z4;
dataptr += DCTSIZE; /* advance pointer to next row */
}
/* Pass 2: process columns. */
dataptr = data;
for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
/* Even part */
tmp10 = tmp0 + tmp3; /* phase 2 */
tmp13 = tmp0 - tmp3;
tmp11 = tmp1 + tmp2;
tmp12 = tmp1 - tmp2;
dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */
dataptr[DCTSIZE*4] = tmp10 - tmp11;
z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */
dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */
dataptr[DCTSIZE*6] = tmp13 - z1;
/* Odd part */
tmp10 = tmp4 + tmp5; /* phase 2 */
tmp11 = tmp5 + tmp6;
tmp12 = tmp6 + tmp7;
/* The rotator is modified from fig 4-8 to avoid extra negations. */
z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */
z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */
z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */
z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */
z11 = tmp7 + z3; /* phase 5 */
z13 = tmp7 - z3;
dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */
dataptr[DCTSIZE*3] = z13 - z2;
dataptr[DCTSIZE*1] = z11 + z4;
dataptr[DCTSIZE*7] = z11 - z4;
dataptr++; /* advance pointer to next column */
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,416 @@
/*
* MJPEG encoder
* 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 "avcodec.h"
#include "mpegvideo.h"
typedef struct MJpegContext {
UINT8 huff_size_dc_luminance[12];
UINT16 huff_code_dc_luminance[12];
UINT8 huff_size_dc_chrominance[12];
UINT16 huff_code_dc_chrominance[12];
UINT8 huff_size_ac_luminance[256];
UINT16 huff_code_ac_luminance[256];
UINT8 huff_size_ac_chrominance[256];
UINT16 huff_code_ac_chrominance[256];
} MJpegContext;
#define SOF0 0xc0
#define SOI 0xd8
#define EOI 0xd9
#define DQT 0xdb
#define DHT 0xc4
#define SOS 0xda
#if 0
/* These are the sample quantization tables given in JPEG spec section K.1.
* The spec says that the values given produce "good" quality, and
* when divided by 2, "very good" quality.
*/
static const unsigned char std_luminance_quant_tbl[64] = {
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99
};
static const unsigned char std_chrominance_quant_tbl[64] = {
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99
};
#endif
/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
/* IMPORTANT: these are only valid for 8-bit data precision! */
static const UINT8 bits_dc_luminance[17] =
{ /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
static const UINT8 val_dc_luminance[] =
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
static const UINT8 bits_dc_chrominance[17] =
{ /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
static const UINT8 val_dc_chrominance[] =
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
static const UINT8 bits_ac_luminance[17] =
{ /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
static const UINT8 val_ac_luminance[] =
{ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa
};
static const UINT8 bits_ac_chrominance[17] =
{ /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
static const UINT8 val_ac_chrominance[] =
{ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa
};
/* isn't this function nicer than the one in the libjpeg ? */
static void build_huffman_codes(UINT8 *huff_size, UINT16 *huff_code,
const UINT8 *bits_table, const UINT8 *val_table)
{
int i, j, k,nb, code, sym;
code = 0;
k = 0;
for(i=1;i<=16;i++) {
nb = bits_table[i];
for(j=0;j<nb;j++) {
sym = val_table[k++];
huff_size[sym] = i;
huff_code[sym] = code;
code++;
}
code <<= 1;
}
}
int mjpeg_init(MpegEncContext *s)
{
MJpegContext *m;
m = malloc(sizeof(MJpegContext));
if (!m)
return -1;
/* build all the huffman tables */
build_huffman_codes(m->huff_size_dc_luminance,
m->huff_code_dc_luminance,
bits_dc_luminance,
val_dc_luminance);
build_huffman_codes(m->huff_size_dc_chrominance,
m->huff_code_dc_chrominance,
bits_dc_chrominance,
val_dc_chrominance);
build_huffman_codes(m->huff_size_ac_luminance,
m->huff_code_ac_luminance,
bits_ac_luminance,
val_ac_luminance);
build_huffman_codes(m->huff_size_ac_chrominance,
m->huff_code_ac_chrominance,
bits_ac_chrominance,
val_ac_chrominance);
s->mjpeg_ctx = m;
return 0;
}
void mjpeg_close(MpegEncContext *s)
{
free(s->mjpeg_ctx);
}
static inline void put_marker(PutBitContext *p, int code)
{
put_bits(p, 8, 0xff);
put_bits(p, 8, code);
}
/* table_class: 0 = DC coef, 1 = AC coefs */
static int put_huffman_table(MpegEncContext *s, int table_class, int table_id,
const UINT8 *bits_table, const UINT8 *value_table)
{
PutBitContext *p = &s->pb;
int n, i;
put_bits(p, 4, table_class);
put_bits(p, 4, table_id);
n = 0;
for(i=1;i<=16;i++) {
n += bits_table[i];
put_bits(p, 8, bits_table[i]);
}
for(i=0;i<n;i++)
put_bits(p, 8, value_table[i]);
return n + 17;
}
static void jpeg_table_header(MpegEncContext *s)
{
PutBitContext *p = &s->pb;
int i, size;
UINT8 *ptr;
/* quant matrixes */
put_marker(p, DQT);
put_bits(p, 16, 2 + 1 * (1 + 64));
put_bits(p, 4, 0); /* 8 bit precision */
put_bits(p, 4, 0); /* table 0 */
for(i=0;i<64;i++) {
put_bits(p, 8, s->init_intra_matrix[i]);
}
#if 0
put_bits(p, 4, 0); /* 8 bit precision */
put_bits(p, 4, 1); /* table 1 */
for(i=0;i<64;i++) {
put_bits(p, 8, m->chrominance_matrix[i]);
}
#endif
/* huffman table */
put_marker(p, DHT);
flush_put_bits(p);
ptr = p->buf_ptr;
put_bits(p, 16, 0); /* patched later */
size = 2;
size += put_huffman_table(s, 0, 0, bits_dc_luminance, val_dc_luminance);
size += put_huffman_table(s, 0, 1, bits_dc_chrominance, val_dc_chrominance);
size += put_huffman_table(s, 1, 0, bits_ac_luminance, val_ac_luminance);
size += put_huffman_table(s, 1, 1, bits_ac_chrominance, val_ac_chrominance);
ptr[0] = size >> 8;
ptr[1] = size;
}
void mjpeg_picture_header(MpegEncContext *s)
{
put_marker(&s->pb, SOI);
jpeg_table_header(s);
put_marker(&s->pb, SOF0);
put_bits(&s->pb, 16, 17);
put_bits(&s->pb, 8, 8); /* 8 bits/component */
put_bits(&s->pb, 16, s->height);
put_bits(&s->pb, 16, s->width);
put_bits(&s->pb, 8, 3); /* 3 components */
/* Y component */
put_bits(&s->pb, 8, 1); /* component number */
put_bits(&s->pb, 4, 2); /* H factor */
put_bits(&s->pb, 4, 2); /* V factor */
put_bits(&s->pb, 8, 0); /* select matrix */
/* Cb component */
put_bits(&s->pb, 8, 2); /* component number */
put_bits(&s->pb, 4, 1); /* H factor */
put_bits(&s->pb, 4, 1); /* V factor */
put_bits(&s->pb, 8, 0); /* select matrix */
/* Cr component */
put_bits(&s->pb, 8, 3); /* component number */
put_bits(&s->pb, 4, 1); /* H factor */
put_bits(&s->pb, 4, 1); /* V factor */
put_bits(&s->pb, 8, 0); /* select matrix */
/* scan header */
put_marker(&s->pb, SOS);
put_bits(&s->pb, 16, 12); /* length */
put_bits(&s->pb, 8, 3); /* 3 components */
/* Y component */
put_bits(&s->pb, 8, 1); /* index */
put_bits(&s->pb, 4, 0); /* DC huffman table index */
put_bits(&s->pb, 4, 0); /* AC huffman table index */
/* Cb component */
put_bits(&s->pb, 8, 2); /* index */
put_bits(&s->pb, 4, 1); /* DC huffman table index */
put_bits(&s->pb, 4, 1); /* AC huffman table index */
/* Cr component */
put_bits(&s->pb, 8, 3); /* index */
put_bits(&s->pb, 4, 1); /* DC huffman table index */
put_bits(&s->pb, 4, 1); /* AC huffman table index */
put_bits(&s->pb, 8, 0); /* Ss (not used) */
put_bits(&s->pb, 8, 63); /* Se (not used) */
put_bits(&s->pb, 8, 0); /* (not used) */
}
void mjpeg_picture_trailer(MpegEncContext *s)
{
jflush_put_bits(&s->pb);
put_marker(&s->pb, EOI);
}
static inline void encode_dc(MpegEncContext *s, int val,
UINT8 *huff_size, UINT16 *huff_code)
{
int mant, nbits;
if (val == 0) {
jput_bits(&s->pb, huff_size[0], huff_code[0]);
} else {
mant = val;
if (val < 0) {
val = -val;
mant--;
}
/* compute the log (XXX: optimize) */
nbits = 0;
while (val != 0) {
val = val >> 1;
nbits++;
}
jput_bits(&s->pb, huff_size[nbits], huff_code[nbits]);
jput_bits(&s->pb, nbits, mant & ((1 << nbits) - 1));
}
}
static void encode_block(MpegEncContext *s, DCTELEM *block, int n)
{
int mant, nbits, code, i, j;
int component, dc, run, last_index, val;
MJpegContext *m = s->mjpeg_ctx;
UINT8 *huff_size_ac;
UINT16 *huff_code_ac;
/* DC coef */
component = (n <= 3 ? 0 : n - 4 + 1);
dc = block[0]; /* overflow is impossible */
val = dc - s->last_dc[component];
if (n < 4) {
encode_dc(s, val, m->huff_size_dc_luminance, m->huff_code_dc_luminance);
huff_size_ac = m->huff_size_ac_luminance;
huff_code_ac = m->huff_code_ac_luminance;
} else {
encode_dc(s, val, m->huff_size_dc_chrominance, m->huff_code_dc_chrominance);
huff_size_ac = m->huff_size_ac_chrominance;
huff_code_ac = m->huff_code_ac_chrominance;
}
s->last_dc[component] = dc;
/* AC coefs */
run = 0;
last_index = s->block_last_index[n];
for(i=1;i<=last_index;i++) {
j = zigzag_direct[i];
val = block[j];
if (val == 0) {
run++;
} else {
while (run >= 16) {
jput_bits(&s->pb, huff_size_ac[0xf0], huff_code_ac[0xf0]);
run -= 16;
}
mant = val;
if (val < 0) {
val = -val;
mant--;
}
/* compute the log (XXX: optimize) */
nbits = 0;
while (val != 0) {
val = val >> 1;
nbits++;
}
code = (run << 4) | nbits;
jput_bits(&s->pb, huff_size_ac[code], huff_code_ac[code]);
jput_bits(&s->pb, nbits, mant & ((1 << nbits) - 1));
run = 0;
}
}
/* output EOB only if not already 64 values */
if (last_index < 63 || run != 0)
jput_bits(&s->pb, huff_size_ac[0], huff_code_ac[0]);
}
void mjpeg_encode_mb(MpegEncContext *s,
DCTELEM block[6][64])
{
int i;
for(i=0;i<6;i++) {
encode_block(s, block[i], i);
}
}

@ -0,0 +1,754 @@
/*
* The simplest mpeg audio layer 2 encoder
* 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 <netinet/in.h>
#include <math.h>
#include "avcodec.h"
#include "mpegaudio.h"
#define NDEBUG
#include <assert.h>
/* define it to use floats in quantization (I don't like floats !) */
//#define USE_FLOATS
#define MPA_STEREO 0
#define MPA_JSTEREO 1
#define MPA_DUAL 2
#define MPA_MONO 3
#include "mpegaudiotab.h"
int MPA_encode_init(AVEncodeContext *avctx)
{
MpegAudioContext *s = avctx->priv_data;
int freq = avctx->rate;
int bitrate = avctx->bit_rate;
int channels = avctx->channels;
int i, v, table;
float a;
if (channels != 1)
return -1;
bitrate = bitrate / 1000;
s->freq = freq;
s->bit_rate = bitrate * 1000;
avctx->frame_size = MPA_FRAME_SIZE;
avctx->key_frame = 1; /* always key frame */
/* encoding freq */
s->lsf = 0;
for(i=0;i<3;i++) {
if (freq_tab[i] == freq)
break;
if ((freq_tab[i] / 2) == freq) {
s->lsf = 1;
break;
}
}
if (i == 3)
return -1;
s->freq_index = i;
/* encoding bitrate & frequency */
for(i=0;i<15;i++) {
if (bitrate_tab[1-s->lsf][i] == bitrate)
break;
}
if (i == 15)
return -1;
s->bitrate_index = i;
/* compute total header size & pad bit */
a = (float)(bitrate * 1000 * MPA_FRAME_SIZE) / (freq * 8.0);
s->frame_size = ((int)a) * 8;
/* frame fractional size to compute padding */
s->frame_frac = 0;
s->frame_frac_incr = (int)((a - floor(a)) * 65536.0);
/* select the right allocation table */
if (!s->lsf) {
if ((freq == 48000 && bitrate >= 56) ||
(bitrate >= 56 && bitrate <= 80))
table = 0;
else if (freq != 48000 && bitrate >= 96)
table = 1;
else if (freq != 32000 && bitrate <= 48)
table = 2;
else
table = 3;
} else {
table = 4;
}
/* number of used subbands */
s->sblimit = sblimit_table[table];
s->alloc_table = alloc_tables[table];
#ifdef DEBUG
printf("%d kb/s, %d Hz, frame_size=%d bits, table=%d, padincr=%x\n",
bitrate, freq, s->frame_size, table, s->frame_frac_incr);
#endif
s->samples_offset = 0;
for(i=0;i<512;i++) {
float a = enwindow[i] * 32768.0 * 16.0;
filter_bank[i] = (int)(a);
}
for(i=0;i<64;i++) {
v = (int)(pow(2.0, (3 - i) / 3.0) * (1 << 20));
if (v <= 0)
v = 1;
scale_factor_table[i] = v;
#ifdef USE_FLOATS
scale_factor_inv_table[i] = pow(2.0, -(3 - i) / 3.0) / (float)(1 << 20);
#else
#define P 15
scale_factor_shift[i] = 21 - P - (i / 3);
scale_factor_mult[i] = (1 << P) * pow(2.0, (i % 3) / 3.0);
#endif
}
for(i=0;i<128;i++) {
v = i - 64;
if (v <= -3)
v = 0;
else if (v < 0)
v = 1;
else if (v == 0)
v = 2;
else if (v < 3)
v = 3;
else
v = 4;
scale_diff_table[i] = v;
}
for(i=0;i<17;i++) {
v = quant_bits[i];
if (v < 0)
v = -v;
else
v = v * 3;
total_quant_bits[i] = 12 * v;
}
return 0;
}
/* 32 point floating point IDCT */
static void idct32(int *out, int *tab, int sblimit, int left_shift)
{
int i, j;
int *t, *t1, xr;
const int *xp = costab32;
for(j=31;j>=3;j-=2) tab[j] += tab[j - 2];
t = tab + 30;
t1 = tab + 2;
do {
t[0] += t[-4];
t[1] += t[1 - 4];
t -= 4;
} while (t != t1);
t = tab + 28;
t1 = tab + 4;
do {
t[0] += t[-8];
t[1] += t[1-8];
t[2] += t[2-8];
t[3] += t[3-8];
t -= 8;
} while (t != t1);
t = tab;
t1 = tab + 32;
do {
t[ 3] = -t[ 3];
t[ 6] = -t[ 6];
t[11] = -t[11];
t[12] = -t[12];
t[13] = -t[13];
t[15] = -t[15];
t += 16;
} while (t != t1);
t = tab;
t1 = tab + 8;
do {
int x1, x2, x3, x4;
x3 = MUL(t[16], FIX(SQRT2*0.5));
x4 = t[0] - x3;
x3 = t[0] + x3;
x2 = MUL(-(t[24] + t[8]), FIX(SQRT2*0.5));
x1 = MUL((t[8] - x2), xp[0]);
x2 = MUL((t[8] + x2), xp[1]);
t[ 0] = x3 + x1;
t[ 8] = x4 - x2;
t[16] = x4 + x2;
t[24] = x3 - x1;
t++;
} while (t != t1);
xp += 2;
t = tab;
t1 = tab + 4;
do {
xr = MUL(t[28],xp[0]);
t[28] = (t[0] - xr);
t[0] = (t[0] + xr);
xr = MUL(t[4],xp[1]);
t[ 4] = (t[24] - xr);
t[24] = (t[24] + xr);
xr = MUL(t[20],xp[2]);
t[20] = (t[8] - xr);
t[ 8] = (t[8] + xr);
xr = MUL(t[12],xp[3]);
t[12] = (t[16] - xr);
t[16] = (t[16] + xr);
t++;
} while (t != t1);
xp += 4;
for (i = 0; i < 4; i++) {
xr = MUL(tab[30-i*4],xp[0]);
tab[30-i*4] = (tab[i*4] - xr);
tab[ i*4] = (tab[i*4] + xr);
xr = MUL(tab[ 2+i*4],xp[1]);
tab[ 2+i*4] = (tab[28-i*4] - xr);
tab[28-i*4] = (tab[28-i*4] + xr);
xr = MUL(tab[31-i*4],xp[0]);
tab[31-i*4] = (tab[1+i*4] - xr);
tab[ 1+i*4] = (tab[1+i*4] + xr);
xr = MUL(tab[ 3+i*4],xp[1]);
tab[ 3+i*4] = (tab[29-i*4] - xr);
tab[29-i*4] = (tab[29-i*4] + xr);
xp += 2;
}
t = tab + 30;
t1 = tab + 1;
do {
xr = MUL(t1[0], *xp);
t1[0] = (t[0] - xr);
t[0] = (t[0] + xr);
t -= 2;
t1 += 2;
xp++;
} while (t >= tab);
for(i=0;i<32;i++) {
out[i] = tab[bitinv32[i]] << left_shift;
}
}
static void filter(MpegAudioContext *s, short *samples)
{
short *p, *q;
int sum, offset, i, j, norm, n;
short tmp[64];
int tmp1[32];
int *out;
// print_pow1(samples, 1152);
offset = s->samples_offset;
out = &s->sb_samples[0][0][0];
for(j=0;j<36;j++) {
/* 32 samples at once */
for(i=0;i<32;i++)
s->samples_buf[offset + (31 - i)] = samples[i];
/* filter */
p = s->samples_buf + offset;
q = filter_bank;
/* maxsum = 23169 */
for(i=0;i<64;i++) {
sum = p[0*64] * q[0*64];
sum += p[1*64] * q[1*64];
sum += p[2*64] * q[2*64];
sum += p[3*64] * q[3*64];
sum += p[4*64] * q[4*64];
sum += p[5*64] * q[5*64];
sum += p[6*64] * q[6*64];
sum += p[7*64] * q[7*64];
tmp[i] = sum >> 14;
p++;
q++;
}
tmp1[0] = tmp[16];
for( i=1; i<=16; i++ ) tmp1[i] = tmp[i+16]+tmp[16-i];
for( i=17; i<=31; i++ ) tmp1[i] = tmp[i+16]-tmp[80-i];
/* integer IDCT 32 with normalization. XXX: There may be some
overflow left */
norm = 0;
for(i=0;i<32;i++) {
norm |= abs(tmp1[i]);
}
n = log2(norm) - 12;
if (n > 0) {
for(i=0;i<32;i++)
tmp1[i] >>= n;
} else {
n = 0;
}
idct32(out, tmp1, s->sblimit, n);
/* advance of 32 samples */
samples += 32;
offset -= 32;
out += 32;
/* handle the wrap around */
if (offset < 0) {
memmove(s->samples_buf + SAMPLES_BUF_SIZE - (512 - 32),
s->samples_buf, (512 - 32) * 2);
offset = SAMPLES_BUF_SIZE - 512;
}
}
s->samples_offset = offset;
// print_pow(s->sb_samples, 1152);
}
static void compute_scale_factors(unsigned char scale_code[SBLIMIT],
unsigned char scale_factors[SBLIMIT][3],
int sb_samples[3][12][SBLIMIT],
int sblimit)
{
int *p, vmax, v, n, i, j, k, code;
int index, d1, d2;
unsigned char *sf = &scale_factors[0][0];
for(j=0;j<sblimit;j++) {
for(i=0;i<3;i++) {
/* find the max absolute value */
p = &sb_samples[i][0][j];
vmax = abs(*p);
for(k=1;k<12;k++) {
p += SBLIMIT;
v = abs(*p);
if (v > vmax)
vmax = v;
}
/* compute the scale factor index using log 2 computations */
if (vmax > 0) {
n = log2(vmax);
/* n is the position of the MSB of vmax. now
use at most 2 compares to find the index */
index = (21 - n) * 3 - 3;
if (index >= 0) {
while (vmax <= scale_factor_table[index+1])
index++;
} else {
index = 0; /* very unlikely case of overflow */
}
} else {
index = 63;
}
#if 0
printf("%2d:%d in=%x %x %d\n",
j, i, vmax, scale_factor_table[index], index);
#endif
/* store the scale factor */
assert(index >=0 && index <= 63);
sf[i] = index;
}
/* compute the transmission factor : look if the scale factors
are close enough to each other */
d1 = scale_diff_table[sf[0] - sf[1] + 64];
d2 = scale_diff_table[sf[1] - sf[2] + 64];
/* handle the 25 cases */
switch(d1 * 5 + d2) {
case 0*5+0:
case 0*5+4:
case 3*5+4:
case 4*5+0:
case 4*5+4:
code = 0;
break;
case 0*5+1:
case 0*5+2:
case 4*5+1:
case 4*5+2:
code = 3;
sf[2] = sf[1];
break;
case 0*5+3:
case 4*5+3:
code = 3;
sf[1] = sf[2];
break;
case 1*5+0:
case 1*5+4:
case 2*5+4:
code = 1;
sf[1] = sf[0];
break;
case 1*5+1:
case 1*5+2:
case 2*5+0:
case 2*5+1:
case 2*5+2:
code = 2;
sf[1] = sf[2] = sf[0];
break;
case 2*5+3:
case 3*5+3:
code = 2;
sf[0] = sf[1] = sf[2];
break;
case 3*5+0:
case 3*5+1:
case 3*5+2:
code = 2;
sf[0] = sf[2] = sf[1];
break;
case 1*5+3:
code = 2;
if (sf[0] > sf[2])
sf[0] = sf[2];
sf[1] = sf[2] = sf[0];
break;
default:
abort();
}
#if 0
printf("%d: %2d %2d %2d %d %d -> %d\n", j,
sf[0], sf[1], sf[2], d1, d2, code);
#endif
scale_code[j] = code;
sf += 3;
}
}
/* The most important function : psycho acoustic module. In this
encoder there is basically none, so this is the worst you can do,
but also this is the simpler. */
static void psycho_acoustic_model(MpegAudioContext *s, short smr[SBLIMIT])
{
int i;
for(i=0;i<s->sblimit;i++) {
smr[i] = (int)(fixed_smr[i] * 10);
}
}
#define SB_NOTALLOCATED 0
#define SB_ALLOCATED 1
#define SB_NOMORE 2
/* Try to maximize the smr while using a number of bits inferior to
the frame size. I tried to make the code simpler, faster and
smaller than other encoders :-) */
static void compute_bit_allocation(MpegAudioContext *s,
short smr1[SBLIMIT],
unsigned char bit_alloc[SBLIMIT],
int *padding)
{
int i, b, max_smr, max_sb, current_frame_size, max_frame_size;
int incr;
short smr[SBLIMIT];
unsigned char subband_status[SBLIMIT];
const unsigned char *alloc;
memcpy(smr, smr1, sizeof(short) * s->sblimit);
memset(subband_status, SB_NOTALLOCATED, s->sblimit);
memset(bit_alloc, 0, s->sblimit);
/* compute frame size and padding */
max_frame_size = s->frame_size;
s->frame_frac += s->frame_frac_incr;
if (s->frame_frac >= 65536) {
s->frame_frac -= 65536;
s->do_padding = 1;
max_frame_size += 8;
} else {
s->do_padding = 0;
}
/* compute the header + bit alloc size */
current_frame_size = 32;
alloc = s->alloc_table;
for(i=0;i<s->sblimit;i++) {
incr = alloc[0];
current_frame_size += incr;
alloc += 1 << incr;
}
for(;;) {
/* look for the subband with the largest signal to mask ratio */
max_sb = -1;
max_smr = 0x80000000;
for(i=0;i<s->sblimit;i++) {
if (smr[i] > max_smr && subband_status[i] != SB_NOMORE) {
max_smr = smr[i];
max_sb = i;
}
}
#if 0
printf("current=%d max=%d max_sb=%d alloc=%d\n",
current_frame_size, max_frame_size, max_sb,
bit_alloc[max_sb]);
#endif
if (max_sb < 0)
break;
/* find alloc table entry (XXX: not optimal, should use
pointer table) */
alloc = s->alloc_table;
for(i=0;i<max_sb;i++) {
alloc += 1 << alloc[0];
}
if (subband_status[max_sb] == SB_NOTALLOCATED) {
/* nothing was coded for this band: add the necessary bits */
incr = 2 + nb_scale_factors[s->scale_code[max_sb]] * 6;
incr += total_quant_bits[alloc[1]];
} else {
/* increments bit allocation */
b = bit_alloc[max_sb];
incr = total_quant_bits[alloc[b + 1]] -
total_quant_bits[alloc[b]];
}
if (current_frame_size + incr <= max_frame_size) {
/* can increase size */
b = ++bit_alloc[max_sb];
current_frame_size += incr;
/* decrease smr by the resolution we added */
smr[max_sb] = smr1[max_sb] - quant_snr[alloc[b]];
/* max allocation size reached ? */
if (b == ((1 << alloc[0]) - 1))
subband_status[max_sb] = SB_NOMORE;
else
subband_status[max_sb] = SB_ALLOCATED;
} else {
/* cannot increase the size of this subband */
subband_status[max_sb] = SB_NOMORE;
}
}
*padding = max_frame_size - current_frame_size;
assert(*padding >= 0);
#if 0
for(i=0;i<s->sblimit;i++) {
printf("%d ", bit_alloc[i]);
}
printf("\n");
#endif
}
/*
* Output the mpeg audio layer 2 frame. Note how the code is small
* compared to other encoders :-)
*/
static void encode_frame(MpegAudioContext *s,
unsigned char bit_alloc[SBLIMIT],
int padding)
{
int i, j, k, l, bit_alloc_bits, b;
unsigned char *sf;
int q[3];
PutBitContext *p = &s->pb;
/* header */
put_bits(p, 12, 0xfff);
put_bits(p, 1, 1 - s->lsf); /* 1 = mpeg1 ID, 0 = mpeg2 lsf ID */
put_bits(p, 2, 4-2); /* layer 2 */
put_bits(p, 1, 1); /* no error protection */
put_bits(p, 4, s->bitrate_index);
put_bits(p, 2, s->freq_index);
put_bits(p, 1, s->do_padding); /* use padding */
put_bits(p, 1, 0); /* private_bit */
put_bits(p, 2, MPA_MONO);
put_bits(p, 2, 0); /* mode_ext */
put_bits(p, 1, 0); /* no copyright */
put_bits(p, 1, 1); /* original */
put_bits(p, 2, 0); /* no emphasis */
/* bit allocation */
j = 0;
for(i=0;i<s->sblimit;i++) {
bit_alloc_bits = s->alloc_table[j];
put_bits(p, bit_alloc_bits, bit_alloc[i]);
j += 1 << bit_alloc_bits;
}
/* scale codes */
for(i=0;i<s->sblimit;i++) {
if (bit_alloc[i])
put_bits(p, 2, s->scale_code[i]);
}
/* scale factors */
sf = &s->scale_factors[0][0];
for(i=0;i<s->sblimit;i++) {
if (bit_alloc[i]) {
switch(s->scale_code[i]) {
case 0:
put_bits(p, 6, sf[0]);
put_bits(p, 6, sf[1]);
put_bits(p, 6, sf[2]);
break;
case 3:
case 1:
put_bits(p, 6, sf[0]);
put_bits(p, 6, sf[2]);
break;
case 2:
put_bits(p, 6, sf[0]);
break;
}
}
sf += 3;
}
/* quantization & write sub band samples */
for(k=0;k<3;k++) {
for(l=0;l<12;l+=3) {
j = 0;
for(i=0;i<s->sblimit;i++) {
bit_alloc_bits = s->alloc_table[j];
b = bit_alloc[i];
if (b) {
int qindex, steps, m, sample, bits;
/* we encode 3 sub band samples of the same sub band at a time */
qindex = s->alloc_table[j+b];
steps = quant_steps[qindex];
for(m=0;m<3;m++) {
sample = s->sb_samples[k][l + m][i];
/* divide by scale factor */
#ifdef USE_FLOATS
{
float a;
a = (float)sample * scale_factor_inv_table[s->scale_factors[i][k]];
q[m] = (int)((a + 1.0) * steps * 0.5);
}
#else
{
int q1, e, shift, mult;
e = s->scale_factors[i][k];
shift = scale_factor_shift[e];
mult = scale_factor_mult[e];
/* normalize to P bits */
if (shift < 0)
q1 = sample << (-shift);
else
q1 = sample >> shift;
q1 = (q1 * mult) >> P;
q[m] = ((q1 + (1 << P)) * steps) >> (P + 1);
}
#endif
if (q[m] >= steps)
q[m] = steps - 1;
assert(q[m] >= 0 && q[m] < steps);
}
bits = quant_bits[qindex];
if (bits < 0) {
/* group the 3 values to save bits */
put_bits(p, -bits,
q[0] + steps * (q[1] + steps * q[2]));
#if 0
printf("%d: gr1 %d\n",
i, q[0] + steps * (q[1] + steps * q[2]));
#endif
} else {
#if 0
printf("%d: gr3 %d %d %d\n",
i, q[0], q[1], q[2]);
#endif
put_bits(p, bits, q[0]);
put_bits(p, bits, q[1]);
put_bits(p, bits, q[2]);
}
}
/* next subband in alloc table */
j += 1 << bit_alloc_bits;
}
}
}
/* padding */
for(i=0;i<padding;i++)
put_bits(p, 1, 0);
/* flush */
flush_put_bits(p);
}
int MPA_encode_frame(AVEncodeContext *avctx,
unsigned char *frame, int buf_size, void *data)
{
MpegAudioContext *s = avctx->priv_data;
short *samples = data;
short smr[SBLIMIT];
unsigned char bit_alloc[SBLIMIT];
int padding;
filter(s, samples);
compute_scale_factors(s->scale_code, s->scale_factors,
s->sb_samples, s->sblimit);
psycho_acoustic_model(s, smr);
compute_bit_allocation(s, smr, bit_alloc, &padding);
init_put_bits(&s->pb, frame, MPA_MAX_CODED_FRAME_SIZE, NULL, NULL);
encode_frame(s, bit_alloc, padding);
s->nb_samples += MPA_FRAME_SIZE;
return s->pb.buf_ptr - s->pb.buf;
}
AVEncoder mp2_encoder = {
"mp2",
CODEC_TYPE_AUDIO,
CODEC_ID_MP2,
sizeof(MpegAudioContext),
MPA_encode_init,
MPA_encode_frame,
NULL,
};

@ -0,0 +1,31 @@
/* max compressed frame size */
#define MPA_MAX_CODED_FRAME_SIZE 1200
#define MPA_FRAME_SIZE 1152
#define SAMPLES_BUF_SIZE 4096
#define SBLIMIT 32 /* number of subbands */
#define DCT_BITS 14 /* number of bits for the DCT */
#define MUL(a,b) (((a) * (b)) >> DCT_BITS)
#define FIX(a) ((int)((a) * (1 << DCT_BITS)))
typedef struct MpegAudioContext {
PutBitContext pb;
int freq, bit_rate;
int lsf; /* 1 if mpeg2 low bitrate selected */
int bitrate_index; /* bit rate */
int freq_index;
int frame_size; /* frame size, in bits, without padding */
long long nb_samples; /* total number of samples encoded */
/* padding computation */
int frame_frac, frame_frac_incr, do_padding;
short samples_buf[SAMPLES_BUF_SIZE]; /* buffer for filter */
int samples_offset; /* offset in samples_buf */
int sb_samples[3][12][SBLIMIT];
unsigned char scale_factors[SBLIMIT][3]; /* scale factors */
unsigned char scale_code[SBLIMIT]; /* code to group 3 scale factors */
int sblimit; /* number of used subbands */
const unsigned char *alloc_table;
} MpegAudioContext;

@ -0,0 +1,310 @@
/*
* mpeg audio layer 2 tables. Most of them come from the mpeg audio
* specification.
*
* Copyright (c) 2000 Gerard Lantau.
*
* The licence of this code is contained in file LICENCE found in the
* same archive
*/
static const unsigned short bitrate_tab[2][15] = {
{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160}, /* mpeg2 lsf */
{0,32,48,56,64,80,96,112,128,160,192,224,256,320,384}, /* mpeg1 */
};
static const unsigned short freq_tab[3] = { 44100, 48000, 32000 };
#define SQRT2 1.41421356237309514547
static const int costab32[30] = {
FIX(0.54119610014619701222),
FIX(1.3065629648763763537),
FIX(0.50979557910415917998),
FIX(2.5629154477415054814),
FIX(0.89997622313641556513),
FIX(0.60134488693504528634),
FIX(0.5024192861881556782),
FIX(5.1011486186891552563),
FIX(0.78815462345125020249),
FIX(0.64682178335999007679),
FIX(0.56694403481635768927),
FIX(1.0606776859903470633),
FIX(1.7224470982383341955),
FIX(0.52249861493968885462),
FIX(10.19000812354803287),
FIX(0.674808341455005678),
FIX(1.1694399334328846596),
FIX(0.53104259108978413284),
FIX(2.0577810099534108446),
FIX(0.58293496820613388554),
FIX(0.83934964541552681272),
FIX(0.50547095989754364798),
FIX(3.4076084184687189804),
FIX(0.62250412303566482475),
FIX(0.97256823786196078263),
FIX(0.51544730992262455249),
FIX(1.4841646163141661852),
FIX(0.5531038960344445421),
FIX(0.74453627100229857749),
FIX(0.5006029982351962726),
};
static const int bitinv32[32] = {
0, 16, 8, 24, 4, 20, 12, 28,
2, 18, 10, 26, 6, 22, 14, 30,
1, 17, 9, 25, 5, 21, 13, 29,
3, 19, 11, 27, 7, 23, 15, 31
};
static short filter_bank[512];
static const double enwindow[512] = {0.000000000,
-0.000000477, -0.000000477, -0.000000477, -0.000000477, -0.000000477, -0.000000477, -0.000000954, -0.000000954,
-0.000000954, -0.000000954, -0.000001431, -0.000001431, -0.000001907, -0.000001907, -0.000002384, -0.000002384,
-0.000002861, -0.000003338, -0.000003338, -0.000003815, -0.000004292, -0.000004768, -0.000005245, -0.000006199,
-0.000006676, -0.000007629, -0.000008106, -0.000009060, -0.000010014, -0.000011444, -0.000012398, -0.000013828,
-0.000014782, -0.000016689, -0.000018120, -0.000019550, -0.000021458, -0.000023365, -0.000025272, -0.000027657,
-0.000030041, -0.000032425, -0.000034809, -0.000037670, -0.000040531, -0.000043392, -0.000046253, -0.000049591,
-0.000052929, -0.000055790, -0.000059605, -0.000062943, -0.000066280, -0.000070095, -0.000073433, -0.000076771,
-0.000080585, -0.000083923, -0.000087261, -0.000090599, -0.000093460, -0.000096321, -0.000099182, 0.000101566,
0.000103951, 0.000105858, 0.000107288, 0.000108242, 0.000108719, 0.000108719, 0.000108242, 0.000106812,
0.000105381, 0.000102520, 0.000099182, 0.000095367, 0.000090122, 0.000084400, 0.000077724, 0.000069618,
0.000060558, 0.000050545, 0.000039577, 0.000027180, 0.000013828, -0.000000954, -0.000017166, -0.000034332,
-0.000052929, -0.000072956, -0.000093937, -0.000116348, -0.000140190, -0.000165462, -0.000191212, -0.000218868,
-0.000247478, -0.000277042, -0.000307560, -0.000339031, -0.000371456, -0.000404358, -0.000438213, -0.000472546,
-0.000507355, -0.000542164, -0.000576973, -0.000611782, -0.000646591, -0.000680923, -0.000714302, -0.000747204,
-0.000779152, -0.000809669, -0.000838757, -0.000866413, -0.000891685, -0.000915051, -0.000935555, -0.000954151,
-0.000968933, -0.000980854, -0.000989437, -0.000994205, -0.000995159, -0.000991821, -0.000983715, 0.000971317,
0.000953674, 0.000930786, 0.000902653, 0.000868797, 0.000829220, 0.000783920, 0.000731945, 0.000674248,
0.000610352, 0.000539303, 0.000462532, 0.000378609, 0.000288486, 0.000191689, 0.000088215, -0.000021458,
-0.000137329, -0.000259876, -0.000388145, -0.000522137, -0.000661850, -0.000806808, -0.000956535, -0.001111031,
-0.001269817, -0.001432419, -0.001597881, -0.001766682, -0.001937389, -0.002110004, -0.002283096, -0.002457142,
-0.002630711, -0.002803326, -0.002974033, -0.003141880, -0.003306866, -0.003467083, -0.003622532, -0.003771782,
-0.003914356, -0.004048824, -0.004174709, -0.004290581, -0.004395962, -0.004489899, -0.004570484, -0.004638195,
-0.004691124, -0.004728317, -0.004748821, -0.004752159, -0.004737377, -0.004703045, -0.004649162, -0.004573822,
-0.004477024, -0.004357815, -0.004215240, -0.004049301, -0.003858566, -0.003643036, -0.003401756, 0.003134727,
0.002841473, 0.002521515, 0.002174854, 0.001800537, 0.001399517, 0.000971317, 0.000515938, 0.000033379,
-0.000475883, -0.001011848, -0.001573563, -0.002161503, -0.002774239, -0.003411293, -0.004072189, -0.004756451,
-0.005462170, -0.006189346, -0.006937027, -0.007703304, -0.008487225, -0.009287834, -0.010103703, -0.010933399,
-0.011775017, -0.012627602, -0.013489246, -0.014358521, -0.015233517, -0.016112804, -0.016994476, -0.017876148,
-0.018756866, -0.019634247, -0.020506859, -0.021372318, -0.022228718, -0.023074150, -0.023907185, -0.024725437,
-0.025527000, -0.026310921, -0.027073860, -0.027815342, -0.028532982, -0.029224873, -0.029890060, -0.030526638,
-0.031132698, -0.031706810, -0.032248020, -0.032754898, -0.033225536, -0.033659935, -0.034055710, -0.034412861,
-0.034730434, -0.035007000, -0.035242081, -0.035435200, -0.035586357, -0.035694122, -0.035758972, 0.035780907,
0.035758972, 0.035694122, 0.035586357, 0.035435200, 0.035242081, 0.035007000, 0.034730434, 0.034412861,
0.034055710, 0.033659935, 0.033225536, 0.032754898, 0.032248020, 0.031706810, 0.031132698, 0.030526638,
0.029890060, 0.029224873, 0.028532982, 0.027815342, 0.027073860, 0.026310921, 0.025527000, 0.024725437,
0.023907185, 0.023074150, 0.022228718, 0.021372318, 0.020506859, 0.019634247, 0.018756866, 0.017876148,
0.016994476, 0.016112804, 0.015233517, 0.014358521, 0.013489246, 0.012627602, 0.011775017, 0.010933399,
0.010103703, 0.009287834, 0.008487225, 0.007703304, 0.006937027, 0.006189346, 0.005462170, 0.004756451,
0.004072189, 0.003411293, 0.002774239, 0.002161503, 0.001573563, 0.001011848, 0.000475883, -0.000033379,
-0.000515938, -0.000971317, -0.001399517, -0.001800537, -0.002174854, -0.002521515, -0.002841473, 0.003134727,
0.003401756, 0.003643036, 0.003858566, 0.004049301, 0.004215240, 0.004357815, 0.004477024, 0.004573822,
0.004649162, 0.004703045, 0.004737377, 0.004752159, 0.004748821, 0.004728317, 0.004691124, 0.004638195,
0.004570484, 0.004489899, 0.004395962, 0.004290581, 0.004174709, 0.004048824, 0.003914356, 0.003771782,
0.003622532, 0.003467083, 0.003306866, 0.003141880, 0.002974033, 0.002803326, 0.002630711, 0.002457142,
0.002283096, 0.002110004, 0.001937389, 0.001766682, 0.001597881, 0.001432419, 0.001269817, 0.001111031,
0.000956535, 0.000806808, 0.000661850, 0.000522137, 0.000388145, 0.000259876, 0.000137329, 0.000021458,
-0.000088215, -0.000191689, -0.000288486, -0.000378609, -0.000462532, -0.000539303, -0.000610352, -0.000674248,
-0.000731945, -0.000783920, -0.000829220, -0.000868797, -0.000902653, -0.000930786, -0.000953674, 0.000971317,
0.000983715, 0.000991821, 0.000995159, 0.000994205, 0.000989437, 0.000980854, 0.000968933, 0.000954151,
0.000935555, 0.000915051, 0.000891685, 0.000866413, 0.000838757, 0.000809669, 0.000779152, 0.000747204,
0.000714302, 0.000680923, 0.000646591, 0.000611782, 0.000576973, 0.000542164, 0.000507355, 0.000472546,
0.000438213, 0.000404358, 0.000371456, 0.000339031, 0.000307560, 0.000277042, 0.000247478, 0.000218868,
0.000191212, 0.000165462, 0.000140190, 0.000116348, 0.000093937, 0.000072956, 0.000052929, 0.000034332,
0.000017166, 0.000000954, -0.000013828, -0.000027180, -0.000039577, -0.000050545, -0.000060558, -0.000069618,
-0.000077724, -0.000084400, -0.000090122, -0.000095367, -0.000099182, -0.000102520, -0.000105381, -0.000106812,
-0.000108242, -0.000108719, -0.000108719, -0.000108242, -0.000107288, -0.000105858, -0.000103951, 0.000101566,
0.000099182, 0.000096321, 0.000093460, 0.000090599, 0.000087261, 0.000083923, 0.000080585, 0.000076771,
0.000073433, 0.000070095, 0.000066280, 0.000062943, 0.000059605, 0.000055790, 0.000052929, 0.000049591,
0.000046253, 0.000043392, 0.000040531, 0.000037670, 0.000034809, 0.000032425, 0.000030041, 0.000027657,
0.000025272, 0.000023365, 0.000021458, 0.000019550, 0.000018120, 0.000016689, 0.000014782, 0.000013828,
0.000012398, 0.000011444, 0.000010014, 0.000009060, 0.000008106, 0.000007629, 0.000006676, 0.000006199,
0.000005245, 0.000004768, 0.000004292, 0.000003815, 0.000003338, 0.000003338, 0.000002861, 0.000002384,
0.000002384, 0.000001907, 0.000001907, 0.000001431, 0.000001431, 0.000000954, 0.000000954, 0.000000954,
0.000000954, 0.000000477, 0.000000477, 0.000000477, 0.000000477, 0.000000477, 0.000000477
};
static int scale_factor_table[64];
#ifdef USE_FLOATS
static float scale_factor_inv_table[64];
#else
static INT8 scale_factor_shift[64];
static unsigned short scale_factor_mult[64];
#endif
static unsigned char scale_diff_table[128];
static const int sblimit_table[5] = { 27 , 30 , 8, 12 , 30 };
static const int quant_steps[17] = {
3, 5, 7, 9, 15,
31, 63, 127, 255, 511,
1023, 2047, 4095, 8191, 16383,
32767, 65535
};
/* we use a negative value if grouped */
static const int quant_bits[17] = {
-5, -7, 3, -10, 4,
5, 6, 7, 8, 9,
10, 11, 12, 13, 14,
15, 16
};
/* signal to noise ratio of each quantification step (could be
computed from quant_steps[]). The values are dB multiplied by 10
*/
static unsigned short quant_snr[17] = {
70, 110, 160, 208,
253, 316, 378, 439,
499, 559, 620, 680,
740, 800, 861, 920,
980
};
/* total number of bits per allocation group */
static unsigned short total_quant_bits[17];
/* encoding tables which give the quantization index. Note how it is
possible to store them efficiently ! */
static const unsigned char alloc_table_0[] = {
4, 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
4, 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
4, 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
2, 0, 1, 16,
2, 0, 1, 16,
2, 0, 1, 16,
2, 0, 1, 16,
};
static const unsigned char alloc_table_1[] = {
4, 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
4, 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
4, 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
2, 0, 1, 16,
2, 0, 1, 16,
2, 0, 1, 16,
2, 0, 1, 16,
2, 0, 1, 16,
2, 0, 1, 16,
2, 0, 1, 16,
};
static const unsigned char alloc_table_2[] = {
4, 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
4, 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
};
static const unsigned char alloc_table_3[] = {
4, 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
4, 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
};
static const unsigned char alloc_table_4[] = {
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
};
const unsigned char *alloc_tables[5] =
{ alloc_table_0, alloc_table_1, alloc_table_2, alloc_table_3, alloc_table_4, };
/* fixed psycho acoustic model. Values of SNR taken from the 'toolame'
project */
const float fixed_smr[SBLIMIT] = {
30, 17, 16, 10, 3, 12, 8, 2.5,
5, 5, 6, 6, 5, 6, 10, 6,
-4, -10, -21, -30, -42, -55, -68, -75,
-75, -75, -75, -75, -91, -107, -110, -108
};
const unsigned char nb_scale_factors[4] = { 3, 2, 1, 2 };

@ -0,0 +1,311 @@
/*
* RV 1.0 compatible encoder.
* Copyright (c) 2000 Gerard Lantau.
*
* The licence of this code is contained in file LICENCE found in the
* same archive
*/
const unsigned char vlc_dc_table[256] = {
0, 1, 2, 2,
3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
};
const unsigned char vlc_dc_lum_code[9] = {
0x4, 0x0, 0x1, 0x5, 0x6, 0xe, 0x1e, 0x3e, 0x7e,
};
const unsigned char vlc_dc_lum_bits[9] = {
3, 2, 2, 3, 3, 4, 5, 6, 7,
};
const unsigned char vlc_dc_chroma_code[9] = {
0x0, 0x1, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe,
};
const unsigned char vlc_dc_chroma_bits[9] = {
2, 2, 2, 3, 4, 5, 6, 7, 8,
};
/*
* Copyright (c) 1995 The Regents of the University of California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose, without fee, and without written agreement is
* hereby granted, provided that the above copyright notice and the following
* two paragraphs appear in all copies of this software.
*
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
* CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#define HUFF_MAXRUN 32
#define HUFF_MAXLEVEL 41
static const int huff_maxlevel[HUFF_MAXRUN] = { 41, 19, 6, 5, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
static const UINT8 huff_table0[41] = { 0x0, 0x6, 0x8, 0xa, 0xc, 0x4c, 0x42, 0x14, 0x3a, 0x30, 0x26, 0x20, 0x34, 0x32, 0x30, 0x2e, 0x3e, 0x3c, 0x3a, 0x38, 0x36, 0x34, 0x32, 0x30, 0x2e, 0x2c, 0x2a, 0x28, 0x26, 0x24, 0x22, 0x20, 0x30, 0x2e, 0x2c, 0x2a, 0x28, 0x26, 0x24, 0x22, 0x20 };
static const UINT8 huff_bits0[41] = { 0, 3, 5, 6, 8, 9, 9, 11, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16 };
static const UINT8 huff_table1[19] = { 0x0, 0x6, 0xc, 0x4a, 0x18, 0x36, 0x2c, 0x2a, 0x3e, 0x3c, 0x3a, 0x38, 0x36, 0x34, 0x32, 0x26, 0x24, 0x22, 0x20 };
static const UINT8 huff_bits1[19] = { 0, 4, 7, 9, 11, 13, 14, 14, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17 };
static const UINT8 huff_table2[6] = { 0x0, 0xa, 0x8, 0x16, 0x28, 0x28 };
static const UINT8 huff_bits2[6] = { 0, 5, 8, 11, 13, 14 };
static const UINT8 huff_table3[5] = { 0x0, 0xe, 0x48, 0x38, 0x26 };
static const UINT8 huff_bits3[5] = { 0, 6, 9, 13, 14 };
static const UINT8 huff_table4[4] = { 0x0, 0xc, 0x1e, 0x24 };
static const UINT8 huff_bits4[4] = { 0, 6, 11, 13 };
static const UINT8 huff_table5[4] = { 0x0, 0xe, 0x12, 0x24 };
static const UINT8 huff_bits5[4] = { 0, 7, 11, 14 };
static const UINT8 huff_table6[4] = { 0x0, 0xa, 0x3c, 0x28 };
static const UINT8 huff_bits6[4] = { 0, 7, 13, 17 };
static const UINT8 huff_table7[3] = { 0x0, 0x8, 0x2a };
static const UINT8 huff_bits7[3] = { 0, 7, 13 };
static const UINT8 huff_table8[3] = { 0x0, 0xe, 0x22 };
static const UINT8 huff_bits8[3] = { 0, 8, 13 };
static const UINT8 huff_table9[3] = { 0x0, 0xa, 0x22 };
static const UINT8 huff_bits9[3] = { 0, 8, 14 };
static const UINT8 huff_table10[3] = { 0x0, 0x4e, 0x20 };
static const UINT8 huff_bits10[3] = { 0, 9, 14 };
static const UINT8 huff_table11[3] = { 0x0, 0x46, 0x34 };
static const UINT8 huff_bits11[3] = { 0, 9, 17 };
static const UINT8 huff_table12[3] = { 0x0, 0x44, 0x32 };
static const UINT8 huff_bits12[3] = { 0, 9, 17 };
static const UINT8 huff_table13[3] = { 0x0, 0x40, 0x30 };
static const UINT8 huff_bits13[3] = { 0, 9, 17 };
static const UINT8 huff_table14[3] = { 0x0, 0x1c, 0x2e };
static const UINT8 huff_bits14[3] = { 0, 11, 17 };
static const UINT8 huff_table15[3] = { 0x0, 0x1a, 0x2c };
static const UINT8 huff_bits15[3] = { 0, 11, 17 };
static const UINT8 huff_table16[3] = { 0x0, 0x10, 0x2a };
static const UINT8 huff_bits16[3] = { 0, 11, 17 };
static const UINT8 huff_table17[2] = { 0x0, 0x3e };
static const UINT8 huff_bits17[2] = { 0, 13 };
static const UINT8 huff_table18[2] = { 0x0, 0x34 };
static const UINT8 huff_bits18[2] = { 0, 13 };
static const UINT8 huff_table19[2] = { 0x0, 0x32 };
static const UINT8 huff_bits19[2] = { 0, 13 };
static const UINT8 huff_table20[2] = { 0x0, 0x2e };
static const UINT8 huff_bits20[2] = { 0, 13 };
static const UINT8 huff_table21[2] = { 0x0, 0x2c };
static const UINT8 huff_bits21[2] = { 0, 13 };
static const UINT8 huff_table22[2] = { 0x0, 0x3e };
static const UINT8 huff_bits22[2] = { 0, 14 };
static const UINT8 huff_table23[2] = { 0x0, 0x3c };
static const UINT8 huff_bits23[2] = { 0, 14 };
static const UINT8 huff_table24[2] = { 0x0, 0x3a };
static const UINT8 huff_bits24[2] = { 0, 14 };
static const UINT8 huff_table25[2] = { 0x0, 0x38 };
static const UINT8 huff_bits25[2] = { 0, 14 };
static const UINT8 huff_table26[2] = { 0x0, 0x36 };
static const UINT8 huff_bits26[2] = { 0, 14 };
static const UINT8 huff_table27[2] = { 0x0, 0x3e };
static const UINT8 huff_bits27[2] = { 0, 17 };
static const UINT8 huff_table28[2] = { 0x0, 0x3c };
static const UINT8 huff_bits28[2] = { 0, 17 };
static const UINT8 huff_table29[2] = { 0x0, 0x3a };
static const UINT8 huff_bits29[2] = { 0, 17 };
static const UINT8 huff_table30[2] = { 0x0, 0x38 };
static const UINT8 huff_bits30[2] = { 0, 17 };
static const UINT8 huff_table31[2] = { 0x0, 0x36 };
static const UINT8 huff_bits31[2] = { 0, 17 };
static const UINT8 *huff_table[32] = { huff_table0, huff_table1, huff_table2, huff_table3, huff_table4, huff_table5, huff_table6, huff_table7, huff_table8, huff_table9, huff_table10, huff_table11, huff_table12, huff_table13, huff_table14, huff_table15, huff_table16, huff_table17, huff_table18, huff_table19, huff_table20, huff_table21, huff_table22, huff_table23, huff_table24, huff_table25, huff_table26, huff_table27, huff_table28, huff_table29, huff_table30, huff_table31 };
static const UINT8 *huff_bits[32] = { huff_bits0, huff_bits1, huff_bits2, huff_bits3, huff_bits4, huff_bits5, huff_bits6, huff_bits7, huff_bits8, huff_bits9, huff_bits10, huff_bits11, huff_bits12, huff_bits13, huff_bits14, huff_bits15, huff_bits16, huff_bits17, huff_bits18, huff_bits19, huff_bits20, huff_bits21, huff_bits22, huff_bits23, huff_bits24, huff_bits25, huff_bits26, huff_bits27, huff_bits28, huff_bits29, huff_bits30, huff_bits31 };
static const UINT8 mbAddrIncrTable[][2] = {
{0x0, 0},
{0x1, 1},
{0x3, 3},
{0x2, 3},
{0x3, 4},
{0x2, 4},
{0x3, 5},
{0x2, 5},
{0x7, 7},
{0x6, 7},
{0xb, 8},
{0xa, 8},
{0x9, 8},
{0x8, 8},
{0x7, 8},
{0x6, 8},
{0x17, 10},
{0x16, 10},
{0x15, 10},
{0x14, 10},
{0x13, 10},
{0x12, 10},
{0x23, 11},
{0x22, 11},
{0x21, 11},
{0x20, 11},
{0x1f, 11},
{0x1e, 11},
{0x1d, 11},
{0x1c, 11},
{0x1b, 11},
{0x1a, 11},
{0x19, 11},
{0x18, 11}};
static const UINT8 mbPatTable[][2] = {
{0x0, 0},
{0xb, 5},
{0x9, 5},
{0xd, 6},
{0xd, 4},
{0x17, 7},
{0x13, 7},
{0x1f, 8},
{0xc, 4},
{0x16, 7},
{0x12, 7},
{0x1e, 8},
{0x13, 5},
{0x1b, 8},
{0x17, 8},
{0x13, 8},
{0xb, 4},
{0x15, 7},
{0x11, 7},
{0x1d, 8},
{0x11, 5},
{0x19, 8},
{0x15, 8},
{0x11, 8},
{0xf, 6},
{0xf, 8},
{0xd, 8},
{0x3, 9},
{0xf, 5},
{0xb, 8},
{0x7, 8},
{0x7, 9},
{0xa, 4},
{0x14, 7},
{0x10, 7},
{0x1c, 8},
{0xe, 6},
{0xe, 8},
{0xc, 8},
{0x2, 9},
{0x10, 5},
{0x18, 8},
{0x14, 8},
{0x10, 8},
{0xe, 5},
{0xa, 8},
{0x6, 8},
{0x6, 9},
{0x12, 5},
{0x1a, 8},
{0x16, 8},
{0x12, 8},
{0xd, 5},
{0x9, 8},
{0x5, 8},
{0x5, 9},
{0xc, 5},
{0x8, 8},
{0x4, 8},
{0x4, 9},
{0x7, 3},
{0xa, 5}, /* grrr... 61, 62, 63 added - Kevin */
{0x8, 5},
{0xc, 6}
};
const UINT8 zigzag_direct[64] = {
0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34,
27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36,
29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46,
53, 60, 61, 54, 47, 55, 62, 63
};
static unsigned char const default_intra_matrix[64] = {
8, 16, 19, 22, 26, 27, 29, 34,
16, 16, 22, 24, 27, 29, 34, 37,
19, 22, 26, 27, 29, 34, 34, 38,
22, 22, 26, 27, 29, 34, 37, 40,
22, 26, 27, 29, 32, 35, 40, 48,
26, 27, 29, 32, 35, 40, 48, 58,
26, 27, 29, 34, 38, 46, 56, 69,
27, 29, 35, 38, 46, 56, 69, 83
};
/* XXX: could hardcode this matrix */
static unsigned char const default_non_intra_matrix[64] = {
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
};
static unsigned char const frame_rate_tab[9] = {
0, 24, 24, 25, 30, 30, 50, 60, 60,
};

File diff suppressed because it is too large Load Diff

@ -0,0 +1,94 @@
/* mpegencode.c */
/* Start codes. */
#define SEQ_END_CODE 0x000001b7
#define SEQ_START_CODE 0x000001b3
#define GOP_START_CODE 0x000001b8
#define PICTURE_START_CODE 0x00000100
#define SLICE_MIN_START_CODE 0x00000101
#define SLICE_MAX_START_CODE 0x000001af
#define EXT_START_CODE 0x000001b5
#define USER_START_CODE 0x000001b2
/* Macros for picture code type. */
#define I_TYPE 1
#define P_TYPE 2
#define B_TYPE 3
typedef int DCTELEM;
enum OutputFormat {
FMT_MPEG1,
FMT_H263,
FMT_MJPEG,
};
#define MAX_NEG_CROP 384
#define MPEG_BUF_SIZE (16 * 1024)
typedef struct MpegEncContext {
/* the following parameters must be initialized before encoding */
int width, height; /* picture size. must be a multiple of 16 */
int gop_size;
int frame_rate; /* number of frames per second */
int intra_only; /* if true, only intra pictures are generated */
int bit_rate; /* wanted bit rate */
enum OutputFormat out_format; /* output format */
int h263_rv10; /* use RV10 variation for H263 */
/* the following fields are managed internally by the encoder */
/* bit output */
PutBitContext pb;
/* sequence parameters */
int picture_number;
int fake_picture_number; /* picture number at the bitstream frame rate */
int gop_picture_number; /* index of the first picture of a GOP */
int mb_width, mb_height;
UINT8 *new_picture[3]; /* picture to be compressed */
UINT8 *last_picture[3]; /* previous picture */
UINT8 *current_picture[3]; /* buffer to store the decompressed current picture */
int last_dc[3];
int qscale;
int pict_type;
int frame_rate_index;
/* macroblock layer */
int mb_incr;
int mb_intra;
/* matrix transmitted in the bitstream */
UINT8 init_intra_matrix[64];
/* precomputed matrix (combine qscale and DCT renorm) */
int intra_matrix[64];
int non_intra_matrix[64];
int block_last_index[6]; /* last non zero coefficient in block */
void *opaque; /* private data for the user */
/* bit rate control */
int I_frame_bits; /* wanted number of bits per I frame */
int P_frame_bits; /* same for P frame */
long long wanted_bits;
long long total_bits;
struct MJpegContext *mjpeg_ctx;
} MpegEncContext;
extern const UINT8 zigzag_direct[64];
/* h263enc.c */
void h263_encode_mb(MpegEncContext *s,
DCTELEM block[6][64],
int motion_x, int motion_y);
void h263_picture_header(MpegEncContext *s, int picture_number);
void rv10_encode_picture_header(MpegEncContext *s, int picture_number);
/* mjpegenc.c */
int mjpeg_init(MpegEncContext *s);
void mjpeg_close(MpegEncContext *s);
void mjpeg_encode_mb(MpegEncContext *s,
DCTELEM block[6][64]);
void mjpeg_picture_header(MpegEncContext *s);
void mjpeg_picture_trailer(MpegEncContext *s);

@ -0,0 +1,245 @@
/*
* Sample rate convertion for both audio and video
* 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 <netinet/in.h>
#include <math.h>
#include "avcodec.h"
#define NDEBUG
#include <assert.h>
#define FRAC_BITS 16
#define FRAC (1 << FRAC_BITS)
static void init_mono_resample(ReSampleChannelContext *s, float ratio)
{
ratio = 1.0 / ratio;
s->iratio = (int)floor(ratio);
if (s->iratio == 0)
s->iratio = 1;
s->incr = (int)((ratio / s->iratio) * FRAC);
s->frac = 0;
s->last_sample = 0;
s->icount = s->iratio;
s->isum = 0;
s->inv = (FRAC / s->iratio);
}
/* fractional audio resampling */
static int fractional_resample(ReSampleChannelContext *s, short *output, short *input, int nb_samples)
{
unsigned int frac, incr;
int l0, l1;
short *q, *p, *pend;
l0 = s->last_sample;
incr = s->incr;
frac = s->frac;
p = input;
pend = input + nb_samples;
q = output;
l1 = *p++;
for(;;) {
/* interpolate */
*q++ = (l0 * (FRAC - frac) + l1 * frac) >> FRAC_BITS;
frac = frac + s->incr;
while (frac >= FRAC) {
if (p >= pend)
goto the_end;
frac -= FRAC;
l0 = l1;
l1 = *p++;
}
}
the_end:
s->last_sample = l1;
s->frac = frac;
return q - output;
}
static int integer_downsample(ReSampleChannelContext *s, short *output, short *input, int nb_samples)
{
short *q, *p, *pend;
int c, sum;
p = input;
pend = input + nb_samples;
q = output;
c = s->icount;
sum = s->isum;
for(;;) {
sum += *p++;
if (--c == 0) {
*q++ = (sum * s->inv) >> FRAC_BITS;
c = s->iratio;
sum = 0;
}
if (p >= pend)
break;
}
s->isum = sum;
s->icount = c;
return q - output;
}
/* n1: number of samples */
static void stereo_to_mono(short *output, short *input, int n1)
{
short *p, *q;
int n = n1;
p = input;
q = output;
while (n >= 4) {
q[0] = (p[0] + p[1]) >> 1;
q[1] = (p[2] + p[3]) >> 1;
q[2] = (p[4] + p[5]) >> 1;
q[3] = (p[6] + p[7]) >> 1;
q += 4;
p += 8;
n -= 4;
}
while (n > 0) {
q[0] = (p[0] + p[1]) >> 1;
q++;
p += 2;
n--;
}
}
/* XXX: should use more abstract 'N' channels system */
static void stereo_split(short *output1, short *output2, short *input, int n)
{
int i;
for(i=0;i<n;i++) {
*output1++ = *input++;
*output2++ = *input++;
}
}
static void stereo_mux(short *output, short *input1, short *input2, int n)
{
int i;
for(i=0;i<n;i++) {
*output++ = *input1++;
*output++ = *input2++;
}
}
static int mono_resample(ReSampleChannelContext *s, short *output, short *input, int nb_samples)
{
short buf1[nb_samples];
short *buftmp;
/* first downsample by an integer factor with averaging filter */
if (s->iratio > 1) {
buftmp = buf1;
nb_samples = integer_downsample(s, buftmp, input, nb_samples);
} else {
buftmp = input;
}
/* then do a fractional resampling with linear interpolation */
if (s->incr != FRAC) {
nb_samples = fractional_resample(s, output, buftmp, nb_samples);
} else {
memcpy(output, buftmp, nb_samples * sizeof(short));
}
return nb_samples;
}
/* ratio = output_rate / input_rate */
int audio_resample_init(ReSampleContext *s,
int output_channels, int input_channels,
int output_rate, int input_rate)
{
int i;
s->ratio = (float)output_rate / (float)input_rate;
if (output_channels > 2 || input_channels > 2)
return -1;
s->input_channels = input_channels;
s->output_channels = output_channels;
for(i=0;i<output_channels;i++) {
init_mono_resample(&s->channel_ctx[i], s->ratio);
}
return 0;
}
/* resample audio. 'nb_samples' is the number of input samples */
/* XXX: optimize it ! */
/* XXX: do it with polyphase filters, since the quality here is
HORRIBLE. Return the number of samples available in output */
int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples)
{
int i, nb_samples1;
short buf[5][nb_samples];
short *buftmp1, *buftmp2[2], *buftmp3[2];
if (s->input_channels == s->output_channels && s->ratio == 1.0) {
/* nothing to do */
memcpy(output, input, nb_samples * s->input_channels * sizeof(short));
return nb_samples;
}
if (s->input_channels == 2 &&
s->output_channels == 1) {
buftmp1 = buf[0];
stereo_to_mono(buftmp1, input, nb_samples);
} else if (s->input_channels == 1 &&
s->output_channels == 2) {
/* XXX: do it */
abort();
} else {
buftmp1 = input;
}
if (s->output_channels == 2) {
buftmp2[0] = buf[1];
buftmp2[1] = buf[2];
buftmp3[0] = buf[3];
buftmp3[1] = buf[4];
stereo_split(buftmp2[0], buftmp2[1], buftmp1, nb_samples);
} else {
buftmp2[0] = buftmp1;
buftmp3[0] = output;
}
/* resample each channel */
nb_samples1 = 0; /* avoid warning */
for(i=0;i<s->output_channels;i++) {
nb_samples1 = mono_resample(&s->channel_ctx[i], buftmp3[i], buftmp2[i], nb_samples);
}
if (s->output_channels == 2) {
stereo_mux(output, buftmp3[0], buftmp3[1], nb_samples1);
}
return nb_samples1;
}

@ -0,0 +1,127 @@
#include "avcodec.h"
/* byte stream handling */
typedef struct {
unsigned char *buffer;
unsigned char *buf_ptr, *buf_end;
void *opaque;
void (*write_packet)(void *opaque, UINT8 *buf, int buf_size);
int (*write_seek)(void *opaque, long long offset, int whence);
long long pos; /* position in the file of the current buffer */
} PutByteContext;
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));
void put_byte(PutByteContext *s, int b);
void put_buffer(PutByteContext *s, unsigned char *buf, int size);
void put_le32(PutByteContext *s, unsigned int val);
void put_le64(PutByteContext *s, unsigned long long val);
void put_le16(PutByteContext *s, unsigned int val);
void put_tag(PutByteContext *s, char *tag);
long long put_seek(PutByteContext *s, long long offset, int whence);
long long put_pos(PutByteContext *s);
void put_flush_packet(PutByteContext *s);
/* udp.c */
typedef struct {
int udp_socket;
int max_payload_size; /* in bytes */
} UDPContext;
int udp_tx_open(UDPContext *s,
const char *uri,
int local_port);
void udp_tx_close(UDPContext *s);
void udp_write_data(void *opaque, UINT8 *buf, int size);
/* generic functions */
struct AVFormatContext;
typedef struct AVFormat {
char *name;
char *long_name;
char *mime_type;
char *extensions; /* comma separated extensions */
enum CodecID audio_codec;
enum CodecID video_codec;
int (*write_header)(struct AVFormatContext *);
int (*write_audio_frame)(struct AVFormatContext *,
unsigned char *buf, int size);
int (*write_video_picture)(struct AVFormatContext *,
unsigned char *buf, int size);
int (*write_trailer)(struct AVFormatContext *);
struct AVFormat *next;
} AVFormat;
typedef struct AVFormatContext {
struct AVFormat *format;
void *priv_data;
PutByteContext pb;
AVEncodeContext *video_enc;
AVEncodeContext *audio_enc;
int is_streamed; /* true if the stream is generated as being streamed */
} AVFormatContext;
extern AVFormat *first_format;
extern int data_out_size;
extern const char *comment_string;
/* rv10enc.c */
extern AVFormat rm_format;
extern AVFormat ra_format;
/* mpegmux.c */
extern AVFormat mpeg_mux_format;
/* asfenc.c */
extern AVFormat asf_format;
/* jpegenc.c */
extern AVFormat mpjpeg_format;
extern AVFormat jpeg_format;
/* swfenc.c */
extern AVFormat swf_format;
/* formats.c */
void register_avformat(AVFormat *format);
AVFormat *guess_format(const char *short_name, const char *filename, const char *mime_type);
void register_avencoder(AVEncoder *format);
AVEncoder *avencoder_find(enum CodecID id);
void avencoder_string(char *buf, int buf_size, AVEncodeContext *enc);
int avencoder_open(AVEncodeContext *avctx, AVEncoder *codec);
int avencoder_encode(AVEncodeContext *avctx, UINT8 *buf, int buf_size, void *data);
int avencoder_close(AVEncodeContext *avctx);
extern AVFormat mp2_format;
extern AVFormat ac3_format;
extern AVFormat h263_format;
extern AVFormat mpeg1video_format;
int strstart(const char *str, const char *val, const char **ptr);
/* grab.c */
extern const char *v4l_device;
long long gettime(void);
int v4l_init(int rate, int width, int height);
int v4l_read_picture(UINT8 *picture[3],
int width, int height,
int picture_number);
int audio_open(int freq, int channels);

@ -0,0 +1,301 @@
/*
* Output a MPEG1 multiplexed video/audio stream
* 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 <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 <getopt.h>
#include "mpegenc.h"
#include "mpegvideo.h"
#include "mpegaudio.h"
#define MAX_PAYLOAD_SIZE 4096
#define NB_STREAMS 2
typedef struct {
UINT8 buffer[MAX_PAYLOAD_SIZE];
int buffer_ptr;
UINT8 id;
int max_buffer_size;
int packet_number;
AVEncodeContext *enc;
float pts;
} StreamInfo;
typedef struct {
int packet_size; /* required packet size */
int packet_number;
int pack_header_freq; /* frequency (in packets^-1) at which we send pack headers */
int system_header_freq;
int mux_rate; /* bitrate in units of 50 bytes/s */
/* stream info */
int nb_streams;
StreamInfo streams[NB_STREAMS];
AVFormatContext *ctx;
} MpegMuxContext;
#define PACK_START_CODE ((unsigned int)0x000001ba)
#define SYSTEM_HEADER_START_CODE ((unsigned int)0x000001bb)
#define PACKET_START_CODE_MASK ((unsigned int)0xffffff00)
#define PACKET_START_CODE_PREFIX ((unsigned int)0x00000100)
#define ISO_11172_END_CODE ((unsigned int)0x000001b9)
#define AUDIO_ID 0xc0
#define VIDEO_ID 0xe0
static int put_pack_header(MpegMuxContext *s, UINT8 *buf, long long timestamp)
{
PutBitContext pb;
init_put_bits(&pb, buf, 128, NULL, NULL);
put_bits(&pb, 32, PACK_START_CODE);
put_bits(&pb, 4, 0x2);
put_bits(&pb, 3, (timestamp >> 30) & 0x07);
put_bits(&pb, 1, 1);
put_bits(&pb, 15, (timestamp >> 15) & 0x7fff);
put_bits(&pb, 1, 1);
put_bits(&pb, 15, (timestamp) & 0x7fff);
put_bits(&pb, 1, 1);
put_bits(&pb, 1, 1);
put_bits(&pb, 22, s->mux_rate);
flush_put_bits(&pb);
return pb.buf_ptr - pb.buf;
}
static int put_system_header(MpegMuxContext *s, UINT8 *buf)
{
int audio_bound, video_bound;
int size, rate_bound, i;
PutBitContext pb;
init_put_bits(&pb, buf, 128, NULL, NULL);
put_bits(&pb, 32, SYSTEM_HEADER_START_CODE);
put_bits(&pb, 16, 0);
put_bits(&pb, 1, 1);
rate_bound = s->mux_rate; /* maximum bit rate of the multiplexed stream */
put_bits(&pb, 22, rate_bound);
put_bits(&pb, 1, 1); /* marker */
audio_bound = 1; /* at most one audio stream */
put_bits(&pb, 6, audio_bound);
put_bits(&pb, 1, 0); /* variable bitrate */
put_bits(&pb, 1, 0); /* non constrainted bit stream */
put_bits(&pb, 1, 1); /* audio locked */
put_bits(&pb, 1, 1); /* video locked */
put_bits(&pb, 1, 1); /* marker */
video_bound = 1; /* at most one video stream */
put_bits(&pb, 5, video_bound);
put_bits(&pb, 8, 0xff); /* reserved byte */
/* audio stream info */
for(i=0;i<s->nb_streams;i++) {
put_bits(&pb, 8, s->streams[i].id); /* stream ID */
put_bits(&pb, 2, 3);
put_bits(&pb, 1, 1); /* buffer bound scale = 1024 */
put_bits(&pb, 13, s->streams[i].max_buffer_size); /* max buffer size */
}
/* no more streams */
put_bits(&pb, 1, 0);
flush_put_bits(&pb);
size = pb.buf_ptr - pb.buf;
/* patch packet size */
buf[4] = (size - 6) >> 8;
buf[5] = (size - 6) & 0xff;
return size;
}
/* Format a packet header for a total size of 'total_size'. Return the
header size */
static int put_packet_header(MpegMuxContext *s,
int id, long long timestamp,
UINT8 *buffer, int total_size)
{
UINT8 *buf_ptr;
PutBitContext pb;
int size, payload_size;
#if 0
printf("packet ID=%2x PTS=%0.3f size=%d\n",
id, timestamp / 90000.0, total_size);
#endif
buf_ptr = buffer;
if ((s->packet_number % s->pack_header_freq) == 0) {
/* output pack and systems header */
size = put_pack_header(s, buf_ptr, timestamp);
buf_ptr += size;
if ((s->packet_number % s->system_header_freq) == 0) {
size = put_system_header(s, buf_ptr);
buf_ptr += size;
}
}
payload_size = total_size - ((buf_ptr - buffer) + 6 + 5);
/* packet header */
init_put_bits(&pb, buf_ptr, 128, NULL, NULL);
put_bits(&pb, 32, PACKET_START_CODE_PREFIX + id);
put_bits(&pb, 16, payload_size + 5);
/* presentation time stamp */
put_bits(&pb, 4, 0x02);
put_bits(&pb, 3, (timestamp >> 30) & 0x07);
put_bits(&pb, 1, 1);
put_bits(&pb, 15, (timestamp >> 15) & 0x7fff);
put_bits(&pb, 1, 1);
put_bits(&pb, 15, (timestamp) & 0x7fff);
put_bits(&pb, 1, 1);
flush_put_bits(&pb);
s->packet_number++;
return pb.buf_ptr - buffer;
}
int mpeg_mux_init(AVFormatContext *ctx)
{
MpegMuxContext *s;
int bitrate, i;
s = malloc(sizeof(MpegMuxContext));
if (!s)
return -1;
memset(s, 0, sizeof(MpegMuxContext));
ctx->priv_data = s;
s->ctx = ctx;
s->packet_number = 0;
/* XXX: hardcoded */
s->packet_size = 2048;
s->nb_streams = 2;
s->streams[0].id = AUDIO_ID;
s->streams[0].max_buffer_size = 10; /* in KBytes */
s->streams[0].enc = ctx->audio_enc;
s->streams[1].id = VIDEO_ID;
s->streams[1].max_buffer_size = 50; /* in KBytes */
s->streams[1].enc = ctx->video_enc;
/* we increase slightly the bitrate to take into account the
headers. XXX: compute it exactly */
bitrate = 2000;
for(i=0;i<s->nb_streams;i++) {
bitrate += s->streams[i].enc->bit_rate;
}
s->mux_rate = (bitrate + (8 * 50) - 1) / (8 * 50);
/* every 2 seconds */
s->pack_header_freq = 2 * bitrate / s->packet_size / 8;
/* every 10 seconds */
s->system_header_freq = s->pack_header_freq * 5;
for(i=0;i<NB_STREAMS;i++) {
s->streams[i].buffer_ptr = 0;
s->streams[i].packet_number = 0;
s->streams[i].pts = 0;
}
return 0;
}
int mpeg_mux_end(AVFormatContext *ctx)
{
PutBitContext pb;
UINT8 buffer[128];
/* write the end header */
init_put_bits(&pb, buffer, sizeof(buffer), NULL, NULL);
put_bits(&pb, 32, ISO_11172_END_CODE);
put_buffer(&ctx->pb, buffer, pb.buf_ptr - buffer);
put_flush_packet(&ctx->pb);
return 0;
}
static void write_stream(MpegMuxContext *s, StreamInfo *stream, UINT8 *buf, int size)
{
int len, len1, header_size;
long long pts;
while (size > 0) {
if (stream->buffer_ptr == 0) {
pts = stream->pts * 90000.0;
header_size = put_packet_header(s, stream->id, pts, stream->buffer, s->packet_size);
stream->buffer_ptr = header_size;
}
len = size;
len1 = s->packet_size - stream->buffer_ptr;
if (len > len1)
len = len1;
memcpy(stream->buffer + stream->buffer_ptr, buf, len);
stream->buffer_ptr += len;
if (stream->buffer_ptr == s->packet_size) {
/* output the packet */
put_buffer(&s->ctx->pb, stream->buffer, s->packet_size);
put_flush_packet(&s->ctx->pb);
stream->buffer_ptr = 0;
stream->packet_number++;
}
buf += len;
size -= len;
}
}
static int mpeg_mux_write_audio(AVFormatContext *ctx, UINT8 *buf, int size)
{
MpegMuxContext *s = ctx->priv_data;
write_stream(s, &s->streams[0], buf, size);
s->streams[0].pts += (float)s->streams[0].enc->frame_size / s->streams[0].enc->rate;
return 0;
}
int mpeg_mux_write_video(AVFormatContext *ctx, UINT8 *buf, int size)
{
MpegMuxContext *s = ctx->priv_data;
write_stream(s, &s->streams[1], buf, size);
s->streams[1].pts += 1.0 / (float)s->streams[1].enc->rate;
return 0;
}
AVFormat mpeg_mux_format = {
"mpeg1",
"MPEG1 multiplex format",
"video/mpeg",
"mpg,mpeg",
CODEC_ID_MP2,
CODEC_ID_MPEG1VIDEO,
mpeg_mux_init,
mpeg_mux_write_audio,
mpeg_mux_write_video,
mpeg_mux_end,
};

@ -0,0 +1,498 @@
/*
* RV 1.0 compatible encoder.
* 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 "mpegenc.h"
#include "mpegvideo.h"
/* in ms */
#define BUFFER_DURATION 0
typedef struct {
int nb_packets;
int packet_total_size;
int packet_max_size;
/* codec related output */
int bit_rate;
float frame_rate;
int nb_frames; /* current frame number */
int total_frames; /* total number of frames */
int num;
AVEncodeContext *enc;
} StreamInfo;
typedef struct {
StreamInfo streams[2];
StreamInfo *audio_stream, *video_stream;
int nb_streams;
int data_pos; /* position of the data after the header */
} RMContext;
static void put_long(PutByteContext *s, unsigned int val)
{
put_byte(s, val >> 24);
put_byte(s, val >> 16);
put_byte(s, val >> 8);
put_byte(s, val);
}
static void put_short(PutByteContext *s, unsigned int val)
{
put_byte(s, val >> 8);
put_byte(s, val);
}
static void put_str(PutByteContext *s, const char *tag)
{
put_short(s,strlen(tag));
while (*tag) {
put_byte(s, *tag++);
}
}
static void put_str8(PutByteContext *s, const char *tag)
{
put_byte(s, strlen(tag));
while (*tag) {
put_byte(s, *tag++);
}
}
int find_tag(const char *tag, char *buf, int buf_size, const char *str)
{
int len = strlen(tag);
char *q;
buf[0] = '\0';
while (*str) {
if (*str == '+' && !strncmp(str + 1, tag, len) && str[len+1] == '=') {
str += len + 2;
q = buf;
while (*str && *str != '+' && (q - buf) < (buf_size - 1)) {
*q++ = *str++;
}
/* remove trailing spaces */
while (q > buf && q[-1] == ' ') q--;
*q = '\0';
return 1;
}
str++;
}
return 0;
}
static void rv10_write_header(AVFormatContext *ctx,
int data_size, int index_pos)
{
RMContext *rm = ctx->priv_data;
PutByteContext *s = &ctx->pb;
StreamInfo *stream;
unsigned char *data_offset_ptr, *start_ptr;
char title[1024], author[1024], copyright[1024], comment[1024];
const char *desc, *mimetype;
int nb_packets, packet_total_size, packet_max_size, size, packet_avg_size, i;
int bit_rate, v, duration, flags, data_pos;
start_ptr = s->buf_ptr;
put_tag(s, ".RMF");
put_long(s,18); /* header size */
put_short(s,0);
put_long(s,0);
put_long(s,4 + rm->nb_streams); /* num headers */
put_tag(s,"PROP");
put_long(s, 50);
put_short(s, 0);
packet_max_size = 0;
packet_total_size = 0;
nb_packets = 0;
bit_rate = 0;
duration = 0;
for(i=0;i<rm->nb_streams;i++) {
StreamInfo *stream = &rm->streams[i];
bit_rate += stream->bit_rate;
if (stream->packet_max_size > packet_max_size)
packet_max_size = stream->packet_max_size;
nb_packets += stream->nb_packets;
packet_total_size += stream->packet_total_size;
/* select maximum duration */
v = (int) (1000.0 * (float)stream->total_frames / stream->frame_rate);
if (v > duration)
duration = v;
}
put_long(s, bit_rate); /* max bit rate */
put_long(s, bit_rate); /* avg bit rate */
put_long(s, packet_max_size); /* max packet size */
if (nb_packets > 0)
packet_avg_size = packet_total_size / nb_packets;
else
packet_avg_size = 0;
put_long(s, packet_avg_size); /* avg packet size */
put_long(s, nb_packets); /* num packets */
put_long(s, duration); /* duration */
put_long(s, BUFFER_DURATION); /* preroll */
put_long(s, index_pos); /* index offset */
/* computation of data the data offset */
data_offset_ptr = s->buf_ptr;
put_long(s, 0); /* data offset : will be patched after */
put_short(s, rm->nb_streams); /* num streams */
flags = 1 | 2; /* save allowed & perfect play */
if (ctx->is_streamed)
flags |= 4; /* live broadcast */
put_short(s, flags);
/* comments */
find_tag("title", title, sizeof(title), comment_string);
find_tag("author", author, sizeof(author), comment_string);
find_tag("copyright", copyright, sizeof(copyright), comment_string);
find_tag("comment", comment, sizeof(comment), comment_string);
put_tag(s,"CONT");
size = strlen(title) + strlen(author) + strlen(copyright) + strlen(comment) +
4 * 2 + 10;
put_long(s,size);
put_short(s,0);
put_str(s, title);
put_str(s, author);
put_str(s, copyright);
put_str(s, comment);
for(i=0;i<rm->nb_streams;i++) {
int codec_data_size;
stream = &rm->streams[i];
if (stream->enc->codec->type == CODEC_TYPE_AUDIO) {
desc = "The Audio Stream";
mimetype = "audio/x-pn-realaudio";
codec_data_size = 73;
} else {
desc = "The Video Stream";
mimetype = "video/x-pn-realvideo";
codec_data_size = 34;
}
put_tag(s,"MDPR");
size = 10 + 9 * 4 + strlen(desc) + strlen(mimetype) + codec_data_size;
put_long(s, size);
put_short(s, 0);
put_short(s, i); /* stream number */
put_long(s, stream->bit_rate); /* max bit rate */
put_long(s, stream->bit_rate); /* avg bit rate */
put_long(s, stream->packet_max_size); /* max packet size */
if (stream->nb_packets > 0)
packet_avg_size = stream->packet_total_size /
stream->nb_packets;
else
packet_avg_size = 0;
put_long(s, packet_avg_size); /* avg packet size */
put_long(s, 0); /* start time */
put_long(s, BUFFER_DURATION); /* preroll */
/* duration */
put_long(s, (int)(stream->total_frames * 1000 / stream->frame_rate));
put_str8(s, desc);
put_str8(s, mimetype);
put_long(s, codec_data_size);
if (stream->enc->codec->type == CODEC_TYPE_AUDIO) {
int coded_frame_size, fscode, sample_rate;
sample_rate = stream->enc->rate;
coded_frame_size = (stream->enc->bit_rate *
stream->enc->frame_size) / (8 * sample_rate);
/* audio codec info */
put_tag(s, ".ra");
put_byte(s, 0xfd);
put_long(s, 0x00040000); /* version */
put_tag(s, ".ra4");
put_long(s, 0x01b53530); /* stream length */
put_short(s, 4); /* unknown */
put_long(s, 0x39); /* header size */
switch(sample_rate) {
case 48000:
case 24000:
case 12000:
fscode = 1;
break;
default:
case 44100:
case 22050:
case 11025:
fscode = 2;
break;
case 32000:
case 16000:
case 8000:
fscode = 3;
}
put_short(s, fscode); /* codec additional info, for AC3, seems
to be a frequency code */
/* special hack to compensate rounding errors... */
if (coded_frame_size == 557)
coded_frame_size--;
put_long(s, coded_frame_size); /* frame length */
put_long(s, 0x51540); /* unknown */
put_long(s, 0x249f0); /* unknown */
put_long(s, 0x249f0); /* unknown */
put_short(s, 0x01);
/* frame length : seems to be very important */
put_short(s, coded_frame_size);
put_long(s, 0); /* unknown */
put_short(s, stream->enc->rate); /* sample rate */
put_long(s, 0x10); /* unknown */
put_short(s, stream->enc->channels);
put_str8(s, "Int0"); /* codec name */
put_str8(s, "dnet"); /* codec name */
put_short(s, 0); /* title length */
put_short(s, 0); /* author length */
put_short(s, 0); /* copyright length */
put_byte(s, 0); /* end of header */
} else {
/* video codec info */
put_long(s,34); /* size */
put_tag(s,"VIDORV10");
put_short(s, stream->enc->width);
put_short(s, stream->enc->height);
put_short(s, 24); /* frames per seconds ? */
put_long(s,0); /* unknown meaning */
put_short(s, 12); /* unknown meaning */
put_long(s,0); /* unknown meaning */
put_short(s, 8); /* unknown meaning */
/* Seems to be the codec version: only use basic H263. The next
versions seems to add a diffential DC coding as in
MPEG... nothing new under the sun */
put_long(s,0x10000000);
//put_long(s,0x10003000);
}
}
/* patch data offset field */
data_pos = s->buf_ptr - start_ptr;
rm->data_pos = data_pos;
data_offset_ptr[0] = data_pos >> 24;
data_offset_ptr[1] = data_pos >> 16;
data_offset_ptr[2] = data_pos >> 8;
data_offset_ptr[3] = data_pos;
/* data stream */
put_tag(s,"DATA");
put_long(s,data_size + 10 + 8);
put_short(s,0);
put_long(s, nb_packets); /* number of packets */
put_long(s,0); /* next data header */
}
static void write_packet_header(AVFormatContext *ctx, StreamInfo *stream,
int length, int key_frame)
{
int timestamp;
PutByteContext *s = &ctx->pb;
stream->nb_packets++;
stream->packet_total_size += length;
if (length > stream->packet_max_size)
stream->packet_max_size = length;
put_short(s,0); /* version */
put_short(s,length + 12);
put_short(s, stream->num); /* stream number */
timestamp = (1000 * (float)stream->nb_frames) / stream->frame_rate;
put_long(s, timestamp); /* timestamp */
put_byte(s, 0); /* reserved */
put_byte(s, key_frame ? 2 : 0); /* flags */
}
static int rm_write_header(AVFormatContext *s)
{
StreamInfo *stream;
RMContext *rm;
int n;
rm = malloc(sizeof(RMContext));
if (!rm)
return -1;
memset(rm, 0, sizeof(RMContext));
s->priv_data = rm;
n = 0;
if (s->audio_enc) {
stream = &rm->streams[n];
memset(stream, 0, sizeof(StreamInfo));
stream->num = n;
rm->audio_stream = stream;
stream->bit_rate = s->audio_enc->bit_rate;
stream->frame_rate = (float)s->audio_enc->rate / (float)s->audio_enc->frame_size;
stream->enc = s->audio_enc;
/* XXX: dummy values */
stream->packet_max_size = 1024;
stream->nb_packets = 1000;
stream->total_frames = stream->nb_packets;
n++;
}
if (s->video_enc) {
stream = &rm->streams[n];
memset(stream, 0, sizeof(StreamInfo));
stream->num = n;
rm->video_stream = stream;
stream->bit_rate = s->video_enc->bit_rate;
stream->frame_rate = s->video_enc->rate;
stream->enc = s->video_enc;
/* XXX: dummy values */
stream->packet_max_size = 4096;
stream->nb_packets = 1000;
stream->total_frames = stream->nb_packets;
n++;
}
rm->nb_streams = n;
rv10_write_header(s, 0, 0);
put_flush_packet(&s->pb);
return 0;
}
static int rm_write_audio(AVFormatContext *s, UINT8 *buf, int size)
{
UINT8 buf1[size];
RMContext *rm = s->priv_data;
PutByteContext *pb = &s->pb;
StreamInfo *stream = rm->audio_stream;
int i;
write_packet_header(s, stream, size, stream->enc->key_frame);
/* for AC3, the words seems to be reversed */
for(i=0;i<size;i+=2) {
buf1[i] = buf[i+1];
buf1[i+1] = buf[i];
}
put_buffer(pb, buf1, size);
put_flush_packet(pb);
stream->nb_frames++;
return 0;
}
static int rm_write_video(AVFormatContext *s, UINT8 *buf, int size)
{
RMContext *rm = s->priv_data;
PutByteContext *pb = &s->pb;
StreamInfo *stream = rm->video_stream;
int key_frame = stream->enc->key_frame;
/* XXX: this is incorrect: should be a parameter */
/* Well, I spent some time finding the meaning of these bits. I am
not sure I understood everything, but it works !! */
#if 1
write_packet_header(s, stream, size + 7, key_frame);
/* bit 7: '1' if final packet of a frame converted in several packets */
put_byte(pb, 0x81);
/* bit 7: '1' if I frame. bits 6..0 : sequence number in current
frame starting from 1 */
if (key_frame) {
put_byte(pb, 0x81);
} else {
put_byte(pb, 0x01);
}
put_short(pb, 0x4000 | (size)); /* total frame size */
put_short(pb, 0x4000 | (size)); /* offset from the start or the end */
#else
/* seems to be used for prefetch/error correction. Help me ! */
write_packet_header(s, size + 6);
put_byte(pb, 0xc0);
put_short(pb, 0x4000 | size); /* total frame size */
put_short(pb, 0x4000 + packet_number * 126);
#endif
put_byte(pb, stream->nb_frames & 0xff);
put_buffer(pb, buf, size);
put_flush_packet(pb);
stream->nb_frames++;
return 0;
}
static int rm_write_trailer(AVFormatContext *s)
{
RMContext *rm = s->priv_data;
int data_size, index_pos, i;
PutByteContext *pb = &s->pb;
if (!s->is_streamed) {
/* end of file: finish to write header */
index_pos = put_seek(pb, 0, SEEK_CUR);
data_size = index_pos - rm->data_pos;
/* index */
put_tag(pb, "INDX");
put_long(pb, 10 + 10 * rm->nb_streams);
put_short(pb, 0);
for(i=0;i<rm->nb_streams;i++) {
put_long(pb, 0); /* zero indices */
put_short(pb, i); /* stream number */
put_long(pb, 0); /* next index */
}
/* undocumented end header */
put_long(pb, 0);
put_long(pb, 0);
put_seek(pb, 0, SEEK_SET);
for(i=0;i<rm->nb_streams;i++)
rm->streams[i].total_frames = rm->streams[i].nb_frames;
rv10_write_header(s, data_size, index_pos);
} else {
/* undocumented end header */
put_long(pb, 0);
put_long(pb, 0);
}
put_flush_packet(pb);
free(rm);
return 0;
}
AVFormat rm_format = {
"rm",
"rm format",
"audio/x-pn-realaudio",
"rm,ra",
CODEC_ID_AC3,
CODEC_ID_RV10,
rm_write_header,
rm_write_audio,
rm_write_video,
rm_write_trailer,
};
AVFormat ra_format = {
"ra",
"ra format",
"audio/x-pn-realaudio",
"ra",
CODEC_ID_AC3,
CODEC_ID_NONE,
rm_write_header,
rm_write_audio,
NULL,
rm_write_trailer,
};

@ -0,0 +1,347 @@
/*
* Flash Compatible Streaming Format
* 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 "mpegenc.h"
#include <assert.h>
/* should have a generic way to indicate probable size */
#define DUMMY_FILE_SIZE (100 * 1024 * 1024)
#define DUMMY_DURATION 600 /* in seconds */
#define TAG_END 0
#define TAG_SHOWFRAME 1
#define TAG_DEFINESHAPE 2
#define TAG_FREECHARACTER 3
#define TAG_PLACEOBJECT 4
#define TAG_REMOVEOBJECT 5
#define TAG_JPEG2 21
#define TAG_LONG 0x100
/* flags for shape definition */
#define FLAG_MOVETO 0x01
#define FLAG_SETFILL0 0x02
#define FLAG_SETFILL1 0x04
/* character id used */
#define BITMAP_ID 0
#define SHAPE_ID 1
typedef struct {
long long duration_pos;
long long tag_pos;
int tag;
} SWFContext;
static void put_swf_tag(AVFormatContext *s, int tag)
{
SWFContext *swf = s->priv_data;
PutByteContext *pb = &s->pb;
swf->tag_pos = put_pos(pb);
swf->tag = tag;
/* reserve some room for the tag */
if (tag & TAG_LONG) {
put_le16(pb, 0);
put_le32(pb, 0);
} else {
put_le16(pb, 0);
}
}
static void put_swf_end_tag(AVFormatContext *s)
{
SWFContext *swf = s->priv_data;
PutByteContext *pb = &s->pb;
long long pos;
int tag_len, tag;
pos = put_pos(pb);
tag_len = pos - swf->tag_pos - 2;
tag = swf->tag;
put_seek(pb, swf->tag_pos, SEEK_SET);
if (tag & TAG_LONG) {
tag &= ~TAG_LONG;
put_le16(pb, (tag << 6) | 0x3f);
put_le32(pb, tag_len - 4);
} else {
assert(tag_len < 0x3f);
put_le16(pb, (tag << 6) | tag_len);
}
put_seek(pb, pos, SEEK_SET);
}
static inline void max_nbits(int *nbits_ptr, int val)
{
int n;
if (val == 0)
return;
val = abs(val);
n = 1;
while (val != 0) {
n++;
val >>= 1;
}
if (n > *nbits_ptr)
*nbits_ptr = n;
}
static void put_swf_rect(PutByteContext *pb,
int xmin, int xmax, int ymin, int ymax)
{
PutBitContext p;
UINT8 buf[256];
int nbits, mask;
init_put_bits(&p, buf, sizeof(buf), NULL, NULL);
nbits = 0;
max_nbits(&nbits, xmin);
max_nbits(&nbits, xmax);
max_nbits(&nbits, ymin);
max_nbits(&nbits, ymax);
mask = (1 << nbits) - 1;
/* rectangle info */
put_bits(&p, 5, nbits);
put_bits(&p, nbits, xmin & mask);
put_bits(&p, nbits, xmax & mask);
put_bits(&p, nbits, ymin & mask);
put_bits(&p, nbits, ymax & mask);
flush_put_bits(&p);
put_buffer(pb, buf, p.buf_ptr - p.buf);
}
static void put_swf_line_edge(PutBitContext *pb, int dx, int dy)
{
int nbits, mask;
put_bits(pb, 1, 1); /* edge */
put_bits(pb, 1, 1); /* line select */
nbits = 2;
max_nbits(&nbits, dx);
max_nbits(&nbits, dy);
mask = (1 << nbits) - 1;
put_bits(pb, 4, nbits - 2); /* 16 bits precision */
if (dx == 0) {
put_bits(pb, 1, 0);
put_bits(pb, 1, 1);
put_bits(pb, nbits, dy & mask);
} else if (dy == 0) {
put_bits(pb, 1, 0);
put_bits(pb, 1, 0);
put_bits(pb, nbits, dx & mask);
} else {
put_bits(pb, 1, 1);
put_bits(pb, nbits, dx & mask);
put_bits(pb, nbits, dy & mask);
}
}
#define FRAC_BITS 16
/* put matrix (not size optimized */
static void put_swf_matrix(PutByteContext *pb,
int a, int b, int c, int d, int tx, int ty)
{
PutBitContext p;
UINT8 buf[256];
init_put_bits(&p, buf, sizeof(buf), NULL, NULL);
put_bits(&p, 1, 1); /* a, d present */
put_bits(&p, 5, 20); /* nb bits */
put_bits(&p, 20, a);
put_bits(&p, 20, d);
put_bits(&p, 1, 1); /* b, c present */
put_bits(&p, 5, 20); /* nb bits */
put_bits(&p, 20, c);
put_bits(&p, 20, b);
put_bits(&p, 5, 20); /* nb bits */
put_bits(&p, 20, tx);
put_bits(&p, 20, ty);
flush_put_bits(&p);
put_buffer(pb, buf, p.buf_ptr - p.buf);
}
static int swf_write_header(AVFormatContext *s)
{
SWFContext *swf;
PutByteContext *pb = &s->pb;
AVEncodeContext *enc = s->video_enc;
PutBitContext p;
UINT8 buf1[256];
swf = malloc(sizeof(SWFContext));
if (!swf)
return -1;
s->priv_data = swf;
put_tag(pb, "FWS");
put_byte(pb, 3); /* version (should use 4 for mpeg audio support) */
put_le32(pb, DUMMY_FILE_SIZE); /* dummy size
(will be patched if not streamed) */
put_swf_rect(pb, 0, enc->width, 0, enc->height);
put_le16(pb, enc->rate << 8); /* frame rate */
swf->duration_pos = put_pos(pb);
put_le16(pb, DUMMY_DURATION * enc->rate); /* frame count */
/* define a shape with the jpeg inside */
put_swf_tag(s, TAG_DEFINESHAPE);
put_le16(pb, SHAPE_ID); /* ID of shape */
/* bounding rectangle */
put_swf_rect(pb, 0, enc->width, 0, enc->height);
/* style info */
put_byte(pb, 1); /* one fill style */
put_byte(pb, 0x41); /* clipped bitmap fill */
put_le16(pb, BITMAP_ID); /* bitmap ID */
/* position of the bitmap */
put_swf_matrix(pb, (int)(1.0 * (1 << FRAC_BITS)), 0,
0, (int)(1.0 * (1 << FRAC_BITS)), 0, 0);
put_byte(pb, 0); /* no line style */
/* shape drawing */
init_put_bits(&p, buf1, sizeof(buf1), NULL, NULL);
put_bits(&p, 4, 1); /* one fill bit */
put_bits(&p, 4, 0); /* zero line bit */
put_bits(&p, 1, 0); /* not an edge */
put_bits(&p, 5, FLAG_MOVETO | FLAG_SETFILL0);
put_bits(&p, 5, 1); /* nbits */
put_bits(&p, 1, 0); /* X */
put_bits(&p, 1, 0); /* Y */
put_bits(&p, 1, 1); /* set fill style 1 */
/* draw the rectangle ! */
put_swf_line_edge(&p, enc->width, 0);
put_swf_line_edge(&p, 0, enc->height);
put_swf_line_edge(&p, -enc->width, 0);
put_swf_line_edge(&p, 0, -enc->height);
/* end of shape */
put_bits(&p, 1, 0); /* not an edge */
put_bits(&p, 5, 0);
flush_put_bits(&p);
put_buffer(pb, buf1, p.buf_ptr - p.buf);
put_swf_end_tag(s);
put_flush_packet(&s->pb);
return 0;
}
static int swf_write_video(AVFormatContext *s, UINT8 *buf, int size)
{
PutByteContext *pb = &s->pb;
AVEncodeContext *enc = s->video_enc;
static int tag_id = 0;
if (enc->frame_number > 1) {
/* remove the shape */
put_swf_tag(s, TAG_REMOVEOBJECT);
put_le16(pb, SHAPE_ID); /* shape ID */
put_le16(pb, 1); /* depth */
put_swf_end_tag(s);
/* free the bitmap */
put_swf_tag(s, TAG_FREECHARACTER);
put_le16(pb, BITMAP_ID);
put_swf_end_tag(s);
}
put_swf_tag(s, TAG_JPEG2 | TAG_LONG);
put_le16(pb, tag_id); /* ID of the image */
/* a dummy jpeg header seems to be required */
put_byte(pb, 0xff);
put_byte(pb, 0xd8);
put_byte(pb, 0xff);
put_byte(pb, 0xd9);
/* write the jpeg image */
put_buffer(pb, buf, size);
put_swf_end_tag(s);
/* draw the shape */
put_swf_tag(s, TAG_PLACEOBJECT);
put_le16(pb, SHAPE_ID); /* shape ID */
put_le16(pb, 1); /* depth */
put_swf_matrix(pb, 1 << FRAC_BITS, 0, 0, 1 << FRAC_BITS, 0, 0);
put_swf_end_tag(s);
/* output the frame */
put_swf_tag(s, TAG_SHOWFRAME);
put_swf_end_tag(s);
put_flush_packet(&s->pb);
return 0;
}
static int swf_write_trailer(AVFormatContext *s)
{
SWFContext *swf = s->priv_data;
PutByteContext *pb = &s->pb;
int file_size;
AVEncodeContext *enc = s->video_enc;
put_swf_tag(s, TAG_END);
put_swf_end_tag(s);
put_flush_packet(&s->pb);
/* patch file size and number of frames if not streamed */
if (!s->is_streamed) {
file_size = put_pos(pb);
put_seek(pb, 4, SEEK_SET);
put_le32(pb, file_size);
put_seek(pb, swf->duration_pos, SEEK_SET);
put_le16(pb, enc->frame_number);
}
free(swf);
return 0;
}
AVFormat swf_format = {
"swf",
"Flash format",
"application/x-shockwave-flash",
"swf",
CODEC_ID_NONE,
CODEC_ID_MJPEG,
swf_write_header,
NULL,
swf_write_video,
swf_write_trailer,
};

123
udp.c

@ -0,0 +1,123 @@
/*
* 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 <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "mpegenc.h"
#define UDP_TX_BUF_SIZE 32768
/* put it in UDP context */
static struct sockaddr_in dest_addr;
/* return non zero if error */
int udp_tx_open(UDPContext *s,
const char *uri,
int local_port)
{
struct sockaddr_in my_addr;
const char *p, *q;
char hostname[1024];
int port, udp_socket, tmp;
struct hostent *hp;
/* 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->udp_socket = udp_socket;
s->max_payload_size = 1024;
return 0;
fail:
return -1;
}
void udp_tx_close(UDPContext *s)
{
close(s->udp_socket);
}
extern int data_out_size;
void udp_write_data(void *opaque, UINT8 *buf, int size)
{
UDPContext *s = opaque;
int ret, len;
/* primitive way to avoid big packets */
data_out_size += size;
while (size > 0) {
len = size;
if (len > s->max_payload_size)
len = s->max_payload_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;
}
}
Loading…
Cancel
Save