1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-12-23 12:43:46 +02:00

Initial revision

Originally committed as revision 5 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
Fabrice Bellard 2001-07-22 14:18:56 +00:00
parent 1b58d58dda
commit de6d9b6404
80 changed files with 31513 additions and 0 deletions

139
Changelog Normal file
View File

@ -0,0 +1,139 @@
version 0.4.5:
- some header fixes (Zdenek Kabelac <kabi@informatics.muni.cz>).
- many MMX optimizations (Nick Kurshev <nickols_k@mail.ru>).
- added configure system (actually a small shell script).
- added mpeg audio layer 1/2/3 decoding using LGPL'ed mpglib by
Michael Hipp (temporary solution - waiting for integer only
decoder).
- fixed VIDIOCSYNC interrupt.
- added Intel H263 decoding support ('I263' avi fourCC)
- added Real Video 1.0 decoding (needs further testing).
- simplified image formats again. Added PGM format (=grey
pgm). Renamed old PGM to PGMYUV.
- fixed msmpeg4 slice issues (tell me if you still find problems).
- fixed opendivx bugs with newer versions (added VOL header decoding).
- added support for mplayer interface.
version 0.4.4:
- fixed some std header definitions (Bjorn Lindgren
<bjorn.e.lindgren@telia.com>).
- added mpeg demux (mpeg 1 and 2 compatible).
- added ASF demux.
- added prototype RM demux.
- added AC3 decoding (done with libac3 by Aaron Holtzman).
- added decoding codec parameter guessing (.e.g. for mpeg, because the
header does not include them).
- fixed header generation in mpeg1, AVI and ASF mux : wmplayer can now
play them (only tested video).
- fixed h263 white bug.
- fixed phase rounding in img resample filter.
- add mmx code for polyphase img resample filter.
- added CPU autodetect.
- added generic title/author/copyright/comment string handling (ASF and RM use them).
- added SWF demux to extract MP3 track (not usable yet because no MP3
decoder).
- added fractional frame rate support.
- codecs are no longer searched by read_header() (should fix ffserver
segfault).
version 0.4.3:
- BGR24 patch (initial patch by Jeroen Vreeken <pe1rxq@amsat.org>).
- fixed raw yuv output.
- added motion rounding support in MPEG4.
- fixed motion bug rounding in MSMPEG4.
- added B frame handling in video core.
- added full MPEG1 decoding support.
- added partial (frame only) MPEG2 support.
- changed the FOURCC code for H.263 to "U263" to be able to see the
+AVI/H.263 file with the UB Video H.263+ decoder. MPlayer works with
this +codec ;) (JuanJo).
- Halfpel motion estimation after mb type selection (JuanJo).
- added pgm and .Y.U.V output format.
- suppressed 'img:' protocol. Simply use: /tmp/test%d.[pgm|Y] as input or
output.
- added pgmpipe I/O format (original patch from Martin Aumueller
<lists@reserv.at>, but changed completely since we use a format
instead of a protocol).
version 0.4.2:
- added H263/MPEG4/MSMPEG4 decoding support. MPEG4 decoding support
(for openDIVX) is almost complete: 8x8 MVs and rounding are
missing. MSMPEG4 support is complete.
- added prototype MPEG1 decoder. Only I and P frames handled yet (it
can decode ffmpeg mpegs :-)).
- added libavcodec API documentation (see apiexample.c).
- fixed image polyphase bug (the bottom of some images could be
greenish).
- added support for non clipped motion vectors (decoding only)
and image sizes non multiple of 16.
- added support for AC prediction (decoding only).
- added file overwrite confirmation (can be disabled with -y).
- Added custom size picture to H.263 using H.263+ (Juanjo).
version 0.4.1:
- added MSMPEG4 (aka DIVX) compatible encoder. Changed default codec
of avi and asf to DIV3.
- added -me option to set motion estimation method
(default=log). suppressed redundant -hq option.
- added options -acodec and -vcodec to force a given codec (useful for
AVI for example).
- fixed -an option.
- improved dct_quantize speed.
- factorized some motion estimation code.
version 0.4.0:
- removing grab code from ffserver and moved it to ffmpeg. Added multi
stream support to ffmpeg.
- added timeshifting support for live feeds (option ?date=xxx in the
URL).
- added high quality image resize code with polyphase filter (need
mmx/see optimisation). Enable multiple image size support in ffserver.
- added multi live feed support in ffserver.
- suppressed master feature from ffserver (it should be done with an
external program which opens the .ffm url and writes it to another
ffserver).
- added preliminary support for video stream parsing (wav and avi half
done). Added proper support for audio/video file convertion in
ffmpeg.
- added preliminary support for video file sending from ffserver.
- redesigning I/O subsystem : now using URL based input and output
(see avio.h).
- added wav format support.
- added "tty user interface" to ffmpeg to stop grabbing gracefully.
- added MMX/SSE optimizations to SAD (Sums of Absolutes Diferences)
(Juan J. Sierralta P. a.k.a. "Juanjo" <juanjo@atmlab.utfsm.cl>).
- added MMX DCT from mpeg2_movie 1.5 (Juanjo).
- added new motion estimation algorithms, log and phods (Juanjo).
- changed directories : libav for format handling, libavcodec for
codecs.
version 0.3.4:
- added stereo in mpeg audio encoder.
version 0.3.3:
- added 'high quality' mode which use motion vectors. It can be used in
real time at low resolution.
- fixed rounding problems which caused quality problems at high
bitrates and large gop size.
version 0.3.2: small fixes
- asf fixes
- put_seek bug fix
version 0.3.1: added avi/divx support
- added avi support
- added mpeg4 codec compatible with open divx. It is based on the h263
codec.
- added sound for flash format (not tested)
version 0.3: initial public release

8
INSTALL Normal file
View File

@ -0,0 +1,8 @@
1) Type './configure' create the configuration (use './configure
--help' to have the configure options).
2) Then type 'make' to build ffmpeg.
3) Type 'make install' to install ffmpeg and ffserver in
/usr/local/bin.

75
configure vendored Executable file
View File

@ -0,0 +1,75 @@
#!/bin/sh
# default parameters
prefix="/usr/local"
cc="gcc"
ar="ar"
cpu=`uname -m`
case "$cpu" in
i386|i486|i586|i686)
cpu="x86"
mmx="yes"
;;
*)
mmx="no"
;;
esac
gprof="no"
if [ "$1" = "-h" -o "$1" = "--help" ] ; then
cat << EOF
Usage: configure [options]
Options: [defaults in brackets after descriptions]
--help print this message
EOF
echo " --prefix=PREFIX install in PREFIX [$prefix]"
echo " --cc=CC use C compiler CC [$cc]"
echo " --cpu=CPU force cpu to CPU [$cpu]"
echo " --disable-mmx disable mmx usage"
echo " --enable-gprof enable profiling with gprof [$gprof]"
exit 1
fi
for opt do
case "$opt" in
--prefix=*) prefix=`echo $opt | cut -d '=' -f 2`
;;
--cc=*) cc=`echo $opt | cut -d '=' -f 2`
;;
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
;;
--disable-mmx) mmx="no"
;;
--enable-gprof) gprof="yes"
;;
esac
done
echo "Install prefix $prefix"
echo "C compiler $cc"
echo "CPU $cpu"
echo "MMX enabled $mmx"
echo "gprof enabled $gprof"
echo "Creating config.mk and config.h"
echo "# Automatically generated by configure - do not modify" > config.mk
echo "/* Automatically generated by configure - do not modify */" > config.h
echo "PREFIX=$prefix" >> config.mk
echo "CC=$cc" >> config.mk
echo "AR=$ar" >> config.mk
if [ "$cpu" = "x86" ] ; then
echo "CONFIG_CPU_X86=y" >> config.mk
echo "#define CONFIG_CPU_X86 1" >> config.h
fi
if [ "$mmx" = "yes" ] ; then
echo "CONFIG_MMX=y" >> config.mk
echo "#define CONFIG_MMX 1" >> config.h
fi
if [ "$gprof" = "yes" ] ; then
echo "CONFIG_GPROF=y" >> config.mk
echo "#define CONFIG_GPROF 1" >> config.h
fi

20
doc/README.dev Normal file
View File

@ -0,0 +1,20 @@
1) API
------
* libavcodec is the library containing the codecs (both encoding and
decoding). See libavcodec/apiexample.c to see how to use it.
* libav is the library containing the file formats handling (mux and
demux code for several formats). (no example yet, the API is likely
to evolve).
2) Coding Rules
---------------
ffmpeg is programmed in ANSI C language. GCC extension are
tolerated. TAB size is 4. The identation is the one specified by
'indent -i4 -kr'.
Main priority in ffmpeg is simplicity and small code size (=less
bugs).

52
doc/bench.txt Normal file
View File

@ -0,0 +1,52 @@
source: MarsAttack, divx, 800 kbit/s
q=10 constant:
* full motion search, fcode=1, half pel:
Video: opendivx (hq), 640x352, 25 fps, 200 kb/s
frame= 500 q=10 size= 1815kB time=20.0 bitrate= 743.6kbits/s
* log motion search:
Video: opendivx (hq), 640x352, 25 fps, 200 kb/s
frame= 500 q=10 size= 1995kB time=20.0 bitrate= 817.2kbits/s
* no motion search:
Video: opendivx, 640x352, 25 fps, 200 kb/s
frame= 500 size= 3197kB time=20.0 fps=25.0 bitrate=1309.6kbits/s q=10
* log motion search:
Video: opendivx (hq), 640x352, 25 fps, 200 kb/s
frame= 500 q=10 size= 1995kB time=20.0 bitrate= 817.2kbits/s
./ffmpeg -me log -t 20 -g 100 -qscale 10 -i img:%d.pgm -an /tmp/b.avi
Stream #0.0: Video: msmpeg4, 640x352, 25 fps, 200 kb/s
frame= 500 q=10 size= 1833kB time=20.0 bitrate= 750.9kbits/s
./ffmpeg -me full -t 20 -g 100 -qscale 10 -i img:%d.pgm -an /tmp/b.avi
Stream #0.0: Video: msmpeg4, 640x352, 25 fps, 200 kb/s
frame= 500 q=10 size= 1793kB time=20.0 bitrate= 734.8kbits/s
-------------------------------------------
* with -sameq, -me log
./ffmpeg -g 100 -t 20 -sameq -i MarsAttacks_f800.avi -an /tmp/a.avi
Stream #0.0: Video: msmpeg4, 640x352, 25 fps, 200 kb/s
frame= 500 q= 5 size= 2605kB time=20.0 bitrate=1067.1kbits/s
./ffmpeg -g 100 -t 20 -sameq -i MarsAttacks_f800.avi -f mpeg1video -an /tmp/a.mpg
Stream #0.0: Video: mpeg1video, 640x352, 25 fps, 200 kb/s
frame= 500 q= 5 size= 2655kB time=20.0 bitrate=1087.7kbits/s
./ffmpeg -g 100 -t 20 -sameq -i MarsAttacks_f800.avi -vcodec opendivx -an /tmp/a.avi
frame= 500 q= 5 size= 2774kB time=20.0 bitrate=1136.2kbits/s
the matrix, complete, video only:
source=14147kB
ffmpeg:
mpeg1 17154kB (20%)
msmpeg4 17229kB

79
doc/ffserver.txt Normal file
View File

@ -0,0 +1,79 @@
*************** FFserver live broadcast server *****************
0) Introduction
ffserver is a streaming server for both audio and video. It supports
several live feeds, streaming from files and time shifting on live
feeds (you can seek to positions in the past on each live feed,
provided you specify a big enough feed storage in ffserver.conf).
1) Quick help
- First you must ensure that your grab system is OK. Verify with
'xawtv' that your TV card is tuned on a correct video source.
- Try with ffmpeg that you can record correctly. For example:
ffmpeg /tmp/a.mpg
will record a ten seconds mpeg file from your TV card and audio
card. Use for example the mpegtv player or MPlayer to view the created
MPEG file.
- Launch ffserver on your PC with the sample config file:
ffserver -f doc/ffserver.conf
- Verify with your browser that ffserver is working correctly. For
that purpose, explore: http://localhost:8090/stat.html .
- Now launch ffmpeg to do real time encoding :
ffmpeg http://localhost:8090/feed1.ffm
- Then, use your favorite players to see each generated stream:
mtvp http://localhost:8090/test1.mpg
mpg123 http://localhost:8090/test.mp2
netscape http://localhost:8090/test.swf
realplayer http://localhost:8090/test.rm
etc...
Note that ffserver generate multiple streams in multiple formats AT
THE SAME TIME. It should be able to handle hundreds of users at the
same time if you internet connection is fast enough.
- Now you can configure ffserver for your real needs. Edit the
ffserver.conf file to use only the formats you want. Read the ffmpeg
documentation (ffmpeg.txt) to learn more about the codec and format
stuff.
- Report any bug you find (and the fix if you have it!).
2) URL Format
ffserver supports that you seek in some formats. The syntax is to
add a '?' option to the URL. Only the 'date' option is supported.
The date format is [YYYY-MM-DDT][[HH:]MM:]SS[.m...] (clost to ISO
date format). For live streams, the date is absolute and give in
GMT. If the day is not specified, the current day is used.
example:
mpg123 http://localhost:8090/test.mp2?date=10:00
play the stream starting at 10:00 AM GMT today.
mpg123 http://localhost:8090/test.mp2?date=2001-06-23T23:00
is also a valid date.
For file streams, the date is relative to the start of the file. No
day can be specified.

956
libav/asf.c Normal file
View File

@ -0,0 +1,956 @@
/*
* ASF compatible encoder and decoder.
* Copyright (c) 2000, 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "avformat.h"
#include "avi.h"
#define PACKET_SIZE 3200
#define PACKET_HEADER_SIZE 12
#define FRAME_HEADER_SIZE 17
typedef struct {
int num;
int seq;
/* use for reading */
AVPacket pkt;
int frag_offset;
} ASFStream;
typedef struct {
int seqno;
int packet_size;
ASFStream streams[2];
/* non streamed additonnal info */
int data_offset;
INT64 nb_packets;
INT64 duration; /* in 100ns units */
/* packet filling */
int packet_size_left;
int packet_timestamp_start;
int packet_timestamp_end;
int packet_nb_frames;
UINT8 packet_buf[PACKET_SIZE];
ByteIOContext pb;
/* only for reading */
int packet_padsize;
} 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 = {
0x75b22633, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c },
};
static const GUID codec_comment_header = {
0x86D15240, 0x311D, 0x11D0, { 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 },
};
static const GUID codec_comment1_header = {
0x86d15241, 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 index_guid = {
0x33000890, 0xe5b1, 0x11cf, { 0x89, 0xf4, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb },
};
static const GUID head1_guid = {
0x5fbf03b5, 0xa92e, 0x11cf, { 0x8e, 0xe3, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 },
};
static const GUID head2_guid = {
0xabd3d211, 0xa9ba, 0x11cf, { 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 },
};
/* I am not a number !!! This GUID is the one found on the PC used to
generate the stream */
static const GUID my_guid = {
0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 },
};
static void put_guid(ByteIOContext *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]);
}
static void put_str16(ByteIOContext *s, const char *tag)
{
int c;
put_le16(s,strlen(tag) + 1);
for(;;) {
c = (UINT8)*tag++;
put_le16(s, c);
if (c == '\0')
break;
}
}
static void put_str16_nolen(ByteIOContext *s, const char *tag)
{
int c;
for(;;) {
c = (UINT8)*tag++;
put_le16(s, c);
if (c == '\0')
break;
}
}
static INT64 put_header(ByteIOContext *pb, const GUID *g)
{
INT64 pos;
pos = url_ftell(pb);
put_guid(pb, g);
put_le64(pb, 24);
return pos;
}
/* update header size */
static void end_header(ByteIOContext *pb, INT64 pos)
{
INT64 pos1;
pos1 = url_ftell(pb);
url_fseek(pb, pos + 16, SEEK_SET);
put_le64(pb, pos1 - pos);
url_fseek(pb, pos1, SEEK_SET);
}
/* 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;
ByteIOContext *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++;
}
/* convert from unix to windows time */
static INT64 unix_to_file_time(int ti)
{
INT64 t;
t = ti * 10000000LL;
t += 116444736000000000LL;
return t;
}
/* write the header (used two times if non streamed) */
static int asf_write_header1(AVFormatContext *s, INT64 file_size, INT64 data_chunk_size)
{
ASFContext *asf = s->priv_data;
ByteIOContext *pb = &s->pb;
int header_size, n, extra_size, extra_size2, wav_extra_size, file_time;
int has_title;
AVCodecContext *enc;
INT64 header_offset, cur_pos, hpos;
has_title = (s->title[0] != '\0');
if (!url_is_streamed(&s->pb)) {
put_guid(pb, &asf_header);
put_le64(pb, 0); /* header length, will be patched after */
put_le32(pb, 3 + has_title + s->nb_streams); /* number of chunks in header */
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 = url_ftell(pb);
hpos = put_header(pb, &file_header);
put_guid(pb, &my_guid);
put_le64(pb, file_size);
file_time = 0;
put_le64(pb, unix_to_file_time(file_time));
put_le64(pb, asf->nb_packets); /* number of packets */
put_le64(pb, asf->duration); /* end time stamp (in 100ns units) */
put_le64(pb, asf->duration); /* duration (in 100ns units) */
put_le32(pb, 0); /* start time stamp */
put_le32(pb, 0); /* ??? */
put_le32(pb, 0); /* ??? */
put_le32(pb, asf->packet_size); /* packet size */
put_le32(pb, asf->packet_size); /* packet size */
put_le32(pb, 80 * asf->packet_size); /* frame_size ??? */
end_header(pb, hpos);
/* unknown headers */
hpos = put_header(pb, &head1_guid);
put_guid(pb, &head2_guid);
put_le32(pb, 6);
put_le16(pb, 0);
end_header(pb, hpos);
/* title and other infos */
if (has_title) {
hpos = put_header(pb, &comment_header);
put_le16(pb, 2 * (strlen(s->title) + 1));
put_le16(pb, 2 * (strlen(s->author) + 1));
put_le16(pb, 2 * (strlen(s->copyright) + 1));
put_le16(pb, 2 * (strlen(s->comment) + 1));
put_le16(pb, 0);
put_str16_nolen(pb, s->title);
put_str16_nolen(pb, s->author);
put_str16_nolen(pb, s->copyright);
put_str16_nolen(pb, s->comment);
end_header(pb, hpos);
}
/* stream headers */
for(n=0;n<s->nb_streams;n++) {
enc = &s->streams[n]->codec;
asf->streams[n].num = n + 1;
asf->streams[n].seq = 0;
switch(enc->codec_type) {
case CODEC_TYPE_AUDIO:
wav_extra_size = 0;
extra_size = 18 + wav_extra_size;
extra_size2 = 0;
break;
default:
case CODEC_TYPE_VIDEO:
wav_extra_size = 0;
extra_size = 0x33;
extra_size2 = 0;
break;
}
hpos = put_header(pb, &stream_header);
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_wav_header(pb, enc);
} else {
put_le32(pb, enc->width);
put_le32(pb, enc->height);
put_byte(pb, 2); /* ??? */
put_le16(pb, 40); /* size */
/* BITMAPINFOHEADER header */
put_bmp_header(pb, enc);
}
end_header(pb, hpos);
}
/* media comments */
hpos = put_header(pb, &codec_comment_header);
put_guid(pb, &codec_comment1_header);
put_le32(pb, s->nb_streams);
for(n=0;n<s->nb_streams;n++) {
enc = &s->streams[n]->codec;
put_le16(pb, asf->streams[n].num);
put_str16(pb, enc->codec_name);
put_le16(pb, 0); /* no parameters */
/* id */
if (enc->codec_type == CODEC_TYPE_AUDIO) {
put_le16(pb, 2);
put_le16(pb, codec_get_tag(codec_wav_tags, enc->codec_id));
} else {
put_le16(pb, 4);
put_le32(pb, codec_get_tag(codec_bmp_tags, enc->codec_id));
}
}
end_header(pb, hpos);
/* patch the header size fields */
cur_pos = url_ftell(pb);
header_size = cur_pos - header_offset;
if (!url_is_streamed(&s->pb)) {
header_size += 24 + 6;
url_fseek(pb, header_offset - 14, SEEK_SET);
put_le64(pb, header_size);
} else {
header_size += 8 + 50;
url_fseek(pb, header_offset - 10, SEEK_SET);
put_le16(pb, header_size);
url_fseek(pb, header_offset - 2, SEEK_SET);
put_le16(pb, header_size);
}
url_fseek(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, data_chunk_size);
put_guid(pb, &my_guid);
put_le64(pb, asf->nb_packets); /* nb packets */
put_byte(pb, 1); /* ??? */
put_byte(pb, 1); /* ??? */
return 0;
}
static int asf_write_header(AVFormatContext *s)
{
ASFContext *asf;
asf = av_mallocz(sizeof(ASFContext));
if (!asf)
return -1;
s->priv_data = asf;
asf->packet_size = PACKET_SIZE;
asf->nb_packets = 0;
asf_write_header1(s, 0, 24);
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, 1,
NULL, 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;
ByteIOContext *pb = &s->pb;
int flags;
if (url_is_streamed(&s->pb)) {
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->nb_packets++;
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, 1,
NULL, 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;
ByteIOContext *pb = &asf->pb;
int val;
val = stream->num;
if (s->streams[val - 1]->codec.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_packet(AVFormatContext *s, int stream_index,
UINT8 *buf, int size)
{
ASFContext *asf = s->priv_data;
int timestamp;
INT64 duration;
AVCodecContext *codec;
codec = &s->streams[stream_index]->codec;
if (codec->codec_type == CODEC_TYPE_AUDIO) {
timestamp = (int)((float)codec->frame_number * codec->frame_size * 1000.0 /
codec->sample_rate);
duration = (codec->frame_number * codec->frame_size * 10000000LL) /
codec->sample_rate;
} else {
timestamp = (int)((float)codec->frame_number * 1000.0 * FRAME_RATE_BASE /
codec->frame_rate);
duration = codec->frame_number *
((10000000LL * FRAME_RATE_BASE) / codec->frame_rate);
}
if (duration > asf->duration)
asf->duration = duration;
put_frame(s, &asf->streams[stream_index], (int)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 (url_is_streamed(&s->pb)) {
put_chunk(s, 0x4524, 0); /* end of stream */
} else {
/* rewrite an updated header */
file_size = url_ftell(&s->pb);
url_fseek(&s->pb, 0, SEEK_SET);
asf_write_header1(s, file_size, file_size - asf->data_offset);
}
put_flush_packet(&s->pb);
free(asf);
return 0;
}
/**********************************/
/* decoding */
//#define DEBUG
#ifdef DEBUG
static void print_guid(const GUID *g)
{
int i;
printf("0x%08x, 0x%04x, 0x%04x, {", g->v1, g->v2, g->v3);
for(i=0;i<8;i++)
printf(" 0x%02x,", g->v4[i]);
printf("}\n");
}
#endif
static void get_guid(ByteIOContext *s, GUID *g)
{
int i;
g->v1 = get_le32(s);
g->v2 = get_le16(s);
g->v3 = get_le16(s);
for(i=0;i<8;i++)
g->v4[i] = get_byte(s);
}
#if 0
static void get_str16(ByteIOContext *pb, char *buf, int buf_size)
{
int len, c;
char *q;
len = get_le16(pb);
q = buf;
while (len > 0) {
c = get_le16(pb);
if ((q - buf) < buf_size - 1)
*q++ = c;
len--;
}
*q = '\0';
}
#endif
static void get_str16_nolen(ByteIOContext *pb, int len, char *buf, int buf_size)
{
int c;
char *q;
q = buf;
while (len > 0) {
c = get_le16(pb);
if ((q - buf) < buf_size - 1)
*q++ = c;
len-=2;
}
*q = '\0';
}
static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
ASFContext *asf;
GUID g;
ByteIOContext *pb = &s->pb;
AVStream *st;
ASFStream *asf_st;
int size, i;
INT64 gsize;
asf = av_mallocz(sizeof(ASFContext));
if (!asf)
return -1;
s->priv_data = asf;
get_guid(pb, &g);
if (memcmp(&g, &asf_header, sizeof(GUID)))
goto fail;
get_le64(pb);
get_le32(pb);
get_byte(pb);
get_byte(pb);
for(;;) {
get_guid(pb, &g);
gsize = get_le64(pb);
#ifdef DEBUG
printf("%08Lx: ", url_ftell(pb) - 24);
print_guid(&g);
printf(" size=0x%Lx\n", gsize);
#endif
if (gsize < 24)
goto fail;
if (!memcmp(&g, &file_header, sizeof(GUID))) {
get_guid(pb, &g);
get_le64(pb); /* file size */
get_le64(pb); /* file time */
get_le64(pb); /* nb_packets */
get_le64(pb); /* length 0 in us */
get_le64(pb); /* length 1 in us */
get_le32(pb);
get_le32(pb);
get_le32(pb);
asf->packet_size = get_le32(pb);
get_le32(pb);
get_le32(pb);
} else if (!memcmp(&g, &stream_header, sizeof(GUID))) {
int type, id, total_size;
unsigned int tag1;
INT64 pos1, pos2;
pos1 = url_ftell(pb);
st = av_mallocz(sizeof(AVStream));
if (!st)
goto fail;
s->streams[s->nb_streams++] = st;
asf_st = av_mallocz(sizeof(ASFStream));
if (!asf_st)
goto fail;
st->priv_data = asf_st;
get_guid(pb, &g);
if (!memcmp(&g, &audio_stream, sizeof(GUID))) {
type = CODEC_TYPE_AUDIO;
} else if (!memcmp(&g, &video_stream, sizeof(GUID))) {
type = CODEC_TYPE_VIDEO;
} else {
goto fail;
}
get_guid(pb, &g);
total_size = get_le64(pb);
get_le32(pb);
get_le32(pb);
st->id = get_le16(pb); /* stream id */
get_le32(pb);
st->codec.codec_type = type;
if (type == CODEC_TYPE_AUDIO) {
id = get_le16(pb);
st->codec.codec_tag = id;
st->codec.codec_id = codec_get_id(codec_wav_tags, id);
st->codec.channels = get_le16(pb);
st->codec.sample_rate = get_le32(pb);
st->codec.bit_rate = get_le32(pb) * 8;
get_le16(pb); /* block align */
get_le16(pb); /* bits per sample */
size = get_le16(pb);
url_fskip(pb, size);
} else {
get_le32(pb);
get_le32(pb);
get_byte(pb);
size = get_le16(pb); /* size */
get_le32(pb); /* size */
st->codec.width = get_le32(pb);
st->codec.height = get_le32(pb);
st->codec.frame_rate = 25 * FRAME_RATE_BASE; /* XXX: find it */
get_le16(pb); /* panes */
get_le16(pb); /* depth */
tag1 = get_le32(pb);
st->codec.codec_tag = tag1;
st->codec.codec_id = codec_get_id(codec_bmp_tags, tag1);
url_fskip(pb, size - 5 * 4);
}
pos2 = url_ftell(pb);
url_fskip(pb, gsize - (pos2 - pos1 + 24));
} else if (!memcmp(&g, &data_header, sizeof(GUID))) {
break;
} else if (!memcmp(&g, &comment_header, sizeof(GUID))) {
int len1, len2, len3, len4, len5;
len1 = get_le16(pb);
len2 = get_le16(pb);
len3 = get_le16(pb);
len4 = get_le16(pb);
len5 = get_le16(pb);
get_str16_nolen(pb, len1, s->title, sizeof(s->title));
get_str16_nolen(pb, len2, s->author, sizeof(s->author));
get_str16_nolen(pb, len3, s->copyright, sizeof(s->copyright));
get_str16_nolen(pb, len4, s->comment, sizeof(s->comment));
url_fskip(pb, len5);
#if 0
} else if (!memcmp(&g, &head1_guid, sizeof(GUID))) {
int v1, v2;
get_guid(pb, &g);
v1 = get_le32(pb);
v2 = get_le16(pb);
} else if (!memcmp(&g, &codec_comment_header, sizeof(GUID))) {
int len, v1, n, num;
char str[256], *q;
char tag[16];
get_guid(pb, &g);
print_guid(&g);
n = get_le32(pb);
for(i=0;i<n;i++) {
num = get_le16(pb); /* stream number */
get_str16(pb, str, sizeof(str));
get_str16(pb, str, sizeof(str));
len = get_le16(pb);
q = tag;
while (len > 0) {
v1 = get_byte(pb);
if ((q - tag) < sizeof(tag) - 1)
*q++ = v1;
len--;
}
*q = '\0';
}
#endif
} else if (url_feof(pb)) {
goto fail;
} else {
url_fseek(pb, gsize - 24, SEEK_CUR);
}
}
get_guid(pb, &g);
get_le64(pb);
get_byte(pb);
get_byte(pb);
asf->packet_size_left = 0;
return 0;
fail:
for(i=0;i<s->nb_streams;i++) {
AVStream *st = s->streams[i];
if (st)
free(st->priv_data);
free(st);
}
free(asf);
return -1;
}
static int asf_get_packet(AVFormatContext *s)
{
ASFContext *asf = s->priv_data;
ByteIOContext *pb = &s->pb;
int c, flags, timestamp, hdr_size;
hdr_size = 12;
c = get_byte(pb);
if (c != 0x82)
return -EIO;
get_le16(pb);
flags = get_byte(pb);
get_byte(pb);
asf->packet_padsize = 0;
if (flags & 0x10) {
asf->packet_padsize = get_le16(pb);
hdr_size += 2;
} else if (flags & 0x08) {
asf->packet_padsize = get_byte(pb);
hdr_size++;
}
timestamp = get_le32(pb);
get_le16(pb); /* duration */
get_byte(pb); /* nb_frames */
#ifdef DEBUG
printf("packet: size=%d padsize=%d\n", asf->packet_size, asf->packet_padsize);
#endif
asf->packet_size_left = asf->packet_size - hdr_size;
return 0;
}
static int asf_read_packet(AVFormatContext *s, AVPacket *pkt)
{
ASFContext *asf = s->priv_data;
AVStream *st;
ASFStream *asf_st;
ByteIOContext *pb = &s->pb;
int ret, num, seq, frag_offset, payload_size, frag_len;
int timestamp, i;
for(;;) {
if (asf->packet_size_left < FRAME_HEADER_SIZE ||
asf->packet_size_left <= asf->packet_padsize) {
/* fail safe */
if (asf->packet_size_left)
url_fskip(pb, asf->packet_size_left);
ret = asf_get_packet(s);
if (ret < 0)
return -EIO;
}
/* read frame header */
num = get_byte(pb) & 0x7f;
seq = get_byte(pb);
frag_offset = get_le32(pb);
get_byte(pb); /* flags */
payload_size = get_le32(pb);
timestamp = get_le32(pb);
frag_len = get_le16(pb);
#ifdef DEBUG
printf("num=%d seq=%d totsize=%d frag_off=%d frag_size=%d\n",
num, seq, payload_size, frag_offset, frag_len);
#endif
st = NULL;
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
if (st->id == num)
break;
}
asf->packet_size_left -= FRAME_HEADER_SIZE + frag_len;
if (i == s->nb_streams) {
/* unhandled packet (should not happen) */
url_fskip(pb, frag_len);
} else {
asf_st = st->priv_data;
if (asf_st->frag_offset == 0) {
/* new packet */
av_new_packet(&asf_st->pkt, payload_size);
asf_st->seq = seq;
} else {
if (seq == asf_st->seq &&
frag_offset == asf_st->frag_offset) {
/* continuing packet */
} else {
/* cannot continue current packet: free it */
av_free_packet(&asf_st->pkt);
asf_st->frag_offset = 0;
if (frag_offset != 0) {
/* cannot create new packet */
url_fskip(pb, frag_len);
goto next_frame;
} else {
/* create new packet */
av_new_packet(&asf_st->pkt, payload_size);
asf_st->seq = seq;
}
}
}
/* read data */
get_buffer(pb, asf_st->pkt.data + frag_offset, frag_len);
asf_st->frag_offset += frag_len;
/* test if whole packet read */
if (asf_st->frag_offset == asf_st->pkt.size) {
/* return packet */
asf_st->pkt.stream_index = i;
asf_st->frag_offset = 0;
memcpy(pkt, &asf_st->pkt, sizeof(AVPacket));
break;
}
}
next_frame:
}
return 0;
}
static int asf_read_close(AVFormatContext *s)
{
ASFContext *asf = s->priv_data;
int i;
for(i=0;i<s->nb_streams;i++) {
AVStream *st = s->streams[i];
free(st->priv_data);
}
free(asf);
return 0;
}
AVFormat asf_format = {
"asf",
"asf format",
"application/octet-stream",
"asf",
CODEC_ID_MP2,
CODEC_ID_MSMPEG4,
asf_write_header,
asf_write_packet,
asf_write_trailer,
asf_read_header,
asf_read_packet,
asf_read_close,
};

179
libav/audio.c Normal file
View File

@ -0,0 +1,179 @@
/*
* Linux audio play and grab interface
* Copyright (c) 2000, 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <linux/soundcard.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <errno.h>
#include <sys/time.h>
#include "avformat.h"
const char *audio_device = "/dev/dsp";
typedef struct {
int fd;
int rate;
int channels;
} AudioData;
#define AUDIO_BLOCK_SIZE 4096
/* audio read support */
static int audio_read(URLContext *h, UINT8 *buf, int size)
{
AudioData *s = h->priv_data;
int ret;
ret = read(s->fd, buf, size);
if (ret < 0)
return -errno;
else
return ret;
}
static int audio_write(URLContext *h, UINT8 *buf, int size)
{
AudioData *s = h->priv_data;
int ret;
ret = write(s->fd, buf, size);
if (ret < 0)
return -errno;
else
return ret;
}
static int audio_get_format(URLContext *h, URLFormat *f)
{
AudioData *s = h->priv_data;
strcpy(f->format_name, "pcm");
f->sample_rate = s->rate;
f->channels = s->channels;
return 0;
}
/* URI syntax: 'audio:[rate[,channels]]'
default: rate=44100, channels=2
*/
static int audio_open(URLContext *h, const char *uri, int flags)
{
AudioData *s;
const char *p;
int freq, channels, audio_fd;
int tmp, err;
h->is_streamed = 1;
h->packet_size = AUDIO_BLOCK_SIZE;
s = malloc(sizeof(AudioData));
if (!s)
return -ENOMEM;
h->priv_data = s;
/* extract parameters */
p = uri;
strstart(p, "audio:", &p);
freq = strtol(p, (char **)&p, 0);
if (freq <= 0)
freq = 44100;
if (*p == ',')
p++;
channels = strtol(p, (char **)&p, 0);
if (channels <= 0)
channels = 2;
s->rate = freq;
s->channels = channels;
/* open linux audio device */
if (flags & URL_WRONLY)
audio_fd = open(audio_device,O_WRONLY);
else
audio_fd = open(audio_device,O_RDONLY);
if (audio_fd < 0) {
perror(audio_device);
return -EIO;
}
/* non blocking mode */
fcntl(audio_fd, F_SETFL, O_NONBLOCK);
#if 0
tmp=(NB_FRAGMENTS << 16) | FRAGMENT_BITS;
err=ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &tmp);
if (err < 0) {
perror("SNDCTL_DSP_SETFRAGMENT");
}
#endif
tmp=AFMT_S16_LE;
err=ioctl(audio_fd,SNDCTL_DSP_SETFMT,&tmp);
if (err < 0) {
perror("SNDCTL_DSP_SETFMT");
goto fail;
}
tmp= (channels == 2);
err=ioctl(audio_fd,SNDCTL_DSP_STEREO,&tmp);
if (err < 0) {
perror("SNDCTL_DSP_STEREO");
goto fail;
}
tmp = freq;
err=ioctl(audio_fd, SNDCTL_DSP_SPEED, &tmp);
if (err < 0) {
perror("SNDCTL_DSP_SPEED");
goto fail;
}
s->rate = tmp;
s->fd = audio_fd;
return 0;
fail:
close(audio_fd);
free(s);
return -EIO;
}
static int audio_close(URLContext *h)
{
AudioData *s = h->priv_data;
close(s->fd);
free(s);
return 0;
}
URLProtocol audio_protocol = {
"audio",
audio_open,
audio_read,
audio_write,
NULL, /* seek */
audio_close,
audio_get_format,
};

192
libav/avformat.h Normal file
View File

@ -0,0 +1,192 @@
#include "avcodec.h"
#define FFMPEG_VERSION "0.4.5"
#include "avio.h"
/* packet functions */
typedef struct AVPacket {
INT64 pts;
UINT8 *data;
int size;
int stream_index;
int flags;
#define PKT_FLAG_KEY 0x0001
} AVPacket;
int av_new_packet(AVPacket *pkt, int size);
void av_free_packet(AVPacket *pkt);
/*************************************************/
/* output formats */
struct AVFormatContext;
struct AVFormatInputContext;
typedef struct AVFormatParameters {
int frame_rate;
int sample_rate;
int channels;
int width;
int height;
int pix_fmt;
} AVFormatParameters;
typedef struct AVFormat {
const char *name;
const char *long_name;
const char *mime_type;
const char *extensions; /* comma separated extensions */
/* output support */
enum CodecID audio_codec; /* default audio codec */
enum CodecID video_codec; /* default video codec */
int (*write_header)(struct AVFormatContext *);
int (*write_packet)(struct AVFormatContext *,
int stream_index,
unsigned char *buf, int size);
int (*write_trailer)(struct AVFormatContext *);
/* optional input support */
/* read the format header and initialize the AVFormatInputContext
structure. Return 0 if OK. 'ap' if non NULL contains
additionnal paramters. Only used in raw format right now */
int (*read_header)(struct AVFormatContext *,
AVFormatParameters *ap);
/* read one packet and put it in 'pkt'. pts and flags are also set */
int (*read_packet)(struct AVFormatContext *, AVPacket *pkt);
/* close the stream. The AVFormatContext and AVStreams are not
freed by this function */
int (*read_close)(struct AVFormatContext *);
/* seek at or before a given pts (given in microsecond). The pts
origin is defined by the stream */
int (*read_seek)(struct AVFormatContext *, INT64 pts);
int flags;
#define AVFMT_NOFILE 0x0001 /* no file should be opened */
struct AVFormat *next;
} AVFormat;
typedef struct AVStream {
int id; /* internal stream id */
AVCodecContext codec; /* codec context */
void *priv_data;
} AVStream;
#define MAX_STREAMS 20
/* format I/O context */
typedef struct AVFormatContext {
struct AVFormat *format;
void *priv_data;
ByteIOContext pb;
int nb_streams;
AVStream *streams[MAX_STREAMS];
char filename[1024]; /* input or output filename */
/* stream info */
char title[512];
char author[512];
char copyright[512];
char comment[512];
/* This buffer is only needed when packets were already buffered but
not decoded, for example to get the codec parameters in mpeg
streams */
struct AVPacketList *packet_buffer;
} AVFormatContext;
typedef struct AVPacketList {
AVPacket pkt;
struct AVPacketList *next;
} AVPacketList;
extern AVFormat *first_format;
/* rv10enc.c */
extern AVFormat rm_format;
/* mpegmux.c */
extern AVFormat mpeg_mux_format;
/* asfenc.c */
extern AVFormat asf_format;
/* avienc.c */
extern AVFormat avi_format;
/* jpegenc.c */
extern AVFormat mpjpeg_format;
extern AVFormat jpeg_format;
/* swfenc.c */
extern AVFormat swf_format;
/* wav.c */
extern AVFormat wav_format;
/* img.c */
extern AVFormat pgm_format;
extern AVFormat pgmyuv_format;
extern AVFormat imgyuv_format;
extern AVFormat pgmpipe_format;
/* raw.c */
extern AVFormat mp2_format;
extern AVFormat ac3_format;
extern AVFormat h263_format;
extern AVFormat mpeg1video_format;
extern AVFormat pcm_format;
extern AVFormat rawvideo_format;
/* ffm.c */
extern AVFormat ffm_format;
/* formats.c */
#define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
#define MKBETAG(a,b,c,d) (d | (c << 8) | (b << 16) | (a << 24))
void register_avformat(AVFormat *format);
AVFormat *guess_format(const char *short_name, const char *filename, const char *mime_type);
int strstart(const char *str, const char *val, const char **ptr);
void nstrcpy(char *buf, int buf_size, const char *str);
int match_ext(const char *filename, const char *extensions);
void register_all(void);
INT64 gettime(void);
typedef struct FifoBuffer {
UINT8 *buffer;
UINT8 *rptr, *wptr, *end;
} FifoBuffer;
int fifo_init(FifoBuffer *f, int size);
void fifo_free(FifoBuffer *f);
int fifo_size(FifoBuffer *f, UINT8 *rptr);
int fifo_read(FifoBuffer *f, UINT8 *buf, int buf_size, UINT8 **rptr_ptr);
void fifo_write(FifoBuffer *f, UINT8 *buf, int size, UINT8 **wptr_ptr);
AVFormatContext *av_open_input_file(const char *filename, int buf_size);
int av_read_packet(AVFormatContext *s, AVPacket *pkt);
void av_close_input_file(AVFormatContext *s);
int av_write_packet(AVFormatContext *s, AVPacket *pkt);
void dump_format(AVFormatContext *ic,
int index,
const char *url,
int is_output);
int parse_image_size(int *width_ptr, int *height_ptr, const char *str);
INT64 gettime(void);
INT64 parse_date(const char *datestr, int duration);
/* ffm specific for ffserver */
#define FFM_PACKET_SIZE 4096
offset_t ffm_read_write_index(int fd);
void ffm_write_write_index(int fd, offset_t pos);
void ffm_set_write_index(AVFormatContext *s, offset_t pos, offset_t file_size);
int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info);

29
libav/avi.h Normal file
View File

@ -0,0 +1,29 @@
#define AVIF_HASINDEX 0x00000010 // Index at end of file?
#define AVIF_MUSTUSEINDEX 0x00000020
#define AVIF_ISINTERLEAVED 0x00000100
#define AVIF_TRUSTCKTYPE 0x00000800 // Use CKType to find key frames?
#define AVIF_WASCAPTUREFILE 0x00010000
#define AVIF_COPYRIGHTED 0x00020000
offset_t start_tag(ByteIOContext *pb, char *tag);
void end_tag(ByteIOContext *pb, offset_t start);
void put_bmp_header(ByteIOContext *pb, AVCodecContext *enc);
void put_wav_header(ByteIOContext *pb, AVCodecContext *enc);
typedef struct CodecTag {
int id;
unsigned int tag;
} CodecTag;
extern CodecTag codec_bmp_tags[];
extern CodecTag codec_wav_tags[];
unsigned int codec_get_tag(CodecTag *tags, int id);
int codec_get_id(CodecTag *tags, unsigned int tag);
/* avidec.c */
int avi_read_header(AVFormatContext *s, AVFormatParameters *ap);
int avi_read_packet(AVFormatContext *s, AVPacket *pkt);
int avi_read_close(AVFormatContext *s);

257
libav/avidec.c Normal file
View File

@ -0,0 +1,257 @@
/*
* AVI decoder.
* Copyright (c) 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include "avformat.h"
#include "avi.h"
//#define DEBUG
typedef struct AVIIndex {
unsigned char tag[4];
unsigned int flags, pos, len;
struct AVIIndex *next;
} AVIIndex;
typedef struct {
INT64 movi_end;
offset_t movi_list;
AVIIndex *first, *last;
} AVIContext;
#ifdef DEBUG
void print_tag(const char *str, unsigned int tag, int size)
{
printf("%s: tag=%c%c%c%c size=0x%x\n",
str, tag & 0xff,
(tag >> 8) & 0xff,
(tag >> 16) & 0xff,
(tag >> 24) & 0xff,
size);
}
#endif
int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
AVIContext *avi;
ByteIOContext *pb = &s->pb;
UINT32 tag, tag1;
int codec_type, stream_index, size, frame_period, bit_rate;
int i;
AVStream *st;
avi = malloc(sizeof(AVIContext));
if (!avi)
return -1;
memset(avi, 0, sizeof(AVIContext));
s->priv_data = avi;
/* check RIFF header */
tag = get_le32(pb);
if (tag != MKTAG('R', 'I', 'F', 'F'))
return -1;
get_le32(pb); /* file size */
tag = get_le32(pb);
if (tag != MKTAG('A', 'V', 'I', ' '))
return -1;
/* first list tag */
stream_index = -1;
codec_type = -1;
frame_period = 0;
for(;;) {
if (url_feof(pb))
goto fail;
tag = get_le32(pb);
size = get_le32(pb);
#ifdef DEBUG
print_tag("tag", tag, size);
#endif
switch(tag) {
case MKTAG('L', 'I', 'S', 'T'):
/* ignored, except when start of video packets */
tag1 = get_le32(pb);
#ifdef DEBUG
print_tag("list", tag1, 0);
#endif
if (tag1 == MKTAG('m', 'o', 'v', 'i')) {
avi->movi_end = url_ftell(pb) + size - 4;
#ifdef DEBUG
printf("movi end=%Lx\n", avi->movi_end);
#endif
goto end_of_header;
}
break;
case MKTAG('a', 'v', 'i', 'h'):
/* avi header */
frame_period = get_le32(pb);
bit_rate = get_le32(pb) * 8;
url_fskip(pb, 4 * 4);
s->nb_streams = get_le32(pb);
for(i=0;i<s->nb_streams;i++) {
AVStream *st;
st = malloc(sizeof(AVStream));
if (!st)
goto fail;
memset(st, 0, sizeof(AVStream));
s->streams[i] = st;
}
url_fskip(pb, size - 7 * 4);
break;
case MKTAG('s', 't', 'r', 'h'):
/* stream header */
stream_index++;
tag1 = get_le32(pb);
switch(tag1) {
case MKTAG('v', 'i', 'd', 's'):
codec_type = CODEC_TYPE_VIDEO;
get_le32(pb); /* codec tag */
get_le32(pb); /* flags */
get_le16(pb); /* priority */
get_le16(pb); /* language */
get_le32(pb); /* XXX: initial frame ? */
get_le32(pb); /* scale */
get_le32(pb); /* rate */
url_fskip(pb, size - 7 * 4);
break;
case MKTAG('a', 'u', 'd', 's'):
codec_type = CODEC_TYPE_AUDIO;
/* nothing really useful */
url_fskip(pb, size - 4);
break;
default:
goto fail;
}
break;
case MKTAG('s', 't', 'r', 'f'):
/* stream header */
if (stream_index >= s->nb_streams) {
url_fskip(pb, size);
} else {
st = s->streams[stream_index];
switch(codec_type) {
case CODEC_TYPE_VIDEO:
get_le32(pb); /* size */
st->codec.width = get_le32(pb);
st->codec.height = get_le32(pb);
if (frame_period)
st->codec.frame_rate = (1000000LL * FRAME_RATE_BASE) / frame_period;
else
st->codec.frame_rate = 25 * FRAME_RATE_BASE;
get_le16(pb); /* panes */
get_le16(pb); /* depth */
tag1 = get_le32(pb);
#ifdef DEBUG
print_tag("video", tag1, 0);
#endif
st->codec.codec_type = CODEC_TYPE_VIDEO;
st->codec.codec_tag = tag1;
st->codec.codec_id = codec_get_id(codec_bmp_tags, tag1);
url_fskip(pb, size - 5 * 4);
break;
case CODEC_TYPE_AUDIO:
tag1 = get_le16(pb);
st->codec.codec_type = CODEC_TYPE_AUDIO;
st->codec.codec_tag = tag1;
st->codec.codec_id = codec_get_id(codec_wav_tags, tag1);
#ifdef DEBUG
printf("audio: 0x%x\n", tag1);
#endif
st->codec.channels = get_le16(pb);
st->codec.sample_rate = get_le32(pb);
st->codec.bit_rate = get_le32(pb) * 8;
url_fskip(pb, size - 3 * 4);
break;
default:
url_fskip(pb, size);
break;
}
}
break;
default:
/* skip tag */
size += (size & 1);
url_fskip(pb, size);
break;
}
}
end_of_header:
/* check stream number */
if (stream_index != s->nb_streams - 1) {
fail:
for(i=0;i<s->nb_streams;i++) {
if (s->streams[i])
free(s->streams[i]);
}
return -1;
}
return 0;
}
int avi_read_packet(AVFormatContext *s, AVPacket *pkt)
{
AVIContext *avi = s->priv_data;
ByteIOContext *pb = &s->pb;
int n, d1, d2, size;
find_next:
if (url_feof(pb) || url_ftell(pb) >= avi->movi_end)
return -1;
d1 = get_byte(pb);
if (d1 < '0' || d1 > '9')
goto find_next;
d2 = get_byte(pb);
if (d2 < '0' || d2 > '9')
goto find_next;
n = (d1 - '0') * 10 + (d2 - '0');
if (n < 0 || n >= s->nb_streams)
goto find_next;
d1 = get_byte(pb);
d2 = get_byte(pb);
if ((d1 != 'd' && d2 != 'c') &&
(d1 != 'w' && d2 != 'b'))
goto find_next;
size = get_le32(pb);
av_new_packet(pkt, size);
pkt->stream_index = n;
get_buffer(pb, pkt->data, pkt->size);
if (size & 1)
get_byte(pb);
return 0;
}
int avi_read_close(AVFormatContext *s)
{
AVIContext *avi = s->priv_data;
free(avi);
return 0;
}

366
libav/avienc.c Normal file
View File

@ -0,0 +1,366 @@
/*
* AVI 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 "avformat.h"
#include "avi.h"
/*
* TODO:
* - fill all fields if non streamed (nb_frames for example)
*/
typedef struct AVIIndex {
unsigned char tag[4];
unsigned int flags, pos, len;
struct AVIIndex *next;
} AVIIndex;
typedef struct {
offset_t movi_list;
AVIIndex *first, *last;
} AVIContext;
offset_t start_tag(ByteIOContext *pb, char *tag)
{
put_tag(pb, tag);
put_le32(pb, 0);
return url_ftell(pb);
}
void end_tag(ByteIOContext *pb, offset_t start)
{
offset_t pos;
pos = url_ftell(pb);
url_fseek(pb, start - 4, SEEK_SET);
put_le32(pb, pos - start);
url_fseek(pb, pos, SEEK_SET);
}
/* Note: when encoding, the first matching tag is used, so order is
important if multiple tags possible for a given codec. */
CodecTag codec_bmp_tags[] = {
{ CODEC_ID_H263, MKTAG('U', '2', '6', '3') },
{ CODEC_ID_H263I, MKTAG('I', '2', '6', '3') }, /* intel h263 */
{ CODEC_ID_MJPEG, MKTAG('M', 'J', 'P', 'G') },
{ CODEC_ID_OPENDIVX, MKTAG('D', 'I', 'V', 'X') },
{ CODEC_ID_OPENDIVX, MKTAG('d', 'i', 'v', 'x') },
{ CODEC_ID_OPENDIVX, MKTAG(0x04, 0, 0, 0) }, /* some broken avi use this */
{ CODEC_ID_MSMPEG4, MKTAG('D', 'I', 'V', '3') }, /* default signature when using MSMPEG4 */
{ CODEC_ID_MSMPEG4, MKTAG('M', 'P', '4', '3') },
{ 0, 0 },
};
CodecTag codec_wav_tags[] = {
{ CODEC_ID_MP2, 0x55 },
{ CODEC_ID_MP2, 0x50 },
{ CODEC_ID_AC3, 0x2000 },
{ CODEC_ID_PCM, 0x01 },
{ 0, 0 },
};
unsigned int codec_get_tag(CodecTag *tags, int id)
{
while (tags->id != 0) {
if (tags->id == id)
return tags->tag;
tags++;
}
return 0;
}
int codec_get_id(CodecTag *tags, unsigned int tag)
{
while (tags->id != 0) {
if (tags->tag == tag)
return tags->id;
tags++;
}
return 0;
}
unsigned int codec_get_bmp_tag(int id)
{
return codec_get_tag(codec_bmp_tags, id);
}
/* BITMAPINFOHEADER header */
void put_bmp_header(ByteIOContext *pb, AVCodecContext *enc)
{
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 */
put_le32(pb, codec_get_bmp_tag(enc->codec_id));
put_le32(pb, enc->width * enc->height * 3);
put_le32(pb, 0);
put_le32(pb, 0);
put_le32(pb, 0);
put_le32(pb, 0);
}
/* WAVEFORMATEX header */
void put_wav_header(ByteIOContext *pb, AVCodecContext *enc)
{
int tag;
tag = codec_get_tag(codec_wav_tags, enc->codec_id);
put_le16(pb, tag);
put_le16(pb, enc->channels);
put_le32(pb, enc->sample_rate);
put_le32(pb, enc->bit_rate / 8);
put_le16(pb, 1); /* block align */
put_le16(pb, 16); /* bits per sample */
put_le16(pb, 0); /* wav_extra_size */
}
static int avi_write_header(AVFormatContext *s)
{
AVIContext *avi;
ByteIOContext *pb = &s->pb;
int bitrate, n, i, nb_frames;
AVCodecContext *stream, *video_enc;
offset_t list1, list2, strh, strf;
avi = malloc(sizeof(AVIContext));
if (!avi)
return -1;
memset(avi, 0, sizeof(AVIContext));
s->priv_data = avi;
put_tag(pb, "RIFF");
put_le32(pb, 0); /* file length */
put_tag(pb, "AVI ");
/* header list */
list1 = start_tag(pb, "LIST");
put_tag(pb, "hdrl");
/* avi header */
put_tag(pb, "avih");
put_le32(pb, 14 * 4);
bitrate = 0;
video_enc = NULL;
for(n=0;n<s->nb_streams;n++) {
stream = &s->streams[n]->codec;
bitrate += stream->bit_rate;
if (stream->codec_type == CODEC_TYPE_VIDEO)
video_enc = stream;
}
if (!video_enc) {
free(avi);
return -1;
}
nb_frames = 0;
put_le32(pb, 1000000LL * FRAME_RATE_BASE / video_enc->frame_rate);
put_le32(pb, bitrate / 8); /* XXX: not quite exact */
put_le32(pb, 0); /* padding */
put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */
put_le32(pb, nb_frames); /* nb frames, filled later */
put_le32(pb, 0); /* initial frame */
put_le32(pb, s->nb_streams); /* nb streams */
put_le32(pb, 1024 * 1024); /* suggested buffer size */
put_le32(pb, video_enc->width);
put_le32(pb, video_enc->height);
put_le32(pb, 0); /* reserved */
put_le32(pb, 0); /* reserved */
put_le32(pb, 0); /* reserved */
put_le32(pb, 0); /* reserved */
/* stream list */
for(i=0;i<n;i++) {
list2 = start_tag(pb, "LIST");
put_tag(pb, "strl");
stream = &s->streams[i]->codec;
/* stream generic header */
strh = start_tag(pb, "strh");
switch(stream->codec_type) {
case CODEC_TYPE_VIDEO:
put_tag(pb, "vids");
put_le32(pb, codec_get_bmp_tag(stream->codec_id));
put_le32(pb, 0); /* flags */
put_le16(pb, 0); /* priority */
put_le16(pb, 0); /* language */
put_le32(pb, 0); /* initial frame */
put_le32(pb, 1000); /* scale */
put_le32(pb, (1000 * stream->frame_rate) / FRAME_RATE_BASE); /* rate */
put_le32(pb, 0); /* start */
put_le32(pb, nb_frames); /* length, XXX: fill later */
put_le32(pb, 1024 * 1024); /* suggested buffer size */
put_le32(pb, 10000); /* quality */
put_le32(pb, stream->width * stream->height * 3); /* sample size */
put_le16(pb, 0);
put_le16(pb, 0);
put_le16(pb, stream->width);
put_le16(pb, stream->height);
break;
case CODEC_TYPE_AUDIO:
put_tag(pb, "auds");
put_le32(pb, 0);
put_le32(pb, 0); /* flags */
put_le16(pb, 0); /* priority */
put_le16(pb, 0); /* language */
put_le32(pb, 0); /* initial frame */
put_le32(pb, 1); /* scale */
put_le32(pb, stream->bit_rate / 8); /* rate */
put_le32(pb, 0); /* start */
put_le32(pb, 0); /* length, XXX: filled later */
put_le32(pb, 12 * 1024); /* suggested buffer size */
put_le32(pb, -1); /* quality */
put_le32(pb, 1); /* sample size */
put_le32(pb, 0);
put_le32(pb, 0);
break;
}
end_tag(pb, strh);
strf = start_tag(pb, "strf");
switch(stream->codec_type) {
case CODEC_TYPE_VIDEO:
put_bmp_header(pb, stream);
break;
case CODEC_TYPE_AUDIO:
put_wav_header(pb, stream);
break;
}
end_tag(pb, strf);
end_tag(pb, list2);
}
end_tag(pb, list1);
avi->movi_list = start_tag(pb, "LIST");
avi->first = NULL;
avi->last = NULL;
put_tag(pb, "movi");
put_flush_packet(pb);
return 0;
}
static int avi_write_packet(AVFormatContext *s, int stream_index,
UINT8 *buf, int size)
{
AVIContext *avi = s->priv_data;
ByteIOContext *pb = &s->pb;
AVIIndex *idx;
unsigned char tag[5];
unsigned int flags;
AVCodecContext *enc;
enc = &s->streams[stream_index]->codec;
tag[0] = '0';
tag[1] = '0' + stream_index;
if (enc->codec_type == CODEC_TYPE_VIDEO) {
tag[2] = 'd';
tag[3] = 'c';
flags = enc->key_frame ? 0x10 : 0x00;
} else {
tag[2] = 'w';
tag[3] = 'b';
flags = 0x10;
}
if (!url_is_streamed(&s->pb)) {
idx = malloc(sizeof(AVIIndex));
memcpy(idx->tag, tag, 4);
idx->flags = flags;
idx->pos = url_ftell(pb) - avi->movi_list;
idx->len = size;
idx->next = NULL;
if (!avi->last)
avi->first = idx;
else
avi->last->next = idx;
avi->last = idx;
}
put_buffer(pb, tag, 4);
put_le32(pb, size);
put_buffer(pb, buf, size);
if (size & 1)
put_byte(pb, 0);
put_flush_packet(pb);
return 0;
}
static int avi_write_trailer(AVFormatContext *s)
{
ByteIOContext *pb = &s->pb;
AVIContext *avi = s->priv_data;
offset_t file_size, idx_chunk;
AVIIndex *idx;
if (!url_is_streamed(&s->pb)) {
end_tag(pb, avi->movi_list);
idx_chunk = start_tag(pb, "idx1");
idx = avi->first;
while (idx != NULL) {
put_buffer(pb, idx->tag, 4);
put_le32(pb, idx->flags);
put_le32(pb, idx->pos);
put_le32(pb, idx->len);
idx = idx->next;
}
end_tag(pb, idx_chunk);
/* update file size */
file_size = url_ftell(pb);
url_fseek(pb, 4, SEEK_SET);
put_le32(pb, file_size);
url_fseek(pb, file_size, SEEK_SET);
}
put_flush_packet(pb);
free(avi);
return 0;
}
AVFormat avi_format = {
"avi",
"avi format",
"video/x-msvideo",
"avi",
CODEC_ID_MP2,
CODEC_ID_MSMPEG4,
avi_write_header,
avi_write_packet,
avi_write_trailer,
avi_read_header,
avi_read_packet,
avi_read_close,
};

146
libav/avio.c Normal file
View File

@ -0,0 +1,146 @@
/*
* Unbuffered io for ffmpeg system
* Copyright (c) 2001 Gerard Lantau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "avformat.h"
URLProtocol *first_protocol = NULL;
int register_protocol(URLProtocol *protocol)
{
URLProtocol **p;
p = &first_protocol;
while (*p != NULL) p = &(*p)->next;
*p = protocol;
protocol->next = NULL;
return 0;
}
int url_open(URLContext **puc, const char *filename, int flags)
{
URLContext *uc;
URLProtocol *up;
const char *p;
char proto_str[128], *q;
int err;
p = filename;
q = proto_str;
while (*p != '\0' && *p != ':') {
if ((q - proto_str) < sizeof(proto_str) - 1)
*q++ = *p;
p++;
}
if (*p == '\0') {
strcpy(proto_str, "file");
} else {
*q = '\0';
}
up = first_protocol;
while (up != NULL) {
if (!strcmp(proto_str, up->name))
goto found;
up = up->next;
}
return -ENOENT;
found:
uc = malloc(sizeof(URLContext));
if (!uc)
return -ENOMEM;
uc->prot = up;
uc->flags = flags;
uc->is_streamed = 0; /* default = not streamed */
uc->packet_size = 1; /* default packet size */
err = up->url_open(uc, filename, flags);
if (err < 0) {
free(uc);
*puc = NULL;
return err;
}
*puc = uc;
return 0;
}
int url_read(URLContext *h, unsigned char *buf, int size)
{
int ret;
if (h->flags & URL_WRONLY)
return -EIO;
ret = h->prot->url_read(h, buf, size);
return ret;
}
int url_write(URLContext *h, unsigned char *buf, int size)
{
int ret;
if (!(h->flags & URL_WRONLY))
return -EIO;
ret = h->prot->url_write(h, buf, size);
return ret;
}
offset_t url_seek(URLContext *h, offset_t pos, int whence)
{
offset_t ret;
if (!h->prot->url_seek)
return -EPIPE;
ret = h->prot->url_seek(h, pos, whence);
return ret;
}
int url_getformat(URLContext *h, URLFormat *f)
{
memset(f, 0, sizeof(*f));
if (!h->prot->url_getformat)
return -ENODATA;
return h->prot->url_getformat(h, f);
}
int url_close(URLContext *h)
{
int ret;
ret = h->prot->url_close(h);
free(h);
return ret;
}
int url_exist(const char *filename)
{
URLContext *h;
if (url_open(&h, filename, URL_RDONLY) < 0)
return 0;
url_close(h);
return 1;
}
offset_t url_filesize(URLContext *h)
{
offset_t pos, size;
pos = url_seek(h, 0, SEEK_CUR);
size = url_seek(h, 0, SEEK_END);
url_seek(h, pos, SEEK_SET);
return size;
}

151
libav/avio.h Normal file
View File

@ -0,0 +1,151 @@
/* output byte stream handling */
typedef long long offset_t;
/* unbuffered I/O */
struct URLContext {
struct URLProtocol *prot;
int flags;
int is_streamed; /* true if streamed (no seek possible), default = false */
int packet_size;
void *priv_data;
};
typedef struct URLFormat {
char format_name[32];
int sample_rate;
int frame_rate;
int channels;
int height;
int width;
int pix_fmt;
} URLFormat;
typedef struct URLContext URLContext;
typedef struct URLPollEntry {
URLContext *handle;
int events;
int revents;
} URLPollEntry;
#define URL_RDONLY 0
#define URL_WRONLY 1
int url_open(URLContext **h, const char *filename, int flags);
int url_read(URLContext *h, unsigned char *buf, int size);
int url_write(URLContext *h, unsigned char *buf, int size);
offset_t url_seek(URLContext *h, offset_t pos, int whence);
int url_getformat(URLContext *h, URLFormat *f);
int url_close(URLContext *h);
int url_exist(const char *filename);
offset_t url_filesize(URLContext *h);
/* not implemented */
int url_poll(URLPollEntry *poll_table, int n, int timeout);
typedef struct URLProtocol {
const char *name;
int (*url_open)(URLContext *h, const char *filename, int flags);
int (*url_read)(URLContext *h, unsigned char *buf, int size);
int (*url_write)(URLContext *h, unsigned char *buf, int size);
offset_t (*url_seek)(URLContext *h, offset_t pos, int whence);
int (*url_close)(URLContext *h);
/* get precise information about the format, if available. return
-ENODATA if not available */
int (*url_getformat)(URLContext *h, URLFormat *f);
struct URLProtocol *next;
} URLProtocol;
extern URLProtocol *first_protocol;
int register_protocol(URLProtocol *protocol);
typedef struct {
unsigned char *buffer;
int buffer_size;
unsigned char *buf_ptr, *buf_end;
void *opaque;
int (*read_packet)(void *opaque, UINT8 *buf, int buf_size);
void (*write_packet)(void *opaque, UINT8 *buf, int buf_size);
int (*seek)(void *opaque, offset_t offset, int whence);
offset_t pos; /* position in the file of the current buffer */
int must_flush; /* true if the next seek should flush */
int eof_reached; /* true if eof reached */
int write_flag; /* true if open for writing */
int is_streamed;
int packet_size;
} ByteIOContext;
int init_put_byte(ByteIOContext *s,
unsigned char *buffer,
int buffer_size,
int write_flag,
void *opaque,
int (*read_packet)(void *opaque, UINT8 *buf, int buf_size),
void (*write_packet)(void *opaque, UINT8 *buf, int buf_size),
int (*seek)(void *opaque, offset_t offset, int whence));
void put_byte(ByteIOContext *s, int b);
void put_buffer(ByteIOContext *s, unsigned char *buf, int size);
void put_le64(ByteIOContext *s, unsigned long long val);
void put_be64(ByteIOContext *s, unsigned long long val);
void put_le32(ByteIOContext *s, unsigned int val);
void put_be32(ByteIOContext *s, unsigned int val);
void put_le16(ByteIOContext *s, unsigned int val);
void put_be16(ByteIOContext *s, unsigned int val);
void put_tag(ByteIOContext *s, char *tag);
offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence);
void url_fskip(ByteIOContext *s, offset_t offset);
offset_t url_ftell(ByteIOContext *s);
int url_feof(ByteIOContext *s);
void put_flush_packet(ByteIOContext *s);
int get_buffer(ByteIOContext *s, unsigned char *buf, int size);
int get_byte(ByteIOContext *s);
unsigned int get_le32(ByteIOContext *s);
unsigned long long get_le64(ByteIOContext *s);
unsigned int get_le16(ByteIOContext *s);
unsigned int get_be16(ByteIOContext *s);
unsigned int get_be32(ByteIOContext *s);
unsigned long long get_be64(ByteIOContext *s);
extern inline int url_is_streamed(ByteIOContext *s)
{
return s->is_streamed;
}
/* get the prefered packet size of the device. All I/Os should be done
by multiple of this size */
extern inline int url_get_packet_size(ByteIOContext *s)
{
return s->packet_size;
}
int url_fdopen(ByteIOContext *s, URLContext *h);
int url_setbufsize(ByteIOContext *s, int buf_size);
int url_fopen(ByteIOContext *s, const char *filename, int flags);
int url_fclose(ByteIOContext *s);
URLContext *url_fileno(ByteIOContext *s);
int url_open_buf(ByteIOContext *s, UINT8 *buf, int buf_size, int flags);
int url_close_buf(ByteIOContext *s);
/* file.c */
extern URLProtocol file_protocol;
extern URLProtocol pipe_protocol;
/* udp.c */
extern URLProtocol udp_protocol;
/* http.c */
extern URLProtocol http_protocol;
/* audio.c */
extern const char *audio_device;
extern URLProtocol audio_protocol;
/* grab.c */
extern const char *v4l_device;
extern URLProtocol video_protocol;

426
libav/aviobuf.c Normal file
View File

@ -0,0 +1,426 @@
/*
* Buffered I/O for ffmpeg system
* Copyright (c) 2000,2001 Gerard Lantau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <sys/time.h>
#include <getopt.h>
#include <string.h>
#include "avformat.h"
#define IO_BUFFER_SIZE 32768
int init_put_byte(ByteIOContext *s,
unsigned char *buffer,
int buffer_size,
int write_flag,
void *opaque,
int (*read_packet)(void *opaque, UINT8 *buf, int buf_size),
void (*write_packet)(void *opaque, UINT8 *buf, int buf_size),
int (*seek)(void *opaque, offset_t offset, int whence))
{
s->buffer = buffer;
s->buffer_size = buffer_size;
s->buf_ptr = buffer;
s->write_flag = write_flag;
if (!s->write_flag)
s->buf_end = buffer;
else
s->buf_end = buffer + buffer_size;
s->opaque = opaque;
s->write_packet = write_packet;
s->read_packet = read_packet;
s->seek = seek;
s->pos = 0;
s->must_flush = 0;
s->eof_reached = 0;
s->is_streamed = 0;
s->packet_size = 1;
return 0;
}
static void flush_buffer(ByteIOContext *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(ByteIOContext *s, int b)
{
*(s->buf_ptr)++ = b;
if (s->buf_ptr >= s->buf_end)
flush_buffer(s);
}
void put_buffer(ByteIOContext *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(ByteIOContext *s)
{
flush_buffer(s);
s->must_flush = 0;
}
offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence)
{
offset_t offset1;
if (whence != SEEK_CUR && whence != SEEK_SET)
return -EINVAL;
if (s->write_flag) {
if (whence == SEEK_CUR) {
offset1 = s->pos + s->buf_ptr - s->buffer;
if (offset == 0)
return offset1;
offset += offset1;
}
offset1 = offset - s->pos;
if (!s->must_flush &&
offset1 >= 0 && offset1 < (s->buf_end - s->buffer)) {
/* can do the seek inside the buffer */
s->buf_ptr = s->buffer + offset1;
} else {
if (!s->seek)
return -EPIPE;
flush_buffer(s);
s->must_flush = 1;
s->buf_ptr = s->buffer;
s->seek(s->opaque, offset, SEEK_SET);
s->pos = offset;
}
} else {
if (whence == SEEK_CUR) {
offset1 = s->pos - (s->buf_end - s->buffer) + (s->buf_ptr - s->buffer);
if (offset == 0)
return offset1;
offset += offset1;
}
offset1 = offset - (s->pos - (s->buf_end - s->buffer));
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->seek)
return -EPIPE;
s->buf_ptr = s->buffer;
s->buf_end = s->buffer;
s->eof_reached = 0;
s->seek(s->opaque, offset, SEEK_SET);
s->pos = offset;
}
}
return offset;
}
void url_fskip(ByteIOContext *s, offset_t offset)
{
url_fseek(s, offset, SEEK_CUR);
}
offset_t url_ftell(ByteIOContext *s)
{
return url_fseek(s, 0, SEEK_CUR);
}
int url_feof(ByteIOContext *s)
{
return s->eof_reached;
}
void put_le32(ByteIOContext *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_be32(ByteIOContext *s, unsigned int val)
{
put_byte(s, val >> 24);
put_byte(s, val >> 16);
put_byte(s, val >> 8);
put_byte(s, val);
}
void put_le64(ByteIOContext *s, unsigned long long val)
{
put_le32(s, val & 0xffffffff);
put_le32(s, val >> 32);
}
void put_be64(ByteIOContext *s, unsigned long long val)
{
put_be32(s, val >> 32);
put_be32(s, val & 0xffffffff);
}
void put_le16(ByteIOContext *s, unsigned int val)
{
put_byte(s, val);
put_byte(s, val >> 8);
}
void put_be16(ByteIOContext *s, unsigned int val)
{
put_byte(s, val >> 8);
put_byte(s, val);
}
void put_tag(ByteIOContext *s, char *tag)
{
while (*tag) {
put_byte(s, *tag++);
}
}
/* Input stream */
static void fill_buffer(ByteIOContext *s)
{
int len;
len = s->read_packet(s->opaque, s->buffer, s->buffer_size);
s->pos += len;
s->buf_ptr = s->buffer;
s->buf_end = s->buffer + len;
if (len == 0) {
s->eof_reached = 1;
}
}
int get_byte(ByteIOContext *s)
{
if (s->buf_ptr < s->buf_end) {
return *s->buf_ptr++;
} else {
fill_buffer(s);
if (s->buf_ptr < s->buf_end)
return *s->buf_ptr++;
else
return 0;
}
}
int get_buffer(ByteIOContext *s, unsigned char *buf, int size)
{
int len, size1;
size1 = size;
while (size > 0) {
len = s->buf_end - s->buf_ptr;
if (len > size)
len = size;
if (len == 0) {
fill_buffer(s);
len = s->buf_end - s->buf_ptr;
if (len == 0)
break;
} else {
memcpy(buf, s->buf_ptr, len);
buf += len;
s->buf_ptr += len;
size -= len;
}
}
return size1 - size;
}
unsigned int get_le16(ByteIOContext *s)
{
unsigned int val;
val = get_byte(s);
val |= get_byte(s) << 8;
return val;
}
unsigned int get_le32(ByteIOContext *s)
{
unsigned int val;
val = get_byte(s);
val |= get_byte(s) << 8;
val |= get_byte(s) << 16;
val |= get_byte(s) << 24;
return val;
}
unsigned long long get_le64(ByteIOContext *s)
{
UINT64 val;
val = (UINT64)get_le32(s);
val |= (UINT64)get_le32(s) << 32;
return val;
}
unsigned int get_be16(ByteIOContext *s)
{
unsigned int val;
val = get_byte(s) << 8;
val |= get_byte(s);
return val;
}
unsigned int get_be32(ByteIOContext *s)
{
unsigned int val;
val = get_byte(s) << 24;
val |= get_byte(s) << 16;
val |= get_byte(s) << 8;
val |= get_byte(s);
return val;
}
unsigned long long get_be64(ByteIOContext *s)
{
UINT64 val;
val = (UINT64)get_be32(s) << 32;
val |= (UINT64)get_be32(s);
return val;
}
/* link with avio functions */
void url_write_packet(void *opaque, UINT8 *buf, int buf_size)
{
URLContext *h = opaque;
url_write(h, buf, buf_size);
}
int url_read_packet(void *opaque, UINT8 *buf, int buf_size)
{
URLContext *h = opaque;
return url_read(h, buf, buf_size);
}
int url_seek_packet(void *opaque, long long offset, int whence)
{
URLContext *h = opaque;
url_seek(h, offset, whence);
return 0;
}
int url_fdopen(ByteIOContext *s, URLContext *h)
{
UINT8 *buffer;
int buffer_size;
buffer_size = (IO_BUFFER_SIZE / h->packet_size) * h->packet_size;
buffer = malloc(buffer_size);
if (!buffer)
return -ENOMEM;
if (init_put_byte(s, buffer, buffer_size,
(h->flags & URL_WRONLY) != 0, h,
url_read_packet, url_write_packet, url_seek_packet) < 0) {
free(buffer);
return -EIO;
}
s->is_streamed = h->is_streamed;
s->packet_size = h->packet_size;
return 0;
}
/* XXX: must be called before any I/O */
int url_setbufsize(ByteIOContext *s, int buf_size)
{
UINT8 *buffer;
buffer = malloc(buf_size);
if (!buffer)
return -ENOMEM;
free(s->buffer);
s->buffer = buffer;
s->buffer_size = buf_size;
s->buf_ptr = buffer;
if (!s->write_flag)
s->buf_end = buffer;
else
s->buf_end = buffer + buf_size;
return 0;
}
int url_fopen(ByteIOContext *s, const char *filename, int flags)
{
URLContext *h;
int err;
err = url_open(&h, filename, flags);
if (err < 0)
return err;
err = url_fdopen(s, h);
if (err < 0) {
url_close(h);
return err;
}
return 0;
}
int url_fclose(ByteIOContext *s)
{
URLContext *h = s->opaque;
free(s->buffer);
memset(s, 0, sizeof(ByteIOContext));
return url_close(h);
}
URLContext *url_fileno(ByteIOContext *s)
{
return s->opaque;
}
/* buffer handling */
int url_open_buf(ByteIOContext *s, UINT8 *buf, int buf_size, int flags)
{
return init_put_byte(s, buf, buf_size,
(flags & URL_WRONLY) != 0, NULL, NULL, NULL, NULL);
}
/* return the written or read size */
int url_close_buf(ByteIOContext *s)
{
return s->buf_ptr - s->buffer;
}

599
libav/ffm.c Normal file
View File

@ -0,0 +1,599 @@
/*
* FFM (ffserver live feed) encoder and decoder
* Copyright (c) 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "avformat.h"
/* The FFM file is made of blocks of fixed size */
#define FFM_HEADER_SIZE 14
#define PACKET_ID 0x666d
/* each packet contains frames (which can span several packets */
#define FRAME_HEADER_SIZE 5
#define FLAG_KEY_FRAME 0x01
typedef struct FFMStream {
INT64 pts;
} FFMStream;
enum {
READ_HEADER,
READ_DATA,
};
typedef struct FFMContext {
/* only reading mode */
offset_t write_index, file_size;
int read_state;
UINT8 header[FRAME_HEADER_SIZE];
/* read and write */
int first_packet; /* true if first packet, needed to set the discontinuity tag */
int packet_size;
int frame_offset;
INT64 pts;
UINT8 *packet_ptr, *packet_end;
UINT8 packet[1]; /* must be last */
} FFMContext;
static void flush_packet(AVFormatContext *s)
{
FFMContext *ffm = s->priv_data;
int fill_size, h;
ByteIOContext *pb = &s->pb;
fill_size = ffm->packet_end - ffm->packet_ptr;
memset(ffm->packet_ptr, 0, fill_size);
/* put header */
put_be16(pb, PACKET_ID);
put_be16(pb, fill_size);
put_be64(pb, ffm->pts);
h = ffm->frame_offset;
if (ffm->first_packet)
h |= 0x8000;
put_be16(pb, h);
put_buffer(pb, ffm->packet, ffm->packet_end - ffm->packet);
/* prepare next packet */
ffm->frame_offset = 0; /* no key frame */
ffm->pts = 0; /* no pts */
ffm->packet_ptr = ffm->packet;
ffm->first_packet = 0;
}
/* 'first' is true if first data of a frame */
static void ffm_write_data(AVFormatContext *s,
UINT8 *buf, int size,
INT64 pts, int first)
{
FFMContext *ffm = s->priv_data;
int len;
if (first && ffm->frame_offset == 0)
ffm->frame_offset = ffm->packet_ptr - ffm->packet + FFM_HEADER_SIZE;
if (first && ffm->pts == 0)
ffm->pts = pts;
/* write as many packets as needed */
while (size > 0) {
len = ffm->packet_end - ffm->packet_ptr;
if (len > size)
len = size;
memcpy(ffm->packet_ptr, buf, len);
ffm->packet_ptr += len;
buf += len;
size -= len;
if (ffm->packet_ptr >= ffm->packet_end) {
/* special case : no pts in packet : we leave the current one */
if (ffm->pts == 0)
ffm->pts = pts;
flush_packet(s);
}
}
}
static int ffm_write_header(AVFormatContext *s)
{
AVStream *st;
FFMStream *fst;
FFMContext *ffm;
ByteIOContext *pb = &s->pb;
AVCodecContext *codec;
int bit_rate, i;
ffm = av_mallocz(sizeof(FFMContext) + FFM_PACKET_SIZE);
if (!ffm)
return -1;
s->priv_data = ffm;
ffm->packet_size = FFM_PACKET_SIZE;
/* header */
put_tag(pb, "FFM1");
put_be32(pb, ffm->packet_size);
/* XXX: store write position in other file ? */
put_be64(pb, ffm->packet_size); /* current write position */
put_be32(pb, s->nb_streams);
bit_rate = 0;
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
bit_rate += st->codec.bit_rate;
}
put_be32(pb, bit_rate);
/* list of streams */
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
fst = av_mallocz(sizeof(FFMStream) + ffm->packet_size);
if (!fst)
goto fail;
st->priv_data = fst;
codec = &st->codec;
/* generic info */
put_be32(pb, codec->codec_id);
put_byte(pb, codec->codec_type);
put_be32(pb, codec->bit_rate);
/* specific info */
switch(codec->codec_type) {
case CODEC_TYPE_VIDEO:
put_be32(pb, (codec->frame_rate * 1000) / FRAME_RATE_BASE);
put_be16(pb, codec->width);
put_be16(pb, codec->height);
break;
case CODEC_TYPE_AUDIO:
put_be32(pb, codec->sample_rate);
put_le16(pb, codec->channels);
break;
}
/* hack to have real time */
fst->pts = gettime();
}
/* flush until end of block reached */
while ((url_ftell(pb) % ffm->packet_size) != 0)
put_byte(pb, 0);
put_flush_packet(pb);
/* init packet mux */
ffm->packet_ptr = ffm->packet;
ffm->packet_end = ffm->packet + ffm->packet_size - FFM_HEADER_SIZE;
ffm->frame_offset = 0;
ffm->pts = 0;
ffm->first_packet = 1;
return 0;
fail:
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
fst = st->priv_data;
if (fst)
free(fst);
}
free(ffm);
return -1;
}
static int ffm_write_packet(AVFormatContext *s, int stream_index,
UINT8 *buf, int size)
{
AVStream *st = s->streams[stream_index];
FFMStream *fst = st->priv_data;
INT64 pts;
UINT8 header[FRAME_HEADER_SIZE];
pts = fst->pts;
/* packet size & key_frame */
header[0] = stream_index;
header[1] = 0;
if (st->codec.key_frame)
header[1] |= FLAG_KEY_FRAME;
header[2] = (size >> 16) & 0xff;
header[3] = (size >> 8) & 0xff;
header[4] = size & 0xff;
ffm_write_data(s, header, FRAME_HEADER_SIZE, pts, 1);
ffm_write_data(s, buf, size, pts, 0);
if (st->codec.codec_type == CODEC_TYPE_AUDIO) {
fst->pts += (INT64)((float)st->codec.frame_size / st->codec.sample_rate * 1000000.0);
} else {
fst->pts += (INT64)(1000000.0 * FRAME_RATE_BASE / (float)st->codec.frame_rate);
}
return 0;
}
static int ffm_write_trailer(AVFormatContext *s)
{
ByteIOContext *pb = &s->pb;
FFMContext *ffm = s->priv_data;
int i;
/* flush packets */
if (ffm->packet_ptr > ffm->packet)
flush_packet(s);
put_flush_packet(pb);
for(i=0;i<s->nb_streams;i++)
free(s->streams[i]->priv_data);
free(ffm);
return 0;
}
/* ffm demux */
static int ffm_is_avail_data(AVFormatContext *s, int size)
{
FFMContext *ffm = s->priv_data;
offset_t pos, avail_size;
int len;
len = ffm->packet_end - ffm->packet_ptr;
if (size <= len)
return 1;
pos = url_ftell(&s->pb);
if (pos == ffm->write_index) {
/* exactly at the end of stream */
return 0;
} else if (pos < ffm->write_index) {
avail_size = ffm->write_index - pos;
} else {
avail_size = (ffm->file_size - pos) + (ffm->write_index - FFM_PACKET_SIZE);
}
avail_size = (avail_size / ffm->packet_size) * (ffm->packet_size - FFM_HEADER_SIZE) + len;
if (size <= avail_size)
return 1;
else
return 0;
}
/* first is true if we read the frame header */
static int ffm_read_data(AVFormatContext *s,
UINT8 *buf, int size, int first)
{
FFMContext *ffm = s->priv_data;
ByteIOContext *pb = &s->pb;
int len, fill_size, size1, frame_offset;
size1 = size;
while (size > 0) {
redo:
len = ffm->packet_end - ffm->packet_ptr;
if (len > size)
len = size;
if (len == 0) {
if (url_ftell(pb) == ffm->file_size)
url_fseek(pb, ffm->packet_size, SEEK_SET);
get_be16(pb); /* PACKET_ID */
fill_size = get_be16(pb);
ffm->pts = get_be64(pb);
frame_offset = get_be16(pb);
get_buffer(pb, ffm->packet, ffm->packet_size - FFM_HEADER_SIZE);
ffm->packet_end = ffm->packet + (ffm->packet_size - FFM_HEADER_SIZE - fill_size);
/* if first packet or resynchronization packet, we must
handle it specifically */
if (ffm->first_packet || (frame_offset & 0x8000)) {
ffm->first_packet = 0;
ffm->packet_ptr = ffm->packet + (frame_offset & 0x7fff) - FFM_HEADER_SIZE;
if (!first)
break;
} else {
ffm->packet_ptr = ffm->packet;
}
goto redo;
}
memcpy(buf, ffm->packet_ptr, len);
buf += len;
ffm->packet_ptr += len;
size -= len;
first = 0;
}
return size1 - size;
}
static int ffm_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
AVStream *st;
FFMStream *fst;
FFMContext *ffm;
ByteIOContext *pb = &s->pb;
AVCodecContext *codec;
int i;
UINT32 tag;
ffm = av_mallocz(sizeof(FFMContext) + FFM_PACKET_SIZE);
if (!ffm)
return -1;
s->priv_data = ffm;
/* header */
tag = get_le32(pb);
if (tag != MKTAG('F', 'F', 'M', '1'))
goto fail;
ffm->packet_size = get_be32(pb);
if (ffm->packet_size != FFM_PACKET_SIZE)
goto fail;
ffm->write_index = get_be64(pb);
/* get also filesize */
if (!url_is_streamed(pb)) {
ffm->file_size = url_filesize(url_fileno(pb));
} else {
ffm->file_size = (1ULL << 63) - 1;
}
s->nb_streams = get_be32(pb);
get_be32(pb); /* total bitrate */
/* read each stream */
for(i=0;i<s->nb_streams;i++) {
st = av_mallocz(sizeof(AVStream));
if (!st)
goto fail;
s->streams[i] = st;
fst = av_mallocz(sizeof(FFMStream) + ffm->packet_size);
if (!fst)
goto fail;
st->priv_data = fst;
codec = &st->codec;
/* generic info */
st->codec.codec_id = get_be32(pb);
st->codec.codec_type = get_byte(pb); /* codec_type */
codec->bit_rate = get_be32(pb);
/* specific info */
switch(codec->codec_type) {
case CODEC_TYPE_VIDEO:
codec->frame_rate = ((INT64)get_be32(pb) * FRAME_RATE_BASE) / 1000;
codec->width = get_be16(pb);
codec->height = get_be16(pb);
break;
case CODEC_TYPE_AUDIO:
codec->sample_rate = get_be32(pb);
codec->channels = get_le16(pb);
break;
}
}
/* get until end of block reached */
while ((url_ftell(pb) % ffm->packet_size) != 0)
get_byte(pb);
/* init packet demux */
ffm->packet_ptr = ffm->packet;
ffm->packet_end = ffm->packet;
ffm->frame_offset = 0;
ffm->pts = 0;
ffm->read_state = READ_HEADER;
ffm->first_packet = 1;
return 0;
fail:
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
if (st) {
fst = st->priv_data;
if (fst)
free(fst);
free(st);
}
}
if (ffm)
free(ffm);
return -1;
}
/* return < 0 if eof */
static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt)
{
int size;
FFMContext *ffm = s->priv_data;
switch(ffm->read_state) {
case READ_HEADER:
if (!ffm_is_avail_data(s, FRAME_HEADER_SIZE))
return -EAGAIN;
#if 0
printf("pos=%08Lx spos=%Lx, write_index=%Lx size=%Lx\n",
url_ftell(&s->pb), s->pb.pos, ffm->write_index, ffm->file_size);
#endif
if (ffm_read_data(s, ffm->header, FRAME_HEADER_SIZE, 1) != FRAME_HEADER_SIZE)
return -EAGAIN;
#if 0
{
int i;
for(i=0;i<FRAME_HEADER_SIZE;i++)
printf("%02x ", ffm->header[i]);
printf("\n");
}
#endif
ffm->read_state = READ_DATA;
/* fall thru */
case READ_DATA:
size = (ffm->header[2] << 16) | (ffm->header[3] << 8) | ffm->header[4];
if (!ffm_is_avail_data(s, size)) {
return -EAGAIN;
}
av_new_packet(pkt, size);
pkt->stream_index = ffm->header[0];
if (ffm->header[1] & FLAG_KEY_FRAME)
pkt->flags |= PKT_FLAG_KEY;
ffm->read_state = READ_HEADER;
if (ffm_read_data(s, pkt->data, size, 0) != size) {
/* bad case: desynchronized packet. we cancel all the packet loading */
av_free_packet(pkt);
return -EAGAIN;
}
break;
}
return 0;
}
//#define DEBUG_SEEK
/* pos is between 0 and file_size - FFM_PACKET_SIZE. It is translated
by the write position inside this function */
static void ffm_seek1(AVFormatContext *s, offset_t pos1)
{
FFMContext *ffm = s->priv_data;
ByteIOContext *pb = &s->pb;
offset_t pos;
pos = pos1 + ffm->write_index;
if (pos >= ffm->file_size)
pos -= (ffm->file_size - FFM_PACKET_SIZE);
#ifdef DEBUG_SEEK
printf("seek to %Lx -> %Lx\n", pos1, pos);
#endif
url_fseek(pb, pos, SEEK_SET);
}
static INT64 get_pts(AVFormatContext *s, offset_t pos)
{
ByteIOContext *pb = &s->pb;
INT64 pts;
ffm_seek1(s, pos);
url_fskip(pb, 4);
pts = get_be64(pb);
#ifdef DEBUG_SEEK
printf("pts=%0.6f\n", pts / 1000000.0);
#endif
return pts;
}
/* seek to a given time in the file. The file read pointer is
positionned at or before pts. XXX: the following code is quite
approximative */
static int ffm_seek(AVFormatContext *s, INT64 wanted_pts)
{
FFMContext *ffm = s->priv_data;
offset_t pos_min, pos_max, pos;
INT64 pts_min, pts_max, pts;
double pos1;
#ifdef DEBUG_SEEK
printf("wanted_pts=%0.6f\n", wanted_pts / 1000000.0);
#endif
/* find the position using linear interpolation (better than
dichotomy in typical cases) */
pos_min = 0;
pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE;
while (pos_min <= pos_max) {
pts_min = get_pts(s, pos_min);
pts_max = get_pts(s, pos_max);
/* linear interpolation */
pos1 = (double)(pos_max - pos_min) * (double)(wanted_pts - pts_min) /
(double)(pts_max - pts_min);
pos = (((INT64)pos1) / FFM_PACKET_SIZE) * FFM_PACKET_SIZE;
if (pos <= pos_min)
pos = pos_min;
else if (pos >= pos_max)
pos = pos_max;
pts = get_pts(s, pos);
/* check if we are lucky */
if (pts == wanted_pts) {
goto found;
} else if (pts > wanted_pts) {
pos_max = pos - FFM_PACKET_SIZE;
} else {
pos_min = pos + FFM_PACKET_SIZE;
}
}
pos = pos_min;
if (pos > 0)
pos -= FFM_PACKET_SIZE;
found:
ffm_seek1(s, pos);
return 0;
}
offset_t ffm_read_write_index(int fd)
{
UINT8 buf[8];
offset_t pos;
int i;
lseek(fd, 8, SEEK_SET);
read(fd, buf, 8);
pos = 0;
for(i=0;i<8;i++)
pos |= buf[i] << (56 - i * 8);
return pos;
}
void ffm_write_write_index(int fd, offset_t pos)
{
UINT8 buf[8];
int i;
for(i=0;i<8;i++)
buf[i] = (pos >> (56 - i * 8)) & 0xff;
lseek(fd, 8, SEEK_SET);
write(fd, buf, 8);
}
void ffm_set_write_index(AVFormatContext *s, offset_t pos, offset_t file_size)
{
FFMContext *ffm = s->priv_data;
ffm->write_index = pos;
ffm->file_size = file_size;
}
static int ffm_read_close(AVFormatContext *s)
{
AVStream *st;
int i;
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
free(st->priv_data);
}
free(s->priv_data);
return 0;
}
AVFormat ffm_format = {
"ffm",
"ffm format",
"",
"ffm",
/* not really used */
CODEC_ID_MP2,
CODEC_ID_MPEG1VIDEO,
ffm_write_header,
ffm_write_packet,
ffm_write_trailer,
ffm_read_header,
ffm_read_packet,
ffm_read_close,
ffm_seek,
};

121
libav/file.c Normal file
View File

@ -0,0 +1,121 @@
/*
* Buffered file io for ffmpeg system
* Copyright (c) 2001 Gerard Lantau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <sys/time.h>
#include "avformat.h"
/* standard file protocol */
static int file_open(URLContext *h, const char *filename, int flags)
{
int access;
int fd;
if (flags & URL_WRONLY) {
access = O_CREAT | O_TRUNC | O_WRONLY;
} else {
access = O_RDONLY;
}
fd = open(filename, access, 0666);
if (fd < 0)
return -ENOENT;
h->priv_data = (void *)fd;
return 0;
}
static int file_read(URLContext *h, unsigned char *buf, int size)
{
int fd = (int)h->priv_data;
return read(fd, buf, size);
}
static int file_write(URLContext *h, unsigned char *buf, int size)
{
int fd = (int)h->priv_data;
return write(fd, buf, size);
}
/* XXX: use llseek */
static offset_t file_seek(URLContext *h, offset_t pos, int whence)
{
int fd = (int)h->priv_data;
return lseek(fd, pos, whence);
}
static int file_close(URLContext *h)
{
int fd = (int)h->priv_data;
return close(fd);
}
URLProtocol file_protocol = {
"file",
file_open,
file_read,
file_write,
file_seek,
file_close,
};
/* pipe protocol */
static int pipe_open(URLContext *h, const char *filename, int flags)
{
int fd;
if (flags & URL_WRONLY) {
fd = 1;
} else {
fd = 0;
}
h->priv_data = (void *)fd;
return 0;
}
static int pipe_read(URLContext *h, unsigned char *buf, int size)
{
int fd = (int)h->priv_data;
return read(fd, buf, size);
}
static int pipe_write(URLContext *h, unsigned char *buf, int size)
{
int fd = (int)h->priv_data;
return write(fd, buf, size);
}
static int pipe_close(URLContext *h)
{
return 0;
}
URLProtocol pipe_protocol = {
"pipe",
pipe_open,
pipe_read,
pipe_write,
NULL,
pipe_close,
};

321
libav/grab.c Normal file
View File

@ -0,0 +1,321 @@
/*
* Linux video grab interface
* Copyright (c) 2000,2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <linux/videodev.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <errno.h>
#include <sys/time.h>
#include "avformat.h"
typedef struct {
int fd;
int frame_format; /* see VIDEO_PALETTE_xxx */
int use_mmap;
int width, height;
float rate;
INT64 time_frame;
} VideoData;
const char *v4l_device = "/dev/video";
/* XXX: move all that to the context */
static struct video_capability video_cap;
static UINT8 *video_buf;
static struct video_mbuf gb_buffers;
static struct video_mmap gb_buf;
static struct video_audio audio;
static int gb_frame = 0;
static int v4l_init(URLContext *h)
{
VideoData *s = h->priv_data;
int width, height;
int ret;
int video_fd, frame_size;
width = s->width;
height = s->height;
video_fd = open(v4l_device, O_RDWR);
if (video_fd < 0) {
perror(v4l_device);
return -EIO;
}
if (ioctl(video_fd,VIDIOCGCAP,&video_cap) < 0) {
perror("VIDIOCGCAP");
goto fail;
}
if (!(video_cap.type & VID_TYPE_CAPTURE)) {
fprintf(stderr, "Fatal: grab device does not handle capture\n");
goto fail;
}
/* unmute audio */
ioctl(video_fd, VIDIOCGAUDIO, &audio);
audio.flags &= ~VIDEO_AUDIO_MUTE;
ioctl(video_fd, VIDIOCSAUDIO, &audio);
ret = ioctl(video_fd,VIDIOCGMBUF,&gb_buffers);
if (ret < 0) {
/* try to use read based access */
struct video_window win;
struct video_picture pict;
int val;
win.x = 0;
win.y = 0;
win.width = width;
win.height = height;
win.chromakey = -1;
win.flags = 0;
ioctl(video_fd, VIDIOCSWIN, &win);
ioctl(video_fd, VIDIOCGPICT, &pict);
#if 0
printf("v4l: colour=%d hue=%d brightness=%d constrast=%d whiteness=%d\n",
pict.colour,
pict.hue,
pict.brightness,
pict.contrast,
pict.whiteness);
#endif
/* try to choose a suitable video format */
pict.palette=VIDEO_PALETTE_YUV420P;
ret = ioctl(video_fd, VIDIOCSPICT, &pict);
if (ret < 0) {
pict.palette=VIDEO_PALETTE_YUV422;
ret = ioctl(video_fd, VIDIOCSPICT, &pict);
if (ret < 0) {
pict.palette=VIDEO_PALETTE_RGB24;
ret = ioctl(video_fd, VIDIOCSPICT, &pict);
if (ret < 0)
goto fail1;
}
}
s->frame_format = pict.palette;
val = 1;
ioctl(video_fd, VIDIOCCAPTURE, &val);
s->time_frame = gettime();
s->use_mmap = 0;
} else {
video_buf = mmap(0,gb_buffers.size,PROT_READ|PROT_WRITE,MAP_SHARED,video_fd,0);
if ((unsigned char*)-1 == video_buf) {
perror("mmap");
goto fail;
}
gb_frame = 0;
s->time_frame = gettime();
/* start to grab the first frame */
gb_buf.frame = 1 - gb_frame;
gb_buf.height = height;
gb_buf.width = width;
gb_buf.format = VIDEO_PALETTE_YUV420P;
ret = ioctl(video_fd, VIDIOCMCAPTURE, &gb_buf);
if (ret < 0 && errno != EAGAIN) {
/* try YUV422 */
gb_buf.format = VIDEO_PALETTE_YUV422;
ret = ioctl(video_fd, VIDIOCMCAPTURE, &gb_buf);
if (ret < 0 && errno != EAGAIN) {
/* try RGB24 */
gb_buf.format = VIDEO_PALETTE_RGB24;
ret = ioctl(video_fd, VIDIOCMCAPTURE, &gb_buf);
}
}
if (ret < 0) {
if (errno != EAGAIN) {
fail1:
fprintf(stderr, "Fatal: grab device does not support suitable format\n");
} else {
fprintf(stderr,"Fatal: grab device does not receive any video signal\n");
}
goto fail;
}
s->frame_format = gb_buf.format;
s->use_mmap = 1;
}
switch(s->frame_format) {
case VIDEO_PALETTE_YUV420P:
frame_size = (width * height * 3) / 2;
break;
case VIDEO_PALETTE_YUV422:
frame_size = width * height * 2;
break;
case VIDEO_PALETTE_RGB24:
frame_size = width * height * 3;
break;
default:
goto fail;
}
s->fd = video_fd;
h->packet_size = frame_size;
return 0;
fail:
close(video_fd);
return -EIO;
}
static int v4l_mm_read_picture(URLContext *h, UINT8 *buf)
{
VideoData *s = h->priv_data;
UINT8 *ptr;
gb_buf.frame = gb_frame;
if (ioctl(s->fd, VIDIOCMCAPTURE, &gb_buf) < 0) {
if (errno == EAGAIN)
fprintf(stderr,"Cannot Sync\n");
else
perror("VIDIOCMCAPTURE");
return -EIO;
}
gb_frame = 1 - gb_frame;
while (ioctl(s->fd, VIDIOCSYNC, &gb_frame) < 0 &&
(errno == EAGAIN || errno == EINTR));
ptr = video_buf + gb_buffers.offsets[gb_frame];
memcpy(buf, ptr, h->packet_size);
return h->packet_size;
}
/* note: we support only one picture read at a time */
static int video_read(URLContext *h, UINT8 *buf, int size)
{
VideoData *s = h->priv_data;
INT64 curtime;
if (size != h->packet_size)
return -EINVAL;
/* wait based on the frame rate */
s->time_frame += (int)(1000000 / s->rate);
do {
curtime = gettime();
} while (curtime < s->time_frame);
/* read one frame */
if (s->use_mmap) {
return v4l_mm_read_picture(h, buf);
} else {
if (read(s->fd, buf, size) != size)
return -EIO;
return h->packet_size;
}
}
static int video_get_format(URLContext *h, URLFormat *f)
{
VideoData *s = h->priv_data;
f->width = s->width;
f->height = s->height;
f->frame_rate = (int)(s->rate * FRAME_RATE_BASE);
strcpy(f->format_name, "rawvideo");
switch(s->frame_format) {
case VIDEO_PALETTE_YUV420P:
f->pix_fmt = PIX_FMT_YUV420P;
break;
case VIDEO_PALETTE_YUV422:
f->pix_fmt = PIX_FMT_YUV422;
break;
case VIDEO_PALETTE_RGB24:
f->pix_fmt = PIX_FMT_BGR24; /* NOTE: v4l uses BGR24, not RGB24 ! */
break;
default:
abort();
}
return 0;
}
/* URI syntax: 'video:width,height,rate'
*/
static int video_open(URLContext *h, const char *uri, int flags)
{
VideoData *s;
const char *p;
int width, height;
int ret;
float rate;
/* extract parameters */
p = uri;
strstart(p, "video:", &p);
width = strtol(p, (char **)&p, 0);
if (width <= 0)
return -EINVAL;
if (*p == ',')
p++;
height = strtol(p, (char **)&p, 0);
if (height <= 0)
return -EINVAL;
if (*p == ',')
p++;
rate = strtod(p, (char **)&p);
if (rate <= 0)
return -EINVAL;
s = malloc(sizeof(VideoData));
if (!s)
return -ENOMEM;
h->priv_data = s;
h->is_streamed = 1;
s->width = width;
s->height = height;
s->rate = rate;
ret = v4l_init(h);
if (ret)
free(s);
return ret;
}
static int video_close(URLContext *h)
{
VideoData *s = h->priv_data;
close(s->fd);
free(s);
return 0;
}
URLProtocol video_protocol = {
"video",
video_open,
video_read,
NULL,
NULL, /* seek */
video_close,
video_get_format,
};

318
libav/http.c Normal file
View File

@ -0,0 +1,318 @@
/*
* HTTP protocol for ffmpeg client
* Copyright (c) 2000, 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "avformat.h"
/* XXX: POST protocol is not completly implemented because ffmpeg use
only a subset of it */
//#define DEBUG
/* used for protocol handling */
#define BUFFER_SIZE 1024
#define URL_SIZE 4096
typedef struct {
int fd;
unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end;
int line_count;
int http_code;
char location[URL_SIZE];
} HTTPContext;
static int http_connect(URLContext *h, const char *path);
static int http_write(URLContext *h, UINT8 *buf, int size);
/* return non zero if error */
static int http_open(URLContext *h, const char *uri, int flags)
{
struct sockaddr_in dest_addr;
const char *p, *path, *proxy_path;
char hostname[1024], *q;
int port, fd = -1, use_proxy;
struct hostent *hp;
HTTPContext *s;
h->is_streamed = 1;
s = malloc(sizeof(HTTPContext));
if (!s) {
return -ENOMEM;
}
h->priv_data = s;
proxy_path = getenv("http_proxy");
use_proxy = (proxy_path != NULL) && !getenv("no_proxy");
/* fill the dest addr */
redo:
if (use_proxy) {
p = proxy_path;
} else {
p = uri;
}
if (!strstart(p, "http://", &p))
goto fail;
q = hostname;
while (*p != ':' && *p != '/' && *p != '\0') {
if ((q - hostname) < sizeof(hostname) - 1)
*q++ = *p;
p++;
}
*q = '\0';
port = 80;
if (*p == ':') {
p++;
port = strtoul(p, (char **)&p, 10);
}
if (port <= 0)
goto fail;
if (use_proxy) {
path = uri;
} else {
if (*p == '\0')
path = "/";
else
path = p;
}
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port);
if ((inet_aton(hostname, &dest_addr.sin_addr)) == 0) {
hp = gethostbyname(hostname);
if (!hp)
goto fail;
memcpy (&dest_addr.sin_addr, hp->h_addr, sizeof(dest_addr.sin_addr));
}
fd = socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0)
goto fail;
if (connect(fd, (struct sockaddr *)&dest_addr,
sizeof(dest_addr)) < 0)
goto fail;
s->fd = fd;
if (http_connect(h, path) < 0)
goto fail;
if (s->http_code == 303 && s->location[0] != '\0') {
/* url moved, get next */
uri = s->location;
goto redo;
}
return 0;
fail:
if (fd >= 0)
close(fd);
free(s);
return -EIO;
}
static int http_getc(HTTPContext *s)
{
int len;
if (s->buf_ptr >= s->buf_end) {
redo:
len = read(s->fd, s->buffer, BUFFER_SIZE);
if (len < 0) {
if (errno == EAGAIN || errno == EINTR)
goto redo;
return -EIO;
} else if (len == 0) {
return -1;
} else {
s->buf_ptr = s->buffer;
s->buf_end = s->buffer + len;
}
}
return *s->buf_ptr++;
}
static int process_line(HTTPContext *s, char *line, int line_count)
{
char *tag, *p;
/* end of header */
if (line[0] == '\0')
return 0;
p = line;
if (line_count == 0) {
while (!isspace(*p) && *p != '\0')
p++;
while (isspace(*p))
p++;
s->http_code = strtol(p, NULL, 10);
#ifdef DEBUG
printf("http_code=%d\n", s->http_code);
#endif
} else {
while (*p != '\0' && *p != ':')
p++;
if (*p != ':')
return 1;
*p = '\0';
tag = line;
p++;
while (isspace(*p))
p++;
if (!strcmp(tag, "Location")) {
strcpy(s->location, p);
}
}
return 1;
}
static int http_connect(URLContext *h, const char *path)
{
HTTPContext *s = h->priv_data;
int post, err, ch;
char line[1024], *q;
/* send http header */
post = h->flags & URL_WRONLY;
snprintf(s->buffer, sizeof(s->buffer),
"%s %s HTTP/1.0\n"
"User-Agent: FFmpeg %s\n"
"Accept: */*\n"
"\n",
post ? "POST" : "GET",
path,
FFMPEG_VERSION
);
if (http_write(h, s->buffer, strlen(s->buffer)) < 0)
return -EIO;
/* init input buffer */
s->buf_ptr = s->buffer;
s->buf_end = s->buffer;
s->line_count = 0;
s->location[0] = '\0';
if (post)
return 0;
/* wait for header */
q = line;
for(;;) {
ch = http_getc(s);
if (ch < 0)
return -EIO;
if (ch == '\n') {
/* process line */
if (q > line && q[-1] == '\r')
q--;
*q = '\0';
#ifdef DEBUG
printf("header='%s'\n", line);
#endif
err = process_line(s, line, s->line_count);
if (err < 0)
return err;
if (err == 0)
return 0;
s->line_count++;
q = line;
} else {
if ((q - line) < sizeof(line) - 1)
*q++ = ch;
}
}
}
static int http_read(URLContext *h, UINT8 *buf, int size)
{
HTTPContext *s = h->priv_data;
int size1, len;
size1 = size;
while (size > 0) {
/* read bytes from input buffer first */
len = s->buf_end - s->buf_ptr;
if (len > 0) {
if (len > size)
len = size;
memcpy(buf, s->buf_ptr, len);
s->buf_ptr += len;
} else {
len = read (s->fd, buf, size);
if (len < 0) {
if (errno != EINTR && errno != EAGAIN)
return -errno;
else
continue;
} else if (len == 0) {
break;
}
}
size -= len;
buf += len;
}
return size1 - size;
}
/* used only when posting data */
static int http_write(URLContext *h, UINT8 *buf, int size)
{
HTTPContext *s = h->priv_data;
int ret, size1;
size1 = size;
while (size > 0) {
ret = write (s->fd, buf, size);
if (ret < 0 && errno != EINTR && errno != EAGAIN)
return -errno;
size -= ret;
buf += ret;
}
return size1 - size;
}
static int http_close(URLContext *h)
{
HTTPContext *s = h->priv_data;
close(s->fd);
return 0;
}
URLProtocol http_protocol = {
"http",
http_open,
http_read,
http_write,
NULL, /* seek */
http_close,
};

578
libav/img.c Normal file
View File

@ -0,0 +1,578 @@
/*
* Image format
* Copyright (c) 2000, 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <math.h>
#include "avformat.h"
#define IMGFMT_YUV 1
#define IMGFMT_PGMYUV 2
#define IMGFMT_PGM 3
typedef struct {
int width;
int height;
int img_number;
int img_size;
int img_fmt;
int is_pipe;
char path[1024];
} VideoData;
static inline int pnm_space(int c)
{
return (c==' ' || c=='\n' || c=='\r' || c=='\t');
}
static void pnm_get(ByteIOContext *f, char *str, int buf_size)
{
char *s;
int c;
do {
c=get_byte(f);
if (c=='#') {
do {
c=get_byte(f);
} while (c!='\n');
c=get_byte(f);
}
} while (pnm_space(c));
s=str;
do {
if (url_feof(f))
break;
if ((s - str) < buf_size - 1)
*s++=c;
c=get_byte(f);
} while (!pnm_space(c));
*s = '\0';
}
static int pgm_read(VideoData *s, ByteIOContext *f, UINT8 *buf, int size, int is_yuv)
{
int width, height, i;
char buf1[32];
UINT8 *picture[3];
width = s->width;
height = s->height;
pnm_get(f, buf1, sizeof(buf1));
if (strcmp(buf1, "P5")) {
return -EIO;
}
pnm_get(f, buf1, sizeof(buf1));
pnm_get(f, buf1, sizeof(buf1));
pnm_get(f, buf1, sizeof(buf1));
picture[0] = buf;
picture[1] = buf + width * height;
picture[2] = buf + width * height + (width * height / 4);
get_buffer(f, picture[0], width * height);
height>>=1;
width>>=1;
if (is_yuv) {
for(i=0;i<height;i++) {
get_buffer(f, picture[1] + i * width, width);
get_buffer(f, picture[2] + i * width, width);
}
} else {
for(i=0;i<height;i++) {
memset(picture[1] + i * width, 128, width);
memset(picture[2] + i * width, 128, width);
}
}
return 0;
}
static int yuv_read(VideoData *s, const char *filename, UINT8 *buf, int size1)
{
ByteIOContext pb1, *pb = &pb1;
char fname[1024], *p;
int size;
size = s->width * s->height;
strcpy(fname, filename);
p = strrchr(fname, '.');
if (!p || p[1] != 'Y')
return -EIO;
if (url_fopen(pb, fname, URL_RDONLY) < 0)
return -EIO;
get_buffer(pb, buf, size);
url_fclose(pb);
p[1] = 'U';
if (url_fopen(pb, fname, URL_RDONLY) < 0)
return -EIO;
get_buffer(pb, buf + size, size / 4);
url_fclose(pb);
p[1] = 'V';
if (url_fopen(pb, fname, URL_RDONLY) < 0)
return -EIO;
get_buffer(pb, buf + size + (size / 4), size / 4);
url_fclose(pb);
return 0;
}
int img_read_packet(AVFormatContext *s1, AVPacket *pkt)
{
VideoData *s = s1->priv_data;
char filename[1024];
int ret;
ByteIOContext f1, *f;
snprintf(filename, sizeof(filename), s->path, s->img_number);
if (!s->is_pipe) {
f = &f1;
if (url_fopen(f, filename, URL_RDONLY) < 0)
return -EIO;
} else {
f = &s1->pb;
if (url_feof(f))
return -EIO;
}
av_new_packet(pkt, s->img_size);
pkt->stream_index = 0;
switch(s->img_fmt) {
case IMGFMT_PGMYUV:
ret = pgm_read(s, f, pkt->data, pkt->size, 1);
break;
case IMGFMT_PGM:
ret = pgm_read(s, f, pkt->data, pkt->size, 0);
break;
case IMGFMT_YUV:
ret = yuv_read(s, filename, pkt->data, pkt->size);
break;
default:
return -EIO;
}
if (!s->is_pipe) {
url_fclose(f);
}
if (ret < 0) {
av_free_packet(pkt);
return -EIO; /* signal EOF */
} else {
s->img_number++;
return 0;
}
}
static int sizes[][2] = {
{ 640, 480 },
{ 720, 480 },
{ 720, 576 },
{ 352, 288 },
{ 352, 240 },
{ 160, 128 },
{ 512, 384 },
{ 640, 352 },
};
static int infer_size(int *width_ptr, int *height_ptr, int size)
{
int i;
for(i=0;i<sizeof(sizes)/sizeof(sizes[0]);i++) {
if ((sizes[i][0] * sizes[i][1]) == size) {
*width_ptr = sizes[i][0];
*height_ptr = sizes[i][1];
return 0;
}
}
return -1;
}
static int img_read_header(AVFormatContext *s1, AVFormatParameters *ap)
{
VideoData *s;
int i, h;
char buf[1024];
char buf1[32];
ByteIOContext pb1, *f = &pb1;
AVStream *st;
s = malloc(sizeof(VideoData));
if (!s)
return -ENOMEM;
s1->priv_data = s;
s1->nb_streams = 1;
st = av_mallocz(sizeof(AVStream));
if (!st) {
free(s);
return -ENOMEM;
}
s1->streams[0] = st;
strcpy(s->path, s1->filename);
s->img_number = 0;
/* find format */
if (s1->format->flags & AVFMT_NOFILE)
s->is_pipe = 0;
else
s->is_pipe = 1;
if (s1->format == &pgmpipe_format ||
s1->format == &pgmyuv_format)
s->img_fmt = IMGFMT_PGMYUV;
else if (s1->format == &pgm_format)
s->img_fmt = IMGFMT_PGM;
else if (s1->format == &imgyuv_format)
s->img_fmt = IMGFMT_YUV;
else
goto fail;
if (!s->is_pipe) {
/* try to find the first image */
for(i=0;i<5;i++) {
snprintf(buf, sizeof(buf), s->path, s->img_number);
if (url_fopen(f, buf, URL_RDONLY) >= 0)
break;
s->img_number++;
}
if (i == 5)
goto fail;
} else {
f = &s1->pb;
}
/* find the image size */
/* XXX: use generic file format guessing, as mpeg */
switch(s->img_fmt) {
case IMGFMT_PGM:
case IMGFMT_PGMYUV:
pnm_get(f, buf1, sizeof(buf1));
pnm_get(f, buf1, sizeof(buf1));
s->width = atoi(buf1);
pnm_get(f, buf1, sizeof(buf1));
h = atoi(buf1);
if (s->img_fmt == IMGFMT_PGMYUV)
h = (h * 2) / 3;
s->height = h;
if (s->width <= 0 ||
s->height <= 0 ||
(s->width % 2) != 0 ||
(s->height % 2) != 0) {
goto fail1;
}
break;
case IMGFMT_YUV:
/* infer size by using the file size. */
{
int img_size;
URLContext *h;
/* XXX: hack hack */
h = url_fileno(f);
img_size = lseek((int)h->priv_data, 0, SEEK_END);
if (infer_size(&s->width, &s->height, img_size) < 0) {
goto fail1;
}
}
break;
}
if (!s->is_pipe) {
url_fclose(f);
} else {
url_fseek(f, 0, SEEK_SET);
}
s->img_size = (s->width * s->height * 3) / 2;
st->codec.codec_type = CODEC_TYPE_VIDEO;
st->codec.codec_id = CODEC_ID_RAWVIDEO;
st->codec.width = s->width;
st->codec.height = s->height;
st->codec.pix_fmt = PIX_FMT_YUV420P;
if (!ap || !ap->frame_rate)
st->codec.frame_rate = 25 * FRAME_RATE_BASE;
else
st->codec.frame_rate = ap->frame_rate;
return 0;
fail1:
if (!s->is_pipe)
url_fclose(f);
fail:
free(s);
return -EIO;
}
static int img_read_close(AVFormatContext *s1)
{
VideoData *s = s1->priv_data;
free(s);
return 0;
}
/******************************************************/
/* image output */
int pgm_save(AVPicture *picture, int width, int height, ByteIOContext *pb, int is_yuv)
{
int i, h;
char buf[100];
UINT8 *ptr, *ptr1, *ptr2;
h = height;
if (is_yuv)
h = (height * 3) / 2;
snprintf(buf, sizeof(buf),
"P5\n%d %d\n%d\n",
width, h, 255);
put_buffer(pb, buf, strlen(buf));
ptr = picture->data[0];
for(i=0;i<height;i++) {
put_buffer(pb, ptr, width);
ptr += picture->linesize[0];
}
if (is_yuv) {
height >>= 1;
width >>= 1;
ptr1 = picture->data[1];
ptr2 = picture->data[2];
for(i=0;i<height;i++) {
put_buffer(pb, ptr1, width);
put_buffer(pb, ptr2, width);
ptr1 += picture->linesize[1];
ptr2 += picture->linesize[2];
}
}
put_flush_packet(pb);
return 0;
}
static int yuv_save(AVPicture *picture, int width, int height, const char *filename)
{
ByteIOContext pb1, *pb = &pb1;
char fname[1024], *p;
int i, j;
UINT8 *ptr;
static char *ext = "YUV";
strcpy(fname, filename);
p = strrchr(fname, '.');
if (!p || p[1] != 'Y')
return -EIO;
for(i=0;i<3;i++) {
if (i == 1) {
width >>= 1;
height >>= 1;
}
p[1] = ext[i];
if (url_fopen(pb, fname, URL_WRONLY) < 0)
return -EIO;
ptr = picture->data[i];
for(j=0;j<height;j++) {
put_buffer(pb, ptr, width);
ptr += picture->linesize[i];
}
put_flush_packet(pb);
url_fclose(pb);
}
return 0;
}
static int img_write_header(AVFormatContext *s)
{
VideoData *img;
img = av_mallocz(sizeof(VideoData));
if (!img)
return -1;
s->priv_data = img;
img->img_number = 1;
strcpy(img->path, s->filename);
/* find format */
if (s->format->flags & AVFMT_NOFILE)
img->is_pipe = 0;
else
img->is_pipe = 1;
if (s->format == &pgmpipe_format ||
s->format == &pgmyuv_format)
img->img_fmt = IMGFMT_PGMYUV;
else if (s->format == &pgm_format)
img->img_fmt = IMGFMT_PGM;
else if (s->format == &imgyuv_format)
img->img_fmt = IMGFMT_YUV;
else
goto fail;
return 0;
fail:
free(img);
return -EIO;
}
static int img_write_packet(AVFormatContext *s, int stream_index,
UINT8 *buf, int size)
{
VideoData *img = s->priv_data;
AVStream *st = s->streams[stream_index];
ByteIOContext pb1, *pb;
AVPicture picture;
int width, height, ret, size1;
char filename[1024];
width = st->codec.width;
height = st->codec.height;
size1 = (width * height * 3) / 2;
if (size != size1)
return -EIO;
picture.data[0] = buf;
picture.data[1] = picture.data[0] + width * height;
picture.data[2] = picture.data[1] + (width * height) / 4;
picture.linesize[0] = width;
picture.linesize[1] = width >> 1;
picture.linesize[2] = width >> 1;
snprintf(filename, sizeof(filename), img->path, img->img_number);
if (!img->is_pipe) {
pb = &pb1;
if (url_fopen(pb, filename, URL_WRONLY) < 0)
return -EIO;
} else {
pb = &s->pb;
}
switch(img->img_fmt) {
case IMGFMT_PGMYUV:
ret = pgm_save(&picture, width, height, pb, 1);
break;
case IMGFMT_PGM:
ret = pgm_save(&picture, width, height, pb, 0);
break;
case IMGFMT_YUV:
ret = yuv_save(&picture, width, height, filename);
break;
}
if (!img->is_pipe) {
url_fclose(pb);
}
img->img_number++;
return 0;
}
static int img_write_trailer(AVFormatContext *s)
{
VideoData *img = s->priv_data;
free(img);
return 0;
}
AVFormat pgm_format = {
"pgm",
"pgm image format",
"",
"pgm",
CODEC_ID_NONE,
CODEC_ID_RAWVIDEO,
img_write_header,
img_write_packet,
img_write_trailer,
img_read_header,
img_read_packet,
img_read_close,
NULL,
AVFMT_NOFILE,
};
AVFormat pgmyuv_format = {
"pgmyuv",
"pgm with YUV content image format",
"",
"pgm",
CODEC_ID_NONE,
CODEC_ID_RAWVIDEO,
img_write_header,
img_write_packet,
img_write_trailer,
img_read_header,
img_read_packet,
img_read_close,
NULL,
AVFMT_NOFILE,
};
AVFormat imgyuv_format = {
".Y.U.V",
".Y.U.V format",
"",
"Y",
CODEC_ID_NONE,
CODEC_ID_RAWVIDEO,
img_write_header,
img_write_packet,
img_write_trailer,
img_read_header,
img_read_packet,
img_read_close,
NULL,
AVFMT_NOFILE,
};
AVFormat pgmpipe_format = {
"pgmpipe",
"PGM pipe format",
"",
"pgm",
CODEC_ID_NONE,
CODEC_ID_RAWVIDEO,
img_write_header,
img_write_packet,
img_write_trailer,
img_read_header,
img_read_packet,
img_read_close,
NULL,
};

102
libav/jpegenc.c Normal file
View File

@ -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 "avformat.h"
/* Multipart JPEG */
#define BOUNDARY_TAG "ffserver"
static int mpjpeg_write_header(AVFormatContext *s)
{
UINT8 buf1[256];
snprintf(buf1, sizeof(buf1), "--%s\n", BOUNDARY_TAG);
put_buffer(&s->pb, buf1, strlen(buf1));
put_flush_packet(&s->pb);
return 0;
}
static int mpjpeg_write_packet(AVFormatContext *s,
int stream_index, UINT8 *buf, int size)
{
UINT8 buf1[256];
snprintf(buf1, sizeof(buf1), "Content-type: image/jpeg\n\n");
put_buffer(&s->pb, buf1, strlen(buf1));
put_buffer(&s->pb, buf, size);
snprintf(buf1, sizeof(buf1), "\n--%s\n", BOUNDARY_TAG);
put_buffer(&s->pb, buf1, strlen(buf1));
put_flush_packet(&s->pb);
return 0;
}
static int mpjpeg_write_trailer(AVFormatContext *s)
{
return 0;
}
AVFormat mpjpeg_format = {
"mpjpeg",
"Mime multipart JPEG format",
"multipart/x-mixed-replace;boundary=" BOUNDARY_TAG,
"mjpg",
CODEC_ID_NONE,
CODEC_ID_MJPEG,
mpjpeg_write_header,
mpjpeg_write_packet,
mpjpeg_write_trailer,
};
/* single frame JPEG */
static int jpeg_write_header(AVFormatContext *s)
{
return 0;
}
static int jpeg_write_packet(AVFormatContext *s, int stream_index,
UINT8 *buf, int size)
{
put_buffer(&s->pb, buf, size);
put_flush_packet(&s->pb);
return 1; /* no more data can be sent */
}
static int jpeg_write_trailer(AVFormatContext *s)
{
return 0;
}
AVFormat jpeg_format = {
"jpeg",
"JPEG image",
"image/jpeg",
"jpg,jpeg",
CODEC_ID_NONE,
CODEC_ID_MJPEG,
jpeg_write_header,
jpeg_write_packet,
jpeg_write_trailer,
};

663
libav/mpeg.c Normal file
View File

@ -0,0 +1,663 @@
/*
* 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 <string.h>
#include <errno.h>
#include <sys/time.h>
#include "avformat.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; /* in bytes */
int packet_number;
float pts;
INT64 start_pts;
} StreamInfo;
typedef struct {
int packet_size; /* required packet size */
int packet_data_max_size; /* maximum data size inside a packet */
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 audio_bound;
int video_bound;
} 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)
/* mpeg2 */
#define PROGRAM_STREAM_MAP 0x1bc
#define PRIVATE_STREAM_1 0x1bd
#define PADDING_STREAM 0x1be
#define PRIVATE_STREAM_2 0x1bf
#define AUDIO_ID 0xc0
#define VIDEO_ID 0xe0
static int put_pack_header(AVFormatContext *ctx,
UINT8 *buf, long long timestamp)
{
MpegMuxContext *s = ctx->priv_data;
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);
put_bits(&pb, 1, 1);
flush_put_bits(&pb);
return pb.buf_ptr - pb.buf;
}
static int put_system_header(AVFormatContext *ctx, UINT8 *buf)
{
MpegMuxContext *s = ctx->priv_data;
int size, rate_bound, i, private_stream_coded, id;
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 */
put_bits(&pb, 6, s->audio_bound);
put_bits(&pb, 1, 1); /* variable bitrate */
put_bits(&pb, 1, 1); /* non constrainted bit stream */
put_bits(&pb, 1, 0); /* audio locked */
put_bits(&pb, 1, 0); /* video locked */
put_bits(&pb, 1, 1); /* marker */
put_bits(&pb, 5, s->video_bound);
put_bits(&pb, 8, 0xff); /* reserved byte */
/* audio stream info */
private_stream_coded = 0;
for(i=0;i<ctx->nb_streams;i++) {
StreamInfo *stream = ctx->streams[i]->priv_data;
id = stream->id;
if (id < 0xc0) {
/* special case for private streams (AC3 use that) */
if (private_stream_coded)
continue;
private_stream_coded = 1;
id = 0xbd;
}
put_bits(&pb, 8, id); /* stream ID */
put_bits(&pb, 2, 3);
if (id < 0xe0) {
/* audio */
put_bits(&pb, 1, 0);
put_bits(&pb, 13, stream->max_buffer_size / 128);
} else {
/* video */
put_bits(&pb, 1, 1);
put_bits(&pb, 13, stream->max_buffer_size / 1024);
}
}
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;
}
static int mpeg_mux_init(AVFormatContext *ctx)
{
MpegMuxContext *s;
int bitrate, i, mpa_id, mpv_id, ac3_id;
AVStream *st;
StreamInfo *stream;
s = malloc(sizeof(MpegMuxContext));
if (!s)
return -1;
memset(s, 0, sizeof(MpegMuxContext));
ctx->priv_data = s;
s->packet_number = 0;
/* XXX: hardcoded */
s->packet_size = 2048;
/* startcode(4) + length(2) + flags(1) */
s->packet_data_max_size = s->packet_size - 7;
s->audio_bound = 0;
s->video_bound = 0;
mpa_id = AUDIO_ID;
ac3_id = 0x80;
mpv_id = VIDEO_ID;
for(i=0;i<ctx->nb_streams;i++) {
st = ctx->streams[i];
stream = av_mallocz(sizeof(StreamInfo));
if (!stream)
goto fail;
st->priv_data = stream;
switch(st->codec.codec_type) {
case CODEC_TYPE_AUDIO:
if (st->codec.codec_id == CODEC_ID_AC3)
stream->id = ac3_id++;
else
stream->id = mpa_id++;
stream->max_buffer_size = 4 * 1024;
s->audio_bound++;
break;
case CODEC_TYPE_VIDEO:
stream->id = mpv_id++;
stream->max_buffer_size = 46 * 1024;
s->video_bound++;
break;
}
}
/* we increase slightly the bitrate to take into account the
headers. XXX: compute it exactly */
bitrate = 2000;
for(i=0;i<ctx->nb_streams;i++) {
st = ctx->streams[i];
bitrate += st->codec.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<ctx->nb_streams;i++) {
stream = ctx->streams[i]->priv_data;
stream->buffer_ptr = 0;
stream->packet_number = 0;
stream->pts = 0;
stream->start_pts = -1;
}
return 0;
fail:
for(i=0;i<ctx->nb_streams;i++) {
free(ctx->streams[i]->priv_data);
}
free(s);
return -ENOMEM;
}
/* flush the packet on stream stream_index */
static void flush_packet(AVFormatContext *ctx, int stream_index)
{
MpegMuxContext *s = ctx->priv_data;
StreamInfo *stream = ctx->streams[stream_index]->priv_data;
UINT8 *buf_ptr;
int size, payload_size, startcode, id, len, stuffing_size, i;
INT64 timestamp;
UINT8 buffer[128];
id = stream->id;
timestamp = stream->start_pts;
#if 0
printf("packet ID=%2x PTS=%0.3f\n",
id, timestamp / 90000.0);
#endif
buf_ptr = buffer;
if ((s->packet_number % s->pack_header_freq) == 0) {
/* output pack and systems header if needed */
size = put_pack_header(ctx, buf_ptr, timestamp);
buf_ptr += size;
if ((s->packet_number % s->system_header_freq) == 0) {
size = put_system_header(ctx, buf_ptr);
buf_ptr += size;
}
}
size = buf_ptr - buffer;
put_buffer(&ctx->pb, buffer, size);
/* packet header */
payload_size = s->packet_size - (size + 6 + 5);
if (id < 0xc0) {
startcode = PRIVATE_STREAM_1;
payload_size -= 4;
} else {
startcode = 0x100 + id;
}
stuffing_size = payload_size - stream->buffer_ptr;
if (stuffing_size < 0)
stuffing_size = 0;
put_be32(&ctx->pb, startcode);
put_be16(&ctx->pb, payload_size + 5);
/* stuffing */
for(i=0;i<stuffing_size;i++)
put_byte(&ctx->pb, 0xff);
/* presentation time stamp */
put_byte(&ctx->pb,
(0x02 << 4) |
(((timestamp >> 30) & 0x07) << 1) |
1);
put_be16(&ctx->pb, (((timestamp >> 15) & 0x7fff) << 1) | 1);
put_be16(&ctx->pb, (((timestamp) & 0x7fff) << 1) | 1);
if (startcode == PRIVATE_STREAM_1) {
put_byte(&ctx->pb, id);
if (id >= 0x80 && id <= 0xbf) {
/* XXX: need to check AC3 spec */
put_byte(&ctx->pb, 1);
put_byte(&ctx->pb, 0);
put_byte(&ctx->pb, 2);
}
}
/* output data */
put_buffer(&ctx->pb, stream->buffer, payload_size - stuffing_size);
put_flush_packet(&ctx->pb);
/* preserve remaining data */
len = stream->buffer_ptr - payload_size;
if (len < 0)
len = 0;
memmove(stream->buffer, stream->buffer + stream->buffer_ptr - len, len);
stream->buffer_ptr = len;
s->packet_number++;
stream->packet_number++;
stream->start_pts = -1;
}
static int mpeg_mux_write_packet(AVFormatContext *ctx,
int stream_index, UINT8 *buf, int size)
{
MpegMuxContext *s = ctx->priv_data;
AVStream *st = ctx->streams[stream_index];
StreamInfo *stream = st->priv_data;
int len;
while (size > 0) {
/* set pts */
if (stream->start_pts == -1)
stream->start_pts = stream->pts * 90000.0;
len = s->packet_data_max_size - stream->buffer_ptr;
if (len > size)
len = size;
memcpy(stream->buffer + stream->buffer_ptr, buf, len);
stream->buffer_ptr += len;
buf += len;
size -= len;
while (stream->buffer_ptr >= s->packet_data_max_size) {
/* output the packet */
if (stream->start_pts == -1)
stream->start_pts = stream->pts * 90000.0;
flush_packet(ctx, stream_index);
}
}
if (st->codec.codec_type == CODEC_TYPE_AUDIO) {
stream->pts += (float)st->codec.frame_size / st->codec.sample_rate;
} else {
stream->pts += FRAME_RATE_BASE / (float)st->codec.frame_rate;
}
return 0;
}
static int mpeg_mux_end(AVFormatContext *ctx)
{
StreamInfo *stream;
int i;
/* flush each packet */
for(i=0;i<ctx->nb_streams;i++) {
stream = ctx->streams[i]->priv_data;
if (stream->buffer_ptr > 0)
flush_packet(ctx, i);
}
/* write the end header */
put_be32(&ctx->pb, ISO_11172_END_CODE);
put_flush_packet(&ctx->pb);
return 0;
}
/*********************************************/
/* demux code */
#define MAX_SYNC_SIZE 100000
typedef struct MpegDemuxContext {
int header_state;
int mux_rate; /* 50 byte/s unit */
} MpegDemuxContext;
static int find_start_code(ByteIOContext *pb, int *size_ptr,
UINT32 *header_state)
{
unsigned int state, v;
int val, n;
state = *header_state;
n = *size_ptr;
while (n > 0) {
if (url_feof(pb))
break;
v = get_byte(pb);
n--;
if (state == 0x000001) {
state = ((state << 8) | v) & 0xffffff;
val = state;
goto found;
}
state = ((state << 8) | v) & 0xffffff;
}
val = -1;
found:
*header_state = state;
*size_ptr = n;
return val;
}
static int mpeg_mux_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
MpegDemuxContext *m;
int size, startcode, c, rate_bound, audio_bound, video_bound, mux_rate, val;
int codec_id, n, i, type;
AVStream *st;
m = av_mallocz(sizeof(MpegDemuxContext));
if (!m)
return -ENOMEM;
s->priv_data = m;
/* search first pack header */
m->header_state = 0xff;
size = MAX_SYNC_SIZE;
for(;;) {
while (size > 0) {
startcode = find_start_code(&s->pb, &size, &m->header_state);
if (startcode == PACK_START_CODE)
goto found;
}
return -ENODATA;
found:
/* search system header just after pack header */
/* parse pack header */
get_byte(&s->pb); /* ts1 */
get_be16(&s->pb); /* ts2 */
get_be16(&s->pb); /* ts3 */
mux_rate = get_byte(&s->pb) << 16;
mux_rate |= get_byte(&s->pb) << 8;
mux_rate |= get_byte(&s->pb);
mux_rate &= (1 << 22) - 1;
m->mux_rate = mux_rate;
startcode = find_start_code(&s->pb, &size, &m->header_state);
if (startcode == SYSTEM_HEADER_START_CODE)
break;
}
size = get_be16(&s->pb);
rate_bound = get_byte(&s->pb) << 16;
rate_bound |= get_byte(&s->pb) << 8;
rate_bound |= get_byte(&s->pb);
rate_bound = (rate_bound >> 1) & ((1 << 22) - 1);
audio_bound = get_byte(&s->pb) >> 2;
video_bound = get_byte(&s->pb) & 0x1f;
get_byte(&s->pb); /* reserved byte */
#if 0
printf("mux_rate=%d kbit/s\n", (m->mux_rate * 50 * 8) / 1000);
printf("rate_bound=%d\n", rate_bound);
printf("audio_bound=%d\n", audio_bound);
printf("video_bound=%d\n", video_bound);
#endif
size -= 6;
s->nb_streams = 0;
while (size > 0) {
c = get_byte(&s->pb);
size--;
if ((c & 0x80) == 0)
break;
val = get_be16(&s->pb);
size -= 2;
if (c >= 0xc0 && c <= 0xdf) {
/* mpeg audio stream */
type = CODEC_TYPE_AUDIO;
codec_id = CODEC_ID_MP2;
n = 1;
c = c | 0x100;
} else if (c >= 0xe0 && c <= 0xef) {
type = CODEC_TYPE_VIDEO;
codec_id = CODEC_ID_MPEG1VIDEO;
n = 1;
c = c | 0x100;
} else if (c == 0xb8) {
/* all audio streams */
/* XXX: hack for DVD: we force AC3, although we do not
know that this codec will be used */
type = CODEC_TYPE_AUDIO;
codec_id = CODEC_ID_AC3;
n = audio_bound;
c = 0x80;
/* c = 0x1c0; */
} else if (c == 0xb9) {
/* all video streams */
type = CODEC_TYPE_VIDEO;
codec_id = CODEC_ID_MPEG1VIDEO;
n = video_bound;
c = 0x1e0;
} else {
type = 0;
codec_id = 0;
n = 0;
}
for(i=0;i<n;i++) {
st = av_mallocz(sizeof(AVStream));
if (!st)
return -ENOMEM;
s->streams[s->nb_streams++] = st;
st->id = c + i;
st->codec.codec_type = type;
st->codec.codec_id = codec_id;
}
}
return 0;
}
static INT64 get_pts(ByteIOContext *pb, int c)
{
INT64 pts;
int val;
if (c < 0)
c = get_byte(pb);
pts = (INT64)((c >> 1) & 0x07) << 30;
val = get_be16(pb);
pts |= (INT64)(val >> 1) << 15;
val = get_be16(pb);
pts |= (INT64)(val >> 1);
return pts;
}
static int mpeg_mux_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
MpegDemuxContext *m = s->priv_data;
AVStream *st;
int len, size, startcode, i, c, flags, header_len;
INT64 pts, dts;
/* next start code (should be immediately after */
redo:
m->header_state = 0xff;
size = MAX_SYNC_SIZE;
startcode = find_start_code(&s->pb, &size, &m->header_state);
// printf("startcode=%x pos=0x%Lx\n", startcode, url_ftell(&s->pb));
if (startcode < 0)
return -EIO;
if (startcode == PACK_START_CODE)
goto redo;
if (startcode == SYSTEM_HEADER_START_CODE)
goto redo;
if (startcode == PADDING_STREAM ||
startcode == PRIVATE_STREAM_2) {
/* skip them */
len = get_be16(&s->pb);
url_fskip(&s->pb, len);
goto redo;
}
/* find matching stream */
if (!((startcode >= 0x1c0 && startcode <= 0x1df) ||
(startcode >= 0x1e0 && startcode <= 0x1ef) ||
(startcode == 0x1bd)))
goto redo;
len = get_be16(&s->pb);
pts = 0;
dts = 0;
/* stuffing */
for(;;) {
c = get_byte(&s->pb);
len--;
/* XXX: for mpeg1, should test only bit 7 */
if (c != 0xff)
break;
}
if ((c & 0xc0) == 0x40) {
/* buffer scale & size */
get_byte(&s->pb);
c = get_byte(&s->pb);
len -= 2;
}
if ((c & 0xf0) == 0x20) {
pts = get_pts(&s->pb, c);
len -= 4;
dts = pts;
} else if ((c & 0xf0) == 0x30) {
pts = get_pts(&s->pb, c);
dts = get_pts(&s->pb, -1);
len -= 9;
} else if ((c & 0xc0) == 0x80) {
/* mpeg 2 PES */
if ((c & 0x30) != 0) {
fprintf(stderr, "Encrypted multiplex not handled\n");
return -EIO;
}
flags = get_byte(&s->pb);
header_len = get_byte(&s->pb);
len -= 2;
if (header_len > len)
goto redo;
if ((flags & 0xc0) == 0x40) {
pts = get_pts(&s->pb, -1);
dts = pts;
header_len -= 5;
len -= 5;
} if ((flags & 0xc0) == 0xc0) {
pts = get_pts(&s->pb, -1);
dts = get_pts(&s->pb, -1);
header_len -= 10;
len -= 10;
}
len -= header_len;
while (header_len > 0) {
get_byte(&s->pb);
header_len--;
}
}
if (startcode == 0x1bd) {
startcode = get_byte(&s->pb);
len--;
if (startcode >= 0x80 && startcode <= 0xbf) {
/* audio: skip header */
get_byte(&s->pb);
get_byte(&s->pb);
get_byte(&s->pb);
len -= 3;
}
}
/* now find stream */
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
if (st->id == startcode)
goto found;
}
/* skip packet */
url_fskip(&s->pb, len);
goto redo;
found:
av_new_packet(pkt, len);
get_buffer(&s->pb, pkt->data, pkt->size);
pkt->pts = pts;
pkt->stream_index = i;
return 0;
}
static int mpeg_mux_read_close(AVFormatContext *s)
{
MpegDemuxContext *m = s->priv_data;
free(m);
return 0;
}
AVFormat mpeg_mux_format = {
"mpeg",
"MPEG multiplex format",
"video/x-mpeg",
"mpg,mpeg,vob",
CODEC_ID_MP2,
CODEC_ID_MPEG1VIDEO,
mpeg_mux_init,
mpeg_mux_write_packet,
mpeg_mux_end,
mpeg_mux_read_header,
mpeg_mux_read_packet,
mpeg_mux_read_close,
};

288
libav/raw.c Normal file
View File

@ -0,0 +1,288 @@
/*
* RAW encoder and decoder
* Copyright (c) 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include "avformat.h"
/* simple formats */
int raw_write_header(struct AVFormatContext *s)
{
return 0;
}
int raw_write_packet(struct AVFormatContext *s,
int stream_index,
unsigned char *buf, int size)
{
put_buffer(&s->pb, buf, size);
put_flush_packet(&s->pb);
return 0;
}
int raw_write_trailer(struct AVFormatContext *s)
{
return 0;
}
/* raw input */
static int raw_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
AVStream *st;
st = malloc(sizeof(AVStream));
if (!st)
return -1;
s->nb_streams = 1;
s->streams[0] = st;
st->id = 0;
if (ap) {
if (s->format->audio_codec != CODEC_ID_NONE) {
st->codec.codec_type = CODEC_TYPE_AUDIO;
st->codec.codec_id = s->format->audio_codec;
} else if (s->format->video_codec != CODEC_ID_NONE) {
st->codec.codec_type = CODEC_TYPE_VIDEO;
st->codec.codec_id = s->format->video_codec;
} else {
free(st);
return -1;
}
switch(st->codec.codec_type) {
case CODEC_TYPE_AUDIO:
st->codec.sample_rate = ap->sample_rate;
st->codec.channels = ap->channels;
/* XXX: endianness */
break;
case CODEC_TYPE_VIDEO:
st->codec.frame_rate = ap->frame_rate;
st->codec.width = ap->width;
st->codec.height = ap->height;
break;
default:
abort();
break;
}
} else {
abort();
}
return 0;
}
#define MIN_SIZE 1024
int raw_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
int packet_size, n, ret;
if (url_feof(&s->pb))
return -EIO;
packet_size = url_get_packet_size(&s->pb);
n = MIN_SIZE / packet_size;
if (n <= 0)
n = 1;
if (av_new_packet(pkt, n * packet_size) < 0)
return -EIO;
pkt->stream_index = 0;
ret = get_buffer(&s->pb, pkt->data, pkt->size);
if (ret < 0)
av_free_packet(pkt);
return ret;
}
int raw_read_close(AVFormatContext *s)
{
return 0;
}
/* mp3 read */
static int mp3_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
AVStream *st;
st = malloc(sizeof(AVStream));
if (!st)
return -1;
s->nb_streams = 1;
s->streams[0] = st;
st->id = 0;
st->codec.codec_type = CODEC_TYPE_AUDIO;
st->codec.codec_id = CODEC_ID_MP2;
/* XXX: read the first frame and extract rate and channels */
st->codec.sample_rate = 44100;
st->codec.channels = 2;
return 0;
}
/* mpeg1/h263 input */
static int video_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
AVStream *st;
st = av_mallocz(sizeof(AVStream));
if (!st)
return -1;
s->nb_streams = 1;
s->streams[0] = st;
st->codec.codec_type = CODEC_TYPE_VIDEO;
st->codec.codec_id = s->format->video_codec;
return 0;
}
AVFormat mp2_format = {
"mp2",
"MPEG audio",
"audio/x-mpeg",
"mp2,mp3",
CODEC_ID_MP2,
0,
raw_write_header,
raw_write_packet,
raw_write_trailer,
mp3_read_header,
raw_read_packet,
raw_read_close,
};
AVFormat ac3_format = {
"ac3",
"raw ac3",
"audio/x-ac3",
"ac3",
CODEC_ID_AC3,
0,
raw_write_header,
raw_write_packet,
raw_write_trailer,
};
AVFormat h263_format = {
"h263",
"raw h263",
"video/x-h263",
"h263",
0,
CODEC_ID_H263,
raw_write_header,
raw_write_packet,
raw_write_trailer,
video_read_header,
raw_read_packet,
raw_read_close,
};
AVFormat mpeg1video_format = {
"mpegvideo",
"MPEG video",
"video/x-mpeg",
"mpg,mpeg",
0,
CODEC_ID_MPEG1VIDEO,
raw_write_header,
raw_write_packet,
raw_write_trailer,
video_read_header,
raw_read_packet,
raw_read_close,
};
AVFormat pcm_format = {
"pcm",
"pcm raw format",
NULL,
"sw",
CODEC_ID_PCM,
0,
raw_write_header,
raw_write_packet,
raw_write_trailer,
raw_read_header,
raw_read_packet,
raw_read_close,
};
int rawvideo_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
int packet_size, ret, width, height;
AVStream *st = s->streams[0];
width = st->codec.width;
height = st->codec.height;
switch(st->codec.pix_fmt) {
case PIX_FMT_YUV420P:
packet_size = (width * height * 3) / 2;
break;
case PIX_FMT_YUV422:
packet_size = (width * height * 2);
break;
case PIX_FMT_BGR24:
case PIX_FMT_RGB24:
packet_size = (width * height * 3);
break;
default:
abort();
break;
}
if (av_new_packet(pkt, packet_size) < 0)
return -EIO;
pkt->stream_index = 0;
/* bypass buffered I/O */
ret = url_read(url_fileno(&s->pb), pkt->data, pkt->size);
if (ret != pkt->size) {
av_free_packet(pkt);
return -EIO;
} else {
return 0;
}
}
AVFormat rawvideo_format = {
"rawvideo",
"raw video format",
NULL,
"yuv",
CODEC_ID_NONE,
CODEC_ID_RAWVIDEO,
raw_write_header,
raw_write_packet,
raw_write_trailer,
raw_read_header,
rawvideo_read_packet,
raw_read_close,
};

710
libav/rm.c Normal file
View File

@ -0,0 +1,710 @@
/*
* "Real" compatible mux and demux.
* Copyright (c) 2000, 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include "avformat.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;
AVCodecContext *enc;
} StreamInfo;
typedef struct {
StreamInfo streams[2];
StreamInfo *audio_stream, *video_stream;
int data_pos; /* position of the data after the header */
int nb_packets;
} RMContext;
static void put_str(ByteIOContext *s, const char *tag)
{
put_be16(s,strlen(tag));
while (*tag) {
put_byte(s, *tag++);
}
}
static void put_str8(ByteIOContext *s, const char *tag)
{
put_byte(s, strlen(tag));
while (*tag) {
put_byte(s, *tag++);
}
}
static void rv10_write_header(AVFormatContext *ctx,
int data_size, int index_pos)
{
RMContext *rm = ctx->priv_data;
ByteIOContext *s = &ctx->pb;
StreamInfo *stream;
unsigned char *data_offset_ptr, *start_ptr;
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_be32(s,18); /* header size */
put_be16(s,0);
put_be32(s,0);
put_be32(s,4 + ctx->nb_streams); /* num headers */
put_tag(s,"PROP");
put_be32(s, 50);
put_be16(s, 0);
packet_max_size = 0;
packet_total_size = 0;
nb_packets = 0;
bit_rate = 0;
duration = 0;
for(i=0;i<ctx->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_be32(s, bit_rate); /* max bit rate */
put_be32(s, bit_rate); /* avg bit rate */
put_be32(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_be32(s, packet_avg_size); /* avg packet size */
put_be32(s, nb_packets); /* num packets */
put_be32(s, duration); /* duration */
put_be32(s, BUFFER_DURATION); /* preroll */
put_be32(s, index_pos); /* index offset */
/* computation of data the data offset */
data_offset_ptr = s->buf_ptr;
put_be32(s, 0); /* data offset : will be patched after */
put_be16(s, ctx->nb_streams); /* num streams */
flags = 1 | 2; /* save allowed & perfect play */
if (url_is_streamed(s))
flags |= 4; /* live broadcast */
put_be16(s, flags);
/* comments */
put_tag(s,"CONT");
size = strlen(ctx->title) + strlen(ctx->author) + strlen(ctx->copyright) +
strlen(ctx->comment) + 4 * 2 + 10;
put_be32(s,size);
put_be16(s,0);
put_str(s, ctx->title);
put_str(s, ctx->author);
put_str(s, ctx->copyright);
put_str(s, ctx->comment);
for(i=0;i<ctx->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_be32(s, size);
put_be16(s, 0);
put_be16(s, i); /* stream number */
put_be32(s, stream->bit_rate); /* max bit rate */
put_be32(s, stream->bit_rate); /* avg bit rate */
put_be32(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_be32(s, packet_avg_size); /* avg packet size */
put_be32(s, 0); /* start time */
put_be32(s, BUFFER_DURATION); /* preroll */
/* duration */
put_be32(s, (int)(stream->total_frames * 1000 / stream->frame_rate));
put_str8(s, desc);
put_str8(s, mimetype);
put_be32(s, codec_data_size);
if (stream->enc->codec_type == CODEC_TYPE_AUDIO) {
int coded_frame_size, fscode, sample_rate;
sample_rate = stream->enc->sample_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_be32(s, 0x00040000); /* version */
put_tag(s, ".ra4");
put_be32(s, 0x01b53530); /* stream length */
put_be16(s, 4); /* unknown */
put_be32(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_be16(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_be32(s, coded_frame_size); /* frame length */
put_be32(s, 0x51540); /* unknown */
put_be32(s, 0x249f0); /* unknown */
put_be32(s, 0x249f0); /* unknown */
put_be16(s, 0x01);
/* frame length : seems to be very important */
put_be16(s, coded_frame_size);
put_be32(s, 0); /* unknown */
put_be16(s, stream->enc->sample_rate); /* sample rate */
put_be32(s, 0x10); /* unknown */
put_be16(s, stream->enc->channels);
put_str8(s, "Int0"); /* codec name */
put_str8(s, "dnet"); /* codec name */
put_be16(s, 0); /* title length */
put_be16(s, 0); /* author length */
put_be16(s, 0); /* copyright length */
put_byte(s, 0); /* end of header */
} else {
/* video codec info */
put_be32(s,34); /* size */
put_tag(s,"VIDORV10");
put_be16(s, stream->enc->width);
put_be16(s, stream->enc->height);
put_be16(s, 24); /* frames per seconds ? */
put_be32(s,0); /* unknown meaning */
put_be16(s, 12); /* unknown meaning */
put_be32(s,0); /* unknown meaning */
put_be16(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_be32(s,0x10000000);
//put_be32(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_be32(s,data_size + 10 + 8);
put_be16(s,0);
put_be32(s, nb_packets); /* number of packets */
put_be32(s,0); /* next data header */
}
static void write_packet_header(AVFormatContext *ctx, StreamInfo *stream,
int length, int key_frame)
{
int timestamp;
ByteIOContext *s = &ctx->pb;
stream->nb_packets++;
stream->packet_total_size += length;
if (length > stream->packet_max_size)
stream->packet_max_size = length;
put_be16(s,0); /* version */
put_be16(s,length + 12);
put_be16(s, stream->num); /* stream number */
timestamp = (1000 * (float)stream->nb_frames) / stream->frame_rate;
put_be32(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;
AVCodecContext *codec;
rm = malloc(sizeof(RMContext));
if (!rm)
return -1;
memset(rm, 0, sizeof(RMContext));
s->priv_data = rm;
for(n=0;n<s->nb_streams;n++) {
s->streams[n]->id = n;
codec = &s->streams[n]->codec;
stream = &rm->streams[n];
memset(stream, 0, sizeof(StreamInfo));
stream->num = n;
stream->bit_rate = codec->bit_rate;
stream->enc = codec;
switch(codec->codec_type) {
case CODEC_TYPE_AUDIO:
rm->audio_stream = stream;
stream->frame_rate = (float)codec->sample_rate / (float)codec->frame_size;
/* XXX: dummy values */
stream->packet_max_size = 1024;
stream->nb_packets = 0;
stream->total_frames = stream->nb_packets;
break;
case CODEC_TYPE_VIDEO:
rm->video_stream = stream;
stream->frame_rate = (float)codec->frame_rate / (float)FRAME_RATE_BASE;
/* XXX: dummy values */
stream->packet_max_size = 4096;
stream->nb_packets = 0;
stream->total_frames = stream->nb_packets;
break;
}
}
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;
ByteIOContext *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;
ByteIOContext *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_be16(pb, 0x4000 | (size)); /* total frame size */
put_be16(pb, 0x4000 | (size)); /* offset from the start or the end */
#else
/* full frame */
write_packet_header(s, size + 6);
put_byte(pb, 0xc0);
put_be16(pb, 0x4000 | size); /* total frame size */
put_be16(pb, 0x4000 + packet_number * 126); /* position in stream */
#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_packet(AVFormatContext *s, int stream_index,
UINT8 *buf, int size)
{
if (s->streams[stream_index]->codec.codec_type ==
CODEC_TYPE_AUDIO)
return rm_write_audio(s, buf, size);
else
return rm_write_video(s, buf, size);
}
static int rm_write_trailer(AVFormatContext *s)
{
RMContext *rm = s->priv_data;
int data_size, index_pos, i;
ByteIOContext *pb = &s->pb;
if (!url_is_streamed(&s->pb)) {
/* end of file: finish to write header */
index_pos = url_fseek(pb, 0, SEEK_CUR);
data_size = index_pos - rm->data_pos;
/* index */
put_tag(pb, "INDX");
put_be32(pb, 10 + 10 * s->nb_streams);
put_be16(pb, 0);
for(i=0;i<s->nb_streams;i++) {
put_be32(pb, 0); /* zero indices */
put_be16(pb, i); /* stream number */
put_be32(pb, 0); /* next index */
}
/* undocumented end header */
put_be32(pb, 0);
put_be32(pb, 0);
url_fseek(pb, 0, SEEK_SET);
for(i=0;i<s->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_be32(pb, 0);
put_be32(pb, 0);
}
put_flush_packet(pb);
free(rm);
return 0;
}
/***************************************************/
static void get_str(ByteIOContext *pb, char *buf, int buf_size)
{
int len, i;
char *q;
len = get_be16(pb);
q = buf;
for(i=0;i<len;i++) {
if (i < buf_size - 1)
*q++ = get_byte(pb);
}
*q = '\0';
}
static void get_str8(ByteIOContext *pb, char *buf, int buf_size)
{
int len, i;
char *q;
len = get_byte(pb);
q = buf;
for(i=0;i<len;i++) {
if (i < buf_size - 1)
*q++ = get_byte(pb);
}
*q = '\0';
}
static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
RMContext *rm;
AVStream *st;
ByteIOContext *pb = &s->pb;
unsigned int tag, v;
int tag_size, size, codec_data_size, i;
INT64 codec_pos;
unsigned int h263_hack_version;
char buf[128];
if (get_le32(pb) != MKTAG('.', 'R', 'M', 'F'))
return -EIO;
rm = av_mallocz(sizeof(RMContext));
if (!rm)
return -ENOMEM;
s->priv_data = rm;
get_be32(pb); /* header size */
get_be16(pb);
get_be32(pb);
get_be32(pb); /* number of headers */
for(;;) {
if (url_feof(pb))
goto fail;
tag = get_le32(pb);
tag_size = get_be32(pb);
get_be16(pb);
#if 0
printf("tag=%c%c%c%c (%08x) size=%d\n",
(tag) & 0xff,
(tag >> 8) & 0xff,
(tag >> 16) & 0xff,
(tag >> 24) & 0xff,
tag,
tag_size);
#endif
if (tag_size < 10)
goto fail;
switch(tag) {
case MKTAG('P', 'R', 'O', 'P'):
/* file header */
get_be32(pb); /* max bit rate */
get_be32(pb); /* avg bit rate */
get_be32(pb); /* max packet size */
get_be32(pb); /* avg packet size */
get_be32(pb); /* nb packets */
get_be32(pb); /* duration */
get_be32(pb); /* preroll */
get_be32(pb); /* index offset */
get_be32(pb); /* data offset */
get_be16(pb); /* nb streams */
get_be16(pb); /* flags */
break;
case MKTAG('C', 'O', 'N', 'T'):
get_str(pb, s->title, sizeof(s->title));
get_str(pb, s->author, sizeof(s->author));
get_str(pb, s->copyright, sizeof(s->copyright));
get_str(pb, s->comment, sizeof(s->comment));
break;
case MKTAG('M', 'D', 'P', 'R'):
st = av_mallocz(sizeof(AVStream));
if (!st)
goto fail;
s->streams[s->nb_streams++] = st;
st->id = get_be16(pb);
get_be32(pb); /* max bit rate */
st->codec.bit_rate = get_be32(pb); /* bit rate */
get_be32(pb); /* max packet size */
get_be32(pb); /* avg packet size */
get_be32(pb); /* start time */
get_be32(pb); /* preroll */
get_be32(pb); /* duration */
get_str8(pb, buf, sizeof(buf)); /* desc */
get_str8(pb, buf, sizeof(buf)); /* mimetype */
codec_data_size = get_be32(pb);
codec_pos = url_ftell(pb);
v = get_be32(pb);
if (v == MKTAG(0xfd, 'a', 'r', '.')) {
/* ra type header */
get_be32(pb); /* version */
get_be32(pb); /* .ra4 */
get_be32(pb);
get_be16(pb);
get_be32(pb); /* header size */
get_be16(pb); /* add codec info */
get_be32(pb); /* coded frame size */
get_be32(pb); /* ??? */
get_be32(pb); /* ??? */
get_be32(pb); /* ??? */
get_be16(pb); /* 1 */
get_be16(pb); /* coded frame size */
get_be32(pb);
st->codec.sample_rate = get_be16(pb);
get_be32(pb);
st->codec.channels = get_be16(pb);
get_str8(pb, buf, sizeof(buf)); /* desc */
get_str8(pb, buf, sizeof(buf)); /* desc */
st->codec.codec_type = CODEC_TYPE_AUDIO;
if (!strcmp(buf, "dnet")) {
st->codec.codec_id = CODEC_ID_AC3;
} else {
st->codec.codec_id = CODEC_ID_NONE;
nstrcpy(st->codec.codec_name, sizeof(st->codec.codec_name),
buf);
}
} else {
if (get_le32(pb) != MKTAG('V', 'I', 'D', 'O')) {
fail1:
fprintf(stderr, "Unsupported video codec\n");
goto fail;
}
st->codec.codec_tag = get_le32(pb);
if (st->codec.codec_tag != MKTAG('R', 'V', '1', '0'))
goto fail1;
st->codec.width = get_be16(pb);
st->codec.height = get_be16(pb);
st->codec.frame_rate = get_be16(pb) * FRAME_RATE_BASE;
st->codec.codec_type = CODEC_TYPE_VIDEO;
get_be32(pb);
get_be16(pb);
get_be32(pb);
get_be16(pb);
/* modification of h263 codec version (!) */
h263_hack_version = get_be32(pb);
switch(h263_hack_version) {
case 0x10000000:
st->codec.sub_id = 0;
st->codec.codec_id = CODEC_ID_RV10;
break;
case 0x10003000:
case 0x10003001:
st->codec.sub_id = 3;
st->codec.codec_id = CODEC_ID_RV10;
break;
default:
/* not handled */
st->codec.codec_id = CODEC_ID_NONE;
break;
}
}
/* skip codec info */
size = url_ftell(pb) - codec_pos;
url_fskip(pb, codec_data_size - size);
break;
case MKTAG('D', 'A', 'T', 'A'):
goto header_end;
default:
/* unknown tag: skip it */
url_fskip(pb, tag_size - 10);
break;
}
}
header_end:
rm->nb_packets = get_be32(pb); /* number of packets */
get_be32(pb); /* next data header */
return 0;
fail:
for(i=0;i<s->nb_streams;i++) {
free(s->streams[i]);
}
return -EIO;
}
static int rm_read_packet(AVFormatContext *s, AVPacket *pkt)
{
RMContext *rm = s->priv_data;
ByteIOContext *pb = &s->pb;
AVStream *st;
int len, num, timestamp, i, tmp, j;
UINT8 *ptr;
redo:
if (rm->nb_packets == 0)
return -EIO;
get_be16(pb);
len = get_be16(pb);
if (len < 12)
return -EIO;
num = get_be16(pb);
timestamp = get_be32(pb);
get_byte(pb); /* reserved */
get_byte(pb); /* flags */
rm->nb_packets--;
len -= 12;
st = NULL;
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
if (num == st->id)
break;
}
if (i == s->nb_streams) {
/* skip packet if unknown number */
url_fskip(pb, len);
goto redo;
}
av_new_packet(pkt, len);
pkt->stream_index = i;
get_buffer(pb, pkt->data, len);
/* for AC3, needs to swap bytes */
if (st->codec.codec_id == CODEC_ID_AC3) {
ptr = pkt->data;
for(j=0;j<len;j+=2) {
tmp = ptr[0];
ptr[0] = ptr[1];
ptr[1] = tmp;
ptr += 2;
}
}
return 0;
}
static int rm_read_close(AVFormatContext *s)
{
RMContext *rm = s->priv_data;
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_packet,
rm_write_trailer,
rm_read_header,
rm_read_packet,
rm_read_close,
};

552
libav/swf.c Normal file
View File

@ -0,0 +1,552 @@
/*
* 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 <string.h>
#include <errno.h>
#include "avformat.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_STREAMHEAD 18
#define TAG_STREAMBLOCK 19
#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;
ByteIOContext *pb = &s->pb;
swf->tag_pos = url_ftell(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;
ByteIOContext *pb = &s->pb;
long long pos;
int tag_len, tag;
pos = url_ftell(pb);
tag_len = pos - swf->tag_pos - 2;
tag = swf->tag;
url_fseek(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);
}
url_fseek(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(ByteIOContext *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(ByteIOContext *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);
}
/* XXX: handle audio only */
static int swf_write_header(AVFormatContext *s)
{
SWFContext *swf;
ByteIOContext *pb = &s->pb;
AVCodecContext *enc, *audio_enc, *video_enc;
PutBitContext p;
UINT8 buf1[256];
int i, width, height, rate;
swf = malloc(sizeof(SWFContext));
if (!swf)
return -1;
s->priv_data = swf;
video_enc = NULL;
audio_enc = NULL;
for(i=0;i<s->nb_streams;i++) {
enc = &s->streams[i]->codec;
if (enc->codec_type == CODEC_TYPE_AUDIO)
audio_enc = enc;
else
video_enc = enc;
}
if (!video_enc) {
/* currenty, cannot work correctly if audio only */
width = 320;
height = 200;
rate = 10 * FRAME_RATE_BASE;
} else {
width = video_enc->width;
height = video_enc->height;
rate = video_enc->frame_rate;
}
put_tag(pb, "FWS");
put_byte(pb, 4); /* 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, width, 0, height);
put_le16(pb, (rate * 256) / FRAME_RATE_BASE); /* frame rate */
swf->duration_pos = url_ftell(pb);
put_le16(pb, DUMMY_DURATION * (INT64)rate / FRAME_RATE_BASE); /* 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, width, 0, 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, width, 0);
put_swf_line_edge(&p, 0, height);
put_swf_line_edge(&p, -width, 0);
put_swf_line_edge(&p, 0, -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);
if (audio_enc) {
int v;
/* start sound */
v = 0;
switch(audio_enc->sample_rate) {
case 11025:
v |= 1 << 2;
break;
case 22050:
v |= 2 << 2;
break;
case 44100:
v |= 3 << 2;
break;
default:
/* not supported */
free(swf);
return -1;
}
if (audio_enc->channels == 2)
v |= 1;
v |= 0x20; /* mp3 compressed */
v |= 0x02; /* 16 bits */
put_swf_tag(s, TAG_STREAMHEAD);
put_byte(&s->pb, 0);
put_byte(&s->pb, v);
put_le16(&s->pb, (audio_enc->sample_rate * FRAME_RATE_BASE) / rate); /* avg samples per frame */
put_swf_end_tag(s);
}
put_flush_packet(&s->pb);
return 0;
}
static int swf_write_video(AVFormatContext *s,
AVCodecContext *enc, UINT8 *buf, int size)
{
ByteIOContext *pb = &s->pb;
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_audio(AVFormatContext *s, UINT8 *buf, int size)
{
ByteIOContext *pb = &s->pb;
put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG);
put_buffer(pb, buf, size);
put_swf_end_tag(s);
put_flush_packet(&s->pb);
return 0;
}
static int swf_write_packet(AVFormatContext *s, int stream_index,
UINT8 *buf, int size)
{
AVCodecContext *codec = &s->streams[stream_index]->codec;
if (codec->codec_type == CODEC_TYPE_AUDIO)
return swf_write_audio(s, buf, size);
else
return swf_write_video(s, codec, buf, size);
}
static int swf_write_trailer(AVFormatContext *s)
{
SWFContext *swf = s->priv_data;
ByteIOContext *pb = &s->pb;
AVCodecContext *enc, *video_enc;
int file_size, i;
video_enc = NULL;
for(i=0;i<s->nb_streams;i++) {
enc = &s->streams[i]->codec;
if (enc->codec_type == CODEC_TYPE_VIDEO)
video_enc = 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 (!url_is_streamed(&s->pb) && video_enc) {
file_size = url_ftell(pb);
url_fseek(pb, 4, SEEK_SET);
put_le32(pb, file_size);
url_fseek(pb, swf->duration_pos, SEEK_SET);
put_le16(pb, video_enc->frame_number);
}
free(swf);
return 0;
}
/***********************************/
/* just to extract MP3 from swf */
static int get_swf_tag(ByteIOContext *pb, int *len_ptr)
{
int tag, len;
if (url_feof(pb))
return -1;
tag = get_le16(pb);
len = tag & 0x3f;
tag = tag >> 6;
if (len == 0x3f) {
len = get_le32(pb);
}
*len_ptr = len;
return tag;
}
static int swf_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
ByteIOContext *pb = &s->pb;
int nbits, len, frame_rate, tag, v;
AVStream *st;
if ((get_be32(pb) & 0xffffff00) != MKBETAG('F', 'W', 'S', 0))
return -EIO;
get_le32(pb);
/* skip rectangle size */
nbits = get_byte(pb) >> 3;
len = (4 * nbits - 3 + 7) / 8;
url_fskip(pb, len);
frame_rate = get_le16(pb);
get_le16(pb); /* frame count */
for(;;) {
tag = get_swf_tag(pb, &len);
if (tag < 0) {
fprintf(stderr, "No streaming found in SWF\n");
return -EIO;
}
if (tag == TAG_STREAMHEAD) {
/* streaming found */
get_byte(pb);
v = get_byte(pb);
get_le16(pb);
/* if mp3 streaming found, OK */
if ((v & 0x20) != 0) {
st = av_mallocz(sizeof(AVStream));
if (!st)
return -ENOMEM;
if (v & 0x01)
st->codec.channels = 2;
else
st->codec.channels = 1;
s->nb_streams = 1;
s->streams[0] = st;
switch((v>> 2) & 0x03) {
case 1:
st->codec.sample_rate = 11025;
break;
case 2:
st->codec.sample_rate = 22050;
break;
case 3:
st->codec.sample_rate = 44100;
break;
default:
free(st);
return -EIO;
}
st->codec.codec_type = CODEC_TYPE_AUDIO;
st->codec.codec_id = CODEC_ID_MP2;
break;
}
} else {
url_fskip(pb, len);
}
}
return 0;
}
static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
{
ByteIOContext *pb = &s->pb;
int tag, len;
for(;;) {
tag = get_swf_tag(pb, &len);
if (tag < 0)
return -EIO;
if (tag == TAG_STREAMBLOCK) {
av_new_packet(pkt, len);
get_buffer(pb, pkt->data, pkt->size);
break;
} else {
url_fskip(pb, len);
}
}
return 0;
}
static int swf_read_close(AVFormatContext *s)
{
return 0;
}
AVFormat swf_format = {
"swf",
"Flash format",
"application/x-shockwave-flash",
"swf",
CODEC_ID_MP2,
CODEC_ID_MJPEG,
swf_write_header,
swf_write_packet,
swf_write_trailer,
swf_read_header,
swf_read_packet,
swf_read_close,
};

148
libav/udp.c Normal file
View File

@ -0,0 +1,148 @@
/*
* UDP prototype streaming system
* Copyright (c) 2000 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "avformat.h"
typedef struct {
int udp_socket;
int max_payload_size; /* in bytes */
} UDPContext;
#define UDP_TX_BUF_SIZE 32768
/* put it in UDP context */
static struct sockaddr_in dest_addr;
/* return non zero if error */
static int udp_open(URLContext *h, const char *uri, int flags)
{
int local_port = 0;
struct sockaddr_in my_addr;
const char *p, *q;
char hostname[1024];
int port, udp_socket, tmp;
struct hostent *hp;
UDPContext *s;
h->is_streamed = 1;
if (!(flags & URL_WRONLY))
return -EIO;
/* fill the dest addr */
p = uri;
if (!strstart(p, "udp:", &p))
return -1;
q = strchr(p, ':');
if (!q)
return -1;
memcpy(hostname, p, q - p);
hostname[q - p] = '\0';
port = strtol(q+1, NULL, 10);
if (port <= 0)
return -1;
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port);
if ((inet_aton(hostname, &dest_addr.sin_addr)) == 0) {
hp = gethostbyname(hostname);
if (!hp)
return -1;
memcpy ((char *) &dest_addr.sin_addr, hp->h_addr, hp->h_length);
}
udp_socket = socket(PF_INET, SOCK_DGRAM, 0);
if (udp_socket < 0)
return -1;
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(local_port);
my_addr.sin_addr.s_addr = htonl (INADDR_ANY);
/* the bind is needed to give a port to the socket now */
if (bind(udp_socket,(struct sockaddr *)&my_addr, sizeof(my_addr)) < 0)
goto fail;
/* limit the tx buf size to limit latency */
tmp = UDP_TX_BUF_SIZE;
if (setsockopt(udp_socket, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) {
perror("setsockopt sndbuf");
goto fail;
}
s = malloc(sizeof(UDPContext));
if (!s)
return -ENOMEM;
h->priv_data = s;
s->udp_socket = udp_socket;
h->packet_size = 1500;
return 0;
fail:
return -EIO;
}
int udp_close(URLContext *h)
{
UDPContext *s = h->priv_data;
close(s->udp_socket);
return 0;
}
int udp_write(URLContext *h, UINT8 *buf, int size)
{
UDPContext *s = h->priv_data;
int ret, len, size1;
/* primitive way to avoid big packets */
size1 = size;
while (size > 0) {
len = size;
if (len > h->packet_size)
len = h->packet_size;
ret = sendto (s->udp_socket, buf, len, 0,
(struct sockaddr *) &dest_addr,
sizeof (dest_addr));
if (ret < 0)
perror("sendto");
buf += len;
size -= len;
}
return size1 - size;
}
URLProtocol udp_protocol = {
"udp",
udp_open,
NULL, /* read */
udp_write,
NULL, /* seek */
udp_close,
};

533
libav/utils.c Normal file
View File

@ -0,0 +1,533 @@
/*
* Various utilities for ffmpeg system
* Copyright (c) 2000,2001 Gerard Lantau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <time.h>
#include "avformat.h"
AVFormat *first_format;
void register_avformat(AVFormat *format)
{
AVFormat **p;
p = &first_format;
while (*p != NULL) p = &(*p)->next;
*p = format;
format->next = NULL;
}
int match_ext(const char *filename, const char *extensions)
{
const char *ext, *p;
char ext1[32], *q;
ext = strrchr(filename, '.');
if (ext) {
ext++;
p = extensions;
for(;;) {
q = ext1;
while (*p != '\0' && *p != ',')
*q++ = *p++;
*q = '\0';
if (!strcasecmp(ext1, ext))
return 1;
if (*p == '\0')
break;
p++;
}
}
return 0;
}
AVFormat *guess_format(const char *short_name, const char *filename, const char *mime_type)
{
AVFormat *fmt, *fmt_found;
int score_max, score;
/* 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 &&
match_ext(filename, fmt->extensions)) {
score += 5;
}
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;
}
void nstrcpy(char *buf, int buf_size, const char *str)
{
int c;
char *q = buf;
for(;;) {
c = *str++;
if (c == 0 || q >= buf + buf_size - 1)
break;
*q++ = c;
}
*q = '\0';
}
void register_all(void)
{
avcodec_init();
avcodec_register_all();
avcodec_register_more();
register_avformat(&mp2_format);
register_avformat(&ac3_format);
register_avformat(&mpeg_mux_format);
register_avformat(&mpeg1video_format);
register_avformat(&h263_format);
register_avformat(&rm_format);
register_avformat(&asf_format);
register_avformat(&avi_format);
register_avformat(&mpjpeg_format);
register_avformat(&jpeg_format);
register_avformat(&swf_format);
register_avformat(&wav_format);
register_avformat(&pcm_format);
register_avformat(&rawvideo_format);
register_avformat(&ffm_format);
register_avformat(&pgm_format);
register_avformat(&pgmyuv_format);
register_avformat(&imgyuv_format);
register_avformat(&pgmpipe_format);
register_protocol(&file_protocol);
register_protocol(&pipe_protocol);
register_protocol(&audio_protocol);
register_protocol(&video_protocol);
register_protocol(&udp_protocol);
register_protocol(&http_protocol);
}
/* memory handling */
int av_new_packet(AVPacket *pkt, int size)
{
pkt->data = malloc(size);
if (!pkt->data)
return -ENOMEM;
pkt->size = size;
/* sane state */
pkt->pts = 0;
pkt->stream_index = 0;
pkt->flags = 0;
return 0;
}
void av_free_packet(AVPacket *pkt)
{
free(pkt->data);
/* fail safe */
pkt->data = NULL;
pkt->size = 0;
}
/* fifo handling */
int fifo_init(FifoBuffer *f, int size)
{
f->buffer = malloc(size);
if (!f->buffer)
return -1;
f->end = f->buffer + size;
f->wptr = f->rptr = f->buffer;
return 0;
}
void fifo_free(FifoBuffer *f)
{
free(f->buffer);
}
int fifo_size(FifoBuffer *f, UINT8 *rptr)
{
int size;
if (f->wptr >= rptr) {
size = f->wptr - rptr;
} else {
size = (f->end - rptr) + (f->wptr - f->buffer);
}
return size;
}
/* get data from the fifo (return -1 if not enough data) */
int fifo_read(FifoBuffer *f, UINT8 *buf, int buf_size, UINT8 **rptr_ptr)
{
UINT8 *rptr = *rptr_ptr;
int size, len;
if (f->wptr >= rptr) {
size = f->wptr - rptr;
} else {
size = (f->end - rptr) + (f->wptr - f->buffer);
}
if (size < buf_size)
return -1;
while (buf_size > 0) {
len = f->end - rptr;
if (len > buf_size)
len = buf_size;
memcpy(buf, rptr, len);
buf += len;
rptr += len;
if (rptr >= f->end)
rptr = f->buffer;
buf_size -= len;
}
*rptr_ptr = rptr;
return 0;
}
void fifo_write(FifoBuffer *f, UINT8 *buf, int size, UINT8 **wptr_ptr)
{
int len;
UINT8 *wptr;
wptr = *wptr_ptr;
while (size > 0) {
len = f->end - wptr;
if (len > size)
len = size;
memcpy(wptr, buf, len);
wptr += len;
if (wptr >= f->end)
wptr = f->buffer;
buf += len;
size -= len;
}
*wptr_ptr = wptr;
}
/* media file handling */
AVFormatContext *av_open_input_file(const char *filename, int buf_size)
{
AVFormatParameters params, *ap;
AVFormat *fmt;
AVFormatContext *ic = NULL;
URLFormat url_format;
int err;
ic = av_mallocz(sizeof(AVFormatContext));
if (!ic)
goto fail;
if (url_fopen(&ic->pb, filename, URL_RDONLY) < 0)
goto fail;
if (buf_size > 0) {
url_setbufsize(&ic->pb, buf_size);
}
/* find format */
err = url_getformat(url_fileno(&ic->pb), &url_format);
if (err >= 0) {
fmt = guess_format(url_format.format_name, NULL, NULL);
ap = &params;
ap->sample_rate = url_format.sample_rate;
ap->frame_rate = url_format.frame_rate;
ap->channels = url_format.channels;
ap->width = url_format.width;
ap->height = url_format.height;
ap->pix_fmt = url_format.pix_fmt;
} else {
fmt = guess_format(NULL, filename, NULL);
ap = NULL;
}
if (!fmt || !fmt->read_header) {
return NULL;
}
ic->format = fmt;
err = ic->format->read_header(ic, ap);
if (err < 0) {
url_fclose(&ic->pb);
goto fail;
}
return ic;
fail:
if (ic)
free(ic);
return NULL;
}
int av_read_packet(AVFormatContext *s, AVPacket *pkt)
{
AVPacketList *pktl;
pktl = s->packet_buffer;
if (pktl) {
/* read packet from packet buffer, if there is data */
*pkt = pktl->pkt;
s->packet_buffer = pktl->next;
free(pktl);
return 0;
} else {
return s->format->read_packet(s, pkt);
}
}
void av_close_input_file(AVFormatContext *s)
{
int i;
if (s->format->read_close)
s->format->read_close(s);
for(i=0;i<s->nb_streams;i++) {
free(s->streams[i]);
}
if (s->packet_buffer) {
AVPacketList *p, *p1;
p = s->packet_buffer;
while (p != NULL) {
p1 = p->next;
av_free_packet(&p->pkt);
free(p);
p = p1;
}
s->packet_buffer = NULL;
}
url_fclose(&s->pb);
free(s);
}
int av_write_packet(AVFormatContext *s, AVPacket *pkt)
{
/* XXX: currently, an emulation because internal API must change */
return s->format->write_packet(s, pkt->stream_index, pkt->data, pkt->size);
}
/* "user interface" functions */
void dump_format(AVFormatContext *ic,
int index,
const char *url,
int is_output)
{
int i;
char buf[256];
fprintf(stderr, "%s #%d, %s, %s '%s':\n",
is_output ? "Output" : "Input",
index, ic->format->name,
is_output ? "to" : "from", url);
for(i=0;i<ic->nb_streams;i++) {
AVStream *st = ic->streams[i];
avcodec_string(buf, sizeof(buf), &st->codec, is_output);
fprintf(stderr, " Stream #%d.%d: %s\n", index, i, buf);
}
}
typedef struct {
const char *str;
int width, height;
} SizeEntry;
static SizeEntry sizes[] = {
{ "sqcif", 128, 96 },
{ "qcif", 176, 144 },
{ "cif", 352, 288 },
{ "4cif", 704, 576 },
};
int parse_image_size(int *width_ptr, int *height_ptr, const char *str)
{
int i;
int n = sizeof(sizes) / sizeof(SizeEntry);
const char *p;
int frame_width = 0, frame_height = 0;
for(i=0;i<n;i++) {
if (!strcmp(sizes[i].str, str)) {
frame_width = sizes[i].width;
frame_height = sizes[i].height;
break;
}
}
if (i == n) {
p = str;
frame_width = strtol(p, (char **)&p, 10);
if (*p)
p++;
frame_height = strtol(p, (char **)&p, 10);
}
if (frame_width <= 0 || frame_height <= 0)
return -1;
*width_ptr = frame_width;
*height_ptr = frame_height;
return 0;
}
INT64 gettime(void)
{
struct timeval tv;
gettimeofday(&tv,NULL);
return (INT64)tv.tv_sec * 1000000 + tv.tv_usec;
}
/* syntax: [YYYY-MM-DD ][[HH:]MM:]SS[.m...] . Return the date in micro seconds since 1970 */
INT64 parse_date(const char *datestr, int duration)
{
const char *p;
INT64 t;
int sec;
p = datestr;
if (!duration) {
static const UINT8 months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int year, month, day, i;
if (strlen(p) >= 5 && p[4] == '-') {
year = strtol(p, (char **)&p, 10);
if (*p)
p++;
month = strtol(p, (char **)&p, 10) - 1;
if (*p)
p++;
day = strtol(p, (char **)&p, 10) - 1;
if (*p)
p++;
day += (year - 1970) * 365;
/* if >= March, take February of current year into account too */
if (month >= 2)
year++;
for(i=1970;i<year;i++) {
if ((i % 100) == 0) {
if ((i % 400) == 0) day++;
} else if ((i % 4) == 0) {
day++;
}
}
for(i=0;i<month;i++)
day += months[i];
} else {
day = (time(NULL) / (3600 * 24));
}
t = day * (3600 * 24);
} else {
t = 0;
}
sec = 0;
for(;;) {
int val;
val = strtol(p, (char **)&p, 10);
sec = sec * 60 + val;
if (*p != ':')
break;
p++;
}
t = (t + sec) * 1000000;
if (*p == '.') {
int val, n;
p++;
n = strlen(p);
if (n > 6)
n = 6;
val = strtol(p, NULL, 10);
while (n < 6) {
val = val * 10;
n++;
}
t += val;
}
return t;
}
/* syntax: '?tag1=val1&tag2=val2...'. No URL decoding is done. Return
1 if found */
int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info)
{
const char *p;
char tag[128], *q;
p = info;
if (*p == '?')
p++;
for(;;) {
q = tag;
while (*p != '\0' && *p != '=' && *p != '&') {
if ((q - tag) < sizeof(tag) - 1)
*q++ = *p;
p++;
}
*q = '\0';
q = arg;
if (*p == '=') {
p++;
while (*p != '&' && *p != '\0') {
if ((q - arg) < arg_size - 1)
*q++ = *p;
p++;
}
*q = '\0';
}
if (!strcmp(tag, tag1))
return 1;
if (*p != '&')
break;
}
return 0;
}

211
libav/wav.c Normal file
View File

@ -0,0 +1,211 @@
/*
* WAV encoder and decoder
* Copyright (c) 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include "avformat.h"
#include "avi.h"
typedef struct {
offset_t data;
} WAVContext;
static int wav_write_header(AVFormatContext *s)
{
WAVContext *wav;
ByteIOContext *pb = &s->pb;
offset_t fmt;
wav = malloc(sizeof(WAVContext));
if (!wav)
return -1;
memset(wav, 0, sizeof(WAVContext));
s->priv_data = wav;
put_tag(pb, "RIFF");
put_le32(pb, 0); /* file length */
put_tag(pb, "WAVE");
/* format header */
fmt = start_tag(pb, "fmt ");
put_wav_header(pb, &s->streams[0]->codec);
end_tag(pb, fmt);
/* data header */
wav->data = start_tag(pb, "data");
put_flush_packet(pb);
return 0;
}
static int wav_write_packet(AVFormatContext *s, int stream_index_ptr,
UINT8 *buf, int size)
{
ByteIOContext *pb = &s->pb;
put_buffer(pb, buf, size);
return 0;
}
static int wav_write_trailer(AVFormatContext *s)
{
ByteIOContext *pb = &s->pb;
WAVContext *wav = s->priv_data;
offset_t file_size;
if (!url_is_streamed(&s->pb)) {
end_tag(pb, wav->data);
/* update file size */
file_size = url_ftell(pb);
url_fseek(pb, 4, SEEK_SET);
put_le32(pb, file_size);
url_fseek(pb, file_size, SEEK_SET);
put_flush_packet(pb);
}
free(wav);
return 0;
}
/* return the size of the found tag */
/* XXX: > 2GB ? */
static int find_tag(ByteIOContext *pb, int tag1)
{
unsigned int tag;
int size;
for(;;) {
if (url_feof(pb))
return -1;
tag = get_le32(pb);
size = get_le32(pb);
if (tag == tag1)
break;
url_fseek(pb, size, SEEK_CUR);
}
if (size < 0)
size = 0x7fffffff;
return size;
}
/* wav input */
static int wav_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
int size;
unsigned int tag;
ByteIOContext *pb = &s->pb;
unsigned int id, channels, rate, bit_rate, extra_size;
AVStream *st;
/* check RIFF header */
tag = get_le32(pb);
if (tag != MKTAG('R', 'I', 'F', 'F'))
return -1;
get_le32(pb); /* file size */
tag = get_le32(pb);
if (tag != MKTAG('W', 'A', 'V', 'E'))
return -1;
/* parse fmt header */
size = find_tag(pb, MKTAG('f', 'm', 't', ' '));
if (size < 0)
return -1;
id = get_le16(pb);
channels = get_le16(pb);
rate = get_le32(pb);
bit_rate = get_le32(pb) * 8;
get_le16(pb); /* block align */
get_le16(pb); /* bits per sample */
if (size >= 18) {
/* wav_extra_size */
extra_size = get_le16(pb);
/* skip unused data */
url_fseek(pb, size - 18, SEEK_CUR);
}
size = find_tag(pb, MKTAG('d', 'a', 't', 'a'));
if (size < 0)
return -1;
/* now we are ready: build format streams */
st = malloc(sizeof(AVStream));
if (!st)
return -1;
s->nb_streams = 1;
s->streams[0] = st;
st->id = 0;
st->codec.codec_type = CODEC_TYPE_AUDIO;
st->codec.codec_tag = id;
st->codec.codec_id = codec_get_id(codec_wav_tags, id);
st->codec.channels = channels;
st->codec.sample_rate = rate;
return 0;
}
#define MAX_SIZE 4096
static int wav_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
int packet_size, n, ret;
if (url_feof(&s->pb))
return -EIO;
packet_size = url_get_packet_size(&s->pb);
n = MAX_SIZE / packet_size;
if (n <= 0)
return n = 1;
if (av_new_packet(pkt, n * packet_size))
return -EIO;
pkt->stream_index = 0;
ret = get_buffer(&s->pb, pkt->data, pkt->size);
if (ret < 0)
av_free_packet(pkt);
return ret;
}
static int wav_read_close(AVFormatContext *s)
{
return 0;
}
AVFormat wav_format = {
"wav",
"wav format",
"audio/x-wav",
"wav",
CODEC_ID_PCM,
CODEC_ID_NONE,
wav_write_header,
wav_write_packet,
wav_write_trailer,
wav_read_header,
wav_read_packet,
wav_read_close,
};

59
libavcodec/Makefile Normal file
View File

@ -0,0 +1,59 @@
include ../config.mk
CFLAGS= -O2 -Wall -g
LDFLAGS= -g
OBJS= common.o utils.o mpegvideo.o h263.o jrevdct.o jfdctfst.o \
mpegaudio.o ac3enc.o mjpegenc.o resample.o dsputil.o \
motion_est.o imgconvert.o imgresample.o msmpeg4.o \
mpeg12.o h263dec.o rv10.o
# currently using libac3 for ac3 decoding
OBJS+= ac3dec.o \
libac3/bit_allocate.o libac3/bitstream.o libac3/downmix.o \
libac3/imdct.o libac3/parse.o
# currently using mpglib for mpeg audio decoding
OBJS+= mpegaudiodec.o \
mpglib/layer1.o mpglib/layer2.o mpglib/layer3.o \
mpglib/dct64_i386.o mpglib/decode_i386.o mpglib/tabinit.o
# i386 mmx specific stuff
ifdef CONFIG_MMX
OBJS += i386/fdct_mmx.o i386/fdctdata.o i386/sad_mmx.o i386/cputest.o \
i386/dsputil_mmx.o
endif
LIB= libavcodec.a
TESTS= imgresample-test dct-test
all: $(LIB) apiexample
$(LIB): $(OBJS)
rm -f $@
$(AR) rcs $@ $(OBJS)
dsputil.o: dsputil.c dsputil.h
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
%.o: %.s
nasm -f elf -o $@ $<
clean:
rm -f *.o *~ *.a i386/*.o i386/*~ \
libac3/*.o libac3/*~ \
mpglib/*.o mpglib/*~ \
apiexample $(TESTS)
# api example program
apiexample: apiexample.c $(LIB)
$(CC) $(CFLAGS) -o $@ $< $(LIB) -lm
# testing progs
imgresample-test: imgresample.c
$(CC) $(CFLAGS) -DTEST -o $@ $^
dct-test: dct-test.o jfdctfst.o i386/fdct_mmx.o i386/fdctdata.o fdctref.o
$(CC) -o $@ $^

189
libavcodec/ac3dec.c Normal file
View File

@ -0,0 +1,189 @@
/*
* AC3 decoder
* Copyright (c) 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "avcodec.h"
#include <inttypes.h>
#include "libac3/ac3.h"
/* currently, I use libac3 which is Copyright (C) Aaron Holtzman and
released under the GPL license. I may reimplement it someday... */
typedef struct AC3DecodeState {
UINT8 inbuf[4096]; /* input buffer */
UINT8 *inbuf_ptr;
int frame_size;
int flags;
ac3_state_t state;
} AC3DecodeState;
static int ac3_decode_init(AVCodecContext *avctx)
{
AC3DecodeState *s = avctx->priv_data;
ac3_init ();
s->inbuf_ptr = s->inbuf;
s->frame_size = 0;
return 0;
}
stream_samples_t samples;
/**** the following two functions comes from ac3dec */
static inline int blah (int32_t i)
{
if (i > 0x43c07fff)
return 32767;
else if (i < 0x43bf8000)
return -32768;
else
return i - 0x43c00000;
}
static inline void float_to_int (float * _f, INT16 * s16)
{
int i;
int32_t * f = (int32_t *) _f; // XXX assumes IEEE float format
for (i = 0; i < 256; i++) {
s16[2*i] = blah (f[i]);
s16[2*i+1] = blah (f[i+256]);
}
}
static inline void float_to_int_mono (float * _f, INT16 * s16)
{
int i;
int32_t * f = (int32_t *) _f; // XXX assumes IEEE float format
for (i = 0; i < 256; i++) {
s16[i] = blah (f[i]);
}
}
/**** end */
#define HEADER_SIZE 7
static int ac3_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
UINT8 *buf, int buf_size)
{
AC3DecodeState *s = avctx->priv_data;
UINT8 *buf_ptr;
int flags, i, len;
int sample_rate, bit_rate;
short *out_samples = data;
float level;
*data_size = 0;
buf_ptr = buf;
while (buf_size > 0) {
len = s->inbuf_ptr - s->inbuf;
if (s->frame_size == 0) {
/* no header seen : find one. We need at least 7 bytes to parse it */
len = HEADER_SIZE - len;
if (len > buf_size)
len = buf_size;
memcpy(s->inbuf_ptr, buf_ptr, len);
buf_ptr += len;
s->inbuf_ptr += len;
buf_size -= len;
if ((s->inbuf_ptr - s->inbuf) == HEADER_SIZE) {
len = ac3_syncinfo (s->inbuf, &s->flags, &sample_rate, &bit_rate);
if (len == 0) {
/* no sync found : move by one byte (inefficient, but simple!) */
memcpy(s->inbuf, s->inbuf + 1, HEADER_SIZE - 1);
s->inbuf_ptr--;
} else {
s->frame_size = len;
/* update codec info */
avctx->sample_rate = sample_rate;
if ((s->flags & AC3_CHANNEL_MASK) == AC3_MONO)
avctx->channels = 1;
else
avctx->channels = 2;
avctx->bit_rate = bit_rate;
}
}
} else if (len < s->frame_size) {
len = s->frame_size - len;
if (len > buf_size)
len = buf_size;
memcpy(s->inbuf_ptr, buf_ptr, len);
buf_ptr += len;
s->inbuf_ptr += len;
buf_size -= len;
} else {
if (avctx->channels == 1)
flags = AC3_MONO;
else
flags = AC3_STEREO;
flags |= AC3_ADJUST_LEVEL;
level = 1;
if (ac3_frame (&s->state, s->inbuf, &flags, &level, 384)) {
fail:
s->inbuf_ptr = s->inbuf;
s->frame_size = 0;
continue;
}
for (i = 0; i < 6; i++) {
if (ac3_block (&s->state))
goto fail;
if (avctx->channels == 1)
float_to_int_mono (*samples, out_samples + i * 256);
else
float_to_int (*samples, out_samples + i * 512);
}
s->inbuf_ptr = s->inbuf;
s->frame_size = 0;
*data_size = 6 * avctx->channels * 256 * sizeof(INT16);
break;
}
}
return buf_ptr - buf;
}
static int ac3_decode_end(AVCodecContext *s)
{
return 0;
}
AVCodec ac3_decoder = {
"ac3",
CODEC_TYPE_AUDIO,
CODEC_ID_AC3,
sizeof(AC3DecodeState),
ac3_decode_init,
NULL,
ac3_decode_end,
ac3_decode_frame,
};
/* register codecs which could clash with mplayer symbols */
/* XXX: rename all symbols to avoid clashed */
void avcodec_register_more(void)
{
register_avcodec(&mp3_decoder);
register_avcodec(&ac3_decoder);
}

1460
libavcodec/ac3enc.c Normal file

File diff suppressed because it is too large Load Diff

32
libavcodec/ac3enc.h Normal file
View File

@ -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;

180
libavcodec/ac3tab.h Normal file
View File

@ -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];

407
libavcodec/apiexample.c Normal file
View File

@ -0,0 +1,407 @@
/* avcodec API use example.
*
* Note that this library only handles codecs (mpeg, mpeg4, etc...),
* not file formats (avi, vob, etc...). See library 'libav' for the
* format handling
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "avcodec.h"
#define INBUF_SIZE 4096
/*
* Audio encoding example
*/
void audio_encode_example(const char *filename)
{
AVCodec *codec;
AVCodecContext codec_context, *c = &codec_context;
int frame_size, i, j, out_size, outbuf_size;
FILE *f;
short *samples;
float t, tincr;
UINT8 *outbuf;
printf("Audio encoding\n");
/* find the MP2 encoder */
codec = avcodec_find_encoder(CODEC_ID_MP2);
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
/* put default values */
memset(c, 0, sizeof(*c));
/* put sample parameters */
c->bit_rate = 64000;
c->sample_rate = 44100;
c->channels = 2;
/* open it */
if (avcodec_open(c, codec) < 0) {
fprintf(stderr, "could not open codec\n");
exit(1);
}
/* the codec gives us the frame size, in samples */
frame_size = c->frame_size;
samples = malloc(frame_size * 2 * c->channels);
outbuf_size = 10000;
outbuf = malloc(outbuf_size);
f = fopen(filename, "w");
if (!f) {
fprintf(stderr, "could not open %s\n", filename);
exit(1);
}
/* encode a single tone sound */
t = 0;
tincr = 2 * M_PI * 440.0 / c->sample_rate;
for(i=0;i<200;i++) {
for(j=0;j<frame_size;j++) {
samples[2*j] = (int)(sin(t) * 10000);
samples[2*j+1] = samples[2*j];
t += tincr;
}
/* encode the samples */
out_size = avcodec_encode_audio(c, outbuf, outbuf_size, samples);
fwrite(outbuf, 1, out_size, f);
}
fclose(f);
free(outbuf);
free(samples);
avcodec_close(c);
}
/*
* Audio decoding.
*/
void audio_decode_example(const char *outfilename, const char *filename)
{
AVCodec *codec;
AVCodecContext codec_context, *c = &codec_context;
int out_size, size, len;
FILE *f, *outfile;
UINT8 *outbuf;
UINT8 inbuf[INBUF_SIZE], *inbuf_ptr;
printf("Audio decoding\n");
/* find the mpeg audio decoder */
codec = avcodec_find_decoder(CODEC_ID_MP2);
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
/* put default values */
memset(c, 0, sizeof(*c));
/* open it */
if (avcodec_open(c, codec) < 0) {
fprintf(stderr, "could not open codec\n");
exit(1);
}
outbuf = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
f = fopen(filename, "r");
if (!f) {
fprintf(stderr, "could not open %s\n", filename);
exit(1);
}
outfile = fopen(outfilename, "w");
if (!outfile) {
fprintf(stderr, "could not open %s\n", outfilename);
exit(1);
}
/* decode until eof */
inbuf_ptr = inbuf;
for(;;) {
size = fread(inbuf, 1, INBUF_SIZE, f);
if (size == 0)
break;
inbuf_ptr = inbuf;
while (size > 0) {
len = avcodec_decode_audio(c, (short *)outbuf, &out_size,
inbuf_ptr, size);
if (len < 0) {
fprintf(stderr, "Error while decoding\n");
exit(1);
}
if (out_size > 0) {
/* if a frame has been decoded, output it */
fwrite(outbuf, 1, out_size, outfile);
}
size -= len;
inbuf_ptr += len;
}
}
fclose(outfile);
fclose(f);
free(outbuf);
avcodec_close(c);
}
/*
* Video encoding example
*/
void video_encode_example(const char *filename)
{
AVCodec *codec;
AVCodecContext codec_context, *c = &codec_context;
int i, out_size, size, x, y, outbuf_size;
FILE *f;
AVPicture picture;
UINT8 *outbuf, *picture_buf;
printf("Video encoding\n");
/* find the mpeg1 video encoder */
codec = avcodec_find_encoder(CODEC_ID_MPEG1VIDEO);
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
/* put default values */
memset(c, 0, sizeof(*c));
/* put sample parameters */
c->bit_rate = 400000;
/* resolution must be a multiple of two */
c->width = 352;
c->height = 288;
/* frames per second */
c->frame_rate = 25 * FRAME_RATE_BASE;
c->gop_size = 10; /* emit one intra frame every ten frames */
/* open it */
if (avcodec_open(c, codec) < 0) {
fprintf(stderr, "could not open codec\n");
exit(1);
}
/* the codec gives us the frame size, in samples */
f = fopen(filename, "w");
if (!f) {
fprintf(stderr, "could not open %s\n", filename);
exit(1);
}
/* alloc image and output buffer */
outbuf_size = 100000;
outbuf = malloc(outbuf_size);
size = c->width * c->height;
picture_buf = malloc((size * 3) / 2); /* size for YUV 420 */
picture.data[0] = picture_buf;
picture.data[1] = picture.data[0] + size;
picture.data[2] = picture.data[1] + size / 4;
picture.linesize[0] = c->width;
picture.linesize[1] = c->width / 2;
picture.linesize[2] = c->width / 2;
/* encode 1 second of video */
for(i=0;i<25;i++) {
printf("encoding frame %3d\r", i);
fflush(stdout);
/* prepare a dummy image */
/* Y */
for(y=0;y<c->height;y++) {
for(x=0;x<c->width;x++) {
picture.data[0][y * picture.linesize[0] + x] = x + y + i * 3;
}
}
/* Cb and Cr */
for(y=0;y<c->height/2;y++) {
for(x=0;x<c->width/2;x++) {
picture.data[1][y * picture.linesize[1] + x] = 128 + y + i * 2;
picture.data[2][y * picture.linesize[2] + x] = 64 + x + i * 5;
}
}
/* encode the image */
out_size = avcodec_encode_video(c, outbuf, outbuf_size, &picture);
fwrite(outbuf, 1, out_size, f);
}
/* add sequence end code to have a real mpeg file */
outbuf[0] = 0x00;
outbuf[1] = 0x00;
outbuf[2] = 0x01;
outbuf[3] = 0xb7;
fwrite(outbuf, 1, 4, f);
fclose(f);
free(picture_buf);
free(outbuf);
avcodec_close(c);
printf("\n");
}
/*
* Video decoding example
*/
void pgm_save(unsigned char *buf,int wrap, int xsize,int ysize,char *filename)
{
FILE *f;
int i;
f=fopen(filename,"w");
fprintf(f,"P5\n%d %d\n%d\n",xsize,ysize,255);
for(i=0;i<ysize;i++)
fwrite(buf + i * wrap,1,xsize,f);
fclose(f);
}
void video_decode_example(const char *outfilename, const char *filename)
{
AVCodec *codec;
AVCodecContext codec_context, *c = &codec_context;
int frame, size, got_picture, len;
FILE *f;
AVPicture picture;
UINT8 inbuf[INBUF_SIZE], *inbuf_ptr;
char buf[1024];
printf("Video decoding\n");
/* find the mpeg1 video decoder */
codec = avcodec_find_decoder(CODEC_ID_MPEG1VIDEO);
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
/* put default values */
memset(c, 0, sizeof(*c));
/* for some codecs, such as msmpeg4 and opendivx, width and height
MUST be initialized there because these info are not available
in the bitstream */
/* open it */
if (avcodec_open(c, codec) < 0) {
fprintf(stderr, "could not open codec\n");
exit(1);
}
/* the codec gives us the frame size, in samples */
f = fopen(filename, "r");
if (!f) {
fprintf(stderr, "could not open %s\n", filename);
exit(1);
}
frame = 0;
for(;;) {
size = fread(inbuf, 1, INBUF_SIZE, f);
if (size == 0)
break;
/* NOTE1: some codecs are stream based (mpegvideo, mpegaudio)
and this is the only method to use them because you cannot
know the compressed data size before analysing it.
BUT some other codecs (msmpeg4, opendivx) are inherently
frame based, so you must call them with all the data for
one frame exactly. You must also initialize 'width' and
'height' before initializing them. */
/* NOTE2: some codecs allow the raw parameters (frame size,
sample rate) to be changed at any frame. We handle this, so
you should also take care of it */
/* here, we use a stream based decoder (mpeg1video), so we
feed decoder and see if it could decode a frame */
inbuf_ptr = inbuf;
while (size > 0) {
len = avcodec_decode_video(c, &picture, &got_picture,
inbuf_ptr, size);
if (len < 0) {
fprintf(stderr, "Error while decoding frame %d\n", frame);
exit(1);
}
if (got_picture) {
printf("saving frame %3d\r", frame);
fflush(stdout);
/* the picture is allocated by the decoder. no need to
free it */
snprintf(buf, sizeof(buf), outfilename, frame);
pgm_save(picture.data[0], picture.linesize[0],
c->width, c->height, buf);
frame++;
}
size -= len;
inbuf_ptr += len;
}
}
/* some codecs, such as MPEG, transmit the I and P frame with a
latency of one frame. You must do the following to have a
chance to get the last frame of the video */
len = avcodec_decode_video(c, &picture, &got_picture,
NULL, 0);
if (got_picture) {
printf("saving frame %3d\r", frame);
fflush(stdout);
/* the picture is allocated by the decoder. no need to
free it */
snprintf(buf, sizeof(buf), outfilename, frame);
pgm_save(picture.data[0], picture.linesize[0],
c->width, c->height, buf);
frame++;
}
fclose(f);
avcodec_close(c);
printf("\n");
}
int main(int argc, char **argv)
{
const char *filename;
/* must be called before using avcodec lib */
avcodec_init();
/* register all the codecs (you can also register only the codec
you wish to have smaller code */
avcodec_register_all();
if (argc <= 1) {
audio_encode_example("/tmp/test.mp2");
audio_decode_example("/tmp/test.sw", "/tmp/test.mp2");
video_encode_example("/tmp/test.mpg");
filename = "/tmp/test.mpg";
} else {
filename = argv[1];
}
// audio_decode_example("/tmp/test.sw", filename);
video_decode_example("/tmp/test%d.pgm", filename);
return 0;
}

177
libavcodec/avcodec.h Normal file
View File

@ -0,0 +1,177 @@
#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,
CODEC_ID_OPENDIVX,
CODEC_ID_PCM,
CODEC_ID_RAWVIDEO,
CODEC_ID_MSMPEG4,
CODEC_ID_H263P,
CODEC_ID_H263I,
};
enum CodecType {
CODEC_TYPE_VIDEO,
CODEC_TYPE_AUDIO,
};
enum PixelFormat {
PIX_FMT_YUV420P,
PIX_FMT_YUV422,
PIX_FMT_RGB24,
PIX_FMT_BGR24,
};
/* in bytes */
#define AVCODEC_MAX_AUDIO_FRAME_SIZE 18432
/* motion estimation type */
extern int motion_estimation_method;
#define ME_ZERO 0
#define ME_FULL 1
#define ME_LOG 2
#define ME_PHODS 3
/* encoding support */
#define CODEC_FLAG_HQ 0x0001 /* high quality (non real time) encoding */
#define CODEC_FLAG_QSCALE 0x0002 /* use fixed qscale */
#define FRAME_RATE_BASE 10000
typedef struct AVCodecContext {
int bit_rate;
int flags;
int sub_id; /* some codecs needs additionnal format info. It is
stored there */
/* video only */
int frame_rate; /* frames per sec multiplied by FRAME_RATE_BASE */
int width, height;
int gop_size; /* 0 = intra only */
int pix_fmt; /* pixel format, see PIX_FMT_xxx */
/* audio only */
int sample_rate; /* samples per sec */
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) */
int quality; /* quality of the previous encoded frame
(between 1 (good) and 31 (bad)) */
struct AVCodec *codec;
void *priv_data;
/* the following fields are ignored */
char codec_name[32];
int codec_type; /* see CODEC_TYPE_xxx */
int codec_id; /* see CODEC_ID_xxx */
unsigned int codec_tag; /* codec tag, only used if unknown codec */
} AVCodecContext;
typedef struct AVCodec {
char *name;
int type;
int id;
int priv_data_size;
int (*init)(AVCodecContext *);
int (*encode)(AVCodecContext *, UINT8 *buf, int buf_size, void *data);
int (*close)(AVCodecContext *);
int (*decode)(AVCodecContext *, void *outdata, int *outdata_size,
UINT8 *buf, int buf_size);
struct AVCodec *next;
} AVCodec;
/* three components are given, that's all */
typedef struct AVPicture {
UINT8 *data[3];
int linesize[3];
} AVPicture;
extern AVCodec ac3_encoder;
extern AVCodec mp2_encoder;
extern AVCodec mpeg1video_encoder;
extern AVCodec h263_encoder;
extern AVCodec h263p_encoder;
extern AVCodec rv10_encoder;
extern AVCodec mjpeg_encoder;
extern AVCodec opendivx_encoder;
extern AVCodec msmpeg4_encoder;
extern AVCodec h263_decoder;
extern AVCodec opendivx_decoder;
extern AVCodec msmpeg4_decoder;
extern AVCodec mpeg_decoder;
extern AVCodec h263i_decoder;
extern AVCodec rv10_decoder;
/* dummy raw codecs */
extern AVCodec pcm_codec;
extern AVCodec rawvideo_codec;
/* the following codecs use external GPL libs */
extern AVCodec mp3_decoder;
extern AVCodec ac3_decoder;
/* resample.c */
struct ReSampleContext;
typedef struct ReSampleContext ReSampleContext;
ReSampleContext *audio_resample_init(int output_channels, int input_channels,
int output_rate, int input_rate);
int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples);
void audio_resample_close(ReSampleContext *s);
/* YUV420 format is assumed ! */
struct ImgReSampleContext;
typedef struct ImgReSampleContext ImgReSampleContext;
ImgReSampleContext *img_resample_init(int output_width, int output_height,
int input_width, int input_height);
void img_resample(ImgReSampleContext *s,
AVPicture *output, AVPicture *input);
void img_resample_close(ImgReSampleContext *s);
int img_convert_to_yuv420(UINT8 *img_out, UINT8 *img,
int pix_fmt, int width, int height);
/* external high level API */
extern AVCodec *first_avcodec;
void avcodec_init(void);
void register_avcodec(AVCodec *format);
AVCodec *avcodec_find_encoder(enum CodecID id);
AVCodec *avcodec_find_decoder(enum CodecID id);
AVCodec *avcodec_find_decoder_by_name(const char *name);
void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode);
int avcodec_open(AVCodecContext *avctx, AVCodec *codec);
int avcodec_decode_audio(AVCodecContext *avctx, INT16 *samples,
int *frame_size_ptr,
UINT8 *buf, int buf_size);
int avcodec_decode_video(AVCodecContext *avctx, AVPicture *picture,
int *got_picture_ptr,
UINT8 *buf, int buf_size);
int avcodec_encode_audio(AVCodecContext *avctx, UINT8 *buf, int buf_size,
const short *samples);
int avcodec_encode_video(AVCodecContext *avctx, UINT8 *buf, int buf_size,
const AVPicture *pict);
int avcodec_close(AVCodecContext *avctx);
void avcodec_register_all(void);
void avcodec_register_more(void);

469
libavcodec/common.c Normal file
View File

@ -0,0 +1,469 @@
/*
* Common bit i/o utils
* Copyright (c) 2000, 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef __FreeBSD__
#include <sys/param.h>
#endif
#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;
#ifdef STATS
st_out_bit_counts[st_current_index] += n;
#endif
// printf("put_bits=%d %x\n", n, value);
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;
}
/* bit input functions */
void init_get_bits(GetBitContext *s,
UINT8 *buffer, int buffer_size)
{
s->buf = buffer;
s->buf_ptr = buffer;
s->buf_end = buffer + buffer_size;
s->bit_cnt = 0;
s->bit_buf = 0;
while (s->buf_ptr < s->buf_end &&
s->bit_cnt < 32) {
s->bit_buf |= (*s->buf_ptr++ << (24 - s->bit_cnt));
s->bit_cnt += 8;
}
}
/* n must be >= 1 and <= 32 */
unsigned int get_bits(GetBitContext *s, int n)
{
unsigned int val;
int bit_cnt;
unsigned int bit_buf;
UINT8 *buf_ptr;
#ifdef STATS
st_bit_counts[st_current_index] += n;
#endif
bit_cnt = s->bit_cnt;
bit_buf = s->bit_buf;
bit_cnt -= n;
if (bit_cnt >= 0) {
/* most common case here */
val = bit_buf >> (32 - n);
bit_buf <<= n;
} else {
val = bit_buf >> (32 - n);
buf_ptr = s->buf_ptr;
buf_ptr += 4;
/* handle common case: we can read everything */
if (buf_ptr <= s->buf_end) {
bit_buf = (buf_ptr[-4] << 24) |
(buf_ptr[-3] << 16) |
(buf_ptr[-2] << 8) |
(buf_ptr[-1]);
} else {
buf_ptr -= 4;
bit_buf = 0;
if (buf_ptr < s->buf_end)
bit_buf |= *buf_ptr++ << 24;
if (buf_ptr < s->buf_end)
bit_buf |= *buf_ptr++ << 16;
if (buf_ptr < s->buf_end)
bit_buf |= *buf_ptr++ << 8;
if (buf_ptr < s->buf_end)
bit_buf |= *buf_ptr++;
}
s->buf_ptr = buf_ptr;
val |= bit_buf >> (32 + bit_cnt);
bit_buf <<= - bit_cnt;
bit_cnt += 32;
}
s->bit_buf = bit_buf;
s->bit_cnt = bit_cnt;
return val;
}
void align_get_bits(GetBitContext *s)
{
int n;
n = s->bit_cnt & 7;
if (n > 0) {
get_bits(s, n);
}
}
/* VLC decoding */
//#define DEBUG_VLC
#define GET_DATA(v, table, i, wrap, size) \
{\
UINT8 *ptr = (UINT8 *)table + i * wrap;\
switch(size) {\
case 1:\
v = *(UINT8 *)ptr;\
break;\
case 2:\
v = *(UINT16 *)ptr;\
break;\
default:\
v = *(UINT32 *)ptr;\
break;\
}\
}
static int alloc_table(VLC *vlc, int size)
{
int index;
index = vlc->table_size;
vlc->table_size += size;
if (vlc->table_size > vlc->table_allocated) {
vlc->table_allocated += (1 << vlc->bits);
vlc->table_bits = realloc(vlc->table_bits,
sizeof(INT8) * vlc->table_allocated);
vlc->table_codes = realloc(vlc->table_codes,
sizeof(INT16) * vlc->table_allocated);
if (!vlc->table_bits ||
!vlc->table_codes)
return -1;
}
return index;
}
static int build_table(VLC *vlc, int table_nb_bits,
int nb_codes,
const void *bits, int bits_wrap, int bits_size,
const void *codes, int codes_wrap, int codes_size,
UINT32 code_prefix, int n_prefix)
{
int i, j, k, n, table_size, table_index, nb, n1, index;
UINT32 code;
INT8 *table_bits;
INT16 *table_codes;
table_size = 1 << table_nb_bits;
table_index = alloc_table(vlc, table_size);
#ifdef DEBUG_VLC
printf("new table index=%d size=%d code_prefix=%x n=%d\n",
table_index, table_size, code_prefix, n_prefix);
#endif
if (table_index < 0)
return -1;
table_bits = &vlc->table_bits[table_index];
table_codes = &vlc->table_codes[table_index];
for(i=0;i<table_size;i++) {
table_bits[i] = 0;
table_codes[i] = -1;
}
/* first pass: map codes and compute auxillary table sizes */
for(i=0;i<nb_codes;i++) {
GET_DATA(n, bits, i, bits_wrap, bits_size);
GET_DATA(code, codes, i, codes_wrap, codes_size);
/* we accept tables with holes */
if (n <= 0)
continue;
#if defined(DEBUG_VLC) && 0
printf("i=%d n=%d code=0x%x\n", i, n, code);
#endif
/* if code matches the prefix, it is in the table */
n -= n_prefix;
if (n > 0 && (code >> n) == code_prefix) {
if (n <= table_nb_bits) {
/* no need to add another table */
j = (code << (table_nb_bits - n)) & (table_size - 1);
nb = 1 << (table_nb_bits - n);
for(k=0;k<nb;k++) {
#ifdef DEBUG_VLC
printf("%4x: code=%d n=%d\n",
j, i, n);
#endif
if (table_bits[j] != 0) {
fprintf(stderr, "incorrect codes\n");
exit(1);
}
table_bits[j] = n;
table_codes[j] = i;
j++;
}
} else {
n -= table_nb_bits;
j = (code >> n) & ((1 << table_nb_bits) - 1);
#ifdef DEBUG_VLC
printf("%4x: n=%d (subtable)\n",
j, n);
#endif
/* compute table size */
n1 = -table_bits[j];
if (n > n1)
n1 = n;
table_bits[j] = -n1;
}
}
}
/* second pass : fill auxillary tables recursively */
for(i=0;i<table_size;i++) {
n = table_bits[i];
if (n < 0) {
n = -n;
if (n > table_nb_bits) {
n = table_nb_bits;
table_bits[i] = -n;
}
index = build_table(vlc, n, nb_codes,
bits, bits_wrap, bits_size,
codes, codes_wrap, codes_size,
(code_prefix << table_nb_bits) | i,
n_prefix + table_nb_bits);
if (index < 0)
return -1;
/* note: realloc has been done, so reload tables */
table_bits = &vlc->table_bits[table_index];
table_codes = &vlc->table_codes[table_index];
table_codes[i] = index;
}
}
return table_index;
}
/* wrap and size allow to handle most types of storage. */
int init_vlc(VLC *vlc, int nb_bits, int nb_codes,
const void *bits, int bits_wrap, int bits_size,
const void *codes, int codes_wrap, int codes_size)
{
vlc->bits = nb_bits;
vlc->table_bits = NULL;
vlc->table_codes = NULL;
vlc->table_allocated = 0;
vlc->table_size = 0;
#ifdef DEBUG_VLC
printf("build table nb_codes=%d\n", nb_codes);
#endif
if (build_table(vlc, nb_bits, nb_codes,
bits, bits_wrap, bits_size,
codes, codes_wrap, codes_size,
0, 0) < 0) {
if (vlc->table_bits)
free(vlc->table_bits);
if (vlc->table_codes)
free(vlc->table_codes);
return -1;
}
return 0;
}
void free_vlc(VLC *vlc)
{
free(vlc->table_bits);
free(vlc->table_codes);
}
int get_vlc(GetBitContext *s, VLC *vlc)
{
int bit_cnt, code, n, nb_bits, index;
UINT32 bit_buf;
INT16 *table_codes;
INT8 *table_bits;
UINT8 *buf_ptr;
SAVE_BITS(s);
nb_bits = vlc->bits;
table_codes = vlc->table_codes;
table_bits = vlc->table_bits;
for(;;) {
SHOW_BITS(s, index, nb_bits);
code = table_codes[index];
n = table_bits[index];
if (n > 0) {
/* most common case */
FLUSH_BITS(n);
#ifdef STATS
st_bit_counts[st_current_index] += n;
#endif
break;
} else if (n == 0) {
return -1;
} else {
FLUSH_BITS(nb_bits);
#ifdef STATS
st_bit_counts[st_current_index] += nb_bits;
#endif
nb_bits = -n;
table_codes = vlc->table_codes + code;
table_bits = vlc->table_bits + code;
}
}
RESTORE_BITS(s);
return code;
}

170
libavcodec/common.h Normal file
View File

@ -0,0 +1,170 @@
#ifndef COMMON_H
#define COMMON_H
#include "../config.h"
#ifndef USE_LIBAVCODEC
// workaround for typedef conflict in MPlayer
typedef unsigned short UINT16;
typedef signed short INT16;
#endif
typedef unsigned char UINT8;
typedef unsigned int UINT32;
typedef unsigned long long UINT64;
typedef signed char INT8;
typedef signed int INT32;
typedef signed long long INT64;
/* bit output */
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);
/* bit input */
typedef struct GetBitContext {
UINT8 *buf, *buf_ptr, *buf_end;
int bit_cnt;
UINT32 bit_buf;
} GetBitContext;
typedef struct VLC {
int bits;
INT16 *table_codes;
INT8 *table_bits;
int table_size, table_allocated;
} VLC;
void init_get_bits(GetBitContext *s,
UINT8 *buffer, int buffer_size);
unsigned int get_bits(GetBitContext *s, int n);
void align_get_bits(GetBitContext *s);
int init_vlc(VLC *vlc, int nb_bits, int nb_codes,
const void *bits, int bits_wrap, int bits_size,
const void *codes, int codes_wrap, int codes_size);
void free_vlc(VLC *vlc);
int get_vlc(GetBitContext *s, VLC *vlc);
/* macro to go faster */
/* n must be <= 24 */
/* XXX: optimize buffer end test */
#define SHOW_BITS(s, val, n)\
{\
if (bit_cnt < n && buf_ptr < (s)->buf_end) {\
bit_buf |= *buf_ptr++ << (24 - bit_cnt);\
bit_cnt += 8;\
if (bit_cnt < n && buf_ptr < (s)->buf_end) {\
bit_buf |= *buf_ptr++ << (24 - bit_cnt);\
bit_cnt += 8;\
if (bit_cnt < n && buf_ptr < (s)->buf_end) {\
bit_buf |= *buf_ptr++ << (24 - bit_cnt);\
bit_cnt += 8;\
}\
}\
}\
val = bit_buf >> (32 - n);\
}
/* SHOW_BITS with n1 >= n must be been done before */
#define FLUSH_BITS(n)\
{\
bit_buf <<= n;\
bit_cnt -= n;\
}
#define SAVE_BITS(s) \
{\
bit_cnt = (s)->bit_cnt;\
bit_buf = (s)->bit_buf;\
buf_ptr = (s)->buf_ptr;\
}
#define RESTORE_BITS(s) \
{\
(s)->buf_ptr = buf_ptr;\
(s)->bit_buf = bit_buf;\
(s)->bit_cnt = bit_cnt;\
}
/* define it to include statistics code (useful only for optimizing
codec efficiency */
//#define STATS
#ifdef STATS
enum {
ST_UNKNOWN,
ST_DC,
ST_INTRA_AC,
ST_INTER_AC,
ST_INTRA_MB,
ST_INTER_MB,
ST_MV,
ST_NB,
};
extern int st_current_index;
extern unsigned int st_bit_counts[ST_NB];
extern unsigned int st_out_bit_counts[ST_NB];
void print_stats(void);
#endif
/* 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;
}
/* memory */
void *av_mallocz(int size);
#endif

105
libavcodec/dct-test.c Normal file
View File

@ -0,0 +1,105 @@
/* DCT test. (c) 2001 Gerard Lantau.
Started from sample code by Juan J. Sierralta P.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include "dsputil.h"
extern void fdct(DCTELEM *block);
extern void init_fdct();
#define AANSCALE_BITS 12
static const unsigned short aanscales[64] = {
/* precomputed values scaled up by 14 bits */
16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270,
21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906,
19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315,
16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552,
8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446,
4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247
};
INT64 gettime(void)
{
struct timeval tv;
gettimeofday(&tv,NULL);
return (INT64)tv.tv_sec * 1000000 + tv.tv_usec;
}
#define NB_ITS 20000
#define NB_ITS_SPEED 50000
void dct_error(const char *name,
void (*fdct_func)(DCTELEM *block))
{
int it, i, scale;
DCTELEM block[64], block1[64];
int err_inf, v;
INT64 err2, ti, ti1, it1;
srandom(0);
err_inf = 0;
err2 = 0;
for(it=0;it<NB_ITS;it++) {
for(i=0;i<64;i++)
block1[i] = random() % 256;
memcpy(block, block1, sizeof(DCTELEM) * 64);
fdct_func(block);
if (fdct_func == jpeg_fdct_ifast) {
for(i=0; i<64; i++) {
scale = (1 << (AANSCALE_BITS + 11)) / aanscales[i];
block[i] = (block[i] * scale) >> AANSCALE_BITS;
}
}
fdct(block1);
for(i=0;i<64;i++) {
v = abs(block[i] - block1[i]);
if (v > err_inf)
err_inf = v;
err2 += v * v;
}
}
printf("DCT %s: err_inf=%d err2=%0.2f\n",
name, err_inf, (double)err2 / NB_ITS / 64.0);
/* speed test */
for(i=0;i<64;i++)
block1[i] = 255 - 63 + i;
ti = gettime();
it1 = 0;
do {
for(it=0;it<NB_ITS_SPEED;it++) {
memcpy(block, block1, sizeof(DCTELEM) * 64);
fdct_func(block);
}
it1 += NB_ITS_SPEED;
ti1 = gettime() - ti;
} while (ti1 < 1000000);
printf("DCT %s: %0.1f kdct/s\n",
name, (double)it1 * 1000.0 / (double)ti1);
}
int main(int argc, char **argv)
{
init_fdct();
printf("ffmpeg DCT test\n");
dct_error("REF", fdct); /* only to verify code ! */
dct_error("AAN", jpeg_fdct_ifast);
dct_error("MMX", fdct_mmx);
return 0;
}

383
libavcodec/dsputil.c Normal file
View File

@ -0,0 +1,383 @@
/*
* DSP utils
* Copyright (c) 2000, 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include "avcodec.h"
#include "dsputil.h"
#ifdef CONFIG_MMX
int mm_flags; /* multimedia extension flags */
#endif
void (*get_pixels)(DCTELEM *block, const UINT8 *pixels, int line_size);
void (*put_pixels_clamped)(const DCTELEM *block, UINT8 *pixels, int line_size);
void (*add_pixels_clamped)(const DCTELEM *block, UINT8 *pixels, int line_size);
op_pixels_abs_func pix_abs16x16;
op_pixels_abs_func pix_abs16x16_x2;
op_pixels_abs_func pix_abs16x16_y2;
op_pixels_abs_func pix_abs16x16_xy2;
static UINT8 cropTbl[256 + 2 * MAX_NEG_CROP];
UINT32 squareTbl[512];
void get_pixels_c(DCTELEM *block, const UINT8 *pixels, int line_size)
{
DCTELEM *p;
const UINT8 *pix;
int i;
/* read the pixels */
p = block;
pix = pixels;
for(i=0;i<8;i++) {
p[0] = pix[0];
p[1] = pix[1];
p[2] = pix[2];
p[3] = pix[3];
p[4] = pix[4];
p[5] = pix[5];
p[6] = pix[6];
p[7] = pix[7];
pix += line_size;
p += 8;
}
}
void put_pixels_clamped_c(const DCTELEM *block, UINT8 *pixels, int line_size)
{
const DCTELEM *p;
UINT8 *pix;
int i;
UINT8 *cm = cropTbl + MAX_NEG_CROP;
/* read the pixels */
p = block;
pix = pixels;
for(i=0;i<8;i++) {
pix[0] = cm[p[0]];
pix[1] = cm[p[1]];
pix[2] = cm[p[2]];
pix[3] = cm[p[3]];
pix[4] = cm[p[4]];
pix[5] = cm[p[5]];
pix[6] = cm[p[6]];
pix[7] = cm[p[7]];
pix += line_size;
p += 8;
}
}
void add_pixels_clamped_c(const DCTELEM *block, UINT8 *pixels, int line_size)
{
const DCTELEM *p;
UINT8 *pix;
int i;
UINT8 *cm = cropTbl + MAX_NEG_CROP;
/* read the pixels */
p = block;
pix = pixels;
for(i=0;i<8;i++) {
pix[0] = cm[pix[0] + p[0]];
pix[1] = cm[pix[1] + p[1]];
pix[2] = cm[pix[2] + p[2]];
pix[3] = cm[pix[3] + p[3]];
pix[4] = cm[pix[4] + p[4]];
pix[5] = cm[pix[5] + p[5]];
pix[6] = cm[pix[6] + p[6]];
pix[7] = cm[pix[7] + p[7]];
pix += line_size;
p += 8;
}
}
#define PIXOP(BTYPE, OPNAME, OP, INCR) \
\
static void OPNAME ## _pixels(BTYPE *block, const UINT8 *pixels, int line_size, int h) \
{ \
BTYPE *p; \
const UINT8 *pix; \
\
p = block; \
pix = pixels; \
do { \
OP(p[0], pix[0]); \
OP(p[1], pix[1]); \
OP(p[2], pix[2]); \
OP(p[3], pix[3]); \
OP(p[4], pix[4]); \
OP(p[5], pix[5]); \
OP(p[6], pix[6]); \
OP(p[7], pix[7]); \
pix += line_size; \
p += INCR; \
} while (--h);; \
} \
\
static void OPNAME ## _pixels_x2(BTYPE *block, const UINT8 *pixels, int line_size, int h) \
{ \
BTYPE *p; \
const UINT8 *pix; \
\
p = block; \
pix = pixels; \
do { \
OP(p[0], avg2(pix[0], pix[1])); \
OP(p[1], avg2(pix[1], pix[2])); \
OP(p[2], avg2(pix[2], pix[3])); \
OP(p[3], avg2(pix[3], pix[4])); \
OP(p[4], avg2(pix[4], pix[5])); \
OP(p[5], avg2(pix[5], pix[6])); \
OP(p[6], avg2(pix[6], pix[7])); \
OP(p[7], avg2(pix[7], pix[8])); \
pix += line_size; \
p += INCR; \
} while (--h); \
} \
\
static void OPNAME ## _pixels_y2(BTYPE *block, const UINT8 *pixels, int line_size, int h) \
{ \
BTYPE *p; \
const UINT8 *pix; \
const UINT8 *pix1; \
\
p = block; \
pix = pixels; \
pix1 = pixels + line_size; \
do { \
OP(p[0], avg2(pix[0], pix1[0])); \
OP(p[1], avg2(pix[1], pix1[1])); \
OP(p[2], avg2(pix[2], pix1[2])); \
OP(p[3], avg2(pix[3], pix1[3])); \
OP(p[4], avg2(pix[4], pix1[4])); \
OP(p[5], avg2(pix[5], pix1[5])); \
OP(p[6], avg2(pix[6], pix1[6])); \
OP(p[7], avg2(pix[7], pix1[7])); \
pix += line_size; \
pix1 += line_size; \
p += INCR; \
} while(--h); \
} \
\
static void OPNAME ## _pixels_xy2(BTYPE *block, const UINT8 *pixels, int line_size, int h) \
{ \
BTYPE *p; \
const UINT8 *pix; \
const UINT8 *pix1; \
\
p = block; \
pix = pixels; \
pix1 = pixels + line_size; \
do { \
OP(p[0], avg4(pix[0], pix[1], pix1[0], pix1[1])); \
OP(p[1], avg4(pix[1], pix[2], pix1[1], pix1[2])); \
OP(p[2], avg4(pix[2], pix[3], pix1[2], pix1[3])); \
OP(p[3], avg4(pix[3], pix[4], pix1[3], pix1[4])); \
OP(p[4], avg4(pix[4], pix[5], pix1[4], pix1[5])); \
OP(p[5], avg4(pix[5], pix[6], pix1[5], pix1[6])); \
OP(p[6], avg4(pix[6], pix[7], pix1[6], pix1[7])); \
OP(p[7], avg4(pix[7], pix[8], pix1[7], pix1[8])); \
pix += line_size; \
pix1 += line_size; \
p += INCR; \
} while(--h); \
} \
\
void (*OPNAME ## _pixels_tab[4])(BTYPE *block, const UINT8 *pixels, int line_size, int h) = { \
OPNAME ## _pixels, \
OPNAME ## _pixels_x2, \
OPNAME ## _pixels_y2, \
OPNAME ## _pixels_xy2, \
};
/* rounding primitives */
#define avg2(a,b) ((a+b+1)>>1)
#define avg4(a,b,c,d) ((a+b+c+d+2)>>2)
#define op_put(a, b) a = b
#define op_avg(a, b) a = avg2(a, b)
#define op_sub(a, b) a -= b
PIXOP(UINT8, put, op_put, line_size)
PIXOP(UINT8, avg, op_avg, line_size)
PIXOP(DCTELEM, sub, op_sub, 8)
/* not rounding primitives */
#undef avg2
#undef avg4
#define avg2(a,b) ((a+b)>>1)
#define avg4(a,b,c,d) ((a+b+c+d+1)>>2)
PIXOP(UINT8, put_no_rnd, op_put, line_size)
PIXOP(UINT8, avg_no_rnd, op_avg, line_size)
/* motion estimation */
#undef avg2
#undef avg4
#define avg2(a,b) ((a+b+1)>>1)
#define avg4(a,b,c,d) ((a+b+c+d+2)>>2)
int pix_abs16x16_c(UINT8 *pix1, UINT8 *pix2, int line_size, int h)
{
int s, i;
s = 0;
for(i=0;i<h;i++) {
s += abs(pix1[0] - pix2[0]);
s += abs(pix1[1] - pix2[1]);
s += abs(pix1[2] - pix2[2]);
s += abs(pix1[3] - pix2[3]);
s += abs(pix1[4] - pix2[4]);
s += abs(pix1[5] - pix2[5]);
s += abs(pix1[6] - pix2[6]);
s += abs(pix1[7] - pix2[7]);
s += abs(pix1[8] - pix2[8]);
s += abs(pix1[9] - pix2[9]);
s += abs(pix1[10] - pix2[10]);
s += abs(pix1[11] - pix2[11]);
s += abs(pix1[12] - pix2[12]);
s += abs(pix1[13] - pix2[13]);
s += abs(pix1[14] - pix2[14]);
s += abs(pix1[15] - pix2[15]);
pix1 += line_size;
pix2 += line_size;
}
return s;
}
int pix_abs16x16_x2_c(UINT8 *pix1, UINT8 *pix2, int line_size, int h)
{
int s, i;
s = 0;
for(i=0;i<h;i++) {
s += abs(pix1[0] - avg2(pix2[0], pix2[1]));
s += abs(pix1[1] - avg2(pix2[1], pix2[2]));
s += abs(pix1[2] - avg2(pix2[2], pix2[3]));
s += abs(pix1[3] - avg2(pix2[3], pix2[4]));
s += abs(pix1[4] - avg2(pix2[4], pix2[5]));
s += abs(pix1[5] - avg2(pix2[5], pix2[6]));
s += abs(pix1[6] - avg2(pix2[6], pix2[7]));
s += abs(pix1[7] - avg2(pix2[7], pix2[8]));
s += abs(pix1[8] - avg2(pix2[8], pix2[9]));
s += abs(pix1[9] - avg2(pix2[9], pix2[10]));
s += abs(pix1[10] - avg2(pix2[10], pix2[11]));
s += abs(pix1[11] - avg2(pix2[11], pix2[12]));
s += abs(pix1[12] - avg2(pix2[12], pix2[13]));
s += abs(pix1[13] - avg2(pix2[13], pix2[14]));
s += abs(pix1[14] - avg2(pix2[14], pix2[15]));
s += abs(pix1[15] - avg2(pix2[15], pix2[16]));
pix1 += line_size;
pix2 += line_size;
}
return s;
}
int pix_abs16x16_y2_c(UINT8 *pix1, UINT8 *pix2, int line_size, int h)
{
int s, i;
UINT8 *pix3 = pix2 + line_size;
s = 0;
for(i=0;i<h;i++) {
s += abs(pix1[0] - avg2(pix2[0], pix3[0]));
s += abs(pix1[1] - avg2(pix2[1], pix3[1]));
s += abs(pix1[2] - avg2(pix2[2], pix3[2]));
s += abs(pix1[3] - avg2(pix2[3], pix3[3]));
s += abs(pix1[4] - avg2(pix2[4], pix3[4]));
s += abs(pix1[5] - avg2(pix2[5], pix3[5]));
s += abs(pix1[6] - avg2(pix2[6], pix3[6]));
s += abs(pix1[7] - avg2(pix2[7], pix3[7]));
s += abs(pix1[8] - avg2(pix2[8], pix3[8]));
s += abs(pix1[9] - avg2(pix2[9], pix3[9]));
s += abs(pix1[10] - avg2(pix2[10], pix3[10]));
s += abs(pix1[11] - avg2(pix2[11], pix3[11]));
s += abs(pix1[12] - avg2(pix2[12], pix3[12]));
s += abs(pix1[13] - avg2(pix2[13], pix3[13]));
s += abs(pix1[14] - avg2(pix2[14], pix3[14]));
s += abs(pix1[15] - avg2(pix2[15], pix3[15]));
pix1 += line_size;
pix2 += line_size;
pix3 += line_size;
}
return s;
}
int pix_abs16x16_xy2_c(UINT8 *pix1, UINT8 *pix2, int line_size, int h)
{
int s, i;
UINT8 *pix3 = pix2 + line_size;
s = 0;
for(i=0;i<h;i++) {
s += abs(pix1[0] - avg4(pix2[0], pix2[1], pix3[0], pix3[1]));
s += abs(pix1[1] - avg4(pix2[1], pix2[2], pix3[1], pix3[2]));
s += abs(pix1[2] - avg4(pix2[2], pix2[3], pix3[2], pix3[3]));
s += abs(pix1[3] - avg4(pix2[3], pix2[4], pix3[3], pix3[4]));
s += abs(pix1[4] - avg4(pix2[4], pix2[5], pix3[4], pix3[5]));
s += abs(pix1[5] - avg4(pix2[5], pix2[6], pix3[5], pix3[6]));
s += abs(pix1[6] - avg4(pix2[6], pix2[7], pix3[6], pix3[7]));
s += abs(pix1[7] - avg4(pix2[7], pix2[8], pix3[7], pix3[8]));
s += abs(pix1[8] - avg4(pix2[8], pix2[9], pix3[8], pix3[9]));
s += abs(pix1[9] - avg4(pix2[9], pix2[10], pix3[9], pix3[10]));
s += abs(pix1[10] - avg4(pix2[10], pix2[11], pix3[10], pix3[11]));
s += abs(pix1[11] - avg4(pix2[11], pix2[12], pix3[11], pix3[12]));
s += abs(pix1[12] - avg4(pix2[12], pix2[13], pix3[12], pix3[13]));
s += abs(pix1[13] - avg4(pix2[13], pix2[14], pix3[13], pix3[14]));
s += abs(pix1[14] - avg4(pix2[14], pix2[15], pix3[14], pix3[15]));
s += abs(pix1[15] - avg4(pix2[15], pix2[16], pix3[15], pix3[16]));
pix1 += line_size;
pix2 += line_size;
pix3 += line_size;
}
return s;
}
void dsputil_init(void)
{
int i;
for(i=0;i<256;i++) cropTbl[i + MAX_NEG_CROP] = i;
for(i=0;i<MAX_NEG_CROP;i++) {
cropTbl[i] = 0;
cropTbl[i + MAX_NEG_CROP + 256] = 255;
}
for(i=0;i<512;i++) {
squareTbl[i] = (i - 256) * (i - 256);
}
get_pixels = get_pixels_c;
put_pixels_clamped = put_pixels_clamped_c;
add_pixels_clamped = add_pixels_clamped_c;
pix_abs16x16 = pix_abs16x16_c;
pix_abs16x16_x2 = pix_abs16x16_x2_c;
pix_abs16x16_y2 = pix_abs16x16_y2_c;
pix_abs16x16_xy2 = pix_abs16x16_xy2_c;
av_fdct = jpeg_fdct_ifast;
#ifdef CONFIG_MMX
dsputil_init_mmx();
#endif
}

91
libavcodec/dsputil.h Normal file
View File

@ -0,0 +1,91 @@
#ifndef DSPUTIL_H
#define DSPUTIL_H
#include "common.h"
#include <inttypes.h>
/* dct code */
typedef short DCTELEM;
void jpeg_fdct_ifast (DCTELEM *data);
void j_rev_dct (DCTELEM *data);
void fdct_mmx(DCTELEM *block);
void (*av_fdct)(DCTELEM *block);
/* pixel operations */
#define MAX_NEG_CROP 384
/* temporary */
extern UINT32 squareTbl[512];
void dsputil_init(void);
/* pixel ops : interface with DCT */
extern void (*get_pixels)(DCTELEM *block, const UINT8 *pixels, int line_size);
extern void (*put_pixels_clamped)(const DCTELEM *block, UINT8 *pixels, int line_size);
extern void (*add_pixels_clamped)(const DCTELEM *block, UINT8 *pixels, int line_size);
void get_pixels_c(DCTELEM *block, const UINT8 *pixels, int line_size);
void put_pixels_clamped_c(const DCTELEM *block, UINT8 *pixels, int line_size);
void add_pixels_clamped_c(const DCTELEM *block, UINT8 *pixels, int line_size);
/* add and put pixel (decoding) */
typedef void (*op_pixels_func)(UINT8 *block, const UINT8 *pixels, int line_size, int h);
extern op_pixels_func put_pixels_tab[4];
extern op_pixels_func avg_pixels_tab[4];
extern op_pixels_func put_no_rnd_pixels_tab[4];
extern op_pixels_func avg_no_rnd_pixels_tab[4];
/* sub pixel (encoding) */
extern void (*sub_pixels_tab[4])(DCTELEM *block, const UINT8 *pixels, int line_size, int h);
#define sub_pixels_2(block, pixels, line_size, dxy) \
sub_pixels_tab[dxy](block, pixels, line_size, 8)
/* motion estimation */
typedef int (*op_pixels_abs_func)(UINT8 *blk1, UINT8 *blk2, int line_size, int h);
extern op_pixels_abs_func pix_abs16x16;
extern op_pixels_abs_func pix_abs16x16_x2;
extern op_pixels_abs_func pix_abs16x16_y2;
extern op_pixels_abs_func pix_abs16x16_xy2;
int pix_abs16x16_c(UINT8 *blk1, UINT8 *blk2, int lx, int h);
int pix_abs16x16_x2_c(UINT8 *blk1, UINT8 *blk2, int lx, int h);
int pix_abs16x16_y2_c(UINT8 *blk1, UINT8 *blk2, int lx, int h);
int pix_abs16x16_xy2_c(UINT8 *blk1, UINT8 *blk2, int lx, int h);
#ifdef CONFIG_MMX
#define MM_MMX 0x0001 /* standard MMX */
#define MM_3DNOW 0x0004 /* AMD 3DNOW */
#define MM_MMXEXT 0x0002 /* SSE integer functions or AMD MMX ext */
#define MM_SSE 0x0008 /* SSE functions */
#define MM_SSE2 0x0010 /* PIV SSE2 functions */
extern int mm_flags;
int mm_support(void);
static inline void emms(void)
{
asm volatile ("emms;");
}
#define __align8 __attribute__ ((aligned (8)))
void dsputil_init_mmx(void);
#else
#define __align8
#endif
#endif

120
libavcodec/fdctref.c Normal file
View File

@ -0,0 +1,120 @@
/* fdctref.c, forward discrete cosine transform, double precision */
/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */
/*
* Disclaimer of Warranty
*
* These software programs are available to the user without any license fee or
* royalty on an "as is" basis. The MPEG Software Simulation Group disclaims
* any and all warranties, whether express, implied, or statuary, including any
* implied warranties or merchantability or of fitness for a particular
* purpose. In no event shall the copyright-holder be liable for any
* incidental, punitive, or consequential damages of any kind whatsoever
* arising from the use of these programs.
*
* This disclaimer of warranty extends to the user of these programs and user's
* customers, employees, agents, transferees, successors, and assigns.
*
* The MPEG Software Simulation Group does not represent or warrant that the
* programs furnished hereunder are free of infringement of any third-party
* patents.
*
* Commercial implementations of MPEG-1 and MPEG-2 video, including shareware,
* are subject to royalty fees to patent holders. Many of these patents are
* general enough such that they are unavoidable regardless of implementation
* design.
*
*/
#include <math.h>
// #include "config.h"
#ifndef PI
# ifdef M_PI
# define PI M_PI
# else
# define PI 3.14159265358979323846
# endif
#endif
/* global declarations */
void init_fdct (void);
void fdct (short *block);
/* private data */
static double c[8][8]; /* transform coefficients */
void init_fdct()
{
int i, j;
double s;
for (i=0; i<8; i++)
{
s = (i==0) ? sqrt(0.125) : 0.5;
for (j=0; j<8; j++)
c[i][j] = s * cos((PI/8.0)*i*(j+0.5));
}
}
void fdct(block)
short *block;
{
register int i, j;
double s;
double tmp[64];
for(i = 0; i < 8; i++)
for(j = 0; j < 8; j++)
{
s = 0.0;
/*
* for(k = 0; k < 8; k++)
* s += c[j][k] * block[8 * i + k];
*/
s += c[j][0] * block[8 * i + 0];
s += c[j][1] * block[8 * i + 1];
s += c[j][2] * block[8 * i + 2];
s += c[j][3] * block[8 * i + 3];
s += c[j][4] * block[8 * i + 4];
s += c[j][5] * block[8 * i + 5];
s += c[j][6] * block[8 * i + 6];
s += c[j][7] * block[8 * i + 7];
tmp[8 * i + j] = s;
}
for(j = 0; j < 8; j++)
for(i = 0; i < 8; i++)
{
s = 0.0;
/*
* for(k = 0; k < 8; k++)
* s += c[i][k] * tmp[8 * k + j];
*/
s += c[i][0] * tmp[8 * 0 + j];
s += c[i][1] * tmp[8 * 1 + j];
s += c[i][2] * tmp[8 * 2 + j];
s += c[i][3] * tmp[8 * 3 + j];
s += c[i][4] * tmp[8 * 4 + j];
s += c[i][5] * tmp[8 * 5 + j];
s += c[i][6] * tmp[8 * 6 + j];
s += c[i][7] * tmp[8 * 7 + j];
block[8 * i + j] = (short)floor(s + 0.499999);
/*
* reason for adding 0.499999 instead of 0.5:
* s is quite often x.5 (at least for i and/or j = 0 or 4)
* and setting the rounding threshold exactly to 0.5 leads to an
* extremely high arithmetic implementation dependency of the result;
* s being between x.5 and x.500001 (which is now incorrectly rounded
* downwards instead of upwards) is assumed to occur less often
* (if at all)
*/
}
}

1291
libavcodec/h263.c Normal file

File diff suppressed because it is too large Load Diff

115
libavcodec/h263data.h Normal file
View File

@ -0,0 +1,115 @@
/* intra MCBPC, mb_type = (intra), then (intraq) */
static const UINT8 intra_MCBPC_code[8] = { 1, 1, 2, 3, 1, 1, 2, 3 };
static const UINT8 intra_MCBPC_bits[8] = { 1, 3, 3, 3, 4, 6, 6, 6 };
/* inter MCBPC, mb_type = (inter), (intra), (interq), (intraq), (inter4v) */
static const UINT8 inter_MCBPC_code[20] = {
1, 3, 2, 5,
3, 4, 3, 3,
0, 1, 2, 3,
4, 4, 3, 2,
2, 5, 4, 5,
};
static const UINT8 inter_MCBPC_bits[20] = {
1, 4, 4, 6,
5, 8, 8, 7,
12, 12, 12, 12,
6, 9, 9, 9,
3, 7, 7, 8,
};
static const 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}
};
static const UINT8 mvtab[33][2] =
{
{1,1}, {1,2}, {1,3}, {1,4}, {3,6}, {5,7}, {4,7}, {3,7},
{11,9}, {10,9}, {9,9}, {17,10}, {16,10}, {15,10}, {14,10}, {13,10},
{12,10}, {11,10}, {10,10}, {9,10}, {8,10}, {7,10}, {6,10}, {5,10},
{4,10}, {7,11}, {6,11}, {5,11}, {4,11}, {3,11}, {2,11}, {3,12},
{2,12}
};
/* third non intra table */
const UINT16 inter_vlc[103][2] = {
{ 0x2, 2 },{ 0xf, 4 },{ 0x15, 6 },{ 0x17, 7 },
{ 0x1f, 8 },{ 0x25, 9 },{ 0x24, 9 },{ 0x21, 10 },
{ 0x20, 10 },{ 0x7, 11 },{ 0x6, 11 },{ 0x20, 11 },
{ 0x6, 3 },{ 0x14, 6 },{ 0x1e, 8 },{ 0xf, 10 },
{ 0x21, 11 },{ 0x50, 12 },{ 0xe, 4 },{ 0x1d, 8 },
{ 0xe, 10 },{ 0x51, 12 },{ 0xd, 5 },{ 0x23, 9 },
{ 0xd, 10 },{ 0xc, 5 },{ 0x22, 9 },{ 0x52, 12 },
{ 0xb, 5 },{ 0xc, 10 },{ 0x53, 12 },{ 0x13, 6 },
{ 0xb, 10 },{ 0x54, 12 },{ 0x12, 6 },{ 0xa, 10 },
{ 0x11, 6 },{ 0x9, 10 },{ 0x10, 6 },{ 0x8, 10 },
{ 0x16, 7 },{ 0x55, 12 },{ 0x15, 7 },{ 0x14, 7 },
{ 0x1c, 8 },{ 0x1b, 8 },{ 0x21, 9 },{ 0x20, 9 },
{ 0x1f, 9 },{ 0x1e, 9 },{ 0x1d, 9 },{ 0x1c, 9 },
{ 0x1b, 9 },{ 0x1a, 9 },{ 0x22, 11 },{ 0x23, 11 },
{ 0x56, 12 },{ 0x57, 12 },{ 0x7, 4 },{ 0x19, 9 },
{ 0x5, 11 },{ 0xf, 6 },{ 0x4, 11 },{ 0xe, 6 },
{ 0xd, 6 },{ 0xc, 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 },{ 0x7, 10 },{ 0x6, 10 },
{ 0x5, 10 },{ 0x4, 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 },{ 0x3, 7 },
};
const INT8 inter_level[102] = {
1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 1, 2, 3, 4,
5, 6, 1, 2, 3, 4, 1, 2,
3, 1, 2, 3, 1, 2, 3, 1,
2, 3, 1, 2, 1, 2, 1, 2,
1, 2, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 2, 3, 1, 2, 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, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1,
};
const INT8 inter_run[102] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 2, 2, 2, 2, 3, 3,
3, 4, 4, 4, 5, 5, 5, 6,
6, 6, 7, 7, 8, 8, 9, 9,
10, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 0, 0, 0, 1, 1, 2,
3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40,
};
static RLTable rl_inter = {
102,
58,
inter_vlc,
inter_run,
inter_level,
};
static const UINT16 h263_format[8][2] = {
{ 0, 0 },
{ 128, 96 },
{ 176, 144 },
{ 352, 288 },
{ 704, 576 },
{ 1408, 1152 },
};

205
libavcodec/h263dec.c Normal file
View File

@ -0,0 +1,205 @@
/*
* H263 decoder
* Copyright (c) 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "dsputil.h"
#include "avcodec.h"
#include "mpegvideo.h"
//#define DEBUG
static int h263_decode_init(AVCodecContext *avctx)
{
MpegEncContext *s = avctx->priv_data;
s->out_format = FMT_H263;
s->width = avctx->width;
s->height = avctx->height;
/* select sub codec */
switch(avctx->codec->id) {
case CODEC_ID_H263:
break;
case CODEC_ID_OPENDIVX:
s->time_increment_bits = 4; /* default value for broken headers */
s->h263_pred = 1;
break;
case CODEC_ID_MSMPEG4:
s->h263_msmpeg4 = 1;
s->h263_pred = 1;
break;
case CODEC_ID_H263I:
s->h263_intel = 1;
break;
default:
return -1;
}
/* for h263, we allocate the images after having read the header */
if (MPV_common_init(s) < 0)
return -1;
if (s->h263_msmpeg4)
msmpeg4_decode_init_vlc(s);
else
h263_decode_init_vlc(s);
return 0;
}
static int h263_decode_end(AVCodecContext *avctx)
{
MpegEncContext *s = avctx->priv_data;
MPV_common_end(s);
return 0;
}
static int h263_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
UINT8 *buf, int buf_size)
{
MpegEncContext *s = avctx->priv_data;
int ret;
DCTELEM block[6][64];
AVPicture *pict = data;
#ifdef DEBUG
printf("*****frame %d size=%d\n", avctx->frame_number, buf_size);
printf("bytes=%x %x %x %x\n", buf[0], buf[1], buf[2], buf[3]);
#endif
/* no supplementary picture */
if (buf_size == 0) {
*data_size = 0;
return 0;
}
init_get_bits(&s->gb, buf, buf_size);
/* let's go :-) */
if (s->h263_msmpeg4) {
ret = msmpeg4_decode_picture_header(s);
} else if (s->h263_pred) {
ret = mpeg4_decode_picture_header(s);
} else if (s->h263_intel) {
ret = intel_h263_decode_picture_header(s);
} else {
ret = h263_decode_picture_header(s);
}
if (ret < 0)
return -1;
MPV_frame_start(s);
#ifdef DEBUG
printf("qscale=%d\n", s->qscale);
#endif
/* decode each macroblock */
for(s->mb_y=0; s->mb_y < s->mb_height; s->mb_y++) {
for(s->mb_x=0; s->mb_x < s->mb_width; s->mb_x++) {
#ifdef DEBUG
printf("**mb x=%d y=%d\n", s->mb_x, s->mb_y);
#endif
/* DCT & quantize */
if (s->h263_msmpeg4) {
msmpeg4_dc_scale(s);
} else if (s->h263_pred) {
h263_dc_scale(s);
} else {
/* default quantization values */
s->y_dc_scale = 8;
s->c_dc_scale = 8;
}
memset(block, 0, sizeof(block));
s->mv_dir = MV_DIR_FORWARD;
s->mv_type = MV_TYPE_16X16;
if (s->h263_msmpeg4) {
if (msmpeg4_decode_mb(s, block) < 0)
return -1;
} else {
if (h263_decode_mb(s, block) < 0)
return -1;
}
MPV_decode_mb(s, block);
}
}
MPV_frame_end(s);
pict->data[0] = s->current_picture[0];
pict->data[1] = s->current_picture[1];
pict->data[2] = s->current_picture[2];
pict->linesize[0] = s->linesize;
pict->linesize[1] = s->linesize / 2;
pict->linesize[2] = s->linesize / 2;
avctx->quality = s->qscale;
*data_size = sizeof(AVPicture);
return buf_size;
}
AVCodec opendivx_decoder = {
"opendivx",
CODEC_TYPE_VIDEO,
CODEC_ID_OPENDIVX,
sizeof(MpegEncContext),
h263_decode_init,
NULL,
h263_decode_end,
h263_decode_frame,
};
AVCodec h263_decoder = {
"h263",
CODEC_TYPE_VIDEO,
CODEC_ID_H263,
sizeof(MpegEncContext),
h263_decode_init,
NULL,
h263_decode_end,
h263_decode_frame,
};
AVCodec msmpeg4_decoder = {
"msmpeg4",
CODEC_TYPE_VIDEO,
CODEC_ID_MSMPEG4,
sizeof(MpegEncContext),
h263_decode_init,
NULL,
h263_decode_end,
h263_decode_frame,
};
AVCodec h263i_decoder = {
"h263i",
CODEC_TYPE_VIDEO,
CODEC_ID_H263I,
sizeof(MpegEncContext),
h263_decode_init,
NULL,
h263_decode_end,
h263_decode_frame,
};

102
libavcodec/i386/cputest.c Normal file
View File

@ -0,0 +1,102 @@
/* Cpu detection code, extracted from mmx.h ((c)1997-99 by H. Dietz
and R. Fisher). Converted to C and improved by Gerard Lantau */
#include <stdlib.h>
#include "../dsputil.h"
#define cpuid(index,eax,ebx,ecx,edx) \
asm ("cpuid" \
: "=a" (eax), "=b" (ebx), \
"=c" (ecx), "=d" (edx) \
: "a" (index) \
: "cc")
/* Function to test if multimedia instructions are supported... */
int mm_support(void)
{
int rval;
int eax, ebx, ecx, edx;
__asm__ __volatile__ (
/* See if CPUID instruction is supported ... */
/* ... Get copies of EFLAGS into eax and ecx */
"pushf\n\t"
"popl %0\n\t"
"movl %0, %1\n\t"
/* ... Toggle the ID bit in one copy and store */
/* to the EFLAGS reg */
"xorl $0x200000, %0\n\t"
"push %0\n\t"
"popf\n\t"
/* ... Get the (hopefully modified) EFLAGS */
"pushf\n\t"
"popl %0\n\t"
: "=a" (eax), "=c" (ecx)
:
: "cc"
);
if (eax == ecx)
return 0; /* CPUID not supported */
cpuid(0, eax, ebx, ecx, edx);
if (ebx == 0x756e6547 &&
edx == 0x49656e69 &&
ecx == 0x6c65746e) {
/* intel */
inteltest:
cpuid(1, eax, ebx, ecx, edx);
if ((edx & 0x00800000) == 0)
return 0;
rval = MM_MMX;
if (edx & 0x02000000)
rval |= MM_MMXEXT | MM_SSE;
if (edx & 0x04000000)
rval |= MM_SSE2;
return rval;
} else if (ebx == 0x68747541 &&
edx == 0x69746e65 &&
ecx == 0x444d4163) {
/* AMD */
cpuid(0x80000000, eax, ebx, ecx, edx);
if ((unsigned)eax < 0x80000001)
goto inteltest;
cpuid(0x80000001, eax, ebx, ecx, edx);
if ((edx & 0x00800000) == 0)
return 0;
rval = MM_MMX;
if (edx & 0x80000000)
rval |= MM_3DNOW;
if (edx & 0x00400000)
rval |= MM_MMXEXT;
return rval;
} else if (ebx == 0x69727943 &&
edx == 0x736e4978 &&
ecx == 0x64616574) {
/* Cyrix Section */
/* See if extended CPUID level 80000001 is supported */
/* The value of CPUID/80000001 for the 6x86MX is undefined
according to the Cyrix CPU Detection Guide (Preliminary
Rev. 1.01 table 1), so we'll check the value of eax for
CPUID/0 to see if standard CPUID level 2 is supported.
According to the table, the only CPU which supports level
2 is also the only one which supports extended CPUID levels.
*/
if (eax != 2)
goto inteltest;
cpuid(0x80000001, eax, ebx, ecx, edx);
if ((eax & 0x00800000) == 0)
return 0;
rval = MM_MMX;
if (eax & 0x01000000)
rval |= MM_MMXEXT;
return rval;
} else {
return 0;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,352 @@
/*
* DSP utils : average functions are compiled twice for 3dnow/mmx2
* Copyright (c) 2000, 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* MMX optimization by Nick Kurshev <nickols_k@mail.ru>
*/
static void DEF(put_pixels_x2)(UINT8 *block, const UINT8 *pixels, int line_size, int h)
{
int dh, hh;
UINT8 *p;
const UINT8 *pix;
p = block;
pix = pixels;
hh=h>>2;
dh=h&3;
while(hh--) {
__asm __volatile(
"movq %4, %%mm0\n\t"
"movq 1%4, %%mm1\n\t"
"movq %5, %%mm2\n\t"
"movq 1%5, %%mm3\n\t"
"movq %6, %%mm4\n\t"
"movq 1%6, %%mm5\n\t"
"movq %7, %%mm6\n\t"
"movq 1%7, %%mm7\n\t"
PAVGB" %%mm1, %%mm0\n\t"
PAVGB" %%mm3, %%mm2\n\t"
PAVGB" %%mm5, %%mm4\n\t"
PAVGB" %%mm7, %%mm6\n\t"
"movq %%mm0, %0\n\t"
"movq %%mm2, %1\n\t"
"movq %%mm4, %2\n\t"
"movq %%mm6, %3\n\t"
:"=m"(*p), "=m"(*(p+line_size)), "=m"(*(p+line_size*2)), "=m"(*(p+line_size*3))
:"m"(*pix), "m"(*(pix+line_size)), "m"(*(pix+line_size*2)), "m"(*(pix+line_size*3))
:"memory");
pix += line_size*4; p += line_size*4;
}
while(dh--) {
__asm __volatile(
"movq %1, %%mm0\n\t"
"movq 1%1, %%mm1\n\t"
PAVGB" %%mm1, %%mm0\n\t"
"movq %%mm0, %0\n\t"
:"=m"(*p)
:"m"(*pix)
:"memory");
pix += line_size; p += line_size;
}
emms();
}
static void DEF(put_pixels_y2)(UINT8 *block, const UINT8 *pixels, int line_size, int h)
{
int dh, hh;
UINT8 *p;
const UINT8 *pix;
p = block;
pix = pixels;
hh=h>>1;
dh=h&1;
while(hh--) {
__asm __volatile(
"movq %2, %%mm0\n\t"
"movq %3, %%mm1\n\t"
"movq %4, %%mm2\n\t"
PAVGB" %%mm1, %%mm0\n\t"
PAVGB" %%mm2, %%mm1\n\t"
"movq %%mm0, %0\n\t"
"movq %%mm1, %1\n\t"
:"=m"(*p), "=m"(*(p+line_size))
:"m"(*pix), "m"(*(pix+line_size)),
"m"(*(pix+line_size*2))
:"memory");
pix += line_size*2;
p += line_size*2;
}
if(dh) {
__asm __volatile(
"movq %1, %%mm0\n\t"
"movq %2, %%mm1\n\t"
PAVGB" %%mm1, %%mm0\n\t"
"movq %%mm0, %0\n\t"
:"=m"(*p)
:"m"(*pix),
"m"(*(pix+line_size))
:"memory");
}
emms();
}
static void DEF(avg_pixels)(UINT8 *block, const UINT8 *pixels, int line_size, int h)
{
int dh, hh;
UINT8 *p;
const UINT8 *pix;
p = block;
pix = pixels;
hh=h>>2;
dh=h&3;
while(hh--) {
__asm __volatile(
"movq %0, %%mm0\n\t"
"movq %4, %%mm1\n\t"
"movq %1, %%mm2\n\t"
"movq %5, %%mm3\n\t"
"movq %2, %%mm4\n\t"
"movq %6, %%mm5\n\t"
"movq %3, %%mm6\n\t"
"movq %7, %%mm7\n\t"
PAVGB" %%mm1, %%mm0\n\t"
PAVGB" %%mm3, %%mm2\n\t"
PAVGB" %%mm5, %%mm4\n\t"
PAVGB" %%mm7, %%mm6\n\t"
"movq %%mm0, %0\n\t"
"movq %%mm2, %1\n\t"
"movq %%mm4, %2\n\t"
"movq %%mm6, %3\n\t"
:"=m"(*p), "=m"(*(p+line_size)), "=m"(*(p+line_size*2)), "=m"(*(p+line_size*3))
:"m"(*pix), "m"(*(pix+line_size)), "m"(*(pix+line_size*2)), "m"(*(pix+line_size*3))
:"memory");
pix += line_size*4; p += line_size*4;
}
while(dh--) {
__asm __volatile(
"movq %0, %%mm0\n\t"
"movq %1, %%mm1\n\t"
PAVGB" %%mm1, %%mm0\n\t"
"movq %%mm0, %0\n\t"
:"=m"(*p)
:"m"(*pix)
:"memory");
pix += line_size; p += line_size;
}
emms();
}
static void DEF(avg_pixels_x2)( UINT8 *block, const UINT8 *pixels, int line_size, int h)
{
int dh, hh;
UINT8 *p;
const UINT8 *pix;
p = block;
pix = pixels;
hh=h>>1;
dh=h&1;
while(hh--) {
__asm __volatile(
"movq %2, %%mm2\n\t"
"movq 1%2, %%mm3\n\t"
"movq %3, %%mm4\n\t"
"movq 1%3, %%mm5\n\t"
"movq %0, %%mm0\n\t"
"movq %1, %%mm1\n\t"
PAVGB" %%mm3, %%mm2\n\t"
PAVGB" %%mm2, %%mm0\n\t"
PAVGB" %%mm5, %%mm4\n\t"
PAVGB" %%mm4, %%mm1\n\t"
"movq %%mm0, %0\n\t"
"movq %%mm1, %1\n\t"
:"=m"(*p), "=m"(*(p+line_size))
:"m"(*pix), "m"(*(pix+line_size))
:"memory");
pix += line_size*2;
p += line_size*2;
}
if(dh) {
__asm __volatile(
"movq %1, %%mm1\n\t"
"movq 1%1, %%mm2\n\t"
"movq %0, %%mm0\n\t"
PAVGB" %%mm2, %%mm1\n\t"
PAVGB" %%mm1, %%mm0\n\t"
"movq %%mm0, %0\n\t"
:"=m"(*p)
:"m"(*pix)
:"memory");
}
emms();
}
static void DEF(avg_pixels_y2)( UINT8 *block, const UINT8 *pixels, int line_size, int h)
{
int dh, hh;
UINT8 *p;
const UINT8 *pix;
p = block;
pix = pixels;
hh=h>>1;
dh=h&1;
while(hh--) {
__asm __volatile(
"movq %2, %%mm2\n\t"
"movq %3, %%mm3\n\t"
"movq %3, %%mm4\n\t"
"movq %4, %%mm5\n\t"
"movq %0, %%mm0\n\t"
"movq %1, %%mm1\n\t"
PAVGB" %%mm3, %%mm2\n\t"
PAVGB" %%mm2, %%mm0\n\t"
PAVGB" %%mm5, %%mm4\n\t"
PAVGB" %%mm4, %%mm1\n\t"
"movq %%mm0, %0\n\t"
"movq %%mm1, %1\n\t"
:"=m"(*p), "=m"(*(p+line_size))
:"m"(*pix), "m"(*(pix+line_size)), "m"(*(pix+line_size*2))
:"memory");
pix += line_size*2;
p += line_size*2;
}
if(dh) {
__asm __volatile(
"movq %1, %%mm1\n\t"
"movq %2, %%mm2\n\t"
"movq %0, %%mm0\n\t"
PAVGB" %%mm2, %%mm1\n\t"
PAVGB" %%mm1, %%mm0\n\t"
"movq %%mm0, %0\n\t"
:"=m"(*p)
:"m"(*pix), "m"(*(pix+line_size))
:"memory");
}
emms();
}
static void DEF(avg_pixels_xy2)( UINT8 *block, const UINT8 *pixels, int line_size, int h)
{
UINT8 *p;
const UINT8 *pix;
p = block;
pix = pixels;
__asm __volatile(
"pxor %%mm7, %%mm7\n\t"
"movq %0, %%mm6\n\t"
::"m"(mm_wtwo[0]):"memory");
do {
__asm __volatile(
"movq %1, %%mm0\n\t"
"movq %2, %%mm1\n\t"
"movq 1%1, %%mm4\n\t"
"movq 1%2, %%mm5\n\t"
"movq %%mm0, %%mm2\n\t"
"movq %%mm1, %%mm3\n\t"
"punpcklbw %%mm7, %%mm0\n\t"
"punpcklbw %%mm7, %%mm1\n\t"
"punpckhbw %%mm7, %%mm2\n\t"
"punpckhbw %%mm7, %%mm3\n\t"
"paddusw %%mm1, %%mm0\n\t"
"paddusw %%mm3, %%mm2\n\t"
"movq %%mm4, %%mm1\n\t"
"movq %%mm5, %%mm3\n\t"
"punpcklbw %%mm7, %%mm4\n\t"
"punpcklbw %%mm7, %%mm5\n\t"
"punpckhbw %%mm7, %%mm1\n\t"
"punpckhbw %%mm7, %%mm3\n\t"
"paddusw %%mm5, %%mm4\n\t"
"paddusw %%mm3, %%mm1\n\t"
"paddusw %%mm6, %%mm4\n\t"
"paddusw %%mm6, %%mm1\n\t"
"paddusw %%mm4, %%mm0\n\t"
"paddusw %%mm1, %%mm2\n\t"
"psrlw $2, %%mm0\n\t"
"psrlw $2, %%mm2\n\t"
"packuswb %%mm2, %%mm0\n\t"
PAVGB" %0, %%mm0\n\t"
"movq %%mm0, %0\n\t"
:"=m"(*p)
:"m"(*pix),
"m"(*(pix+line_size))
:"memory");
pix += line_size;
p += line_size ;
} while(--h);
emms();
}
static void DEF(sub_pixels_x2)( DCTELEM *block, const UINT8 *pixels, int line_size, int h)
{
DCTELEM *p;
const UINT8 *pix;
p = block;
pix = pixels;
__asm __volatile(
"pxor %%mm7, %%mm7":::"memory");
do {
__asm __volatile(
"movq 1%1, %%mm2\n\t"
"movq %0, %%mm0\n\t"
PAVGB" %1, %%mm2\n\t"
"movq 8%0, %%mm1\n\t"
"movq %%mm2, %%mm3\n\t"
"punpcklbw %%mm7, %%mm2\n\t"
"punpckhbw %%mm7, %%mm3\n\t"
"psubsw %%mm2, %%mm0\n\t"
"psubsw %%mm3, %%mm1\n\t"
"movq %%mm0, %0\n\t"
"movq %%mm1, 8%0\n\t"
:"=m"(*p)
:"m"(*pix)
:"memory");
pix += line_size;
p += 8;
} while (--h);
emms();
}
static void DEF(sub_pixels_y2)( DCTELEM *block, const UINT8 *pixels, int line_size, int h)
{
DCTELEM *p;
const UINT8 *pix;
p = block;
pix = pixels;
__asm __volatile(
"pxor %%mm7, %%mm7":::"memory");
do {
__asm __volatile(
"movq %2, %%mm2\n\t"
"movq %0, %%mm0\n\t"
PAVGB" %1, %%mm2\n\t"
"movq 8%0, %%mm1\n\t"
"movq %%mm2, %%mm3\n\t"
"punpcklbw %%mm7, %%mm2\n\t"
"punpckhbw %%mm7, %%mm3\n\t"
"psubsw %%mm2, %%mm0\n\t"
"psubsw %%mm3, %%mm1\n\t"
"movq %%mm0, %0\n\t"
"movq %%mm1, 8%0\n\t"
:"=m"(*p)
:"m"(*pix), "m"(*(pix+line_size))
:"memory");
pix += line_size;
p += 8;
} while (--h);
emms();
}

507
libavcodec/i386/fdct_mmx.s Normal file
View File

@ -0,0 +1,507 @@
; //////////////////////////////////////////////////////////////////////////////
; //
; // fdctam32.c - AP922 MMX(3D-Now) forward-DCT
; // ----------
; // Intel Application Note AP-922 - fast, precise implementation of DCT
; // http://developer.intel.com/vtune/cbts/appnotes.htm
; // ----------
; //
; // This routine can use a 3D-Now/MMX enhancement to increase the
; // accuracy of the fdct_col_4 macro. The dct_col function uses 3D-Now's
; // PMHULHRW instead of MMX's PMHULHW(and POR). The substitution improves
; // accuracy very slightly with performance penalty. If the target CPU
; // does not support 3D-Now, then this function cannot be executed.
; //
; // For a fast, precise MMX implementation of inverse-DCT
; // visit http://www.elecard.com/peter
; //
; // v1.0 07/22/2000 (initial release)
; //
; // liaor@iname.com http://members.tripod.com/~liaor
; //////////////////////////////////////////////////////////////////////////////
;;;
;;; A.Stevens Jul 2000: ported to nasm syntax and disentangled from
;;; from Win**** compiler specific stuff.
;;; All the real work was done above though.
;;; See above for how to optimise quality on 3DNow! CPU's
;;
;; Macros for code-readability...
;;
%define INP eax ; pointer to (short *blk)
%define OUT ecx ; pointer to output (temporary store space qwTemp[])
%define TABLE ebx ; pointer to tab_frw_01234567[]
%define TABLEF ebx ; pointer to tg_all_16
%define round_frw_row edx
%define x0 INP + 0*16
%define x1 INP + 1*16
%define x2 INP + 2*16
%define x3 INP + 3*16
%define x4 INP + 4*16
%define x5 INP + 5*16
%define x6 INP + 6*16
%define x7 INP + 7*16
%define y0 OUT + 0*16
%define y1 OUT + 1*16
%define y2 OUT + 2*16
%define y3 OUT + 3*16
%define y4 OUT + 4*16
%define y5 OUT + 5*16
%define y6 OUT + 6*16
%define y7 OUT + 7*16
;;
;; Constants for DCT
;;
%define BITS_FRW_ACC 3 ; 2 or 3 for accuracy
%define SHIFT_FRW_COL BITS_FRW_ACC
%define SHIFT_FRW_ROW (BITS_FRW_ACC + 17)
%define RND_FRW_ROW (1 << (SHIFT_FRW_ROW-1))
%define RND_FRW_COL (1 << (SHIFT_FRW_COL-1))
extern fdct_one_corr
extern fdct_r_row ; Defined in C for convenience
;;
;; Concatenated table of forward dct transformation coeffs.
;;
extern fdct_tg_all_16 ; Defined in C for convenience
;; Offsets into table..
%define tg_1_16 (TABLEF + 0)
%define tg_2_16 (TABLEF + 8)
%define tg_3_16 (TABLEF + 16)
%define cos_4_16 (TABLEF + 24)
%define ocos_4_16 (TABLEF + 32)
;;
;; Concatenated table of forward dct coefficients
;;
extern tab_frw_01234567 ; Defined in C for convenience
;; Offsets into table..
SECTION .text
global fdct_mmx
;;;
;;; void fdct_mmx( short *blk )
;;;
; ////////////////////////////////////////////////////////////////////////
; //
; // The high-level pseudocode for the fdct_am32() routine :
; //
; // fdct_am32()
; // {
; // forward_dct_col03(); // dct_column transform on cols 0-3
; // forward_dct_col47(); // dct_column transform on cols 4-7
; // for ( j = 0; j < 8; j=j+1 )
; // forward_dct_row1(j); // dct_row transform on row #j
; // }
; //
;
align 32
fdct_mmx:
push ebp ; save stack pointer
mov ebp, esp ; link
push ebx
push ecx
push edx
push edi
mov INP, [ebp+8]; ; input data is row 0 of blk[]
;// transform the left half of the matrix (4 columns)
lea TABLEF, [fdct_tg_all_16];
mov OUT, INP;
; lea round_frw_col, [r_frw_col]
; for ( i = 0; i < 2; i = i + 1)
; the for-loop is executed twice. We are better off unrolling the
; loop to avoid branch misprediction.
.mmx32_fdct_col03:
movq mm0, [x1] ; 0 ; x1
;;
movq mm1, [x6] ; 1 ; x6
movq mm2, mm0 ; 2 ; x1
movq mm3, [x2] ; 3 ; x2
paddsw mm0, mm1 ; t1 = x[1] + x[6]
movq mm4, [x5] ; 4 ; x5
psllw mm0, SHIFT_FRW_COL ; t1
movq mm5, [x0] ; 5 ; x0
paddsw mm4, mm3 ; t2 = x[2] + x[5]
paddsw mm5, [x7] ; t0 = x[0] + x[7]
psllw mm4, SHIFT_FRW_COL ; t2
movq mm6, mm0 ; 6 ; t1
psubsw mm2, mm1 ; 1 ; t6 = x[1] - x[6]
movq mm1, [tg_2_16] ; 1 ; tg_2_16
psubsw mm0, mm4 ; tm12 = t1 - t2
movq mm7, [x3] ; 7 ; x3
pmulhw mm1, mm0 ; tm12*tg_2_16
paddsw mm7, [x4] ; t3 = x[3] + x[4]
psllw mm5, SHIFT_FRW_COL ; t0
paddsw mm6, mm4 ; 4 ; tp12 = t1 + t2
psllw mm7, SHIFT_FRW_COL ; t3
movq mm4, mm5 ; 4 ; t0
psubsw mm5, mm7 ; tm03 = t0 - t3
paddsw mm1, mm5 ; y2 = tm03 + tm12*tg_2_16
paddsw mm4, mm7 ; 7 ; tp03 = t0 + t3
por mm1, [fdct_one_corr] ; correction y2 +0.5
psllw mm2, SHIFT_FRW_COL+1 ; t6
pmulhw mm5, [tg_2_16] ; tm03*tg_2_16
movq mm7, mm4 ; 7 ; tp03
psubsw mm3, [x5] ; t5 = x[2] - x[5]
psubsw mm4, mm6 ; y4 = tp03 - tp12
movq [y2], mm1 ; 1 ; save y2
paddsw mm7, mm6 ; 6 ; y0 = tp03 + tp12
movq mm1, [x3] ; 1 ; x3
psllw mm3, SHIFT_FRW_COL+1 ; t5
psubsw mm1, [x4] ; t4 = x[3] - x[4]
movq mm6, mm2 ; 6 ; t6
movq [y4], mm4 ; 4 ; save y4
paddsw mm2, mm3 ; t6 + t5
pmulhw mm2, [ocos_4_16] ; tp65 = (t6 + t5)*cos_4_16
psubsw mm6, mm3 ; 3 ; t6 - t5
pmulhw mm6, [ocos_4_16] ; tm65 = (t6 - t5)*cos_4_16
psubsw mm5, mm0 ; 0 ; y6 = tm03*tg_2_16 - tm12
por mm5, [fdct_one_corr] ; correction y6 +0.5
psllw mm1, SHIFT_FRW_COL ; t4
por mm2, [fdct_one_corr] ; correction tp65 +0.5
movq mm4, mm1 ; 4 ; t4
movq mm3, [x0] ; 3 ; x0
paddsw mm1, mm6 ; tp465 = t4 + tm65
psubsw mm3, [x7] ; t7 = x[0] - x[7]
psubsw mm4, mm6 ; 6 ; tm465 = t4 - tm65
movq mm0, [tg_1_16] ; 0 ; tg_1_16
psllw mm3, SHIFT_FRW_COL ; t7
movq mm6, [tg_3_16] ; 6 ; tg_3_16
pmulhw mm0, mm1 ; tp465*tg_1_16
movq [y0], mm7 ; 7 ; save y0
pmulhw mm6, mm4 ; tm465*tg_3_16
movq [y6], mm5 ; 5 ; save y6
movq mm7, mm3 ; 7 ; t7
movq mm5, [tg_3_16] ; 5 ; tg_3_16
psubsw mm7, mm2 ; tm765 = t7 - tp65
paddsw mm3, mm2 ; 2 ; tp765 = t7 + tp65
pmulhw mm5, mm7 ; tm765*tg_3_16
paddsw mm0, mm3 ; y1 = tp765 + tp465*tg_1_16
paddsw mm6, mm4 ; tm465*tg_3_16
pmulhw mm3, [tg_1_16] ; tp765*tg_1_16
;;
por mm0, [fdct_one_corr] ; correction y1 +0.5
paddsw mm5, mm7 ; tm765*tg_3_16
psubsw mm7, mm6 ; 6 ; y3 = tm765 - tm465*tg_3_16
add INP, 0x08 ; ; increment pointer
movq [y1], mm0 ; 0 ; save y1
paddsw mm5, mm4 ; 4 ; y5 = tm765*tg_3_16 + tm465
movq [y3], mm7 ; 7 ; save y3
psubsw mm3, mm1 ; 1 ; y7 = tp765*tg_1_16 - tp465
movq [y5], mm5 ; 5 ; save y5
.mmx32_fdct_col47: ; begin processing last four columns
movq mm0, [x1] ; 0 ; x1
;;
movq [y7], mm3 ; 3 ; save y7 (columns 0-4)
;;
movq mm1, [x6] ; 1 ; x6
movq mm2, mm0 ; 2 ; x1
movq mm3, [x2] ; 3 ; x2
paddsw mm0, mm1 ; t1 = x[1] + x[6]
movq mm4, [x5] ; 4 ; x5
psllw mm0, SHIFT_FRW_COL ; t1
movq mm5, [x0] ; 5 ; x0
paddsw mm4, mm3 ; t2 = x[2] + x[5]
paddsw mm5, [x7] ; t0 = x[0] + x[7]
psllw mm4, SHIFT_FRW_COL ; t2
movq mm6, mm0 ; 6 ; t1
psubsw mm2, mm1 ; 1 ; t6 = x[1] - x[6]
movq mm1, [tg_2_16] ; 1 ; tg_2_16
psubsw mm0, mm4 ; tm12 = t1 - t2
movq mm7, [x3] ; 7 ; x3
pmulhw mm1, mm0 ; tm12*tg_2_16
paddsw mm7, [x4] ; t3 = x[3] + x[4]
psllw mm5, SHIFT_FRW_COL ; t0
paddsw mm6, mm4 ; 4 ; tp12 = t1 + t2
psllw mm7, SHIFT_FRW_COL ; t3
movq mm4, mm5 ; 4 ; t0
psubsw mm5, mm7 ; tm03 = t0 - t3
paddsw mm1, mm5 ; y2 = tm03 + tm12*tg_2_16
paddsw mm4, mm7 ; 7 ; tp03 = t0 + t3
por mm1, [fdct_one_corr] ; correction y2 +0.5
psllw mm2, SHIFT_FRW_COL+1 ; t6
pmulhw mm5, [tg_2_16] ; tm03*tg_2_16
movq mm7, mm4 ; 7 ; tp03
psubsw mm3, [x5] ; t5 = x[2] - x[5]
psubsw mm4, mm6 ; y4 = tp03 - tp12
movq [y2+8], mm1 ; 1 ; save y2
paddsw mm7, mm6 ; 6 ; y0 = tp03 + tp12
movq mm1, [x3] ; 1 ; x3
psllw mm3, SHIFT_FRW_COL+1 ; t5
psubsw mm1, [x4] ; t4 = x[3] - x[4]
movq mm6, mm2 ; 6 ; t6
movq [y4+8], mm4 ; 4 ; save y4
paddsw mm2, mm3 ; t6 + t5
pmulhw mm2, [ocos_4_16] ; tp65 = (t6 + t5)*cos_4_16
psubsw mm6, mm3 ; 3 ; t6 - t5
pmulhw mm6, [ocos_4_16] ; tm65 = (t6 - t5)*cos_4_16
psubsw mm5, mm0 ; 0 ; y6 = tm03*tg_2_16 - tm12
por mm5, [fdct_one_corr] ; correction y6 +0.5
psllw mm1, SHIFT_FRW_COL ; t4
por mm2, [fdct_one_corr] ; correction tp65 +0.5
movq mm4, mm1 ; 4 ; t4
movq mm3, [x0] ; 3 ; x0
paddsw mm1, mm6 ; tp465 = t4 + tm65
psubsw mm3, [x7] ; t7 = x[0] - x[7]
psubsw mm4, mm6 ; 6 ; tm465 = t4 - tm65
movq mm0, [tg_1_16] ; 0 ; tg_1_16
psllw mm3, SHIFT_FRW_COL ; t7
movq mm6, [tg_3_16] ; 6 ; tg_3_16
pmulhw mm0, mm1 ; tp465*tg_1_16
movq [y0+8], mm7 ; 7 ; save y0
pmulhw mm6, mm4 ; tm465*tg_3_16
movq [y6+8], mm5 ; 5 ; save y6
movq mm7, mm3 ; 7 ; t7
movq mm5, [tg_3_16] ; 5 ; tg_3_16
psubsw mm7, mm2 ; tm765 = t7 - tp65
paddsw mm3, mm2 ; 2 ; tp765 = t7 + tp65
pmulhw mm5, mm7 ; tm765*tg_3_16
paddsw mm0, mm3 ; y1 = tp765 + tp465*tg_1_16
paddsw mm6, mm4 ; tm465*tg_3_16
pmulhw mm3, [tg_1_16] ; tp765*tg_1_16
;;
por mm0, [fdct_one_corr] ; correction y1 +0.5
paddsw mm5, mm7 ; tm765*tg_3_16
psubsw mm7, mm6 ; 6 ; y3 = tm765 - tm465*tg_3_16
;;
movq [y1+8], mm0 ; 0 ; save y1
paddsw mm5, mm4 ; 4 ; y5 = tm765*tg_3_16 + tm465
movq [y3+8], mm7 ; 7 ; save y3
psubsw mm3, mm1 ; 1 ; y7 = tp765*tg_1_16 - tp465
movq [y5+8], mm5 ; 5 ; save y5
movq [y7+8], mm3 ; 3 ; save y7
; emms;
; } ; end of forward_dct_col07()
; done with dct_row transform
; fdct_mmx32_cols() --
; the following subroutine repeats the row-transform operation,
; except with different shift&round constants. This version
; does NOT transpose the output again. Thus the final output
; is transposed with respect to the source.
;
; The output is stored into blk[], which destroys the original
; input data.
mov INP, [ebp+8]; ;; row 0
mov edi, 0x08; ;x = 8
lea TABLE, [tab_frw_01234567]; ; row 0
mov OUT, INP;
lea round_frw_row, [fdct_r_row];
; for ( x = 8; x > 0; --x ) ; transform one row per iteration
; ---------- loop begin
.lp_mmx_fdct_row1:
movd mm5, [INP+12]; ; mm5 = 7 6
punpcklwd mm5, [INP+8] ; mm5 = 5 7 4 6
movq mm2, mm5; ; mm2 = 5 7 4 6
psrlq mm5, 32; ; mm5 = _ _ 5 7
movq mm0, [INP]; ; mm0 = 3 2 1 0
punpcklwd mm5, mm2;; mm5 = 4 5 6 7
movq mm1, mm0; ; mm1 = 3 2 1 0
paddsw mm0, mm5; ; mm0 = [3+4, 2+5, 1+6, 0+7] (xt3, xt2, xt1, xt0)
psubsw mm1, mm5; ; mm1 = [3-4, 2-5, 1-6, 0-7] (xt7, xt6, xt5, xt4)
movq mm2, mm0; ; mm2 = [ xt3 xt2 xt1 xt0 ]
;movq [ xt3xt2xt1xt0 ], mm0;
;movq [ xt7xt6xt5xt4 ], mm1;
punpcklwd mm0, mm1;; mm0 = [ xt5 xt1 xt4 xt0 ]
punpckhwd mm2, mm1;; mm2 = [ xt7 xt3 xt6 xt2 ]
movq mm1, mm2; ; mm1
;; shuffle bytes around
; movq mm0, [INP] ; 0 ; x3 x2 x1 x0
; movq mm1, [INP+8] ; 1 ; x7 x6 x5 x4
movq mm2, mm0 ; 2 ; x3 x2 x1 x0
movq mm3, [TABLE] ; 3 ; w06 w04 w02 w00
punpcklwd mm0, mm1 ; x5 x1 x4 x0
movq mm5, mm0 ; 5 ; x5 x1 x4 x0
punpckldq mm0, mm0 ; x4 x0 x4 x0 [ xt2 xt0 xt2 xt0 ]
movq mm4, [TABLE+8] ; 4 ; w07 w05 w03 w01
punpckhwd mm2, mm1 ; 1 ; x7 x3 x6 x2
pmaddwd mm3, mm0 ; x4*w06+x0*w04 x4*w02+x0*w00
movq mm6, mm2 ; 6 ; x7 x3 x6 x2
movq mm1, [TABLE+32] ; 1 ; w22 w20 w18 w16
punpckldq mm2, mm2 ; x6 x2 x6 x2 [ xt3 xt1 xt3 xt1 ]
pmaddwd mm4, mm2 ; x6*w07+x2*w05 x6*w03+x2*w01
punpckhdq mm5, mm5 ; x5 x1 x5 x1 [ xt6 xt4 xt6 xt4 ]
pmaddwd mm0, [TABLE+16] ; x4*w14+x0*w12 x4*w10+x0*w08
punpckhdq mm6, mm6 ; x7 x3 x7 x3 [ xt7 xt5 xt7 xt5 ]
movq mm7, [TABLE+40] ; 7 ; w23 w21 w19 w17
pmaddwd mm1, mm5 ; x5*w22+x1*w20 x5*w18+x1*w16
;mm3 = a1, a0 (y2,y0)
;mm1 = b1, b0 (y3,y1)
;mm0 = a3,a2 (y6,y4)
;mm5 = b3,b2 (y7,y5)
paddd mm3, [round_frw_row] ; +rounder (y2,y0)
pmaddwd mm7, mm6 ; x7*w23+x3*w21 x7*w19+x3*w17
pmaddwd mm2, [TABLE+24] ; x6*w15+x2*w13 x6*w11+x2*w09
paddd mm3, mm4 ; 4 ; a1=sum(even1) a0=sum(even0) ; now ( y2, y0)
pmaddwd mm5, [TABLE+48] ; x5*w30+x1*w28 x5*w26+x1*w24
;;
pmaddwd mm6, [TABLE+56] ; x7*w31+x3*w29 x7*w27+x3*w25
paddd mm1, mm7 ; 7 ; b1=sum(odd1) b0=sum(odd0) ; now ( y3, y1)
paddd mm0, [round_frw_row] ; +rounder (y6,y4)
psrad mm3, SHIFT_FRW_ROW ; (y2, y0)
paddd mm1, [round_frw_row] ; +rounder (y3,y1)
paddd mm0, mm2 ; 2 ; a3=sum(even3) a2=sum(even2) ; now (y6, y4)
paddd mm5, [round_frw_row] ; +rounder (y7,y5)
psrad mm1, SHIFT_FRW_ROW ; y1=a1+b1 y0=a0+b0
paddd mm5, mm6 ; 6 ; b3=sum(odd3) b2=sum(odd2) ; now ( y7, y5)
psrad mm0, SHIFT_FRW_ROW ;y3=a3+b3 y2=a2+b2
add OUT, 16; ; increment row-output address by 1 row
psrad mm5, SHIFT_FRW_ROW ; y4=a3-b3 y5=a2-b2
add INP, 16; ; increment row-address by 1 row
packssdw mm3, mm0 ; 0 ; y6 y4 y2 y0
packssdw mm1, mm5 ; 3 ; y7 y5 y3 y1
movq mm6, mm3; ; mm0 = y6 y4 y2 y0
punpcklwd mm3, mm1; ; y3 y2 y1 y0
sub edi, 0x01; ; i = i - 1
punpckhwd mm6, mm1; ; y7 y6 y5 y4
add TABLE,64; ; increment to next table
movq [OUT-16], mm3 ; 1 ; save y3 y2 y1 y0
movq [OUT-8], mm6 ; 7 ; save y7 y6 y5 y4
cmp edi, 0x00;
jg near .lp_mmx_fdct_row1; ; begin fdct processing on next row
;;
;; Tidy up and return
;;
pop edi
pop edx
pop ecx
pop ebx
pop ebp ; restore stack pointer
emms
ret

143
libavcodec/i386/fdctdata.c Normal file
View File

@ -0,0 +1,143 @@
//////////////////////////////////////////////////////////////////////////////
//
// fdctam32.c - AP922 MMX(3D-Now) forward-DCT
// ----------
// Intel Application Note AP-922 - fast, precise implementation of DCT
// http://developer.intel.com/vtune/cbts/appnotes.htm
// ----------
//
// This routine uses a 3D-Now/MMX enhancement to increase the
// accuracy of the fdct_col_4 macro. The dct_col function uses 3D-Now's
// PMHULHRW instead of MMX's PMHULHW(and POR). The substitution improves
// accuracy very slightly with performance penalty. If the target CPU
// does not support 3D-Now, then this function cannot be executed.
// fdctmm32.c contains the standard MMX implementation of AP-922.
//
// For a fast, precise MMX implementation of inverse-DCT
// visit http://www.elecard.com/peter
//
// v1.0 07/22/2000 (initial release)
// Initial release of AP922 MMX(3D-Now) forward_DCT.
// This code was tested with Visual C++ 6.0Pro + service_pack4 +
// processor_pack_beta! If you have the processor_pack_beta, you can
// remove the #include for amd3dx.h, and substitute the 'normal'
// assembly lines for the macro'd versions. Otherwise, this
// code should compile 'as is', under Visual C++ 6.0 Pro.
//
// liaor@iname.com http://members.tripod.com/~liaor
//////////////////////////////////////////////////////////////////////////////
#include <inttypes.h>
//////////////////////////////////////////////////////////////////////
//
// constants for the forward DCT
// -----------------------------
//
// Be sure to check that your compiler is aligning all constants to QWORD
// (8-byte) memory boundaries! Otherwise the unaligned memory access will
// severely stall MMX execution.
//
//////////////////////////////////////////////////////////////////////
#define BITS_FRW_ACC 3 //; 2 or 3 for accuracy
#define SHIFT_FRW_COL BITS_FRW_ACC
#define SHIFT_FRW_ROW (BITS_FRW_ACC + 17)
//#define RND_FRW_ROW (262144 * (BITS_FRW_ACC - 1)) //; 1 << (SHIFT_FRW_ROW-1)
#define RND_FRW_ROW (1 << (SHIFT_FRW_ROW-1))
//#define RND_FRW_COL (2 * (BITS_FRW_ACC - 1)) //; 1 << (SHIFT_FRW_COL-1)
#define RND_FRW_COL (1 << (SHIFT_FRW_COL-1))
//concatenated table, for forward DCT transformation
const int16_t fdct_tg_all_16[] = {
13036, 13036, 13036, 13036, // tg * (2<<16) + 0.5
27146, 27146, 27146, 27146, // tg * (2<<16) + 0.5
-21746, -21746, -21746, -21746, // tg * (2<<16) + 0.5
-19195, -19195, -19195, -19195, //cos * (2<<16) + 0.5
23170, 23170, 23170, 23170 }; //cos * (2<<15) + 0.5
const long long fdct_one_corr = 0x0001000100010001LL;
const long fdct_r_row[2] = {RND_FRW_ROW, RND_FRW_ROW };
const int16_t tab_frw_01234567[] = { // forward_dct coeff table
//row0
16384, 16384, 21407, -8867, // w09 w01 w08 w00
16384, 16384, 8867, -21407, // w13 w05 w12 w04
16384, -16384, 8867, 21407, // w11 w03 w10 w02
-16384, 16384, -21407, -8867, // w15 w07 w14 w06
22725, 12873, 19266, -22725, // w22 w20 w18 w16
19266, 4520, -4520, -12873, // w23 w21 w19 w17
12873, 4520, 4520, 19266, // w30 w28 w26 w24
-22725, 19266, -12873, -22725, // w31 w29 w27 w25
//row1
22725, 22725, 29692, -12299, // w09 w01 w08 w00
22725, 22725, 12299, -29692, // w13 w05 w12 w04
22725, -22725, 12299, 29692, // w11 w03 w10 w02
-22725, 22725, -29692, -12299, // w15 w07 w14 w06
31521, 17855, 26722, -31521, // w22 w20 w18 w16
26722, 6270, -6270, -17855, // w23 w21 w19 w17
17855, 6270, 6270, 26722, // w30 w28 w26 w24
-31521, 26722, -17855, -31521, // w31 w29 w27 w25
//row2
21407, 21407, 27969, -11585, // w09 w01 w08 w00
21407, 21407, 11585, -27969, // w13 w05 w12 w04
21407, -21407, 11585, 27969, // w11 w03 w10 w02
-21407, 21407, -27969, -11585, // w15 w07 w14 w06
29692, 16819, 25172, -29692, // w22 w20 w18 w16
25172, 5906, -5906, -16819, // w23 w21 w19 w17
16819, 5906, 5906, 25172, // w30 w28 w26 w24
-29692, 25172, -16819, -29692, // w31 w29 w27 w25
//row3
19266, 19266, 25172, -10426, // w09 w01 w08 w00
19266, 19266, 10426, -25172, // w13 w05 w12 w04
19266, -19266, 10426, 25172, // w11 w03 w10 w02
-19266, 19266, -25172, -10426, // w15 w07 w14 w06,
26722, 15137, 22654, -26722, // w22 w20 w18 w16
22654, 5315, -5315, -15137, // w23 w21 w19 w17
15137, 5315, 5315, 22654, // w30 w28 w26 w24
-26722, 22654, -15137, -26722, // w31 w29 w27 w25,
//row4
16384, 16384, 21407, -8867, // w09 w01 w08 w00
16384, 16384, 8867, -21407, // w13 w05 w12 w04
16384, -16384, 8867, 21407, // w11 w03 w10 w02
-16384, 16384, -21407, -8867, // w15 w07 w14 w06
22725, 12873, 19266, -22725, // w22 w20 w18 w16
19266, 4520, -4520, -12873, // w23 w21 w19 w17
12873, 4520, 4520, 19266, // w30 w28 w26 w24
-22725, 19266, -12873, -22725, // w31 w29 w27 w25
//row5
19266, 19266, 25172, -10426, // w09 w01 w08 w00
19266, 19266, 10426, -25172, // w13 w05 w12 w04
19266, -19266, 10426, 25172, // w11 w03 w10 w02
-19266, 19266, -25172, -10426, // w15 w07 w14 w06
26722, 15137, 22654, -26722, // w22 w20 w18 w16
22654, 5315, -5315, -15137, // w23 w21 w19 w17
15137, 5315, 5315, 22654, // w30 w28 w26 w24
-26722, 22654, -15137, -26722, // w31 w29 w27 w25
//row6
21407, 21407, 27969, -11585, // w09 w01 w08 w00
21407, 21407, 11585, -27969, // w13 w05 w12 w04
21407, -21407, 11585, 27969, // w11 w03 w10 w02
-21407, 21407, -27969, -11585, // w15 w07 w14 w06,
29692, 16819, 25172, -29692, // w22 w20 w18 w16
25172, 5906, -5906, -16819, // w23 w21 w19 w17
16819, 5906, 5906, 25172, // w30 w28 w26 w24
-29692, 25172, -16819, -29692, // w31 w29 w27 w25,
//row7
22725, 22725, 29692, -12299, // w09 w01 w08 w00
22725, 22725, 12299, -29692, // w13 w05 w12 w04
22725, -22725, 12299, 29692, // w11 w03 w10 w02
-22725, 22725, -29692, -12299, // w15 w07 w14 w06,
31521, 17855, 26722, -31521, // w22 w20 w18 w16
26722, 6270, -6270, -17855, // w23 w21 w19 w17
17855, 6270, 6270, 26722, // w30 w28 w26 w24
-31521, 26722, -17855, -31521 // w31 w29 w27 w25
};

536
libavcodec/i386/mmx.h Normal file
View File

@ -0,0 +1,536 @@
/* mmx.h
MultiMedia eXtensions GCC interface library for IA32.
To use this library, simply include this header file
and compile with GCC. You MUST have inlining enabled
in order for mmx_ok() to work; this can be done by
simply using -O on the GCC command line.
Compiling with -DMMX_TRACE will cause detailed trace
output to be sent to stderr for each mmx operation.
This adds lots of code, and obviously slows execution to
a crawl, but can be very useful for debugging.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR ANY PARTICULAR PURPOSE.
1997-99 by H. Dietz and R. Fisher
Notes:
It appears that the latest gas has the pand problem fixed, therefore
I'll undefine BROKEN_PAND by default.
*/
#ifndef _MMX_H
#define _MMX_H
/* Warning: at this writing, the version of GAS packaged
with most Linux distributions does not handle the
parallel AND operation mnemonic correctly. If the
symbol BROKEN_PAND is defined, a slower alternative
coding will be used. If execution of mmxtest results
in an illegal instruction fault, define this symbol.
*/
#undef BROKEN_PAND
/* The type of an value that fits in an MMX register
(note that long long constant values MUST be suffixed
by LL and unsigned long long values by ULL, lest
they be truncated by the compiler)
*/
typedef union {
long long q; /* Quadword (64-bit) value */
unsigned long long uq; /* Unsigned Quadword */
int d[2]; /* 2 Doubleword (32-bit) values */
unsigned int ud[2]; /* 2 Unsigned Doubleword */
short w[4]; /* 4 Word (16-bit) values */
unsigned short uw[4]; /* 4 Unsigned Word */
char b[8]; /* 8 Byte (8-bit) values */
unsigned char ub[8]; /* 8 Unsigned Byte */
float s[2]; /* Single-precision (32-bit) value */
} __attribute__ ((aligned (8))) mmx_t; /* On an 8-byte (64-bit) boundary */
/* Helper functions for the instruction macros that follow...
(note that memory-to-register, m2r, instructions are nearly
as efficient as register-to-register, r2r, instructions;
however, memory-to-memory instructions are really simulated
as a convenience, and are only 1/3 as efficient)
*/
#ifdef MMX_TRACE
/* Include the stuff for printing a trace to stderr...
*/
#include <stdio.h>
#define mmx_i2r(op, imm, reg) \
{ \
mmx_t mmx_trace; \
mmx_trace.uq = (imm); \
fprintf(stderr, #op "_i2r(" #imm "=0x%08x%08x, ", \
mmx_trace.d[1], mmx_trace.d[0]); \
__asm__ __volatile__ ("movq %%" #reg ", %0" \
: "=X" (mmx_trace) \
: /* nothing */ ); \
fprintf(stderr, #reg "=0x%08x%08x) => ", \
mmx_trace.d[1], mmx_trace.d[0]); \
__asm__ __volatile__ (#op " %0, %%" #reg \
: /* nothing */ \
: "X" (imm)); \
__asm__ __volatile__ ("movq %%" #reg ", %0" \
: "=X" (mmx_trace) \
: /* nothing */ ); \
fprintf(stderr, #reg "=0x%08x%08x\n", \
mmx_trace.d[1], mmx_trace.d[0]); \
}
#define mmx_m2r(op, mem, reg) \
{ \
mmx_t mmx_trace; \
mmx_trace = (mem); \
fprintf(stderr, #op "_m2r(" #mem "=0x%08x%08x, ", \
mmx_trace.d[1], mmx_trace.d[0]); \
__asm__ __volatile__ ("movq %%" #reg ", %0" \
: "=X" (mmx_trace) \
: /* nothing */ ); \
fprintf(stderr, #reg "=0x%08x%08x) => ", \
mmx_trace.d[1], mmx_trace.d[0]); \
__asm__ __volatile__ (#op " %0, %%" #reg \
: /* nothing */ \
: "X" (mem)); \
__asm__ __volatile__ ("movq %%" #reg ", %0" \
: "=X" (mmx_trace) \
: /* nothing */ ); \
fprintf(stderr, #reg "=0x%08x%08x\n", \
mmx_trace.d[1], mmx_trace.d[0]); \
}
#define mmx_r2m(op, reg, mem) \
{ \
mmx_t mmx_trace; \
__asm__ __volatile__ ("movq %%" #reg ", %0" \
: "=X" (mmx_trace) \
: /* nothing */ ); \
fprintf(stderr, #op "_r2m(" #reg "=0x%08x%08x, ", \
mmx_trace.d[1], mmx_trace.d[0]); \
mmx_trace = (mem); \
fprintf(stderr, #mem "=0x%08x%08x) => ", \
mmx_trace.d[1], mmx_trace.d[0]); \
__asm__ __volatile__ (#op " %%" #reg ", %0" \
: "=X" (mem) \
: /* nothing */ ); \
mmx_trace = (mem); \
fprintf(stderr, #mem "=0x%08x%08x\n", \
mmx_trace.d[1], mmx_trace.d[0]); \
}
#define mmx_r2r(op, regs, regd) \
{ \
mmx_t mmx_trace; \
__asm__ __volatile__ ("movq %%" #regs ", %0" \
: "=X" (mmx_trace) \
: /* nothing */ ); \
fprintf(stderr, #op "_r2r(" #regs "=0x%08x%08x, ", \
mmx_trace.d[1], mmx_trace.d[0]); \
__asm__ __volatile__ ("movq %%" #regd ", %0" \
: "=X" (mmx_trace) \
: /* nothing */ ); \
fprintf(stderr, #regd "=0x%08x%08x) => ", \
mmx_trace.d[1], mmx_trace.d[0]); \
__asm__ __volatile__ (#op " %" #regs ", %" #regd); \
__asm__ __volatile__ ("movq %%" #regd ", %0" \
: "=X" (mmx_trace) \
: /* nothing */ ); \
fprintf(stderr, #regd "=0x%08x%08x\n", \
mmx_trace.d[1], mmx_trace.d[0]); \
}
#define mmx_m2m(op, mems, memd) \
{ \
mmx_t mmx_trace; \
mmx_trace = (mems); \
fprintf(stderr, #op "_m2m(" #mems "=0x%08x%08x, ", \
mmx_trace.d[1], mmx_trace.d[0]); \
mmx_trace = (memd); \
fprintf(stderr, #memd "=0x%08x%08x) => ", \
mmx_trace.d[1], mmx_trace.d[0]); \
__asm__ __volatile__ ("movq %0, %%mm0\n\t" \
#op " %1, %%mm0\n\t" \
"movq %%mm0, %0" \
: "=X" (memd) \
: "X" (mems)); \
mmx_trace = (memd); \
fprintf(stderr, #memd "=0x%08x%08x\n", \
mmx_trace.d[1], mmx_trace.d[0]); \
}
#else
/* These macros are a lot simpler without the tracing...
*/
#define mmx_i2r(op, imm, reg) \
__asm__ __volatile__ (#op " %0, %%" #reg \
: /* nothing */ \
: "i" (imm) )
#define mmx_m2r(op, mem, reg) \
__asm__ __volatile__ (#op " %0, %%" #reg \
: /* nothing */ \
: "m" (mem))
#define mmx_r2m(op, reg, mem) \
__asm__ __volatile__ (#op " %%" #reg ", %0" \
: "=m" (mem) \
: /* nothing */ )
#define mmx_r2r(op, regs, regd) \
__asm__ __volatile__ (#op " %" #regs ", %" #regd)
#define mmx_m2m(op, mems, memd) \
__asm__ __volatile__ ("movq %0, %%mm0\n\t" \
#op " %1, %%mm0\n\t" \
"movq %%mm0, %0" \
: "=m" (memd) \
: "m" (mems))
#endif
/* 1x64 MOVe Quadword
(this is both a load and a store...
in fact, it is the only way to store)
*/
#define movq_m2r(var, reg) mmx_m2r(movq, var, reg)
#define movq_r2m(reg, var) mmx_r2m(movq, reg, var)
#define movq_r2r(regs, regd) mmx_r2r(movq, regs, regd)
#define movq(vars, vard) \
__asm__ __volatile__ ("movq %1, %%mm0\n\t" \
"movq %%mm0, %0" \
: "=X" (vard) \
: "X" (vars))
/* 1x32 MOVe Doubleword
(like movq, this is both load and store...
but is most useful for moving things between
mmx registers and ordinary registers)
*/
#define movd_m2r(var, reg) mmx_m2r(movd, var, reg)
#define movd_r2m(reg, var) mmx_r2m(movd, reg, var)
#define movd_r2r(regs, regd) mmx_r2r(movd, regs, regd)
#define movd(vars, vard) \
__asm__ __volatile__ ("movd %1, %%mm0\n\t" \
"movd %%mm0, %0" \
: "=X" (vard) \
: "X" (vars))
/* 2x32, 4x16, and 8x8 Parallel ADDs
*/
#define paddd_m2r(var, reg) mmx_m2r(paddd, var, reg)
#define paddd_r2r(regs, regd) mmx_r2r(paddd, regs, regd)
#define paddd(vars, vard) mmx_m2m(paddd, vars, vard)
#define paddw_m2r(var, reg) mmx_m2r(paddw, var, reg)
#define paddw_r2r(regs, regd) mmx_r2r(paddw, regs, regd)
#define paddw(vars, vard) mmx_m2m(paddw, vars, vard)
#define paddb_m2r(var, reg) mmx_m2r(paddb, var, reg)
#define paddb_r2r(regs, regd) mmx_r2r(paddb, regs, regd)
#define paddb(vars, vard) mmx_m2m(paddb, vars, vard)
/* 4x16 and 8x8 Parallel ADDs using Saturation arithmetic
*/
#define paddsw_m2r(var, reg) mmx_m2r(paddsw, var, reg)
#define paddsw_r2r(regs, regd) mmx_r2r(paddsw, regs, regd)
#define paddsw(vars, vard) mmx_m2m(paddsw, vars, vard)
#define paddsb_m2r(var, reg) mmx_m2r(paddsb, var, reg)
#define paddsb_r2r(regs, regd) mmx_r2r(paddsb, regs, regd)
#define paddsb(vars, vard) mmx_m2m(paddsb, vars, vard)
/* 4x16 and 8x8 Parallel ADDs using Unsigned Saturation arithmetic
*/
#define paddusw_m2r(var, reg) mmx_m2r(paddusw, var, reg)
#define paddusw_r2r(regs, regd) mmx_r2r(paddusw, regs, regd)
#define paddusw(vars, vard) mmx_m2m(paddusw, vars, vard)
#define paddusb_m2r(var, reg) mmx_m2r(paddusb, var, reg)
#define paddusb_r2r(regs, regd) mmx_r2r(paddusb, regs, regd)
#define paddusb(vars, vard) mmx_m2m(paddusb, vars, vard)
/* 2x32, 4x16, and 8x8 Parallel SUBs
*/
#define psubd_m2r(var, reg) mmx_m2r(psubd, var, reg)
#define psubd_r2r(regs, regd) mmx_r2r(psubd, regs, regd)
#define psubd(vars, vard) mmx_m2m(psubd, vars, vard)
#define psubw_m2r(var, reg) mmx_m2r(psubw, var, reg)
#define psubw_r2r(regs, regd) mmx_r2r(psubw, regs, regd)
#define psubw(vars, vard) mmx_m2m(psubw, vars, vard)
#define psubb_m2r(var, reg) mmx_m2r(psubb, var, reg)
#define psubb_r2r(regs, regd) mmx_r2r(psubb, regs, regd)
#define psubb(vars, vard) mmx_m2m(psubb, vars, vard)
/* 4x16 and 8x8 Parallel SUBs using Saturation arithmetic
*/
#define psubsw_m2r(var, reg) mmx_m2r(psubsw, var, reg)
#define psubsw_r2r(regs, regd) mmx_r2r(psubsw, regs, regd)
#define psubsw(vars, vard) mmx_m2m(psubsw, vars, vard)
#define psubsb_m2r(var, reg) mmx_m2r(psubsb, var, reg)
#define psubsb_r2r(regs, regd) mmx_r2r(psubsb, regs, regd)
#define psubsb(vars, vard) mmx_m2m(psubsb, vars, vard)
/* 4x16 and 8x8 Parallel SUBs using Unsigned Saturation arithmetic
*/
#define psubusw_m2r(var, reg) mmx_m2r(psubusw, var, reg)
#define psubusw_r2r(regs, regd) mmx_r2r(psubusw, regs, regd)
#define psubusw(vars, vard) mmx_m2m(psubusw, vars, vard)
#define psubusb_m2r(var, reg) mmx_m2r(psubusb, var, reg)
#define psubusb_r2r(regs, regd) mmx_r2r(psubusb, regs, regd)
#define psubusb(vars, vard) mmx_m2m(psubusb, vars, vard)
/* 4x16 Parallel MULs giving Low 4x16 portions of results
*/
#define pmullw_m2r(var, reg) mmx_m2r(pmullw, var, reg)
#define pmullw_r2r(regs, regd) mmx_r2r(pmullw, regs, regd)
#define pmullw(vars, vard) mmx_m2m(pmullw, vars, vard)
/* 4x16 Parallel MULs giving High 4x16 portions of results
*/
#define pmulhw_m2r(var, reg) mmx_m2r(pmulhw, var, reg)
#define pmulhw_r2r(regs, regd) mmx_r2r(pmulhw, regs, regd)
#define pmulhw(vars, vard) mmx_m2m(pmulhw, vars, vard)
/* 4x16->2x32 Parallel Mul-ADD
(muls like pmullw, then adds adjacent 16-bit fields
in the multiply result to make the final 2x32 result)
*/
#define pmaddwd_m2r(var, reg) mmx_m2r(pmaddwd, var, reg)
#define pmaddwd_r2r(regs, regd) mmx_r2r(pmaddwd, regs, regd)
#define pmaddwd(vars, vard) mmx_m2m(pmaddwd, vars, vard)
/* 1x64 bitwise AND
*/
#ifdef BROKEN_PAND
#define pand_m2r(var, reg) \
{ \
mmx_m2r(pandn, (mmx_t) -1LL, reg); \
mmx_m2r(pandn, var, reg); \
}
#define pand_r2r(regs, regd) \
{ \
mmx_m2r(pandn, (mmx_t) -1LL, regd); \
mmx_r2r(pandn, regs, regd) \
}
#define pand(vars, vard) \
{ \
movq_m2r(vard, mm0); \
mmx_m2r(pandn, (mmx_t) -1LL, mm0); \
mmx_m2r(pandn, vars, mm0); \
movq_r2m(mm0, vard); \
}
#else
#define pand_m2r(var, reg) mmx_m2r(pand, var, reg)
#define pand_r2r(regs, regd) mmx_r2r(pand, regs, regd)
#define pand(vars, vard) mmx_m2m(pand, vars, vard)
#endif
/* 1x64 bitwise AND with Not the destination
*/
#define pandn_m2r(var, reg) mmx_m2r(pandn, var, reg)
#define pandn_r2r(regs, regd) mmx_r2r(pandn, regs, regd)
#define pandn(vars, vard) mmx_m2m(pandn, vars, vard)
/* 1x64 bitwise OR
*/
#define por_m2r(var, reg) mmx_m2r(por, var, reg)
#define por_r2r(regs, regd) mmx_r2r(por, regs, regd)
#define por(vars, vard) mmx_m2m(por, vars, vard)
/* 1x64 bitwise eXclusive OR
*/
#define pxor_m2r(var, reg) mmx_m2r(pxor, var, reg)
#define pxor_r2r(regs, regd) mmx_r2r(pxor, regs, regd)
#define pxor(vars, vard) mmx_m2m(pxor, vars, vard)
/* 2x32, 4x16, and 8x8 Parallel CoMPare for EQuality
(resulting fields are either 0 or -1)
*/
#define pcmpeqd_m2r(var, reg) mmx_m2r(pcmpeqd, var, reg)
#define pcmpeqd_r2r(regs, regd) mmx_r2r(pcmpeqd, regs, regd)
#define pcmpeqd(vars, vard) mmx_m2m(pcmpeqd, vars, vard)
#define pcmpeqw_m2r(var, reg) mmx_m2r(pcmpeqw, var, reg)
#define pcmpeqw_r2r(regs, regd) mmx_r2r(pcmpeqw, regs, regd)
#define pcmpeqw(vars, vard) mmx_m2m(pcmpeqw, vars, vard)
#define pcmpeqb_m2r(var, reg) mmx_m2r(pcmpeqb, var, reg)
#define pcmpeqb_r2r(regs, regd) mmx_r2r(pcmpeqb, regs, regd)
#define pcmpeqb(vars, vard) mmx_m2m(pcmpeqb, vars, vard)
/* 2x32, 4x16, and 8x8 Parallel CoMPare for Greater Than
(resulting fields are either 0 or -1)
*/
#define pcmpgtd_m2r(var, reg) mmx_m2r(pcmpgtd, var, reg)
#define pcmpgtd_r2r(regs, regd) mmx_r2r(pcmpgtd, regs, regd)
#define pcmpgtd(vars, vard) mmx_m2m(pcmpgtd, vars, vard)
#define pcmpgtw_m2r(var, reg) mmx_m2r(pcmpgtw, var, reg)
#define pcmpgtw_r2r(regs, regd) mmx_r2r(pcmpgtw, regs, regd)
#define pcmpgtw(vars, vard) mmx_m2m(pcmpgtw, vars, vard)
#define pcmpgtb_m2r(var, reg) mmx_m2r(pcmpgtb, var, reg)
#define pcmpgtb_r2r(regs, regd) mmx_r2r(pcmpgtb, regs, regd)
#define pcmpgtb(vars, vard) mmx_m2m(pcmpgtb, vars, vard)
/* 1x64, 2x32, and 4x16 Parallel Shift Left Logical
*/
#define psllq_i2r(imm, reg) mmx_i2r(psllq, imm, reg)
#define psllq_m2r(var, reg) mmx_m2r(psllq, var, reg)
#define psllq_r2r(regs, regd) mmx_r2r(psllq, regs, regd)
#define psllq(vars, vard) mmx_m2m(psllq, vars, vard)
#define pslld_i2r(imm, reg) mmx_i2r(pslld, imm, reg)
#define pslld_m2r(var, reg) mmx_m2r(pslld, var, reg)
#define pslld_r2r(regs, regd) mmx_r2r(pslld, regs, regd)
#define pslld(vars, vard) mmx_m2m(pslld, vars, vard)
#define psllw_i2r(imm, reg) mmx_i2r(psllw, imm, reg)
#define psllw_m2r(var, reg) mmx_m2r(psllw, var, reg)
#define psllw_r2r(regs, regd) mmx_r2r(psllw, regs, regd)
#define psllw(vars, vard) mmx_m2m(psllw, vars, vard)
/* 1x64, 2x32, and 4x16 Parallel Shift Right Logical
*/
#define psrlq_i2r(imm, reg) mmx_i2r(psrlq, imm, reg)
#define psrlq_m2r(var, reg) mmx_m2r(psrlq, var, reg)
#define psrlq_r2r(regs, regd) mmx_r2r(psrlq, regs, regd)
#define psrlq(vars, vard) mmx_m2m(psrlq, vars, vard)
#define psrld_i2r(imm, reg) mmx_i2r(psrld, imm, reg)
#define psrld_m2r(var, reg) mmx_m2r(psrld, var, reg)
#define psrld_r2r(regs, regd) mmx_r2r(psrld, regs, regd)
#define psrld(vars, vard) mmx_m2m(psrld, vars, vard)
#define psrlw_i2r(imm, reg) mmx_i2r(psrlw, imm, reg)
#define psrlw_m2r(var, reg) mmx_m2r(psrlw, var, reg)
#define psrlw_r2r(regs, regd) mmx_r2r(psrlw, regs, regd)
#define psrlw(vars, vard) mmx_m2m(psrlw, vars, vard)
/* 2x32 and 4x16 Parallel Shift Right Arithmetic
*/
#define psrad_i2r(imm, reg) mmx_i2r(psrad, imm, reg)
#define psrad_m2r(var, reg) mmx_m2r(psrad, var, reg)
#define psrad_r2r(regs, regd) mmx_r2r(psrad, regs, regd)
#define psrad(vars, vard) mmx_m2m(psrad, vars, vard)
#define psraw_i2r(imm, reg) mmx_i2r(psraw, imm, reg)
#define psraw_m2r(var, reg) mmx_m2r(psraw, var, reg)
#define psraw_r2r(regs, regd) mmx_r2r(psraw, regs, regd)
#define psraw(vars, vard) mmx_m2m(psraw, vars, vard)
/* 2x32->4x16 and 4x16->8x8 PACK and Signed Saturate
(packs source and dest fields into dest in that order)
*/
#define packssdw_m2r(var, reg) mmx_m2r(packssdw, var, reg)
#define packssdw_r2r(regs, regd) mmx_r2r(packssdw, regs, regd)
#define packssdw(vars, vard) mmx_m2m(packssdw, vars, vard)
#define packsswb_m2r(var, reg) mmx_m2r(packsswb, var, reg)
#define packsswb_r2r(regs, regd) mmx_r2r(packsswb, regs, regd)
#define packsswb(vars, vard) mmx_m2m(packsswb, vars, vard)
/* 4x16->8x8 PACK and Unsigned Saturate
(packs source and dest fields into dest in that order)
*/
#define packuswb_m2r(var, reg) mmx_m2r(packuswb, var, reg)
#define packuswb_r2r(regs, regd) mmx_r2r(packuswb, regs, regd)
#define packuswb(vars, vard) mmx_m2m(packuswb, vars, vard)
/* 2x32->1x64, 4x16->2x32, and 8x8->4x16 UNPaCK Low
(interleaves low half of dest with low half of source
as padding in each result field)
*/
#define punpckldq_m2r(var, reg) mmx_m2r(punpckldq, var, reg)
#define punpckldq_r2r(regs, regd) mmx_r2r(punpckldq, regs, regd)
#define punpckldq(vars, vard) mmx_m2m(punpckldq, vars, vard)
#define punpcklwd_m2r(var, reg) mmx_m2r(punpcklwd, var, reg)
#define punpcklwd_r2r(regs, regd) mmx_r2r(punpcklwd, regs, regd)
#define punpcklwd(vars, vard) mmx_m2m(punpcklwd, vars, vard)
#define punpcklbw_m2r(var, reg) mmx_m2r(punpcklbw, var, reg)
#define punpcklbw_r2r(regs, regd) mmx_r2r(punpcklbw, regs, regd)
#define punpcklbw(vars, vard) mmx_m2m(punpcklbw, vars, vard)
/* 2x32->1x64, 4x16->2x32, and 8x8->4x16 UNPaCK High
(interleaves high half of dest with high half of source
as padding in each result field)
*/
#define punpckhdq_m2r(var, reg) mmx_m2r(punpckhdq, var, reg)
#define punpckhdq_r2r(regs, regd) mmx_r2r(punpckhdq, regs, regd)
#define punpckhdq(vars, vard) mmx_m2m(punpckhdq, vars, vard)
#define punpckhwd_m2r(var, reg) mmx_m2r(punpckhwd, var, reg)
#define punpckhwd_r2r(regs, regd) mmx_r2r(punpckhwd, regs, regd)
#define punpckhwd(vars, vard) mmx_m2m(punpckhwd, vars, vard)
#define punpckhbw_m2r(var, reg) mmx_m2r(punpckhbw, var, reg)
#define punpckhbw_r2r(regs, regd) mmx_r2r(punpckhbw, regs, regd)
#define punpckhbw(vars, vard) mmx_m2m(punpckhbw, vars, vard)
/* Empty MMx State
(used to clean-up when going from mmx to float use
of the registers that are shared by both; note that
there is no float-to-mmx operation needed, because
only the float tag word info is corruptible)
*/
#ifdef MMX_TRACE
#define emms() \
{ \
fprintf(stderr, "emms()\n"); \
__asm__ __volatile__ ("emms"); \
}
#else
#define emms() __asm__ __volatile__ ("emms")
#endif
#endif

798
libavcodec/i386/sad_mmx.s Normal file
View File

@ -0,0 +1,798 @@
; MMX/SSE optimized routines for SAD of 16*16 macroblocks
; Copyright (C) Juan J. Sierralta P. <juanjo@atmlab.utfsm.cl>
;
; dist1_* Original Copyright (C) 2000 Chris Atenasio <chris@crud.net>
; Enhancements and rest Copyright (C) 2000 Andrew Stevens <as@comlab.ox.ac.uk>
;
; 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
;
global pix_abs16x16_mmx
; int pix_abs16x16_mmx(unsigned char *pix1,unsigned char *pix2, int lx, int h);
; esi = p1 (init: blk1)
; edi = p2 (init: blk2)
; ecx = rowsleft (init: h)
; edx = lx;
; mm0 = distance accumulators (4 words)
; mm1 = distance accumulators (4 words)
; mm2 = temp
; mm3 = temp
; mm4 = temp
; mm5 = temp
; mm6 = 0
; mm7 = temp
align 32
pix_abs16x16_mmx:
push ebp ; save frame pointer
mov ebp, esp
push ebx ; Saves registers (called saves convention in
push ecx ; x86 GCC it seems)
push edx ;
push esi
push edi
pxor mm0, mm0 ; zero acculumators
pxor mm1, mm1
pxor mm6, mm6
mov esi, [ebp+8] ; get pix1
mov edi, [ebp+12] ; get pix2
mov edx, [ebp+16] ; get lx
mov ecx, [ebp+20] ; get rowsleft
jmp .nextrow
align 32
.nextrow:
; First 8 bytes of the row
movq mm4, [edi] ; load first 8 bytes of pix2 row
movq mm5, [esi] ; load first 8 bytes of pix1 row
movq mm3, mm4 ; mm4 := abs(mm4-mm5)
movq mm2,[esi+8] ; load last 8 bytes of pix1 row
psubusb mm4, mm5
movq mm7,[edi+8] ; load last 8 bytes of pix2 row
psubusb mm5, mm3
por mm4, mm5
; Last 8 bytes of the row
movq mm3, mm7 ; mm7 := abs(mm7-mm2)
psubusb mm7, mm2
psubusb mm2, mm3
por mm7, mm2
; Now mm4 and mm7 have 16 absdiffs to add
; First 8 bytes of the row2
add edi, edx
movq mm2, [edi] ; load first 8 bytes of pix2 row
add esi, edx
movq mm5, [esi] ; load first 8 bytes of pix1 row
movq mm3, mm2 ; mm2 := abs(mm2-mm5)
psubusb mm2, mm5
movq mm6,[esi+8] ; load last 8 bytes of pix1 row
psubusb mm5, mm3
por mm2, mm5
; Last 8 bytes of the row2
movq mm5,[edi+8] ; load last 8 bytes of pix2 row
movq mm3, mm5 ; mm5 := abs(mm5-mm6)
psubusb mm5, mm6
psubusb mm6, mm3
por mm5, mm6
; Now mm2, mm4, mm5, mm7 have 32 absdiffs
movq mm3, mm7
pxor mm6, mm6 ; Zero mm6
punpcklbw mm3, mm6 ; Unpack to words and add
punpckhbw mm7, mm6
paddusw mm7, mm3
movq mm3, mm5
punpcklbw mm3, mm6 ; Unpack to words and add
punpckhbw mm5, mm6
paddusw mm5, mm3
paddusw mm0, mm7 ; Add to the acumulator (mm0)
paddusw mm1, mm5 ; Add to the acumulator (mm1)
movq mm3, mm4
punpcklbw mm3, mm6 ; Unpack to words and add
punpckhbw mm4, mm6
movq mm5, mm2
paddusw mm4, mm3
punpcklbw mm5, mm6 ; Unpack to words and add
punpckhbw mm2, mm6
paddusw mm2, mm5
; Loop termination
add esi, edx ; update pointers to next row
paddusw mm0, mm4 ; Add to the acumulator (mm0)
add edi, edx
sub ecx,2
paddusw mm1, mm2 ; Add to the acumulator (mm1)
test ecx, ecx ; check rowsleft
jnz near .nextrow
paddusw mm0, mm1
movq mm2, mm0 ; Copy mm0 to mm2
psrlq mm2, 32
paddusw mm0, mm2 ; Add
movq mm3, mm0
psrlq mm3, 16
paddusw mm0, mm3
movd eax, mm0 ; Store return value
and eax, 0xffff
pop edi
pop esi
pop edx
pop ecx
pop ebx
pop ebp ; restore stack pointer
;emms ; clear mmx registers
ret ; return
global pix_abs16x16_sse
; int pix_abs16x16_mmx(unsigned char *pix1,unsigned char *pix2, int lx, int h);
; esi = p1 (init: blk1)
; edi = p2 (init: blk2)
; ecx = rowsleft (init: h)
; edx = lx;
; mm0 = distance accumulators (4 words)
; mm1 = distance accumulators (4 words)
; mm2 = temp
; mm3 = temp
; mm4 = temp
; mm5 = temp
; mm6 = temp
; mm7 = temp
align 32
pix_abs16x16_sse:
push ebp ; save frame pointer
mov ebp, esp
push ebx ; Saves registers (called saves convention in
push ecx ; x86 GCC it seems)
push edx ;
push esi
push edi
pxor mm0, mm0 ; zero acculumators
pxor mm1, mm1
mov esi, [ebp+8] ; get pix1
mov edi, [ebp+12] ; get pix2
mov edx, [ebp+16] ; get lx
mov ecx, [ebp+20] ; get rowsleft
jmp .next4row
align 32
.next4row:
; First row
movq mm4, [edi] ; load first 8 bytes of pix2 row
movq mm5, [edi+8] ; load last 8 bytes of pix2 row
psadbw mm4, [esi] ; SAD of first 8 bytes
psadbw mm5, [esi+8] ; SAD of last 8 bytes
paddw mm0, mm4 ; Add to acumulators
paddw mm1, mm5
; Second row
add edi, edx;
add esi, edx;
movq mm6, [edi] ; load first 8 bytes of pix2 row
movq mm7, [edi+8] ; load last 8 bytes of pix2 row
psadbw mm6, [esi] ; SAD of first 8 bytes
psadbw mm7, [esi+8] ; SAD of last 8 bytes
paddw mm0, mm6 ; Add to acumulators
paddw mm1, mm7
; Third row
add edi, edx;
add esi, edx;
movq mm4, [edi] ; load first 8 bytes of pix2 row
movq mm5, [edi+8] ; load last 8 bytes of pix2 row
psadbw mm4, [esi] ; SAD of first 8 bytes
psadbw mm5, [esi+8] ; SAD of last 8 bytes
paddw mm0, mm4 ; Add to acumulators
paddw mm1, mm5
; Fourth row
add edi, edx;
add esi, edx;
movq mm6, [edi] ; load first 8 bytes of pix2 row
movq mm7, [edi+8] ; load last 8 bytes of pix2 row
psadbw mm6, [esi] ; SAD of first 8 bytes
psadbw mm7, [esi+8] ; SAD of last 8 bytes
paddw mm0, mm6 ; Add to acumulators
paddw mm1, mm7
; Loop termination
add esi, edx ; update pointers to next row
add edi, edx
sub ecx,4
test ecx, ecx ; check rowsleft
jnz near .next4row
paddd mm0, mm1 ; Sum acumulators
movd eax, mm0 ; Store return value
pop edi
pop esi
pop edx
pop ecx
pop ebx
pop ebp ; restore stack pointer
;emms ; clear mmx registers
ret ; return
global pix_abs16x16_x2_mmx
; int pix_abs16x16_x2_mmx(unsigned char *pix1,unsigned char *pix2, int lx, int h);
; esi = p1 (init: blk1)
; edi = p2 (init: blk2)
; ecx = rowsleft (init: h)
; edx = lx;
; mm0 = distance accumulators (4 words)
; mm1 = distance accumulators (4 words)
; mm2 = temp
; mm3 = temp
; mm4 = temp
; mm5 = temp
; mm6 = 0
; mm7 = temp
align 32
pix_abs16x16_x2_mmx:
push ebp ; save frame pointer
mov ebp, esp
push ebx ; Saves registers (called saves convention in
push ecx ; x86 GCC it seems)
push edx ;
push esi
push edi
pxor mm0, mm0 ; zero acculumators
pxor mm1, mm1
pxor mm6, mm6
mov esi, [ebp+8] ; get pix1
mov edi, [ebp+12] ; get pix2
mov edx, [ebp+16] ; get lx
mov ecx, [ebp+20] ; get rowsleft
jmp .nextrow_x2
align 32
.nextrow_x2:
; First 8 bytes of the row
movq mm4, [edi] ; load first 8 bytes of pix2 row
movq mm5, [edi+1] ; load bytes 1-8 of pix2 row
movq mm2, mm4 ; copy mm4 on mm2
movq mm3, mm5 ; copy mm5 on mm3
punpcklbw mm4, mm6 ; first 4 bytes of [edi] on mm4
punpcklbw mm5, mm6 ; first 4 bytes of [edi+1] on mm5
paddusw mm4, mm5 ; mm4 := first 4 bytes interpolated in words
psrlw mm4, 1
punpckhbw mm2, mm6 ; last 4 bytes of [edi] on mm2
punpckhbw mm3, mm6 ; last 4 bytes of [edi+1] on mm3
paddusw mm2, mm3 ; mm2 := last 4 bytes interpolated in words
psrlw mm2, 1
packuswb mm4, mm2 ; pack 8 bytes interpolated on mm4
movq mm5,[esi] ; load first 8 bytes of pix1 row
movq mm3, mm4 ; mm4 := abs(mm4-mm5)
psubusb mm4, mm5
psubusb mm5, mm3
por mm4, mm5
; Last 8 bytes of the row
movq mm7, [edi+8] ; load last 8 bytes of pix2 row
movq mm5, [edi+9] ; load bytes 10-17 of pix2 row
movq mm2, mm7 ; copy mm7 on mm2
movq mm3, mm5 ; copy mm5 on mm3
punpcklbw mm7, mm6 ; first 4 bytes of [edi+8] on mm7
punpcklbw mm5, mm6 ; first 4 bytes of [edi+9] on mm5
paddusw mm7, mm5 ; mm1 := first 4 bytes interpolated in words
psrlw mm7, 1
punpckhbw mm2, mm6 ; last 4 bytes of [edi] on mm2
punpckhbw mm3, mm6 ; last 4 bytes of [edi+1] on mm3
paddusw mm2, mm3 ; mm2 := last 4 bytes interpolated in words
psrlw mm2, 1
packuswb mm7, mm2 ; pack 8 bytes interpolated on mm1
movq mm5,[esi+8] ; load last 8 bytes of pix1 row
movq mm3, mm7 ; mm7 := abs(mm1-mm5)
psubusb mm7, mm5
psubusb mm5, mm3
por mm7, mm5
; Now mm4 and mm7 have 16 absdiffs to add
movq mm3, mm4 ; Make copies of these bytes
movq mm2, mm7
punpcklbw mm4, mm6 ; Unpack to words and add
punpcklbw mm7, mm6
paddusw mm4, mm7
paddusw mm0, mm4 ; Add to the acumulator (mm0)
punpckhbw mm3, mm6 ; Unpack to words and add
punpckhbw mm2, mm6
paddusw mm3, mm2
paddusw mm1, mm3 ; Add to the acumulator (mm1)
; Loop termination
add esi, edx ; update pointers to next row
add edi, edx
sub ecx,1
test ecx, ecx ; check rowsleft
jnz near .nextrow_x2
paddusw mm0, mm1
movq mm1, mm0 ; Copy mm0 to mm1
psrlq mm1, 32
paddusw mm0, mm1 ; Add
movq mm2, mm0
psrlq mm2, 16
paddusw mm0, mm2
movd eax, mm0 ; Store return value
and eax, 0xffff
pop edi
pop esi
pop edx
pop ecx
pop ebx
pop ebp ; restore stack pointer
emms ; clear mmx registers
ret ; return
global pix_abs16x16_y2_mmx
; int pix_abs16x16_y2_mmx(unsigned char *pix1,unsigned char *pix2, int lx, int h);
; esi = p1 (init: blk1)
; edi = p2 (init: blk2)
; ebx = p2 + lx
; ecx = rowsleft (init: h)
; edx = lx;
; mm0 = distance accumulators (4 words)
; mm1 = distance accumulators (4 words)
; mm2 = temp
; mm3 = temp
; mm4 = temp
; mm5 = temp
; mm6 = 0
; mm7 = temp
align 32
pix_abs16x16_y2_mmx:
push ebp ; save frame pointer
mov ebp, esp
push ebx ; Saves registers (called saves convention in
push ecx ; x86 GCC it seems)
push edx ;
push esi
push edi
pxor mm0, mm0 ; zero acculumators
pxor mm1, mm1
pxor mm6, mm6
mov esi, [ebp+8] ; get pix1
mov edi, [ebp+12] ; get pix2
mov edx, [ebp+16] ; get lx
mov ecx, [ebp+20] ; get rowsleft
mov ebx, edi
add ebx, edx
jmp .nextrow_y2
align 32
.nextrow_y2:
; First 8 bytes of the row
movq mm4, [edi] ; load first 8 bytes of pix2 row
movq mm5, [ebx] ; load bytes 1-8 of pix2 row
movq mm2, mm4 ; copy mm4 on mm2
movq mm3, mm5 ; copy mm5 on mm3
punpcklbw mm4, mm6 ; first 4 bytes of [edi] on mm4
punpcklbw mm5, mm6 ; first 4 bytes of [ebx] on mm5
paddusw mm4, mm5 ; mm4 := first 4 bytes interpolated in words
psrlw mm4, 1
punpckhbw mm2, mm6 ; last 4 bytes of [edi] on mm2
punpckhbw mm3, mm6 ; last 4 bytes of [edi+1] on mm3
paddusw mm2, mm3 ; mm2 := last 4 bytes interpolated in words
psrlw mm2, 1
packuswb mm4, mm2 ; pack 8 bytes interpolated on mm4
movq mm5,[esi] ; load first 8 bytes of pix1 row
movq mm3, mm4 ; mm4 := abs(mm4-mm5)
psubusb mm4, mm5
psubusb mm5, mm3
por mm4, mm5
; Last 8 bytes of the row
movq mm7, [edi+8] ; load last 8 bytes of pix2 row
movq mm5, [ebx+8] ; load bytes 10-17 of pix2 row
movq mm2, mm7 ; copy mm7 on mm2
movq mm3, mm5 ; copy mm5 on mm3
punpcklbw mm7, mm6 ; first 4 bytes of [edi+8] on mm7
punpcklbw mm5, mm6 ; first 4 bytes of [ebx+8] on mm5
paddusw mm7, mm5 ; mm1 := first 4 bytes interpolated in words
psrlw mm7, 1
punpckhbw mm2, mm6 ; last 4 bytes of [edi+8] on mm2
punpckhbw mm3, mm6 ; last 4 bytes of [ebx+8] on mm3
paddusw mm2, mm3 ; mm2 := last 4 bytes interpolated in words
psrlw mm2, 1
packuswb mm7, mm2 ; pack 8 bytes interpolated on mm1
movq mm5,[esi+8] ; load last 8 bytes of pix1 row
movq mm3, mm7 ; mm7 := abs(mm1-mm5)
psubusb mm7, mm5
psubusb mm5, mm3
por mm7, mm5
; Now mm4 and mm7 have 16 absdiffs to add
movq mm3, mm4 ; Make copies of these bytes
movq mm2, mm7
punpcklbw mm4, mm6 ; Unpack to words and add
punpcklbw mm7, mm6
paddusw mm4, mm7
paddusw mm0, mm4 ; Add to the acumulator (mm0)
punpckhbw mm3, mm6 ; Unpack to words and add
punpckhbw mm2, mm6
paddusw mm3, mm2
paddusw mm1, mm3 ; Add to the acumulator (mm1)
; Loop termination
add esi, edx ; update pointers to next row
add edi, edx
add ebx, edx
sub ecx,1
test ecx, ecx ; check rowsleft
jnz near .nextrow_y2
paddusw mm0, mm1
movq mm1, mm0 ; Copy mm0 to mm1
psrlq mm1, 32
paddusw mm0, mm1 ; Add
movq mm2, mm0
psrlq mm2, 16
paddusw mm0, mm2
movd eax, mm0 ; Store return value
and eax, 0xffff
pop edi
pop esi
pop edx
pop ecx
pop ebx
pop ebp ; restore stack pointer
emms ; clear mmx registers
ret ; return
global pix_abs16x16_xy2_mmx
; int pix_abs16x16_xy2_mmx(unsigned char *p1,unsigned char *p2,int lx,int h);
; esi = p1 (init: blk1)
; edi = p2 (init: blk2)
; ebx = p1+lx
; ecx = rowsleft (init: h)
; edx = lx;
; mm0 = distance accumulators (4 words)
; mm1 = bytes p2
; mm2 = bytes p1
; mm3 = bytes p1+lx
; I'd love to find someplace to stash p1+1 and p1+lx+1's bytes
; but I don't think thats going to happen in iA32-land...
; mm4 = temp 4 bytes in words interpolating p1, p1+1
; mm5 = temp 4 bytes in words from p2
; mm6 = temp comparison bit mask p1,p2
; mm7 = temp comparison bit mask p2,p1
align 32
pix_abs16x16_xy2_mmx:
push ebp ; save stack pointer
mov ebp, esp ; so that we can do this
push ebx ; Saves registers (called saves convention in
push ecx ; x86 GCC it seems)
push edx ;
push esi
push edi
pxor mm0, mm0 ; zero acculumators
mov esi, [ebp+12] ; get p1
mov edi, [ebp+8] ; get p2
mov edx, [ebp+16] ; get lx
mov ecx, [ebp+20] ; rowsleft := h
mov ebx, esi
add ebx, edx
jmp .nextrowmm11 ; snap to it
align 32
.nextrowmm11:
;;
;; First 8 bytes of row
;;
;; First 4 bytes of 8
movq mm4, [esi] ; mm4 := first 4 bytes p1
pxor mm7, mm7
movq mm2, mm4 ; mm2 records all 8 bytes
punpcklbw mm4, mm7 ; First 4 bytes p1 in Words...
movq mm6, [ebx] ; mm6 := first 4 bytes p1+lx
movq mm3, mm6 ; mm3 records all 8 bytes
punpcklbw mm6, mm7
paddw mm4, mm6
movq mm5, [esi+1] ; mm5 := first 4 bytes p1+1
punpcklbw mm5, mm7 ; First 4 bytes p1 in Words...
paddw mm4, mm5
movq mm6, [ebx+1] ; mm6 := first 4 bytes p1+lx+1
punpcklbw mm6, mm7
paddw mm4, mm6
psrlw mm4, 2 ; mm4 := First 4 bytes interpolated in words
movq mm5, [edi] ; mm5:=first 4 bytes of p2 in words
movq mm1, mm5
punpcklbw mm5, mm7
movq mm7,mm4
pcmpgtw mm7,mm5 ; mm7 := [i : W0..3,mm4>mm5]
movq mm6,mm4 ; mm6 := [i : W0..3, (mm4-mm5)*(mm4-mm5 > 0)]
psubw mm6,mm5
pand mm6, mm7
paddw mm0, mm6 ; Add to accumulator
movq mm6,mm5 ; mm6 := [i : W0..3,mm5>mm4]
pcmpgtw mm6,mm4
psubw mm5,mm4 ; mm5 := [i : B0..7, (mm5-mm4)*(mm5-mm4 > 0)]
pand mm5, mm6
paddw mm0, mm5 ; Add to accumulator
;; Second 4 bytes of 8
movq mm4, mm2 ; mm4 := Second 4 bytes p1 in words
pxor mm7, mm7
punpckhbw mm4, mm7
movq mm6, mm3 ; mm6 := Second 4 bytes p1+1 in words
punpckhbw mm6, mm7
paddw mm4, mm6
movq mm5, [esi+1] ; mm5 := first 4 bytes p1+1
punpckhbw mm5, mm7 ; First 4 bytes p1 in Words...
paddw mm4, mm5
movq mm6, [ebx+1] ; mm6 := first 4 bytes p1+lx+1
punpckhbw mm6, mm7
paddw mm4, mm6
psrlw mm4, 2 ; mm4 := First 4 bytes interpolated in words
movq mm5, mm1 ; mm5:= second 4 bytes of p2 in words
punpckhbw mm5, mm7
movq mm7,mm4
pcmpgtw mm7,mm5 ; mm7 := [i : W0..3,mm4>mm5]
movq mm6,mm4 ; mm6 := [i : W0..3, (mm4-mm5)*(mm4-mm5 > 0)]
psubw mm6,mm5
pand mm6, mm7
paddw mm0, mm6 ; Add to accumulator
movq mm6,mm5 ; mm6 := [i : W0..3,mm5>mm4]
pcmpgtw mm6,mm4
psubw mm5,mm4 ; mm5 := [i : B0..7, (mm5-mm4)*(mm5-mm4 > 0)]
pand mm5, mm6
paddw mm0, mm5 ; Add to accumulator
;;
;; Second 8 bytes of row
;;
;; First 4 bytes of 8
movq mm4, [esi+8] ; mm4 := first 4 bytes p1+8
pxor mm7, mm7
movq mm2, mm4 ; mm2 records all 8 bytes
punpcklbw mm4, mm7 ; First 4 bytes p1 in Words...
movq mm6, [ebx+8] ; mm6 := first 4 bytes p1+lx+8
movq mm3, mm6 ; mm3 records all 8 bytes
punpcklbw mm6, mm7
paddw mm4, mm6
movq mm5, [esi+9] ; mm5 := first 4 bytes p1+9
punpcklbw mm5, mm7 ; First 4 bytes p1 in Words...
paddw mm4, mm5
movq mm6, [ebx+9] ; mm6 := first 4 bytes p1+lx+9
punpcklbw mm6, mm7
paddw mm4, mm6
psrlw mm4, 2 ; mm4 := First 4 bytes interpolated in words
movq mm5, [edi+8] ; mm5:=first 4 bytes of p2+8 in words
movq mm1, mm5
punpcklbw mm5, mm7
movq mm7,mm4
pcmpgtw mm7,mm5 ; mm7 := [i : W0..3,mm4>mm5]
movq mm6,mm4 ; mm6 := [i : W0..3, (mm4-mm5)*(mm4-mm5 > 0)]
psubw mm6,mm5
pand mm6, mm7
paddw mm0, mm6 ; Add to accumulator
movq mm6,mm5 ; mm6 := [i : W0..3,mm5>mm4]
pcmpgtw mm6,mm4
psubw mm5,mm4 ; mm5 := [i : B0..7, (mm5-mm4)*(mm5-mm4 > 0)]
pand mm5, mm6
paddw mm0, mm5 ; Add to accumulator
;; Second 4 bytes of 8
movq mm4, mm2 ; mm4 := Second 4 bytes p1 in words
pxor mm7, mm7
punpckhbw mm4, mm7
movq mm6, mm3 ; mm6 := Second 4 bytes p1+1 in words
punpckhbw mm6, mm7
paddw mm4, mm6
movq mm5, [esi+9] ; mm5 := first 4 bytes p1+1
punpckhbw mm5, mm7 ; First 4 bytes p1 in Words...
paddw mm4, mm5
movq mm6, [ebx+9] ; mm6 := first 4 bytes p1+lx+1
punpckhbw mm6, mm7
paddw mm4, mm6
psrlw mm4, 2 ; mm4 := First 4 bytes interpolated in words
movq mm5, mm1 ; mm5:= second 4 bytes of p2 in words
punpckhbw mm5, mm7
movq mm7,mm4
pcmpgtw mm7,mm5 ; mm7 := [i : W0..3,mm4>mm5]
movq mm6,mm4 ; mm6 := [i : W0..3, (mm4-mm5)*(mm4-mm5 > 0)]
psubw mm6,mm5
pand mm6, mm7
paddw mm0, mm6 ; Add to accumulator
movq mm6,mm5 ; mm6 := [i : W0..3,mm5>mm4]
pcmpgtw mm6,mm4
psubw mm5,mm4 ; mm5 := [i : B0..7, (mm5-mm4)*(mm5-mm4 > 0)]
pand mm5, mm6
paddw mm0, mm5 ; Add to accumulator
;;
;; Loop termination condition... and stepping
;;
add esi, edx ; update pointer to next row
add edi, edx ; ditto
add ebx, edx
sub ecx,1
test ecx, ecx ; check rowsleft
jnz near .nextrowmm11
;; Sum the Accumulators
movq mm4, mm0
psrlq mm4, 32
paddw mm0, mm4
movq mm6, mm0
psrlq mm6, 16
paddw mm0, mm6
movd eax, mm0 ; store return value
and eax, 0xffff
pop edi
pop esi
pop edx
pop ecx
pop ebx
pop ebp ; restore stack pointer
emms ; clear mmx registers
ret ; we now return you to your regular programming

214
libavcodec/imgconvert.c Normal file
View File

@ -0,0 +1,214 @@
/*
* Misc image convertion routines
* Copyright (c) 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "avcodec.h"
/* XXX: totally non optimized */
static void yuv422_to_yuv420p(UINT8 *lum, UINT8 *cb, UINT8 *cr,
UINT8 *src, int width, int height)
{
int x, y;
UINT8 *p = src;
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;
}
}
}
#define SCALEBITS 8
#define ONE_HALF (1 << (SCALEBITS - 1))
#define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5))
static void rgb24_to_yuv420p(UINT8 *lum, UINT8 *cb, UINT8 *cr,
UINT8 *src, int width, int height)
{
int wrap, wrap3, x, y;
int r, g, b, r1, g1, b1;
UINT8 *p;
wrap = width;
wrap3 = width * 3;
p = src;
for(y=0;y<height;y+=2) {
for(x=0;x<width;x+=2) {
r = p[0];
g = p[1];
b = p[2];
r1 = r;
g1 = g;
b1 = b;
lum[0] = (FIX(0.29900) * r + FIX(0.58700) * g +
FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;
r = p[3];
g = p[4];
b = p[5];
r1 += r;
g1 += g;
b1 += b;
lum[1] = (FIX(0.29900) * r + FIX(0.58700) * g +
FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;
p += wrap3;
lum += wrap;
r = p[0];
g = p[1];
b = p[2];
r1 += r;
g1 += g;
b1 += b;
lum[0] = (FIX(0.29900) * r + FIX(0.58700) * g +
FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;
r = p[3];
g = p[4];
b = p[5];
r1 += r;
g1 += g;
b1 += b;
lum[1] = (FIX(0.29900) * r + FIX(0.58700) * g +
FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;
cb[0] = ((- FIX(0.16874) * r1 - FIX(0.33126) * g1 +
FIX(0.50000) * b1 + 4 * ONE_HALF - 1) >> (SCALEBITS + 2)) + 128;
cr[0] = ((FIX(0.50000) * r1 - FIX(0.41869) * g1 -
FIX(0.08131) * b1 + 4 * ONE_HALF - 1) >> (SCALEBITS + 2)) + 128;
cb++;
cr++;
p += -wrap3 + 2 * 3;
lum += -wrap + 2;
}
p += wrap3;
lum += wrap;
}
}
static void bgr24_to_yuv420p(UINT8 *lum, UINT8 *cb, UINT8 *cr,
UINT8 *src, int width, int height)
{
int wrap, wrap3, x, y;
int r, g, b, r1, g1, b1;
UINT8 *p;
wrap = width;
wrap3 = width * 3;
p = src;
for(y=0;y<height;y+=2) {
for(x=0;x<width;x+=2) {
b = p[0];
g = p[1];
r = p[2];
r1 = r;
g1 = g;
b1 = b;
lum[0] = (FIX(0.29900) * r + FIX(0.58700) * g +
FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;
b = p[3];
g = p[4];
r = p[5];
r1 += r;
g1 += g;
b1 += b;
lum[1] = (FIX(0.29900) * r + FIX(0.58700) * g +
FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;
p += wrap3;
lum += wrap;
b = p[0];
g = p[1];
r = p[2];
r1 += r;
g1 += g;
b1 += b;
lum[0] = (FIX(0.29900) * r + FIX(0.58700) * g +
FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;
b = p[3];
g = p[4];
r = p[5];
r1 += r;
g1 += g;
b1 += b;
lum[1] = (FIX(0.29900) * r + FIX(0.58700) * g +
FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;
cb[0] = ((- FIX(0.16874) * r1 - FIX(0.33126) * g1 +
FIX(0.50000) * b1 + 4 * ONE_HALF - 1) >> (SCALEBITS + 2)) + 128;
cr[0] = ((FIX(0.50000) * r1 - FIX(0.41869) * g1 -
FIX(0.08131) * b1 + 4 * ONE_HALF - 1) >> (SCALEBITS + 2)) + 128;
cb++;
cr++;
p += -wrap3 + 2 * 3;
lum += -wrap + 2;
}
p += wrap3;
lum += wrap;
}
}
int img_convert_to_yuv420(UINT8 *img_out, UINT8 *img,
int pix_fmt, int width, int height)
{
UINT8 *pict;
int size, size_out;
UINT8 *picture[3];
pict = img_out;
size = width * height;
size_out = (size * 3) / 2;
picture[0] = pict;
picture[1] = pict + size;
picture[2] = picture[1] + (size / 4);
switch(pix_fmt) {
case PIX_FMT_YUV420P:
memcpy(pict, img, size_out);
break;
case PIX_FMT_YUV422:
yuv422_to_yuv420p(picture[0], picture[1], picture[2],
img, width, height);
break;
case PIX_FMT_RGB24:
rgb24_to_yuv420p(picture[0], picture[1], picture[2],
img, width, height);
break;
case PIX_FMT_BGR24:
bgr24_to_yuv420p(picture[0], picture[1], picture[2],
img, width, height);
break;
}
return size_out;
}

614
libavcodec/imgresample.c Normal file
View File

@ -0,0 +1,614 @@
/*
* High quality image resampling with polyphase filters
* Copyright (c) 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "dsputil.h"
#include "avcodec.h"
#define NB_COMPONENTS 3
#define PHASE_BITS 4
#define NB_PHASES (1 << PHASE_BITS)
#define NB_TAPS 4
#define FCENTER 1 /* index of the center of the filter */
#define POS_FRAC_BITS 16
#define POS_FRAC (1 << POS_FRAC_BITS)
/* 6 bits precision is needed for MMX */
#define FILTER_BITS 8
#define LINE_BUF_HEIGHT (NB_TAPS * 4)
struct ImgReSampleContext {
int iwidth, iheight, owidth, oheight;
int h_incr, v_incr;
INT16 h_filters[NB_PHASES][NB_TAPS] __align8; /* horizontal filters */
INT16 v_filters[NB_PHASES][NB_TAPS] __align8; /* vertical filters */
UINT8 *line_buf;
};
static inline int get_phase(int pos)
{
return ((pos) >> (POS_FRAC_BITS - PHASE_BITS)) & ((1 << PHASE_BITS) - 1);
}
/* This function must be optimized */
static void h_resample_fast(UINT8 *dst, int dst_width, UINT8 *src, int src_width,
int src_start, int src_incr, INT16 *filters)
{
int src_pos, phase, sum, i;
UINT8 *s;
INT16 *filter;
src_pos = src_start;
for(i=0;i<dst_width;i++) {
#ifdef TEST
/* test */
if ((src_pos >> POS_FRAC_BITS) < 0 ||
(src_pos >> POS_FRAC_BITS) > (src_width - NB_TAPS))
abort();
#endif
s = src + (src_pos >> POS_FRAC_BITS);
phase = get_phase(src_pos);
filter = filters + phase * NB_TAPS;
#if NB_TAPS == 4
sum = s[0] * filter[0] +
s[1] * filter[1] +
s[2] * filter[2] +
s[3] * filter[3];
#else
{
int j;
sum = 0;
for(j=0;j<NB_TAPS;j++)
sum += s[j] * filter[j];
}
#endif
sum = sum >> FILTER_BITS;
if (sum < 0)
sum = 0;
else if (sum > 255)
sum = 255;
dst[0] = sum;
src_pos += src_incr;
dst++;
}
}
/* This function must be optimized */
static void v_resample(UINT8 *dst, int dst_width, UINT8 *src, int wrap,
INT16 *filter)
{
int sum, i;
UINT8 *s;
s = src;
for(i=0;i<dst_width;i++) {
#if NB_TAPS == 4
sum = s[0 * wrap] * filter[0] +
s[1 * wrap] * filter[1] +
s[2 * wrap] * filter[2] +
s[3 * wrap] * filter[3];
#else
{
int j;
UINT8 *s1 = s;
sum = 0;
for(j=0;j<NB_TAPS;j++) {
sum += s1[0] * filter[j];
s1 += wrap;
}
}
#endif
sum = sum >> FILTER_BITS;
if (sum < 0)
sum = 0;
else if (sum > 255)
sum = 255;
dst[0] = sum;
dst++;
s++;
}
}
#ifdef CONFIG_MMX
#include "i386/mmx.h"
#define FILTER4(reg) \
{\
s = src + (src_pos >> POS_FRAC_BITS);\
phase = get_phase(src_pos);\
filter = filters + phase * NB_TAPS;\
movq_m2r(*s, reg);\
punpcklbw_r2r(mm7, reg);\
movq_m2r(*filter, mm6);\
pmaddwd_r2r(reg, mm6);\
movq_r2r(mm6, reg);\
psrlq_i2r(32, reg);\
paddd_r2r(mm6, reg);\
psrad_i2r(FILTER_BITS, reg);\
src_pos += src_incr;\
}
#define DUMP(reg) movq_r2m(reg, tmp); printf(#reg "=%016Lx\n", tmp.uq);
/* XXX: do four pixels at a time */
static void h_resample_fast4_mmx(UINT8 *dst, int dst_width, UINT8 *src, int src_width,
int src_start, int src_incr, INT16 *filters)
{
int src_pos, phase;
UINT8 *s;
INT16 *filter;
mmx_t tmp;
src_pos = src_start;
pxor_r2r(mm7, mm7);
while (dst_width >= 4) {
FILTER4(mm0);
FILTER4(mm1);
FILTER4(mm2);
FILTER4(mm3);
packuswb_r2r(mm7, mm0);
packuswb_r2r(mm7, mm1);
packuswb_r2r(mm7, mm3);
packuswb_r2r(mm7, mm2);
movq_r2m(mm0, tmp);
dst[0] = tmp.ub[0];
movq_r2m(mm1, tmp);
dst[1] = tmp.ub[0];
movq_r2m(mm2, tmp);
dst[2] = tmp.ub[0];
movq_r2m(mm3, tmp);
dst[3] = tmp.ub[0];
dst += 4;
dst_width -= 4;
}
while (dst_width > 0) {
FILTER4(mm0);
packuswb_r2r(mm7, mm0);
movq_r2m(mm0, tmp);
dst[0] = tmp.ub[0];
dst++;
dst_width--;
}
emms();
}
static void v_resample4_mmx(UINT8 *dst, int dst_width, UINT8 *src, int wrap,
INT16 *filter)
{
int sum, i, v;
UINT8 *s;
mmx_t tmp;
mmx_t coefs[4];
for(i=0;i<4;i++) {
v = filter[i];
coefs[i].uw[0] = v;
coefs[i].uw[1] = v;
coefs[i].uw[2] = v;
coefs[i].uw[3] = v;
}
pxor_r2r(mm7, mm7);
s = src;
while (dst_width >= 4) {
movq_m2r(s[0 * wrap], mm0);
punpcklbw_r2r(mm7, mm0);
movq_m2r(s[1 * wrap], mm1);
punpcklbw_r2r(mm7, mm1);
movq_m2r(s[2 * wrap], mm2);
punpcklbw_r2r(mm7, mm2);
movq_m2r(s[3 * wrap], mm3);
punpcklbw_r2r(mm7, mm3);
pmullw_m2r(coefs[0], mm0);
pmullw_m2r(coefs[1], mm1);
pmullw_m2r(coefs[2], mm2);
pmullw_m2r(coefs[3], mm3);
paddw_r2r(mm1, mm0);
paddw_r2r(mm3, mm2);
paddw_r2r(mm2, mm0);
psraw_i2r(FILTER_BITS, mm0);
packuswb_r2r(mm7, mm0);
movq_r2m(mm0, tmp);
*(UINT32 *)dst = tmp.ud[0];
dst += 4;
s += 4;
dst_width -= 4;
}
while (dst_width > 0) {
sum = s[0 * wrap] * filter[0] +
s[1 * wrap] * filter[1] +
s[2 * wrap] * filter[2] +
s[3 * wrap] * filter[3];
sum = sum >> FILTER_BITS;
if (sum < 0)
sum = 0;
else if (sum > 255)
sum = 255;
dst[0] = sum;
dst++;
s++;
dst_width--;
}
emms();
}
#endif
/* slow version to handle limit cases. Does not need optimisation */
static void h_resample_slow(UINT8 *dst, int dst_width, UINT8 *src, int src_width,
int src_start, int src_incr, INT16 *filters)
{
int src_pos, phase, sum, j, v, i;
UINT8 *s, *src_end;
INT16 *filter;
src_end = src + src_width;
src_pos = src_start;
for(i=0;i<dst_width;i++) {
s = src + (src_pos >> POS_FRAC_BITS);
phase = get_phase(src_pos);
filter = filters + phase * NB_TAPS;
sum = 0;
for(j=0;j<NB_TAPS;j++) {
if (s < src)
v = src[0];
else if (s >= src_end)
v = src_end[-1];
else
v = s[0];
sum += v * filter[j];
s++;
}
sum = sum >> FILTER_BITS;
if (sum < 0)
sum = 0;
else if (sum > 255)
sum = 255;
dst[0] = sum;
src_pos += src_incr;
dst++;
}
}
static void h_resample(UINT8 *dst, int dst_width, UINT8 *src, int src_width,
int src_start, int src_incr, INT16 *filters)
{
int n, src_end;
if (src_start < 0) {
n = (0 - src_start + src_incr - 1) / src_incr;
h_resample_slow(dst, n, src, src_width, src_start, src_incr, filters);
dst += n;
dst_width -= n;
src_start += n * src_incr;
}
src_end = src_start + dst_width * src_incr;
if (src_end > ((src_width - NB_TAPS) << POS_FRAC_BITS)) {
n = (((src_width - NB_TAPS + 1) << POS_FRAC_BITS) - 1 - src_start) /
src_incr;
} else {
n = dst_width;
}
#ifdef CONFIG_MMX
if ((mm_flags & MM_MMX) && NB_TAPS == 4)
h_resample_fast4_mmx(dst, n,
src, src_width, src_start, src_incr, filters);
else
#endif
h_resample_fast(dst, n,
src, src_width, src_start, src_incr, filters);
if (n < dst_width) {
dst += n;
dst_width -= n;
src_start += n * src_incr;
h_resample_slow(dst, dst_width,
src, src_width, src_start, src_incr, filters);
}
}
static void component_resample(ImgReSampleContext *s,
UINT8 *output, int owrap, int owidth, int oheight,
UINT8 *input, int iwrap, int iwidth, int iheight)
{
int src_y, src_y1, last_src_y, ring_y, phase_y, y1, y;
UINT8 *new_line, *src_line;
last_src_y = - FCENTER - 1;
/* position of the bottom of the filter in the source image */
src_y = (last_src_y + NB_TAPS) * POS_FRAC;
ring_y = NB_TAPS; /* position in ring buffer */
for(y=0;y<oheight;y++) {
/* apply horizontal filter on new lines from input if needed */
src_y1 = src_y >> POS_FRAC_BITS;
while (last_src_y < src_y1) {
if (++ring_y >= LINE_BUF_HEIGHT + NB_TAPS)
ring_y = NB_TAPS;
last_src_y++;
/* handle limit conditions : replicate line (slighly
inefficient because we filter multiple times */
y1 = last_src_y;
if (y1 < 0) {
y1 = 0;
} else if (y1 >= iheight) {
y1 = iheight - 1;
}
src_line = input + y1 * iwrap;
new_line = s->line_buf + ring_y * owidth;
/* apply filter and handle limit cases correctly */
h_resample(new_line, owidth,
src_line, iwidth, - FCENTER * POS_FRAC, s->h_incr,
&s->h_filters[0][0]);
/* handle ring buffer wraping */
if (ring_y >= LINE_BUF_HEIGHT) {
memcpy(s->line_buf + (ring_y - LINE_BUF_HEIGHT) * owidth,
new_line, owidth);
}
}
/* apply vertical filter */
phase_y = get_phase(src_y);
#ifdef CONFIG_MMX
/* desactivated MMX because loss of precision */
if ((mm_flags & MM_MMX) && NB_TAPS == 4 && 0)
v_resample4_mmx(output, owidth,
s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
&s->v_filters[phase_y][0]);
else
#endif
v_resample(output, owidth,
s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
&s->v_filters[phase_y][0]);
src_y += s->v_incr;
output += owrap;
}
}
/* XXX: the following filter is quite naive, but it seems to suffice
for 4 taps */
static void build_filter(INT16 *filter, float factor)
{
int ph, i, v;
float x, y, tab[NB_TAPS], norm, mult;
/* if upsampling, only need to interpolate, no filter */
if (factor > 1.0)
factor = 1.0;
for(ph=0;ph<NB_PHASES;ph++) {
norm = 0;
for(i=0;i<NB_TAPS;i++) {
x = M_PI * ((float)(i - FCENTER) - (float)ph / NB_PHASES) * factor;
if (x == 0)
y = 1.0;
else
y = sin(x) / x;
tab[i] = y;
norm += y;
}
/* normalize so that an uniform color remains the same */
mult = (float)(1 << FILTER_BITS) / norm;
for(i=0;i<NB_TAPS;i++) {
v = (int)(tab[i] * mult);
filter[ph * NB_TAPS + i] = v;
}
}
}
ImgReSampleContext *img_resample_init(int owidth, int oheight,
int iwidth, int iheight)
{
ImgReSampleContext *s;
s = av_mallocz(sizeof(ImgReSampleContext));
if (!s)
return NULL;
s->line_buf = av_mallocz(owidth * (LINE_BUF_HEIGHT + NB_TAPS));
if (!s->line_buf)
goto fail;
s->owidth = owidth;
s->oheight = oheight;
s->iwidth = iwidth;
s->iheight = iheight;
s->h_incr = (iwidth * POS_FRAC) / owidth;
s->v_incr = (iheight * POS_FRAC) / oheight;
build_filter(&s->h_filters[0][0], (float)owidth / (float)iwidth);
build_filter(&s->v_filters[0][0], (float)oheight / (float)iheight);
return s;
fail:
free(s);
return NULL;
}
void img_resample(ImgReSampleContext *s,
AVPicture *output, AVPicture *input)
{
int i, shift;
for(i=0;i<3;i++) {
shift = (i == 0) ? 0 : 1;
component_resample(s, output->data[i], output->linesize[i],
s->owidth >> shift, s->oheight >> shift,
input->data[i], input->linesize[i],
s->iwidth >> shift, s->iheight >> shift);
}
}
void img_resample_close(ImgReSampleContext *s)
{
free(s->line_buf);
free(s);
}
#ifdef TEST
void *av_mallocz(int size)
{
void *ptr;
ptr = malloc(size);
memset(ptr, 0, size);
return ptr;
}
/* input */
#define XSIZE 256
#define YSIZE 256
UINT8 img[XSIZE * YSIZE];
/* output */
#define XSIZE1 512
#define YSIZE1 512
UINT8 img1[XSIZE1 * YSIZE1];
UINT8 img2[XSIZE1 * YSIZE1];
void save_pgm(const char *filename, UINT8 *img, int xsize, int ysize)
{
FILE *f;
f=fopen(filename,"w");
fprintf(f,"P5\n%d %d\n%d\n", xsize, ysize, 255);
fwrite(img,1, xsize * ysize,f);
fclose(f);
}
static void dump_filter(INT16 *filter)
{
int i, ph;
for(ph=0;ph<NB_PHASES;ph++) {
printf("%2d: ", ph);
for(i=0;i<NB_TAPS;i++) {
printf(" %5.2f", filter[ph * NB_TAPS + i] / 256.0);
}
printf("\n");
}
}
#ifdef CONFIG_MMX
int mm_flags;
#endif
int main(int argc, char **argv)
{
int x, y, v, i, xsize, ysize;
ImgReSampleContext *s;
float fact, factors[] = { 1/2.0, 3.0/4.0, 1.0, 4.0/3.0, 16.0/9.0, 2.0 };
char buf[256];
/* build test image */
for(y=0;y<YSIZE;y++) {
for(x=0;x<XSIZE;x++) {
if (x < XSIZE/2 && y < YSIZE/2) {
if (x < XSIZE/4 && y < YSIZE/4) {
if ((x % 10) <= 6 &&
(y % 10) <= 6)
v = 0xff;
else
v = 0x00;
} else if (x < XSIZE/4) {
if (x & 1)
v = 0xff;
else
v = 0;
} else if (y < XSIZE/4) {
if (y & 1)
v = 0xff;
else
v = 0;
} else {
if (y < YSIZE*3/8) {
if ((y+x) & 1)
v = 0xff;
else
v = 0;
} else {
if (((x+3) % 4) <= 1 &&
((y+3) % 4) <= 1)
v = 0xff;
else
v = 0x00;
}
}
} else if (x < XSIZE/2) {
v = ((x - (XSIZE/2)) * 255) / (XSIZE/2);
} else if (y < XSIZE/2) {
v = ((y - (XSIZE/2)) * 255) / (XSIZE/2);
} else {
v = ((x + y - XSIZE) * 255) / XSIZE;
}
img[y * XSIZE + x] = v;
}
}
save_pgm("/tmp/in.pgm", img, XSIZE, YSIZE);
for(i=0;i<sizeof(factors)/sizeof(float);i++) {
fact = factors[i];
xsize = (int)(XSIZE * fact);
ysize = (int)(YSIZE * fact);
s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
printf("Factor=%0.2f\n", fact);
dump_filter(&s->h_filters[0][0]);
component_resample(s, img1, xsize, xsize, ysize,
img, XSIZE, XSIZE, YSIZE);
img_resample_close(s);
sprintf(buf, "/tmp/out%d.pgm", i);
save_pgm(buf, img1, xsize, ysize);
}
/* mmx test */
#ifdef CONFIG_MMX
printf("MMX test\n");
fact = 0.72;
xsize = (int)(XSIZE * fact);
ysize = (int)(YSIZE * fact);
mm_flags = MM_MMX;
s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
component_resample(s, img1, xsize, xsize, ysize,
img, XSIZE, XSIZE, YSIZE);
mm_flags = 0;
s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
component_resample(s, img2, xsize, xsize, ysize,
img, XSIZE, XSIZE, YSIZE);
if (memcmp(img1, img2, xsize * ysize) != 0) {
fprintf(stderr, "mmx error\n");
exit(1);
}
printf("MMX OK\n");
#endif
return 0;
}
#endif

224
libavcodec/jfdctfst.c Normal file
View File

@ -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 "dsputil.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 */
}
}

1167
libavcodec/jrevdct.c Normal file

File diff suppressed because it is too large Load Diff

108
libavcodec/libac3/ac3.h Normal file
View File

@ -0,0 +1,108 @@
/*
* ac3.h
*
* Copyright (C) Aaron Holtzman - May 1999
*
* This file is part of ac3dec, a free Dolby AC-3 stream decoder.
*
* ac3dec 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, or (at your option)
* any later version.
*
* ac3dec 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 GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
*/
typedef struct ac3_ba_s {
uint16_t fsnroffst; // fine SNR offset
uint16_t fgaincod; // fast gain
uint16_t deltbae; // delta bit allocation exists
int8_t deltba[50]; // per-band delta bit allocation
} ac3_ba_t;
typedef struct ac3_state_s {
uint8_t fscod; // sample rate
uint8_t halfrate; // halfrate factor
uint8_t acmod; // coded channels
float clev; // centre channel mix level
float slev; // surround channels mix level
uint8_t lfeon; // coded lfe channel
int output; // type of output
float level; // output level
float bias; // output bias
uint16_t cplinu; // coupling in use
uint16_t chincpl[5]; // channel coupled
uint16_t phsflginu; // phase flags in use (stereo only)
uint16_t cplbndstrc[18]; // coupling band structure
uint16_t cplstrtmant; // coupling channel start mantissa
uint16_t cplendmant; // coupling channel end mantissa
float cplco[5][18]; // coupling coordinates
// derived information
uint16_t cplstrtbnd; // coupling start band (for bit allocation)
uint16_t ncplbnd; // number of coupling bands
uint16_t rematflg[4]; // stereo rematrixing
uint16_t endmant[5]; // channel end mantissa
uint8_t cpl_exp[256]; // decoded coupling channel exponents
uint8_t fbw_exp[5][256]; // decoded channel exponents
uint8_t lfe_exp[7]; // decoded lfe channel exponents
uint16_t sdcycod; // slow decay
uint16_t fdcycod; // fast decay
uint16_t sgaincod; // slow gain
uint16_t dbpbcod; // dB per bit - encodes the dbknee value
uint16_t floorcod; // masking floor
uint16_t csnroffst; // coarse SNR offset
ac3_ba_t cplba; // coupling bit allocation parameters
ac3_ba_t ba[5]; // channel bit allocation parameters
ac3_ba_t lfeba; // lfe bit allocation parameters
uint16_t cplfleak; // coupling fast leak init
uint16_t cplsleak; // coupling slow leak init
// derived bit allocation information
int8_t fbw_bap[5][256];
int8_t cpl_bap[256];
int8_t lfe_bap[7];
} ac3_state_t;
/* samples work structure */
typedef float stream_samples_t[6][256];
#define AC3_CHANNEL 0
#define AC3_MONO 1
#define AC3_STEREO 2
#define AC3_3F 3
#define AC3_2F1R 4
#define AC3_3F1R 5
#define AC3_2F2R 6
#define AC3_3F2R 7
#define AC3_CHANNEL1 8
#define AC3_CHANNEL2 9
#define AC3_DOLBY 10
#define AC3_CHANNEL_MASK 15
#define AC3_LFE 16
#define AC3_ADJUST_LEVEL 32
void ac3_init (void);
int ac3_syncinfo (uint8_t * buf, int * flags,
int * sample_rate, int * bit_rate);
int ac3_frame (ac3_state_t * state, uint8_t * buf, int * flags,
float * level, float bias);
int ac3_block (ac3_state_t * state);

View File

@ -0,0 +1,51 @@
/*
* ac3_internal.h
*
* Copyright (C) Aaron Holtzman - May 1999
*
* This file is part of ac3dec, a free Dolby AC-3 stream decoder.
*
* ac3dec 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, or (at your option)
* any later version.
*
* ac3dec 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 GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#define LEVEL_PLUS3DB 1.4142135623730951
#define LEVEL_3DB 0.7071067811865476
#define LEVEL_45DB 0.5946035575013605
#define LEVEL_6DB 0.5
/* Exponent strategy constants */
#define EXP_REUSE (0)
#define EXP_D15 (1)
#define EXP_D25 (2)
#define EXP_D45 (3)
/* Delta bit allocation constants */
#define DELTA_BIT_REUSE (0)
#define DELTA_BIT_NEW (1)
#define DELTA_BIT_NONE (2)
#define DELTA_BIT_RESERVED (3)
void bit_allocate (ac3_state_t * state, ac3_ba_t * ba, int bndstart,
int start, int end, int fastleak, int slowleak,
uint8_t * exp, int8_t * bap);
int downmix_init (int input, int flags, float * level, float clev, float slev);
void downmix (float * samples, int acmod, int output, float level, float bias,
float clev, float slev);
void imdct_init (void);
extern void (* imdct_256) (float data[], float delay[]);
extern void (* imdct_512) (float data[], float delay[]);

View File

@ -0,0 +1,255 @@
/*
* bit_allocate.c
*
* Copyright (C) Aaron Holtzman - May 1999
*
* This file is part of ac3dec, a free Dolby AC-3 stream decoder.
*
* ac3dec 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, or (at your option)
* any later version.
*
* ac3dec 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 GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "ac3.h"
#include "ac3_internal.h"
static int hthtab[3][50] = {
{0x730, 0x730, 0x7c0, 0x800, 0x820, 0x840, 0x850, 0x850, 0x860, 0x860,
0x860, 0x860, 0x860, 0x870, 0x870, 0x870, 0x880, 0x880, 0x890, 0x890,
0x8a0, 0x8a0, 0x8b0, 0x8b0, 0x8c0, 0x8c0, 0x8d0, 0x8e0, 0x8f0, 0x900,
0x910, 0x910, 0x910, 0x910, 0x900, 0x8f0, 0x8c0, 0x870, 0x820, 0x7e0,
0x7a0, 0x770, 0x760, 0x7a0, 0x7c0, 0x7c0, 0x6e0, 0x400, 0x3c0, 0x3c0},
{0x710, 0x710, 0x7a0, 0x7f0, 0x820, 0x830, 0x840, 0x850, 0x850, 0x860,
0x860, 0x860, 0x860, 0x860, 0x870, 0x870, 0x870, 0x880, 0x880, 0x880,
0x890, 0x890, 0x8a0, 0x8a0, 0x8b0, 0x8b0, 0x8c0, 0x8c0, 0x8e0, 0x8f0,
0x900, 0x910, 0x910, 0x910, 0x910, 0x900, 0x8e0, 0x8b0, 0x870, 0x820,
0x7e0, 0x7b0, 0x760, 0x770, 0x7a0, 0x7c0, 0x780, 0x5d0, 0x3c0, 0x3c0},
{0x680, 0x680, 0x750, 0x7b0, 0x7e0, 0x810, 0x820, 0x830, 0x840, 0x850,
0x850, 0x850, 0x860, 0x860, 0x860, 0x860, 0x860, 0x860, 0x860, 0x860,
0x870, 0x870, 0x870, 0x870, 0x880, 0x880, 0x880, 0x890, 0x8a0, 0x8b0,
0x8c0, 0x8d0, 0x8e0, 0x8f0, 0x900, 0x910, 0x910, 0x910, 0x900, 0x8f0,
0x8d0, 0x8b0, 0x840, 0x7f0, 0x790, 0x760, 0x7a0, 0x7c0, 0x7b0, 0x720}
};
static int8_t baptab[305] = {
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,
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, // 93 padding entries
16, 16, 16, 16, 16, 16, 16, 16, 16, 14, 14, 14, 14, 14, 14, 14,
14, 12, 12, 12, 12, 11, 11, 11, 11, 10, 10, 10, 10, 9, 9, 9,
9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5,
5, 4, 4, -3, -3, 3, 3, 3, -2, -2, -1, -1, -1, -1, -1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0 // 148 padding entries
};
static int bndtab[30] = {21, 22, 23, 24, 25, 26, 27, 28, 31, 34,
37, 40, 43, 46, 49, 55, 61, 67, 73, 79,
85, 97, 109, 121, 133, 157, 181, 205, 229, 253};
static int8_t latab[256] = {
-64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53,
-52, -52, -51, -50, -49, -48, -47, -47, -46, -45, -44, -44,
-43, -42, -41, -41, -40, -39, -38, -38, -37, -36, -36, -35,
-35, -34, -33, -33, -32, -32, -31, -30, -30, -29, -29, -28,
-28, -27, -27, -26, -26, -25, -25, -24, -24, -23, -23, -22,
-22, -21, -21, -21, -20, -20, -19, -19, -19, -18, -18, -18,
-17, -17, -17, -16, -16, -16, -15, -15, -15, -14, -14, -14,
-13, -13, -13, -13, -12, -12, -12, -12, -11, -11, -11, -11,
-10, -10, -10, -10, -10, -9, -9, -9, -9, -9, -8, -8,
-8, -8, -8, -8, -7, -7, -7, -7, -7, -7, -6, -6,
-6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, -5,
-5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4,
-4, -3, -3, -3, -3, -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, -2, -2, -2, -2, -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, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0
};
#define UPDATE_LEAK() \
do { \
fastleak += fdecay; \
if (fastleak > psd + fgain) \
fastleak = psd + fgain; \
slowleak += sdecay; \
if (slowleak > psd + sgain) \
slowleak = psd + sgain; \
} while (0)
#define COMPUTE_MASK() \
do { \
if (psd > dbknee) \
mask -= (psd - dbknee) >> 2; \
if (mask > hth [i >> halfrate]) \
mask = hth [i >> halfrate]; \
mask -= snroffset + 128 * deltba[i]; \
mask = (mask > 0) ? 0 : ((-mask) >> 5); \
mask -= floor; \
} while (0)
void bit_allocate (ac3_state_t * state, ac3_ba_t * ba, int bndstart,
int start, int end, int fastleak, int slowleak,
uint8_t * exp, int8_t * bap)
{
static int slowgain[4] = {0x540, 0x4d8, 0x478, 0x410};
static int dbpbtab[4] = {0xc00, 0x500, 0x300, 0x100};
static int floortab[8] = {0x910, 0x950, 0x990, 0x9d0,
0xa10, 0xa90, 0xb10, 0x1400};
int i, j;
int fdecay, fgain, sdecay, sgain, dbknee, floor, snroffset;
int psd, mask;
int8_t * deltba;
int * hth;
int halfrate;
halfrate = state->halfrate;
fdecay = (63 + 20 * state->fdcycod) >> halfrate;
fgain = 128 + 128 * ba->fgaincod;
sdecay = (15 + 2 * state->sdcycod) >> halfrate;
sgain = slowgain[state->sgaincod];
dbknee = dbpbtab[state->dbpbcod];
hth = hthtab[state->fscod];
/*
* if there is no delta bit allocation, make deltba point to an area
* known to contain zeroes. baptab+156 here.
*/
deltba = (ba->deltbae == DELTA_BIT_NONE) ? baptab + 156 : ba->deltba;
floor = floortab[state->floorcod];
snroffset = 960 - 64 * state->csnroffst - 4 * ba->fsnroffst + floor;
floor >>= 5;
i = bndstart;
j = start;
if (start == 0) { // not the coupling channel
int lowcomp;
lowcomp = 0;
j = end - 1;
do {
if (i < j) {
if (exp[i+1] == exp[i] - 2)
lowcomp = 384;
else if (lowcomp && (exp[i+1] > exp[i]))
lowcomp -= 64;
}
psd = 128 * exp[i];
mask = psd + fgain + lowcomp;
COMPUTE_MASK ();
bap[i++] = (baptab+156)[mask + 4 * exp[i]];
} while ((i < 3) || ((i < 7) && (exp[i] > exp[i-1])));
fastleak = psd + fgain;
slowleak = psd + sgain;
while (i < 7) {
if (i < j) {
if (exp[i+1] == exp[i] - 2)
lowcomp = 384;
else if (lowcomp && (exp[i+1] > exp[i]))
lowcomp -= 64;
}
psd = 128 * exp[i];
UPDATE_LEAK ();
mask = ((fastleak + lowcomp < slowleak) ?
fastleak + lowcomp : slowleak);
COMPUTE_MASK ();
bap[i++] = (baptab+156)[mask + 4 * exp[i]];
}
if (end == 7) // lfe channel
return;
do {
if (exp[i+1] == exp[i] - 2)
lowcomp = 320;
else if (lowcomp && (exp[i+1] > exp[i]))
lowcomp -= 64;
psd = 128 * exp[i];
UPDATE_LEAK ();
mask = ((fastleak + lowcomp < slowleak) ?
fastleak + lowcomp : slowleak);
COMPUTE_MASK ();
bap[i++] = (baptab+156)[mask + 4 * exp[i]];
} while (i < 20);
while (lowcomp > 128) { // two iterations maximum
lowcomp -= 128;
psd = 128 * exp[i];
UPDATE_LEAK ();
mask = ((fastleak + lowcomp < slowleak) ?
fastleak + lowcomp : slowleak);
COMPUTE_MASK ();
bap[i++] = (baptab+156)[mask + 4 * exp[i]];
}
j = i;
}
do {
int startband, endband;
startband = j;
endband = ((bndtab-20)[i] < end) ? (bndtab-20)[i] : end;
psd = 128 * exp[j++];
while (j < endband) {
int next, delta;
next = 128 * exp[j++];
delta = next - psd;
switch (delta >> 9) {
case -6: case -5: case -4: case -3: case -2:
psd = next;
break;
case -1:
psd = next + latab[(-delta) >> 1];
break;
case 0:
psd += latab[delta >> 1];
break;
}
}
// minpsd = -289
UPDATE_LEAK ();
mask = (fastleak < slowleak) ? fastleak : slowleak;
COMPUTE_MASK ();
i++;
j = startband;
do {
// max(mask+4*exp)=147=-(minpsd+fgain-deltba-snroffset)>>5+4*exp
// min(mask+4*exp)=-156=-(sgain-deltba-snroffset)>>5
bap[j++] = (baptab+156)[mask + 4 * exp[j]];
} while (j < endband);
} while (j < end);
}

View File

@ -0,0 +1,77 @@
/*
* bitstream.c
*
* Copyright (C) Aaron Holtzman - Dec 1999
*
* This file is part of ac3dec, a free AC-3 audio decoder
*
* ac3dec 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, or (at your option)
* any later version.
*
* ac3dec 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 GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include "ac3.h"
#include "ac3_internal.h"
#include "bitstream.h"
#define BUFFER_SIZE 4096
static uint8_t *buffer_start;
uint32_t bits_left;
uint32_t current_word;
void bitstream_set_ptr (uint8_t * buf)
{
buffer_start = buf;
bits_left = 0;
}
static inline void
bitstream_fill_current()
{
current_word = *((uint32_t*)buffer_start)++;
current_word = swab32(current_word);
}
//
// The fast paths for _get is in the
// bitstream.h header file so it can be inlined.
//
// The "bottom half" of this routine is suffixed _bh
//
// -ah
//
uint32_t
bitstream_get_bh(uint32_t num_bits)
{
uint32_t result;
num_bits -= bits_left;
result = (current_word << (32 - bits_left)) >> (32 - bits_left);
bitstream_fill_current();
if(num_bits != 0)
result = (result << num_bits) | (current_word >> (32 - num_bits));
bits_left = 32 - num_bits;
return result;
}

View File

@ -0,0 +1,68 @@
/*
* bitstream.h
*
* Copyright (C) Aaron Holtzman - Dec 1999
*
* This file is part of ac3dec, a free AC-3 audio decoder
*
* ac3dec 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, or (at your option)
* any later version.
*
* ac3dec 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 GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
//My new and improved vego-matic endian swapping routine
//(stolen from the kernel)
#ifdef WORDS_BIGENDIAN
# define swab32(x) (x)
#else
# if defined (__i386__)
# define swab32(x) __i386_swab32(x)
static inline const uint32_t __i386_swab32(uint32_t x)
{
__asm__("bswap %0" : "=r" (x) : "0" (x));
return x;
}
# else
# define swab32(x)\
((((uint8_t*)&x)[0] << 24) | (((uint8_t*)&x)[1] << 16) | \
(((uint8_t*)&x)[2] << 8) | (((uint8_t*)&x)[3]))
# endif
#endif
extern uint32_t bits_left;
extern uint32_t current_word;
void bitstream_set_ptr (uint8_t * buf);
uint32_t bitstream_get_bh(uint32_t num_bits);
static inline uint32_t
bitstream_get(uint32_t num_bits)
{
uint32_t result;
if(num_bits < bits_left) {
result = (current_word << (32 - bits_left)) >> (32 - num_bits);
bits_left -= num_bits;
return result;
}
return bitstream_get_bh(num_bits);
}

533
libavcodec/libac3/downmix.c Normal file
View File

@ -0,0 +1,533 @@
/*
*
* downmix.c
*
* Copyright (C) Aaron Holtzman - Sept 1999
*
* Originally based on code by Yuqing Deng.
*
* This file is part of ac3dec, a free Dolby AC-3 stream decoder.
*
* ac3dec 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, or (at your option)
* any later version.
*
* ac3dec 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 GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
*/
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "ac3.h"
#include "ac3_internal.h"
#define CONVERT(acmod,output) (((output) << 3) + (acmod))
int downmix_init (int input, int flags, float * level, float clev, float slev)
{
static uint8_t table[11][8] = {
{AC3_CHANNEL, AC3_DOLBY, AC3_STEREO, AC3_STEREO,
AC3_STEREO, AC3_STEREO, AC3_STEREO, AC3_STEREO},
{AC3_MONO, AC3_MONO, AC3_MONO, AC3_MONO,
AC3_MONO, AC3_MONO, AC3_MONO, AC3_MONO},
{AC3_CHANNEL, AC3_DOLBY, AC3_STEREO, AC3_STEREO,
AC3_STEREO, AC3_STEREO, AC3_STEREO, AC3_STEREO},
{AC3_CHANNEL, AC3_DOLBY, AC3_STEREO, AC3_3F,
AC3_STEREO, AC3_3F, AC3_STEREO, AC3_3F},
{AC3_CHANNEL, AC3_DOLBY, AC3_STEREO, AC3_STEREO,
AC3_2F1R, AC3_2F1R, AC3_2F1R, AC3_2F1R},
{AC3_CHANNEL, AC3_DOLBY, AC3_STEREO, AC3_STEREO,
AC3_2F1R, AC3_3F1R, AC3_2F1R, AC3_3F1R},
{AC3_CHANNEL, AC3_DOLBY, AC3_STEREO, AC3_3F,
AC3_2F2R, AC3_2F2R, AC3_2F2R, AC3_2F2R},
{AC3_CHANNEL, AC3_DOLBY, AC3_STEREO, AC3_3F,
AC3_2F2R, AC3_3F2R, AC3_2F2R, AC3_3F2R},
{AC3_CHANNEL1, AC3_MONO, AC3_MONO, AC3_MONO,
AC3_MONO, AC3_MONO, AC3_MONO, AC3_MONO},
{AC3_CHANNEL2, AC3_MONO, AC3_MONO, AC3_MONO,
AC3_MONO, AC3_MONO, AC3_MONO, AC3_MONO},
{AC3_CHANNEL, AC3_DOLBY, AC3_STEREO, AC3_DOLBY,
AC3_DOLBY, AC3_DOLBY, AC3_DOLBY, AC3_DOLBY}
};
int output;
output = flags & AC3_CHANNEL_MASK;
if (output > AC3_DOLBY)
return -1;
output = table[output][input & 7];
if ((output == AC3_STEREO) &&
((input == AC3_DOLBY) || ((input == AC3_3F) && (clev == LEVEL_3DB))))
output = AC3_DOLBY;
if (flags & AC3_ADJUST_LEVEL)
switch (CONVERT (input & 7, output)) {
case CONVERT (AC3_3F, AC3_MONO):
*level *= LEVEL_3DB / (1 + clev);
break;
case CONVERT (AC3_STEREO, AC3_MONO):
case CONVERT (AC3_2F2R, AC3_2F1R):
case CONVERT (AC3_3F2R, AC3_3F1R):
level_3db:
*level *= LEVEL_3DB;
break;
case CONVERT (AC3_3F2R, AC3_2F1R):
if (clev < LEVEL_PLUS3DB - 1)
goto level_3db;
// break thru
case CONVERT (AC3_3F, AC3_STEREO):
case CONVERT (AC3_3F1R, AC3_2F1R):
case CONVERT (AC3_3F1R, AC3_2F2R):
case CONVERT (AC3_3F2R, AC3_2F2R):
*level /= 1 + clev;
break;
case CONVERT (AC3_2F1R, AC3_MONO):
*level *= LEVEL_PLUS3DB / (2 + slev);
break;
case CONVERT (AC3_2F1R, AC3_STEREO):
case CONVERT (AC3_3F1R, AC3_3F):
*level /= 1 + slev * LEVEL_3DB;
break;
case CONVERT (AC3_3F1R, AC3_MONO):
*level *= LEVEL_3DB / (1 + clev + 0.5 * slev);
break;
case CONVERT (AC3_3F1R, AC3_STEREO):
*level /= 1 + clev + slev * LEVEL_3DB;
break;
case CONVERT (AC3_2F2R, AC3_MONO):
*level *= LEVEL_3DB / (1 + slev);
break;
case CONVERT (AC3_2F2R, AC3_STEREO):
case CONVERT (AC3_3F2R, AC3_3F):
*level /= (1 + slev);
break;
case CONVERT (AC3_3F2R, AC3_MONO):
*level *= LEVEL_3DB / (1 + clev + slev);
break;
case CONVERT (AC3_3F2R, AC3_STEREO):
*level /= 1 + clev + slev;
break;
case CONVERT (AC3_MONO, AC3_DOLBY):
*level *= LEVEL_PLUS3DB;
break;
case CONVERT (AC3_3F, AC3_DOLBY):
case CONVERT (AC3_2F1R, AC3_DOLBY):
*level *= 1 / (1 + LEVEL_3DB);
break;
case CONVERT (AC3_3F1R, AC3_DOLBY):
case CONVERT (AC3_2F2R, AC3_DOLBY):
*level *= 1 / (1 + 2 * LEVEL_3DB);
break;
case CONVERT (AC3_3F2R, AC3_DOLBY):
*level *= 1 / (1 + 3 * LEVEL_3DB);
break;
}
return output;
}
static void mix1to1 (float * samples, float level, float bias)
{
int i;
for (i = 0; i < 256; i++)
samples[i] = samples[i] * level + bias;
}
static void move1to1 (float * src, float * dest, float level, float bias)
{
int i;
for (i = 0; i < 256; i++)
dest[i] = src[i] * level + bias;
}
static void mix2to1 (float * samples, float level, float bias)
{
int i;
for (i = 0; i < 256; i++)
samples[i] = (samples[i] + samples[i + 256]) * level + bias;
}
static void move2to1 (float * src, float * dest, float level, float bias)
{
int i;
for (i = 0; i < 256; i++)
dest[i] = (src[i] + src[i + 256]) * level + bias;
}
static void mix3to1 (float * samples, float level, float clev, float bias)
{
int i;
for (i = 0; i < 256; i++)
samples[i] = ((samples[i] + samples[i + 512]) * level +
samples[i + 256] * clev + bias);
}
static void mix21to1 (float * samples, float level, float slev, float bias)
{
int i;
for (i = 0; i < 256; i++)
samples[i] = ((samples[i] + samples[i + 256]) * level +
samples[i + 512] * slev + bias);
}
static void mix31to1 (float * samples, float level, float clev, float slev,
float bias)
{
int i;
for (i = 0; i < 256; i++)
samples[i] = ((samples[i] + samples[i + 512]) * level +
samples[i + 256] * clev + samples[i + 768] * slev +
bias);
}
static void mix22to1 (float * samples, float level, float slev, float bias)
{
int i;
for (i = 0; i < 256; i++)
samples[i] = ((samples[i] + samples[i + 256]) * level +
(samples[i + 512] + samples[i + 768]) * slev + bias);
}
static void mix32to1 (float * samples, float level, float clev, float slev,
float bias)
{
int i;
for (i = 0; i < 256; i++)
samples[i] = ((samples[i] + samples[i + 512]) * level +
samples[i + 256] * clev +
(samples[i + 768] + samples[i + 1024]) * slev + bias);
}
static void mix1to2 (float * src, float * dest, float level, float bias)
{
int i;
for (i = 0; i < 256; i++)
dest[i] = src[i] = src[i] * level + bias;
}
static void mix3to2 (float * samples, float level, float clev, float bias)
{
int i;
float common;
for (i = 0; i < 256; i++) {
common = samples[i + 256] * clev + bias;
samples[i] = samples[i] * level + common;
samples[i + 256] = samples[i + 512] * level + common;
}
}
static void mix21to2 (float * left, float * right, float level, float slev,
float bias)
{
int i;
float common;
for (i = 0; i < 256; i++) {
common = right[i + 256] * slev + bias;
left[i] = left[i] * level + common;
right[i] = right[i] * level + common;
}
}
static void mix11to1 (float * front, float * rear, float level, float slev,
float bias)
{
int i;
for (i = 0; i < 256; i++)
front[i] = front[i] * level + rear[i] * slev + bias;
}
static void mix31to2 (float * samples, float level, float clev, float slev,
float bias)
{
int i;
float common;
for (i = 0; i < 256; i++) {
common = samples[i + 256] * clev + samples[i + 768] * slev + bias;
samples[i] = samples[i] * level + common;
samples[i + 256] = samples[i + 512] * level + common;
}
}
static void mix32to2 (float * samples, float level, float clev, float slev,
float bias)
{
int i;
float common;
for (i = 0; i < 256; i++) {
common = samples[i + 256] * clev + bias;
samples[i] = samples[i] * level + common + samples[i + 768] * slev;
samples[i + 256] = (samples[i + 512] * level + common +
samples[i + 1024] * slev);
}
}
static void mix21toS (float * samples, float level, float level3db, float bias)
{
int i;
float surround;
for (i = 0; i < 256; i++) {
surround = samples[i + 512] * level3db;
samples[i] = samples[i] * level - surround + bias;
samples[i + 256] = samples[i + 256] * level + surround + bias;
}
}
static void mix22toS (float * samples, float level, float level3db, float bias)
{
int i;
float surround;
for (i = 0; i < 256; i++) {
surround = (samples[i + 512] + samples[i + 768]) * level3db;
samples[i] = samples[i] * level - surround + bias;
samples[i + 256] = samples[i + 256] * level + surround + bias;
}
}
static void mix31toS (float * samples, float level, float level3db, float bias)
{
int i;
float common, surround;
for (i = 0; i < 256; i++) {
common = samples[i + 256] * level3db + bias;
surround = samples[i + 768] * level3db;
samples[i] = samples[i] * level + common - surround;
samples[i + 256] = samples[i + 512] * level + common + surround;
}
}
static void mix32toS (float * samples, float level, float level3db, float bias)
{
int i;
float common, surround;
for (i = 0; i < 256; i++) {
common = samples[i + 256] * level3db + bias;
surround = (samples[i + 768] + samples[i + 1024]) * level3db;
samples[i] = samples[i] * level + common - surround;
samples[i + 256] = samples[i + 512] * level + common + surround;
}
}
void downmix (float * samples, int acmod, int output, float level, float bias,
float clev, float slev)
{
switch (CONVERT (acmod, output & AC3_CHANNEL_MASK)) {
case CONVERT (AC3_3F2R, AC3_3F2R):
mix1to1 (samples + 1024, level, bias);
case CONVERT (AC3_3F1R, AC3_3F1R):
case CONVERT (AC3_2F2R, AC3_2F2R):
mix1to1 (samples + 768, level, bias);
case CONVERT (AC3_3F, AC3_3F):
case CONVERT (AC3_2F1R, AC3_2F1R):
mix_3to3:
mix1to1 (samples + 512, level, bias);
case CONVERT (AC3_CHANNEL, AC3_CHANNEL):
case CONVERT (AC3_STEREO, AC3_STEREO):
case CONVERT (AC3_STEREO, AC3_DOLBY):
mix_2to2:
mix1to1 (samples + 256, level, bias);
case CONVERT (AC3_CHANNEL, AC3_CHANNEL1):
case CONVERT (AC3_MONO, AC3_MONO):
mix1to1 (samples, level, bias);
break;
case CONVERT (AC3_CHANNEL, AC3_CHANNEL2):
mix_1to1_b:
mix1to1 (samples + 256, level, bias);
break;
case CONVERT (AC3_STEREO, AC3_MONO):
mix_2to1:
mix2to1 (samples, level * LEVEL_3DB, bias);
break;
case CONVERT (AC3_2F1R, AC3_MONO):
if (slev == 0)
goto mix_2to1;
mix21to1 (samples, level * LEVEL_3DB, level * slev * LEVEL_3DB, bias);
break;
case CONVERT (AC3_2F2R, AC3_MONO):
if (slev == 0)
goto mix_2to1;
mix22to1 (samples, level * LEVEL_3DB, level * slev * LEVEL_3DB, bias);
break;
case CONVERT (AC3_3F, AC3_MONO):
mix_3to1:
mix3to1 (samples, level * LEVEL_3DB, level * clev * LEVEL_PLUS3DB,
bias);
break;
case CONVERT (AC3_3F1R, AC3_MONO):
if (slev == 0)
goto mix_3to1;
mix31to1 (samples, level * LEVEL_3DB, level * clev * LEVEL_PLUS3DB,
level * slev * LEVEL_3DB, bias);
break;
case CONVERT (AC3_3F2R, AC3_MONO):
if (slev == 0)
goto mix_3to1;
mix32to1 (samples, level * LEVEL_3DB, level * clev * LEVEL_PLUS3DB,
level * slev * LEVEL_3DB, bias);
break;
case CONVERT (AC3_CHANNEL, AC3_MONO):
mix2to1 (samples, level * LEVEL_6DB, bias);
break;
case CONVERT (AC3_MONO, AC3_DOLBY):
mix1to2 (samples, samples + 256, level * LEVEL_3DB, bias);
break;
case CONVERT (AC3_3F, AC3_DOLBY):
clev = LEVEL_3DB;
case CONVERT (AC3_3F, AC3_STEREO):
mix_3to2:
mix3to2 (samples, level, level * clev, bias);
break;
case CONVERT (AC3_2F1R, AC3_DOLBY):
mix21toS (samples, level, level * LEVEL_3DB, bias);
break;
case CONVERT (AC3_3F1R, AC3_DOLBY):
mix31toS (samples, level, level * LEVEL_3DB, bias);
break;
case CONVERT (AC3_2F2R, AC3_DOLBY):
mix22toS (samples, level, level * LEVEL_3DB, bias);
break;
case CONVERT (AC3_3F2R, AC3_DOLBY):
mix32toS (samples, level, level * LEVEL_3DB, bias);
break;
case CONVERT (AC3_2F1R, AC3_STEREO):
if (slev == 0)
goto mix_2to2;
mix21to2 (samples, samples + 256, level, level * slev * LEVEL_3DB,
bias);
break;
case CONVERT (AC3_3F1R, AC3_STEREO):
if (slev == 0)
goto mix_3to2;
mix31to2 (samples, level, level * clev, level * slev * LEVEL_3DB,
bias);
break;
case CONVERT (AC3_2F2R, AC3_STEREO):
if (slev == 0)
goto mix_2to2;
mix11to1 (samples, samples + 512, level, level * slev, bias);
mix11to1 (samples + 256, samples + 768, level, level * slev, bias);
break;
case CONVERT (AC3_3F2R, AC3_STEREO):
if (slev == 0)
goto mix_3to2;
mix32to2 (samples, level, level * clev, level * slev, bias);
break;
case CONVERT (AC3_3F1R, AC3_3F):
if (slev == 0)
goto mix_3to3;
mix21to2 (samples, samples + 512, level, level * slev * LEVEL_3DB,
bias);
case CONVERT (AC3_3F2R, AC3_3F):
if (slev == 0)
goto mix_3to3;
mix11to1 (samples, samples + 768, level, level * slev, bias);
mix11to1 (samples + 512, samples + 1024, level, level * slev, bias);
goto mix_1to1_b;
case CONVERT (AC3_2F1R, AC3_2F2R):
mix1to2 (samples + 512, samples + 768, level * LEVEL_3DB, bias);
goto mix_2to2;
case CONVERT (AC3_3F1R, AC3_3F2R):
mix1to2 (samples + 768, samples + 1024, level * LEVEL_3DB, bias);
goto mix_3to3;
case CONVERT (AC3_2F2R, AC3_2F1R):
mix2to1 (samples + 512, level * LEVEL_3DB, bias);
goto mix_2to2;
case CONVERT (AC3_3F2R, AC3_3F1R):
mix2to1 (samples + 768, level * LEVEL_3DB, bias);
goto mix_3to3;
case CONVERT (AC3_3F1R, AC3_2F2R):
mix3to2 (samples, level, level * clev, bias);
mix1to2 (samples + 768, samples + 512, level * LEVEL_3DB, bias);
break;
case CONVERT (AC3_3F1R, AC3_2F1R):
mix3to2 (samples, level, level * clev, bias);
move1to1 (samples + 768, samples + 512, level, bias);
break;
case CONVERT (AC3_3F2R, AC3_2F1R):
mix3to2 (samples, level, level * clev, bias);
move2to1 (samples + 768, samples + 512, level * LEVEL_3DB, bias);
break;
case CONVERT (AC3_3F2R, AC3_2F2R):
mix3to2 (samples, level, level * clev, bias);
move1to1 (samples + 768, samples + 512, level, bias);
move1to1 (samples + 1024, samples + 768, level, bias);
break;
}
}

408
libavcodec/libac3/imdct.c Normal file
View File

@ -0,0 +1,408 @@
/*
* imdct.c
*
* Copyright (C) Aaron Holtzman - May 1999
*
* This file is part of ac3dec, a free Dolby AC-3 stream decoder.
*
* ac3dec 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, or (at your option)
* any later version.
*
* ac3dec 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 GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
*/
//#include "config.h"
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "ac3.h"
#include "ac3_internal.h"
void (* imdct_256) (float data[], float delay[]);
void (* imdct_512) (float data[], float delay[]);
typedef struct complex_s
{
float real;
float imag;
} complex_t;
/* 128 point bit-reverse LUT */
static uint8_t bit_reverse_512[] = {
0x00, 0x40, 0x20, 0x60, 0x10, 0x50, 0x30, 0x70,
0x08, 0x48, 0x28, 0x68, 0x18, 0x58, 0x38, 0x78,
0x04, 0x44, 0x24, 0x64, 0x14, 0x54, 0x34, 0x74,
0x0c, 0x4c, 0x2c, 0x6c, 0x1c, 0x5c, 0x3c, 0x7c,
0x02, 0x42, 0x22, 0x62, 0x12, 0x52, 0x32, 0x72,
0x0a, 0x4a, 0x2a, 0x6a, 0x1a, 0x5a, 0x3a, 0x7a,
0x06, 0x46, 0x26, 0x66, 0x16, 0x56, 0x36, 0x76,
0x0e, 0x4e, 0x2e, 0x6e, 0x1e, 0x5e, 0x3e, 0x7e,
0x01, 0x41, 0x21, 0x61, 0x11, 0x51, 0x31, 0x71,
0x09, 0x49, 0x29, 0x69, 0x19, 0x59, 0x39, 0x79,
0x05, 0x45, 0x25, 0x65, 0x15, 0x55, 0x35, 0x75,
0x0d, 0x4d, 0x2d, 0x6d, 0x1d, 0x5d, 0x3d, 0x7d,
0x03, 0x43, 0x23, 0x63, 0x13, 0x53, 0x33, 0x73,
0x0b, 0x4b, 0x2b, 0x6b, 0x1b, 0x5b, 0x3b, 0x7b,
0x07, 0x47, 0x27, 0x67, 0x17, 0x57, 0x37, 0x77,
0x0f, 0x4f, 0x2f, 0x6f, 0x1f, 0x5f, 0x3f, 0x7f};
static uint8_t bit_reverse_256[] = {
0x00, 0x20, 0x10, 0x30, 0x08, 0x28, 0x18, 0x38,
0x04, 0x24, 0x14, 0x34, 0x0c, 0x2c, 0x1c, 0x3c,
0x02, 0x22, 0x12, 0x32, 0x0a, 0x2a, 0x1a, 0x3a,
0x06, 0x26, 0x16, 0x36, 0x0e, 0x2e, 0x1e, 0x3e,
0x01, 0x21, 0x11, 0x31, 0x09, 0x29, 0x19, 0x39,
0x05, 0x25, 0x15, 0x35, 0x0d, 0x2d, 0x1d, 0x3d,
0x03, 0x23, 0x13, 0x33, 0x0b, 0x2b, 0x1b, 0x3b,
0x07, 0x27, 0x17, 0x37, 0x0f, 0x2f, 0x1f, 0x3f};
static complex_t buf[128];
/* Twiddle factor LUT */
static complex_t w_1[1];
static complex_t w_2[2];
static complex_t w_4[4];
static complex_t w_8[8];
static complex_t w_16[16];
static complex_t w_32[32];
static complex_t w_64[64];
static complex_t * w[7] = {w_1, w_2, w_4, w_8, w_16, w_32, w_64};
/* Twiddle factors for IMDCT */
static float xcos1[128];
static float xsin1[128];
static float xcos2[64];
static float xsin2[64];
/* Windowing function for Modified DCT - Thank you acroread */
float imdct_window[] = {
0.00014, 0.00024, 0.00037, 0.00051, 0.00067, 0.00086, 0.00107, 0.00130,
0.00157, 0.00187, 0.00220, 0.00256, 0.00297, 0.00341, 0.00390, 0.00443,
0.00501, 0.00564, 0.00632, 0.00706, 0.00785, 0.00871, 0.00962, 0.01061,
0.01166, 0.01279, 0.01399, 0.01526, 0.01662, 0.01806, 0.01959, 0.02121,
0.02292, 0.02472, 0.02662, 0.02863, 0.03073, 0.03294, 0.03527, 0.03770,
0.04025, 0.04292, 0.04571, 0.04862, 0.05165, 0.05481, 0.05810, 0.06153,
0.06508, 0.06878, 0.07261, 0.07658, 0.08069, 0.08495, 0.08935, 0.09389,
0.09859, 0.10343, 0.10842, 0.11356, 0.11885, 0.12429, 0.12988, 0.13563,
0.14152, 0.14757, 0.15376, 0.16011, 0.16661, 0.17325, 0.18005, 0.18699,
0.19407, 0.20130, 0.20867, 0.21618, 0.22382, 0.23161, 0.23952, 0.24757,
0.25574, 0.26404, 0.27246, 0.28100, 0.28965, 0.29841, 0.30729, 0.31626,
0.32533, 0.33450, 0.34376, 0.35311, 0.36253, 0.37204, 0.38161, 0.39126,
0.40096, 0.41072, 0.42054, 0.43040, 0.44030, 0.45023, 0.46020, 0.47019,
0.48020, 0.49022, 0.50025, 0.51028, 0.52031, 0.53033, 0.54033, 0.55031,
0.56026, 0.57019, 0.58007, 0.58991, 0.59970, 0.60944, 0.61912, 0.62873,
0.63827, 0.64774, 0.65713, 0.66643, 0.67564, 0.68476, 0.69377, 0.70269,
0.71150, 0.72019, 0.72877, 0.73723, 0.74557, 0.75378, 0.76186, 0.76981,
0.77762, 0.78530, 0.79283, 0.80022, 0.80747, 0.81457, 0.82151, 0.82831,
0.83496, 0.84145, 0.84779, 0.85398, 0.86001, 0.86588, 0.87160, 0.87716,
0.88257, 0.88782, 0.89291, 0.89785, 0.90264, 0.90728, 0.91176, 0.91610,
0.92028, 0.92432, 0.92822, 0.93197, 0.93558, 0.93906, 0.94240, 0.94560,
0.94867, 0.95162, 0.95444, 0.95713, 0.95971, 0.96217, 0.96451, 0.96674,
0.96887, 0.97089, 0.97281, 0.97463, 0.97635, 0.97799, 0.97953, 0.98099,
0.98236, 0.98366, 0.98488, 0.98602, 0.98710, 0.98811, 0.98905, 0.98994,
0.99076, 0.99153, 0.99225, 0.99291, 0.99353, 0.99411, 0.99464, 0.99513,
0.99558, 0.99600, 0.99639, 0.99674, 0.99706, 0.99736, 0.99763, 0.99788,
0.99811, 0.99831, 0.99850, 0.99867, 0.99882, 0.99895, 0.99908, 0.99919,
0.99929, 0.99938, 0.99946, 0.99953, 0.99959, 0.99965, 0.99969, 0.99974,
0.99978, 0.99981, 0.99984, 0.99986, 0.99988, 0.99990, 0.99992, 0.99993,
0.99994, 0.99995, 0.99996, 0.99997, 0.99998, 0.99998, 0.99998, 0.99999,
0.99999, 0.99999, 0.99999, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000,
1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000 };
static inline void swap_cmplx(complex_t *a, complex_t *b)
{
complex_t tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
static inline complex_t cmplx_mult(complex_t a, complex_t b)
{
complex_t ret;
ret.real = a.real * b.real - a.imag * b.imag;
ret.imag = a.real * b.imag + a.imag * b.real;
return ret;
}
void
imdct_do_512(float data[],float delay[])
{
int i,k;
int p,q;
int m;
int two_m;
int two_m_plus_one;
float tmp_a_i;
float tmp_a_r;
float tmp_b_i;
float tmp_b_r;
float *data_ptr;
float *delay_ptr;
float *window_ptr;
//
// 512 IMDCT with source and dest data in 'data'
//
// Pre IFFT complex multiply plus IFFT cmplx conjugate
for( i=0; i < 128; i++) {
/* z[i] = (X[256-2*i-1] + j * X[2*i]) * (xcos1[i] + j * xsin1[i]) ; */
buf[i].real = (data[256-2*i-1] * xcos1[i]) - (data[2*i] * xsin1[i]);
buf[i].imag = -1.0 * ((data[2*i] * xcos1[i]) + (data[256-2*i-1] * xsin1[i]));
}
//Bit reversed shuffling
for(i=0; i<128; i++) {
k = bit_reverse_512[i];
if (k < i)
swap_cmplx(&buf[i],&buf[k]);
}
/* FFT Merge */
for (m=0; m < 7; m++) {
if(m)
two_m = (1 << m);
else
two_m = 1;
two_m_plus_one = (1 << (m+1));
for(k = 0; k < two_m; k++) {
for(i = 0; i < 128; i += two_m_plus_one) {
p = k + i;
q = p + two_m;
tmp_a_r = buf[p].real;
tmp_a_i = buf[p].imag;
tmp_b_r = buf[q].real * w[m][k].real - buf[q].imag * w[m][k].imag;
tmp_b_i = buf[q].imag * w[m][k].real + buf[q].real * w[m][k].imag;
buf[p].real = tmp_a_r + tmp_b_r;
buf[p].imag = tmp_a_i + tmp_b_i;
buf[q].real = tmp_a_r - tmp_b_r;
buf[q].imag = tmp_a_i - tmp_b_i;
}
}
}
/* Post IFFT complex multiply plus IFFT complex conjugate*/
for( i=0; i < 128; i++) {
/* y[n] = z[n] * (xcos1[n] + j * xsin1[n]) ; */
tmp_a_r = buf[i].real;
tmp_a_i = -1.0 * buf[i].imag;
buf[i].real =(tmp_a_r * xcos1[i]) - (tmp_a_i * xsin1[i]);
buf[i].imag =(tmp_a_r * xsin1[i]) + (tmp_a_i * xcos1[i]);
}
data_ptr = data;
delay_ptr = delay;
window_ptr = imdct_window;
/* Window and convert to real valued signal */
for(i=0; i< 64; i++) {
*data_ptr++ = 2.0f * (-buf[64+i].imag * *window_ptr++ + *delay_ptr++);
*data_ptr++ = 2.0f * ( buf[64-i-1].real * *window_ptr++ + *delay_ptr++);
}
for(i=0; i< 64; i++) {
*data_ptr++ = 2.0f * (-buf[i].real * *window_ptr++ + *delay_ptr++);
*data_ptr++ = 2.0f * ( buf[128-i-1].imag * *window_ptr++ + *delay_ptr++);
}
/* The trailing edge of the window goes into the delay line */
delay_ptr = delay;
for(i=0; i< 64; i++) {
*delay_ptr++ = -buf[64+i].real * *--window_ptr;
*delay_ptr++ = buf[64-i-1].imag * *--window_ptr;
}
for(i=0; i<64; i++) {
*delay_ptr++ = buf[i].imag * *--window_ptr;
*delay_ptr++ = -buf[128-i-1].real * *--window_ptr;
}
}
void
imdct_do_256(float data[],float delay[])
{
int i,k;
int p,q;
int m;
int two_m;
int two_m_plus_one;
float tmp_a_i;
float tmp_a_r;
float tmp_b_i;
float tmp_b_r;
float *data_ptr;
float *delay_ptr;
float *window_ptr;
complex_t *buf_1, *buf_2;
buf_1 = &buf[0];
buf_2 = &buf[64];
/* Pre IFFT complex multiply plus IFFT cmplx conjugate */
for(k=0; k<64; k++) {
/* X1[k] = X[2*k] */
/* X2[k] = X[2*k+1] */
p = 2 * (128-2*k-1);
q = 2 * (2 * k);
/* Z1[k] = (X1[128-2*k-1] + j * X1[2*k]) * (xcos2[k] + j * xsin2[k]); */
buf_1[k].real = data[p] * xcos2[k] - data[q] * xsin2[k];
buf_1[k].imag = -1.0f * (data[q] * xcos2[k] + data[p] * xsin2[k]);
/* Z2[k] = (X2[128-2*k-1] + j * X2[2*k]) * (xcos2[k] + j * xsin2[k]); */
buf_2[k].real = data[p + 1] * xcos2[k] - data[q + 1] * xsin2[k];
buf_2[k].imag = -1.0f * ( data[q + 1] * xcos2[k] + data[p + 1] * xsin2[k]);
}
//IFFT Bit reversed shuffling
for(i=0; i<64; i++) {
k = bit_reverse_256[i];
if (k < i) {
swap_cmplx(&buf_1[i],&buf_1[k]);
swap_cmplx(&buf_2[i],&buf_2[k]);
}
}
/* FFT Merge */
for (m=0; m < 6; m++) {
two_m = (1 << m);
two_m_plus_one = (1 << (m+1));
//FIXME
if(m)
two_m = (1 << m);
else
two_m = 1;
for(k = 0; k < two_m; k++) {
for(i = 0; i < 64; i += two_m_plus_one) {
p = k + i;
q = p + two_m;
//Do block 1
tmp_a_r = buf_1[p].real;
tmp_a_i = buf_1[p].imag;
tmp_b_r = buf_1[q].real * w[m][k].real - buf_1[q].imag * w[m][k].imag;
tmp_b_i = buf_1[q].imag * w[m][k].real + buf_1[q].real * w[m][k].imag;
buf_1[p].real = tmp_a_r + tmp_b_r;
buf_1[p].imag = tmp_a_i + tmp_b_i;
buf_1[q].real = tmp_a_r - tmp_b_r;
buf_1[q].imag = tmp_a_i - tmp_b_i;
//Do block 2
tmp_a_r = buf_2[p].real;
tmp_a_i = buf_2[p].imag;
tmp_b_r = buf_2[q].real * w[m][k].real - buf_2[q].imag * w[m][k].imag;
tmp_b_i = buf_2[q].imag * w[m][k].real + buf_2[q].real * w[m][k].imag;
buf_2[p].real = tmp_a_r + tmp_b_r;
buf_2[p].imag = tmp_a_i + tmp_b_i;
buf_2[q].real = tmp_a_r - tmp_b_r;
buf_2[q].imag = tmp_a_i - tmp_b_i;
}
}
}
/* Post IFFT complex multiply */
for( i=0; i < 64; i++) {
/* y1[n] = z1[n] * (xcos2[n] + j * xs in2[n]) ; */
tmp_a_r = buf_1[i].real;
tmp_a_i = -buf_1[i].imag;
buf_1[i].real =(tmp_a_r * xcos2[i]) - (tmp_a_i * xsin2[i]);
buf_1[i].imag =(tmp_a_r * xsin2[i]) + (tmp_a_i * xcos2[i]);
/* y2[n] = z2[n] * (xcos2[n] + j * xsin2[n]) ; */
tmp_a_r = buf_2[i].real;
tmp_a_i = -buf_2[i].imag;
buf_2[i].real =(tmp_a_r * xcos2[i]) - (tmp_a_i * xsin2[i]);
buf_2[i].imag =(tmp_a_r * xsin2[i]) + (tmp_a_i * xcos2[i]);
}
data_ptr = data;
delay_ptr = delay;
window_ptr = imdct_window;
/* Window and convert to real valued signal */
for(i=0; i< 64; i++) {
*data_ptr++ = 2.0f * (-buf_1[i].imag * *window_ptr++ + *delay_ptr++);
*data_ptr++ = 2.0f * ( buf_1[64-i-1].real * *window_ptr++ + *delay_ptr++);
}
for(i=0; i< 64; i++) {
*data_ptr++ = 2.0f * (-buf_1[i].real * *window_ptr++ + *delay_ptr++);
*data_ptr++ = 2.0f * ( buf_1[64-i-1].imag * *window_ptr++ + *delay_ptr++);
}
delay_ptr = delay;
for(i=0; i< 64; i++) {
*delay_ptr++ = -buf_2[i].real * *--window_ptr;
*delay_ptr++ = buf_2[64-i-1].imag * *--window_ptr;
}
for(i=0; i< 64; i++) {
*delay_ptr++ = buf_2[i].imag * *--window_ptr;
*delay_ptr++ = -buf_2[64-i-1].real * *--window_ptr;
}
}
void imdct_init (void)
{
#ifdef LIBAC3_MLIB
void imdct_do_256_mlib(float data[],float delay[]);
void imdct_do_512_mlib(float data[],float delay[]);
imdct_512 = imdct_do_512_mlib;
imdct_256 = imdct_do_256_mlib;
#else
int i, j, k;
/* Twiddle factors to turn IFFT into IMDCT */
for (i = 0; i < 128; i++) {
xcos1[i] = -cos ((M_PI / 2048) * (8 * i + 1));
xsin1[i] = -sin ((M_PI / 2048) * (8 * i + 1));
}
/* More twiddle factors to turn IFFT into IMDCT */
for (i = 0; i < 64; i++) {
xcos2[i] = -cos ((M_PI / 1024) * (8 * i + 1));
xsin2[i] = -sin ((M_PI / 1024) * (8 * i + 1));
}
for (i = 0; i < 7; i++) {
j = 1 << i;
for (k = 0; k < j; k++) {
w[i][k].real = cos (-M_PI * k / j);
w[i][k].imag = sin (-M_PI * k / j);
}
}
imdct_512 = imdct_do_512;
imdct_256 = imdct_do_256;
#endif
}

684
libavcodec/libac3/parse.c Normal file
View File

@ -0,0 +1,684 @@
/*
* parse.c
*
* Copyright (C) Aaron Holtzman - May 1999
*
* This file is part of ac3dec, a free Dolby AC-3 stream decoder.
*
* ac3dec 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, or (at your option)
* any later version.
*
* ac3dec 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 GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
*/
#include <inttypes.h>
#include <string.h>
#include "ac3.h"
#include "ac3_internal.h"
#include "bitstream.h"
#include "tables.h"
extern stream_samples_t samples; // FIXME
static float delay[6][256];
void ac3_init (void)
{
imdct_init ();
}
static uint8_t halfrate[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3};
int ac3_syncinfo (uint8_t * buf, int * flags,
int * sample_rate, int * bit_rate)
{
static int rate[] = { 32, 40, 48, 56, 64, 80, 96, 112,
128, 160, 192, 224, 256, 320, 384, 448,
512, 576, 640};
static uint8_t lfeon[8] = {0x10, 0x10, 0x04, 0x04, 0x04, 0x01, 0x04, 0x01};
int frmsizecod;
int bitrate;
int half;
int acmod;
if ((buf[0] != 0x0b) || (buf[1] != 0x77)) // syncword
return 0;
if (buf[5] >= 0x60) // bsid >= 12
return 0;
half = halfrate[buf[5] >> 3];
// acmod, dsurmod and lfeon
acmod = buf[6] >> 5;
*flags = (((buf[6] & 0xf8) == 0x50) ? AC3_DOLBY : acmod) |
((buf[6] & lfeon[acmod]) ? AC3_LFE : 0);
frmsizecod = buf[4] & 63;
if (frmsizecod >= 38)
return 0;
bitrate = rate [frmsizecod >> 1];
*bit_rate = (bitrate * 1000) >> half;
switch (buf[4] & 0xc0) {
case 0: // 48 KHz
*sample_rate = 48000 >> half;
return 4 * bitrate;
case 0x40:
*sample_rate = 44100 >> half;
return 2 * (320 * bitrate / 147 + (frmsizecod & 1));
case 0x80:
*sample_rate = 32000 >> half;
return 6 * bitrate;
default:
return 0;
}
}
int ac3_frame (ac3_state_t * state, uint8_t * buf, int * flags, float * level,
float bias)
{
static float clev[4] = {LEVEL_3DB, LEVEL_45DB, LEVEL_6DB, LEVEL_45DB};
static float slev[4] = {LEVEL_3DB, LEVEL_6DB, 0, LEVEL_6DB};
int chaninfo;
int acmod;
state->fscod = buf[4] >> 6;
state->halfrate = halfrate[buf[5] >> 3];
state->acmod = acmod = buf[6] >> 5;
bitstream_set_ptr (buf + 6);
bitstream_get (3); // skip acmod we already parsed
if ((acmod == 2) && (bitstream_get (2) == 2)) // dsurmod
acmod = AC3_DOLBY;
if ((acmod & 1) && (acmod != 1))
state->clev = clev[bitstream_get (2)]; // cmixlev
if (acmod & 4)
state->slev = slev[bitstream_get (2)]; // surmixlev
state->lfeon = bitstream_get (1);
state->output = downmix_init (acmod, *flags, level,
state->clev, state->slev);
if (state->output < 0)
return 1;
*flags = state->output;
state->level = *level;
state->bias = bias;
chaninfo = !acmod;
do {
bitstream_get (5); // dialnorm
if (bitstream_get (1)) // compre
bitstream_get (8); // compr
if (bitstream_get (1)) // langcode
bitstream_get (8); // langcod
if (bitstream_get (1)) // audprodie
bitstream_get (7); // mixlevel + roomtyp
} while (chaninfo--);
bitstream_get (2); // copyrightb + origbs
if (bitstream_get (1)) // timecod1e
bitstream_get (14); // timecod1
if (bitstream_get (1)) // timecod2e
bitstream_get (14); // timecod2
if (bitstream_get (1)) { // addbsie
int addbsil;
addbsil = bitstream_get (6);
do {
bitstream_get (8); // addbsi
} while (addbsil--);
}
return 0;
}
static int parse_exponents (int expstr, int ngrps, uint8_t exponent,
uint8_t * dest)
{
int exps;
while (ngrps--) {
exps = bitstream_get (7);
exponent += exp_1[exps];
if (exponent > 24)
return 1;
switch (expstr) {
case EXP_D45:
*(dest++) = exponent;
*(dest++) = exponent;
case EXP_D25:
*(dest++) = exponent;
case EXP_D15:
*(dest++) = exponent;
}
exponent += exp_2[exps];
if (exponent > 24)
return 1;
switch (expstr) {
case EXP_D45:
*(dest++) = exponent;
*(dest++) = exponent;
case EXP_D25:
*(dest++) = exponent;
case EXP_D15:
*(dest++) = exponent;
}
exponent += exp_3[exps];
if (exponent > 24)
return 1;
switch (expstr) {
case EXP_D45:
*(dest++) = exponent;
*(dest++) = exponent;
case EXP_D25:
*(dest++) = exponent;
case EXP_D15:
*(dest++) = exponent;
}
}
return 0;
}
static int parse_deltba (int8_t * deltba)
{
int deltnseg, deltlen, delta, j;
memset (deltba, 0, 50);
deltnseg = bitstream_get (3);
j = 0;
do {
j += bitstream_get (5);
deltlen = bitstream_get (4);
delta = bitstream_get (3);
delta -= (delta >= 4) ? 3 : 4;
if (!deltlen)
continue;
if (j + deltlen >= 50)
return 1;
while (deltlen--)
deltba[j++] = delta;
} while (deltnseg--);
return 0;
}
static inline int zero_snr_offsets (int nfchans, ac3_state_t * state)
{
int i;
if ((state->csnroffst) || (state->cplinu && state->cplba.fsnroffst) ||
(state->lfeon && state->lfeba.fsnroffst))
return 0;
for (i = 0; i < nfchans; i++)
if (state->ba[i].fsnroffst)
return 0;
return 1;
}
static float q_1[2];
static float q_2[2];
static float q_4;
static int q_1_pointer;
static int q_2_pointer;
static int q_4_pointer;
#define GET_COEFF(COEFF,DITHER) \
switch (bap[i]) { \
case 0: \
DITHER (scale_factor[exp[i]]); \
\
case -1: \
if (q_1_pointer >= 0) { \
COEFF (q_1[q_1_pointer--] * scale_factor[exp[i]]); \
} else { \
int code; \
\
code = bitstream_get (5); \
\
q_1_pointer = 1; \
q_1[0] = q_1_2[code]; \
q_1[1] = q_1_1[code]; \
COEFF (q_1_0[code] * scale_factor[exp[i]]); \
} \
\
case -2: \
if (q_2_pointer >= 0) { \
COEFF (q_2[q_2_pointer--] * scale_factor[exp[i]]); \
} else { \
int code; \
\
code = bitstream_get (7); \
\
q_2_pointer = 1; \
q_2[0] = q_2_2[code]; \
q_2[1] = q_2_1[code]; \
COEFF (q_2_0[code] * scale_factor[exp[i]]); \
} \
\
case 3: \
COEFF (q_3[bitstream_get (3)] * scale_factor[exp[i]]); \
\
case -3: \
if (q_4_pointer == 0) { \
q_4_pointer = -1; \
COEFF (q_4 * scale_factor[exp[i]]); \
} else { \
int code; \
\
code = bitstream_get (7); \
\
q_4_pointer = 0; \
q_4 = q_4_1[code]; \
COEFF (q_4_0[code] * scale_factor[exp[i]]); \
} \
\
case 4: \
COEFF (q_5[bitstream_get (4)] * scale_factor[exp[i]]); \
\
default: \
COEFF (((int16_t)(bitstream_get(bap[i]) << (16 - bap[i]))) * \
scale_factor[exp[i]]); \
}
#define CHANNEL_COEFF(val) \
coeff[i++] = val; \
continue;
#define CHANNEL_DITHER(val) \
if (dither) { \
coeff[i++] = dither_gen () * val; \
continue; \
} else { \
coeff[i++] = 0; \
continue; \
}
static uint16_t lfsr_state = 1;
static inline int16_t dither_gen(void)
{
int16_t state;
state = dither_lut[lfsr_state >> 8] ^ (lfsr_state << 8);
lfsr_state = (uint16_t) state;
return ((state * (int) (LEVEL_3DB * 256)) >> 8);
}
static void coeff_get (float * coeff, uint8_t * exp, int8_t * bap,
int dither, int end)
{
int i;
i = 0;
while (i < end)
GET_COEFF (CHANNEL_COEFF, CHANNEL_DITHER);
}
#define COUPLING_COEFF(val) \
cplcoeff = val; \
break;
#define COUPLING_DITHER(val) \
cplcoeff = val; \
for (ch = 0; ch < nfchans; ch++) \
if (state->chincpl[ch]) { \
if (dithflag[ch]) \
samples[ch][i] = \
state->cplco[ch][bnd] * dither_gen () * cplcoeff; \
else \
samples[ch][i] = 0; \
} \
i++; \
continue;
int ac3_block (ac3_state_t * state)
{
static const uint8_t nfchans_tbl[8] = {2, 1, 2, 3, 3, 4, 4, 5};
static int rematrix_band[4] = {25, 37, 61, 253};
int i, nfchans, chaninfo;
uint8_t cplexpstr, chexpstr[5], lfeexpstr, do_bit_alloc, done_cpl;
uint8_t blksw[5], dithflag[5];
nfchans = nfchans_tbl[state->acmod];
for (i = 0; i < nfchans; i++)
blksw[i] = bitstream_get (1);
for (i = 0; i < nfchans; i++)
dithflag[i] = bitstream_get (1);
chaninfo = !(state->acmod);
do {
if (bitstream_get (1)) // dynrnge
bitstream_get (8); // dynrng
} while (chaninfo--);
if (bitstream_get (1)) { // cplstre
state->cplinu = bitstream_get (1);
if (state->cplinu) {
static int bndtab[16] = {31, 35, 37, 39, 41, 42, 43, 44,
45, 45, 46, 46, 47, 47, 48, 48};
int cplbegf;
int cplendf;
int ncplsubnd;
for (i = 0; i < nfchans; i++)
state->chincpl[i] = bitstream_get (1);
switch (state->acmod) {
case 0: case 1:
return 1;
case 2:
state->phsflginu = bitstream_get (1);
}
cplbegf = bitstream_get (4);
cplendf = bitstream_get (4);
if (cplendf + 3 - cplbegf < 0)
return 1;
state->ncplbnd = ncplsubnd = cplendf + 3 - cplbegf;
state->cplstrtbnd = bndtab[cplbegf];
state->cplstrtmant = cplbegf * 12 + 37;
state->cplendmant = cplendf * 12 + 73;
for (i = 0; i < ncplsubnd - 1; i++) {
state->cplbndstrc[i] = bitstream_get (1);
state->ncplbnd -= state->cplbndstrc[i];
}
state->cplbndstrc[i] = 0; // last value is a sentinel
}
}
if (state->cplinu) {
int j, cplcoe;
cplcoe = 0;
for (i = 0; i < nfchans; i++)
if (state->chincpl[i])
if (bitstream_get (1)) { // cplcoe
int mstrcplco, cplcoexp, cplcomant;
cplcoe = 1;
mstrcplco = 3 * bitstream_get (2);
for (j = 0; j < state->ncplbnd; j++) {
cplcoexp = bitstream_get (4);
cplcomant = bitstream_get (4);
if (cplcoexp == 15)
cplcomant <<= 14;
else
cplcomant = (cplcomant | 0x10) << 13;
state->cplco[i][j] =
cplcomant * scale_factor[cplcoexp + mstrcplco];
}
}
if ((state->acmod == 2) && state->phsflginu && cplcoe)
for (j = 0; j < state->ncplbnd; j++)
if (bitstream_get (1)) // phsflg
state->cplco[1][j] = -state->cplco[1][j];
}
if ((state->acmod == 2) && (bitstream_get (1))) { // rematstr
int end;
end = (state->cplinu) ? state->cplstrtmant : 253;
i = 0;
do
state->rematflg[i] = bitstream_get (1);
while (rematrix_band[i++] < end);
}
cplexpstr = EXP_REUSE;
lfeexpstr = EXP_REUSE;
if (state->cplinu)
cplexpstr = bitstream_get (2);
for (i = 0; i < nfchans; i++)
chexpstr[i] = bitstream_get (2);
if (state->lfeon)
lfeexpstr = bitstream_get (1);
for (i = 0; i < nfchans; i++)
if (chexpstr[i] != EXP_REUSE) {
if (state->cplinu && state->chincpl[i])
state->endmant[i] = state->cplstrtmant;
else {
int chbwcod;
chbwcod = bitstream_get (6);
if (chbwcod > 60)
return 1;
state->endmant[i] = chbwcod * 3 + 73;
}
}
do_bit_alloc = 0;
if (cplexpstr != EXP_REUSE) {
int cplabsexp, ncplgrps;
do_bit_alloc = 1;
ncplgrps = ((state->cplendmant - state->cplstrtmant) /
(3 << (cplexpstr - 1)));
cplabsexp = bitstream_get (4) << 1;
if (parse_exponents (cplexpstr, ncplgrps, cplabsexp,
state->cpl_exp + state->cplstrtmant))
return 1;
}
for (i = 0; i < nfchans; i++)
if (chexpstr[i] != EXP_REUSE) {
int grp_size, nchgrps;
do_bit_alloc = 1;
grp_size = 3 << (chexpstr[i] - 1);
nchgrps = (state->endmant[i] + grp_size - 4) / grp_size;
state->fbw_exp[i][0] = bitstream_get (4);
if (parse_exponents (chexpstr[i], nchgrps, state->fbw_exp[i][0],
state->fbw_exp[i] + 1))
return 1;
bitstream_get (2); // gainrng
}
if (lfeexpstr != EXP_REUSE) {
do_bit_alloc = 1;
state->lfe_exp[0] = bitstream_get (4);
if (parse_exponents (lfeexpstr, 2, state->lfe_exp[0],
state->lfe_exp + 1))
return 1;
}
if (bitstream_get (1)) { // baie
do_bit_alloc = 1;
state->sdcycod = bitstream_get (2);
state->fdcycod = bitstream_get (2);
state->sgaincod = bitstream_get (2);
state->dbpbcod = bitstream_get (2);
state->floorcod = bitstream_get (3);
}
if (bitstream_get (1)) { //snroffste
do_bit_alloc = 1;
state->csnroffst = bitstream_get (6);
if (state->cplinu) {
state->cplba.fsnroffst = bitstream_get (4);
state->cplba.fgaincod = bitstream_get (3);
}
for (i = 0; i < nfchans; i++) {
state->ba[i].fsnroffst = bitstream_get (4);
state->ba[i].fgaincod = bitstream_get (3);
}
if (state->lfeon) {
state->lfeba.fsnroffst = bitstream_get (4);
state->lfeba.fgaincod = bitstream_get (3);
}
}
if ((state->cplinu) && (bitstream_get (1))) { // cplleake
do_bit_alloc = 1;
state->cplfleak = 2304 - (bitstream_get (3) << 8);
state->cplsleak = 2304 - (bitstream_get (3) << 8);
}
if (bitstream_get (1)) { // deltbaie
do_bit_alloc = 1;
if (state->cplinu)
state->cplba.deltbae = bitstream_get (2);
for (i = 0; i < nfchans; i++)
state->ba[i].deltbae = bitstream_get (2);
if (state->cplinu && (state->cplba.deltbae == DELTA_BIT_NEW) &&
parse_deltba (state->cplba.deltba))
return 1;
for (i = 0; i < nfchans; i++)
if ((state->ba[i].deltbae == DELTA_BIT_NEW) &&
parse_deltba (state->ba[i].deltba))
return 1;
}
if (do_bit_alloc) {
if (zero_snr_offsets (nfchans, state)) {
memset (state->cpl_bap, 0, sizeof (state->cpl_bap));
memset (state->fbw_bap, 0, sizeof (state->fbw_bap));
memset (state->lfe_bap, 0, sizeof (state->lfe_bap));
} else {
if (state->cplinu)
bit_allocate (state, &state->cplba, state->cplstrtbnd,
state->cplstrtmant, state->cplendmant,
state->cplfleak, state->cplsleak,
state->cpl_exp, state->cpl_bap);
for (i = 0; i < nfchans; i++)
bit_allocate (state, state->ba + i, 0, 0, state->endmant[i],
0, 0, state->fbw_exp[i], state->fbw_bap[i]);
if (state->lfeon) {
state->lfeba.deltbae = DELTA_BIT_NONE;
bit_allocate (state, &state->lfeba, 0, 0, 7, 0, 0,
state->lfe_exp, state->lfe_bap);
}
}
}
if (bitstream_get (1)) { // skiple
i = bitstream_get (9); // skipl
while (i--)
bitstream_get (8);
}
q_1_pointer = q_2_pointer = q_4_pointer = -1;
done_cpl = 0;
for (i = 0; i < nfchans; i++) {
int j;
coeff_get (samples[i], state->fbw_exp[i], state->fbw_bap[i],
dithflag[i], state->endmant[i]);
if (state->cplinu && state->chincpl[i]) {
if (!done_cpl) {
int i, i_end, bnd, sub_bnd, ch;
float cplcoeff;
done_cpl = 1;
#define bap state->cpl_bap
#define exp state->cpl_exp
sub_bnd = bnd = 0;
i = state->cplstrtmant;
while (i < state->cplendmant) {
i_end = i + 12;
while (state->cplbndstrc[sub_bnd++])
i_end += 12;
while (i < i_end) {
GET_COEFF (COUPLING_COEFF, COUPLING_DITHER);
for (ch = 0; ch < nfchans; ch++)
if (state->chincpl[ch])
samples[ch][i] =
state->cplco[ch][bnd] * cplcoeff;
i++;
}
bnd++;
}
#undef bap
#undef exp
}
j = state->cplendmant;
} else
j = state->endmant[i];
for (; j < 256; j++)
samples[i][j] = 0;
}
if (state->acmod == 2) {
int j, end, band;
end = ((state->endmant[0] < state->endmant[1]) ?
state->endmant[0] : state->endmant[1]);
i = 0;
j = 13;
do {
if (!state->rematflg[i]) {
j = rematrix_band[i++];
continue;
}
band = rematrix_band[i++];
if (band > end)
band = end;
do {
float tmp0, tmp1;
tmp0 = samples[0][j];
tmp1 = samples[1][j];
samples[0][j] = tmp0 + tmp1;
samples[1][j] = tmp0 - tmp1;
} while (++j < band);
} while (j < end);
}
if (state->lfeon) {
coeff_get (samples[5], state->lfe_exp, state->lfe_bap, 0, 7);
#if 0
for (i = 7; i < 256; i++)
samples[5][i] = 0;
#endif
}
for (i = 0; i < nfchans; i++)
if (blksw[i])
imdct_256 (samples[i], delay[i]);
else
imdct_512 (samples[i], delay[i]);
#if 0
if (state->lfeon)
imdct_512 (samples[5], delay[5]);
#endif
downmix (*samples, state->acmod, state->output, state->level, state->bias,
state->clev, state->slev);
return 0;
}

250
libavcodec/libac3/tables.h Normal file
View File

@ -0,0 +1,250 @@
/*
* parse.c
*
* Copyright (C) Aaron Holtzman - May 1999
*
* This file is part of ac3dec, a free Dolby AC-3 stream decoder.
*
* ac3dec 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, or (at your option)
* any later version.
*
* ac3dec 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 GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
*/
static int8_t exp_1[128] = {
-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,
-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,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
25,25,25
};
static int8_t exp_2[128] = {
-2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
-2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
-2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
-2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
-2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
25,25,25
};
static int8_t exp_3[128] = {
-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,
-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,
-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,
-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,
-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,
25,25,25
};
#define Q0 ((-2 << 15) / 3.0)
#define Q1 (0)
#define Q2 ((2 << 15) / 3.0)
static const float q_1_0[ 32 ] = {
Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,
Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,
Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,
0,0,0,0,0
};
static const float q_1_1[ 32 ] = {
Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2,
Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2,
Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2,
0,0,0,0,0
};
static const float q_1_2[ 32 ] = {
Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2,
Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2,
Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2,
0,0,0,0,0
};
#undef Q0
#undef Q1
#undef Q2
#define Q0 ((-4 << 15) / 5.0)
#define Q1 ((-2 << 15) / 5.0)
#define Q2 (0)
#define Q3 ((2 << 15) / 5.0)
#define Q4 ((4 << 15) / 5.0)
static const float q_2_0[ 128 ] = {
Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,
Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,
Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,
Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,
Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,
0,0,0
};
static const float q_2_1[ 128 ] = {
Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4,
Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4,
Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4,
Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4,
Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4,
0,0,0
};
static const float q_2_2[ 128 ] = {
Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,
Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,
Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,
Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,
Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,
0,0,0
};
#undef Q0
#undef Q1
#undef Q2
#undef Q3
#undef Q4
static const float q_3[8] = {
(-6 << 15)/7.0, (-4 << 15)/7.0, (-2 << 15)/7.0, 0,
( 2 << 15)/7.0, ( 4 << 15)/7.0, ( 6 << 15)/7.0, 0
};
#define Q0 ((-10 << 15) / 11.0)
#define Q1 ((-8 << 15) / 11.0)
#define Q2 ((-6 << 15) / 11.0)
#define Q3 ((-4 << 15) / 11.0)
#define Q4 ((-2 << 15) / 11.0)
#define Q5 (0)
#define Q6 ((2 << 15) / 11.0)
#define Q7 ((4 << 15) / 11.0)
#define Q8 ((6 << 15) / 11.0)
#define Q9 ((8 << 15) / 11.0)
#define QA ((10 << 15) / 11.0)
static const float q_4_0[ 128 ] = {
Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0,
Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1,
Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2,
Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3,
Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4,
Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5,
Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6,
Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7,
Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8,
Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9,
QA, QA, QA, QA, QA, QA, QA, QA, QA, QA, QA,
0, 0, 0, 0, 0, 0, 0
};
static const float q_4_1[ 128 ] = {
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
0, 0, 0, 0, 0, 0, 0
};
#undef Q0
#undef Q1
#undef Q2
#undef Q3
#undef Q4
#undef Q5
#undef Q6
#undef Q7
#undef Q8
#undef Q9
#undef QA
static const float q_5[16] = {
(-14 << 15)/15.0,(-12 << 15)/15.0,(-10 << 15)/15.0,
( -8 << 15)/15.0,( -6 << 15)/15.0,( -4 << 15)/15.0,
( -2 << 15)/15.0, 0 ,( 2 << 15)/15.0,
( 4 << 15)/15.0,( 6 << 15)/15.0,( 8 << 15)/15.0,
( 10 << 15)/15.0,( 12 << 15)/15.0,( 14 << 15)/15.0,
0
};
static const uint32_t u32_scale_factors[25] =
{
0x38000000, //2 ^ -(0 + 15)
0x37800000, //2 ^ -(1 + 15)
0x37000000, //2 ^ -(2 + 15)
0x36800000, //2 ^ -(3 + 15)
0x36000000, //2 ^ -(4 + 15)
0x35800000, //2 ^ -(5 + 15)
0x35000000, //2 ^ -(6 + 15)
0x34800000, //2 ^ -(7 + 15)
0x34000000, //2 ^ -(8 + 15)
0x33800000, //2 ^ -(9 + 15)
0x33000000, //2 ^ -(10 + 15)
0x32800000, //2 ^ -(11 + 15)
0x32000000, //2 ^ -(12 + 15)
0x31800000, //2 ^ -(13 + 15)
0x31000000, //2 ^ -(14 + 15)
0x30800000, //2 ^ -(15 + 15)
0x30000000, //2 ^ -(16 + 15)
0x2f800000, //2 ^ -(17 + 15)
0x2f000000, //2 ^ -(18 + 15)
0x2e800000, //2 ^ -(19 + 15)
0x2e000000, //2 ^ -(20 + 15)
0x2d800000, //2 ^ -(21 + 15)
0x2d000000, //2 ^ -(22 + 15)
0x2c800000, //2 ^ -(23 + 15)
0x2c000000 //2 ^ -(24 + 15)
};
static float * scale_factor = (float *) u32_scale_factors;
static const uint16_t dither_lut[256] = {
0x0000, 0xa011, 0xe033, 0x4022, 0x6077, 0xc066, 0x8044, 0x2055,
0xc0ee, 0x60ff, 0x20dd, 0x80cc, 0xa099, 0x0088, 0x40aa, 0xe0bb,
0x21cd, 0x81dc, 0xc1fe, 0x61ef, 0x41ba, 0xe1ab, 0xa189, 0x0198,
0xe123, 0x4132, 0x0110, 0xa101, 0x8154, 0x2145, 0x6167, 0xc176,
0x439a, 0xe38b, 0xa3a9, 0x03b8, 0x23ed, 0x83fc, 0xc3de, 0x63cf,
0x8374, 0x2365, 0x6347, 0xc356, 0xe303, 0x4312, 0x0330, 0xa321,
0x6257, 0xc246, 0x8264, 0x2275, 0x0220, 0xa231, 0xe213, 0x4202,
0xa2b9, 0x02a8, 0x428a, 0xe29b, 0xc2ce, 0x62df, 0x22fd, 0x82ec,
0x8734, 0x2725, 0x6707, 0xc716, 0xe743, 0x4752, 0x0770, 0xa761,
0x47da, 0xe7cb, 0xa7e9, 0x07f8, 0x27ad, 0x87bc, 0xc79e, 0x678f,
0xa6f9, 0x06e8, 0x46ca, 0xe6db, 0xc68e, 0x669f, 0x26bd, 0x86ac,
0x6617, 0xc606, 0x8624, 0x2635, 0x0660, 0xa671, 0xe653, 0x4642,
0xc4ae, 0x64bf, 0x249d, 0x848c, 0xa4d9, 0x04c8, 0x44ea, 0xe4fb,
0x0440, 0xa451, 0xe473, 0x4462, 0x6437, 0xc426, 0x8404, 0x2415,
0xe563, 0x4572, 0x0550, 0xa541, 0x8514, 0x2505, 0x6527, 0xc536,
0x258d, 0x859c, 0xc5be, 0x65af, 0x45fa, 0xe5eb, 0xa5c9, 0x05d8,
0xae79, 0x0e68, 0x4e4a, 0xee5b, 0xce0e, 0x6e1f, 0x2e3d, 0x8e2c,
0x6e97, 0xce86, 0x8ea4, 0x2eb5, 0x0ee0, 0xaef1, 0xeed3, 0x4ec2,
0x8fb4, 0x2fa5, 0x6f87, 0xcf96, 0xefc3, 0x4fd2, 0x0ff0, 0xafe1,
0x4f5a, 0xef4b, 0xaf69, 0x0f78, 0x2f2d, 0x8f3c, 0xcf1e, 0x6f0f,
0xede3, 0x4df2, 0x0dd0, 0xadc1, 0x8d94, 0x2d85, 0x6da7, 0xcdb6,
0x2d0d, 0x8d1c, 0xcd3e, 0x6d2f, 0x4d7a, 0xed6b, 0xad49, 0x0d58,
0xcc2e, 0x6c3f, 0x2c1d, 0x8c0c, 0xac59, 0x0c48, 0x4c6a, 0xec7b,
0x0cc0, 0xacd1, 0xecf3, 0x4ce2, 0x6cb7, 0xcca6, 0x8c84, 0x2c95,
0x294d, 0x895c, 0xc97e, 0x696f, 0x493a, 0xe92b, 0xa909, 0x0918,
0xe9a3, 0x49b2, 0x0990, 0xa981, 0x89d4, 0x29c5, 0x69e7, 0xc9f6,
0x0880, 0xa891, 0xe8b3, 0x48a2, 0x68f7, 0xc8e6, 0x88c4, 0x28d5,
0xc86e, 0x687f, 0x285d, 0x884c, 0xa819, 0x0808, 0x482a, 0xe83b,
0x6ad7, 0xcac6, 0x8ae4, 0x2af5, 0x0aa0, 0xaab1, 0xea93, 0x4a82,
0xaa39, 0x0a28, 0x4a0a, 0xea1b, 0xca4e, 0x6a5f, 0x2a7d, 0x8a6c,
0x4b1a, 0xeb0b, 0xab29, 0x0b38, 0x2b6d, 0x8b7c, 0xcb5e, 0x6b4f,
0x8bf4, 0x2be5, 0x6bc7, 0xcbd6, 0xeb83, 0x4b92, 0x0bb0, 0xaba1
};

417
libavcodec/mjpegenc.c Normal file
View File

@ -0,0 +1,417 @@
/*
* 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 "dsputil.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->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, s->chroma_intra_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);
}
}

517
libavcodec/motion_est.c Normal file
View File

@ -0,0 +1,517 @@
/*
* Motion estimation
* Copyright (c) 2000,2001 Gerard Lantau.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include "avcodec.h"
#include "dsputil.h"
#include "mpegvideo.h"
static void halfpel_motion_search(MpegEncContext * s,
int *mx_ptr, int *my_ptr, int dmin,
int xmin, int ymin, int xmax, int ymax);
/* config it to test motion vector encoding (send random vectors) */
//#define CONFIG_TEST_MV_ENCODE
static int pix_sum(UINT8 * pix, int line_size)
{
int s, i, j;
s = 0;
for (i = 0; i < 16; i++) {
for (j = 0; j < 16; j += 8) {
s += pix[0];
s += pix[1];
s += pix[2];
s += pix[3];
s += pix[4];
s += pix[5];
s += pix[6];
s += pix[7];
pix += 8;
}
pix += line_size - 16;
}
return s;
}
static int pix_norm1(UINT8 * pix, int line_size)
{
int s, i, j;
UINT32 *sq = squareTbl + 256;
s = 0;
for (i = 0; i < 16; i++) {
for (j = 0; j < 16; j += 8) {
s += sq[pix[0]];
s += sq[pix[1]];
s += sq[pix[2]];
s += sq[pix[3]];
s += sq[pix[4]];
s += sq[pix[5]];
s += sq[pix[6]];
s += sq[pix[7]];
pix += 8;
}
pix += line_size - 16;
}
return s;
}
static int pix_norm(UINT8 * pix1, UINT8 * pix2, int line_size)
{
int s, i, j;
UINT32 *sq = squareTbl + 256;
s = 0;
for (i = 0; i < 16; i++) {
for (j = 0; j < 16; j += 8) {
s += sq[pix1[0] - pix2[0]];
s += sq[pix1[1] - pix2[1]];
s += sq[pix1[2] - pix2[2]];
s += sq[pix1[3] - pix2[3]];
s += sq[pix1[4] - pix2[4]];
s += sq[pix1[5] - pix2[5]];
s += sq[pix1[6] - pix2[6]];
s += sq[pix1[7] - pix2[7]];
pix1 += 8;
pix2 += 8;
}
pix1 += line_size - 16;
pix2 += line_size - 16;
}
return s;
}
static void no_motion_search(MpegEncContext * s,
int *mx_ptr, int *my_ptr)
{
*mx_ptr = 16 * s->mb_x;
*my_ptr = 16 * s->mb_y;
}
static int full_motion_search(MpegEncContext * s,
int *mx_ptr, int *my_ptr, int range,
int xmin, int ymin, int xmax, int ymax)
{
int x1, y1, x2, y2, xx, yy, x, y;
int mx, my, dmin, d;
UINT8 *pix;
xx = 16 * s->mb_x;
yy = 16 * s->mb_y;
x1 = xx - range + 1; /* we loose one pixel to avoid boundary pb with half pixel pred */
if (x1 < xmin)
x1 = xmin;
x2 = xx + range - 1;
if (x2 > xmax)
x2 = xmax;
y1 = yy - range + 1;
if (y1 < ymin)
y1 = ymin;
y2 = yy + range - 1;
if (y2 > ymax)
y2 = ymax;
pix = s->new_picture[0] + (yy * s->linesize) + xx;
dmin = 0x7fffffff;
mx = 0;
my = 0;
for (y = y1; y <= y2; y++) {
for (x = x1; x <= x2; x++) {
d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x,
s->linesize, 16);
if (d < dmin ||
(d == dmin &&
(abs(x - xx) + abs(y - yy)) <
(abs(mx - xx) + abs(my - yy)))) {
dmin = d;
mx = x;
my = y;
}
}
}
*mx_ptr = mx;
*my_ptr = my;
#if 0
if (*mx_ptr < -(2 * range) || *mx_ptr >= (2 * range) ||
*my_ptr < -(2 * range) || *my_ptr >= (2 * range)) {
fprintf(stderr, "error %d %d\n", *mx_ptr, *my_ptr);
}
#endif
return dmin;
}
static int log_motion_search(MpegEncContext * s,
int *mx_ptr, int *my_ptr, int range,
int xmin, int ymin, int xmax, int ymax)
{
int x1, y1, x2, y2, xx, yy, x, y;
int mx, my, dmin, d;
UINT8 *pix;
xx = s->mb_x << 4;
yy = s->mb_y << 4;
/* Left limit */
x1 = xx - range;
if (x1 < xmin)
x1 = xmin;
/* Right limit */
x2 = xx + range;
if (x2 > xmax)
x2 = xmax;
/* Upper limit */
y1 = yy - range;
if (y1 < ymin)
y1 = ymin;
/* Lower limit */
y2 = yy + range;
if (y2 > ymax)
y2 = ymax;
pix = s->new_picture[0] + (yy * s->linesize) + xx;
dmin = 0x7fffffff;
mx = 0;
my = 0;
do {
for (y = y1; y <= y2; y += range) {
for (x = x1; x <= x2; x += range) {
d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize, 16);
if (d < dmin || (d == dmin && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
dmin = d;
mx = x;
my = y;
}
}
}
range = range >> 1;
x1 = mx - range;
if (x1 < xmin)
x1 = xmin;
x2 = mx + range;
if (x2 > xmax)
x2 = xmax;
y1 = my - range;
if (y1 < ymin)
y1 = ymin;
y2 = my + range;
if (y2 > ymax)
y2 = ymax;
} while (range >= 1);
#ifdef DEBUG
fprintf(stderr, "log - MX: %d\tMY: %d\n", mx, my);
#endif
*mx_ptr = mx;
*my_ptr = my;
return dmin;
}
static int phods_motion_search(MpegEncContext * s,
int *mx_ptr, int *my_ptr, int range,
int xmin, int ymin, int xmax, int ymax)
{
int x1, y1, x2, y2, xx, yy, x, y, lastx, d;
int mx, my, dminx, dminy;
UINT8 *pix;
xx = s->mb_x << 4;
yy = s->mb_y << 4;
/* Left limit */
x1 = xx - range;
if (x1 < xmin)
x1 = xmin;
/* Right limit */
x2 = xx + range;
if (x2 > xmax)
x2 = xmax;
/* Upper limit */
y1 = yy - range;
if (y1 < ymin)
y1 = ymin;
/* Lower limit */
y2 = yy + range;
if (y2 > ymax)
y2 = ymax;
pix = s->new_picture[0] + (yy * s->linesize) + xx;
mx = 0;
my = 0;
x = xx;
y = yy;
do {
dminx = 0x7fffffff;
dminy = 0x7fffffff;
lastx = x;
for (x = x1; x <= x2; x += range) {
d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize, 16);
if (d < dminx || (d == dminx && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
dminx = d;
mx = x;
}
}
x = lastx;
for (y = y1; y <= y2; y += range) {
d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize, 16);
if (d < dminy || (d == dminy && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
dminy = d;
my = y;
}
}
range = range >> 1;
x = mx;
y = my;
x1 = mx - range;
if (x1 < xmin)
x1 = xmin;
x2 = mx + range;
if (x2 > xmax)
x2 = xmax;
y1 = my - range;
if (y1 < ymin)
y1 = ymin;
y2 = my + range;
if (y2 > ymax)
y2 = ymax;
} while (range >= 1);
#ifdef DEBUG
fprintf(stderr, "phods - MX: %d\tMY: %d\n", mx, my);
#endif
/* half pixel search */
*mx_ptr = mx;
*my_ptr = my;
return dminy;
}
/* The idea would be to make half pel ME after Inter/Intra decision to
save time. */
static void halfpel_motion_search(MpegEncContext * s,
int *mx_ptr, int *my_ptr, int dmin,
int xmin, int ymin, int xmax, int ymax)
{
int mx, my, mx1, my1, d, xx, yy, dminh;
UINT8 *pix;
mx = *mx_ptr << 1;
my = *my_ptr << 1;
xx = 16 * s->mb_x;
yy = 16 * s->mb_y;
dminh = dmin;
/* Half pixel search */
mx1 = mx;
my1 = my;
pix = s->new_picture[0] + (yy * s->linesize) + xx;
if ((mx > (xmin << 1)) && mx < (xmax << 1) &&
(my > (ymin << 1)) && my < (ymax << 1)) {
int dx, dy, px, py;
UINT8 *ptr;
for (dy = -1; dy <= 1; dy++) {
for (dx = -1; dx <= 1; dx++) {
if (dx != 0 || dy != 0) {
px = mx1 + dx;
py = my1 + dy;
ptr = s->last_picture[0] + ((py >> 1) * s->linesize) + (px >> 1);
switch (((py & 1) << 1) | (px & 1)) {
default:
case 0:
d = pix_abs16x16(pix, ptr, s->linesize, 16);
break;
case 1:
d = pix_abs16x16_x2(pix, ptr, s->linesize, 16);
break;
case 2:
d = pix_abs16x16_y2(pix, ptr, s->linesize, 16);
break;
case 3:
d = pix_abs16x16_xy2(pix, ptr, s->linesize, 16);
break;
}
if (d < dminh) {
dminh = d;
mx = px;
my = py;
}
}
}
}
}
*mx_ptr = mx - (xx << 1);
*my_ptr = my - (yy << 1);
//fprintf(stderr,"half - MX: %d\tMY: %d\n",*mx_ptr ,*my_ptr);
}
#ifndef CONFIG_TEST_MV_ENCODE
int estimate_motion(MpegEncContext * s,
int mb_x, int mb_y,
int *mx_ptr, int *my_ptr)
{
UINT8 *pix, *ppix;
int sum, varc, vard, mx, my, range, dmin, xx, yy;
int xmin, ymin, xmax, ymax;
range = 8 * (1 << (s->f_code - 1));
/* XXX: temporary kludge to avoid overflow for msmpeg4 */
if (s->out_format == FMT_H263 && !s->h263_msmpeg4)
range = range * 2;
if (s->unrestricted_mv) {
xmin = -16;
ymin = -16;
xmax = s->width;
ymax = s->height;
} else {
xmin = 0;
ymin = 0;
xmax = s->width - 16;
ymax = s->height - 16;
}
switch(s->full_search) {
case ME_ZERO:
default:
no_motion_search(s, &mx, &my);
dmin = 0;
break;
case ME_FULL:
dmin = full_motion_search(s, &mx, &my, range, xmin, ymin, xmax, ymax);
break;
case ME_LOG:
dmin = log_motion_search(s, &mx, &my, range / 2, xmin, ymin, xmax, ymax);
break;
case ME_PHODS:
dmin = phods_motion_search(s, &mx, &my, range / 2, xmin, ymin, xmax, ymax);
break;
}
#ifdef CONFIG_MMX
if (mm_flags & MM_MMX)
emms();
#endif
/* intra / predictive decision */
xx = mb_x * 16;
yy = mb_y * 16;
pix = s->new_picture[0] + (yy * s->linesize) + xx;
/* At this point (mx,my) are full-pell and the absolute displacement */
ppix = s->last_picture[0] + (my * s->linesize) + mx;
sum = pix_sum(pix, s->linesize);
varc = pix_norm1(pix, s->linesize);
vard = pix_norm(pix, ppix, s->linesize);
vard = vard >> 8;
sum = sum >> 8;
varc = (varc >> 8) - (sum * sum);
#if 0
printf("varc=%d (sum=%d) vard=%d mx=%d my=%d\n",
varc, sum, vard, mx - xx, my - yy);
#endif
if (vard <= 64 || vard < varc) {
if (s->full_search != ME_ZERO) {
halfpel_motion_search(s, &mx, &my, dmin, xmin, ymin, xmax, ymax);
} else {
mx -= 16 * s->mb_x;
my -= 16 * s->mb_y;
}
*mx_ptr = mx;
*my_ptr = my;
return 0;
} else {
*mx_ptr = 0;
*my_ptr = 0;
return 1;
}
}
#else
/* test version which generates valid random vectors */
int estimate_motion(MpegEncContext * s,
int mb_x, int mb_y,
int *mx_ptr, int *my_ptr)
{
int xx, yy, x1, y1, x2, y2, range;
if ((random() % 10) >= 5) {
range = 8 * (1 << (s->f_code - 1));
if (s->out_format == FMT_H263 && !s->h263_msmpeg4)
range = range * 2;
xx = 16 * s->mb_x;
yy = 16 * s->mb_y;
x1 = xx - range;
if (x1 < 0)
x1 = 0;
x2 = xx + range - 1;
if (x2 > (s->width - 16))
x2 = s->width - 16;
y1 = yy - range;
if (y1 < 0)
y1 = 0;
y2 = yy + range - 1;
if (y2 > (s->height - 16))
y2 = s->height - 16;
*mx_ptr = (random() % (2 * (x2 - x1 + 1))) + 2 * (x1 - xx);
*my_ptr = (random() % (2 * (y2 - y1 + 1))) + 2 * (y1 - yy);
return 0;
} else {
*mx_ptr = 0;
*my_ptr = 0;
return 1;
}
}
#endif

1530
libavcodec/mpeg12.c Normal file

File diff suppressed because it is too large Load Diff

362
libavcodec/mpeg12data.h Normal file
View File

@ -0,0 +1,362 @@
/*
* MPEG1/2 tables
*/
const UINT8 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
};
const UINT8 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,
};
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 UINT16 vlc_dc_lum_code[12] = {
0x4, 0x0, 0x1, 0x5, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe, 0x1ff,
};
const unsigned char vlc_dc_lum_bits[12] = {
3, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9, 9,
};
const UINT16 vlc_dc_chroma_code[12] = {
0x0, 0x1, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe, 0x3fe, 0x3ff,
};
const unsigned char vlc_dc_chroma_bits[12] = {
2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10,
};
static const UINT16 mpeg1_vlc[113][2] = {
{ 0x3, 2 }, { 0x4, 4 }, { 0x5, 5 }, { 0x6, 7 },
{ 0x26, 8 }, { 0x21, 8 }, { 0xa, 10 }, { 0x1d, 12 },
{ 0x18, 12 }, { 0x13, 12 }, { 0x10, 12 }, { 0x1a, 13 },
{ 0x19, 13 }, { 0x18, 13 }, { 0x17, 13 }, { 0x1f, 14 },
{ 0x1e, 14 }, { 0x1d, 14 }, { 0x1c, 14 }, { 0x1b, 14 },
{ 0x1a, 14 }, { 0x19, 14 }, { 0x18, 14 }, { 0x17, 14 },
{ 0x16, 14 }, { 0x15, 14 }, { 0x14, 14 }, { 0x13, 14 },
{ 0x12, 14 }, { 0x11, 14 }, { 0x10, 14 }, { 0x18, 15 },
{ 0x17, 15 }, { 0x16, 15 }, { 0x15, 15 }, { 0x14, 15 },
{ 0x13, 15 }, { 0x12, 15 }, { 0x11, 15 }, { 0x10, 15 },
{ 0x3, 3 }, { 0x6, 6 }, { 0x25, 8 }, { 0xc, 10 },
{ 0x1b, 12 }, { 0x16, 13 }, { 0x15, 13 }, { 0x1f, 15 },
{ 0x1e, 15 }, { 0x1d, 15 }, { 0x1c, 15 }, { 0x1b, 15 },
{ 0x1a, 15 }, { 0x19, 15 }, { 0x13, 16 }, { 0x12, 16 },
{ 0x11, 16 }, { 0x10, 16 }, { 0x5, 4 }, { 0x4, 7 },
{ 0xb, 10 }, { 0x14, 12 }, { 0x14, 13 }, { 0x7, 5 },
{ 0x24, 8 }, { 0x1c, 12 }, { 0x13, 13 }, { 0x6, 5 },
{ 0xf, 10 }, { 0x12, 12 }, { 0x7, 6 }, { 0x9, 10 },
{ 0x12, 13 }, { 0x5, 6 }, { 0x1e, 12 }, { 0x14, 16 },
{ 0x4, 6 }, { 0x15, 12 }, { 0x7, 7 }, { 0x11, 12 },
{ 0x5, 7 }, { 0x11, 13 }, { 0x27, 8 }, { 0x10, 13 },
{ 0x23, 8 }, { 0x1a, 16 }, { 0x22, 8 }, { 0x19, 16 },
{ 0x20, 8 }, { 0x18, 16 }, { 0xe, 10 }, { 0x17, 16 },
{ 0xd, 10 }, { 0x16, 16 }, { 0x8, 10 }, { 0x15, 16 },
{ 0x1f, 12 }, { 0x1a, 12 }, { 0x19, 12 }, { 0x17, 12 },
{ 0x16, 12 }, { 0x1f, 13 }, { 0x1e, 13 }, { 0x1d, 13 },
{ 0x1c, 13 }, { 0x1b, 13 }, { 0x1f, 16 }, { 0x1e, 16 },
{ 0x1d, 16 }, { 0x1c, 16 }, { 0x1b, 16 },
{ 0x1, 6 }, /* escape */
{ 0x2, 2 }, /* EOB */
};
static const UINT16 mpeg2_vlc[113][2] = {
{0x02, 2}, {0x06, 3}, {0x07, 4}, {0x1c, 5},
{0x1d, 5}, {0x05, 6}, {0x04, 6}, {0x7b, 7},
{0x7c, 7}, {0x23, 8}, {0x22, 8}, {0xfa, 8},
{0xfb, 8}, {0xfe, 8}, {0xff, 8}, {0x1f,14},
{0x1e,14}, {0x1d,14}, {0x1c,14}, {0x1b,14},
{0x1a,14}, {0x19,14}, {0x18,14}, {0x17,14},
{0x16,14}, {0x15,14}, {0x14,14}, {0x13,14},
{0x12,14}, {0x11,14}, {0x10,14}, {0x18,15},
{0x17,15}, {0x16,15}, {0x15,15}, {0x14,15},
{0x13,15}, {0x12,15}, {0x11,15}, {0x10,15},
{0x02, 3}, {0x06, 5}, {0x79, 7}, {0x27, 8},
{0x20, 8}, {0x16,13}, {0x15,13}, {0x1f,15},
{0x1e,15}, {0x1d,15}, {0x1c,15}, {0x1b,15},
{0x1a,15}, {0x19,15}, {0x13,16}, {0x12,16},
{0x11,16}, {0x10,16}, {0x05, 5}, {0x07, 7},
{0xfc, 8}, {0x0c,10}, {0x14,13}, {0x07, 5},
{0x26, 8}, {0x1c,12}, {0x13,13}, {0x06, 6},
{0xfd, 8}, {0x12,12}, {0x07, 6}, {0x04, 9},
{0x12,13}, {0x06, 7}, {0x1e,12}, {0x14,16},
{0x04, 7}, {0x15,12}, {0x05, 7}, {0x11,12},
{0x78, 7}, {0x11,13}, {0x7a, 7}, {0x10,13},
{0x21, 8}, {0x1a,16}, {0x25, 8}, {0x19,16},
{0x24, 8}, {0x18,16}, {0x05, 9}, {0x17,16},
{0x07, 9}, {0x16,16}, {0x0d,10}, {0x15,16},
{0x1f,12}, {0x1a,12}, {0x19,12}, {0x17,12},
{0x16,12}, {0x1f,13}, {0x1e,13}, {0x1d,13},
{0x1c,13}, {0x1b,13}, {0x1f,16}, {0x1e,16},
{0x1d,16}, {0x1c,16}, {0x1b,16},
{0x01,6}, /* escape */
{0x06,4}, /* EOB */
};
static const UINT8 mpeg1_level[111] = {
1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40,
1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 1, 2, 3, 4, 5, 1,
2, 3, 4, 1, 2, 3, 1, 2,
3, 1, 2, 3, 1, 2, 1, 2,
1, 2, 1, 2, 1, 2, 1, 2,
1, 2, 1, 2, 1, 2, 1, 2,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1,
};
static const UINT8 mpeg1_run[111] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 2, 2, 2, 2, 2, 3,
3, 3, 3, 4, 4, 4, 5, 5,
5, 6, 6, 6, 7, 7, 8, 8,
9, 9, 10, 10, 11, 11, 12, 12,
13, 13, 14, 14, 15, 15, 16, 16,
17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31,
};
static RLTable rl_mpeg1 = {
111,
111,
mpeg1_vlc,
mpeg1_run,
mpeg1_level,
};
static RLTable rl_mpeg2 = {
111,
111,
mpeg2_vlc,
mpeg1_run,
mpeg1_level,
};
static const UINT8 mbAddrIncrTable[35][2] = {
{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},
{0x8, 11}, /* escape */
{0xf, 11}, /* stuffing */
};
static const UINT8 mbPatTable[63][2] = {
{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},
{0x8, 5},
{0xc, 6}
};
#define MB_INTRA 0x01
#define MB_PAT 0x02
#define MB_BACK 0x04
#define MB_FOR 0x08
#define MB_QUANT 0x10
static const UINT8 table_mb_ptype[32][2] = {
[ MB_FOR|MB_PAT ] { 1, 1 },
[ MB_PAT ] { 1, 2 },
[ MB_FOR ] { 1, 3 },
[ MB_INTRA ] { 3, 5 },
[ MB_QUANT|MB_FOR|MB_PAT ] { 2, 5 },
[ MB_QUANT|MB_PAT ] { 1, 5 },
[ MB_QUANT|MB_INTRA ] { 1, 6 },
};
static const UINT8 table_mb_btype[32][2] = {
[ MB_FOR|MB_BACK ] { 2, 2 },
[ MB_FOR|MB_BACK|MB_PAT ] { 3, 2 },
[ MB_BACK ] { 2, 3 },
[ MB_BACK|MB_PAT ] { 3, 3 },
[ MB_FOR ] { 2, 4 },
[ MB_FOR|MB_PAT ] { 3, 4 },
[ MB_INTRA ] { 3, 5 },
[ MB_QUANT|MB_FOR|MB_BACK|MB_PAT ] { 2, 5 },
[ MB_QUANT|MB_FOR|MB_PAT ] { 3, 6 },
[ MB_QUANT|MB_BACK|MB_PAT ] { 2, 6 },
[ MB_QUANT|MB_INTRA ] { 1, 6 },
};
static const UINT8 mbMotionVectorTable[17][2] = {
{ 0x1, 1 },
{ 0x1, 2 },
{ 0x1, 3 },
{ 0x1, 4 },
{ 0x3, 6 },
{ 0x5, 7 },
{ 0x4, 7 },
{ 0x3, 7 },
{ 0xb, 9 },
{ 0xa, 9 },
{ 0x9, 9 },
{ 0x11, 10 },
{ 0x10, 10 },
{ 0xf, 10 },
{ 0xe, 10 },
{ 0xd, 10 },
{ 0xc, 10 },
};
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 const int frame_rate_tab[9] = {
0,
(int)(23.976 * FRAME_RATE_BASE),
(int)(24 * FRAME_RATE_BASE),
(int)(25 * FRAME_RATE_BASE),
(int)(29.97 * FRAME_RATE_BASE),
(int)(30 * FRAME_RATE_BASE),
(int)(50 * FRAME_RATE_BASE),
(int)(59.94 * FRAME_RATE_BASE),
(int)(60 * FRAME_RATE_BASE),
};
static const UINT8 non_linear_qscale[32] = {
0, 1, 2, 3, 4, 5, 6, 7,
8,10,12,14,16,18,20,22,
24,28,32,36,40,44,48,52,
56,64,72,80,88,96,104,112,
};

106
libavcodec/mpeg4data.h Normal file
View File

@ -0,0 +1,106 @@
/* dc encoding for mpeg4 */
static const UINT8 DCtab_lum[13][2] =
{
{3,3}, {3,2}, {2,2}, {2,3}, {1,3}, {1,4}, {1,5}, {1,6}, {1,7},
{1,8}, {1,9}, {1,10}, {1,11},
};
static const UINT8 DCtab_chrom[13][2] =
{
{3,2}, {2,2}, {1,2}, {1,3}, {1,4}, {1,5}, {1,6}, {1,7}, {1,8},
{1,9}, {1,10}, {1,11}, {1,12},
};
const UINT16 intra_vlc[103][2] = {
{ 0x2, 2 },
{ 0x6, 3 },{ 0xf, 4 },{ 0xd, 5 },{ 0xc, 5 },
{ 0x15, 6 },{ 0x13, 6 },{ 0x12, 6 },{ 0x17, 7 },
{ 0x1f, 8 },{ 0x1e, 8 },{ 0x1d, 8 },{ 0x25, 9 },
{ 0x24, 9 },{ 0x23, 9 },{ 0x21, 9 },{ 0x21, 10 },
{ 0x20, 10 },{ 0xf, 10 },{ 0xe, 10 },{ 0x7, 11 },
{ 0x6, 11 },{ 0x20, 11 },{ 0x21, 11 },{ 0x50, 12 },
{ 0x51, 12 },{ 0x52, 12 },{ 0xe, 4 },{ 0x14, 6 },
{ 0x16, 7 },{ 0x1c, 8 },{ 0x20, 9 },{ 0x1f, 9 },
{ 0xd, 10 },{ 0x22, 11 },{ 0x53, 12 },{ 0x55, 12 },
{ 0xb, 5 },{ 0x15, 7 },{ 0x1e, 9 },{ 0xc, 10 },
{ 0x56, 12 },{ 0x11, 6 },{ 0x1b, 8 },{ 0x1d, 9 },
{ 0xb, 10 },{ 0x10, 6 },{ 0x22, 9 },{ 0xa, 10 },
{ 0xd, 6 },{ 0x1c, 9 },{ 0x8, 10 },{ 0x12, 7 },
{ 0x1b, 9 },{ 0x54, 12 },{ 0x14, 7 },{ 0x1a, 9 },
{ 0x57, 12 },{ 0x19, 8 },{ 0x9, 10 },{ 0x18, 8 },
{ 0x23, 11 },{ 0x17, 8 },{ 0x19, 9 },{ 0x18, 9 },
{ 0x7, 10 },{ 0x58, 12 },{ 0x7, 4 },{ 0xc, 6 },
{ 0x16, 8 },{ 0x17, 9 },{ 0x6, 10 },{ 0x5, 11 },
{ 0x4, 11 },{ 0x59, 12 },{ 0xf, 6 },{ 0x16, 9 },
{ 0x5, 10 },{ 0xe, 6 },{ 0x4, 10 },{ 0x11, 7 },
{ 0x24, 11 },{ 0x10, 7 },{ 0x25, 11 },{ 0x13, 7 },
{ 0x5a, 12 },{ 0x15, 8 },{ 0x5b, 12 },{ 0x14, 8 },
{ 0x13, 8 },{ 0x1a, 8 },{ 0x15, 9 },{ 0x14, 9 },
{ 0x13, 9 },{ 0x12, 9 },{ 0x11, 9 },{ 0x26, 11 },
{ 0x27, 11 },{ 0x5c, 12 },{ 0x5d, 12 },{ 0x5e, 12 },
{ 0x5f, 12 },{ 0x3, 7 },
};
const INT8 intra_level[102] = {
1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 1, 2, 3, 4, 5,
6, 7, 8, 9, 10, 1, 2, 3,
4, 5, 1, 2, 3, 4, 1, 2,
3, 1, 2, 3, 1, 2, 3, 1,
2, 3, 1, 2, 1, 2, 1, 1,
1, 1, 1, 1, 2, 3, 4, 5,
6, 7, 8, 1, 2, 3, 1, 2,
1, 2, 1, 2, 1, 2, 1, 2,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1,
};
const INT8 intra_run[102] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 2, 2, 2,
2, 2, 3, 3, 3, 3, 4, 4,
4, 5, 5, 5, 6, 6, 6, 7,
7, 7, 8, 8, 9, 9, 10, 11,
12, 13, 14, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 2, 2,
3, 3, 4, 4, 5, 5, 6, 6,
7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20,
};
static RLTable rl_intra = {
102,
67,
intra_vlc,
intra_run,
intra_level,
};
/* alternate scan orders used when doing AC prediction */
UINT8 ff_alternate_horizontal_scan[64] = {
0, 1, 2, 3, 8, 9, 16, 17,
10, 11, 4, 5, 6, 7, 15, 14,
13, 12, 19, 18, 24, 25, 32, 33,
26, 27, 20, 21, 22, 23, 28, 29,
30, 31, 34, 35, 40, 41, 48, 49,
42, 43, 36, 37, 38, 39, 44, 45,
46, 47, 50, 51, 56, 57, 58, 59,
52, 53, 54, 55, 60, 61, 62, 63,
};
UINT8 ff_alternate_vertical_scan[64] = {
0, 8, 16, 24, 1, 9, 2, 10,
17, 25, 32, 40, 48, 56, 57, 49,
41, 33, 26, 18, 3, 11, 4, 12,
19, 27, 34, 42, 50, 58, 35, 43,
51, 59, 20, 28, 5, 13, 6, 14,
21, 29, 36, 44, 52, 60, 37, 45,
53, 61, 22, 30, 7, 15, 23, 31,
38, 46, 54, 62, 39, 47, 55, 63,
};

774
libavcodec/mpegaudio.c Normal file
View File

@ -0,0 +1,774 @@
/*
* 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 <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(AVCodecContext *avctx)
{
MpegAudioContext *s = avctx->priv_data;
int freq = avctx->sample_rate;
int bitrate = avctx->bit_rate;
int channels = avctx->channels;
int i, v, table, ch_bitrate;
float a;
if (channels > 2)
return -1;
bitrate = bitrate / 1000;
s->nb_channels = channels;
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 */
ch_bitrate = bitrate / s->nb_channels;
if (!s->lsf) {
if ((freq == 48000 && ch_bitrate >= 56) ||
(ch_bitrate >= 56 && ch_bitrate <= 80))
table = 0;
else if (freq != 48000 && ch_bitrate >= 96)
table = 1;
else if (freq != 32000 && ch_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
for(i=0;i<s->nb_channels;i++)
s->samples_offset[i] = 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, int ch, short *samples, int incr)
{
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[ch];
out = &s->sb_samples[ch][0][0][0];
for(j=0;j<36;j++) {
/* 32 samples at once */
for(i=0;i<32;i++) {
s->samples_buf[ch][offset + (31 - i)] = samples[0];
samples += incr;
}
/* filter */
p = s->samples_buf[ch] + 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 */
offset -= 32;
out += 32;
/* handle the wrap around */
if (offset < 0) {
memmove(s->samples_buf[ch] + SAMPLES_BUF_SIZE - (512 - 32),
s->samples_buf[ch], (512 - 32) * 2);
offset = SAMPLES_BUF_SIZE - 512;
}
}
s->samples_offset[ch] = 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[MPA_MAX_CHANNELS][SBLIMIT],
unsigned char bit_alloc[MPA_MAX_CHANNELS][SBLIMIT],
int *padding)
{
int i, ch, b, max_smr, max_ch, max_sb, current_frame_size, max_frame_size;
int incr;
short smr[MPA_MAX_CHANNELS][SBLIMIT];
unsigned char subband_status[MPA_MAX_CHANNELS][SBLIMIT];
const unsigned char *alloc;
memcpy(smr, smr1, s->nb_channels * sizeof(short) * SBLIMIT);
memset(subband_status, SB_NOTALLOCATED, s->nb_channels * SBLIMIT);
memset(bit_alloc, 0, s->nb_channels * 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 * s->nb_channels;
alloc += 1 << incr;
}
for(;;) {
/* look for the subband with the largest signal to mask ratio */
max_sb = -1;
max_ch = -1;
max_smr = 0x80000000;
for(ch=0;ch<s->nb_channels;ch++) {
for(i=0;i<s->sblimit;i++) {
if (smr[ch][i] > max_smr && subband_status[ch][i] != SB_NOMORE) {
max_smr = smr[ch][i];
max_sb = i;
max_ch = ch;
}
}
}
#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_ch][max_sb] == SB_NOTALLOCATED) {
/* nothing was coded for this band: add the necessary bits */
incr = 2 + nb_scale_factors[s->scale_code[max_ch][max_sb]] * 6;
incr += total_quant_bits[alloc[1]];
} else {
/* increments bit allocation */
b = bit_alloc[max_ch][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_ch][max_sb];
current_frame_size += incr;
/* decrease smr by the resolution we added */
smr[max_ch][max_sb] = smr1[max_ch][max_sb] - quant_snr[alloc[b]];
/* max allocation size reached ? */
if (b == ((1 << alloc[0]) - 1))
subband_status[max_ch][max_sb] = SB_NOMORE;
else
subband_status[max_ch][max_sb] = SB_ALLOCATED;
} else {
/* cannot increase the size of this subband */
subband_status[max_ch][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[MPA_MAX_CHANNELS][SBLIMIT],
int padding)
{
int i, j, k, l, bit_alloc_bits, b, ch;
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, s->nb_channels == 2 ? MPA_STEREO : 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];
for(ch=0;ch<s->nb_channels;ch++) {
put_bits(p, bit_alloc_bits, bit_alloc[ch][i]);
}
j += 1 << bit_alloc_bits;
}
/* scale codes */
for(i=0;i<s->sblimit;i++) {
for(ch=0;ch<s->nb_channels;ch++) {
if (bit_alloc[ch][i])
put_bits(p, 2, s->scale_code[ch][i]);
}
}
/* scale factors */
for(i=0;i<s->sblimit;i++) {
for(ch=0;ch<s->nb_channels;ch++) {
if (bit_alloc[ch][i]) {
sf = &s->scale_factors[ch][i][0];
switch(s->scale_code[ch][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;
}
}
}
}
/* 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];
for(ch=0;ch<s->nb_channels;ch++) {
b = bit_alloc[ch][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[ch][k][l + m][i];
/* divide by scale factor */
#ifdef USE_FLOATS
{
float a;
a = (float)sample * scale_factor_inv_table[s->scale_factors[ch][i][k]];
q[m] = (int)((a + 1.0) * steps * 0.5);
}
#else
{
int q1, e, shift, mult;
e = s->scale_factors[ch][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(AVCodecContext *avctx,
unsigned char *frame, int buf_size, void *data)
{
MpegAudioContext *s = avctx->priv_data;
short *samples = data;
short smr[MPA_MAX_CHANNELS][SBLIMIT];
unsigned char bit_alloc[MPA_MAX_CHANNELS][SBLIMIT];
int padding, i;
for(i=0;i<s->nb_channels;i++) {
filter(s, i, samples + i, s->nb_channels);
}
for(i=0;i<s->nb_channels;i++) {
compute_scale_factors(s->scale_code[i], s->scale_factors[i],
s->sb_samples[i], s->sblimit);
}
for(i=0;i<s->nb_channels;i++) {
psycho_acoustic_model(s, smr[i]);
}
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;
}
AVCodec mp2_encoder = {
"mp2",
CODEC_TYPE_AUDIO,
CODEC_ID_MP2,
sizeof(MpegAudioContext),
MPA_encode_init,
MPA_encode_frame,
NULL,
};

34
libavcodec/mpegaudio.h Normal file
View File

@ -0,0 +1,34 @@
/* max compressed frame size */
#define MPA_MAX_CODED_FRAME_SIZE 1200
#define MPA_FRAME_SIZE 1152
#define MPA_MAX_CHANNELS 2
#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 nb_channels;
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[MPA_MAX_CHANNELS][SAMPLES_BUF_SIZE]; /* buffer for filter */
int samples_offset[MPA_MAX_CHANNELS]; /* offset in samples_buf */
int sb_samples[MPA_MAX_CHANNELS][3][12][SBLIMIT];
unsigned char scale_factors[MPA_MAX_CHANNELS][SBLIMIT][3]; /* scale factors */
/* code to group 3 scale factors */
unsigned char scale_code[MPA_MAX_CHANNELS][SBLIMIT];
int sblimit; /* number of used subbands */
const unsigned char *alloc_table;
} MpegAudioContext;

293
libavcodec/mpegaudiodec.c Normal file
View File

@ -0,0 +1,293 @@
/*
* MPEG Audio decoder
* Copyright (c) 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "avcodec.h"
#include "mpglib/mpg123.h"
/*
* TODO:
* - add free format
* - do not rely anymore on mpglib (first step: implement dct64 and decoding filter)
*/
#define HEADER_SIZE 4
#define BACKSTEP_SIZE 512
typedef struct MPADecodeContext {
struct mpstr mpstr;
UINT8 inbuf1[2][MAXFRAMESIZE + BACKSTEP_SIZE]; /* input buffer */
int inbuf_index;
UINT8 *inbuf_ptr, *inbuf;
int frame_size;
int error_protection;
int layer;
int sample_rate;
int bit_rate;
int old_frame_size;
GetBitContext gb;
} MPADecodeContext;
/* XXX: suppress that mess */
struct mpstr *gmp;
GetBitContext *gmp_gb;
static MPADecodeContext *gmp_s;
/* XXX: merge constants with encoder */
static const unsigned short mp_bitrate_tab[2][3][15] = {
{ {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 },
{0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 },
{0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 } },
{ {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256},
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160},
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}
}
};
static unsigned short mp_freq_tab[3] = { 44100, 48000, 32000 };
static int decode_init(AVCodecContext * avctx)
{
MPADecodeContext *s = avctx->priv_data;
struct mpstr *mp = &s->mpstr;
static int init;
mp->fr.single = -1;
mp->synth_bo = 1;
if(!init) {
init = 1;
make_decode_tables(32767);
init_layer2();
init_layer3(SBLIMIT);
}
s->inbuf_index = 0;
s->inbuf = &s->inbuf1[s->inbuf_index][BACKSTEP_SIZE];
s->inbuf_ptr = s->inbuf;
return 0;
}
/* fast header check for resync */
static int check_header(UINT32 header)
{
/* header */
if ((header & 0xffe00000) != 0xffe00000)
return -1;
/* layer check */
if (((header >> 17) & 3) == 0)
return -1;
/* bit rate : currently no free format supported */
if (((header >> 12) & 0xf) == 0xf ||
((header >> 12) & 0xf) == 0x0)
return -1;
/* frequency */
if (((header >> 10) & 3) == 3)
return -1;
return 0;
}
/* header decoding. MUST check the header before because no
consistency check is done there */
static void decode_header(MPADecodeContext *s, UINT32 header)
{
struct frame *fr = &s->mpstr.fr;
int sample_rate, frame_size;
if (header & (1<<20)) {
fr->lsf = (header & (1<<19)) ? 0 : 1;
fr->mpeg25 = 0;
} else {
fr->lsf = 1;
fr->mpeg25 = 1;
}
s->layer = 4 - ((header >> 17) & 3);
/* extract frequency */
fr->sampling_frequency = ((header >> 10) & 3);
sample_rate = mp_freq_tab[fr->sampling_frequency] >> (fr->lsf + fr->mpeg25);
fr->sampling_frequency += 3 * (fr->lsf + fr->mpeg25);
s->error_protection = ((header>>16) & 1) ^ 1;
fr->bitrate_index = ((header>>12)&0xf);
fr->padding = ((header>>9)&0x1);
fr->extension = ((header>>8)&0x1);
fr->mode = ((header>>6)&0x3);
fr->mode_ext = ((header>>4)&0x3);
fr->copyright = ((header>>3)&0x1);
fr->original = ((header>>2)&0x1);
fr->emphasis = header & 0x3;
fr->stereo = (fr->mode == MPG_MD_MONO) ? 1 : 2;
frame_size = mp_bitrate_tab[fr->lsf][s->layer - 1][fr->bitrate_index];
s->bit_rate = frame_size * 1000;
switch(s->layer) {
case 1:
frame_size = (frame_size * 12000) / sample_rate;
frame_size = ((frame_size + fr->padding) << 2);
break;
case 2:
frame_size = (frame_size * 144000) / sample_rate;
frame_size += fr->padding;
break;
case 3:
frame_size = (frame_size * 144000) / (sample_rate << fr->lsf);
frame_size += fr->padding;
break;
}
s->frame_size = frame_size;
s->sample_rate = sample_rate;
#if 0
printf("layer%d, %d Hz, %d kbits/s, %s\n",
s->layer, s->sample_rate, s->bit_rate, fr->stereo ? "stereo" : "mono");
#endif
}
static int mp_decode_frame(MPADecodeContext *s,
short *samples)
{
int nb_bytes;
init_get_bits(&s->gb, s->inbuf + HEADER_SIZE, s->inbuf_ptr - s->inbuf - HEADER_SIZE);
/* skip error protection field */
if (s->error_protection)
get_bits(&s->gb, 16);
/* XXX: horrible: global! */
gmp = &s->mpstr;
gmp_s = s;
gmp_gb = &s->gb;
nb_bytes = 0;
switch(s->layer) {
case 1:
do_layer1(&s->mpstr.fr,(unsigned char *)samples, &nb_bytes);
break;
case 2:
do_layer2(&s->mpstr.fr,(unsigned char *)samples, &nb_bytes);
break;
case 3:
do_layer3(&s->mpstr.fr,(unsigned char *)samples, &nb_bytes);
s->inbuf_index ^= 1;
s->inbuf = &s->inbuf1[s->inbuf_index][BACKSTEP_SIZE];
s->old_frame_size = s->frame_size;
break;
default:
break;
}
return nb_bytes;
}
/*
* seek back in the stream for backstep bytes (at most 511 bytes, and
* at most in last frame). Note that this is slightly incorrect (data
* can span more than one block!)
*/
int set_pointer(long backstep)
{
UINT8 *ptr;
/* compute current position in stream */
ptr = gmp_gb->buf_ptr - (gmp_gb->bit_cnt >> 3);
/* copy old data before current one */
ptr -= backstep;
memcpy(ptr, gmp_s->inbuf1[gmp_s->inbuf_index ^ 1] +
BACKSTEP_SIZE + gmp_s->old_frame_size - backstep, backstep);
/* init get bits again */
init_get_bits(gmp_gb, ptr, gmp_s->frame_size + backstep);
return 0;
}
static int decode_frame(AVCodecContext * avctx,
void *data, int *data_size,
UINT8 * buf, int buf_size)
{
MPADecodeContext *s = avctx->priv_data;
UINT32 header;
UINT8 *buf_ptr;
int len, out_size;
short *out_samples = data;
*data_size = 0;
buf_ptr = buf;
while (buf_size > 0) {
len = s->inbuf_ptr - s->inbuf;
if (s->frame_size == 0) {
/* no header seen : find one. We need at least 7 bytes to parse it */
len = HEADER_SIZE - len;
if (len > buf_size)
len = buf_size;
memcpy(s->inbuf_ptr, buf_ptr, len);
buf_ptr += len;
s->inbuf_ptr += len;
buf_size -= len;
if ((s->inbuf_ptr - s->inbuf) == HEADER_SIZE) {
header = (s->inbuf[0] << 24) | (s->inbuf[1] << 16) |
(s->inbuf[2] << 8) | s->inbuf[3];
if (check_header(header) < 0) {
/* no sync found : move by one byte (inefficient, but simple!) */
memcpy(s->inbuf, s->inbuf + 1, HEADER_SIZE - 1);
s->inbuf_ptr--;
} else {
decode_header(s, header);
/* update codec info */
avctx->sample_rate = s->sample_rate;
avctx->channels = s->mpstr.fr.stereo ? 2 : 1;
avctx->bit_rate = s->bit_rate;
}
}
} else if (len < s->frame_size) {
len = s->frame_size - len;
if (len > buf_size)
len = buf_size;
memcpy(s->inbuf_ptr, buf_ptr, len);
buf_ptr += len;
s->inbuf_ptr += len;
buf_size -= len;
} else {
out_size = mp_decode_frame(s, out_samples);
s->inbuf_ptr = s->inbuf;
s->frame_size = 0;
*data_size = out_size;
break;
}
}
return buf_ptr - buf;
}
AVCodec mp3_decoder =
{
"mpegaudio",
CODEC_TYPE_AUDIO,
CODEC_ID_MP2,
sizeof(MPADecodeContext),
decode_init,
NULL,
NULL,
decode_frame,
};

310
libavcodec/mpegaudiotab.h Normal file
View File

@ -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 };

1281
libavcodec/mpegvideo.c Normal file

File diff suppressed because it is too large Load Diff

273
libavcodec/mpegvideo.h Normal file
View File

@ -0,0 +1,273 @@
/*
* Generic DCT based hybrid video encoder
* Copyright (c) 2000,2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Macros for picture code type. */
#define I_TYPE 1
#define P_TYPE 2
#define B_TYPE 3
enum OutputFormat {
FMT_MPEG1,
FMT_H263,
FMT_MJPEG,
};
#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_plus; /* h263 plus headers */
int h263_rv10; /* use RV10 variation for H263 */
int h263_pred; /* use OpenDIVX (aka mpeg4) ac/dc predictions */
int h263_msmpeg4; /* generate MSMPEG4 compatible stream */
int h263_intel; /* use I263 intel h263 header */
int fixed_qscale; /* fixed qscale if non zero */
/* the following fields are managed internally by the encoder */
/* bit output */
PutBitContext pb;
/* sequence parameters */
int context_initialized;
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;
int linesize; /* line size, in bytes, may be different from width */
UINT8 *new_picture[3]; /* picture to be compressed */
UINT8 *last_picture[3]; /* previous picture */
UINT8 *last_picture_base[3]; /* real start of the picture */
UINT8 *next_picture[3]; /* previous picture (for bidir pred) */
UINT8 *next_picture_base[3]; /* real start of the picture */
UINT8 *aux_picture[3]; /* aux picture (for B frames only) */
UINT8 *aux_picture_base[3]; /* real start of the picture */
UINT8 *current_picture[3]; /* buffer to store the decompressed current picture */
int last_dc[3]; /* last DC values for MPEG1 */
INT16 *dc_val[3]; /* used for mpeg4 DC prediction */
int y_dc_scale, c_dc_scale;
UINT8 *coded_block; /* used for coded block pattern prediction */
INT16 (*ac_val[3])[16]; /* used for for mpeg4 AC prediction */
int ac_pred;
int qscale;
int pict_type;
int frame_rate_index;
/* motion compensation */
int unrestricted_mv;
int h263_long_vectors; /* use horrible h263v1 long vector mode */
int f_code; /* resolution */
INT16 (*motion_val)[2]; /* used for MV prediction */
int full_search;
int mv_dir;
#define MV_DIR_BACKWARD 1
#define MV_DIR_FORWARD 2
int mv_type;
#define MV_TYPE_16X16 0 /* 1 vector for the whole mb */
#define MV_TYPE_8X8 1 /* 4 vectors (h263) */
#define MV_TYPE_16X8 2 /* 2 vectors, one per 16x8 block */
#define MV_TYPE_FIELD 3 /* 2 vectors, one per field */
#define MV_TYPE_DMV 4 /* 2 vectors, special mpeg2 Dual Prime Vectors */
/* motion vectors for a macroblock
first coordinate : 0 = forward 1 = backward
second " : depend on type
third " : 0 = x, 1 = y
*/
int mv[2][4][2];
int field_select[2][2];
int last_mv[2][2][2];
int has_b_frames;
int no_rounding; /* apply no rounding to motion estimation (MPEG4) */
/* macroblock layer */
int mb_x, mb_y;
int mb_incr;
int mb_intra;
/* matrix transmitted in the bitstream */
UINT16 intra_matrix[64];
UINT16 chroma_intra_matrix[64];
UINT16 non_intra_matrix[64];
UINT16 chroma_non_intra_matrix[64];
/* precomputed matrix (combine qscale and DCT renorm) */
int q_intra_matrix[64];
int q_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;
/* mpeg4 specific */
int time_increment_bits;
/* RV10 specific */
int rv10_version; /* RV10 version: 0 or 3 */
int rv10_first_dc_coded[3];
/* MJPEG specific */
struct MJpegContext *mjpeg_ctx;
/* MSMPEG4 specific */
int mv_table_index;
int rl_table_index;
int rl_chroma_table_index;
int dc_table_index;
int use_skip_mb_code;
int slice_height; /* in macroblocks */
int first_slice_line;
/* decompression specific */
GetBitContext gb;
/* MPEG2 specific - I wish I had not to support this mess. */
int progressive_sequence;
int mpeg_f_code[2][2];
int picture_structure;
/* picture type */
#define PICT_TOP_FIELD 1
#define PICT_BOTTOM_FIELD 2
#define PICT_FRAME 3
int intra_dc_precision;
int frame_pred_frame_dct;
int top_field_first;
int concealment_motion_vectors;
int q_scale_type;
int intra_vlc_format;
int alternate_scan;
int repeat_first_field;
int chroma_420_type;
int progressive_frame;
int mpeg2;
int full_pel[2];
int interlaced_dct;
int last_qscale;
int first_slice;
} MpegEncContext;
extern const UINT8 zigzag_direct[64];
int MPV_common_init(MpegEncContext *s);
void MPV_common_end(MpegEncContext *s);
void MPV_decode_mb(MpegEncContext *s, DCTELEM block[6][64]);
void MPV_frame_start(MpegEncContext *s);
void MPV_frame_end(MpegEncContext *s);
/* motion_est.c */
int estimate_motion(MpegEncContext *s,
int mb_x, int mb_y,
int *mx_ptr, int *my_ptr);
/* mpeg12.c */
extern const UINT8 default_intra_matrix[64];
extern const UINT8 default_non_intra_matrix[64];
void mpeg1_encode_picture_header(MpegEncContext *s, int picture_number);
void mpeg1_encode_mb(MpegEncContext *s,
DCTELEM block[6][64],
int motion_x, int motion_y);
/* h263enc.c */
/* run length table */
#define MAX_RUN 64
#define MAX_LEVEL 64
typedef struct RLTable {
int n; /* number of entries of table_vlc minus 1 */
int last; /* number of values for last = 0 */
const UINT16 (*table_vlc)[2];
const INT8 *table_run;
const INT8 *table_level;
UINT8 *index_run[2]; /* encoding only */
INT8 *max_level[2]; /* encoding & decoding */
INT8 *max_run[2]; /* encoding & decoding */
VLC vlc; /* decoding only */
} RLTable;
void init_rl(RLTable *rl);
void init_vlc_rl(RLTable *rl);
extern inline int get_rl_index(const RLTable *rl, int last, int run, int level)
{
int index;
index = rl->index_run[last][run];
if (index >= rl->n)
return rl->n;
if (level > rl->max_level[last][run])
return rl->n;
return index + level - 1;
}
void h263_encode_mb(MpegEncContext *s,
DCTELEM block[6][64],
int motion_x, int motion_y);
void h263_encode_picture_header(MpegEncContext *s, int picture_number);
void h263_dc_scale(MpegEncContext *s);
INT16 *h263_pred_motion(MpegEncContext * s, int block,
int *px, int *py);
void mpeg4_pred_ac(MpegEncContext * s, INT16 *block, int n,
int dir);
void mpeg4_encode_picture_header(MpegEncContext *s, int picture_number);
void h263_encode_init_vlc(MpegEncContext *s);
void h263_decode_init_vlc(MpegEncContext *s);
int h263_decode_picture_header(MpegEncContext *s);
int mpeg4_decode_picture_header(MpegEncContext * s);
int intel_h263_decode_picture_header(MpegEncContext *s);
int h263_decode_mb(MpegEncContext *s,
DCTELEM block[6][64]);
int h263_get_picture_format(int width, int height);
extern UINT8 ff_alternate_horizontal_scan[64];
extern UINT8 ff_alternate_vertical_scan[64];
/* rv10.c */
void rv10_encode_picture_header(MpegEncContext *s, int picture_number);
int rv_decode_dc(MpegEncContext *s, int n);
/* msmpeg4.c */
void msmpeg4_encode_picture_header(MpegEncContext * s, int picture_number);
void msmpeg4_encode_mb(MpegEncContext * s,
DCTELEM block[6][64],
int motion_x, int motion_y);
void msmpeg4_dc_scale(MpegEncContext * s);
int msmpeg4_decode_picture_header(MpegEncContext * s);
int msmpeg4_decode_mb(MpegEncContext *s,
DCTELEM block[6][64]);
int msmpeg4_decode_init_vlc(MpegEncContext *s);
/* 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);

931
libavcodec/msmpeg4.c Normal file
View File

@ -0,0 +1,931 @@
/*
* MSMPEG4 backend for ffmpeg encoder and decoder
* Copyright (c) 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include "common.h"
#include "dsputil.h"
#include "mpegvideo.h"
/*
* You can also call this codec : MPEG4 with a twist !
*
* TODO:
* - (encoding) select best mv table (two choices)
* - (encoding) select best vlc/dc table
* - (decoding) handle slice indication
*/
//#define DEBUG
/* motion vector table */
typedef struct MVTable {
int n;
const UINT16 *table_mv_code;
const UINT8 *table_mv_bits;
const UINT8 *table_mvx;
const UINT8 *table_mvy;
UINT16 *table_mv_index; /* encoding: convert mv to index in table_mv */
VLC vlc; /* decoding: vlc */
} MVTable;
static void msmpeg4_encode_block(MpegEncContext * s, DCTELEM * block, int n);
static int msmpeg4_decode_block(MpegEncContext * s, DCTELEM * block,
int n, int coded);
static int msmpeg4_decode_dc(MpegEncContext * s, int n, int *dir_ptr);
static int msmpeg4_decode_motion(MpegEncContext * s,
int *mx_ptr, int *my_ptr);
#ifdef DEBUG
int intra_count = 0;
int frame_count = 0;
#endif
/* XXX: move it to mpegvideo.h */
static int init_done = 0;
#include "msmpeg4data.h"
#ifdef STATS
const char *st_names[ST_NB] = {
"unknown",
"dc",
"intra_ac",
"inter_ac",
"intra_mb",
"inter_mb",
"mv",
};
int st_current_index = 0;
unsigned int st_bit_counts[ST_NB];
unsigned int st_out_bit_counts[ST_NB];
#define set_stat(var) st_current_index = var;
void print_stats(void)
{
unsigned int total;
int i;
printf("Input:\n");
total = 0;
for(i=0;i<ST_NB;i++)
total += st_bit_counts[i];
if (total == 0)
total = 1;
for(i=0;i<ST_NB;i++) {
printf("%-10s : %10.1f %5.1f%%\n",
st_names[i],
(double)st_bit_counts[i] / 8.0,
(double)st_bit_counts[i] * 100.0 / total);
}
printf("%-10s : %10.1f %5.1f%%\n",
"total",
(double)total / 8.0,
100.0);
printf("Output:\n");
total = 0;
for(i=0;i<ST_NB;i++)
total += st_out_bit_counts[i];
if (total == 0)
total = 1;
for(i=0;i<ST_NB;i++) {
printf("%-10s : %10.1f %5.1f%%\n",
st_names[i],
(double)st_out_bit_counts[i] / 8.0,
(double)st_out_bit_counts[i] * 100.0 / total);
}
printf("%-10s : %10.1f %5.1f%%\n",
"total",
(double)total / 8.0,
100.0);
}
#else
#define set_stat(var)
#endif
/* build the table which associate a (x,y) motion vector to a vlc */
static void init_mv_table(MVTable *tab)
{
int i, x, y;
tab->table_mv_index = malloc(sizeof(UINT16) * 4096);
/* mark all entries as not used */
for(i=0;i<4096;i++)
tab->table_mv_index[i] = tab->n;
for(i=0;i<tab->n;i++) {
x = tab->table_mvx[i];
y = tab->table_mvy[i];
tab->table_mv_index[(x << 6) | y] = i;
}
}
static void code012(PutBitContext *pb, int n)
{
if (n == 0) {
put_bits(pb, 1, 0);
} else {
put_bits(pb, 1, 1);
put_bits(pb, 1, (n >= 2));
}
}
/* write MSMPEG4 V3 compatible frame header */
void msmpeg4_encode_picture_header(MpegEncContext * s, int picture_number)
{
int i;
align_put_bits(&s->pb);
put_bits(&s->pb, 2, s->pict_type - 1);
put_bits(&s->pb, 5, s->qscale);
s->rl_table_index = 2;
s->rl_chroma_table_index = 1; /* only for I frame */
s->dc_table_index = 1;
s->mv_table_index = 1; /* only if P frame */
s->use_skip_mb_code = 1; /* only if P frame */
if (s->pict_type == I_TYPE) {
put_bits(&s->pb, 5, 0x17); /* indicate only one "slice" */
code012(&s->pb, s->rl_chroma_table_index);
code012(&s->pb, s->rl_table_index);
put_bits(&s->pb, 1, s->dc_table_index);
s->no_rounding = 1;
} else {
put_bits(&s->pb, 1, s->use_skip_mb_code);
s->rl_chroma_table_index = s->rl_table_index;
code012(&s->pb, s->rl_table_index);
put_bits(&s->pb, 1, s->dc_table_index);
put_bits(&s->pb, 1, s->mv_table_index);
s->no_rounding ^= 1;
}
if (!init_done) {
/* init various encoding tables */
init_done = 1;
init_mv_table(&mv_tables[0]);
init_mv_table(&mv_tables[1]);
for(i=0;i<NB_RL_TABLES;i++)
init_rl(&rl_table[i]);
}
#ifdef DEBUG
intra_count = 0;
printf("*****frame %d:\n", frame_count++);
#endif
}
/* predict coded block */
static inline int coded_block_pred(MpegEncContext * s, int n, UINT8 **coded_block_ptr)
{
int x, y, wrap, pred, a, b, c;
x = 2 * s->mb_x + 1 + (n & 1);
y = 2 * s->mb_y + 1 + ((n & 2) >> 1);
wrap = s->mb_width * 2 + 2;
/* B C
* A X
*/
a = s->coded_block[(x - 1) + (y) * wrap];
b = s->coded_block[(x - 1) + (y - 1) * wrap];
c = s->coded_block[(x) + (y - 1) * wrap];
if (b == c) {
pred = a;
} else {
pred = c;
}
/* store value */
*coded_block_ptr = &s->coded_block[(x) + (y) * wrap];
return pred;
}
static void msmpeg4_encode_motion(MpegEncContext * s,
int mx, int my)
{
int code;
MVTable *mv;
/* modulo encoding */
/* WARNING : you cannot reach all the MVs even with the modulo
encoding. This is a somewhat strange compromise they took !!! */
if (mx <= -64)
mx += 64;
else if (mx >= 64)
mx -= 64;
if (my <= -64)
my += 64;
else if (my >= 64)
my -= 64;
mx += 32;
my += 32;
#if 0
if ((unsigned)mx >= 64 ||
(unsigned)my >= 64)
fprintf(stderr, "error mx=%d my=%d\n", mx, my);
#endif
mv = &mv_tables[s->mv_table_index];
code = mv->table_mv_index[(mx << 6) | my];
set_stat(ST_MV);
put_bits(&s->pb,
mv->table_mv_bits[code],
mv->table_mv_code[code]);
if (code == mv->n) {
/* escape : code litterally */
put_bits(&s->pb, 6, mx);
put_bits(&s->pb, 6, my);
}
}
void msmpeg4_encode_mb(MpegEncContext * s,
DCTELEM block[6][64],
int motion_x, int motion_y)
{
int cbp, coded_cbp, i;
int pred_x, pred_y;
UINT8 *coded_block;
if (!s->mb_intra) {
/* compute cbp */
set_stat(ST_INTER_MB);
cbp = 0;
for (i = 0; i < 6; i++) {
if (s->block_last_index[i] >= 0)
cbp |= 1 << (5 - i);
}
if (s->use_skip_mb_code && (cbp | motion_x | motion_y) == 0) {
/* skip macroblock */
put_bits(&s->pb, 1, 1);
return;
}
if (s->use_skip_mb_code)
put_bits(&s->pb, 1, 0); /* mb coded */
put_bits(&s->pb,
table_mb_non_intra[cbp + 64][1],
table_mb_non_intra[cbp + 64][0]);
/* motion vector */
h263_pred_motion(s, 0, &pred_x, &pred_y);
msmpeg4_encode_motion(s, motion_x - pred_x,
motion_y - pred_y);
} else {
/* compute cbp */
cbp = 0;
coded_cbp = 0;
for (i = 0; i < 6; i++) {
int val, pred;
val = (s->block_last_index[i] >= 1);
cbp |= val << (5 - i);
if (i < 4) {
/* predict value for close blocks only for luma */
pred = coded_block_pred(s, i, &coded_block);
*coded_block = val;
val = val ^ pred;
}
coded_cbp |= val << (5 - i);
}
#if 0
if (coded_cbp)
printf("cbp=%x %x\n", cbp, coded_cbp);
#endif
if (s->pict_type == I_TYPE) {
set_stat(ST_INTRA_MB);
put_bits(&s->pb,
table_mb_intra[coded_cbp][1], table_mb_intra[coded_cbp][0]);
} else {
if (s->use_skip_mb_code)
put_bits(&s->pb, 1, 0); /* mb coded */
put_bits(&s->pb,
table_mb_non_intra[cbp][1],
table_mb_non_intra[cbp][0]);
}
set_stat(ST_INTRA_MB);
put_bits(&s->pb, 1, 0); /* no AC prediction yet */
}
for (i = 0; i < 6; i++) {
msmpeg4_encode_block(s, block[i], i);
}
}
/* strongly inspirated from MPEG4, but not exactly the same ! */
void msmpeg4_dc_scale(MpegEncContext * s)
{
int scale;
if (s->qscale < 5)
scale = 8;
else if (s->qscale < 9)
scale = 2 * s->qscale;
else
scale = s->qscale + 8;
s->y_dc_scale = scale;
s->c_dc_scale = (s->qscale + 13) / 2;
}
/* dir = 0: left, dir = 1: top prediction */
static int msmpeg4_pred_dc(MpegEncContext * s, int n,
UINT16 **dc_val_ptr, int *dir_ptr)
{
int a, b, c, x, y, wrap, pred, scale;
UINT16 *dc_val;
/* find prediction */
if (n < 4) {
x = 2 * s->mb_x + 1 + (n & 1);
y = 2 * s->mb_y + 1 + ((n & 2) >> 1);
wrap = s->mb_width * 2 + 2;
dc_val = s->dc_val[0];
scale = s->y_dc_scale;
} else {
x = s->mb_x + 1;
y = s->mb_y + 1;
wrap = s->mb_width + 2;
dc_val = s->dc_val[n - 4 + 1];
scale = s->c_dc_scale;
}
/* B C
* A X
*/
a = dc_val[(x - 1) + (y) * wrap];
b = dc_val[(x - 1) + (y - 1) * wrap];
c = dc_val[(x) + (y - 1) * wrap];
/* XXX: the following solution consumes divisions, but it does not
necessitate to modify mpegvideo.c. The problem comes from the
fact they decided to store the quantized DC (which would lead
to problems if Q could vary !) */
a = (a + (scale >> 1)) / scale;
b = (b + (scale >> 1)) / scale;
c = (c + (scale >> 1)) / scale;
/* XXX: WARNING: they did not choose the same test as MPEG4. This
is very important ! */
if (abs(a - b) <= abs(b - c)) {
pred = c;
*dir_ptr = 1;
} else {
pred = a;
*dir_ptr = 0;
}
/* update predictor */
*dc_val_ptr = &dc_val[(x) + (y) * wrap];
return pred;
}
#define DC_MAX 119
static void msmpeg4_encode_dc(MpegEncContext * s, int level, int n, int *dir_ptr)
{
int sign, code;
int pred;
UINT16 *dc_val;
pred = msmpeg4_pred_dc(s, n, &dc_val, dir_ptr);
/* update predictor */
if (n < 4) {
*dc_val = level * s->y_dc_scale;
} else {
*dc_val = level * s->c_dc_scale;
}
/* do the prediction */
level -= pred;
sign = 0;
if (level < 0) {
level = -level;
sign = 1;
}
code = level;
if (code > DC_MAX)
code = DC_MAX;
if (s->dc_table_index == 0) {
if (n < 4) {
put_bits(&s->pb, table0_dc_lum[code][1], table0_dc_lum[code][0]);
} else {
put_bits(&s->pb, table0_dc_chroma[code][1], table0_dc_chroma[code][0]);
}
} else {
if (n < 4) {
put_bits(&s->pb, table1_dc_lum[code][1], table1_dc_lum[code][0]);
} else {
put_bits(&s->pb, table1_dc_chroma[code][1], table1_dc_chroma[code][0]);
}
}
if (code == DC_MAX)
put_bits(&s->pb, 8, level);
if (level != 0) {
put_bits(&s->pb, 1, sign);
}
}
/* Encoding of a block. Very similar to MPEG4 except for a different
escape coding (same as H263) and more vlc tables.
*/
static void msmpeg4_encode_block(MpegEncContext * s, DCTELEM * block, int n)
{
int level, run, last, i, j, last_index;
int last_non_zero, sign, slevel;
int code, run_diff, dc_pred_dir;
const RLTable *rl;
if (s->mb_intra) {
set_stat(ST_DC);
msmpeg4_encode_dc(s, block[0], n, &dc_pred_dir);
i = 1;
if (n < 4) {
rl = &rl_table[s->rl_table_index];
} else {
rl = &rl_table[3 + s->rl_chroma_table_index];
}
run_diff = 0;
set_stat(ST_INTRA_AC);
} else {
i = 0;
rl = &rl_table[3 + s->rl_table_index];
run_diff = 1;
set_stat(ST_INTER_AC);
}
/* 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;
slevel = level;
if (level < 0) {
sign = 1;
level = -level;
}
code = get_rl_index(rl, last, run, level);
put_bits(&s->pb, rl->table_vlc[code][1], rl->table_vlc[code][0]);
if (code == rl->n) {
int level1, run1;
level1 = level - rl->max_level[last][run];
if (level1 < 1)
goto esc2;
code = get_rl_index(rl, last, run, level1);
if (code == rl->n) {
esc2:
put_bits(&s->pb, 1, 0);
if (level > MAX_LEVEL)
goto esc3;
run1 = run - rl->max_run[last][level] - run_diff;
if (run1 < 0)
goto esc3;
code = get_rl_index(rl, last, run1, level);
if (code == rl->n) {
esc3:
/* third escape */
put_bits(&s->pb, 1, 0);
put_bits(&s->pb, 1, last);
put_bits(&s->pb, 6, run);
put_bits(&s->pb, 8, slevel & 0xff);
} else {
/* second escape */
put_bits(&s->pb, 1, 1);
put_bits(&s->pb, rl->table_vlc[code][1], rl->table_vlc[code][0]);
put_bits(&s->pb, 1, sign);
}
} else {
/* first escape */
put_bits(&s->pb, 1, 1);
put_bits(&s->pb, rl->table_vlc[code][1], rl->table_vlc[code][0]);
put_bits(&s->pb, 1, sign);
}
} else {
put_bits(&s->pb, 1, sign);
}
last_non_zero = i;
}
}
}
/****************************************/
/* decoding stuff */
static VLC mb_non_intra_vlc;
static VLC mb_intra_vlc;
static VLC dc_lum_vlc[2];
static VLC dc_chroma_vlc[2];
/* init all vlc decoding tables */
int msmpeg4_decode_init_vlc(MpegEncContext *s)
{
int i;
MVTable *mv;
for(i=0;i<NB_RL_TABLES;i++) {
init_rl(&rl_table[i]);
init_vlc_rl(&rl_table[i]);
}
for(i=0;i<2;i++) {
mv = &mv_tables[i];
init_vlc(&mv->vlc, 9, mv->n + 1,
mv->table_mv_bits, 1, 1,
mv->table_mv_code, 2, 2);
}
init_vlc(&dc_lum_vlc[0], 9, 120,
&table0_dc_lum[0][1], 8, 4,
&table0_dc_lum[0][0], 8, 4);
init_vlc(&dc_chroma_vlc[0], 9, 120,
&table0_dc_chroma[0][1], 8, 4,
&table0_dc_chroma[0][0], 8, 4);
init_vlc(&dc_lum_vlc[1], 9, 120,
&table1_dc_lum[0][1], 8, 4,
&table1_dc_lum[0][0], 8, 4);
init_vlc(&dc_chroma_vlc[1], 9, 120,
&table1_dc_chroma[0][1], 8, 4,
&table1_dc_chroma[0][0], 8, 4);
init_vlc(&mb_non_intra_vlc, 9, 128,
&table_mb_non_intra[0][1], 8, 4,
&table_mb_non_intra[0][0], 8, 4);
init_vlc(&mb_intra_vlc, 9, 128,
&table_mb_intra[0][1], 4, 2,
&table_mb_intra[0][0], 4, 2);
return 0;
}
static int decode012(GetBitContext *gb)
{
int n;
n = get_bits(gb, 1);
if (n == 0)
return 0;
else
return get_bits(gb, 1) + 1;
}
int msmpeg4_decode_picture_header(MpegEncContext * s)
{
int code;
s->pict_type = get_bits(&s->gb, 2) + 1;
if (s->pict_type != I_TYPE &&
s->pict_type != P_TYPE)
return -1;
s->qscale = get_bits(&s->gb, 5);
if (s->pict_type == I_TYPE) {
code = get_bits(&s->gb, 5);
/* 0x17: one slice, 0x18: three slices */
/* XXX: implement it */
if (code < 0x17)
return -1;
s->slice_height = s->mb_height / (code - 0x16);
s->rl_chroma_table_index = decode012(&s->gb);
s->rl_table_index = decode012(&s->gb);
s->dc_table_index = get_bits(&s->gb, 1);
s->no_rounding = 1;
} else {
s->use_skip_mb_code = get_bits(&s->gb, 1);
s->rl_table_index = decode012(&s->gb);
s->rl_chroma_table_index = s->rl_table_index;
s->dc_table_index = get_bits(&s->gb, 1);
s->mv_table_index = get_bits(&s->gb, 1);
s->no_rounding ^= 1;
}
#ifdef DEBUG
printf("*****frame %d:\n", frame_count++);
#endif
return 0;
}
void memsetw(short *tab, int val, int n)
{
int i;
for(i=0;i<n;i++)
tab[i] = val;
}
int msmpeg4_decode_mb(MpegEncContext *s,
DCTELEM block[6][64])
{
int cbp, code, i;
int pred, val;
UINT8 *coded_val;
/* special slice handling */
if (s->mb_x == 0) {
if ((s->mb_y % s->slice_height) == 0) {
int wrap;
/* reset DC pred (set previous line to 1024) */
wrap = 2 * s->mb_width + 2;
memsetw(&s->dc_val[0][(1) + (2 * s->mb_y) * wrap],
1024, 2 * s->mb_width);
wrap = s->mb_width + 2;
memsetw(&s->dc_val[1][(1) + (s->mb_y) * wrap],
1024, s->mb_width);
memsetw(&s->dc_val[2][(1) + (s->mb_y) * wrap],
1024, s->mb_width);
s->first_slice_line = 1;
} else {
s->first_slice_line = 0;
}
}
if (s->pict_type == P_TYPE) {
set_stat(ST_INTER_MB);
if (s->use_skip_mb_code) {
if (get_bits(&s->gb, 1)) {
/* skip mb */
s->mb_intra = 0;
for(i=0;i<6;i++)
s->block_last_index[i] = -1;
s->mv_dir = MV_DIR_FORWARD;
s->mv_type = MV_TYPE_16X16;
s->mv[0][0][0] = 0;
s->mv[0][0][1] = 0;
return 0;
}
}
code = get_vlc(&s->gb, &mb_non_intra_vlc);
if (code < 0)
return -1;
if (code & 0x40)
s->mb_intra = 0;
else
s->mb_intra = 1;
cbp = code & 0x3f;
} else {
set_stat(ST_INTRA_MB);
s->mb_intra = 1;
code = get_vlc(&s->gb, &mb_intra_vlc);
if (code < 0)
return -1;
/* predict coded block pattern */
cbp = 0;
for(i=0;i<6;i++) {
val = ((code >> (5 - i)) & 1);
if (i < 4) {
pred = coded_block_pred(s, i, &coded_val);
val = val ^ pred;
*coded_val = val;
}
cbp |= val << (5 - i);
}
}
if (!s->mb_intra) {
int mx, my;
set_stat(ST_MV);
h263_pred_motion(s, 0, &mx, &my);
if (msmpeg4_decode_motion(s, &mx, &my) < 0)
return -1;
s->mv_dir = MV_DIR_FORWARD;
s->mv_type = MV_TYPE_16X16;
s->mv[0][0][0] = mx;
s->mv[0][0][1] = my;
} else {
set_stat(ST_INTRA_MB);
s->ac_pred = get_bits(&s->gb, 1);
}
for (i = 0; i < 6; i++) {
if (msmpeg4_decode_block(s, block[i], i, (cbp >> (5 - i)) & 1) < 0)
return -1;
}
return 0;
}
static int msmpeg4_decode_block(MpegEncContext * s, DCTELEM * block,
int n, int coded)
{
int code, level, i, j, last, run, run_diff;
int dc_pred_dir;
RLTable *rl;
const UINT8 *scan_table;
if (s->mb_intra) {
/* DC coef */
set_stat(ST_DC);
level = msmpeg4_decode_dc(s, n, &dc_pred_dir);
if (level < 0)
return -1;
block[0] = level;
if (n < 4) {
rl = &rl_table[s->rl_table_index];
} else {
rl = &rl_table[3 + s->rl_chroma_table_index];
}
run_diff = 0;
i = 1;
if (!coded) {
goto not_coded;
}
if (s->ac_pred) {
if (dc_pred_dir == 0)
scan_table = ff_alternate_vertical_scan; /* left */
else
scan_table = ff_alternate_horizontal_scan; /* top */
} else {
scan_table = zigzag_direct;
}
set_stat(ST_INTRA_AC);
} else {
i = 0;
rl = &rl_table[3 + s->rl_table_index];
run_diff = 1;
if (!coded) {
s->block_last_index[n] = i - 1;
return 0;
}
scan_table = zigzag_direct;
set_stat(ST_INTER_AC);
}
for(;;) {
code = get_vlc(&s->gb, &rl->vlc);
if (code < 0)
return -1;
if (code == rl->n) {
/* escape */
if (get_bits(&s->gb, 1) == 0) {
if (get_bits(&s->gb, 1) == 0) {
/* third escape */
last = get_bits(&s->gb, 1);
run = get_bits(&s->gb, 6);
level = get_bits(&s->gb, 8);
level = (level << 24) >> 24; /* sign extend */
} else {
/* second escape */
code = get_vlc(&s->gb, &rl->vlc);
if (code < 0 || code >= rl->n)
return -1;
run = rl->table_run[code];
level = rl->table_level[code];
last = code >= rl->last;
run += rl->max_run[last][level] + run_diff;
if (get_bits(&s->gb, 1))
level = -level;
}
} else {
/* first escape */
code = get_vlc(&s->gb, &rl->vlc);
if (code < 0 || code >= rl->n)
return -1;
run = rl->table_run[code];
level = rl->table_level[code];
last = code >= rl->last;
level += rl->max_level[last][run];
if (get_bits(&s->gb, 1))
level = -level;
}
} else {
run = rl->table_run[code];
level = rl->table_level[code];
last = code >= rl->last;
if (get_bits(&s->gb, 1))
level = -level;
}
i += run;
if (i >= 64)
return -1;
j = scan_table[i];
block[j] = level;
i++;
if (last)
break;
}
not_coded:
if (s->mb_intra) {
mpeg4_pred_ac(s, block, n, dc_pred_dir);
if (s->ac_pred) {
i = 64; /* XXX: not optimal */
}
}
s->block_last_index[n] = i - 1;
return 0;
}
static int msmpeg4_decode_dc(MpegEncContext * s, int n, int *dir_ptr)
{
int level, pred;
UINT16 *dc_val;
if (n < 4) {
level = get_vlc(&s->gb, &dc_lum_vlc[s->dc_table_index]);
} else {
level = get_vlc(&s->gb, &dc_chroma_vlc[s->dc_table_index]);
}
if (level < 0)
return -1;
if (level == DC_MAX) {
level = get_bits(&s->gb, 8);
if (get_bits(&s->gb, 1))
level = -level;
} else if (level != 0) {
if (get_bits(&s->gb, 1))
level = -level;
}
pred = msmpeg4_pred_dc(s, n, &dc_val, dir_ptr);
level += pred;
/* update predictor */
if (n < 4) {
*dc_val = level * s->y_dc_scale;
} else {
*dc_val = level * s->c_dc_scale;
}
return level;
}
static int msmpeg4_decode_motion(MpegEncContext * s,
int *mx_ptr, int *my_ptr)
{
MVTable *mv;
int code, mx, my;
mv = &mv_tables[s->mv_table_index];
code = get_vlc(&s->gb, &mv->vlc);
if (code < 0)
return -1;
if (code == mv->n) {
mx = get_bits(&s->gb, 6);
my = get_bits(&s->gb, 6);
} else {
mx = mv->table_mvx[code];
my = mv->table_mvy[code];
}
mx += *mx_ptr - 32;
my += *my_ptr - 32;
/* WARNING : they do not do exactly modulo encoding */
if (mx <= -64)
mx += 64;
else if (mx >= 64)
mx -= 64;
if (my <= -64)
my += 64;
else if (my >= 64)
my -= 64;
*mx_ptr = mx;
*my_ptr = my;
return 0;
}

1767
libavcodec/msmpeg4data.h Normal file

File diff suppressed because it is too large Load Diff

301
libavcodec/resample.c Normal file
View File

@ -0,0 +1,301 @@
/*
* 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 <math.h>
#include "avcodec.h"
#define NDEBUG
#include <assert.h>
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;
struct ReSampleContext {
ReSampleChannelContext channel_ctx[2];
float ratio;
/* channel convert */
int input_channels, output_channels, filter_channels;
};
#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--;
}
}
/* n1: number of samples */
static void mono_to_stereo(short *output, short *input, int n1)
{
short *p, *q;
int n = n1;
int v;
p = input;
q = output;
while (n >= 4) {
v = p[0]; q[0] = v; q[1] = v;
v = p[1]; q[2] = v; q[3] = v;
v = p[2]; q[4] = v; q[5] = v;
v = p[3]; q[6] = v; q[7] = v;
q += 8;
p += 4;
n -= 4;
}
while (n > 0) {
v = p[0]; q[0] = v; q[1] = v;
q += 2;
p += 1;
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;
}
ReSampleContext *audio_resample_init(int output_channels, int input_channels,
int output_rate, int input_rate)
{
ReSampleContext *s;
int i;
if (output_channels > 2 || input_channels > 2)
return NULL;
s = av_mallocz(sizeof(ReSampleContext));
if (!s)
return NULL;
s->ratio = (float)output_rate / (float)input_rate;
s->input_channels = input_channels;
s->output_channels = output_channels;
s->filter_channels = s->input_channels;
if (s->output_channels < s->filter_channels)
s->filter_channels = s->output_channels;
for(i=0;i<s->filter_channels;i++) {
init_mono_resample(&s->channel_ctx[i], s->ratio);
}
return s;
}
/* 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 bufin[2][nb_samples];
short bufout[2][(int)(nb_samples * s->ratio) + 16]; /* make some zoom to avoid round pb */
short *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) {
buftmp2[0] = bufin[0];
buftmp3[0] = output;
stereo_to_mono(buftmp2[0], input, nb_samples);
} else if (s->output_channels == 2 && s->input_channels == 1) {
buftmp2[0] = input;
buftmp3[0] = bufout[0];
} else if (s->output_channels == 2) {
buftmp2[0] = bufin[0];
buftmp2[1] = bufin[1];
buftmp3[0] = bufout[0];
buftmp3[1] = bufout[1];
stereo_split(buftmp2[0], buftmp2[1], input, nb_samples);
} else {
buftmp2[0] = input;
buftmp3[0] = output;
}
/* resample each channel */
nb_samples1 = 0; /* avoid warning */
for(i=0;i<s->filter_channels;i++) {
nb_samples1 = mono_resample(&s->channel_ctx[i], buftmp3[i], buftmp2[i], nb_samples);
}
if (s->output_channels == 2 && s->input_channels == 1) {
mono_to_stereo(output, buftmp3[0], nb_samples1);
} else if (s->output_channels == 2) {
stereo_mux(output, buftmp3[0], buftmp3[1], nb_samples1);
}
return nb_samples1;
}
void audio_resample_close(ReSampleContext *s)
{
free(s);
}

487
libavcodec/rv10.c Normal file
View File

@ -0,0 +1,487 @@
/*
* RV10 codec
* Copyright (c) 2000,2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "dsputil.h"
#include "avcodec.h"
#include "mpegvideo.h"
//#define DEBUG
static const UINT16 rv_lum_code[256] =
{
0x3e7f, 0x0f00, 0x0f01, 0x0f02, 0x0f03, 0x0f04, 0x0f05, 0x0f06,
0x0f07, 0x0f08, 0x0f09, 0x0f0a, 0x0f0b, 0x0f0c, 0x0f0d, 0x0f0e,
0x0f0f, 0x0f10, 0x0f11, 0x0f12, 0x0f13, 0x0f14, 0x0f15, 0x0f16,
0x0f17, 0x0f18, 0x0f19, 0x0f1a, 0x0f1b, 0x0f1c, 0x0f1d, 0x0f1e,
0x0f1f, 0x0f20, 0x0f21, 0x0f22, 0x0f23, 0x0f24, 0x0f25, 0x0f26,
0x0f27, 0x0f28, 0x0f29, 0x0f2a, 0x0f2b, 0x0f2c, 0x0f2d, 0x0f2e,
0x0f2f, 0x0f30, 0x0f31, 0x0f32, 0x0f33, 0x0f34, 0x0f35, 0x0f36,
0x0f37, 0x0f38, 0x0f39, 0x0f3a, 0x0f3b, 0x0f3c, 0x0f3d, 0x0f3e,
0x0f3f, 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386,
0x0387, 0x0388, 0x0389, 0x038a, 0x038b, 0x038c, 0x038d, 0x038e,
0x038f, 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396,
0x0397, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e,
0x039f, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6,
0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce,
0x00cf, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056,
0x0057, 0x0020, 0x0021, 0x0022, 0x0023, 0x000c, 0x000d, 0x0004,
0x0000, 0x0005, 0x000e, 0x000f, 0x0024, 0x0025, 0x0026, 0x0027,
0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7,
0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03ae, 0x03af,
0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7,
0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
0x0f40, 0x0f41, 0x0f42, 0x0f43, 0x0f44, 0x0f45, 0x0f46, 0x0f47,
0x0f48, 0x0f49, 0x0f4a, 0x0f4b, 0x0f4c, 0x0f4d, 0x0f4e, 0x0f4f,
0x0f50, 0x0f51, 0x0f52, 0x0f53, 0x0f54, 0x0f55, 0x0f56, 0x0f57,
0x0f58, 0x0f59, 0x0f5a, 0x0f5b, 0x0f5c, 0x0f5d, 0x0f5e, 0x0f5f,
0x0f60, 0x0f61, 0x0f62, 0x0f63, 0x0f64, 0x0f65, 0x0f66, 0x0f67,
0x0f68, 0x0f69, 0x0f6a, 0x0f6b, 0x0f6c, 0x0f6d, 0x0f6e, 0x0f6f,
0x0f70, 0x0f71, 0x0f72, 0x0f73, 0x0f74, 0x0f75, 0x0f76, 0x0f77,
0x0f78, 0x0f79, 0x0f7a, 0x0f7b, 0x0f7c, 0x0f7d, 0x0f7e, 0x0f7f,
};
static const UINT8 rv_lum_bits[256] =
{
14, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10,
10, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8,
8, 7, 7, 7, 7, 7, 7, 7,
7, 6, 6, 6, 6, 5, 5, 4,
2, 4, 5, 5, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8,
10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
};
static const UINT16 rv_chrom_code[256] =
{
0xfe7f, 0x3f00, 0x3f01, 0x3f02, 0x3f03, 0x3f04, 0x3f05, 0x3f06,
0x3f07, 0x3f08, 0x3f09, 0x3f0a, 0x3f0b, 0x3f0c, 0x3f0d, 0x3f0e,
0x3f0f, 0x3f10, 0x3f11, 0x3f12, 0x3f13, 0x3f14, 0x3f15, 0x3f16,
0x3f17, 0x3f18, 0x3f19, 0x3f1a, 0x3f1b, 0x3f1c, 0x3f1d, 0x3f1e,
0x3f1f, 0x3f20, 0x3f21, 0x3f22, 0x3f23, 0x3f24, 0x3f25, 0x3f26,
0x3f27, 0x3f28, 0x3f29, 0x3f2a, 0x3f2b, 0x3f2c, 0x3f2d, 0x3f2e,
0x3f2f, 0x3f30, 0x3f31, 0x3f32, 0x3f33, 0x3f34, 0x3f35, 0x3f36,
0x3f37, 0x3f38, 0x3f39, 0x3f3a, 0x3f3b, 0x3f3c, 0x3f3d, 0x3f3e,
0x3f3f, 0x0f80, 0x0f81, 0x0f82, 0x0f83, 0x0f84, 0x0f85, 0x0f86,
0x0f87, 0x0f88, 0x0f89, 0x0f8a, 0x0f8b, 0x0f8c, 0x0f8d, 0x0f8e,
0x0f8f, 0x0f90, 0x0f91, 0x0f92, 0x0f93, 0x0f94, 0x0f95, 0x0f96,
0x0f97, 0x0f98, 0x0f99, 0x0f9a, 0x0f9b, 0x0f9c, 0x0f9d, 0x0f9e,
0x0f9f, 0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6,
0x03c7, 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce,
0x03cf, 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6,
0x00e7, 0x0030, 0x0031, 0x0032, 0x0033, 0x0008, 0x0009, 0x0002,
0x0000, 0x0003, 0x000a, 0x000b, 0x0034, 0x0035, 0x0036, 0x0037,
0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
0x03d0, 0x03d1, 0x03d2, 0x03d3, 0x03d4, 0x03d5, 0x03d6, 0x03d7,
0x03d8, 0x03d9, 0x03da, 0x03db, 0x03dc, 0x03dd, 0x03de, 0x03df,
0x0fa0, 0x0fa1, 0x0fa2, 0x0fa3, 0x0fa4, 0x0fa5, 0x0fa6, 0x0fa7,
0x0fa8, 0x0fa9, 0x0faa, 0x0fab, 0x0fac, 0x0fad, 0x0fae, 0x0faf,
0x0fb0, 0x0fb1, 0x0fb2, 0x0fb3, 0x0fb4, 0x0fb5, 0x0fb6, 0x0fb7,
0x0fb8, 0x0fb9, 0x0fba, 0x0fbb, 0x0fbc, 0x0fbd, 0x0fbe, 0x0fbf,
0x3f40, 0x3f41, 0x3f42, 0x3f43, 0x3f44, 0x3f45, 0x3f46, 0x3f47,
0x3f48, 0x3f49, 0x3f4a, 0x3f4b, 0x3f4c, 0x3f4d, 0x3f4e, 0x3f4f,
0x3f50, 0x3f51, 0x3f52, 0x3f53, 0x3f54, 0x3f55, 0x3f56, 0x3f57,
0x3f58, 0x3f59, 0x3f5a, 0x3f5b, 0x3f5c, 0x3f5d, 0x3f5e, 0x3f5f,
0x3f60, 0x3f61, 0x3f62, 0x3f63, 0x3f64, 0x3f65, 0x3f66, 0x3f67,
0x3f68, 0x3f69, 0x3f6a, 0x3f6b, 0x3f6c, 0x3f6d, 0x3f6e, 0x3f6f,
0x3f70, 0x3f71, 0x3f72, 0x3f73, 0x3f74, 0x3f75, 0x3f76, 0x3f77,
0x3f78, 0x3f79, 0x3f7a, 0x3f7b, 0x3f7c, 0x3f7d, 0x3f7e, 0x3f7f,
};
static const UINT8 rv_chrom_bits[256] =
{
16, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14,
14, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10,
10, 8, 8, 8, 8, 8, 8, 8,
8, 6, 6, 6, 6, 4, 4, 3,
2, 3, 4, 4, 6, 6, 6, 6,
8, 8, 8, 8, 8, 8, 8, 8,
10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14,
};
static VLC rv_dc_lum, rv_dc_chrom;
int rv_decode_dc(MpegEncContext *s, int n)
{
int code;
if (n < 4) {
code = get_vlc(&s->gb, &rv_dc_lum);
if (code < 0) {
/* XXX: I don't understand why they use LONGER codes than
necessary. The following code would be completely useless
if they had thought about it !!! */
code = get_bits(&s->gb, 7);
if (code == 0x7c) {
code = (INT8)(get_bits(&s->gb, 7) + 1);
} else if (code == 0x7d) {
code = -128 + get_bits(&s->gb, 7);
} else if (code == 0x7e) {
if (get_bits(&s->gb, 1) == 0)
code = (INT8)(get_bits(&s->gb, 8) + 1);
else
code = (INT8)(get_bits(&s->gb, 8));
} else if (code == 0x7f) {
get_bits(&s->gb, 11);
code = 1;
}
} else {
code -= 128;
}
} else {
code = get_vlc(&s->gb, &rv_dc_chrom);
/* same remark */
if (code < 0) {
code = get_bits(&s->gb, 9);
if (code == 0x1fc) {
code = (INT8)(get_bits(&s->gb, 7) + 1);
} else if (code == 0x1fd) {
code = -128 + get_bits(&s->gb, 7);
} else if (code == 0x1fe) {
get_bits(&s->gb, 9);
code = 1;
} else {
return 0xffff;
}
} else {
code -= 128;
}
}
return -code;
}
/* 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 */
}
static int get_num(GetBitContext *gb)
{
int n, n1;
n = get_bits(gb, 16);
if (n >= 0x4000) {
return n - 0x4000;
} else {
n1 = get_bits(gb, 16);
return (n << 16) | n1;
}
}
/* read RV 1.0 compatible frame header */
static int rv10_decode_picture_header(MpegEncContext *s)
{
int mb_count, pb_frame, marker, h, full_frame;
/* skip packet header */
h = get_bits(&s->gb, 8);
if ((h & 0xc0) == 0xc0) {
int len, pos;
full_frame = 1;
len = get_num(&s->gb);
pos = get_num(&s->gb);
} else {
int seq, frame_size, pos;
full_frame = 0;
seq = get_bits(&s->gb, 8);
frame_size = get_num(&s->gb);
pos = get_num(&s->gb);
}
/* picture number */
get_bits(&s->gb, 8);
marker = get_bits(&s->gb, 1);
if (get_bits(&s->gb, 1))
s->pict_type = P_TYPE;
else
s->pict_type = I_TYPE;
pb_frame = get_bits(&s->gb, 1);
#ifdef DEBUG
printf("pict_type=%d pb_frame=%d\n", s->pict_type, pb_frame);
#endif
if (pb_frame)
return -1;
s->qscale = get_bits(&s->gb, 5);
if (s->pict_type == I_TYPE) {
if (s->rv10_version == 3) {
/* specific MPEG like DC coding not used */
s->last_dc[0] = get_bits(&s->gb, 8);
s->last_dc[1] = get_bits(&s->gb, 8);
s->last_dc[2] = get_bits(&s->gb, 8);
#ifdef DEBUG
printf("DC:%d %d %d\n",
s->last_dc[0],
s->last_dc[1],
s->last_dc[2]);
#endif
}
}
/* if multiple packets per frame are sent, the position at which
to display the macro blocks is coded here */
if (!full_frame) {
s->mb_x = get_bits(&s->gb, 6); /* mb_x */
s->mb_y = get_bits(&s->gb, 6); /* mb_y */
mb_count = get_bits(&s->gb, 12);
} else {
s->mb_x = 0;
s->mb_y = 0;
mb_count = s->mb_width * s->mb_height;
}
get_bits(&s->gb, 3); /* ignored */
s->f_code = 1;
s->unrestricted_mv = 1;
#if 0
s->h263_long_vectors = 1;
#endif
return mb_count;
}
static int rv10_decode_init(AVCodecContext *avctx)
{
MpegEncContext *s = avctx->priv_data;
static int done;
s->out_format = FMT_H263;
s->width = avctx->width;
s->height = avctx->height;
s->h263_rv10 = 1;
s->rv10_version = avctx->sub_id;
if (MPV_common_init(s) < 0)
return -1;
h263_decode_init_vlc(s);
/* init rv vlc */
if (!done) {
init_vlc(&rv_dc_lum, 9, 256,
rv_lum_bits, 1, 1,
rv_lum_code, 2, 2);
init_vlc(&rv_dc_chrom, 9, 256,
rv_chrom_bits, 1, 1,
rv_chrom_code, 2, 2);
done = 1;
}
return 0;
}
static int rv10_decode_end(AVCodecContext *avctx)
{
MpegEncContext *s = avctx->priv_data;
MPV_common_end(s);
return 0;
}
static int rv10_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
UINT8 *buf, int buf_size)
{
MpegEncContext *s = avctx->priv_data;
int i, mb_count, mb_pos, left;
DCTELEM block[6][64];
AVPicture *pict = data;
#ifdef DEBUG
printf("*****frame %d size=%d\n", avctx->frame_number, buf_size);
#endif
/* no supplementary picture */
if (buf_size == 0) {
*data_size = 0;
return 0;
}
init_get_bits(&s->gb, buf, buf_size);
mb_count = rv10_decode_picture_header(s);
if (mb_count < 0) {
#ifdef DEBUG
printf("HEADER ERROR\n");
#endif
return -1;
}
if (s->mb_x >= s->mb_width ||
s->mb_y >= s->mb_height) {
#ifdef DEBUG
printf("POS ERROR %d %d\n", s->mb_x, s->mb_y);
#endif
return -1;
}
mb_pos = s->mb_y * s->mb_width + s->mb_x;
left = s->mb_width * s->mb_height - mb_pos;
if (mb_count > left) {
#ifdef DEBUG
printf("COUNT ERROR\n");
#endif
return -1;
}
if (s->mb_x == 0 && s->mb_y == 0) {
MPV_frame_start(s);
}
#ifdef DEBUG
printf("qscale=%d\n", s->qscale);
#endif
/* default quantization values */
s->y_dc_scale = 8;
s->c_dc_scale = 8;
s->rv10_first_dc_coded[0] = 0;
s->rv10_first_dc_coded[1] = 0;
s->rv10_first_dc_coded[2] = 0;
/* decode each macroblock */
for(i=0;i<mb_count;i++) {
#ifdef DEBUG
printf("**mb x=%d y=%d\n", s->mb_x, s->mb_y);
#endif
memset(block, 0, sizeof(block));
s->mv_dir = MV_DIR_FORWARD;
s->mv_type = MV_TYPE_16X16;
if (h263_decode_mb(s, block) < 0) {
#ifdef DEBUG
printf("ERROR\n");
#endif
return -1;
}
MPV_decode_mb(s, block);
if (++s->mb_x == s->mb_width) {
s->mb_x = 0;
s->mb_y++;
}
}
if (s->mb_x == 0 &&
s->mb_y == s->mb_height) {
MPV_frame_end(s);
pict->data[0] = s->current_picture[0];
pict->data[1] = s->current_picture[1];
pict->data[2] = s->current_picture[2];
pict->linesize[0] = s->linesize;
pict->linesize[1] = s->linesize / 2;
pict->linesize[2] = s->linesize / 2;
avctx->quality = s->qscale;
*data_size = sizeof(AVPicture);
} else {
*data_size = 0;
}
return buf_size;
}
AVCodec rv10_decoder = {
"rv10",
CODEC_TYPE_VIDEO,
CODEC_ID_RV10,
sizeof(MpegEncContext),
rv10_decode_init,
NULL,
rv10_decode_end,
rv10_decode_frame,
};

306
libavcodec/utils.c Normal file
View File

@ -0,0 +1,306 @@
/*
* utils for libavcodec
* Copyright (c) 2001 Gerard Lantau.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "common.h"
#include "dsputil.h"
#include "avcodec.h"
/* memory alloc */
void *av_mallocz(int size)
{
void *ptr;
ptr = malloc(size);
if (!ptr)
return NULL;
memset(ptr, 0, size);
return ptr;
}
/* encoder management */
AVCodec *first_avcodec;
void register_avcodec(AVCodec *format)
{
AVCodec **p;
p = &first_avcodec;
while (*p != NULL) p = &(*p)->next;
*p = format;
format->next = NULL;
}
int avcodec_open(AVCodecContext *avctx, AVCodec *codec)
{
int ret;
avctx->codec = codec;
avctx->frame_number = 0;
avctx->priv_data = av_mallocz(codec->priv_data_size);
if (!avctx->priv_data)
return -ENOMEM;
ret = avctx->codec->init(avctx);
if (ret < 0) {
free(avctx->priv_data);
avctx->priv_data = NULL;
return ret;
}
return 0;
}
int avcodec_encode_audio(AVCodecContext *avctx, UINT8 *buf, int buf_size,
const short *samples)
{
int ret;
ret = avctx->codec->encode(avctx, buf, buf_size, (void *)samples);
avctx->frame_number++;
return ret;
}
int avcodec_encode_video(AVCodecContext *avctx, UINT8 *buf, int buf_size,
const AVPicture *pict)
{
int ret;
ret = avctx->codec->encode(avctx, buf, buf_size, (void *)pict);
avctx->frame_number++;
return ret;
}
/* decode a frame. return -1 if error, otherwise return the number of
bytes used. If no frame could be decompressed, *got_picture_ptr is
zero. Otherwise, it is non zero */
int avcodec_decode_video(AVCodecContext *avctx, AVPicture *picture,
int *got_picture_ptr,
UINT8 *buf, int buf_size)
{
int ret;
ret = avctx->codec->decode(avctx, picture, got_picture_ptr,
buf, buf_size);
avctx->frame_number++;
return ret;
}
/* decode an audio frame. return -1 if error, otherwise return the
*number of bytes used. If no frame could be decompressed,
*frame_size_ptr is zero. Otherwise, it is the decompressed frame
*size in BYTES. */
int avcodec_decode_audio(AVCodecContext *avctx, INT16 *samples,
int *frame_size_ptr,
UINT8 *buf, int buf_size)
{
int ret;
ret = avctx->codec->decode(avctx, samples, frame_size_ptr,
buf, buf_size);
avctx->frame_number++;
return ret;
}
int avcodec_close(AVCodecContext *avctx)
{
if (avctx->codec->close)
avctx->codec->close(avctx);
free(avctx->priv_data);
avctx->priv_data = NULL;
avctx->codec = NULL;
return 0;
}
AVCodec *avcodec_find_encoder(enum CodecID id)
{
AVCodec *p;
p = first_avcodec;
while (p) {
if (p->encode != NULL && p->id == id)
return p;
p = p->next;
}
return NULL;
}
AVCodec *avcodec_find_decoder(enum CodecID id)
{
AVCodec *p;
p = first_avcodec;
while (p) {
if (p->decode != NULL && p->id == id)
return p;
p = p->next;
}
return NULL;
}
AVCodec *avcodec_find_decoder_by_name(const char *name)
{
AVCodec *p;
p = first_avcodec;
while (p) {
if (p->decode != NULL && strcmp(name,p->name) == 0)
return p;
p = p->next;
}
return NULL;
}
AVCodec *avcodec_find(enum CodecID id)
{
AVCodec *p;
p = first_avcodec;
while (p) {
if (p->id == id)
return p;
p = p->next;
}
return NULL;
}
void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
{
const char *codec_name;
AVCodec *p;
char buf1[32];
if (encode)
p = avcodec_find_encoder(enc->codec_id);
else
p = avcodec_find_decoder(enc->codec_id);
if (p) {
codec_name = p->name;
} else if (enc->codec_name[0] != '\0') {
codec_name = enc->codec_name;
} else {
/* output avi tags */
if (enc->codec_type == CODEC_TYPE_VIDEO) {
snprintf(buf1, sizeof(buf1), "%c%c%c%c",
enc->codec_tag & 0xff,
(enc->codec_tag >> 8) & 0xff,
(enc->codec_tag >> 16) & 0xff,
(enc->codec_tag >> 24) & 0xff);
} else {
snprintf(buf1, sizeof(buf1), "0x%04x", enc->codec_tag);
}
codec_name = buf1;
}
switch(enc->codec_type) {
case CODEC_TYPE_VIDEO:
snprintf(buf, buf_size,
"Video: %s%s",
codec_name, enc->flags & CODEC_FLAG_HQ ? " (hq)" : "");
if (enc->width) {
snprintf(buf + strlen(buf), buf_size - strlen(buf),
", %dx%d, %0.2f fps",
enc->width, enc->height,
(float)enc->frame_rate / FRAME_RATE_BASE);
}
break;
case CODEC_TYPE_AUDIO:
snprintf(buf, buf_size,
"Audio: %s",
codec_name);
if (enc->sample_rate) {
snprintf(buf + strlen(buf), buf_size - strlen(buf),
", %d Hz, %s",
enc->sample_rate,
enc->channels == 2 ? "stereo" : "mono");
}
break;
default:
abort();
}
if (enc->bit_rate != 0) {
snprintf(buf + strlen(buf), buf_size - strlen(buf),
", %d kb/s", enc->bit_rate / 1000);
}
}
/* must be called before any other functions */
void avcodec_init(void)
{
dsputil_init();
}
/* simple call to use all the codecs */
void avcodec_register_all(void)
{
register_avcodec(&ac3_encoder);
register_avcodec(&mp2_encoder);
register_avcodec(&mpeg1video_encoder);
register_avcodec(&h263_encoder);
register_avcodec(&h263p_encoder);
register_avcodec(&rv10_encoder);
register_avcodec(&mjpeg_encoder);
register_avcodec(&opendivx_encoder);
register_avcodec(&msmpeg4_encoder);
register_avcodec(&pcm_codec);
register_avcodec(&rawvideo_codec);
/* decoders */
register_avcodec(&h263_decoder);
register_avcodec(&opendivx_decoder);
register_avcodec(&msmpeg4_decoder);
register_avcodec(&mpeg_decoder);
register_avcodec(&h263i_decoder);
register_avcodec(&rv10_decoder);
}
static int encode_init(AVCodecContext *s)
{
return 0;
}
static int decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
UINT8 *buf, int buf_size)
{
return -1;
}
static int encode_frame(AVCodecContext *avctx,
unsigned char *frame, int buf_size, void *data)
{
return -1;
}
/* dummy pcm codec */
AVCodec pcm_codec = {
"pcm",
CODEC_TYPE_AUDIO,
CODEC_ID_PCM,
0,
encode_init,
encode_frame,
NULL,
decode_frame,
};
AVCodec rawvideo_codec = {
"rawvideo",
CODEC_TYPE_VIDEO,
CODEC_ID_RAWVIDEO,
0,
encode_init,
encode_frame,
NULL,
decode_frame,
};