diff options
216 files changed, 58871 insertions, 0 deletions
diff --git a/DOCS/AUTHORS b/DOCS/AUTHORS new file mode 100644 index 0000000000..d1ae5a9737 --- /dev/null +++ b/DOCS/AUTHORS @@ -0,0 +1,78 @@ + AUTHORS: + ~~~~~~~~ + +====================== The MPlayer project: =========================== + +Arpád Gereöffy (A'rpi/ESP-team): <arpi@thot.banki.hu> +- player code (mpeg stream demultiplexer and avi/asf parser, A-V sync, seek...) +- mp3lib, based on mpg123 sources [MP3 audio decoder] +- getch2 [keyboard handler] +- some changes in libmpeg2 code (progressive frames, bitrate & fps support) +- libvo improvements: adding OpenGL support, bugfix in mga driver... +- YUY2 support into mga_vid driver (for DivX/MPEG4) +- YUY2, RGB/BGR 15/16/24/32 support into libvo drivers (for AVI codecs) +- scripts in the TVout directory (allows using TVout on Matrox G400 DH on fb) +- hacking DivX/Mpeg4 VfW codecs to get YUV output +- opendivx decoder speed optimizations (see opendivx/ChangeLog) + +Zoltán Ponekker (Pontscho/Fresh!): <pontscho@makacs.poliod.hu> +- configure script and Makefiles for easy compile +- GUI system (coming soon!) +- 3DNow! support into mp3lib +- various X11 driver changes (keyboard handling, fullscreen, bpp detect, etc) +- libvo: adding xmga driver (similar to Xv but works under X3.3.x) + +Gábor Lénárt (LGB): <lgb@supervisor.hu> +- testing and some improvements in mpeg player's user interface (options) +- ./configure script improvements + +Gabucino: <gabucino@k2.jozsef.kando.hu> +- web design, docs improvements/updating +- testing, (Open)DivX encoding, picture quality comparsions + +Dariusz Pietrzak: <dariush@ajax.umcs.lublin.pl> +- mailing lists hosting (see README for details) + +Main testers: + Gabucino + Balazs Tibor (Tibcu) + Sasi Peter (SaPe) + Christoph H. Lampert + +========================== The Codecs: =================================== + +Aaron Holtzman: <aholtzma@engr.uvic.ca> +- ac3dec (and libac3) author [AC3 audio decoder] +- mga_vid driver [Matrox G200/G400 YUV Back-end Scaler] +- mpeg2dec [Fast MPEG1/MPEG2 video decoder, currently used in player] + +Michel Lespinasse: <walken@zoy.org> +- did large libmpeg2 changes for better speed and mpeg conformance + +Eugene Kuznetsov: <divx@euro.ru> +- avifile author [AVI player library for linux, using Win32 VfW/ACM codecs] +- technical help about AVI and ASF formats, and how to get YUV using VfW... + +Project Mayo: [http://www.projectmayo.com] +- the OpenDivX codec authors + +Michael Hipp: +- mpg123 author [free mpeg audio player, isn't used directly but in mp3lib] + +Mark Podlipec: +- xanim author [i'm using its aLaw audio decoder] + +Jutta Degener and Carsten Bormann: +- xa_gsm.c authors [MS-GSM audio codec] + +Their code is not used in current player version, but I've got some ideas or +other technical help from: + +John F. McGowan http://www.jmcgowan.com/ +- AVI FAQ author/collector. [site with many useful docs on codecs and avi fmt] + +Dirk Farin: <farin@ti.uni-mannheim.de> +- dvdview author [MPEG1/MPEG2 video decoder, used in v0.5-v0.8] + +Adam Williams: <broadcast@earthling.net> +- libmpeg3 (and xmovie) author [MPEG1/MPEG2 video decoder, used in v0.1-v0.4] diff --git a/DOCS/ChangeLog b/DOCS/ChangeLog new file mode 100644 index 0000000000..3daeaea322 --- /dev/null +++ b/DOCS/ChangeLog @@ -0,0 +1,479 @@ +ChangeLog: +~~~~~~~~~~ + +v0.12-pre1: [ not yet released ] + - ffmpeg included into source tree + +=========================================================================== +Note: If you've sent patches not applied in pre22, please send them again! +/|\ (I've got tons of mails last weeks, and can't re-read all of them) +/~\ Please include in the Subject: MPLAYER-PATCH +=========================================================================== + +*** 0.11 release is coming SOON!!! *** + +v0.11-pre25: small fixes again :( + - DOCS updated (email address changed from arpi@* -> maillist) + - LIRC fix, mplayer_lirc changed back to mplayer [Andreas Ackermann] + - stream.c: unsigned int fixes, required for some strange .asf files + - asfheader.c: using w=h=b=1 for audio_concealment_none + - VCD-related stuff moved from stream.c to vcd_read.c + +v0.11-pre24: small fixes again :( + - DOCS/LIRC changed: users *must* enable lirc support manually, it is + not autodetected yet. (./configure --enable-lirc) + - the {prefix} bug fixed by Gabucino + - added manpage by Gabucino + - manpage -vo fixes by A'rpi + +v0.11-pre23: lirc support, text updates, mailinglists + - added "-ni" option to force usage of the non-interleaved AVI parser + - DOCS/* updated by Gabucino + - new homepage by Gabucino + - mplayer users & announce mailing lists by Dariusz Pietrzak (see README) + - LIRC support by Andreas Ackermann (see DOCS/LIRC) + enable with ./configure --enable-lirc + TODO: ./configure should detect LIRC installed and better Makefile handling + - added AVI_NINI parser for broken (no index) non-interleaved files + +v0.11-pre22: last fixes, release is coming soon! + - non-interleaved avi EOF bug fixed [thanks to DC-1 for help] + - "You" strings in Makefile after make dep bug fixed... [thx to DC-1] + - SDL disabled by default. You have to ./configure --enable-sdl to enable. + - homepage updated by Gabucino + - homepage updated by A'rpi + - FAQ updated by A'rpi + +fork() -> 0.12pre1 + +v0.11-pre21: mpeg1 pp, stereo fix + - "Skip chunk xxxx" messages moved from -v to -v -v -v debug level... + [thanks to Christoph H. Lampert] + - divx postprocess filter works for mpeg1 files too! (-divxq 1/3/7/31) + - mpeg layer-2 audio fixed - it's stereo again!!! + - audio select() detection: if detected audio buffer size == 0, then + exit with message "recompile mplayer with #undef HAVE_AUDIO_SELECT"... + - syncfb driver added to the source tree, under drivers/ + (it's very similar to mga_vid, but has syncronization to screen and + de-interlace features) + - draw_slice in syncfb finished for G400 cards (plays mpeg 1/2, opendivx) + (de-interlacing has been disabled, because it's buggy now) + +v0.11-pre20: NI-AVI support, small fixes & patches... + - asf parser: flag 0x40 (explicit packet size) implemented [Marvin] + - new option to select DSP device: -dsp (default: /dev/dsp) [Pontscho] + - option -o changed to -vo + - ./configure: applied patches [LGB,Ian Kumlien,Magnus Pfeffer] + - avi chunk_id->ds mapper moved to demux_avi_select_stream() + - added non-interleaved .AVI parser + - added non-interleaved .AVI detection (if a_pos-v_pos distance > 1MB) + +v0.11-pre19: small fixes... + - vo_xmga.c: G200 draw_slice fixed + xmga + mga: common part (draw_frame & draw_slice) moved to mga_common.c + - some independent code (asfinfo.c and GL-test) moved to the new TOOLS subdir + - movinfo.c added to TOOLS (small util to dump .mov file structure) + - AVI & ASF stream id detection changed: now using IDs from the header + (but still can be overriden by -aid or -vid) [Christoph H. Lampert] + - native MS-GSM audio codec ported from avifile source (-afm 6) + [thanks for the testfile to Christoph H. Lampert] + - README updated (input & codec lists) + - implemented .asf audio descrambling [Dirk Vornheder & Einon] + -> that weird_al_yankovic asf is not so weird now :) + - AUTHORS file changed + +v0.11-pre18: patch release :) + - skip broken .asf fragments (for better seeking) + - seeking code cleanup in sources (now it's in a switch(){}) + - opendivx encoding bitrate option changed from -divxq to -br + (for the divx -> divx re-encoding) + - TO DO section moved to file TODO + - applied ./configure and Makefile changes patch from LGB + - libvo function changes by Pontscho: x11 (with -fs), xmga (bugfixed!) + - libvo: driver sources renamed from video_out_*.c -> vo_*.c + - libvo: added uninit() function to drivers + - libvo: fork()'ed X11 eventhandler for x11 and xmga drivers [me & Pontscho] + (gl and xv version is coming soon!) + - libvo: sdl driver now closes SDL at QUIT... + - small english fixes (docs & messages) [Balazs Tibor] + +v0.11-pre17: fixes + - asf "missing video stream" fixed (stream id & 0x7F) [Christoph H. Lampert] + - added GL-test directory, it contains source and compiler script of a + very simple open-gl texture updating (glTexSubImage) test program. + if it runs well, then mplayer -o gl should work too. + it works on G400+Utah-GLX, but segfaults in the G400 driver of X 4.0.2/DRI. + try it with different cards/drivers, and please report me the results. + - benchmarking in gltest.c: calculate fps and process times + - .asf seeking v0.01-pre0.1 :) + +v0.11-pre16: ACM fixed + - Win32/ACM audio codec fixed (most important for asf with divx audio): + There was an output buffer size problem with the Win32/ACM audio codec + at low bitrates (usually used for .asf files with divx audio) + Input and output buffer sizes are now queryed, problem solved :) + - SDL support compiling hint by Michael Durller added to the FAQ + - opendivx support in .asf files [Gérard Lantau] + - ./configure & Makefiles patch by Aaron Hope applied. + (adds --with-win32libdir and fixes --with-x11libdir) + - ./configure fixed, now it defaults to /usr/lib/win32 if detection failed + +v0.11-pre15: asf sync fixed + - asf parser: now supports other than 0x5D segments [Dirk Vornheder] + - new asf PTS reading: sync works now, including fps... + (-fps no longer required!) [thanks again to Eugene Kuznetsov for docs!] + +v0.11-pre14: small fixes, asf sync v0.1 :) + - version number incremented :))) + - libvo / Xv driver swapped Red-Blue fixed + - asf timestamps implemented - now asf A-V should be in sync if you + specify the correct fps at commandline (-fps), +-1 fps allowed... + [i haven't yet found method to get fps out from asf headers :(((] + - some error and consistency checking into demux_asf + if you see many warning! messages playing an .asf file, then contact + me and upload the file (first 1MB is enough if it represents the problem) + Don't forget: there is no public doc about the .asf file format, so + everything we know is suspected and can be wrong... without your help + we never will have working .asf player... + - asf fragment offset checks disabled for grouping... + +v0.11-pre13: libvo changes, mpeg bitrate, vcd fix, asf grouping + - libvo: draw_slice() interface changed, now it has src stride[3] and + destination rect dimension (w,h,x,y) + It's able to blit whole frames, not only 16-pixel slices... + - libmpeg2 and opendivx codec changed to use new draw_slice() + -> opendivx extra 64-pixel width band at right disappeared! + - mpeg bitrate fix: if picture->bitrate==0x3FFFF (means "unspecified" ?) + then using standard VCD bitrate (75*2324 bytes/sec) + -> fixed seeking for those mpegs with "16MBit/s" bitrate... + - drivers/sis_vid: video4linux interface disabled + - broken VCD playing fixed: stream_reset shouldn't seek to 0x0... + [bugreport: Kang Sun] + - asf_parser: grouping implemented! [test file provided by Gabucino :))] + +v0.11-pre12: ./configure fixes, improved odivx-encoding, streaming fixes + - ./configure: using /tmp/main$$.c instead /tmp.main.c, and + remove file after tests [SaPe] + - ./configure: trying the gcc optimize options and fallback to 'pentium' + if fails (useful for people with old gcc and new cpu :)) + - removed -fomit-frame-pointer from OPTFLAGS at config.mak + - version number incremented [Gabucino] + - odivx encoder fix: allow long (longer than xxxx.avi) destination filenames + (sizeof() changed to strlen()...) [Gabucino] + - avi writer - overwrite disabled (exits with error message if destination + file already exists...) [Gabucino] + - use -divxq to set encoding bitrate (in bits (no kbits!) default: 780000) + - no audio decoding if -encode option is used + - audio streaming disabled if -nosound specified (setting audio_id to -2) + - fast Mpeg-ES detection (doesn't read the whole Mpeg-PS file) + - compile-time option to disable using soundcard driver's select() + (requires for some people with buggy/pre-alpha/etc sound driver...) + +v0.11-pre11: streaming fixes, asf support pre, indeo5 fix + - asf/asfinfo.c improved: now it dumps streams to files - need testing! + (it's ready to be converted to asf demuxer and intergated into MPlayer) + - stream.c / stream_reset() fix: now it really seek back to 0 position! + - .asf file format detection added (no .asf reading yet!!!) + - .asf demultiplexer added, changes in demuxer.c to handle fragmented packets + > it plays .asf video well, but still has problems with divx/wma audio. :((( + - indeo 5 playing fixed (removed ICDECOMPRESS_UPDATE from flags) + - xmga resizing problems with some window managers, so default order is + changed xmga,xma... to mga,xmga,... + - found gcc bug: compiling MPlayer with flags + OPTFLAGS=-O -g -march=i686 -mcpu=i686 -pipe -fomit-frame-pointer -ffast-math + cause image sizes negating -> mga_vid kernel driver Oops... :((( + - runaway.bride.sample.avi seeking segfault discovered: AC3 resync fails :( + - improved signal handling: module name is now printed. audio_resync added. + - RGB opendivx encoding implemented, now AVI->opendivx is possible. + +v0.11-pre10: OpenDivX encoding, streaming fixes, avi seek fixes + - new libvo driver: odivx (OpenDivX File Writer) + - AVI file writting support, new option: -encode filename + to encode an mpeg/vob/vcd to opendivx: + mplayer file1.mpg -encode file2.avi -o odivx -nosound + (sound encoding/copy is not yet supported) + - libvo: default driver priority changed to: xmga,mga,syncfb,3dfx,xv,x11,gl + - avi writer: index support + - small fixes in avi writer to be compliant (adjusted chunk/list lengths) + - demuxer.c: stream buffering fixes: + - missing {} in mplayer.c occuring audio reads when has_audio=0 + - reordered packet reader and pack count checks -> no more unwanted EOF + - added 4MB buffer memory usage limit to demuxed streams + - CPU flags in ./configure changed: + k7 -> k6 (current stable gcc doesn't supports k7) + 386,486 -> i386,i486 [Balazs Tibor] + - demux_avi: index check now accepts (raw.len+1)==idx.len [Balazs Tibor] + - FAQ added + + ** Now we are ready with planned features & urgent fixes, ** + ** it's time to final testing and then the 0.11 release!! ** + +v0.11-pre9: OpenDivX fixes,speedup + - solved OpenDivX width problem (stride=width+(Quality?0:64)) + now -divxq 0 works, and 0 is the default + - libvo call moved out from my_convert_yuv() so it can be measured (cpu %) + - IDCT code ported from libmpeg2 -> much faster OpenDivX decoding + +v0.11-pre8: SDL fixes, OpenDivX support + - added -I/usr/X11R6/include to libvo CFLAGS + - (removed later: applied libvo SDL driver fixes by Jeffrey Boser) + - OpenDivX support, initial hack, maybe not work for you... + (I need testfiles, I have just only one) + use -divxq option to adjust quality (1..29 works), 1=default + +v0.11-pre7: SDL support + - ported SDL driver from mpeg2dec/libvo (currect CVS) + (it's slower than internal X11 driver, but supports software scaling!) + - fixed SDL driver to support -fs and pass keyboard events + - SDL driver changed to support YV12 and YUY2 formats instead of IYUV + (now works with DivX files too) + - 'q' (Quit) disabled in SDL fullscreen mode (because it's impossible + to restore screen before exiting so it gets unusable state now) + +v0.11-pre6: audio fix + - fixed video_out_xv.c compiling problems [bugreport: Kalle Mellerup] + - modified audio playing: always keep buffer (both internal and card's) + filled using select() -> -alsa audio delays should be fixed. + - updated DOCS/AUTHORS and DOCS/README + +v0.11-pre5: xmmp audio support, applied Pontscho's libvo patch + - xmmp audio driver support by Arthur Kleer + - new video_out driver by Pontscho: xmga (Matrox G200/G400 only!) + It does same under X 3.3.x what Xv extension does under X 4.0.x! + (you will have a moveable/resizeable window but see an YUV video + overlay in it using color keying) + - added keyboard event support in X11 windows [Pontscho] + (using mplayer_[put|get]_key() in codecctrl.c) + +v0.11-pre4: x11 driver fixes, 15/16bpp support + - version in version.h fixed :))) [Pontscho] + - inttypes.h moved to DOCS/ (copy back to the root if you need it) + - depth calculation in vo_init() changed (Pontscho's version couldn't + make difference between 15 and 16bpp) + - x11 driver now uses vo_init() instead of get_depth() + - yuv2mmx: 15bpp not really supported -> removed from list, now + conversion is done (well) by the C code -> MPEG play in 15bpp works! + - avi playing support added in 15bpp (memcpy) + - avi playing support added in 16bpp (C 15->16 converter by me) + - avi playing support added in 16bpp (MMX 15->16 converter by Strepto) + - libvo/x11: yuv2rgb used MMX code on non-MMX CPUs too!!! fixed... + - all x11 modes tested (and mpeg/24bpp byteorder fixed): + MPEG: AVI/VfW: + 15bpp C convert memcpy + 16bpp MMX/C convert MMX/C convert + 24bpp C convert memcpy + 32bpp MMX/C convert memcpy / C conv. + => now all the movie types are viewable using the -o x11 driver! + +v0.11-pre3: mpeg fixes, fullscreen support + - vertical.mpg serious libvo (x11,gl) segfaults fixed: + yuv2rgb_mmx requires one more lines that vertical image size... + fixed (allocating memory for width*(height+1)). [bugreport: Gabucino] + - Pontscho's fullscreen patch applied! + Using option -fs will maximize window size (for all resizeable drivers + including mga!) and disable window decorations (x11,Xv,gl only) + - simple inttypes.h included for libc5 (and glibc2.0 too?) users + - homepage updates (links changed ftp->http) + +v0.11-pre2: better user messages, mp3 codec selection, demuxer changes + - w32codec.zip restored at the FTP site (somehow it damaged...) + - added version.h, and used its content everywhere + - 'premature end-of-file' problem fixed: freeing audio buffers and + setting d_audio->id=-2 if has_audio==0 [bugreport by Dmitri Pogosyan] + - some more messages added if verbose>=1 + - demuxer.c: error message printed if A or V chunk buffer is full + 'mplayer test.avi -aid -2' still not works without option '-nosound' + - adding new config.h option to set default MP3 audio codec (mpg123/l3codeca) + ./configure selects mp3lib only if you have 3Dnow [idea: Gabucino] + - automatic fallback to mp3lib/mpg123 if l3codeca.acm can't be loaded/inited + +v0.11-pre1: AVI sync fixes + - AVI audio seeking improvements: now using nBlockAlign value to seek + inside the chunk, so divx audio works without big delays!!! + - AVI PTS calculation modified: counting video PTS when skip_video_frames>0 + so new audio PTS values will be correct. Solved many sync probs! + - A-V sync with AVI files fixed! + Now only the Desperado-trailer has 1.0 sec delay after seeking. + - fixed AVI sync in -bps mode too! :) (perfect except that Desperado avi) + +v0.10: The new year release! + - testing + - docs changed + - it's time to release and remove the old buggy 0.09 version... + - release!!! + +v0.10-pre8: libvo/x11 changes + - libvo: x11/xv driver separated to x11 and xv drivers + - libvo: DUMMY_VO_FUNC removed from driver sources + - libvo: default driver order changed, because some users with software-only + opengl though that this 'slow' player can only play at 1-3fps :) + +v0.10-pre7: libmpeg2 interface changes, display size/area changes, AVI fixes + - libmpeg2/decode.c modified: + - removed unused OMS and mpeg2dec stuff + - decode_data rewritten, now works like parse_es.c + => doesn't copy any data -> faster and less memory usage + - mplayer.c sends code 0x1FF after every frame, so libmpeg2 knows + when has to display it + - mplayer.c: in_frame flag fixes, didn't work well with mpeg2 streams + (because there is a 0x1B2 chunk between 0x100 and 0x101) + - 'picture' changed from static to shmem-allocated + -> better picture after codec restart (tested with JapAd.mpg) + -> keep information of the header changes (after init) + - mpeg image size changed, now only the real part of frame is displayed + (no more green strip at the bottom) + - picture struct: new fields: display_picture_width/height + - image buffer allocation (shmem) is done by decode.c instead of libvo + - new option: -xy <value> (resize both x/y direction) + if value<=8 -> x_scale = y_scale = value + else -> x_size=value y_size=aspectratio*x_size + - mplayer.c: video output moved out from avi/mpg init sections and + now it's common code (added movie_size_x/y variables and out_fmt global) + - new keys: + ESC => quit + + and - => adjust audio delay +- 0.1 second + k => kill/restart the mpeg codec process (for testing) + - codec control interface changed: wait for syncword after (re)start + to avoid receiving old frames => it's stable again! + - removed (now unused) allocate/free image buffer code from libvo + - mplayer: new internal variable for video format: has_video + 0 = none (unused yet) + 1 = mpeg 1/2 video + 2 = win32/VfW video codec + - config.h has defaults for bps-based AVI sync and ALSA timer code options: + #undef AVI_SYNC_BPS => now it's disabled by default!!! use -bps to enable + #define ALSA_TIMER => now it's enabled by default!!! use -noalsa to dis. + - help updated + - prints max compressed framesize at exit (both avi & mpeg) + - AVI audio seeking fixed: some ACM codecs (divx audio and ms-adpcm) + can't seek inside a chunk, they are only able to play whole chunks. + Current audio seeking has changed to seek inside the chunk only if the + codec supports it (only internal codecs and ACM/mp3 allows it). + - AVI: audio delay correction if can't seek inside the chunk + +v0.10-pre6: mpeg signal & EOF fixes + - ./configure: k6_mtrr (2.4.test11+) added [Pontscho] + - `term destroys if mplayer (mpg) called from mc.ext` bug fixed: + added sighandler to the 3rd process (mpeg codec) to avoid sig. recursion + - better output at exit (handled now by exit_player()) + - mpeg EOF problem (codec restart) fixed: added EOF detection to parse_es.c + - internal flag 'current_module' added to get more info at segfaults + (contains module number where the segfault occured) + - audio detection changed: using afm=4 (Win32/ACM) for MP3 audio (AVI files) + (you MUST have l3codeca.acm at /usr/lib/win32, or you have to use '-afm 1') + +v0.10-pre5: flipping fixed + - AVI image flipping reworked: + - new flag: avi_header.flipped, TRUE if upside-down + - image flipping code removed/disabled from libvo modules + - duplicate flip_page() calls removed (overload with x11 and mga) + - aLaw audio codec (AVI id 0x06) added (uses code from xanim source) + +v0.10-pre4: test release, small fixes + - video_out driver <-> codec incompatibility message changed + - fixed the config.format bug in drivers/mga_vid_test, so it works again! + [thanks to David Whysong] + - libmpeg2 upgraded + +v0.10-pre3: test release, verbose mode, new docs + - new option: -v = increment verbose level + (debug printf's changed to verbose level-dependent) + - default level: 0, only some informal output + - init debug: 1, some basic debug infos, avi header, function values + - player debug: 2, print avi indexes, chunk inputs, more debug infos + - parser debug: 3, prints everything related to input parsers + to increment verbose level, use multiple -v options (-v -v -v for level-3) + - bitrate calculation for AVI files + - README rewritten, added Troubleshooting and Bugreports sections + - TVout directory added (only the scripts) + +v0.10-pre2: bugfix test release, bps-sync enabled + - avi: supporting both 0-based and movi-based index types (autodetect) + - avi: tested with VBR audio: plays well with -mc 0 option, seek doesn't + work yet [thanks to Alan Chen for testfile] + - avi: A-V sync to avg. byte/sec implemented (again) and enabled by default + (disable with -nobps if you want) + - ./configire: 3rd name ('kni') of the P3 added. Where is the compatibility? + - useless '\' removed from libac3/Makefile [Otvos Ferenc] + +v0.10-pre1: test release, players merged!!! + - avip and mpegp has been merged to a single binary called 'mplayer' + - file type detection (AVI/MPEG-PS/MPEG-ES/Other) + - no redundant code (common code for common jobs) + - big format-dependent codes moved to functions (separated files) + - better error messages, removed some debug stuff, code cleanups + - old libmpeg2 version removed from source tree + - help texts merged (help_avi+help_mpg -> help_mp) + - new options: -x <x> -y <y> = scale image (if selected driver supports) + if value<=8 then image size will be multiplied by value, otherwise + image size will be scaled to <value> pixels. + For example: + 2x ZOOM: mplayer -x 2 -y 2 test.mpg + 800x600: mplayer -x 800 -y 600 test.mpg + [default values are still configurable at compile-time, see config.h] + - TV project (not finished) codebase added (see tvision.c, or: make tvision) + +v0.09: Beta release [same as 0.09-pre3] + - version changed in the files + - docs updated + +v0.09-pre3: bugfix test-release, X11 support testing + - fixed the if [ -z $pparam ] bug in ./configure [Christian Birchinger] + - many changes in AVI seek code, resulting near-perfect seeking now! + current method calc absolute audio position, so with VBR audio it + doesn't work yet... + - avip: Xv support (YUY2 image format) + - avip: X11 support (24 & 32 bpp only, BGR format) + I need a very fast 15->16bpp converter for 16bpp support... anyone helps? + +v0.09-pre2: bugfix test-release + - removed unnecessary code from libmpeg2/header.c + Walken told me that standard mpg/vob streams must NOT use framerate + and bitrate extension... and the ext. id check is done by the caller. + - CRC support to mp3lib's mpeg audio layer-2 decoder + thanks for bugreport & testfile to Samson + +v0.09-pre1: bugfix test-release + - imported new libmpeg2 files (under testing...) + - GL renderer flickering bug fixed (MMX missing emms() between yuv2rgb and + glTexSubImage(), bug triggered by new Utah-GLX code) + [thanks for Christian Birchinger] + +v0.08: Index support, avi seeking, DLL loader fix, compilation fixes + - Added support for chunk index usage (disable with -noidx option) + - Removed code optimization flags from loader/Makefile because + it segfaults if compile optimized code (it does some hacks with + pointers, maybe the reordered code confuses it) + - added new tool called aviparse (read and check avi file structure) + - indexed and raw chunk info comparing, bad chunks dropped + - termcap usage is optional (for those debian users without termcap) + - #if HAVE_* fixed (to #ifdef HAVE_*) + - ./configure supports new /proc/cpuinfo (2.4.0-test11) + - sse is called 'sse' again + - 'flags' field renamed to 'features' + - Xv benchmark results added to DOCS/SPEED + - avi seeking (and other goodies, pause etc) implemented + no PTS resync after seek yet. + - default video_out driver changed from 'mga' to the first available driver + new driver priority: mga_vid, opengl, x11 + +v0.07: Easier compile + - Added Pontscho's ./configure script (it's modified a lot) + - Updated makefiles, and tested a lot :) + - Updated DOCS/INSTALL + +v0.06: Better codec selection + - avi audio&video codec selection moved to new codecs.c file, + loader/driver.c and loader/afl.c modified for this + - yuv support fixed, codecs.c setup flags to handle yuv properly + yuv works fine with divx, mpeg4, cvid, and upside-down iv50 + - DOCS/INSTALL updated + - DOCS/SPEED updated, DivX benchmarks added + +v0.05: Merged with MPEGplayer 0.90pre6, first public release of AVI player + - code merged with mpegplayer, new Makefile, some small modifications + - docs updated and moved to DOCS + +v0.04: YUV support, some code cleanup, preview-release + +v0.01: first version based on new MPEGplayer's codebase. diff --git a/DOCS/ChangeLog.mpeg b/DOCS/ChangeLog.mpeg new file mode 100644 index 0000000000..265a57c16b --- /dev/null +++ b/DOCS/ChangeLog.mpeg @@ -0,0 +1,232 @@ +ChangeLog: +~~~~~~~~~~ +v0.2: [first public release] +- parser: add support for VOB files (audio format still has problems...) +- libmpeg3: improvements in file-type detector, supporting mpegs with RIFF hdr +- libmpeg3: improvements on mpeg3_read_program() to handle damaged files better +- libmpeg3: new functions for separated PTS access: mpeg3_audio_pts() and + mpeg3_video_pts(), they return timestamp in seconds, format: double +- play: new audio-video sync method, using timestamps from streams. + much better, even on very damaged files! +- play: measuring of audio buffer size instead constant hard-wired value +- libmpeg3: more improvements to handle better strange files... +- play: drop timestamp correction if > 2 seconds (good for concatenated files) + +v0.3: +- much better audio-video sync, using limited timestamp correction +- TVout directory added, with tools & scripts to setup TVout on Matrox cards + (it is able to play mpegs fullscreen on TV without using X) + +v0.5: +- integrating dvdview for video decoding + (still using libmpeg3 for system stream parsing and audio decoding) + -> not works... some variable randomly changes (uninitialized pointers + in dvdview??? c++/c mixing problem?) + +v0.6: +- new player from scratch, using my mp3lib for audio, parser.c for demuxing. + integrated dvdview is still buggy... + +v0.7: [second edition] +- dvdview as separated process, using FIFOs for communication. +- some fixes in dvdview/system/sysdec1.cc, improved re-syncing on reset +- double-buffering support into dvdview's mga_vid class (and some + changes in the mga_vid kernel module too!) +- EOF problem solved +- background playing option (using MGA Color-Keying and xsetroot) +- rebuild README, added Standard Disclaimer section + +v0.71: +- better missing-stream detection (counting only the real packets) +- check for file and missing streams before fork() +- fixed ugly byteorder bug when reading header dword +- new system stream sync method (doesn't requires SYSTEM_HEADER_START_CODE) +- seeking (byte or second pos), works *only* with streams with immediate + SYSTEM_HEADER frames. + +v0.8: [seeking works] +- implementing own video packet reader -> disabling the whole streaming part + of dvdview. +- saving system headers, and re-sent after starting dvdview (seeking/resync) + -> allow seeking in single-header mpeg files (contact2.mpg) +- advanced resync and seek_sec method, using video-packet type-checks +- fix read() problem, when not enough bytes available in fifo (see man 2 read) +- removed unused objects (postproc,options,streaming) from dvdview's Makefile + (smaller executable, faster compile) +- sec. and bytepos seek fixed, works well now. +- simple console gui, using my getch2 (from mailer3 source) for keyboard. + allows seek,pause,quit functions (for testing only) + it's time to begin develop some nice GUI with skins, plugins etc :) +- improved runtime seeking, added force_redraw variable, and PTS audio + correction after every seek. + +v0.81: +- fps fixed (other than 25fps supported again) +- EOF handling fixed again +- nosound support (currently only system streams supported, not video-only) + also see -nosound commandline option +- mga_vid: changed mmap() to allow double buffering in 704x528 +- mga_vid: double buffering is optional from now (dvdview option -db ) +* it successfully plays .VOB files (without sound) +- PTS/DTS support in mpeg-2 system streams (.vob files) +- PCM audio (48kHz stereo, unsigned, swapped byteorder) playing implemented +* it "plays" .VOB files with PCM sound, but it's too sloooooow :((( +- some optimization of dvdview's bitstream handler (see FillBits & GetBitsFast) + +v0.82: [VOB support] +- updated dvdview from current CVS version (1.2.0-pre) -> about 25% faster!!! +* it's now fast enough for VOB playback +- AC3 audio support (using Aaron Holtzman's libac3 from ac3dec package) +- new, simpler Makefile for libac3 +- re-organized text files (README splitted to ChangeLog and AUTHORS) + +v0.83: [ALSA support] +- some timing code to fix audio syncing with ALSA drivers (test it! I can't) + use -alsa cmdline option to enable this experimental code! +- cmdline option (-abs) for overriding audio buffer size (default: measured) + why is it needed? some audio drivers has bad implementaion of select(), + so measuring buffer size gives false result. + if you hear sound before picture window appears, then you should use this! + +v0.84: +- multiple DVD audio channels/streams support (use -aid option to select chn.) +- cmdline option for maximum PTS time correction (-mc <value>) +- PTS sync code moved to frame display loop -> more precise timing + now it sync audio after every 5 decoded frames +- cmdline option for override frame rate (-fps <rate>) + some .VOB files has bad frame rate value in headers (why? any ideas?) +- ac3 audio seeking works (some hack in libac3's parse.c) + +v0.85: [first non-experimental release] +- directory structure changed +- better documentation, added new INSTALL +- every Makefile uses OPTFLAGS environment variable, see INSTALL +- help (run mpg12play without any parameters or with -h/--help) +- fixed byte seeking (-sb) +- allow selecting mpeg audio channel, see -aid (streams 0x1C0-1DF) +- allow selecting video channel, see -vid (0x1E0-1EF) +- allow audio format override, see -afm +- new streaming system (with 4k buffering) +- initial VCD (Video CD) support, use -vcd to select track, and give + device name as filename (e.g.: mpg12play -vcd 2 /dev/cdrom) + Problems with dual streaming, it's very slow! reads every sectors twice... +- VCD cache system... -> solved dual (A+V) streaming slowdown + +v0.86: [cleanup] +- last_frame_* thing removed + control fifo read() fixed -> better and + linear (no seek-back) resync if dvdview dies +- better nosound timing (uses -alsa timer), seeking works +- resync_to_pts eliminated (using new max_pts_correction) +- cleanups, error checks, small fixes in the whole player.c +- removed some unused old code +- exit code moved to exit_player(), removed redundancy, fixed kill order + +v0.87: +- i've found the reason of bad fps value with some vob files... + the fps is correct, but the dvdview doesn't decode all the frames + (reads repeat_first_field flag but don't rely on it) +- new demuxer code: read & demux input stream only at once, and uses two + memory FIFO-s for packages. also new reader code, everyting named ds_*() + The new demuxer can autodetect video and audio stream ids, if not + specified with -aid / -vid option, and better implementation of -afm +- vcd cache is optional (and disabled by default), because unneccesary with + new demux/streaming code + +v0.90pre: +- new codec added: mpeg2dec by Aaron Holtzman + after doing some fixes (see at bottom), it's able to play mpeg1/mpeg2 video +- FIFO API changed: after frame_complete command (0x0) the codec must + send the fps*10000 and the length*100 value. length is 1.00 for a simple + frame, and >=1 for mpeg2 fields (eliminates the fps problem) + Now, using mpeg2dec we are able to play .vob files with correct fps timing! +- better AC3 resync after seek (new func. in libac3: ac3_bitstream_reset()) + using ac3_decode_frame() instead ds_fill_buffer() when syncing PTS + +v0.90pre2: +- mpeg2dec integrated into player binary +- using pipe() instead of named pipes +- using shared memory (mmap(...MAP_ANON...)) for packet transfer to codec +- stream_select() thing removed +- some optimization in demuxer code +- measuring codec CPU usage (relative to video time!!!, so it can be >100% + on a slow system) This value must be <=100% for continous video playback. + +v0.90pre3: +- ugly bug fixed causing packet loss at codec restarting + (i wrote control_fifo instead of control_fifo2 into codec controller) +- video init part moved to the player +- using shared memory for image buffers to avoid green flashes when + codec restarted... +- new shared memory allocation code (the mmap() thing worked only with + kernel 2.4.x). thanx to LGB for the info and help... see linux/shmem.[ch] +- config.h moved, Makefiles changed a bit (added libvo path, thanx to LGB) + you may select CPU extensions (3Dnow/MMX/SSE) *only* at config.h +- meaningfull error messages if video stream cannot be synced + (many user asked about "missing video stream" error...) + +v0.90pre4: +- included new mpeg2dec source (with SSE idct code) + +v0.90pre5: +- libvo: OpenGL video renderer code by me +- included new mpeg2dec and ac3dec from today CVS snapshot +- new docs: SPEED and MTRR +- seq. head processing and video init code moved into player.c, just + before fork()'ing, so the child inherits all this info! +- removed all sequenceheader[] code, it's unneeded now +- source cleanup, removed some debug printf()'s, old comments +- EOF problem seems to be solved (maybe at the cleanup???) +- implemented bitrate (and free framerate) reading into mpeg2dec/header.c +- seeking skip times are better, based on bitrate + + +Changed in libac3 source: +~~~~~~~~~~~~~~~~~~~~~~~~~ +- ac3.h replaced with the old version from v0.6.0 +- decode.c modified to fit my interface +- stats.h: use stats_* functions only if DEBUG defined + +Changed in libmpeg2 source: +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- header.c: implemented repeat_first_field thing (see picture.repeat_count) +- HACK_MODE set to 1 (default is 0, which works only with mpeg2 streams) +- decode.c: some changes added, active only if MPG12PLAY #defined +- header.c: implemented bitrate (and free framerate) reading + +Changed in libvo source: +~~~~~~~~~~~~~~~~~~~~~~~~ +- fixed bug in mga_vid vo module: used dest_width/height instead src_* + (dst is important only for the card, we need (for memory, etc) the src size!) +- added OpenGL video renderer (based on x11 rendere and Pontscho's opengl code) + +Changed in DVDview source: +~~~~~~~~~~~~~~~~~~~~~~~~~~ +main.cc: replaced with my code +Makefile: removed unneccesary objects, added optimization flags +output/out_mgavid.cc & .hh: added double-buffering and color-keying support +system/userpack.cc & .hh: new code, by me (interface to my packet reader) +video12/vdecoder.hh: added GetSeqHeader() function (for accessing FPS value) +video12/vdecoder.cc: commented out calls to PrintDataBin() (debug info only) + +TODO: +~~~~~ +- multiple video packets (whole frame) transfer to codec - DONE +- B-frame skipping (DVD for slow systems) +- VCD support - DONE +- DVD Audio downsampling (for 44kHz cards) +- SEEKing in VOB files with AC3 sound (some hack needed in libac3) - DONE +- own AC3 frame reader -> better resync after seek - DONE +- player source is really ugly now... it's time to some cleanup - DONE? +- seek/resync without immediate SYSTEM_HEADER frames. - DONE +- end of file detecion !!! - DONE - NOT done (see matrix.vob!) - DONE +- other than 25fps movies - DONE +- test with mono sound - DONE (currently playing as stereo) +- nosound (no audio card or no audio stream) - DONE +- .vob support (non-crypted DVD/mpeg2 stream) - DONE +- AC3 and PCM audio support - DONE +- audio-only and video-only file support +- nice GUI (something new written in gtk or modify xmovie's gui) +- Xv support - DONE (libvo has it) +- easier compile, maybe new ./configure and makefiles - DONE? +- decss support (encrypted dvd) +- test speed with pgcc (does it worth?) diff --git a/DOCS/INSTALL b/DOCS/INSTALL new file mode 100644 index 0000000000..c81b5abda3 --- /dev/null +++ b/DOCS/INSTALL @@ -0,0 +1,29 @@ + ======================================================================= + * HOW TO COMPILE MOVIE PLAYER COMPONENTS * (C) 2000. A'rpi/ESP-team * + ======================================================================= + +Pontscho/Fresh! did some script and makefiles so compiling is much +easier now. If you find a bug in that, please contact us: + pontscho@makacs.poliod.hu + arpi@esp-team.scene.hu + +1. The Player: (mplayer) +~~~~~~~~~~~~~~ + ./configure +[* check config.h and config.mak files! *] + make dep + make + make install + +2. Drivers: (mga_vid.o) +~~~~~~~~~~~~~~~~~~~~~~~ + cd drivers + make + mknod /dev/mga_vid c 178 0 + chmod go+rw /dev/mga_vid + +3. Matrox G400 DH TV-out tools: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + cd TVout + ./compile.sh + diff --git a/DOCS/LIRC b/DOCS/LIRC new file mode 100644 index 0000000000..831ede3c66 --- /dev/null +++ b/DOCS/LIRC @@ -0,0 +1,54 @@ + +LIRC support for MPlayer + written by Andreas Ackermann in 2/2001 + contact: acki@acki-netz.de + +o What is LIRC? + + Linux Infrared Remote Control - use an easy to build home-brewn IR-receiver, + an (almost) arbitrary remote control and control your linux box with it! + More about it at www.lirc.org. + +o MPlayer and LIRC + + If you have installed the lirc-package, you can compile MPlayer with LIRC + support using ./configure --enable-lirc + You should do 'make distclean' before re-compile with 'make dep;make' + + If everything went fine, MPlayer will print a message like + LIRC init was successful. + on startup. If an error occurs it will tell you. If it doens't tell you + anything about LIRC there's no support compiled in. That's it :-) + + The application name for MPlayer is - oh wonder - mplayer. + It understands the following commands: + + PAUSE - pause playing. Any other keystroke will continue replay. + QUIT - exit mplayer + RWND - 10 secs back + FRWND - 60 secs back + FWD - skip 10 secs + FFWD - skip 60 secs + + Don't forget to enable the repeat flag for RWND/FWD in .lircrc. Here's an + excerpt from my .lircrc: + + begin + remote = CU-SX070 + prog = mplayer + button = Tape_Play + repeat = 1 + config = FFWD + end + + begin + remote = CU-SX070 + prog = mplayer + button = Tape_Stop + config = QUIT + end + + Enjoy + + -Andreas + diff --git a/DOCS/MPlayer-FAQ b/DOCS/MPlayer-FAQ new file mode 100644 index 0000000000..40d3ae414d --- /dev/null +++ b/DOCS/MPlayer-FAQ @@ -0,0 +1,120 @@ +Yes, this is the MPlayer FAQ. +============================= + +About: +~~~~~~ +Many people asked same questions so I decided to write this stuff. +I know that people will never read this but at least i try to +pull down number of these mails. +And from now i can say that "read the fuckin' FAQ!" :-) + +Let's ask! +~~~~~~~~~~ +Q: SDL output doesn't work or compile. Problem is .... +A: It works only with SDL v1.1.7 (and maybe newer) + It does NOT work with 1.1.6, 1.1.5 1.1.4 1.1.3 1.0.4 etc, don't ask. + +Q: I am still having trouble compiling with SDL support. gcc says something + about "undefined reference to `SDL_EnableKeyRepeat'" What's now? +A: Where did you install the SDL library? If you installed in /usr/local + (the default) then edit the top level config.mak and add + "-L/usr/local/lib " after "X_LIBS=" Now type make. You're done! + +Q: I have problem ... with the SDL driver. +A: It's very experimental & buggy code, and it's UNSUPPORTED by us. + Please do NOT report bugs or ask features relating to SDL. + But you can improve it, and send us patches! + +Q: It doesn't compile, and it misses uint64_t inttypes.h and similar things... +A: copy DOCS/inttypes.h to MPlayer directory (cp DOCS/inttypes.h .) + try again... if fail, contact me + +Q: I have Pentium III but ./configure doesn't detect SSE +A: Only kernel versions 2.4.x supports SSE + +Q: fullscreen option (-fs) and/or -xy doesn't work with x11 driver (-vo x11) +A: x11 driver doesn't support scaling, and it can't change screen resolution. + Yes, I know that it should be but I have no time to write software + scaling routines and experiencing with XVidMode extension... + You can do it yourself, just press ALT,CTRL,- or ALT,CTRL,+ simultaneously, + see X-server docs for details. + +Q: audio goes out of sync playing .avi file +A: try with -bps or -nobps option + if still bad, send me (upload to ftp) that file, I'll check. + +Q: what is the meaning of numbers in the status line? +A: see: + A: 2.1 V: 2.2 A-V: -0.167 ct: 0.042 57 41% 0% 2.6% 0 + - A: audio position in seconds + - V: video position in seconds + - A-V: audio-video difference in seconds (delay) + - ct: total A-V sync correction done + - frames played (counting from last seek) + - video codec cpu usage in percent (for mpeg it includes video_out too!) + - video_out cpu usage for avi, 0 for mpg (see above) + - audio codec cpu usage in percent + - dropped bad frames (mpg only) + Most of them are for debug purposes, and will be removed soon. + +Q: Why is video_out cpu usage zero (0%) for mpeg files? +A: It's not zero, but it's built in into codec, so can't be measured separated. + You should try to play the file using -vo null and then -vo ... and check + the difference to see video_out speed... + +Q: OpenGL (-vo gl) output doesn't work (hangup/black window/X11 errors) +A: your opengl driver doesn't support dynamic texture chanegs (glTexSubImage) + it's known not to work with X 4.0.x DRI drivers and nVidia's binary shit. + it's known to work with Utah-GLX and Matrox G400 card. + it will not work with 3DFX cards because the 256x256 texture size limit. + +Q: I have g200/g400, how to compile/use mga_vid driver? +A: read INSTALL and README... + +Q: What's XMMP? (it's XMMS or XMPS but mispelled?) +A: It's a new project, see www.frozenproductions.com for details + +Q: There are error messages about file not found /usr/lib/win32/.... +A: Download & install w32codec.zip from *our* FTP + (avifile's codec package has different DLL set) + +Q: It wants to load l3codeca.acm, but I don't have such file. +A: You should use w32codec.zip from MPlayer FTP, instead of avifile's pack! + +Q: ...... works with avifile/aviplay while doesn't with MPlayer +A: MPlayer != avifile + The only common thing between these players is the Win32 DLL loader. + The codecs (dll) sets, syncronization, demultiplexing etc is totaly + different and shouldn't be compared. + If something works with aviplay it doesn't mean that MPlayer should do + it and vice versa. You should contact me, I'll fix the bug!!! + +Q: Indeo 3.x/4.x movies are viewed upside-down!!!? +A: It's a known bug (really it's a bug/limitation of the DLL codec) + +Q: Indeo 3.x,4.x video doesn't work at 32bpp resolutions (16,24 bpp are ok) +A: It's a known bug (really it's a bug/limitation of the DLL codec) + +Q: I've got 'MPlayer interrupted by signal 11' in module audio_setup or + decode_audio. +A: It's a damaged file with bad mp3 audio stream. Try it with -afm 4 + +Q: It aborts with signal 11 playing a file with IMA-ADPCM audio. +A: This codec isn't yet supported! + +Q: Why do you enjoy making that much pre-releases? +A: Download one and you'll know! + +Q: Are there rpm/deb/... packages of MPlayer? +A: Not yet. + +Q: Are there any mailing lists on MPlayer? +A: Yes! See README on how to subscribe them! + +Q: I've found a nasty bug when I tried to play my favourite video!! + Who should I inform? +A: Inform the MPlayer-users mailing list about your problem. *ALWAYS* + read the README about what information we NEED to identify your problem. + Use the developers addresses (specified in AUTHORS) only if you want to + flame, or want to ask for a date. ;) + diff --git a/DOCS/MTRR b/DOCS/MTRR new file mode 100644 index 0000000000..2a4d383462 --- /dev/null +++ b/DOCS/MTRR @@ -0,0 +1,38 @@ +Setting up MTRR for X11 or mga_vid: +=================================== + +1. find the base address +~~~~~~~~~~~~~~~~~~~~~~~~ +You have 3 cases to find it: + +- from X11 startup messages, for example: +(--) SVGA: PCI: Matrox MGA G400 AGP rev 4, Memory @ 0xd8000000, 0xd4000000 +(--) SVGA: Linear framebuffer at 0xD8000000 + +- from /proc/pci (use lspci -v command): +01:00.0 VGA compatible controller: Matrox Graphics, Inc.: Unknown device 0525 + Memory at d8000000 (32-bit, prefetchable) + +- from mga_vid kernel driver messages (use dmesg): +mga_mem_base = d8000000 + +2. find memory size +~~~~~~~~~~~~~~~~~~~ +This is much easier, just convert video ram size to hexadecimal, or +use this table: + 1 MB 0x100000 + 2 MB 0x200000 + 4 MB 0x400000 + 8 MB 0x800000 + 16 MB 0x1000000 + 32 MB 0x2000000 + +3. setting up mtrr +~~~~~~~~~~~~~~~~~~ +You know base address and memory size, let's setup mtrr registers! + + For example, for the matrox card above (base=0xd8000000) with 32MB + ram (size=0x2000000) just execute: +echo "base=0xd8000000 size=0x2000000 type=write-combining" >| /proc/mtrr + +(older K6-2's [around 266Mhz, stepping 0] may not support MTRR.) diff --git a/DOCS/OpenDivX b/DOCS/OpenDivX new file mode 100644 index 0000000000..e7494b80a0 --- /dev/null +++ b/DOCS/OpenDivX @@ -0,0 +1,30 @@ + +OpenDivX support in MPlayer +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +See http://www.projectmayo.com for details on Open DivX codecs. +It's an opensource DivX-like video codec written for windows. +I did a fast hack to get it compile under linux (it has some +dependency on windows header files and some visualc extensions). + +Decoder: +~~~~~~~~ +Now it's used for AVI files with fourcc 'dvx1' +You can adjust Quality level using the -divxq option. Valid values: + + postprcc_level = 0 ----> no post processing (fastest) + postproc_level = 1 ~ 9 ----> horizontal Y deblocking only + postproc_level = 10 ~ 19 ----> hor. + ver. Y deblocking + postproc_level = 20 ~ 29 ----> hor. + ver. Y and hor. C deblocking + postproc_level = 30 ~ 39 ----> hor. + ver. Y and hor.+ver. C deblocking + postproc_level = 40 ~ 49 ----> h+v Y, h+v C deblock and Y deringing + postproc_level = 50 ~ 59 ----> h+v Y, h+v C deblock and Y+C deringing + +Note: last level (Chroma deringing) sometimes crashes. + +Encoder: +~~~~~~~~ +There is a very alpha hack to convert mpeg video into OpenDivX .avi files. +You should disable audio, and select 'odivx' video device as output: + mplayer input.mpg -nosound -vo odivx -encode output.avi +Yes, I know that it's unusable now, it's only for testing purposes. diff --git a/DOCS/README b/DOCS/README new file mode 100644 index 0000000000..cfc9671cd6 --- /dev/null +++ b/DOCS/README @@ -0,0 +1,271 @@ +MoviePlayer v0.11 (C) 2000-2001. by Arpad Gereoffy (A'rpi/ESP-team) +================= * See the file AUTHORS for the complete list! * + +About: +~~~~~~ +Yes. Yet another movie player for linux. +What is the special with this? It works, at least for me :) +I've tried lots of players under linux (mtv,xmps,dvdview,livid/oms,VideoLAN, +xine,xanim,avifile,xmmp) but they all have some problem. Mostly with +special files or with audio/video sync. Most of them is unable to play +both mpeg1, mpeg2 and avi (DivX) files. Many players have image quality +or speed problems too. So I've decided to write/modify one... + +Short history: +- mpg12play v0.1 has born, using libmpeg3 from www.heroinewarrior.com +- mpg12play 2nd generation (v0.5-), using dvdview by Dirk Farin +- mpg12play 3nd generation (v0.9-), using libmpeg2 (mpeg2dec) by Aaron Holtzman +- mplayer has born, containing mpg12play 0.90pre5 and a new simple avi player +- mplayer 0.10, mpeg and avi player in a single binary +- mplayer 0.11: added .asf file support, and OpenDivX en/decoding + +As you see, I didn't write any codecs, just some players. But I spent +a lot of time finding the best way to parse bad damaged input files +(both mpg and avi) and to do perfect A-V sync with seeking ability. +My player is rock solid playing damaged mpeg files (useful for some VCDs), +and it plays bad AVI files which are unplayable with the famous +windows media player. Even AVI files without index chunk are playable! +As you see, stability and quality are the most important things for me, +speed has lower priority, but is still very important. + +What about the GUI? +I'm not a GUI programmer. I hate GUIs, I like the pure black 80x25 console. +So the player has only keyboard control from the controlling console/xterm now. +But there is a GUI development for the player, coordinated by Pontscho/Fresh! +It's still under development, but it will be merged and released soon. +BTW he needs some nice skins, if you are a good graphician, contact him!!! + +Win32 codecs? +Yes, we are using Win32 (Video for Windows) codecs for AVI/ASF decoding. +They must be installed to the /usr/lib/win32/ directory, with all lower case. +You can grab the codecs package from + ftp://thot.banki.hu/esp-team/linux/MPlayer/w32codec.zip +or can be found in your C:\WINDOWS\SYSTEM\ dir, see codecs.c for filenames. +Some people asked why don't we use ActiveMovie/DirectShow codecs. The reason is +simple: we'd have to emulate the whole DirectX architecture and implement the +(patented!) COM interface to be able to use them. BTW the old VfW DivX codec +is faster than the new .AX version, but it has no quality/CPU setting +option (this is an improper name, since it doesn't affect the decoder. If +it's set to 1 or higher, it applies a filter which decreases blockiness and +eats away CPU cycles). + +Supported input formats: +~~~~~~~~~~~~~~~~~~~~~~~~ +- VCD (Video CD) directly from CD-ROM or from CDRwin's .bin image file +- MPEG 1/2 System Stream (PS/VOB) and Elementary Stream (ES) file formats +- RIFF AVI file format +- ASF 1.0 file format + +Supported audio codecs: +~~~~~~~~~~~~~~~~~~~~~~~ +- PCM (uncompressed) audio (8/16 bit, mono/stereo) +- MPEG layer 2/3 audio (using mp3lib, based on mpg123) +- AC3 audio (using ac3dec/libac3) +- Win32 ACM audio codecs (the *.ACM files) [Only in the AVI player] + tested with: DivX audio, MS-ADPCM +- aLaw audio (using code from xanim) +- MS-GSM audio (using modified xa_gsm.c from avifile) + +Supported video codecs: +~~~~~~~~~~~~~~~~~~~~~~~ +- MPEG 1 and MPEG 2 video decoder (using mpeg2dec/libmpeg2, supports + 3DNow! and MMX) +- Win32 ICM (VfW) video codecs (for example DivX using DIVXC32.DLL) +- OpenDivX encore & decore (see ProjectMayo) + +Supported video output devices: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- mga: Matrox G200/G400 hardware YUV overlay via the mga_vid device + (Some people reported that G200 is broken :( if you are a programmer + and you have a G200, please check it and fix if you can!) +- xmga: Matrox G200/G400 overlay (mga_vid) in X11 window + (Xv emulation on X 3.3.x !) +- x11: X11 optionally with SHM extension +- xv: X11 using overlays with the Xvideo extension (hardware YUV & scaling) +- gl: OpenGL renderer, requires Utah-GLX or DRI or nVidia's new driver +- syncfb: Matrox G400 YUV support on framebuffer (not tested, maybe broken) +- 3dfx: Voodoo2/3 hardware YUV (/dev/3dfx) support (not yet tested, maybe broken) +- sdl: SDL v1.1.7 driver (slower than 'x11', but supports software scaling) +- null: Null output (for speed tests/benchmarking) +- pgm: PGM file output (for testing purposes) +- md5: MD5sum output (for mpeg conformance tests) +NOTE: not all are available for AVI files + +Supported audio output devices: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- OSS driver +- ALSA driver with OSS emulation +- ESD with the esddsp utility + +Speed: +~~~~~~ +Most of time-critical parts are optimized for MMX/SSE/3DNow!. +You can improve rendering speed by setting up MTRR registers, see doc in MTRR. +Some benchmark results can be found in the doc file SPEED. + +Usage: +~~~~~~ + mplayer [options] [-vo driver] [path/]filename + + Options: + see mplayer -h for options + see mplayer -vo help for available output drivers + + Keys: + <- or -> seek backward/forward 10 seconds + up or down seek backward/forward 1 minute + p or SPACE pause movie (press any key to continue) + q or ^C stop playing and quit program + + Examples: + mplayer -vo x11 /mnt/Films/Contact/contact2.mpg + mplayer -afm 3 /mnt/DVDtrailers/alien4.vob + mplayer -vcd 2 /dev/cdrom + mplayer -alsa -abs 65536 -delay -0.4 -nobps ~/movies/test.avi + + Note: for using Matrox YUV driver (-vo mga or xmga), you have to first + load the driver: insmod drivers/mga_vid.o + +License: +~~~~~~~~ +Since MPlayer incorporates a lot of code from other projects, this isn't +decided yet. +We're going for GPL (will be pretty hard, though). + +TV output: +~~~~~~~~~~ +If you have a Matrox G400 Dual-Head card, you can watch movies on TV, +using TV-out feature of the second head. You must have matroxfb support +enabled in your kernel (2.4.x kernels). You don't need X11 for this! +Tested only with PAL TV! + + cd TVout + ./modules + ./cloning or ./independ + ./TV-704x528 (or another TV* script) + +Sending bugreports: +~~~~~~~~~~~~~~~~~~~ +First please read all the docs in this package, most of the problems are +described somewhere. At least read the Troubleshooting section! +We don't like answering questions which are already answered in this +readme or other docs. +You should try the latest test (pre) release version too, maybe your bug +is already fixed, but the new version hasn't been released. +If you couldn't solve the problem, then send a quality bugreport +via E-Mail to the MPlayer-users list : mplayer@alan.umcs.lublin.pl + +*NEVER* send attached AVIs, MPEGs, or any big files to this list!!! +Upload them to ftp://thot.banki.hu/incoming , and inform the list about +your upload. + +Please include these: +- your kernel version number ('uname -a') +- linux distribution and glibc version (example: Slackware 7.1 + glibc 2.1.3) +- gcc and binutils version ('gcc -v' and 'as --version') +- your X11 version (example: X 4.0.2 + DRI snapshot2001jan12) +- video card vendor/model (example: Matrox G400 MAX AGP) +- CPU vendor and type (example: Intel Celeron2-566 at 850MHz) + +Also include the required logs (as attachment, may be compressed zip/gz/bz2) +depending the problem type (see bellow at Troubleshooting section). + +To log output to a file, use the &> shell operator. For example: + ./configure &>configure.log + mplayer -v test.avi &>play.log + +If we ask you for the file, then you have two choices: +- upload the file to ftp://thot.banki.hu/incoming (at least a few megabytes) +- send the exact URL of the file, and we'll download it soon. + +Please do not ask for features already listed in the TODO! + +Troubleshooting: +~~~~~~~~~~~~~~~~ +1. Please read the docs first... + +2. If you have compiling problems: + - if you are an experienced programmer, please try to fix it, and send + us the patch + - if gcc reports problems around inttypes.h, try to copy DOCS/inttypes.h + to the directory where the error occured. (or upgrade glibc to 2.1/newer) + - if gcc reports problems around video_out_gl.c, try disabling OpenGL + support: ./configure --disable-gl (you have broken OpenGL headers/libs) + - if you are a user, send us a bugreport (see above), including these: + - output of ./configure + - output of make dep and make + - config.h and all of config.mak files + Note: many users reported that SSE was not detected while running on P3. + Current stable 2.2.x kernels does NOT support SSE, so you can't use it + without patches or using the 2.4.x series. + +3. If you have a problem with the player, please run it with -v option, and + send the output of it, with a detailed description of the problem. + - can't play AVI files: check that codec .DLL and .ACM files are installed to + /usr/lib/win32/ and are all lowercase (divxc32.dll instead of DivXc32.DLL) + +4. If you have a file-specific problem (can't play a special file, + crashes with it or similar) then please run with -v -v -v (debug level 3). + Send us the output and the problem description via email bugreport. + We may ask you to upload the file. + - if it segfaults with an AVI file with MP3 audio, try with -afm 1 or -afm 4 + - if it's still bad, try with -nosound + +5. If you have problem with display driver, please first check the list above, + many of them isn't yet capable to AVI playing, and some of them are + untested and/or unfinished. + +6. If you have speed problems (too slow playing), then please first check that: + - you don't use OpenGL driver while have software-only opengl (DRI disabled, + or not yet installed, conflicting libs installed, or your hardware not + supported etc...) + - you have set up MTRR registers properly (many new cards are really + slow without setting up MTRR registers. it's NOT done by X 3.3.x! Also, + there are older K6-2's, which lack MTRR support /stepping=0/). + - you have a fast machine (don't report that your 386 can't play DivX) + - try with Null output (-vo null) and check CPU usage (first % value) + +7. sound-related problems: + - maybe your card doesn't support 48kHz playback and the movie requires it. + - try player with the -noalsa option + - delayed audio with some AVI files: try with -bps or -nobps option! + - if you experienced delayed audio, try to compensate with -delay or -abs. + you can specify audio card's buffer size in bytes with -abs option, or + specify audio delay in seconds (positive/negative float) with -delay + for example: mplayer -alsa -delay -0.75 test.avi + mplayer -abs 65536 -delay 0.3 test.mpg + - to play AVI files with VBR MP3 audio use the -mc 0 option! + - no sound at all: check that you have working OSS driver (/dev/dsp), + and it isn't used by another program (for example esd, xmms etc.) + +8. unsupported codecs (AVI files): + We may add support for your movie, but we need the following things: + - the codec DLL file: find it in your WINDOWS directory. In the SYSTEM.INI + there will be a listing of the installed codecs (vids.<codecname>=DLLfile) + - a sample file encoded with that codec. + + +Download: +~~~~~~~~~ +Download: ftp://thot.banki.hu/esp-team/linux/MPlayer/ + or: http://thot.banki.hu/esp-ftp/linux/MPlayer/ +Homepage: http://thot.banki.hu/esp-team/MPlayer.html + +Mailing lists: +~~~~~~~~~~~~~~ +There are two public mailing lists on MPlayer. Subscribing can be achieved by +writing to the following addresses, and specifying "subscribe" in the Subject, +or message body. + +- MPlayer-users + Write an e-mail to mplayer-request@alan.umcs.lublin.pl +- MPlayer-announce + Write an e-mail to mplayer-announce-request@alan.umcs.lublin.pl + +Special thanks to Dariusz Pietrzak for the list hosting! + +Standard Disclaimer: +~~~~~~~~~~~~~~~~~~~~ +Use only at your own risk! There may be errors and inaccuracies that could +be damaging to your system or your eye. Proceed with caution, and although +this is highly unlikely, I don't take any responsibility for that! diff --git a/DOCS/SOUNDCARDS b/DOCS/SOUNDCARDS new file mode 100644 index 0000000000..8c396c32f5 --- /dev/null +++ b/DOCS/SOUNDCARDS @@ -0,0 +1,21 @@ +Recommended options for better sound sync: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +(first try without these, maybe it works well without 'hacking' defaults) + +ALSA: -alsa -abs 65536 + +Aureal Vortex2: -alsa -abs 65536 -delay -0.5 + +SB Live!: kernel 2.2.x: -alsa + 2.4.x: nothing + +OSS/Free: please contact me for good parameters + + +... and not use your soundcard by other application ( for ex. XMMS ) ... +... and use very-very high speed hdd or CDROM and CPU ... + + + Pontscho/fresh!mindworkz + pontscho@makacs.poliod.hu
\ No newline at end of file diff --git a/DOCS/SPEED b/DOCS/SPEED new file mode 100644 index 0000000000..d15285cb4a --- /dev/null +++ b/DOCS/SPEED @@ -0,0 +1,40 @@ +Some benchmark values +===================== + +Test system: Abit BE6-2 mb, Intel Celeron2-566 @ 850Mhz, Matrox G400 MAX +Linux: Slackware 7.0, kernel 2.4.0-test8, glibc 2.1.2 + +MPEG 1/2 Video codec CPU usage in percent (%) : +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +1. Setup: mga_vid YUV, MMX idct, no mtrr settings +2. Setup: mga_vid YUV, SSE idct, with mtrr settings +3. Setup: Utah-GLX OpenGL + software C YUV->RGB, SSE idct +4. Setup: X11 Shm (32bpp) + software MMX YUV->RGB, SSE idct, with mtrr +5. Setup: null output (codec speed only) +6. Setup: X11 4.0.1e + Xv extension, SSE idct, with mtrr + + 1. 2. 3. 4. 5. 6. + DolbyDigitalBroadway.vob: 60% 35% 78% 67% 26% 47% + matrix.vob (trailer): 51% 30% 62% 56% 23% 40% + PAL (352x288/25) mpeg1: 16% 9% 30% 13% 7% 8% + 3D anim (30fps mpeg1): 20% 14% 35% 25% 12% 14% + +Win32 Video codec CPU usage in percent (%) : +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +(All tests with YUV/YUY2 output format to null device) + DivX 720x416/30fps 27% + DivX 704x320/25fps 24% + DivX 640x352/24fps 22% + DivX 480x204/24fps 12% + IV50 320x240/15fps 7% + +Audio codec CPU usage in percent (%) : +~~~~~~~~~~~~~~~~~~~~~ + Mpeg layer-2 audio (VCD): 1.2% + PCM audio (DVD, 48khz): 1.3% + AC3 audio (DVD, 2.0 mode) 4.1% + AC3 audio (DVD, 5.1 mode) 6.5% + AC3 audio (DivX, 5.1 mode) 3.5% + MP3 audio (mp3lib) 2.8% + MP3 audio (l3codeca.dll) 1.8% + DivX audio (divxa32.dll) 3.3% diff --git a/DOCS/TODO b/DOCS/TODO new file mode 100644 index 0000000000..f2fae7e80d --- /dev/null +++ b/DOCS/TODO @@ -0,0 +1,30 @@ +TO DO: +~~~~~~ +Urgent: +- asterix.avi audio delays after 5-10 mins (bps mode only) +- PAUSE doesn't work in the X11 and SDL windows (because no Check X Events) +- SDL fullscreen problems at quit/eof - DONE? +- finish ASF seeking +- fix vo_syncfb - DONE for G400 + +Fix compilation problems: +- SDL version detection into ./configure - DONE (disabled :)) + +Libvo features: +- framebuffer and svgalib support (both) +- DGA support (LGB?) +- real fullscreen (black bands at unused areas) support - DONE for xmga & x11 +- fix X4.0.x/DRI OpenGL (doesn't work, at least mga & tdfx & nvidia) +- change libmpeg2 & libvo interface to be compatible with libmpeg2-0.2.0 release + +Player features: +- libcss support +- subtitles support (.sub files) +- show movie length / position in percent +- show current frame number [Gabucino] +- seek_to_frame and seek_to_index options +- fix mp3lib to avoid segfault with some damaged .avi files (workaround: -afm 4) +- integrating the gui? +- support for more codecs (sample .avi files and .dll needed!) - HELP! +- support for MPEG TS (transport streams) and PES format - I need sample files! +- verify valid range of numeric options (like '-xy 0') diff --git a/DOCS/inttypes.h b/DOCS/inttypes.h new file mode 100644 index 0000000000..b1e93879e4 --- /dev/null +++ b/DOCS/inttypes.h @@ -0,0 +1,13 @@ + +// fallback if the user doesn't have inttypes.h (libc5 systems) + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +typedef unsigned long long uint64_t; + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed long int32_t; +typedef signed long long int64_t; + diff --git a/DOCS/mplayer.1 b/DOCS/mplayer.1 new file mode 100644 index 0000000000..fd89c47651 --- /dev/null +++ b/DOCS/mplayer.1 @@ -0,0 +1,190 @@ +.\" MPlayer (C) 2000-2001 Arpad Gereoffy <arpi@esp-team.scene.hu> +.\" This manpage was/is done by Gabucino +.\" Manpage v1.1 +.\" +.TH MPlayer 0.11 +.SH NAME +mplayer \- Movie Player for Linux +.SH SYNOPSIS +.B mplayer +.RB [ \-vo\ output\ driver ] +.RB [ \-vcd\ track\ number ] +.RB [ \-sb\ byte\ position ] +.RB [ \-nosound\ ] +.RB [ \-abs\ seconds ] +.RB [ \-delay\ secs ] +.RB [ \-bps\ value ] +.RB [ \-noalsa\ ] +.RB [ \-aid\ id ] +.RB [ \-vid\ id ] +.RB [ \-fps\ rate ] +.RB [ \-mc\ seconds/5f ] +.RB [ \-afm\ audio\ decoder ] +.RB [ \-fs\ ] +.RB [ \-x\ x ] +.RB [ \-y\ y ] +.RB [ \-xy\ factor ] +.RB [ \-dsp\ device ] +.RB [ \-divxq\ quality ] +.I file +.PP +.SH DESCRIPTION +.I mplayer +Yes. Yet another movie player for linux. +What is the special with this? It works, at least for me :) +I've tried lots of players under linux (mtv,xmps,dvdview,livid/oms,VideoLAN, +xine,xanim,avifile,xmmp) but they all have some problem. Mostly with +special files or with audio/video sync. Most of them is unable to play +both mpeg1, mpeg2 and avi (DivX) files. Many players have image quality +or speed problems too. So I've decided to write/modify one... +.LP +.SH "GENERAL OPTIONS" +.TP +.I NOTE +MPlayer works out-of-the-box, so you generally don't have to mess with +any options. +.TP +.BI \-vo\ output\ driver +select output driver + +you can get the list of available drivers executing +.I mplayer -vo help + +.TP +.BI \-vcd\ track +play video cd track from device instead of plain file +.TP +.BI \-nosound +don't play sound +.TP +.B \-fs +fullscreen playing (only gl, xmga and xv drivers) + +.I NOTE +The X11 driver doesn't support fullscreen and scaling. +However, you can do it yourself, just press ALT,CTRL,- +or ALT,CTRL,+ simultaneously, see X-server docs for details. +.TP +.B \-x\ x +scale image to x width [if driver suppports!] +.TP +.B \-y\ y +scale image to y height +.TP +.B \-xy\ factor +scale image by <factor> +.TP +.B \-dsp\ device +select another DSP output device +.TP +.B \-divxq\ quality +apply postprocess filter on decoded image. +You need a STRONG CPU in order to use this! +The supported formats and settings are: + + MPEG1 1, 3, 7, 31 + OpenDivX 1-59 (maybe less/more) + DivX not YET supported + +.I NOTE +You can use this with OpenDivX encoding too! See ALPHA/BETA CODE section. +.IP +.SH KEYBOARD CONTROL +.TP +.I NOTE +These keys may/may not work, depending on your video output driver. +.TP + <- or -> seek backward/forward 10 seconds + +up or down seek backward/forward 1 minute + +p or SPACE pause movie (press any key) + +q or ESC stop playing and quit program + ++ or - adjust audio delay by +/- 0.1 second +.IP +.SH "ADVANCED OPTIONS" +.TP +.I NOTE +These options can help you solve your particular problem.. Also, see the DOCS! +.TP +.B \-afm <1-5> +force audio format 1:MPEG 2:PCM 3:AC3 4:Win32 5:aLaw + +.I NOTE +With DivX AVIs with MP3 audio, you can choose whether to use MP3LIB (option 1), +or Win32 DLL l3codeca.acm (option 4) (default). On CPUs with the 3DNow! +instruction set, the first gives more performance. Your mileage may vary. +.TP +.BI \-sb\ position +seek to byte position +.TP +.BI \-abs\ bytes +audio buffer size (in bytes, default: measuring) +.TP +.B \-delay\ secs +audio delay in seconds (may be +/- float value) +.TP +.B \-bps +use avg. byte/sec value for A-V sync (AVI) +.TP +.B \-noalsa +disable timing code +.TP +.B \-aid\ id +select audio channel [MPG: 0-31 AVI: 1-99] +.TP +.B \-vid\ id +select video channel [MPG: 0-15 AVI: -- ] +.TP +.B \-fps\ value +force frame rate (if value is wrong in the header) +.TP +.B \-mc\ seconds/5frame +maximum sync correction per 5 frames (in seconds) +.TP +.B \-ni +force usage of non-interleaved AVI parser +.IP +.SH "ALPHA/BETA CODE" +.TP +.I NOTE +These are included in this manpage just for completeness! If you don't +know what are these, you DON'T need these! In either case, double-check DOCS! +.TP +.B \-br\ rate +used with '-vo odivx' . +Specifies the bitrate to encode OpenDivx at +(in bits! e.g: 780000). +.TP +.B \-encode\ file +used with '-vo odivx' . +Specifies the output OpenDivX file. Won't overwrite. +.IP +.SH "EXAMPLES" +Just launch it! :) +.LP +.SH BUGS +Possibly. Check DOCS. + +Bugreports should be addressed to the MPlayer-users mailing list +(mplayer@alan.umcs.lublin.pl) ! If you want to submit a bugreport +(which we love to receive!), please double-check the README, and +tell us all that we need to know to identify your problem. + +.LP +.SH AUTHORS +Check DOCS/AUTHORS ! + +MPlayer is (C) 2000-2001 +.I Arpad Gereoffy <arpi@thot.banki.hu> + +This manpage is maintained by +.I Gabucino. +.LP +.SH STANDARD DISCLAIMER +Use only at your own risk! There may be errors and inaccuracies that could +be damaging to your system or your eye. Proceed with caution, and although +this is highly unlikely, the author doesn't take any responsibility for that! +.\" end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..ebbdf1636d --- /dev/null +++ b/Makefile @@ -0,0 +1,82 @@ +# LINUX Makefile made by A'rpi / Astral +# Some cleanup by LGB: * 'make -C dir' instead of 'cd dir;make;cd..' +# * for loops instead of linear sequence of make directories +# * some minor problems with make clean and distclean were corrected + +include config.mak + +PRG = mplayer +PRG_AVIP = aviparse +PRG_TV = tvision +prefix = /usr/local +BINDIR = ${prefix}/bin +# BINDIR = /usr/local/bin +SRCS = linux/getch2.c linux/timer-lx.c linux/shmem.c xa/xa_gsm.c lirc_mp.c +OBJS = linux/getch2.o linux/timer-lx.o linux/shmem.o xa/xa_gsm.o lirc_mp.o +CFLAGS = $(OPTFLAGS) -Iloader -Ilibvo # -Wall +A_LIBS = -Lmp3lib -lMP3 -Llibac3 -lac3 +VO_LIBS = -Llibvo -lvo $(X_LIBS) + +.SUFFIXES: .c .o + +# .PHONY: all clean + +all: $(PRG) +# $(PRG_AVIP) + +.c.o: + $(CC) -c $(CFLAGS) -o $@ $< + +COMMONLIBS = libvo/libvo.a libac3/libac3.a mp3lib/libMP3.a + +loader/libloader.a: + $(MAKE) -C loader + +libmpeg2/libmpeg2.a: + $(MAKE) -C libmpeg2 + +libvo/libvo.a: + $(MAKE) -C libvo + +libac3/libac3.a: + $(MAKE) -C libac3 + +mp3lib/libMP3.a: + $(MAKE) -C mp3lib + +opendivx/libdecore.a: + $(MAKE) -C opendivx + +encore/libencore.a: + $(MAKE) -C encore + +$(PRG): mplayer.o $(OBJS) loader/libloader.a libmpeg2/libmpeg2.a opendivx/libdecore.a $(COMMONLIBS) encore/libencore.a + $(CC) $(CFLAGS) -o $(PRG) mplayer.o $(OBJS) $(XMM_LIBS) $(LIRC_LIBS) $(A_LIBS) -lm $(TERMCAP_LIB) -Lloader -lloader -ldl -Llibmpeg2 -lmpeg2 -Lopendivx -ldecore $(VO_LIBS) -Lencore -lencore -lpthread + +$(PRG_AVIP): aviparse.o $(OBJS) loader/libloader.a $(COMMONLIBS) + $(CC) $(CFLAGS) -o $(PRG_AVIP) aviparse.o $(OBJS) $(A_LIBS) -lm $(TERMCAP_LIB) -Lloader -lloader -ldl $(VO_LIBS) -lpthread + +$(PRG_TV): tvision.o $(OBJS) $(COMMONLIBS) + $(CC) $(CFLAGS) -o $(PRG_TV) tvision.o $(OBJS) -lm $(TERMCAP_LIB) $(VO_LIBS) + +install: $(PRG) + strip $(PRG) + cp $(PRG) $(BINDIR) + install -m 644 DOCS/mplayer.1 $(prefix)/man/man1/mplayer.1 + +clean: + rm -f *.o *~ $(OBJS) + +distclean: + @for a in mp3lib libac3 libmpeg2 opendivx encore libvo loader drivers drivers/syncfb ; do $(MAKE) -C $$a distclean ; done + makedepend + rm -f *~ $(PRG) $(PRG_AVIP) $(PRG_TV) $(OBJS) *.o *.a Makefile.bak + +dep: depend + +depend: + @for a in mp3lib libac3 libmpeg2 libvo opendivx encore ; do $(MAKE) -C $$a dep ; done +# cd loader;make dep;cd .. + makedepend -- $(CFLAGS) -- mplayer.c aviparse.c tvision.c $(SRCS) &>/dev/null + +# DO NOT DELETE diff --git a/TOOLS/GL-test/compile.sh b/TOOLS/GL-test/compile.sh new file mode 100755 index 0000000000..2bb40def0a --- /dev/null +++ b/TOOLS/GL-test/compile.sh @@ -0,0 +1,2 @@ + +gcc -g -O4 gltest.c ../../linux/timer-lx.o -o gltest -L/usr/X11/lib -lglut -lGL -lGLU -lX11 -lXext -lXmu -lXi -lm diff --git a/TOOLS/GL-test/gltest.c b/TOOLS/GL-test/gltest.c new file mode 100644 index 0000000000..e8c6d33146 --- /dev/null +++ b/TOOLS/GL-test/gltest.c @@ -0,0 +1,189 @@ +// OpenGL glTexSubImage() test/benchmark prg (C) 2001. by A'rpi/ESP-team + +#include <GL/glut.h> +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <inttypes.h> + +// pixel size: 3 or 4 +#define BYTES_PP 3 + +// blit by lines (defined) or frames (not defined) +#define FAST_BLIT + +static uint32_t image_width=720; // DVD size +static uint32_t image_height=576; + +static uint32_t image_format; +static uint32_t image_bpp; +static uint32_t image_bytes; + +static uint32_t texture_width=512; +static uint32_t texture_height=512; + +static unsigned char *ImageData=NULL; + +static GLvoid resize(int x,int y){ + printf("Resize: %dx%d\n",x,y); + glViewport( 0, 0, x, y ); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, image_width, image_height, 0, -1,1); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +float akarmi=0; + +int counter=0; +float gen_time=0; +float up_time=0; +float render_time=0; + +unsigned char sintable[4096]; + +extern float GetRelativeTime(); + +static void redraw(void) +{ +// glClear(GL_COLOR_BUFFER_BIT); + int x,y,i; + unsigned char *d=ImageData; + int dstride=BYTES_PP*image_width; + + GetRelativeTime(); + + // generate some image: + for(y=0;y<image_height;y++){ + int y1=2048*sin(akarmi*0.36725+y*0.0165); + int y2=2048*sin(akarmi*0.45621+y*0.02753); + int y3=2048*sin(akarmi*0.15643+y*0.03732); + for(x=0;x<image_width;x++){ + d[0]=sintable[(y1+x*135)&4095]; + d[1]=sintable[(y2+x*62)&4095]; + d[2]=sintable[(y3+x*23)&4095]; + d+=BYTES_PP; + } + } + + gen_time+=GetRelativeTime(); + +#ifdef FAST_BLIT + // upload texture: + for(i=0;i<image_height;i++){ + glTexSubImage2D( GL_TEXTURE_2D, // target + 0, // level + 0, // x offset + i, // y offset + image_width, // width + 1, // height + (BYTES_PP==4)?GL_RGBA:GL_RGB, // format + GL_UNSIGNED_BYTE, // type + ImageData+i*dstride ); // *pixels + } +#else + glTexSubImage2D( GL_TEXTURE_2D, // target + 0, // level + 0, // x offset + 0, // y offset + image_width, // width + image_height, // height + (BYTES_PP==4)?GL_RGBA:GL_RGB, // format + GL_UNSIGNED_BYTE, // type + ImageData ); // *pixels +#endif + + up_time+=GetRelativeTime(); + + glColor3f(1,1,1); + glBegin(GL_QUADS); + glTexCoord2f(0,0);glVertex2i(0,0); + glTexCoord2f(0,1);glVertex2i(0,texture_height); + glTexCoord2f(1,1);glVertex2i(texture_width,texture_height); + glTexCoord2f(1,0);glVertex2i(texture_width,0); + glEnd(); + + glFinish(); + glutSwapBuffers(); + + render_time+=GetRelativeTime(); + + ++counter; + { float total=gen_time+up_time+render_time; + if(total>2.0){ + printf("%8.3f fps (gen: %2d%% upload: %2d%% render: %2d%%)\n", + (float)counter/total, + (int)(100.0*gen_time/total), + (int)(100.0*up_time/total), + (int)(100.0*render_time/total) + ); + gen_time=up_time=render_time=0; + counter=0; + } } + +} + +static GLvoid IdleFunc(){ + akarmi+=0.1; + glutPostRedisplay(); +} + +int +main(int argc, char **argv) +{ + int i; + + glutInit(&argc, argv); + glutInitWindowSize(640, 480); + glutInitDisplayMode(GLUT_DOUBLE); + (void) glutCreateWindow("csg"); + + glutDisplayFunc(redraw); + glutReshapeFunc(resize); + glutIdleFunc(IdleFunc); + + texture_width=32; + while(texture_width<image_width) texture_width*=2; + while(texture_width<image_height) texture_width*=2; + texture_height=texture_width; + + image_bpp=8*BYTES_PP; + image_bytes=BYTES_PP; + + ImageData=malloc(texture_width*texture_height*image_bytes); + memset(ImageData,128,texture_width*texture_height*image_bytes); + + glDisable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + glDisable(GL_CULL_FACE); + + glEnable(GL_TEXTURE_2D); + + printf("Creating %dx%d texture...\n",texture_width,texture_height); + +#if 1 +// glBindTexture(GL_TEXTURE_2D, texture_id); + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR); +#ifdef TEXTUREFORMAT_32BPP + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, texture_width, texture_height, 0, +#else + glTexImage2D(GL_TEXTURE_2D, 0, BYTES_PP, texture_width, texture_height, 0, +#endif + (image_bytes==4)?GL_RGBA:GL_BGR, GL_UNSIGNED_BYTE, ImageData); +#endif + + resize(640,480); + + glClearColor( 1.0f,0.0f,1.0f,0.0f ); + glClear( GL_COLOR_BUFFER_BIT ); + + for(i=0;i<4096;i++) sintable[i]=128+127*sin(2.0*3.14159265*i/4096.0); + + glutMainLoop(); + return 0; /* ANSI C requires main to return int. */ +} diff --git a/TOOLS/asfinfo.c b/TOOLS/asfinfo.c new file mode 100644 index 0000000000..3e26bfe18a --- /dev/null +++ b/TOOLS/asfinfo.c @@ -0,0 +1,255 @@ +#define SAVE_STREAMS + +// simple ASF header display program by A'rpi/ESP-team +// .asf fileformat docs from http://divx.euro.ru + +#include <stdio.h> +#include <stdlib.h> + +typedef struct __attribute__((packed)) +{ + long biSize; // sizeof(BITMAPINFOHEADER) + long biWidth; + long biHeight; + short biPlanes; // unused + short biBitCount; + long biCompression; // fourcc of image + long biSizeImage; // size of image. For uncompressed images + // ( biCompression 0 or 3 ) can be zero. + + + long biXPelsPerMeter; // unused + long biYPelsPerMeter; // unused + long biClrUsed; // valid only for palettized images. + // Number of colors in palette. + long biClrImportant; +} BITMAPINFOHEADER; + +typedef struct +{ + short wFormatTag; // value that identifies compression format + short nChannels; + long nSamplesPerSec; + long nAvgBytesPerSec; + short nBlockAlign; // size of a data sample + short wBitsPerSample; + short cbSize; // size of format-specific data +} WAVEFORMATEX; + +typedef struct __attribute__((packed)) { + unsigned char guid[16]; + unsigned long long size; +} ASF_obj_header_t; + +typedef struct __attribute__((packed)) { + ASF_obj_header_t objh; + unsigned int cno; // number of subchunks + unsigned char v1; // unknown (0x01) + unsigned char v2; // unknown (0x02) +} ASF_header_t; + +typedef struct __attribute__((packed)) { + unsigned char client[16]; // Client GUID + unsigned long long file_size; + unsigned long long creat_time; //File creation time FILETIME 8 + unsigned long long packets; //Number of packets UINT64 8 + unsigned long long end_timestamp; //Timestamp of the end position UINT64 8 + unsigned long long duration; //Duration of the playback UINT64 8 + unsigned long start_timestamp; //Timestamp of the start position UINT32 4 + unsigned long unk1; //Unknown, maybe reserved ( usually contains 0 ) UINT32 4 + unsigned long flags; //Unknown, maybe flags ( usually contains 2 ) UINT32 4 + unsigned long packetsize; //Size of packet, in bytes UINT32 4 + unsigned long packetsize2; //Size of packet ( confirm ) UINT32 4 + unsigned long frame_size; //Size of uncompressed video frame UINT32 4 +} ASF_file_header_t; + +typedef struct __attribute__((packed)) { + unsigned char type[16]; // Stream type (audio/video) GUID 16 + unsigned char concealment[16]; // Audio error concealment type GUID 16 + unsigned long long unk1; // Unknown, maybe reserved ( usually contains 0 ) UINT64 8 + unsigned long type_size; //Total size of type-specific data UINT32 4 + unsigned long stream_size; //Size of stream-specific data UINT32 4 + unsigned short stream_no; //Stream number UINT16 2 + unsigned long unk2; //Unknown UINT32 4 +} ASF_stream_header_t; + +typedef struct __attribute__((packed)) { + unsigned char streamno; + unsigned char seq; + unsigned long x; + unsigned char flag; +} ASF_segmhdr_t; + + +ASF_header_t asfh; +ASF_obj_header_t objh; +ASF_file_header_t fileh; +ASF_stream_header_t streamh; +unsigned char buffer[8192]; + +int i; + +char* chunk_type(unsigned char* guid){ + switch(*((unsigned int*)guid)){ + case 0xF8699E40: return "guid_audio_stream"; + case 0xBC19EFC0: return "guid_video_stream"; + case 0x49f1a440: return "guid_audio_conceal_none"; + case 0xbfc3cd50: return "guid_audio_conceal_interleave"; + case 0x75B22630: return "guid_header"; + case 0x75b22636: return "guid_data_chunk"; + case 0x33000890: return "guid_index_chunk"; + case 0xB7DC0791: return "guid_stream_header"; + case 0xD6E229D1: return "guid_header_2_0"; + case 0x8CABDCA1: return "guid_file_header"; + } + return NULL; +} + +void print_wave_header(WAVEFORMATEX *h){ + + printf("======= WAVE Format =======\n"); + + printf("Format Tag: %d (0x%X)\n",h->wFormatTag,h->wFormatTag); + printf("Channels: %d\n",h->nChannels); + printf("Samplerate: %d\n",h->nSamplesPerSec); + printf("avg byte/sec: %d\n",h->nAvgBytesPerSec); + printf("Block align: %d\n",h->nBlockAlign); + printf("bits/sample: %d\n",h->wBitsPerSample); + printf("cbSize: %d\n",h->cbSize); + + switch(h->wFormatTag){ + case 0x01: printf("Audio in PCM format\n");break; + case 0x50: printf("Audio in MPEG Layer 1/2 format\n");break; + case 0x55: printf("Audio in MPEG Layer-3 format\n");break; // ACM + case 0x02: printf("Audio in MS ADPCM format\n");break; // ACM + case 0x11: printf("Audio in IMA ADPCM format\n");break; // ACM + case 0x31: + case 0x32: printf("Audio in MS GSM 6.10 format\n");break; // ACM + case 0x160: + case 0x161: printf("Audio in DivX WMA format\n");break; // ACM + default: printf("Audio in UNKNOWN (id=0x%X) format\n",h->wFormatTag); + } + + printf("===========================\n"); + + +} + +void print_video_header(BITMAPINFOHEADER *h){ + printf("======= VIDEO Format ======\n"); + printf(" biSize %d\n", h->biSize); + printf(" biWidth %d\n", h->biWidth); + printf(" biHeight %d\n", h->biHeight); + printf(" biPlanes %d\n", h->biPlanes); + printf(" biBitCount %d\n", h->biBitCount); + printf(" biCompression %d='%.4s'\n", h->biCompression, &h->biCompression); + printf(" biSizeImage %d\n", h->biSizeImage); + printf("===========================\n"); +} + +FILE* streams[128]; + +int main(int argc,char* argv[]){ +FILE *f=fopen(argc>1?argv[1]:"Alice Deejay - Back In My Life.asf","rb"); + +if(!f){ printf("file not found\n");exit(1);} + +//printf("sizeof=%d\n",sizeof(objh)); +//printf("sizeof=%d\n",sizeof(asfh)); + +fread(&asfh,sizeof(asfh),1,f); // header obj +//for(i=0;i<16;i++) printf("%02X ",asfh.objh.guid[i]); +printf("[%s] %d (subchunks: %d)\n",chunk_type(asfh.objh.guid),(int) asfh.objh.size,asfh.cno); + +while(fread(&objh,sizeof(objh),1,f)>0){ + int pos=ftell(f); +// for(i=0;i<16;i++) printf("%02X ",objh.guid[i]); + printf("0x%08X [%s] %d\n",pos-sizeof(objh), chunk_type(objh.guid),(int) objh.size); + switch(*((unsigned int*)&objh.guid)){ + case 0xB7DC0791: // guid_stream_header + fread(&streamh,sizeof(streamh),1,f); + printf("stream type: %s\n",chunk_type(streamh.type)); + printf("stream concealment: %s\n",chunk_type(streamh.concealment)); + printf("type: %d bytes, stream: %d bytes ID: %d\n",(int)streamh.type_size,(int)streamh.stream_size,(int)streamh.stream_no); + printf("FILEPOS=0x%X\n",ftell(f)); + // type-specific data: + fread(buffer,streamh.type_size,1,f); + switch(*((unsigned int*)&streamh.type)){ + case 0xF8699E40: // guid_audio_stream + print_wave_header((WAVEFORMATEX*)buffer); + break; + case 0xBC19EFC0: // guid_video_stream + print_video_header((BITMAPINFOHEADER*)&buffer[4+4+1+2]); + break; + } + // stream-specific data: + fread(buffer,streamh.stream_size,1,f); + break; +// case 0xD6E229D1: return "guid_header_2_0"; + case 0x8CABDCA1: // guid_file_header + fread(&fileh,sizeof(fileh),1,f); + printf("packets: %d flags: %d pack_size: %d frame_size: %d\n",(int)fileh.packets,(int)fileh.flags,(int)fileh.packetsize,(int)fileh.frame_size); + break; + case 0x75b22636: // guid_data_chunk + { int endp=pos+objh.size-sizeof(objh); + unsigned char* packet=malloc((int)fileh.packetsize); + int fpos; + fseek(f,26,SEEK_CUR); + while((fpos=ftell(f))<endp){ + fread(packet,(int)fileh.packetsize,1,f); + if(packet[0]==0x82){ + unsigned char flags=packet[3]; + unsigned char* p=&packet[5]; + unsigned long time; + unsigned short duration; + int segs=1; + int seg; + int padding=0; + if(flags&8){ + padding=p[0];++p; + } else + if(flags&16){ + padding=p[0]|(p[1]<<8);p+=2; + } + time=*((unsigned long*)p);p+=4; + duration=*((unsigned short*)p);p+=2; + if(flags&1){ + segs=p[0]-0x80;++p; + } + printf("%08X: flag=%02X segs=%d pad=%d time=%d dur=%d\n", + fpos,flags,segs,padding,time,duration); + for(seg=0;seg<segs;seg++){ + ASF_segmhdr_t* sh=(ASF_segmhdr_t*)p; + int len=0; + p+=sizeof(ASF_segmhdr_t); + if(sh->flag&8) p+=8;// else + if(sh->flag&1) ++p; + if(flags&1){ + len=*((unsigned short*)p);p+=2; + } + printf(" seg #%d: streamno=%d seq=%d flag=%02X len=%d\n",seg,sh->streamno&0x7F,sh->seq,sh->flag,len); +#ifdef SAVE_STREAMS + if(!streams[sh->streamno&0x7F]){ + char name[256]; + sprintf(name,"stream%02X.dat",sh->streamno&0x7F); + streams[sh->streamno&0x7F]=fopen(name,"wb"); + } + fwrite(p,len,1,streams[sh->streamno&0x7F]); +#endif + p+=len; + } + } else + printf("%08X: UNKNOWN %02X %02X %02X %02X %02X...\n",fpos,packet[0],packet[1],packet[2],packet[3],packet[4]); + } + } + break; + +// case 0x33000890: return "guid_index_chunk"; + + } + fseek(f,pos+objh.size-sizeof(objh),SEEK_SET); +} + + +} + diff --git a/TOOLS/c b/TOOLS/c new file mode 100755 index 0000000000..5ba26feeb6 --- /dev/null +++ b/TOOLS/c @@ -0,0 +1 @@ +gcc movinfo.c -o movinfo diff --git a/TOOLS/movinfo.c b/TOOLS/movinfo.c new file mode 100644 index 0000000000..3c3c3ddd9e --- /dev/null +++ b/TOOLS/movinfo.c @@ -0,0 +1,124 @@ +// show QuickTime .mov file structure (C) 2001. by A'rpi/ESP-team + +#include <stdio.h> +#include <stdlib.h> + +unsigned int read_dword(FILE *f){ + unsigned char atom_size_b[4]; + if(fread(&atom_size_b,4,1,f)<=0) return -1; + return (atom_size_b[0]<<24)|(atom_size_b[1]<<16)|(atom_size_b[2]<<8)|atom_size_b[3]; +} + +void lschunks(FILE *f,int level,unsigned int endpos){ + unsigned int atom_size; + unsigned int atom_type; + int pos; + while(endpos==0 || ftell(f)<endpos){ + pos=ftell(f); + atom_size=read_dword(f);// if(fread(&atom_size_b,4,1,f)<=0) break; + if(fread(&atom_type,4,1,f)<=0) break; + + if(atom_size<8) break; // error + + printf("%08X: %*s %.4s (%08X) %d\n",pos,level*2,"",&atom_type,atom_type,atom_size); + + if(atom_type==0x64737473) { // stsd + unsigned int tmp; + unsigned int count; + int i; + fread(&tmp,4,1,f); + count=read_dword(f);// fread(&count,4,1,f); + printf("desc count = %d\n",count); + for(i=0;i<count;i++){ + unsigned int len; + unsigned int format; + len=read_dword(f); // fread(&len,4,1,f); + fread(&format,4,1,f); + printf(" desc #%d: %.4s (%d)\n",i+1,&format,len); + fseek(f,len-8,SEEK_CUR); + } + } + + if(atom_type==0x6F637473) { // stco + int len,i; + read_dword(f); + len=read_dword(f); + printf("Chunk table size :%d\n",len); + for(i=0;i<len;i++) printf(" chunk #%d: 0x%X\n",i+1,read_dword(f)); + } + + + if(atom_type==0x73747473) { // stts + int len,i; + read_dword(f); + len=read_dword(f); + printf("T->S table size :%d\n",len); + for(i=0;i<len;i++){ + int num=read_dword(f); + int dur=read_dword(f); + printf("%5d samples: %d duration\n",num,dur); + } + } + + if(atom_type==0x63737473) { // stsc + int len,i; + read_dword(f); + len=read_dword(f); + printf("S->C table size :%d\n",len); + for(i=0;i<len;i++){ + int first=read_dword(f); + int spc=read_dword(f); + int sdid=read_dword(f); + printf(" chunk %d... %d s/c desc: %d\n",first,spc,sdid); + } + } + + if(atom_type==0x7A737473) { // stsz + int len,i,ss; + read_dword(f); + ss=read_dword(f); + len=read_dword(f); + printf("Sample size table len: %d\n",len); + if(ss){ + printf(" common sample size: %d bytes\n",ss); + } else { + for(i=0;i<len;i++) printf(" sample #%d: %d bytes\n",i+1,read_dword(f)); + } + } + + +#if 1 + switch(atom_type){ + case 0x75716D72: // rmqu + case 0x65657266: // free JUNK + case 0x64686B74: // tkhd Track header + case 0x61746475: // udta User data + case 0x7461646D: // mdat Movie data + case 0x64737473: // stsd Sample description + case 0x6F637473: // stco Chunk offset table + case 0x73747473: // stts Sample time table + case 0x63737473: // stsc Sample->Chunk mapping table + case 0x7A737473: // stsz Sample size table + break; + default: lschunks(f,level+1,pos+atom_size); + } +#else + switch(atom_type){ + case 0x766F6F6D: // moov + case 0x61726D72: // rmra + case 0x61646D72: // rmda + lschunks(f,level+1,pos+atom_size); + } +#endif + fseek(f,pos+atom_size,SEEK_SET); + } +} + +int main(int argc,char* argv[]){ +int pos; +FILE *f=fopen(argc>1?argv[1]:"Akira.mov","rb"); +if(!f) return 1; + +lschunks(f,0,0); + +} diff --git a/TVout/Mon-640x400 b/TVout/Mon-640x400 new file mode 100755 index 0000000000..84238371cb --- /dev/null +++ b/TVout/Mon-640x400 @@ -0,0 +1,3 @@ + +fbset/fbset -fb /dev/fb1 -db fbset.db 640x400-60 + diff --git a/TVout/Mon-640x480 b/TVout/Mon-640x480 new file mode 100755 index 0000000000..6d7d257b8e --- /dev/null +++ b/TVout/Mon-640x480 @@ -0,0 +1,3 @@ + +fbset/fbset -fb /dev/fb1 -db fbset.db 640x480-60 + diff --git a/TVout/TV-640x512 b/TVout/TV-640x512 new file mode 100755 index 0000000000..aa3924e27a --- /dev/null +++ b/TVout/TV-640x512 @@ -0,0 +1,2 @@ + +fbset/fbset -fb /dev/fb0 -left 60 -right 0 -upper 70 -lower 39 -hslen 76 -vslen 4 -xres 640 -yres 512 -bcast true diff --git a/TVout/TV-640x528 b/TVout/TV-640x528 new file mode 100755 index 0000000000..6edeb82164 --- /dev/null +++ b/TVout/TV-640x528 @@ -0,0 +1,3 @@ + +fbset/fbset -fb /dev/fb0 -left 40 -right 0 -upper 63 -lower 29 -hslen 56 -vslen 4 -xres 640 -yres 528 -vxres 640 -vyres 528 -depth 32 -laced false -bcast true + diff --git a/TVout/TV-704x528 b/TVout/TV-704x528 new file mode 100755 index 0000000000..2554239e10 --- /dev/null +++ b/TVout/TV-704x528 @@ -0,0 +1,3 @@ + +fbset/fbset -fb /dev/fb0 -left 40 -right 0 -upper 63 -lower 29 -hslen 56 -vslen 4 -xres 640 -yres 528 -vxres 704 -vyres 528 -depth 32 -laced false -bcast true + diff --git a/TVout/TV-704x576 b/TVout/TV-704x576 new file mode 100755 index 0000000000..9585e6e5f1 --- /dev/null +++ b/TVout/TV-704x576 @@ -0,0 +1,3 @@ + +fbset/fbset -fb /dev/fb0 -left 42 -right 0 -upper 29 -lower 20 -hslen 46 -vslen 4 -xres 704 -yres 576 -vxres 704 -vyres 576 -depth 32 -laced false -bcast true + diff --git a/TVout/TV-720x576 b/TVout/TV-720x576 new file mode 100755 index 0000000000..fb5272a8c3 --- /dev/null +++ b/TVout/TV-720x576 @@ -0,0 +1,3 @@ + +fbset/fbset -fb /dev/fb0 -left 18 -right 0 -upper 39 -lower 10 -hslen 46 -vslen 4 -xres 720 -yres 576 -vxres 720 -vyres 576 -depth 32 -laced false -bcast true + diff --git a/TVout/clean.sh b/TVout/clean.sh new file mode 100755 index 0000000000..56d7fd13b6 --- /dev/null +++ b/TVout/clean.sh @@ -0,0 +1,13 @@ + +# Compile TVout tools + +rm -f con2fb/con2fb + +cd matroxset +make clean +cd .. + +cd fbset +make clean +cd .. + diff --git a/TVout/cloning b/TVout/cloning new file mode 100755 index 0000000000..c8c545c254 --- /dev/null +++ b/TVout/cloning @@ -0,0 +1,14 @@ + +# SETUP TVout +# Same picture on TV & Monitor + +# CRTC1 -> TVout & Monitor +matroxset/matroxset -f /dev/fb1 -m 0 +matroxset/matroxset -f /dev/fb0 -m 3 + +# Enable TV +matroxset/matroxset 1 + +# Keep consoles on CRTC1 +con2fb/con2fb /dev/fb0 /dev/tty1 +con2fb/con2fb /dev/fb0 /dev/tty2 diff --git a/TVout/compile.sh b/TVout/compile.sh new file mode 100755 index 0000000000..51160101bd --- /dev/null +++ b/TVout/compile.sh @@ -0,0 +1,15 @@ + +# Compile TVout tools + +cd con2fb +gcc con2fb.c -o con2fb +cd .. + +cd matroxset +make +cd .. + +cd fbset +make +cd .. + diff --git a/TVout/con2fb/con2fb.c b/TVout/con2fb/con2fb.c new file mode 100644 index 0000000000..8ca7a9deaa --- /dev/null +++ b/TVout/con2fb/con2fb.c @@ -0,0 +1,79 @@ +/* this is userspace utility which allows you to redirect console to another fb device + * You can specify devices & consoles by both numbers and devices. Framebuffers numbers + * are zero based (/dev/fb0 ... ), consoles begins with 1 (/dev/tty1 ... ) + */ +#include <linux/fb.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +int main(int argc, char* argv[]) { + struct fb_con2fbmap c2m; + char* fbPath; + u_int32_t con, fb; + char* e; + char* progname = strrchr(argv[0], '/'); + int f; + + if (progname) + progname++; + else + progname = argv[0]; + if (argc < 3) { + fprintf(stderr, "usage: %s fbdev console\n", progname); + return 1; + } + fb = strtoul(argv[1], &e, 10); + if (*e) { + struct stat sbf; + + if (stat(argv[1], &sbf)) { + fprintf(stderr, "%s: are you sure that %s can be used to describe fbdev?\n", progname, argv[1]); + return 1; + } + if (!S_ISCHR(sbf.st_mode)) { + fprintf(stderr, "%s: %s must be character device\n", progname, argv[1]); + return 1; + } + fb = sbf.st_rdev & 0xFF; + if (fb >= 32) + fb >>= 5; + fbPath = argv[1]; + } else + fbPath = "/dev/fb0"; + con = strtoul(argv[2], &e, 10); + if (*e) { + struct stat sbf; + + if (stat(argv[2], &sbf)) { + fprintf(stderr, "%s: are you sure that %s can be used to describe vt?\n", progname, argv[2]); + return 1; + } + if (!S_ISCHR(sbf.st_mode)) { + fprintf(stderr, "%s: %s must be character device\n", progname, argv[2]); + return 1; + } + con = sbf.st_rdev & 0xFF; + } + c2m.console = con; + c2m.framebuffer = fb; + f = open(fbPath, O_RDWR); + if (f < 0) { + fprintf(stderr, "%s: Cannot open %s\n", progname, fbPath); + return 1; + } + if (ioctl(f, FBIOPUT_CON2FBMAP, &c2m)) { + fprintf(stderr, "%s: Cannot set console mapping\n", progname); + close(f); + return 1; + } + close(f); + return 0; +} + + diff --git a/TVout/fbset.db b/TVout/fbset.db new file mode 100644 index 0000000000..0dff5fb377 --- /dev/null +++ b/TVout/fbset.db @@ -0,0 +1,34 @@ + +# FBset mode database + +mode "640x480" # H: 33.78 kHz, V: 67.56 Hz + geometry 640 480 640 480 4 + timings 35242 24 64 17 1 112 2 +endmode + +mode "640x480-60" + # D: 25.176 MHz, H: 31.469 kHz, V: 59.942 Hz + geometry 640 480 640 480 16 + timings 39721 48 16 33 10 96 2 + hsync high + accel true +# rgba 5/11,6/5,5/0,0/0 +endmode + +mode "640x400-60" + # D: 25.176 MHz, H: 31.469 kHz, V: 59.942 Hz + geometry 640 400 640 400 16 + timings 39721 48 16 33 10 96 2 + hsync high + accel true +# rgba 5/11,6/5,5/0,0/0 +endmode + +mode "vga70" + # H: 31.113 kHz, V: 69.294 Hz + geometry 640 400 640 400 4 + timings 35242 64 96 35 12 112 2 +# vsync high +# csync high +endmode + diff --git a/TVout/fbset/INSTALL b/TVout/fbset/INSTALL new file mode 100644 index 0000000000..87780aa30d --- /dev/null +++ b/TVout/fbset/INSTALL @@ -0,0 +1,20 @@ + + + FBSET INSTALLATION GUIDE + + +Change the current directory to the directory containing the fbset sources and +type + + make install + +This will create the fbset binary and install it, together with the manual +pages. It also creates the standard frame buffer special device nodes. + + +The etc subdirectory contains sample frame buffer mode definitions files. Copy +one of them to /etc/fb.modes and edit it to your needs. + + +Enjoy! + diff --git a/TVout/fbset/Makefile b/TVout/fbset/Makefile new file mode 100644 index 0000000000..3a71024b01 --- /dev/null +++ b/TVout/fbset/Makefile @@ -0,0 +1,41 @@ +# +# Linux Frame Buffer Device Configuration +# + +CC = gcc -Wall -O2 -I. +BISON = bison -d +FLEX = flex +INSTALL = install +RM = rm -f + +All: fbset + + +fbset: fbset.o modes.tab.o lex.yy.o + +fbset.o: fbset.c fbset.h fb.h +modes.tab.o: modes.tab.c fbset.h fb.h +lex.yy.o: lex.yy.c fbset.h modes.tab.h + +lex.yy.c: modes.l + $(FLEX) modes.l + +modes.tab.c: modes.y + $(BISON) modes.y + +install: fbset + if [ -f /sbin/fbset ]; then rm /sbin/fbset; fi + $(INSTALL) fbset /usr/sbin + $(INSTALL) fbset.8 /usr/man/man8 + $(INSTALL) fb.modes.5 /usr/man/man5 + if [ ! -c /dev/fb0 ]; then mknod /dev/fb0 c 29 0; fi + if [ ! -c /dev/fb1 ]; then mknod /dev/fb1 c 29 32; fi + if [ ! -c /dev/fb2 ]; then mknod /dev/fb2 c 29 64; fi + if [ ! -c /dev/fb3 ]; then mknod /dev/fb3 c 29 96; fi + if [ ! -c /dev/fb4 ]; then mknod /dev/fb4 c 29 128; fi + if [ ! -c /dev/fb5 ]; then mknod /dev/fb5 c 29 160; fi + if [ ! -c /dev/fb6 ]; then mknod /dev/fb6 c 29 192; fi + if [ ! -c /dev/fb7 ]; then mknod /dev/fb7 c 29 224; fi + +clean: + $(RM) *.o fbset lex.yy.c modes.tab.c modes.tab.h diff --git a/TVout/fbset/fb.h b/TVout/fbset/fb.h new file mode 100644 index 0000000000..b901d9e204 --- /dev/null +++ b/TVout/fbset/fb.h @@ -0,0 +1,497 @@ +#ifndef _LINUX_FB_H +#define _LINUX_FB_H + +#include <asm/types.h> + +/* Definitions of frame buffers */ + +#define FB_MAJOR 29 + +#define FB_MODES_SHIFT 5 /* 32 modes per framebuffer */ +#define FB_NUM_MINORS 256 /* 256 Minors */ +#define FB_MAX (FB_NUM_MINORS / (1 << FB_MODES_SHIFT)) +#define GET_FB_IDX(node) (MINOR(node) >> FB_MODES_SHIFT) + +/* ioctls + 0x46 is 'F' */ +#define FBIOGET_VSCREENINFO 0x4600 +#define FBIOPUT_VSCREENINFO 0x4601 +#define FBIOGET_FSCREENINFO 0x4602 +#define FBIOGETCMAP 0x4604 +#define FBIOPUTCMAP 0x4605 +#define FBIOPAN_DISPLAY 0x4606 +/* 0x4607-0x460B are defined below */ +/* #define FBIOGET_MONITORSPEC 0x460C */ +/* #define FBIOPUT_MONITORSPEC 0x460D */ +/* #define FBIOSWITCH_MONIBIT 0x460E */ +#define FBIOGET_CON2FBMAP 0x460F +#define FBIOPUT_CON2FBMAP 0x4610 + +#define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ +#define FB_TYPE_PLANES 1 /* Non interleaved planes */ +#define FB_TYPE_INTERLEAVED_PLANES 2 /* Interleaved planes */ +#define FB_TYPE_TEXT 3 /* Text/attributes */ +#define FB_TYPE_VGA_PLANES 4 /* EGA/VGA planes */ + +#define FB_AUX_TEXT_MDA 0 /* Monochrome text */ +#define FB_AUX_TEXT_CGA 1 /* CGA/EGA/VGA Color text */ +#define FB_AUX_TEXT_S3_MMIO 2 /* S3 MMIO fasttext */ +#define FB_AUX_TEXT_MGA_STEP16 3 /* MGA Millenium I: text, attr, 14 reserved bytes */ +#define FB_AUX_TEXT_MGA_STEP8 4 /* other MGAs: text, attr, 6 reserved bytes */ + +#define FB_AUX_VGA_PLANES_VGA4 0 /* 16 color planes (EGA/VGA) */ +#define FB_AUX_VGA_PLANES_CFB4 1 /* CFB4 in planes (VGA) */ +#define FB_AUX_VGA_PLANES_CFB8 2 /* CFB8 in planes (VGA) */ + +#define FB_VISUAL_MONO01 0 /* Monochr. 1=Black 0=White */ +#define FB_VISUAL_MONO10 1 /* Monochr. 1=White 0=Black */ +#define FB_VISUAL_TRUECOLOR 2 /* True color */ +#define FB_VISUAL_PSEUDOCOLOR 3 /* Pseudo color (like atari) */ +#define FB_VISUAL_DIRECTCOLOR 4 /* Direct color */ +#define FB_VISUAL_STATIC_PSEUDOCOLOR 5 /* Pseudo color readonly */ + +#define FB_ACCEL_NONE 0 /* no hardware accelerator */ +#define FB_ACCEL_ATARIBLITT 1 /* Atari Blitter */ +#define FB_ACCEL_AMIGABLITT 2 /* Amiga Blitter */ +#define FB_ACCEL_S3_TRIO64 3 /* Cybervision64 (S3 Trio64) */ +#define FB_ACCEL_NCR_77C32BLT 4 /* RetinaZ3 (NCR 77C32BLT) */ +#define FB_ACCEL_S3_VIRGE 5 /* Cybervision64/3D (S3 ViRGE) */ +#define FB_ACCEL_ATI_MACH64GX 6 /* ATI Mach 64GX family */ +#define FB_ACCEL_DEC_TGA 7 /* DEC 21030 TGA */ +#define FB_ACCEL_ATI_MACH64CT 8 /* ATI Mach 64CT family */ +#define FB_ACCEL_ATI_MACH64VT 9 /* ATI Mach 64CT family VT class */ +#define FB_ACCEL_ATI_MACH64GT 10 /* ATI Mach 64CT family GT class */ +#define FB_ACCEL_SUN_CREATOR 11 /* Sun Creator/Creator3D */ +#define FB_ACCEL_SUN_CGSIX 12 /* Sun cg6 */ +#define FB_ACCEL_SUN_LEO 13 /* Sun leo/zx */ +#define FB_ACCEL_IMS_TWINTURBO 14 /* IMS Twin Turbo */ +#define FB_ACCEL_3DLABS_PERMEDIA2 15 /* 3Dlabs Permedia 2 */ +#define FB_ACCEL_MATROX_MGA2064W 16 /* Matrox MGA2064W (Millenium) */ +#define FB_ACCEL_MATROX_MGA1064SG 17 /* Matrox MGA1064SG (Mystique) */ +#define FB_ACCEL_MATROX_MGA2164W 18 /* Matrox MGA2164W (Millenium II) */ +#define FB_ACCEL_MATROX_MGA2164W_AGP 19 /* Matrox MGA2164W (Millenium II) */ +#define FB_ACCEL_MATROX_MGAG100 20 /* Matrox G100 (Productiva G100) */ +#define FB_ACCEL_MATROX_MGAG200 21 /* Matrox G200 (Myst, Mill, ...) */ +#define FB_ACCEL_SUN_CG14 22 /* Sun cgfourteen */ +#define FB_ACCEL_SUN_BWTWO 23 /* Sun bwtwo */ +#define FB_ACCEL_SUN_CGTHREE 24 /* Sun cgthree */ +#define FB_ACCEL_SUN_TCX 25 /* Sun tcx */ +#define FB_ACCEL_MATROX_MGAG400 26 /* Matrox G400 */ + +struct fb_fix_screeninfo { + char id[16]; /* identification string eg "TT Builtin" */ + char *smem_start; /* Start of frame buffer mem */ + /* (physical address) */ + __u32 smem_len; /* Length of frame buffer mem */ + __u32 type; /* see FB_TYPE_* */ + __u32 type_aux; /* Interleave for interleaved Planes */ + __u32 visual; /* see FB_VISUAL_* */ + __u16 xpanstep; /* zero if no hardware panning */ + __u16 ypanstep; /* zero if no hardware panning */ + __u16 ywrapstep; /* zero if no hardware ywrap */ + __u32 line_length; /* length of a line in bytes */ + char *mmio_start; /* Start of Memory Mapped I/O */ + /* (physical address) */ + __u32 mmio_len; /* Length of Memory Mapped I/O */ + __u32 accel; /* Type of acceleration available */ + __u16 reserved[3]; /* Reserved for future compatibility */ +}; + +/* Interpretation of offset for color fields: All offsets are from the right, + * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you + * can use the offset as right argument to <<). A pixel afterwards is a bit + * stream and is written to video memory as that unmodified. This implies + * big-endian byte order if bits_per_pixel is greater than 8. + */ +struct fb_bitfield { + __u32 offset; /* beginning of bitfield */ + __u32 length; /* length of bitfield */ + __u32 msb_right; /* != 0 : Most significant bit is */ + /* right */ +}; + +#define FB_NONSTD_HAM 1 /* Hold-And-Modify (HAM) */ + +#define FB_ACTIVATE_NOW 0 /* set values immediately (or vbl)*/ +#define FB_ACTIVATE_NXTOPEN 1 /* activate on next open */ +#define FB_ACTIVATE_TEST 2 /* don't set, round up impossible */ +#define FB_ACTIVATE_MASK 15 + /* values */ +#define FB_ACTIVATE_VBL 16 /* activate values on next vbl */ +#define FB_CHANGE_CMAP_VBL 32 /* change colormap on vbl */ +#define FB_ACTIVATE_ALL 64 /* change all VCs on this fb */ + +#define FB_ACCELF_TEXT 1 /* text mode acceleration */ + +#define FB_SYNC_HOR_HIGH_ACT 1 /* horizontal sync high active */ +#define FB_SYNC_VERT_HIGH_ACT 2 /* vertical sync high active */ +#define FB_SYNC_EXT 4 /* external sync */ +#define FB_SYNC_COMP_HIGH_ACT 8 /* composite sync high active */ +#define FB_SYNC_BROADCAST 16 /* broadcast video timings */ + /* vtotal = 144d/288n/576i => PAL */ + /* vtotal = 121d/242n/484i => NTSC */ +#define FB_SYNC_ON_GREEN 32 /* sync on green */ + +#define FB_VMODE_NONINTERLACED 0 /* non interlaced */ +#define FB_VMODE_INTERLACED 1 /* interlaced */ +#define FB_VMODE_DOUBLE 2 /* double scan */ +#define FB_VMODE_MASK 255 + +#define FB_VMODE_YWRAP 256 /* ywrap instead of panning */ +#define FB_VMODE_SMOOTH_XPAN 512 /* smooth xpan possible (internally used) */ +#define FB_VMODE_CONUPDATE 512 /* don't update x/yoffset */ + +struct fb_var_screeninfo { + __u32 xres; /* visible resolution */ + __u32 yres; + __u32 xres_virtual; /* virtual resolution */ + __u32 yres_virtual; + __u32 xoffset; /* offset from virtual to visible */ + __u32 yoffset; /* resolution */ + + __u32 bits_per_pixel; /* guess what */ + __u32 grayscale; /* != 0 Graylevels instead of colors */ + + struct fb_bitfield red; /* bitfield in fb mem if true color, */ + struct fb_bitfield green; /* else only length is significant */ + struct fb_bitfield blue; + struct fb_bitfield transp; /* transparency */ + + __u32 nonstd; /* != 0 Non standard pixel format */ + + __u32 activate; /* see FB_ACTIVATE_* */ + + __u32 height; /* height of picture in mm */ + __u32 width; /* width of picture in mm */ + + __u32 accel_flags; /* acceleration flags (hints) */ + + /* Timing: All values in pixclocks, except pixclock (of course) */ + __u32 pixclock; /* pixel clock in ps (pico seconds) */ + __u32 left_margin; /* time from sync to picture */ + __u32 right_margin; /* time from picture to sync */ + __u32 upper_margin; /* time from sync to picture */ + __u32 lower_margin; + __u32 hsync_len; /* length of horizontal sync */ + __u32 vsync_len; /* length of vertical sync */ + __u32 sync; /* see FB_SYNC_* */ + __u32 vmode; /* see FB_VMODE_* */ + __u32 reserved[6]; /* Reserved for future compatibility */ +}; + +struct fb_cmap { + __u32 start; /* First entry */ + __u32 len; /* Number of entries */ + __u16 *red; /* Red values */ + __u16 *green; + __u16 *blue; + __u16 *transp; /* transparency, can be NULL */ +}; + +struct fb_con2fbmap { + __u32 console; + __u32 framebuffer; +}; + +struct fb_monspecs { + __u32 hfmin; /* hfreq lower limit (Hz) */ + __u32 hfmax; /* hfreq upper limit (Hz) */ + __u16 vfmin; /* vfreq lower limit (Hz) */ + __u16 vfmax; /* vfreq upper limit (Hz) */ + unsigned dpms : 1; /* supports DPMS */ +}; + +#ifdef __KERNEL__ + +#include <linux/fs.h> + + +struct fb_info; +struct fb_info_gen; +struct vm_area_struct; +struct file; + + /* + * Frame buffer operations + */ + +struct fb_ops { + /* open/release and usage marking */ + int (*fb_open)(struct fb_info *info, int user); + int (*fb_release)(struct fb_info *info, int user); + /* get non settable parameters */ + int (*fb_get_fix)(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); + /* get settable parameters */ + int (*fb_get_var)(struct fb_var_screeninfo *var, int con, + struct fb_info *info); + /* set settable parameters */ + int (*fb_set_var)(struct fb_var_screeninfo *var, int con, + struct fb_info *info); + /* get colormap */ + int (*fb_get_cmap)(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); + /* set colormap */ + int (*fb_set_cmap)(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); + /* pan display */ + int (*fb_pan_display)(struct fb_var_screeninfo *var, int con, + struct fb_info *info); + /* perform fb specific ioctl */ + int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, int con, struct fb_info *info); + /* perform fb specific mmap */ + int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma); + /* switch to/from raster image mode */ + int (*fb_rasterimg)(struct fb_info *info, int start); +}; + + + /* + * This is the interface between the low-level console driver and the + * low-level frame buffer device + */ + +struct display { + /* Filled in by the frame buffer device */ + + struct fb_var_screeninfo var; /* variable infos. yoffset and vmode */ + /* are updated by fbcon.c */ + struct fb_cmap cmap; /* colormap */ + char *screen_base; /* pointer to top of virtual screen */ + /* (virtual address) */ + int visual; + int type; /* see FB_TYPE_* */ + int type_aux; /* Interleave for interleaved Planes */ + u_short ypanstep; /* zero if no hardware ypan */ + u_short ywrapstep; /* zero if no hardware ywrap */ + u_long line_length; /* length of a line in bytes */ + u_short can_soft_blank; /* zero if no hardware blanking */ + u_short inverse; /* != 0 text black on white as default */ + struct display_switch *dispsw; /* low level operations */ + void *dispsw_data; /* optional dispsw helper data */ + +#if 0 + struct fb_fix_cursorinfo fcrsr; + struct fb_var_cursorinfo *vcrsr; + struct fb_cursorstate crsrstate; +#endif + + /* Filled in by the low-level console driver */ + + struct vc_data *conp; /* pointer to console data */ + struct fb_info *fb_info; /* frame buffer for this console */ + int vrows; /* number of virtual rows */ + unsigned short cursor_x; /* current cursor position */ + unsigned short cursor_y; + int fgcol; /* text colors */ + int bgcol; + u_long next_line; /* offset to one line below */ + u_long next_plane; /* offset to next plane */ + u_char *fontdata; /* Font associated to this display */ + unsigned short _fontheightlog; + unsigned short _fontwidthlog; + unsigned short _fontheight; + unsigned short _fontwidth; + int userfont; /* != 0 if fontdata kmalloc()ed */ + u_short scrollmode; /* Scroll Method */ + short yscroll; /* Hardware scrolling */ + unsigned char fgshift, bgshift; + unsigned short charmask; /* 0xff or 0x1ff */ +}; + + +struct fb_info { + char modename[40]; /* default video mode */ + kdev_t node; + int flags; +#define FBINFO_FLAG_MODULE 1 /* Low-level driver is a module */ + struct fb_ops *fbops; + struct fb_monspecs monspecs; + struct display *disp; /* initial display variable */ + struct vc_data *display_fg; /* Console visible on this display */ + char fontname[40]; /* default font name */ + int (*changevar)(int); /* tell console var has changed */ + int (*switch_con)(int, struct fb_info*); + /* tell fb to switch consoles */ + int (*updatevar)(int, struct fb_info*); + /* tell fb to update the vars */ + void (*blank)(int, struct fb_info*); /* tell fb to (un)blank the screen */ + /* arg = 0: unblank */ + /* arg > 0: VESA level (arg-1) */ + + /* From here on everything is device dependent */ +}; + +#ifdef MODULE +#define FBINFO_FLAG_DEFAULT FBINFO_FLAG_MODULE +#else +#define FBINFO_FLAG_DEFAULT 0 +#endif + + /* + * This structure abstracts from the underlying hardware. It is not + * mandatory but used by the `generic' frame buffer operations. + * Read drivers/video/skeletonfb.c for more information. + */ + +struct fbgen_hwswitch { + void (*detect)(void); + int (*encode_fix)(struct fb_fix_screeninfo *fix, const void *par, + struct fb_info_gen *info); + int (*decode_var)(const struct fb_var_screeninfo *var, void *par, + struct fb_info_gen *info); + int (*encode_var)(struct fb_var_screeninfo *var, const void *par, + struct fb_info_gen *info); + void (*get_par)(void *par, struct fb_info_gen *info); + void (*set_par)(const void *par, struct fb_info_gen *info); + int (*getcolreg)(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, struct fb_info *info); + int (*setcolreg)(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info); + int (*pan_display)(const struct fb_var_screeninfo *var, + struct fb_info_gen *info); + int (*blank)(int blank_mode, struct fb_info_gen *info); + void (*set_disp)(const void *par, struct display *disp, + struct fb_info_gen *info); +}; + +struct fb_info_gen { + struct fb_info info; + + /* Entries for a generic frame buffer device */ + /* Yes, this starts looking like C++ */ + u_int parsize; + struct fbgen_hwswitch *fbhw; + + /* From here on everything is device dependent */ +}; + + /* + * `Generic' versions of the frame buffer device operations + */ + +extern int fbgen_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +extern int fbgen_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +extern int fbgen_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +extern int fbgen_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +extern int fbgen_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +extern int fbgen_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +extern int fbgen_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con, + struct fb_info *info); + + /* + * Helper functions + */ + +extern int fbgen_do_set_var(struct fb_var_screeninfo *var, int isactive, + struct fb_info_gen *info); +extern void fbgen_set_disp(int con, struct fb_info_gen *info); +extern void fbgen_install_cmap(int con, struct fb_info_gen *info); +extern int fbgen_update_var(int con, struct fb_info *info); +extern int fbgen_switch(int con, struct fb_info *info); +extern void fbgen_blank(int blank, struct fb_info *info); + + +struct fb_videomode { + const char *name; + struct fb_var_screeninfo var; +}; + + +/* drivers/char/fbmem.c */ +extern int register_framebuffer(struct fb_info *fb_info); +extern int unregister_framebuffer(const struct fb_info *fb_info); +extern int fbmon_valid_timings(u_int pixclock, u_int htotal, u_int vtotal, + const struct fb_info *fb_info); +extern int fbmon_dpms(const struct fb_info *fb_info); + + +extern int num_registered_fb; +extern struct fb_info *registered_fb[FB_MAX]; +extern char con2fb_map[MAX_NR_CONSOLES]; + +/* drivers/video/fbcon.c */ +extern struct display fb_display[MAX_NR_CONSOLES]; + +/* drivers/video/fbcmap.c */ +extern int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp); +extern void fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to, + int fsfromto); +extern int fb_get_cmap(struct fb_cmap *cmap, int kspc, + int (*getcolreg)(u_int, u_int *, u_int *, u_int *, + u_int *, struct fb_info *), + struct fb_info *fb_info); +extern int fb_set_cmap(struct fb_cmap *cmap, int kspc, + int (*setcolreg)(u_int, u_int, u_int, u_int, u_int, + struct fb_info *), + struct fb_info *fb_info); +extern struct fb_cmap *fb_default_cmap(int len); +extern void fb_invert_cmaps(void); + +/* VESA Blanking Levels */ +#define VESA_NO_BLANKING 0 +#define VESA_VSYNC_SUSPEND 1 +#define VESA_HSYNC_SUSPEND 2 +#define VESA_POWERDOWN 3 + +#endif /* __KERNEL__ */ + +#if 1 + +#define FBCMD_GET_CURRENTPAR 0xDEAD0005 +#define FBCMD_SET_CURRENTPAR 0xDEAD8005 + +#endif + + +#if 1 /* Preliminary */ + + /* + * Hardware Cursor + */ + +#define FBIOGET_FCURSORINFO 0x4607 +#define FBIOGET_VCURSORINFO 0x4608 +#define FBIOPUT_VCURSORINFO 0x4609 +#define FBIOGET_CURSORSTATE 0x460A +#define FBIOPUT_CURSORSTATE 0x460B + + +struct fb_fix_cursorinfo { + __u16 crsr_width; /* width and height of the cursor in */ + __u16 crsr_height; /* pixels (zero if no cursor) */ + __u16 crsr_xsize; /* cursor size in display pixels */ + __u16 crsr_ysize; + __u16 crsr_color1; /* colormap entry for cursor color1 */ + __u16 crsr_color2; /* colormap entry for cursor color2 */ +}; + +struct fb_var_cursorinfo { + __u16 width; + __u16 height; + __u16 xspot; + __u16 yspot; + __u8 data[1]; /* field with [height][width] */ +}; + +struct fb_cursorstate { + __s16 xoffset; + __s16 yoffset; + __u16 mode; +}; + +#define FB_CURSOR_OFF 0 +#define FB_CURSOR_ON 1 +#define FB_CURSOR_FLASH 2 + +#endif /* Preliminary */ + +#endif /* _LINUX_FB_H */ diff --git a/TVout/fbset/fb.modes.5 b/TVout/fbset/fb.modes.5 new file mode 100644 index 0000000000..0918f08f5d --- /dev/null +++ b/TVout/fbset/fb.modes.5 @@ -0,0 +1,228 @@ +.TH fb.modes 8 "Aug 1996" local "Linux frame buffer utils" +.SH NAME +fb.modes \- frame buffer modes file +.SH DESCRIPTION +.I /etc/fb.modes +contains an unlimited number of video mode descriptions. The general format +of a video mode is: +.sp +mode +.RI \" name \" +.RS +geometry +.RI < xres > +.RI < yres > +.RI < vxres > +.RI < vyres > +.RI < depth > +.br +timings +.RI < pixclock > +.RI < left > +.RI < right > +.RI < upper > +.RI < lower > +.RI < hslen > +.RI < vslen > +.br +.B options +.RI < value > +.RE +endmode +.SH OPTIONS +geometry options: +.RS +.TP +.I xres +visible horizontal resolution (in pixels) +.TP +.I yres +visible vertical resolution (in pixels) +.TP +.I vxres +virtual horizontal resolution (in pixels) +.TP +.I vyres +virtual vertical resolution (in pixels) +.TP +.I depth +display depth (in bits per pixel) +.RE +.PP +timing options: +.RS +.TP +.I pixclock +length of one pixel (in picoseconds) +.TP +.I left +left margin (in pixels) +.TP +.I right +right margin (in pixels) +.TP +.I upper +upper margin (in pixel lines) +.TP +.I lower +lower margin (in pixel lines) +.TP +.I hslen +horizontal sync length (in pixels) +.TP +.I vslen +vertical sync length (in pixel lines) +.RE +.PP +other options: +.RS +the first value of this options is the default +.TP +.IR \fBhsync "\ {" low | high } +the horizontal sync polarity +.TP +.IR \fBvsync "\ {" low | high } +the vertical sync polarity +.TP +.IR \fBcsync "\ {" low | high } +the composite sync polarity +.TP +.IR \fBextsync "\ {" false | true } +enable or disable external resync. If enabled the sync timings are not +generated by the frame buffer device and must be provided externally +instead. Note that this option may not be supported by every frame buffer +device +.TP +.IR \fBlaced "\ {" false | true } +enable or disable interlace. If enabled the display will be split in two +frames, each frame contains only even and odd lines respectively. These two +frames will be displayed alternating, this way twice the lines can be +displayed and the vertical frequency for monitor stays the same, but the +visible vertical frequency gets halved +.TP +.IR \fBdouble "\ {" false | true } +enable or disable doublescan. If enabled every line will be displayed twice +and this way the horizontal frequency can easily be doubled, so that the +same resolution can be displayed on different monitors, even if the +horizontal frequency specification differs. Note that this option may not be +supported by every frame buffer device +.RE +.SH INTERNALS +Generally a frame buffer display is organized as follows: +.sp +.ad c ++\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-+\-\-\-+ +.br +.RB "|\ \ \ |\ \ \ \ \ \ \ " ^ "\ \ \ \ \ \ \ |\ \ \ |\ \ \ |" +.br +.RB "|\ \ \ |\ \ \ \ \ \ \ " | "\ " \fI5 "\ \ \ \ \ |\ \ \ |\ \ \ |" +.br +.RB "|\ \ \ |\ \ \ \ \ \ \ " v "\ \ \ \ \ \ \ |\ \ \ |\ \ \ |" +.br ++\-\-\-#################\-\-\-+\-\-\-+ +.br +.RB "|\ \ \ #\ \ \ \ \ \ \ " ^ "\ \ \ \ \ \ \ #\ \ \ |\ \ \ |" +.br +.RB "|\ \ \ #\ \ \ \ \ \ \ " | "\ \ \ \ \ \ \ #\ \ \ |\ \ \ |" +.br +.RB "|\ \ \ #\ \ \ \ \ \ \ " | "\ \ \ \ \ \ \ #\ \ \ |\ \ \ |" +.br +.RI "| " 1 " # " \fB| " " 2 " # " 3 " | " 4 " |" +.br +.RB "|" "<\->" "#" "<\-\-\-\-\-\-+\-\-\-\-\-\->" "#" "<\->" "|" "<\->" "|" +.br +.RB "|\ \ \ #\ \ \ \ \ \ \ " | "\ \ \ \ \ \ \ #\ \ \ |\ \ \ |" +.br +.RB "|\ \ \ #\ \ \ \ \ \ \ " | "\ " \fI6 "\ \ \ \ \ #\ \ \ |\ \ \ |" +.br +.RB "|\ \ \ #\ \ \ \ \ \ \ " | "\ \ \ \ \ \ \ #\ \ \ |\ \ \ |" +.br +.RB "|\ \ \ #\ \ \ \ \ \ \ " v "\ \ \ \ \ \ \ #\ \ \ |\ \ \ |" +.br ++\-\-\-#################\-\-\-+\-\-\-+ +.br +.RB "|\ \ \ |\ \ \ \ \ \ \ " ^ "\ \ \ \ \ \ \ |\ \ \ |\ \ \ |" +.br +.RB "|\ \ \ |\ \ \ \ \ \ \ " | "\ " \fI7 "\ \ \ \ \ |\ \ \ |\ \ \ |" +.br +.RB "|\ \ \ |\ \ \ \ \ \ \ " v "\ \ \ \ \ \ \ |\ \ \ |\ \ \ |" +.br ++\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-+\-\-\-+ +.br +.RB "|\ \ \ |\ \ \ \ \ \ \ " ^ "\ \ \ \ \ \ \ |\ \ \ |\ \ \ |" +.br +.RB "|\ \ \ |\ \ \ \ \ \ \ " | "\ " \fI8 "\ \ \ \ \ |\ \ \ |\ \ \ |" +.br +.RB "|\ \ \ |\ \ \ \ \ \ \ " v "\ \ \ \ \ \ \ |\ \ \ |\ \ \ |" +.br ++\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-+\-\-\-+ +.sp +.ad n +.RS +.I 1 +\t left margin +.br +.I 2 +\t xres +.br +.I 3 +\t right margin +.br +.I 4 +\t horizontal sync len +.br +.I 5 +\t upper margin +.br +.I 6 +\t yres +.br +.I 7 +\t lower margin +.br +.I 8 +\t vertical sync len +.RE +.sp +The area bordered with `#' is the visible display area. Horizontal and +vertical frequencies can now easily be calculated, for this the sum of +horizontal or vertical values are important +.RS +.sp +htotal\ =\ left\ +\ xres\ +\ right\ +\ hslen +.br +vtotal\ =\ upper\ +\ yres\ +\ lower\ +\ vslen +.sp +.RE +The length of one line can now be calculated with pixclock +.RS +.sp +line\ =\ pixclock\ *\ htotal +.sp +.RE +and we have the horizontal frequency +.RS +.sp +hfreq\ =\ 1E12\ /\ line\ =\ 1E12\ /\ (pixclock\ *\ htotal) +.sp +.RE +To get the vertical frequency vtotal must eventually adjusted. If the +display is laced, vtotal must be halved or if the display is a doublescan +one, vtotal must be doubled. Now we can calculate the length of one frame +.RS +.sp +if\ (lace)\ \ \ vtotal\ /=\ 2 +.br +if\ (double)\ vtotal\ *=\ 2 +.sp +frame\ =\ vtotal\ *\ line +.sp +.RE +and we get also the vertical frequency +.RS +.sp +vfreq\ =\ 1E12\ /\ frame\ =\ hfreq\ /\ vtotal +.sp +.RE +.SH SEE ALSO +.BR fbset "(8), " fbdev (4) diff --git a/TVout/fbset/fbset.8 b/TVout/fbset/fbset.8 new file mode 100644 index 0000000000..74e7d3c1b8 --- /dev/null +++ b/TVout/fbset/fbset.8 @@ -0,0 +1,242 @@ +.TH fbset 8 "July 1998" local "Linux frame buffer utils" +.SH NAME +fbset \- show and modify frame buffer device settings +.SH SYNOPSIS +.B fbset +.RI [ options ] +.RI [ mode ] +.SH DESCRIPTION +.B This documentation is out of date!! +.PP +.B fbset +is a system utility to show or change the settings of the frame buffer +device. The frame buffer device provides a simple and unique interface to +access different kinds of graphic displays. +.PP +Frame buffer devices are accessed via special device nodes located in the +/dev directory. The naming scheme for these nodes is always +.IR \fBfb < n >, +where +.I n +is the number of the used frame buffer device. +.PP +.B fbset +uses an own video mode database located in /etc/fb.modes. An unlimited +number of video modes can be defined in this database. For further +information see +.BR fb.modes (5). +.SH OPTIONS +If no option is given, +.B fbset +will display the current frame buffer settings. +.sp +General options: +.RS +.TP +.BR \-\-help ",\ " \-h +display an usage information +.TP +.BR \-\-now ",\ " \-n +change the video mode immediately. If no frame buffer device is given via +.B \-fb +, then this option is activated by default +.TP +.BR \-\-show ",\ " \-s +display the video mode settings. This is default if no further option or +only a frame buffer device via +.B \-fb +is given +.TP +.BR \-\-info ",\ " \-i +display all available frame buffer information +.TP +.BR \-\-verbose ",\ " \-v +display information what +.B fbset +is currently doing +.TP +.BR \-\-version ",\ " \-V +display the version information about +.B fbset +.TP +.BR \-\-xfree86 ",\ " \-x +display the timing information as it's needed by XFree86 +.RE +.PP +Frame buffer device nodes: +.RS +.TP +.BR \-fb "\ <" \fIdevice > +.I device +gives the frame buffer device node. If no device via +.B \-fb +is given, +.I /dev/fb0 +is used +.TP +.RE +.PP +Video mode database: +.RS +.TP +.BR \-db "\ <" \fIfile > +set an alternative video mode database file (default is +.IR /etc/fb.modes ), +see also +.BR fb.modes (5) +.RE +.PP +Display geometry: +.RS +.TP +.BR \-xres "\ <" \fIvalue > +set visible horizontal resolution (in pixels) +.TP +.BR \-yres "\ <" \fIvalue > +set visible vertical resolution (in pixels) +.TP +.BR \-vxres "\ <" \fIvalue > +set virtual horizontal resolution (in pixels) +.TP +.BR \-vyres "\ <" \fIvalue > +set virtual vertical resolution (in pixels) +.TP +.BR \-depth "\ <" \fIvalue > +set display depth (in bits per pixel) +.TP +.BR \-\-geometry ",\ " \-g "\ ..." +set all geometry parameters at once in the order +.RI < xres > +.RI < yres > +.RI < vxres > +.RI < vyres > +.RI < depth >, +e.g. +.B \-g +.I 640 400 640 400 4 +.TP +.BR \-match "\ \ \ \ \ \ " +make the physical resolution match the virtual resolution +.RE +.PP +Display timings: +.RS +.TP +.BR \-pixclock "\ <" \fIvalue > +set the length of one pixel (in picoseconds). Note that the frame buffer +device may only support some pixel lengths +.TP +.BR \-left "\ <" \fIvalue > +set left margin (in pixels) +.TP +.BR \-right "\ <" \fIvalue > +set right margin (in pixels) +.TP +.BR \-upper "\ <" \fIvalue > +set upper margin (in pixel lines) +.TP +.BR \-lower "\ <" \fIvalue > +set lower margin (in pixel lines) +.TP +.BR \-hslen "\ <" \fIvalue > +set horizontal sync length (in pixels) +.TP +.BR \-vslen "\ <" \fIvalue > +set vertical sync length (in pixel lines) +.TP +.BR \-\-timings ",\ " \-t "\ ..." +set all timing parameters at once in the order +.RI < pixclock > +.RI < left > +.RI < right > +.RI < upper > +.RI < lower > +.RI < hslen > +.RI < vslen >, +e.g. +.B \-g +.I 35242 64 96 35 12 112 2 +.RE +.PP +Display flags: +.RS +.TP +.IR \fB\-hsync "\ {" low | high } +set the horizontal sync polarity +.TP +.IR \fB\-vsync "\ {" low | high } +set the vertical sync polarity +.TP +.IR \fB\-csync "\ {" low | high } +set the composite sync polarity +.TP +.IR \fB\-extsync "\ {" false | true } +enable or disable external resync. If enabled the sync timings are not +generated by the frame buffer device and must be provided externally +instead. Note that this option may not be supported by every frame buffer +device +.TP +.IR \fB\-bcast "\ {" false | true } +enable or disable broadcast modes. If enabled the frame buffer generates the +exact timings for several broadcast modes (e.g. PAL or NTSC). Note that +this option may not be supported by every frame buffer device +.TP +.IR \fB\-laced "\ {" false | true } +enable or disable interlace. If enabled the display will be split in two +frames, each frame contains only even and odd lines respectively. These two +frames will be displayed alternating, this way twice the lines can be +displayed and the vertical frequency for the monitor stays the same, but the +visible vertical frequency gets halved +.TP +.IR \fB\-double "\ {" false | true } +enable or disable doublescan. If enabled every line will be displayed twice +and this way the horizontal frequency can easily be doubled, so that the +same resolution can be displayed on different monitors, even if the +horizontal frequency specification differs. Note that this option may not be +supported by every frame buffer device +.RE +.PP +Display positioning: +.RS +.TP +.IR \fB\-move "\ {" left | right | up | down } +move the visible part of the display in the specified direction +.TP +.BR \-step "\ <" \fIvalue > +set step size for display positioning (in pixels or pixel lines), if +.B \-step +is not given display will be moved 8 pixels horizontally or 2 pixel lines +vertically +.RE +.SH EXAMPLE +To set the used video mode for +.B X +insert the following in rc.local: +.RS +.sp +.B fbset +-fb +.I /dev/fb0 +vga +.sp +.RE +and make the used frame buffer device known to +.BR X : +.RS +.sp +.B export +.RI FRAMEBUFFER= /dev/fb0 +.RE +.SH FILES +.I /dev/fb* +.br +.I /etc/fb.modes +.SH SEE ALSO +.BR fb.modes "(5), " fbdev (4) +.SH AUTHORS +.TP +Geert Uytterhoeven <Geert.Uytterhoeven@cs.kuleuven.ac.be> +.TP +Roman Zippel <zippel@fh-brandenburg.de> +.br +man files diff --git a/TVout/fbset/fbset.c b/TVout/fbset/fbset.c new file mode 100644 index 0000000000..a9da078ede --- /dev/null +++ b/TVout/fbset/fbset.c @@ -0,0 +1,1054 @@ +/* + * Linux Frame Buffer Device Configuration + * + * © Copyright 1995-1999 by Geert Uytterhoeven + * (Geert.Uytterhoeven@cs.kuleuven.ac.be) + * + * -------------------------------------------------------------------------- + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of the Linux + * distribution for more details. + * + * Petr Vandrovec <vandrove@vc.cvut.cz>: + * -grayscale, -rgba, -nonstd, VGA modes reporting + * + * Brad Midgley <brad@exodus.pht.com>: + * -match + * + */ + + +#include <stdarg.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <ctype.h> +#include <sys/stat.h> + +struct file; +struct inode; + +#include "fb.h" + +#include "fbset.h" + + + /* + * Default Frame Buffer Special Device Node + */ + +#define DEFAULT_FRAMEBUFFER "/dev/fb0" + + + /* + * Default Video Mode Database File + */ + +#define DEFAULT_MODEDBFILE "/etc/fb.modes" + + + /* + * Command Line Options + */ + +static const char *ProgramName; + +static int Opt_test = 0; +static int Opt_show = 0; +static int Opt_info = 0; +static int Opt_version = 0; +static int Opt_verbose = 0; +static int Opt_xfree86 = 0; +static int Opt_change = 0; +static int Opt_all = 0; + +static const char *Opt_fb = NULL; +const char *Opt_modedb = DEFAULT_MODEDBFILE; +static const char *Opt_xres = NULL; +static const char *Opt_yres = NULL; +static const char *Opt_vxres = NULL; +static const char *Opt_vyres = NULL; +static const char *Opt_depth = NULL; +static const char *Opt_pixclock = NULL; +static const char *Opt_left = NULL; +static const char *Opt_right = NULL; +static const char *Opt_upper = NULL; +static const char *Opt_lower = NULL; +static const char *Opt_hslen = NULL; +static const char *Opt_vslen = NULL; +static const char *Opt_accel = NULL; +static const char *Opt_hsync = NULL; +static const char *Opt_vsync = NULL; +static const char *Opt_csync = NULL; +static const char *Opt_gsync = NULL; +static const char *Opt_extsync = NULL; +static const char *Opt_bcast = NULL; +static const char *Opt_laced = NULL; +static const char *Opt_double = NULL; +static const char *Opt_move = NULL; +static const char *Opt_step = NULL; +static const char *Opt_modename = NULL; +static const char *Opt_rgba = NULL; +static const char *Opt_nonstd = NULL; +static const char *Opt_grayscale = NULL; +static const char *Opt_matchyres = NULL; + +static struct { + const char *name; + const char **value; + const int change; +} Options[] = { + { "-fb", &Opt_fb, 0 }, + { "-db", &Opt_modedb, 0 }, + { "-xres", &Opt_xres, 1 }, + { "-yres", &Opt_yres, 1 }, + { "-vxres", &Opt_vxres, 1 }, + { "-vyres", &Opt_vyres, 1 }, + { "-depth", &Opt_depth, 1 }, + { "-nonstd", &Opt_nonstd, 1}, + { "-pixclock", &Opt_pixclock, 1 }, + { "-left", &Opt_left, 1 }, + { "-right", &Opt_right, 1 }, + { "-upper", &Opt_upper, 1 }, + { "-lower", &Opt_lower, 1 }, + { "-hslen", &Opt_hslen, 1 }, + { "-vslen", &Opt_vslen, 1 }, + { "-accel", &Opt_accel, 1 }, + { "-hsync", &Opt_hsync, 1 }, + { "-vsync", &Opt_vsync, 1 }, + { "-csync", &Opt_csync, 1 }, + { "-gsync", &Opt_gsync, 1 }, + { "-extsync", &Opt_extsync, 1 }, + { "-bcast", &Opt_bcast, 1 }, + { "-laced", &Opt_laced, 1 }, + { "-double", &Opt_double, 1 }, + { "-move", &Opt_move, 1 }, + { "-step", &Opt_step, 1 }, + { "-rgba", &Opt_rgba, 1 }, + { "-grayscale", &Opt_grayscale, 1 }, + { NULL, NULL, 0 } +}; + + + /* + * Video Mode Database + */ + +struct VideoMode *VideoModes = NULL; + + + /* + * Hardware Text Modes + */ + +static struct textentry { + __u32 id; + const char *name; +} Textmodes[] = { + { FB_AUX_TEXT_MDA, "Monochrome text" }, + { FB_AUX_TEXT_CGA, "CGA/EGA/VGA Color text" }, + { FB_AUX_TEXT_S3_MMIO, "S3 MMIO fasttext" }, + { FB_AUX_TEXT_MGA_STEP16, "MGA Millennium I step 16 text" }, + { FB_AUX_TEXT_MGA_STEP8, "MGA step 8 text" }, +}; + +static struct textentry VGAModes[] = { + { FB_AUX_VGA_PLANES_VGA4, "VGA 16 colors in 4 planes" }, + { FB_AUX_VGA_PLANES_CFB4, "VGA 16 colors in 1 plane" }, + { FB_AUX_VGA_PLANES_CFB8, "VGA 256 colors in 4 planes" }, + /* last entry has name == NULL */ + { 0, NULL} +}; + + /* + * Hardware Accelerators + */ + +static struct accelentry { + __u32 id; + const char *name; +} Accelerators[] = { + { FB_ACCEL_NONE, "No" }, + { FB_ACCEL_ATARIBLITT, "Atari Blitter" }, + { FB_ACCEL_AMIGABLITT, "Amiga Blitter" }, + { FB_ACCEL_S3_TRIO64, "S3 Trio64" }, + { FB_ACCEL_NCR_77C32BLT, "NCR 77C32BLT" }, + { FB_ACCEL_S3_VIRGE, "S3 ViRGE" }, + { FB_ACCEL_ATI_MACH64GX, "ATI Mach64GX" }, + { FB_ACCEL_DEC_TGA, "DEC 21030 TGA" }, + { FB_ACCEL_ATI_MACH64CT, "ATI Mach64CT" }, + { FB_ACCEL_ATI_MACH64VT, "ATI Mach64VT" }, + { FB_ACCEL_ATI_MACH64GT, "ATI Mach64GT" }, + { FB_ACCEL_SUN_CREATOR, "Sun Creator/Creator3D" }, + { FB_ACCEL_SUN_CGSIX, "Sun cg6" }, + { FB_ACCEL_SUN_LEO, "Sun leo/zx" }, + { FB_ACCEL_IMS_TWINTURBO, "IMS Twin Turbo" }, + { FB_ACCEL_3DLABS_PERMEDIA2, "3Dlabs Permedia 2" }, + { FB_ACCEL_MATROX_MGA2064W, "Matrox MGA2064W (Millennium)" }, + { FB_ACCEL_MATROX_MGA1064SG, "Matrox MGA1064SG (Mystique)" }, + { FB_ACCEL_MATROX_MGA2164W, "Matrox MGA2164W (Millennium II)" }, + { FB_ACCEL_MATROX_MGA2164W_AGP, "Matrox MGA2164W (Millennium II AGP)" }, + { FB_ACCEL_MATROX_MGAG100, "Matrox G100 (Productiva G100)" }, + { FB_ACCEL_MATROX_MGAG200, "Matrox G200 (Millennium, Mystique)" }, + { FB_ACCEL_SUN_CG14, "Sun cg14" }, + { FB_ACCEL_SUN_BWTWO, "Sun bw2" }, + { FB_ACCEL_SUN_CGTHREE, "Sun cg3" }, + { FB_ACCEL_SUN_TCX, "Sun tcx" }, + { FB_ACCEL_MATROX_MGAG400, "Matrox G400" }, +}; + + + /* + * Current Video Mode + */ + +struct VideoMode Current; + + + /* + * Function Prototypes + */ + +int OpenFrameBuffer(const char *name); +void CloseFrameBuffer(int fh); +void GetVarScreenInfo(int fh, struct fb_var_screeninfo *var); +void SetVarScreenInfo(int fh, struct fb_var_screeninfo *var); +void GetFixScreenInfo(int fh, struct fb_fix_screeninfo *fix); +static void ConvertFromVideoMode(const struct VideoMode *vmode, + struct fb_var_screeninfo *var); +static void ConvertToVideoMode(const struct fb_var_screeninfo *var, + struct VideoMode *vmode); +static int atoboolean(const char *var); +static void ReadModeDB(void); +static struct VideoMode *FindVideoMode(const char *name); +static void ModifyVideoMode(struct VideoMode *vmode); +static void DisplayVModeInfo(struct VideoMode *vmode); +static void DisplayFBInfo(struct fb_fix_screeninfo *fix); +static int FillScanRates(struct VideoMode *vmode); +static void Usage(void) __attribute__ ((noreturn)); +int main(int argc, char *argv[]); + + + /* + * Print an Error Message and Exit + */ + +void Die(const char *fmt, ...) +{ + va_list ap; + + fflush(stdout); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(1); +} + + + /* + * Open the Frame Buffer Device + */ + +int OpenFrameBuffer(const char *name) +{ + int fh; + + if (Opt_verbose) + printf("Opening frame buffer device `%s'\n", name); + + if ((fh = open(name, O_RDONLY)) == -1) + Die("open %s: %s\n", name, strerror(errno)); + return fh; +} + + + /* + * Close the Frame Buffer Device + */ + +void CloseFrameBuffer(int fh) +{ + close(fh); +} + + /* + * Get the Variable Part of the Screen Info + */ + +void GetVarScreenInfo(int fh, struct fb_var_screeninfo *var) +{ + if (ioctl(fh, FBIOGET_VSCREENINFO, var)) + Die("ioctl FBIOGET_VSCREENINFO: %s\n", strerror(errno)); +} + + + /* + * Set (and Get) the Variable Part of the Screen Info + */ + +void SetVarScreenInfo(int fh, struct fb_var_screeninfo *var) +{ + if (ioctl(fh, FBIOPUT_VSCREENINFO, var)) + Die("ioctl FBIOPUT_VSCREENINFO: %s\n", strerror(errno)); +} + + + /* + * Get the Fixed Part of the Screen Info + */ + +void GetFixScreenInfo(int fh, struct fb_fix_screeninfo *fix) +{ + if (ioctl(fh, FBIOGET_FSCREENINFO, fix)) + Die("ioctl FBIOGET_FSCREENINFO: %s\n", strerror(errno)); +} + + + /* + * Conversion Routines + */ + +static void ConvertFromVideoMode(const struct VideoMode *vmode, + struct fb_var_screeninfo *var) +{ + memset(var, 0, sizeof(struct fb_var_screeninfo)); + var->xres = vmode->xres; + var->yres = vmode->yres; + var->xres_virtual = vmode->vxres; + var->yres_virtual = vmode->vyres; + var->bits_per_pixel = vmode->depth; + var->nonstd = vmode->nonstd; + if (Opt_test) + var->activate = FB_ACTIVATE_TEST; + else + var->activate = FB_ACTIVATE_NOW; + if (Opt_all) + var->activate = FB_ACTIVATE_ALL; + var->accel_flags = vmode->accel_flags; + var->pixclock = vmode->pixclock; + var->left_margin = vmode->left; + var->right_margin = vmode->right; + var->upper_margin = vmode->upper; + var->lower_margin = vmode->lower; + var->hsync_len = vmode->hslen; + var->vsync_len = vmode->vslen; + if (vmode->hsync == HIGH) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (vmode->vsync == HIGH) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + if (vmode->csync == HIGH) + var->sync |= FB_SYNC_COMP_HIGH_ACT; + if (vmode->gsync == HIGH) + var->sync |= FB_SYNC_ON_GREEN; + if (vmode->extsync == TRUE) + var->sync |= FB_SYNC_EXT; + if (vmode->bcast == TRUE) + var->sync |= FB_SYNC_BROADCAST; + if (vmode->laced == TRUE) + var->vmode = FB_VMODE_INTERLACED; + else if (vmode->dblscan == TRUE) + var->vmode = FB_VMODE_DOUBLE; + else + var->vmode = FB_VMODE_NONINTERLACED; + var->vmode |= FB_VMODE_CONUPDATE; + var->red.length = vmode->red.length; + var->red.offset = vmode->red.offset; + var->green.length = vmode->green.length; + var->green.offset = vmode->green.offset; + var->blue.length = vmode->blue.length; + var->blue.offset = vmode->blue.offset; + var->transp.length = vmode->transp.length; + var->transp.offset = vmode->transp.offset; + var->grayscale = vmode->grayscale; +} + + +static void ConvertToVideoMode(const struct fb_var_screeninfo *var, + struct VideoMode *vmode) +{ + vmode->name = NULL; + vmode->xres = var->xres; + vmode->yres = var->yres; + vmode->vxres = var->xres_virtual; + vmode->vyres = var->yres_virtual; + vmode->depth = var->bits_per_pixel; + vmode->nonstd = var->nonstd; + vmode->accel_flags = var->accel_flags; + vmode->pixclock = var->pixclock; + vmode->left = var->left_margin; + vmode->right = var->right_margin; + vmode->upper = var->upper_margin; + vmode->lower = var->lower_margin; + vmode->hslen = var->hsync_len; + vmode->vslen = var->vsync_len; + vmode->hsync = var->sync & FB_SYNC_HOR_HIGH_ACT ? HIGH : LOW; + vmode->vsync = var->sync & FB_SYNC_VERT_HIGH_ACT ? HIGH : LOW; + vmode->csync = var->sync & FB_SYNC_COMP_HIGH_ACT ? HIGH : LOW; + vmode->gsync = var->sync & FB_SYNC_ON_GREEN ? TRUE : FALSE; + vmode->extsync = var->sync & FB_SYNC_EXT ? TRUE : FALSE; + vmode->bcast = var->sync & FB_SYNC_BROADCAST ? TRUE : FALSE; + vmode->grayscale = var->grayscale; + vmode->laced = FALSE; + vmode->dblscan = FALSE; + switch (var->vmode & FB_VMODE_MASK) { + case FB_VMODE_INTERLACED: + vmode->laced = TRUE; + break; + case FB_VMODE_DOUBLE: + vmode->dblscan = TRUE; + break; + } + vmode->red.length = var->red.length; + vmode->red.offset = var->red.offset; + vmode->green.length = var->green.length; + vmode->green.offset = var->green.offset; + vmode->blue.length = var->blue.length; + vmode->blue.offset = var->blue.offset; + vmode->transp.length = var->transp.length; + vmode->transp.offset = var->transp.offset; + FillScanRates(vmode); +} + + +static int atoboolean(const char *var) +{ + int value = 0; + + if (!strcasecmp(var, "false") || !strcasecmp(var, "low") || + !strcasecmp(var, "no") || !strcasecmp(var, "off") || + !strcmp(var, "0")) + value = 0; + else if (!strcasecmp(var, "true") || !strcasecmp(var, "high") || + !strcasecmp(var, "yes") || !strcasecmp(var, "on") || + !strcmp(var, "1")) + value = 1; + else + Die("Invalid value `%s'\n", var); + + return value; +} + + +void AddVideoMode(const struct VideoMode *vmode) +{ + struct VideoMode *vmode2; + + if (FindVideoMode(vmode->name)) + Die("%s:%d: Duplicate mode name `%s'\n", Opt_modedb, line, + vmode->name); + vmode2 = malloc(sizeof(struct VideoMode)); + *vmode2 = *vmode; + if (!FillScanRates(vmode2)) + Die("%s:%d: Bad video mode `%s'\n", Opt_modedb, line, vmode2->name); + vmode2->next = VideoModes; + VideoModes = vmode2; +} + + + /* + * Read the Video Mode Database + */ + +static void ReadModeDB(void) +{ + if (Opt_verbose) + printf("Reading mode database from file `%s'\n", Opt_modedb); + + if (!(yyin = fopen(Opt_modedb, "r"))) + Die("fopen %s: %s\n", Opt_modedb, strerror(errno)); + yyparse(); + fclose(yyin); +} + + +static void getColor(struct color *color, const char** opt) +{ + char* ptr; + + color->length = 0; + color->offset = 0; + ptr = (char*)(*opt); + if (!ptr) + return; + color->length = strtoul(ptr, &ptr, 0); + if (!ptr) + return; + if (*ptr == '/') + color->offset = strtoul(ptr+1, &ptr, 0); + if (ptr) { + while (*ptr && isspace(*ptr)) + ptr++; + if (*ptr == ',') { + ptr++; + } else if (*ptr) + Die("Bad RGBA syntax, rL/rO,gL/gO,bL/bO,tL/tO or rL,gL,bL,tL\n"); + } + *opt = ptr; + return; +} + +void makeRGBA(struct VideoMode *vmode, const char* opt) +{ + getColor(&vmode->red, &opt); + getColor(&vmode->green, &opt); + getColor(&vmode->blue, &opt); + getColor(&vmode->transp, &opt); +} + + /* + * Find a Video Mode + */ + +static struct VideoMode *FindVideoMode(const char *name) +{ + struct VideoMode *vmode; + + for (vmode = VideoModes; vmode; vmode = vmode->next) + if (!strcmp(name, vmode->name)) + break; + + return vmode; +} + + + /* + * Modify a Video Mode + */ + +static void ModifyVideoMode(struct VideoMode *vmode) +{ + u_int hstep = 8, vstep = 2; + + if (Opt_xres) + vmode->xres = strtoul(Opt_xres, NULL, 0); + if (Opt_yres) + vmode->yres = strtoul(Opt_yres, NULL, 0); + if (Opt_vxres) + vmode->vxres = strtoul(Opt_vxres, NULL, 0); + if (Opt_vyres) + vmode->vyres = strtoul(Opt_vyres, NULL, 0); + if (Opt_depth) + vmode->depth = strtoul(Opt_depth, NULL, 0); + if (Opt_nonstd) + vmode->nonstd = strtoul(Opt_nonstd, NULL, 0); + if (Opt_accel) + vmode->accel_flags = atoboolean(Opt_accel) ? FB_ACCELF_TEXT : 0; + if (Opt_pixclock) + vmode->pixclock = strtoul(Opt_pixclock, NULL, 0); + if (Opt_left) + vmode->left = strtoul(Opt_left, NULL, 0); + if (Opt_right) + vmode->right = strtoul(Opt_right, NULL, 0); + if (Opt_upper) + vmode->upper = strtoul(Opt_upper, NULL, 0); + if (Opt_lower) + vmode->lower = strtoul(Opt_lower, NULL, 0); + if (Opt_hslen) + vmode->hslen = strtoul(Opt_hslen, NULL, 0); + if (Opt_vslen) + vmode->vslen = strtoul(Opt_vslen, NULL, 0); + if (Opt_hsync) + vmode->hsync = atoboolean(Opt_hsync); + if (Opt_vsync) + vmode->vsync = atoboolean(Opt_vsync); + if (Opt_csync) + vmode->csync = atoboolean(Opt_csync); + if (Opt_gsync) + vmode->gsync = atoboolean(Opt_gsync); + if (Opt_extsync) + vmode->extsync = atoboolean(Opt_extsync); + if (Opt_bcast) + vmode->bcast = atoboolean(Opt_bcast); + if (Opt_laced) + vmode->laced = atoboolean(Opt_laced); + if (Opt_double) + vmode->dblscan = atoboolean(Opt_double); + if (Opt_grayscale) + vmode->grayscale = atoboolean(Opt_grayscale); + if (Opt_step) + hstep = vstep = strtoul(Opt_step, NULL, 0); + if (Opt_matchyres) + vmode->vyres = vmode->yres; + if (Opt_move) { + if (!strcasecmp(Opt_move, "left")) { + if (hstep > vmode->left) + Die("The left margin cannot be negative\n"); + vmode->left -= hstep; + vmode->right += hstep; + } else if (!strcasecmp(Opt_move, "right")) { + if (hstep > vmode->right) + Die("The right margin cannot be negative\n"); + vmode->left += hstep; + vmode->right -= hstep; + } else if (!strcasecmp(Opt_move, "up")) { + if (vstep > vmode->upper) + Die("The upper margin cannot be negative\n"); + vmode->upper -= vstep; + vmode->lower += vstep; + } else if (!strcasecmp(Opt_move, "down")) { + if (vstep > vmode->lower) + Die("The lower margin cannot be negative\n"); + vmode->upper += vstep; + vmode->lower -= vstep; + } else + Die("Invalid direction `%s'\n", Opt_move); + } + if (Opt_rgba) { + makeRGBA(vmode, Opt_rgba); + } + if (!FillScanRates(vmode)) + Die("Bad video mode\n"); +} + + + /* + * Display the Video Mode Information + */ + +static void DisplayVModeInfo(struct VideoMode *vmode) +{ + u_int res, sstart, send, total; + + puts(""); + if (!Opt_xfree86) { + printf("mode \"%dx%d", vmode->xres, vmode->yres); + if (vmode->pixclock) { + printf("-%d\"\n", (int)(vmode->vrate+0.5)); + printf(" # D: %5.3f MHz, H: %5.3f kHz, V: %5.3f Hz\n", + vmode->drate/1E6, vmode->hrate/1E3, vmode->vrate); + } else + puts("\""); + printf(" geometry %d %d %d %d %d\n", vmode->xres, vmode->yres, + vmode->vxres, vmode->vyres, vmode->depth); + printf(" timings %d %d %d %d %d %d %d\n", vmode->pixclock, + vmode->left, vmode->right, vmode->upper, vmode->lower, + vmode->hslen, vmode->vslen); + if (vmode->hsync) + puts(" hsync high"); + if (vmode->vsync) + puts(" vsync high"); + if (vmode->csync) + puts(" csync high"); + if (vmode->gsync) + puts(" gsync true"); + if (vmode->extsync) + puts(" extsync true"); + if (vmode->bcast) + puts(" bcast true"); + if (vmode->laced) + puts(" laced true"); + if (vmode->dblscan) + puts(" double true"); + if (vmode->nonstd) + printf(" nonstd %u\n", vmode->nonstd); + if (vmode->accel_flags) + puts(" accel true"); + if (vmode->grayscale) + puts(" grayscale true"); + printf(" rgba %u/%u,%u/%u,%u/%u,%u/%u\n", + vmode->red.length, vmode->red.offset, vmode->green.length, + vmode->green.offset, vmode->blue.length, vmode->blue.offset, + vmode->transp.length, vmode->transp.offset); + puts("endmode\n"); + } else { + printf("Mode \"%dx%d\"\n", vmode->xres, vmode->yres); + if (vmode->pixclock) { + printf(" # D: %5.3f MHz, H: %5.3f kHz, V: %5.3f Hz\n", + vmode->drate/1E6, vmode->hrate/1E3, vmode->vrate); + printf(" DotClock %5.3f\n", vmode->drate/1E6+0.001); + } else + puts(" DotClock Unknown"); + res = vmode->xres; + sstart = res+vmode->right; + send = sstart+vmode->hslen; + total = send+vmode->left; + printf(" HTimings %d %d %d %d\n", res, sstart, send, total); + res = vmode->yres; + sstart = res+vmode->lower; + send = sstart+vmode->vslen; + total = send+vmode->upper; + printf(" VTimings %d %d %d %d\n", res, sstart, send, total); + printf(" Flags "); + if (vmode->laced) + printf(" \"Interlace\""); + if (vmode->dblscan) + printf(" \"DoubleScan\""); + if (vmode->hsync) + printf(" \"+HSync\""); + else + printf(" \"-HSync\""); + if (vmode->vsync) + printf(" \"+VSync\""); + else + printf(" \"-VSync\""); + if (vmode->csync) + printf(" \"Composite\""); + if (vmode->extsync) + puts(" # Warning: XFree86 doesn't support extsync\n"); + if (vmode->bcast) + printf(" \"bcast\""); + if (vmode->accel_flags) + puts(" # Warning: XFree86 doesn't support accel\n"); + if (vmode->grayscale) + puts(" # Warning: XFree86 doesn't support grayscale\n"); + puts("\nEndMode\n"); + } +} + + + /* + * Display the Frame Buffer Device Information + */ + +static void DisplayFBInfo(struct fb_fix_screeninfo *fix) +{ + int i; + + puts("Frame buffer device information:"); + printf(" Name : %s\n", fix->id); + printf(" Address : %p\n", fix->smem_start); + printf(" Size : %d\n", fix->smem_len); + printf(" Type : "); + switch (fix->type) { + case FB_TYPE_PACKED_PIXELS: + puts("PACKED PIXELS"); + break; + case FB_TYPE_PLANES: + puts("PLANES"); + break; + case FB_TYPE_INTERLEAVED_PLANES: + printf("INTERLEAVED PLANES (%d bytes interleave)\n", + fix->type_aux); + break; + case FB_TYPE_TEXT: + for (i = 0; i < sizeof(Textmodes)/sizeof(*Textmodes); i++) + if (fix->type_aux == Textmodes[i].id) + break; + if (i < sizeof(Textmodes)/sizeof(*Textmodes)) + puts(Textmodes[i].name); + else + printf("Unknown text (%d)\n", fix->type_aux); + break; + case FB_TYPE_VGA_PLANES: + { + struct textentry *t; + + for (t = VGAModes; t->name; t++) + if (fix->type_aux == t->id) + break; + if (t->name) + puts(t->name); + else + printf("Unknown VGA mode (%d)\n", fix->type_aux); + } + break; + default: + printf("%d (UNKNOWN)\n", fix->type); + printf(" Type_aux : %d\n", fix->type_aux); + break; + } + printf(" Visual : "); + switch (fix->visual) { + case FB_VISUAL_MONO01: + puts("MONO01"); + break; + case FB_VISUAL_MONO10: + puts("MONO10"); + break; + case FB_VISUAL_TRUECOLOR: + puts("TRUECOLOR"); + break; + case FB_VISUAL_PSEUDOCOLOR: + puts("PSEUDOCOLOR"); + break; + case FB_VISUAL_DIRECTCOLOR: + puts("DIRECTCOLOR"); + break; + case FB_VISUAL_STATIC_PSEUDOCOLOR: + puts("STATIC PSEUDOCOLOR"); + break; + default: + printf("%d (UNKNOWN)\n", fix->visual); + break; + } + printf(" XPanStep : %d\n", fix->xpanstep); + printf(" YPanStep : %d\n", fix->ypanstep); + printf(" YWrapStep : %d\n", fix->ywrapstep); + printf(" LineLength : %d\n", fix->line_length); + if (fix->mmio_len) { + printf(" MMIO Address: %p\n", fix->mmio_start); + printf(" MMIO Size : %d\n", fix->mmio_len); + } + printf(" Accelerator : "); + for (i = 0; i < sizeof(Accelerators)/sizeof(*Accelerators); i++) + if (fix->accel == Accelerators[i].id) + break; + if (i < sizeof(Accelerators)/sizeof(*Accelerators)) + puts(Accelerators[i].name); + else + printf("Unknown (%d)\n", fix->accel); +} + + + /* + * Calculate the Scan Rates for a Video Mode + */ + +static int FillScanRates(struct VideoMode *vmode) +{ + u_int htotal = vmode->left+vmode->xres+vmode->right+vmode->hslen; + u_int vtotal = vmode->upper+vmode->yres+vmode->lower+vmode->vslen; + + if (vmode->dblscan) + vtotal <<= 2; + else if (!vmode->laced) + vtotal <<= 1; + + if (!htotal || !vtotal) + return 0; + + if (vmode->pixclock) { + vmode->drate = 1E12/vmode->pixclock; + vmode->hrate = vmode->drate/htotal; + vmode->vrate = vmode->hrate/vtotal*2; + } else { + vmode->drate = 0; + vmode->hrate = 0; + vmode->vrate = 0; + } + + return 1; +} + + + /* + * Print the Usage Template and Exit + */ + +static void Usage(void) +{ + puts(VERSION); + Die("\nUsage: %s [options] [mode]\n\n" + "Valid options:\n" + " General options:\n" + " -h, --help : display this usage information\n" + " --test : don't change, just test whether the mode is " + "valid\n" + " -s, --show : display video mode settings\n" + " -i, --info : display all frame buffer information\n" + " -v, --verbose : verbose mode\n" + " -V, --version : print version information\n" + " -x, --xfree86 : XFree86 compatibility mode\n" + " -a, --all : change all virtual consoles on this device\n" + " Frame buffer special device nodes:\n" + " -fb <device> : processed frame buffer device\n" + " (default is " DEFAULT_FRAMEBUFFER ")\n" + " Video mode database:\n" + " -db <file> : video mode database file\n" + " (default is " DEFAULT_MODEDBFILE ")\n" + " Display geometry:\n" + " -xres <value> : horizontal resolution (in pixels)\n" + " -yres <value> : vertical resolution (in pixels)\n" + " -vxres <value> : virtual horizontal resolution (in pixels)\n" + " -vyres <value> : virtual vertical resolution (in pixels)\n" + " -depth <value> : display depth (in bits per pixel)\n" + " -nonstd <value> : select nonstandard video mode\n" + " -g, --geometry ... : set all geometry parameters at once\n" + " -match : set virtual vertical resolution by virtual resolution\n" + " Display timings:\n" + " -pixclock <value> : pixel clock (in picoseconds)\n" + " -left <value> : left margin (in pixels)\n" + " -right <value> : right margin (in pixels)\n" + " -upper <value> : upper margin (in pixel lines)\n" + " -lower <value> : lower margin (in pixel lines)\n" + " -hslen <value> : horizontal sync length (in pixels)\n" + " -vslen <value> : vertical sync length (in pixel lines)\n" + " -t, --timings ... : set all timing parameters at once\n" + " Display flags:\n" + " -accel <value> : hardware text acceleration enable (false or " + "true)\n" + " -hsync <value> : horizontal sync polarity (low or high)\n" + " -vsync <value> : vertical sync polarity (low or high)\n" + " -csync <value> : composite sync polarity (low or high)\n" + " -gsync <value> : synch on green (false or true)\n" + " -extsync <value> : external sync enable (false or true)\n" + " -bcast <value> : broadcast enable (false or true)\n" + " -laced <value> : interlace enable (false or true)\n" + " -double <value> : doublescan enable (false or true)\n" + " -rgba <r,g,b,a> : recommended length of color entries\n" + " -grayscale <value> : grayscale enable (false or true)\n" + " Display positioning:\n" + " -move <direction> : move the visible part (left, right, up or " + "down)\n" + " -step <value> : step increment (in pixels or pixel lines)\n" + " (default is 8 horizontal, 2 vertical)\n", + ProgramName); +} + + + /* + * Main Routine + */ + +int main(int argc, char *argv[]) +{ + struct VideoMode *vmode; + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + int fh = -1, i; + + ProgramName = argv[0]; + + /* + * Parse the Options + */ + + while (--argc > 0) { + argv++; + if (!strcmp(argv[0], "-h") || !strcmp(argv[0], "--help")) + Usage(); + else if (!strcmp(argv[0], "-v") || !strcmp(argv[0], "--verbose")) + Opt_verbose = 1; + else if (!strcmp(argv[0], "-V") || !strcmp(argv[0], "--version")) + Opt_version = 1; + else if (!strcmp(argv[0], "--test")) + Opt_test = 1; + else if (!strcmp(argv[0], "-s") || !strcmp(argv[0], "--show")) + Opt_show = 1; + else if (!strcmp(argv[0], "-i") || !strcmp(argv[0], "--info")) { + Opt_show = 1; + Opt_info = 1; + } else if (!strcmp(argv[0], "-x") || !strcmp(argv[0], "--xfree86")) + Opt_xfree86 = 1; + else if (!strcmp(argv[0], "-a") || !strcmp(argv[0], "--all")) + Opt_all = 1; + else if (!strcmp(argv[0], "-g") || !strcmp(argv[0], "--geometry")) { + if (argc > 5) { + Opt_xres = argv[1]; + Opt_yres = argv[2]; + Opt_vxres = argv[3]; + Opt_vyres = argv[4]; + Opt_depth = argv[5]; + Opt_change = 1; + argc -= 5; + argv += 5; + } else + Usage(); + } else if (!strcmp(argv[0], "-t") || !strcmp(argv[0], "--timings")) { + if (argc > 7) { + Opt_pixclock = argv[1]; + Opt_left = argv[2]; + Opt_right = argv[3]; + Opt_upper = argv[4]; + Opt_lower = argv[5]; + Opt_hslen = argv[6]; + Opt_vslen = argv[7]; + Opt_change = 1; + argc -= 7; + argv += 7; + } else + Usage(); + } else if (!strcmp(argv[0], "-match")) { + Opt_matchyres = argv[0]; + Opt_change = 1; + } else { + for (i = 0; Options[i].name; i++) + if (!strcmp(argv[0], Options[i].name)) + break; + if (Options[i].name) { + if (argc-- > 1) { + *Options[i].value = argv[1]; + Opt_change |= Options[i].change; + argv++; + } else + Usage(); + } else if (!Opt_modename) { + Opt_modename = argv[0]; + Opt_change = 1; + } else + Usage(); + } + } + + if (Opt_version || Opt_verbose) + puts(VERSION); + + if (!Opt_fb) + Opt_fb = DEFAULT_FRAMEBUFFER; + + /* + * Open the Frame Buffer Device + */ + + fh = OpenFrameBuffer(Opt_fb); + + /* + * Get the Video Mode + */ + + if (Opt_modename) { + + /* + * Read the Video Mode Database + */ + + ReadModeDB(); + + if (!(vmode = FindVideoMode(Opt_modename))) + Die("Unknown video mode `%s'\n", Opt_modename); + + Current = *vmode; + if (Opt_verbose) + printf("Using video mode `%s'\n", Opt_modename); + } else { + GetVarScreenInfo(fh, &var); + ConvertToVideoMode(&var, &Current); + if (Opt_verbose) + printf("Using current video mode from `%s'\n", Opt_fb); + } + + if (Opt_change) { + + /* + * Optionally Modify the Video Mode + */ + + ModifyVideoMode(&Current); + + /* + * Set the Video Mode + */ + + ConvertFromVideoMode(&Current, &var); + if (Opt_verbose) + printf("Setting video mode to `%s'\n", Opt_fb); + SetVarScreenInfo(fh, &var); + ConvertToVideoMode(&var, &Current); + } + + /* + * Display some Video Mode Information + */ + + if (Opt_show || !Opt_change) + DisplayVModeInfo(&Current); + + if (Opt_info) { + if (Opt_verbose) + puts("Getting further frame buffer information"); + GetFixScreenInfo(fh, &fix); + DisplayFBInfo(&fix); + } + + /* + * Close the Frame Buffer Device + */ + + CloseFrameBuffer(fh); + + exit(0); +} diff --git a/TVout/fbset/fbset.h b/TVout/fbset/fbset.h new file mode 100644 index 0000000000..9b1d2acfa0 --- /dev/null +++ b/TVout/fbset/fbset.h @@ -0,0 +1,82 @@ +/* + * Linux Frame Buffer Device Configuration + * + * © Copyright 1995-1998 by Geert Uytterhoeven + * (Geert.Uytterhoeven@cs.kuleuven.ac.be) + * + * -------------------------------------------------------------------------- + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of the Linux + * distribution for more details. + */ + + +#include <stdio.h> +#include <sys/types.h> + +#ifdef __GLIBC__ +#include <asm/types.h> +#endif + +#define VERSION "Linux Frame Buffer Device Configuration " \ + "Version 2.1 (23/06/1999)\n" \ + "(C) Copyright 1995-1999 by Geert Uytterhoeven\n" + +#define LOW (0) +#define HIGH (1) + +#define FALSE (0) +#define TRUE (1) + +struct color { + unsigned int length; + unsigned int offset; +}; + +struct VideoMode { + struct VideoMode *next; + const char *name; + /* geometry */ + __u32 xres; + __u32 yres; + __u32 vxres; + __u32 vyres; + __u32 depth; + __u32 nonstd; + /* acceleration */ + __u32 accel_flags; + /* timings */ + __u32 pixclock; + __u32 left; + __u32 right; + __u32 upper; + __u32 lower; + __u32 hslen; + __u32 vslen; + /* flags */ + unsigned hsync : 1; + unsigned vsync : 1; + unsigned csync : 1; + unsigned gsync : 1; + unsigned extsync : 1; + unsigned bcast : 1; + unsigned laced : 1; + unsigned dblscan : 1; + unsigned grayscale : 1; + /* scanrates */ + double drate; + double hrate; + double vrate; + /* RGB entries */ + struct color red, green, blue, transp; +}; + +extern FILE *yyin; +extern int line; +extern const char *Opt_modedb; + +extern int yyparse(void); +extern void Die(const char *fmt, ...) __attribute__ ((noreturn)); +extern void AddVideoMode(const struct VideoMode *vmode); +extern void makeRGBA(struct VideoMode *vmode, const char* opt); diff --git a/TVout/fbset/modeline2fb b/TVout/fbset/modeline2fb new file mode 100755 index 0000000000..3a227f558c --- /dev/null +++ b/TVout/fbset/modeline2fb @@ -0,0 +1,150 @@ +#!/usr/bin/perl + +# Simple modeline-to-fb.modes translator +# (c) 1998 by Patrick Reynolds +# distributed under the GNU General Public License + +# mapping of modeline options to fb.modes options +%options_map = ( + "-hsync" => "hsync low", + "-vsync" => "vsync low", + "+hsync" => "hsync high", + "+vsync" => "vsync high", + "interlace" => "laced true", + "doublescan" => "double true" +); + +@possible_vxres = ( 640, 800, 1024, 1152, 1280, 1600, 1920, 2048 ); + +# default settings (override with -d and -r) +$depth = 8; +$rounding = 128; + +# parse options +while ($ARGV[0] =~ /^-/) { + $arg = shift; + if ($arg eq "-d" || $arg eq "--depth") { + if (!($arg = shift @ARGV)) { + usage("-d requires an argument"); + } + $depth = $arg; + } + elsif ($arg eq "-r" || $arg eq "--rounding") { + if (!($arg = shift @ARGV)) { + usage("-r requires an argument"); + } + $rounding = $arg; + } + elsif ($arg eq "-x" || $arg eq "--vxres") { + if (!($arg = shift @ARGV)) { + usage("-x requires an argument"); + } + push @possible_vxres, (split/,/,$arg); + @possible_vxres = sort { $a <=> $b } @possible_vxres; + print "new vxres: " . (join ",", @possible_vxres) . "\n"; + } + elsif ($arg eq "-h" || $arg eq "--help") { + usage(); + } + else { + usage("unknown option: $arg"); + } +} + +# find out how much video memory is available +open(FBSET, "fbset -i|") || die "could not detect available video memory"; +while (<FBSET>) { + if (/Size\s*:\s*(\d+)/) { + $size = $1; + last; + } +} +if (!$size) { die "could not detect available video memory"; } + +# huge kludge (hey, that rhymes!) ... +# subtract 16384 from the available memory $size +# why? the default 640x480 mode uses all but 16384, and when I set it +# to use more than that, it oopses (!). So... for safety's sake, and +# because you probably don't use those 15-25 lines anyway... +$size -= 16384; + +print "# modes.fb - video mode descriptions for fbset +# +# See fbset(8) and fb.modes(5) for more information + +"; + +$flag = 0; +# read all XF86Config files +while(<>) { + chomp; + next if !(($name, $clock, $xres, $xsyncstart, $xsyncend, $xfres, + $yres, $ysyncstart, $ysyncend, $yfres, $extra) = + /^\s*modeline\s+"([^"]+)"\s+([0-9.]+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s*(.*)$/i); + $flag = 1; + + # timing transformations, as described in the fb HOWTO + $pixtime = int(1000000/$clock); + $left = $xfres - $xsyncend; + $right = $xsyncstart - $xres; + $hsynclen = $xsyncend - $xsyncstart; + $top = $yfres - $ysyncend; + $bottom = $ysyncstart - $yres; + $vsynclen = $ysyncend - $ysyncstart; + + # pick a virtual X and Y resolution + $vxres = get_vxres($xres); + if ($vxres < 0) { + print STDERR "Could not guess a good virtual resolution for mode $name.\n"; + print STDERR "Use the advanced options --rounding and --vxres.\n"; + next; + } + $vyres = int($size/$vxres); + + # print out our entry + print "mode \"$name\"\n"; + print " geometry $xres $yres $vxres $vyres $depth\n"; + print " timings $pixtime $left $right $top $bottom $hsynclen $vsynclen\n"; + + # handle extra options at the end of the modeline + $extra =~ tr/A-Z/a-z/; + @options = split/\s+/,$extra; + foreach (@options) { + if ($options_map{$_}) { + print " $options_map{$_}\n"; + } + else { + print " # unknown option: $_\n"; + } + } + print "endmode\n\n"; +} + +if (!$flag) { + print STDERR "No modelines found.\n"; + print STDERR "Make sure the file you specified was an XF86Config file and\n"; + print STDERR "used the single-line Modeline format.\n\n"; + print STDERR "Use \"$0 --help\" for help.\n"; +} + +sub get_vxres { + foreach (@possible_vxres) { + return $_ if ($_ >= $_[0] && ($_ % $rounding) == 0); + } + return -1; +} + +sub usage { + print STDERR "$_[0]\n" if ($_[0]); + print STDERR "$0 [OPTION] [FILES]\n\n"; + print STDERR " -d,--depth depth use a certain display depth (default is 8)\n"; + print STDERR " -h,--help what you see here\n\n"; + print STDERR "Advanced options:\n"; + print STDERR " -r,--rounding div vxres divisor (default is 128)\n"; + print STDERR " -x,--vxres X,X,X,... extra possible vxres values\n\n"; + print STDERR "[FILES] refers to one or more XF86Config files. Note that\n"; + print STDERR "all modelines must be in single-line format.\n\n"; + print STDERR "Example:\n"; + print STDERR " $0 -d 16 /etc/X11/XF86Config\n"; + exit 0; +} diff --git a/TVout/fbset/modes.l b/TVout/fbset/modes.l new file mode 100644 index 0000000000..426eb5c1be --- /dev/null +++ b/TVout/fbset/modes.l @@ -0,0 +1,136 @@ + +/* + * Linux Frame Buffer Device Configuration + * + * © Copyright 1995-1998 by Geert Uytterhoeven + * (Geert.Uytterhoeven@cs.kuleuven.ac.be) + * + * -------------------------------------------------------------------------- + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of the Linux + * distribution for more details. + */ + + +%{ + +#define YYSTYPE long + +#include <string.h> +#include <stdlib.h> + +#include "fbset.h" +#include "modes.tab.h" + +struct keyword { + const char *name; + int token; + int value; +}; + +static struct keyword keywords[] = { + { "mode", MODE, 0 }, + { "geometry", GEOMETRY, 0 }, + { "timings", TIMINGS, 0 }, + { "hsync", HSYNC, 0 }, + { "vsync", VSYNC, 0 }, + { "csync", CSYNC, 0 }, + { "gsync", GSYNC, 0 }, + { "extsync", EXTSYNC, 0 }, + { "bcast", BCAST, 0 }, + { "laced", LACED, 0 }, + { "double", DOUBLE, 0 }, + { "rgba", RGBA, 0 }, + { "nonstd", NONSTD, 0 }, + { "accel", ACCEL, 0 }, + { "grayscale", GRAYSCALE, 0 }, + { "endmode", ENDMODE, 0 }, + { "low", POLARITY, LOW }, + { "high", POLARITY, HIGH }, + { "false", BOOLEAN, FALSE }, + { "true", BOOLEAN, TRUE }, + { "", -1, 0 } +}; + +int line = 1; + + +void yyerror(const char *s) +{ + Die("%s:%d: %s\n", Opt_modedb, line, s); +} + + +int yywrap(void) +{ + return 1; +} + + +static int FindToken(const char *s) +{ + int i; + + for (i = 0; keywords[i].token > 0; i++) + if (!strcasecmp(s, keywords[i].name)) { + yylval = keywords[i].value; + return keywords[i].token; + } + Die("%s:%d: Unknown keyword `%s'\n", Opt_modedb, line, s); +} + + +static const char *CopyString(const char *s) +{ + int len; + char *s2; + + len = strlen(s)-2; + if (!(s2 = malloc(len+1))) + Die("No memory\n"); + strncpy(s2, s+1, len); + s2[len] = '\0'; + return s2; +} + + +%} + +keyword [a-zA-Z][a-zA-Z0-9]* +number [0-9]* +string \"[^\"\n]*\" +comment \#([^\n]*) +space [ \t]+ +junk . + +%% + +{keyword} { + return FindToken(yytext); + } + +{number} { + yylval = strtoul(yytext, NULL, 0); + return NUMBER; + } + +{string} { + yylval = (unsigned long)CopyString(yytext); + return STRING; + } + +{comment}$ break; + +{space} break; + +\n { + line++; + break; + } + +{junk} { + Die("%s:%d: Invalid token `%s'\n", Opt_modedb, line, yytext); + } + +%% diff --git a/TVout/fbset/modes.y b/TVout/fbset/modes.y new file mode 100644 index 0000000000..27b497a00b --- /dev/null +++ b/TVout/fbset/modes.y @@ -0,0 +1,175 @@ +/* + * Linux Frame Buffer Device Configuration + * + * © Copyright 1995-1998 by Geert Uytterhoeven + * (Geert.Uytterhoeven@cs.kuleuven.ac.be) + * + * -------------------------------------------------------------------------- + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of the Linux + * distribution for more details. + */ + + +%{ + +#define YYSTYPE long + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "fb.h" +#include "fbset.h" + +extern int yylex(void); +extern void yyerror(const char *s); +extern int line; + + +static struct VideoMode VideoMode; + +static void ClearVideoMode(void) +{ + memset(&VideoMode, 0, sizeof(VideoMode)); + VideoMode.accel_flags = FB_ACCELF_TEXT; +} + +%} + +%start file + +%token MODE GEOMETRY TIMINGS HSYNC VSYNC CSYNC GSYNC EXTSYNC BCAST LACED DOUBLE + RGBA NONSTD ACCEL GRAYSCALE + ENDMODE POLARITY BOOLEAN STRING NUMBER + +%% + +file : vmodes + ; + + +vmodes : /* empty */ + | vmodes vmode + ; + +vmode : MODE STRING geometry timings options ENDMODE + { + VideoMode.name = (const char *)$2; + AddVideoMode(&VideoMode); + ClearVideoMode(); + } + ; + +geometry : GEOMETRY NUMBER NUMBER NUMBER NUMBER NUMBER + { + ClearVideoMode(); + VideoMode.xres = $2; + VideoMode.yres = $3; + VideoMode.vxres = $4; + VideoMode.vyres = $5; + VideoMode.depth = $6; + } + ; + +timings : TIMINGS NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER + { + VideoMode.pixclock = $2; + VideoMode.left = $3; + VideoMode.right = $4; + VideoMode.upper = $5; + VideoMode.lower = $6; + VideoMode.hslen = $7; + VideoMode.vslen = $8; + } + ; + +options : /* empty */ + | options hsync + | options vsync + | options csync + | options gsync + | options extsync + | options bcast + | options laced + | options double + | options rgba + | options nonstd + | options accel + | options grayscale + ; + +hsync : HSYNC POLARITY + { + VideoMode.hsync = $2; + } + ; + +vsync : VSYNC POLARITY + { + VideoMode.vsync = $2; + } + ; + +csync : CSYNC POLARITY + { + VideoMode.csync = $2; + } + ; + +gsync : GSYNC POLARITY + { + VideoMode.gsync = $2; + } + ; + +extsync : EXTSYNC BOOLEAN + { + VideoMode.extsync = $2; + } + ; + +bcast : BCAST BOOLEAN + { + VideoMode.bcast = $2; + } + ; + +laced : LACED BOOLEAN + { + VideoMode.laced = $2; + } + ; + +double : DOUBLE BOOLEAN + { + VideoMode.dblscan = $2; + } + ; + +rgba : RGBA STRING + { + makeRGBA(&VideoMode, (const char*)$2); + } + ; + +nonstd : NONSTD NUMBER + { + VideoMode.nonstd = $2; + } + ; + +accel : ACCEL BOOLEAN + { + VideoMode.accel_flags = $2; + } + ; + +grayscale : GRAYSCALE BOOLEAN + { + VideoMode.grayscale = $2; + } + ; + +%% diff --git a/TVout/independ b/TVout/independ new file mode 100755 index 0000000000..f9c78a1335 --- /dev/null +++ b/TVout/independ @@ -0,0 +1,16 @@ + +# SETUP TVout +# Independent picture on TV and Monitor + +# CRTC1 -> TVout +matroxset/matroxset -f /dev/fb0 -m 2 + +# CRTC2 -> Monitor +matroxset/matroxset -f /dev/fb1 -m 1 + +# Enable TV +matroxset/matroxset 1 + +# move tty1-2 to CRTC2 +con2fb/con2fb /dev/fb1 /dev/tty1 +con2fb/con2fb /dev/fb1 /dev/tty2 diff --git a/TVout/matroxset/Makefile b/TVout/matroxset/Makefile new file mode 100644 index 0000000000..364b8a9e05 --- /dev/null +++ b/TVout/matroxset/Makefile @@ -0,0 +1,10 @@ +CFLAGS = -O2 -W -Wall + +all: matroxset + +matrox: matroxset.o + +matroxset.o: matroxset.c + +clean: + -rm *.o matroxset diff --git a/TVout/matroxset/fb.h b/TVout/matroxset/fb.h new file mode 100644 index 0000000000..7e4fbe20a3 --- /dev/null +++ b/TVout/matroxset/fb.h @@ -0,0 +1,502 @@ +#ifndef _LINUX_FB_H +#define _LINUX_FB_H + +#include <linux/tty.h> +#include <asm/types.h> + +/* Definitions of frame buffers */ + +#define FB_MAJOR 29 +#define FB_MAX 32 /* sufficient for now */ + +/* ioctls + 0x46 is 'F' */ +#define FBIOGET_VSCREENINFO 0x4600 +#define FBIOPUT_VSCREENINFO 0x4601 +#define FBIOGET_FSCREENINFO 0x4602 +#define FBIOGETCMAP 0x4604 +#define FBIOPUTCMAP 0x4605 +#define FBIOPAN_DISPLAY 0x4606 +/* 0x4607-0x460B are defined below */ +/* #define FBIOGET_MONITORSPEC 0x460C */ +/* #define FBIOPUT_MONITORSPEC 0x460D */ +/* #define FBIOSWITCH_MONIBIT 0x460E */ +#define FBIOGET_CON2FBMAP 0x460F +#define FBIOPUT_CON2FBMAP 0x4610 +#define FBIOBLANK 0x4611 /* arg: 0 or vesa level + 1 */ +#define FBIOGET_VBLANK _IOR('F', 0x12, struct fb_vblank) + +/* next 2 lines are temporary solution, support in 2.5 will be different */ +#define FBIOGET_VT_VSCREENINFO 0x4680 +#define FBIOPUT_VT_VSCREENINFO 0x4681 + + +#define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ +#define FB_TYPE_PLANES 1 /* Non interleaved planes */ +#define FB_TYPE_INTERLEAVED_PLANES 2 /* Interleaved planes */ +#define FB_TYPE_TEXT 3 /* Text/attributes */ +#define FB_TYPE_VGA_PLANES 4 /* EGA/VGA planes */ + +#define FB_AUX_TEXT_MDA 0 /* Monochrome text */ +#define FB_AUX_TEXT_CGA 1 /* CGA/EGA/VGA Color text */ +#define FB_AUX_TEXT_S3_MMIO 2 /* S3 MMIO fasttext */ +#define FB_AUX_TEXT_MGA_STEP16 3 /* MGA Millenium I: text, attr, 14 reserved bytes */ +#define FB_AUX_TEXT_MGA_STEP8 4 /* other MGAs: text, attr, 6 reserved bytes */ + +#define FB_AUX_VGA_PLANES_VGA4 0 /* 16 color planes (EGA/VGA) */ +#define FB_AUX_VGA_PLANES_CFB4 1 /* CFB4 in planes (VGA) */ +#define FB_AUX_VGA_PLANES_CFB8 2 /* CFB8 in planes (VGA) */ + +#define FB_VISUAL_MONO01 0 /* Monochr. 1=Black 0=White */ +#define FB_VISUAL_MONO10 1 /* Monochr. 1=White 0=Black */ +#define FB_VISUAL_TRUECOLOR 2 /* True color */ +#define FB_VISUAL_PSEUDOCOLOR 3 /* Pseudo color (like atari) */ +#define FB_VISUAL_DIRECTCOLOR 4 /* Direct color */ +#define FB_VISUAL_STATIC_PSEUDOCOLOR 5 /* Pseudo color readonly */ + +#define FB_ACCEL_NONE 0 /* no hardware accelerator */ +#define FB_ACCEL_ATARIBLITT 1 /* Atari Blitter */ +#define FB_ACCEL_AMIGABLITT 2 /* Amiga Blitter */ +#define FB_ACCEL_S3_TRIO64 3 /* Cybervision64 (S3 Trio64) */ +#define FB_ACCEL_NCR_77C32BLT 4 /* RetinaZ3 (NCR 77C32BLT) */ +#define FB_ACCEL_S3_VIRGE 5 /* Cybervision64/3D (S3 ViRGE) */ +#define FB_ACCEL_ATI_MACH64GX 6 /* ATI Mach 64GX family */ +#define FB_ACCEL_DEC_TGA 7 /* DEC 21030 TGA */ +#define FB_ACCEL_ATI_MACH64CT 8 /* ATI Mach 64CT family */ +#define FB_ACCEL_ATI_MACH64VT 9 /* ATI Mach 64CT family VT class */ +#define FB_ACCEL_ATI_MACH64GT 10 /* ATI Mach 64CT family GT class */ +#define FB_ACCEL_SUN_CREATOR 11 /* Sun Creator/Creator3D */ +#define FB_ACCEL_SUN_CGSIX 12 /* Sun cg6 */ +#define FB_ACCEL_SUN_LEO 13 /* Sun leo/zx */ +#define FB_ACCEL_IMS_TWINTURBO 14 /* IMS Twin Turbo */ +#define FB_ACCEL_3DLABS_PERMEDIA2 15 /* 3Dlabs Permedia 2 */ +#define FB_ACCEL_MATROX_MGA2064W 16 /* Matrox MGA2064W (Millenium) */ +#define FB_ACCEL_MATROX_MGA1064SG 17 /* Matrox MGA1064SG (Mystique) */ +#define FB_ACCEL_MATROX_MGA2164W 18 /* Matrox MGA2164W (Millenium II) */ +#define FB_ACCEL_MATROX_MGA2164W_AGP 19 /* Matrox MGA2164W (Millenium II) */ +#define FB_ACCEL_MATROX_MGAG100 20 /* Matrox G100 (Productiva G100) */ +#define FB_ACCEL_MATROX_MGAG200 21 /* Matrox G200 (Myst, Mill, ...) */ +#define FB_ACCEL_SUN_CG14 22 /* Sun cgfourteen */ +#define FB_ACCEL_SUN_BWTWO 23 /* Sun bwtwo */ +#define FB_ACCEL_SUN_CGTHREE 24 /* Sun cgthree */ +#define FB_ACCEL_SUN_TCX 25 /* Sun tcx */ +#define FB_ACCEL_MATROX_MGAG400 26 /* Matrox G400 */ +#define FB_ACCEL_NV3 27 /* nVidia RIVA 128 */ +#define FB_ACCEL_NV4 28 /* nVidia RIVA TNT */ +#define FB_ACCEL_NV5 29 /* nVidia RIVA TNT2 */ +#define FB_ACCEL_CT_6555x 30 /* C&T 6555x */ +#define FB_ACCEL_3DFX_BANSHEE 31 /* 3Dfx Banshee */ +#define FB_ACCEL_ATI_RAGE128 32 /* ATI Rage128 family */ + +struct fb_fix_screeninfo { + char id[16]; /* identification string eg "TT Builtin" */ + unsigned long smem_start; /* Start of frame buffer mem */ + /* (physical address) */ + __u32 smem_len; /* Length of frame buffer mem */ + __u32 type; /* see FB_TYPE_* */ + __u32 type_aux; /* Interleave for interleaved Planes */ + __u32 visual; /* see FB_VISUAL_* */ + __u16 xpanstep; /* zero if no hardware panning */ + __u16 ypanstep; /* zero if no hardware panning */ + __u16 ywrapstep; /* zero if no hardware ywrap */ + __u32 line_length; /* length of a line in bytes */ + unsigned long mmio_start; /* Start of Memory Mapped I/O */ + /* (physical address) */ + __u32 mmio_len; /* Length of Memory Mapped I/O */ + __u32 accel; /* Type of acceleration available */ + __u16 reserved[3]; /* Reserved for future compatibility */ +}; + +/* Interpretation of offset for color fields: All offsets are from the right, + * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you + * can use the offset as right argument to <<). A pixel afterwards is a bit + * stream and is written to video memory as that unmodified. This implies + * big-endian byte order if bits_per_pixel is greater than 8. + */ +struct fb_bitfield { + __u32 offset; /* beginning of bitfield */ + __u32 length; /* length of bitfield */ + __u32 msb_right; /* != 0 : Most significant bit is */ + /* right */ +}; + +#define FB_NONSTD_HAM 1 /* Hold-And-Modify (HAM) */ + +#define FB_ACTIVATE_NOW 0 /* set values immediately (or vbl)*/ +#define FB_ACTIVATE_NXTOPEN 1 /* activate on next open */ +#define FB_ACTIVATE_TEST 2 /* don't set, round up impossible */ +#define FB_ACTIVATE_MASK 15 + /* values */ +#define FB_ACTIVATE_VBL 16 /* activate values on next vbl */ +#define FB_CHANGE_CMAP_VBL 32 /* change colormap on vbl */ +#define FB_ACTIVATE_ALL 64 /* change all VCs on this fb */ + +#define FB_ACCELF_TEXT 1 /* text mode acceleration */ + +#define FB_SYNC_HOR_HIGH_ACT 1 /* horizontal sync high active */ +#define FB_SYNC_VERT_HIGH_ACT 2 /* vertical sync high active */ +#define FB_SYNC_EXT 4 /* external sync */ +#define FB_SYNC_COMP_HIGH_ACT 8 /* composite sync high active */ +#define FB_SYNC_BROADCAST 16 /* broadcast video timings */ + /* vtotal = 144d/288n/576i => PAL */ + /* vtotal = 121d/242n/484i => NTSC */ +#define FB_SYNC_ON_GREEN 32 /* sync on green */ + +#define FB_VMODE_NONINTERLACED 0 /* non interlaced */ +#define FB_VMODE_INTERLACED 1 /* interlaced */ +#define FB_VMODE_DOUBLE 2 /* double scan */ +#define FB_VMODE_MASK 255 + +#define FB_VMODE_YWRAP 256 /* ywrap instead of panning */ +#define FB_VMODE_SMOOTH_XPAN 512 /* smooth xpan possible (internally used) */ +#define FB_VMODE_CONUPDATE 512 /* don't update x/yoffset */ + +struct fb_var_screeninfo { + __u32 xres; /* visible resolution */ + __u32 yres; + __u32 xres_virtual; /* virtual resolution */ + __u32 yres_virtual; + __u32 xoffset; /* offset from virtual to visible */ + __u32 yoffset; /* resolution */ + + __u32 bits_per_pixel; /* guess what */ + __u32 grayscale; /* != 0 Graylevels instead of colors */ + + struct fb_bitfield red; /* bitfield in fb mem if true color, */ + struct fb_bitfield green; /* else only length is significant */ + struct fb_bitfield blue; + struct fb_bitfield transp; /* transparency */ + + __u32 nonstd; /* != 0 Non standard pixel format */ + + __u32 activate; /* see FB_ACTIVATE_* */ + + __u32 height; /* height of picture in mm */ + __u32 width; /* width of picture in mm */ + + __u32 accel_flags; /* acceleration flags (hints) */ + + /* Timing: All values in pixclocks, except pixclock (of course) */ + __u32 pixclock; /* pixel clock in ps (pico seconds) */ + __u32 left_margin; /* time from sync to picture */ + __u32 right_margin; /* time from picture to sync */ + __u32 upper_margin; /* time from sync to picture */ + __u32 lower_margin; + __u32 hsync_len; /* length of horizontal sync */ + __u32 vsync_len; /* length of vertical sync */ + __u32 sync; /* see FB_SYNC_* */ + __u32 vmode; /* see FB_VMODE_* */ + __u32 reserved[6]; /* Reserved for future compatibility */ +}; + +struct fb_cmap { + __u32 start; /* First entry */ + __u32 len; /* Number of entries */ + __u16 *red; /* Red values */ + __u16 *green; + __u16 *blue; + __u16 *transp; /* transparency, can be NULL */ +}; + +struct fb_con2fbmap { + __u32 console; + __u32 framebuffer; +}; + +/* VESA Blanking Levels */ +#define VESA_NO_BLANKING 0 +#define VESA_VSYNC_SUSPEND 1 +#define VESA_HSYNC_SUSPEND 2 +#define VESA_POWERDOWN 3 + +struct fb_monspecs { + __u32 hfmin; /* hfreq lower limit (Hz) */ + __u32 hfmax; /* hfreq upper limit (Hz) */ + __u16 vfmin; /* vfreq lower limit (Hz) */ + __u16 vfmax; /* vfreq upper limit (Hz) */ + unsigned dpms : 1; /* supports DPMS */ +}; + +/* next structure is only 2.2 temporary hack, 2.3 solution will be different */ +struct fb_vt_info { + __u32 console; + struct fb_var_screeninfo *info; +}; + +#define FB_VBLANK_VBLANKING 1 /* currently in a vertical blank */ +#define FB_VBLANK_HBLANKING 2 /* currently in a horizontal blank */ +#define FB_VBLANK_HAVE_VBLANK 4 /* vertical blanks can be detected */ +#define FB_VBLANK_HAVE_HBLANK 8 /* horizontal blanks can be detected */ +#define FB_VBLANK_HAVE_COUNT 16 /* global retrace counter is available */ +#define FB_VBLANK_HAVE_VCOUNT 32 /* the vcount field is valid */ +#define FB_VBLANK_HAVE_HCOUNT 64 /* the hcount field is valid */ + +struct fb_vblank { + __u32 flags; /* FB_VBLANK flags */ + __u32 count; /* counter of retraces since boot */ + __s32 vcount; /* current scanline position */ + __s32 hcount; /* current scandot position */ + __u32 reserved[4]; /* reserved for future compatibility */ +}; + +#ifdef __KERNEL__ + +#if 1 /* to go away in 2.4.0 */ +extern int GET_FB_IDX(kdev_t rdev); +#else +#define GET_FB_IDX(node) (MINOR(node)) +#endif + +#include <linux/fs.h> +#include <linux/init.h> + + +struct fb_info; +struct fb_info_gen; +struct vm_area_struct; +struct file; + + /* + * Frame buffer operations + */ + +struct fb_ops { + /* open/release and usage marking */ + int (*fb_open)(struct fb_info *info, int user); + int (*fb_release)(struct fb_info *info, int user); + /* get non settable parameters */ + int (*fb_get_fix)(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); + /* get settable parameters */ + int (*fb_get_var)(struct fb_var_screeninfo *var, int con, + struct fb_info *info); + /* set settable parameters */ + int (*fb_set_var)(struct fb_var_screeninfo *var, int con, + struct fb_info *info); + /* get colormap */ + int (*fb_get_cmap)(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); + /* set colormap */ + int (*fb_set_cmap)(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); + /* pan display */ + int (*fb_pan_display)(struct fb_var_screeninfo *var, int con, + struct fb_info *info); + /* perform fb specific ioctl */ + int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, int con, struct fb_info *info); + /* perform fb specific mmap */ + int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma); + /* switch to/from raster image mode */ + int (*fb_rasterimg)(struct fb_info *info, int start); +}; + +struct fb_info { + char modename[40]; /* default video mode */ + kdev_t node; + int flags; + int open; /* Has this been open already ? */ +#define FBINFO_FLAG_MODULE 1 /* Low-level driver is a module */ + struct fb_fix_screeninfo fix; /* Current fix */ + struct fb_monspecs monspecs; /* Current Monitor specs */ + struct fb_ops *fbops; + char *screen_base; /* Virtual address */ + struct display *disp; /* initial display variable */ + struct display *currcon; + struct vc_data *display_fg; /* Console visible on this display */ + char fontname[40]; /* default font name */ + int (*changevar)(int); /* tell console var has changed */ + int (*switch_con)(int, struct fb_info*); + /* tell fb to switch consoles */ + int (*updatevar)(int, struct fb_info*); + /* tell fb to update the vars */ + void (*blank)(int, struct fb_info*); /* tell fb to (un)blank the screen */ + /* arg = 0: unblank */ + /* arg > 0: VESA level (arg-1) */ + void *pseudo_palette; /* Fake palette of 16 colors and + the cursor's color for non + palette mode */ + /* From here on everything is device dependent */ + void *par; +}; + +#ifdef MODULE +#define FBINFO_FLAG_DEFAULT FBINFO_FLAG_MODULE +#else +#define FBINFO_FLAG_DEFAULT 0 +#endif + + /* + * This structure abstracts from the underlying hardware. It is not + * mandatory but used by the `generic' frame buffer operations. + * Read drivers/video/skeletonfb.c for more information. + */ + +struct fbgen_hwswitch { + void (*detect)(void); + int (*encode_fix)(struct fb_fix_screeninfo *fix, const void *par, + struct fb_info_gen *info); + int (*decode_var)(const struct fb_var_screeninfo *var, void *par, + struct fb_info_gen *info); + int (*encode_var)(struct fb_var_screeninfo *var, const void *par, + struct fb_info_gen *info); + void (*get_par)(void *par, struct fb_info_gen *info); + void (*set_par)(const void *par, struct fb_info_gen *info); + int (*getcolreg)(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, struct fb_info *info); + int (*setcolreg)(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info); + int (*pan_display)(const struct fb_var_screeninfo *var, + struct fb_info_gen *info); + int (*blank)(int blank_mode, struct fb_info_gen *info); + void (*set_disp)(const void *par, struct display *disp, + struct fb_info_gen *info); +}; + +struct fb_info_gen { + struct fb_info info; + + /* Entries for a generic frame buffer device */ + /* Yes, this starts looking like C++ */ + u_int parsize; + struct fbgen_hwswitch *fbhw; + + /* From here on everything is device dependent */ +}; + + /* + * `Generic' versions of the frame buffer device operations + */ + +extern int fbgen_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +extern int fbgen_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +extern int fbgen_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +extern int fbgen_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +extern int fbgen_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +extern int fbgen_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +extern int fbgen_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con, + struct fb_info *info); + + /* + * Helper functions + */ + +extern int fbgen_do_set_var(struct fb_var_screeninfo *var, int isactive, + struct fb_info_gen *info); +extern void fbgen_set_disp(int con, struct fb_info_gen *info); +extern void fbgen_install_cmap(int con, struct fb_info_gen *info); +extern int fbgen_update_var(int con, struct fb_info *info); +extern int fbgen_switch(int con, struct fb_info *info); +extern void fbgen_blank(int blank, struct fb_info *info); + + +/* drivers/video/fbmem.c */ +extern int register_framebuffer(struct fb_info *fb_info); +extern int unregister_framebuffer(const struct fb_info *fb_info); + +extern int num_registered_fb; +extern struct fb_info *registered_fb[FB_MAX]; + +/* drivers/video/fbmon.c */ +extern int fbmon_valid_timings(u_int pixclock, u_int htotal, u_int vtotal, + const struct fb_info *fb_info); +extern int fbmon_dpms(const struct fb_info *fb_info); + +/* drivers/video/fbcmap.c */ +extern int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp); +extern void fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to, + int fsfromto); +extern int fb_get_cmap(struct fb_cmap *cmap, int kspc, + int (*getcolreg)(u_int, u_int *, u_int *, u_int *, + u_int *, struct fb_info *), + struct fb_info *fb_info); +extern int fb_set_cmap(struct fb_cmap *cmap, int kspc, + int (*setcolreg)(u_int, u_int, u_int, u_int, u_int, + struct fb_info *), + struct fb_info *fb_info); +extern struct fb_cmap *fb_default_cmap(int len); +extern void fb_invert_cmaps(void); + +struct fb_videomode { + const char *name; /* optional */ + u32 refresh; /* optional */ + u32 xres; + u32 yres; + u32 pixclock; + u32 left_margin; + u32 right_margin; + u32 upper_margin; + u32 lower_margin; + u32 hsync_len; + u32 vsync_len; + u32 sync; + u32 vmode; +}; + +extern int __init fb_find_mode(struct fb_var_screeninfo *var, + struct fb_info *info, const char *mode_option, + const struct fb_videomode *db, + unsigned int dbsize, + const struct fb_videomode *default_mode, + unsigned int default_bpp); + +#endif /* __KERNEL__ */ + +#if 1 + +#define FBCMD_GET_CURRENTPAR 0xDEAD0005 +#define FBCMD_SET_CURRENTPAR 0xDEAD8005 + +#endif + + +#if 1 /* Preliminary */ + + /* + * Hardware Cursor + */ + +#define FBIOGET_FCURSORINFO 0x4607 +#define FBIOGET_VCURSORINFO 0x4608 +#define FBIOPUT_VCURSORINFO 0x4609 +#define FBIOGET_CURSORSTATE 0x460A +#define FBIOPUT_CURSORSTATE 0x460B + + +struct fb_fix_cursorinfo { + __u16 crsr_width; /* width and height of the cursor in */ + __u16 crsr_height; /* pixels (zero if no cursor) */ + __u16 crsr_xsize; /* cursor size in display pixels */ + __u16 crsr_ysize; + __u16 crsr_color1; /* colormap entry for cursor color1 */ + __u16 crsr_color2; /* colormap entry for cursor color2 */ +}; + +struct fb_var_cursorinfo { + __u16 width; + __u16 height; + __u16 xspot; + __u16 yspot; + __u8 data[1]; /* field with [height][width] */ +}; + +struct fb_cursorstate { + __s16 xoffset; + __s16 yoffset; + __u16 mode; +}; + +#define FB_CURSOR_OFF 0 +#define FB_CURSOR_ON 1 +#define FB_CURSOR_FLASH 2 + +#endif /* Preliminary */ + +#endif /* _LINUX_FB_H */ diff --git a/TVout/matroxset/matroxfb.h b/TVout/matroxset/matroxfb.h new file mode 100644 index 0000000000..182d76b25a --- /dev/null +++ b/TVout/matroxset/matroxfb.h @@ -0,0 +1,32 @@ +#ifndef __LINUX_MATROXFB_H__ +#define __LINUX_MATROXFB_H__ + +#include <asm/ioctl.h> +#include <asm/types.h> + +struct matroxioc_output_mode { + __u32 output; /* which output */ +#define MATROXFB_OUTPUT_PRIMARY 0x0000 +#define MATROXFB_OUTPUT_SECONDARY 0x0001 + __u32 mode; /* which mode */ +#define MATROXFB_OUTPUT_MODE_PAL 0x0001 +#define MATROXFB_OUTPUT_MODE_NTSC 0x0002 +#define MATROXFB_OUTPUT_MODE_MONITOR 0x0080 +}; +#define MATROXFB_SET_OUTPUT_MODE _IOW('n',0xFA,sizeof(struct matroxioc_output_mode)) +#define MATROXFB_GET_OUTPUT_MODE _IOWR('n',0xFA,sizeof(struct matroxioc_output_mode)) + +/* bitfield */ +#define MATROXFB_OUTPUT_CONN_PRIMARY (1 << MATROXFB_OUTPUT_PRIMARY) +#define MATROXFB_OUTPUT_CONN_SECONDARY (1 << MATROXFB_OUTPUT_SECONDARY) +/* connect these outputs to this framebuffer */ +#define MATROXFB_SET_OUTPUT_CONNECTION _IOW('n',0xF8,sizeof(__u32)) +/* which outputs are connected to this framebuffer */ +#define MATROXFB_GET_OUTPUT_CONNECTION _IOR('n',0xF8,sizeof(__u32)) +/* which outputs are available for this framebuffer */ +#define MATROXFB_GET_AVAILABLE_OUTPUTS _IOR('n',0xF9,sizeof(__u32)) +/* which outputs exist on this framebuffer */ +#define MATROXFB_GET_ALL_OUTPUTS _IOR('n',0xFB,sizeof(__u32)) + +#endif + diff --git a/TVout/matroxset/matroxset.c b/TVout/matroxset/matroxset.c new file mode 100644 index 0000000000..af989156f9 --- /dev/null +++ b/TVout/matroxset/matroxset.c @@ -0,0 +1,162 @@ +#include <stdio.h> +#include <sys/types.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <fcntl.h> +#include "fb.h" +#include "matroxfb.h" + +static int help(void) { + fprintf(stderr, "usage: matroxset [-f fbdev] [-o output] [-m] [value]\n" + "\n" + "where -f fbdev is fbdev device (default /dev/fb1)\n" + " -o output is output number to investigate (0=primary, 1=secondary=default)\n" + " -m says that CRTC->output mapping should be changed/retrieved\n" + " -p print information about blanking\n" + " value if present, value is set, if missing, value is retrieved\n" + "\n" + "For output mode, 128 means monitor, 1 = PAL TV, 2 = NTSC TV\n"); + return 98; +} + +int main(int argc, char* argv[]) { + char* fb = "/dev/fb1"; + int fd; + struct matroxioc_output_mode mom; + struct fb_vblank vbl; + int rtn; + int output = MATROXFB_OUTPUT_SECONDARY; + int o_present = 0; + int m_present = 0; + int p_present = 0; + int act; + u_int32_t conns; + + while ((rtn = getopt(argc, argv, "o:f:mhp")) != -1) { + switch (rtn) { + case 'o': + output = strtoul(optarg, NULL, 0); + o_present = 1; + break; + case 'm': + m_present = 1; + break; + case 'f': + fb = optarg; + break; + case 'p': + p_present = 1; + break; + case 'h': + return help(); + default: + fprintf(stderr, "Bad commandline\n"); + return 99; + } + } + act = 0; + if (p_present) { + if (m_present || o_present) { + fprintf(stderr, "You cannot use -p together with -m or -o\n"); + return 95; + } + act = 4; + } else if (optind >= argc) { + if (m_present) { + if (o_present) { + fprintf(stderr, "You cannot use -m and -o together\n"); + return 96; + } + act = 2; + } else { + mom.output = output; + mom.mode = 0; + } + } else { + if (m_present) { + conns = strtoul(argv[optind], NULL, 0); + act = 3; + } else { + mom.output = output; + mom.mode = strtoul(argv[optind], NULL, 0); + act = 1; + } + } + fd = open(fb, O_RDWR); + if (fd == -1) { + fprintf(stderr, "Cannot open %s: %s\n", fb, strerror(errno)); + return 122; + } + switch (act) { + case 0: + rtn = ioctl(fd, MATROXFB_GET_OUTPUT_MODE, &mom); + if (rtn) + break; + printf("Output mode is %u\n", mom.mode); + break; + case 1: + rtn = ioctl(fd, MATROXFB_SET_OUTPUT_MODE, &mom); + break; + case 2: + rtn = ioctl(fd, MATROXFB_GET_OUTPUT_CONNECTION, &conns); + if (rtn) + break; + printf("This framebuffer is connected to outputs %08X\n", conns); + break; + case 3: + rtn = ioctl(fd, MATROXFB_SET_OUTPUT_CONNECTION, &conns); + break; + case 4: +#if 0 + { int i; for (i = 0; i < 1000000; i++) { + rtn = ioctl(fd, FBIOGET_VBLANK, &vbl); + if (rtn) + break; + }} +#else + rtn = ioctl(fd, FBIOGET_VBLANK, &vbl); + if (rtn) + break; +#endif + printf("VBlank flags: %08X\n", vbl.flags); + printf(" Symbolic: "); + { + static const struct { u_int32_t mask; const char* msg; } *ptr, vals[] = { + { FB_VBLANK_HAVE_VBLANK, "vblank" }, + { FB_VBLANK_HAVE_HBLANK, "hblank" }, + { FB_VBLANK_HAVE_COUNT, "field no." }, + { FB_VBLANK_HAVE_VCOUNT, "line no." }, + { FB_VBLANK_HAVE_HCOUNT, "column no." }, + { FB_VBLANK_VBLANKING, "vblanking" }, + { FB_VBLANK_HBLANKING, "hblanking" }, + { 0, NULL }}; + int ap = 0; + for (ptr = vals; ptr->msg; ptr++) { + if (vbl.flags & ptr->mask) { + if (ap) printf(", "); + printf(ptr->msg); + ap = 1; + } + } + if (!ap) + printf("none"); + printf("\n"); + } + printf("Field count: %12u\n", vbl.count); + printf("Vertical line: %12u\n", vbl.vcount); + printf("Horizontal column: %12u\n", vbl.hcount); + break; + default: + rtn = -1; errno = EINVAL; + break; + } + if (rtn) { + fprintf(stderr, "ioctl failed: %s\n", strerror(errno)); + } + close(fd); + return 0; +} + diff --git a/TVout/matroxset/normal b/TVout/matroxset/normal new file mode 100755 index 0000000000..f17caf5351 --- /dev/null +++ b/TVout/matroxset/normal @@ -0,0 +1,12 @@ +#! /bin/sh + +if [ -c /dev/fb0 ]; then + HEAD0=/dev/fb0 + HEAD1=/dev/fb1 +else + HEAD0=/dev/fb/0 + HEAD1=/dev/fb/1 +fi +matroxset -f ${HEAD1} -m 0 +matroxset -f ${HEAD0} -m 1 +matroxset -f ${HEAD1} -m 2 diff --git a/TVout/matroxset/swapit b/TVout/matroxset/swapit new file mode 100755 index 0000000000..918f54618c --- /dev/null +++ b/TVout/matroxset/swapit @@ -0,0 +1,5 @@ +#! /bin/sh +~/mga/con2fb /dev/fb0 /dev/tty4 +rmmod matroxfb_maven +modprobe matroxfb_maven +~/mga/con2fb /dev/fb1 /dev/tty4 diff --git a/TVout/matroxset/swapped b/TVout/matroxset/swapped new file mode 100755 index 0000000000..c6dc7cf016 --- /dev/null +++ b/TVout/matroxset/swapped @@ -0,0 +1,12 @@ +#! /bin/sh + +if [ -c /dev/fb0 ]; then + HEAD0=/dev/fb0 + HEAD1=/dev/fb1 +else + HEAD0=/dev/fb/0 + HEAD1=/dev/fb/1 +fi +matroxset -f ${HEAD1} -m 0 +matroxset -f ${HEAD0} -m 2 +matroxset -f ${HEAD1} -m 1 diff --git a/TVout/modules b/TVout/modules new file mode 100755 index 0000000000..2c210e97f3 --- /dev/null +++ b/TVout/modules @@ -0,0 +1,8 @@ + +# Load kernel modules... +# (you must have 2.3/2.4 kernel with matroxfb enabled!) + +modprobe i2c-matroxfb +modprobe matroxfb_Ti3026 +modprobe matroxfb_crtc2 +modprobe matroxfb_maven diff --git a/alaw.c b/alaw.c new file mode 100644 index 0000000000..de8c43962c --- /dev/null +++ b/alaw.c @@ -0,0 +1,29 @@ +// code from xanim sources... +// (I hope that not hurt copyright :o) + +#define xaLONG long +#define xaULONG unsigned long +#define xaBYTE char +#define xaUBYTE unsigned char + +xaULONG long xa_alaw_2_sign[256]; + +void Gen_aLaw_2_Signed() +{ xaULONG i; + for(i=0;i<256;i++) + { xaUBYTE data = (xaUBYTE)(i); + xaLONG d, t, seg; + + data ^= 0x55; + + t = (data & 0xf) << 4; + seg = (data & 0x70) >> 4; + if (seg == 0) t += 8; + else if (seg == 1) t += 0x108; + else { t += 108; t <<= seg - 1; } + + d = (data & 0x80)?(t):(-t); + xa_alaw_2_sign[i] = (xaULONG)((xaULONG)(d) & 0xffff); + } +} + diff --git a/asfheader.c b/asfheader.c new file mode 100644 index 0000000000..c5e9064e7c --- /dev/null +++ b/asfheader.c @@ -0,0 +1,183 @@ +// .asf fileformat docs from http://divx.euro.ru + +typedef struct __attribute__((packed)) { + unsigned char guid[16]; + unsigned long long size; +} ASF_obj_header_t; + +typedef struct __attribute__((packed)) { + ASF_obj_header_t objh; + unsigned int cno; // number of subchunks + unsigned char v1; // unknown (0x01) + unsigned char v2; // unknown (0x02) +} ASF_header_t; + +typedef struct __attribute__((packed)) { + unsigned char client[16]; // Client GUID + unsigned long long file_size; + unsigned long long creat_time; //File creation time FILETIME 8 + unsigned long long packets; //Number of packets UINT64 8 + unsigned long long end_timestamp; //Timestamp of the end position UINT64 8 + unsigned long long duration; //Duration of the playback UINT64 8 + unsigned long start_timestamp; //Timestamp of the start position UINT32 4 + unsigned long unk1; //Unknown, maybe reserved ( usually contains 0 ) UINT32 4 + unsigned long flags; //Unknown, maybe flags ( usually contains 2 ) UINT32 4 + unsigned long packetsize; //Size of packet, in bytes UINT32 4 + unsigned long packetsize2; //Size of packet ( confirm ) UINT32 4 + unsigned long frame_size; //Size of uncompressed video frame UINT32 4 +} ASF_file_header_t; + +typedef struct __attribute__((packed)) { + unsigned char type[16]; // Stream type (audio/video) GUID 16 + unsigned char concealment[16]; // Audio error concealment type GUID 16 + unsigned long long unk1; // Unknown, maybe reserved ( usually contains 0 ) UINT64 8 + unsigned long type_size; //Total size of type-specific data UINT32 4 + unsigned long stream_size; //Size of stream-specific data UINT32 4 + unsigned short stream_no; //Stream number UINT16 2 + unsigned long unk2; //Unknown UINT32 4 +} ASF_stream_header_t; + + +ASF_header_t asfh; +ASF_obj_header_t objh; +ASF_file_header_t fileh; +ASF_stream_header_t streamh; +unsigned char* asf_packet=NULL; +//int asf_video_id=-1; +int asf_scrambling_h=1; +int asf_scrambling_w=1; +int asf_scrambling_b=1; + +int i; + +void asf_descrambling(unsigned char *src,int len){ + unsigned char *dst=malloc(len); + unsigned char *s2=src; + int i=0,x,y; + while(len-i>=asf_scrambling_h*asf_scrambling_w*asf_scrambling_b){ +// printf("descrambling! (w=%d b=%d)\n",w,asf_scrambling_b); + //i+=asf_scrambling_h*asf_scrambling_w; + for(x=0;x<asf_scrambling_w;x++) + for(y=0;y<asf_scrambling_h;y++){ + memcpy(dst+i,s2+(y*asf_scrambling_w+x)*asf_scrambling_b,asf_scrambling_b); + i+=asf_scrambling_b; + } + s2+=asf_scrambling_h*asf_scrambling_w*asf_scrambling_b; + } + //if(i<len) memcpy(dst+i,src+i,len-i); + memcpy(src,dst,i); + free(dst); +} + +char* asf_chunk_type(unsigned char* guid){ + switch(*((unsigned int*)guid)){ + case 0xF8699E40: return "guid_audio_stream"; + case 0xBC19EFC0: return "guid_video_stream"; + case 0x49f1a440: return "guid_audio_conceal_none"; + case 0xbfc3cd50: return "guid_audio_conceal_interleave"; + case 0x75B22630: return "guid_header"; + case 0x75b22636: return "guid_data_chunk"; + case 0x33000890: return "guid_index_chunk"; + case 0xB7DC0791: return "guid_stream_header"; + case 0xD6E229D1: return "guid_header_2_0"; + case 0x8CABDCA1: return "guid_file_header"; + } + return NULL; +} + +int asf_check_header(){ + unsigned char asfhdrguid[16]={0x30,0x26,0xB2,0x75,0x8E,0x66,0xCF,0x11,0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C}; + int i; + stream_read(demuxer->stream,(char*) &asfh,sizeof(asfh)); // header obj +// for(i=0;i<16;i++) printf(" %02X",temp[i]);printf("\n"); +// for(i=0;i<16;i++) printf(" %02X",asfhdrguid[i]);printf("\n"); + if(memcmp(asfhdrguid,asfh.objh.guid,16)){ + if(verbose) printf("ASF_check: not ASF guid!\n"); + return 0; // not ASF guid + } + if(asfh.cno>256){ + if(verbose) printf("ASF_check: invalid subchunks_no %d\n",(int) asfh.cno); + return 0; // invalid header??? + } + return 1; +} + +int read_asf_header(){ + unsigned char buffer[512]; + +#if 1 + printf("ASF file! (subchunks: %d)\n",asfh.cno); +while(!stream_eof(demuxer->stream)){ + int pos,endpos; + pos=stream_tell(demuxer->stream); + stream_read(demuxer->stream,(char*) &objh,sizeof(objh)); + if(stream_eof(demuxer->stream)) break; // EOF + endpos=pos+objh.size; +// for(i=0;i<16;i++) printf("%02X ",objh.guid[i]); + printf("0x%08X [%s] %d\n",pos, asf_chunk_type(objh.guid),(int) objh.size); + switch(*((unsigned int*)&objh.guid)){ + case 0xB7DC0791: // guid_stream_header + stream_read(demuxer->stream,(char*) &streamh,sizeof(streamh)); + printf("stream type: %s\n",asf_chunk_type(streamh.type)); + printf("stream concealment: %s\n",asf_chunk_type(streamh.concealment)); + printf("type: %d bytes, stream: %d bytes ID: %d\n",(int)streamh.type_size,(int)streamh.stream_size,(int)streamh.stream_no); + printf("unk1: %lX unk2: %X\n",streamh.unk1,streamh.unk2); + printf("FILEPOS=0x%X\n",stream_tell(demuxer->stream)); + // type-specific data: + stream_read(demuxer->stream,(char*) buffer,streamh.type_size); + switch(*((unsigned int*)&streamh.type)){ + case 0xF8699E40: // guid_audio_stream + memcpy(avi_header.wf_ext,buffer,streamh.type_size<64?streamh.type_size:64); + if(verbose>=1) print_wave_header((WAVEFORMATEX*)buffer); + if((*((unsigned int*)&streamh.concealment))==0xbfc3cd50){ + stream_read(demuxer->stream,(char*) buffer,streamh.stream_size); + asf_scrambling_h=buffer[0]; + asf_scrambling_w=(buffer[2]<<8)|buffer[1]; + asf_scrambling_b=(buffer[4]<<8)|buffer[3]; + asf_scrambling_w/=asf_scrambling_b; + } else { + asf_scrambling_b=asf_scrambling_h=asf_scrambling_w=1; + } + printf("ASF audio scrambling: %d x %d x %d\n",asf_scrambling_h,asf_scrambling_w,asf_scrambling_b); + if(demuxer->audio->id==-1) demuxer->audio->id=streamh.stream_no & 0x7F; + break; + case 0xBC19EFC0: // guid_video_stream + memcpy(&avi_header.bih,&buffer[4+4+1+2],sizeof(BITMAPINFOHEADER)); + if(verbose>=1) print_video_header((BITMAPINFOHEADER*)&buffer[4+4+1+2]); + //asf_video_id=streamh.stream_no & 0x7F; + if(demuxer->video->id==-1) demuxer->video->id=streamh.stream_no & 0x7F; + break; + } + // stream-specific data: + // stream_read(demuxer->stream,(char*) buffer,streamh.stream_size); + break; +// case 0xD6E229D1: return "guid_header_2_0"; + case 0x8CABDCA1: // guid_file_header + stream_read(demuxer->stream,(char*) &fileh,sizeof(fileh)); + printf("packets: %d flags: %d pack_size: %d frame_size: %d\n",(int)fileh.packets,(int)fileh.flags,(int)fileh.packetsize,(int)fileh.frame_size); + asf_packet=malloc(fileh.packetsize); // !!! + break; + case 0x75b22636: // guid_data_chunk + avi_header.movi_start=stream_tell(demuxer->stream)+26; + avi_header.movi_end=endpos; + if(verbose>=1) printf("Found movie at 0x%X - 0x%X\n",avi_header.movi_start,avi_header.movi_end); + break; + +// case 0x33000890: return "guid_index_chunk"; + + } // switch GUID + if(!stream_seek(demuxer->stream,endpos)) break; +} // while EOF + +#if 0 +if(verbose){ + printf("ASF duration: %d\n",(int)fileh.duration); + printf("ASF start pts: %d\n",(int)fileh.start_timestamp); + printf("ASF end pts: %d\n",(int)fileh.end_timestamp); +} +#endif + +#endif +return 1; +} + diff --git a/aviheader.c b/aviheader.c new file mode 100644 index 0000000000..9fd8c220c1 --- /dev/null +++ b/aviheader.c @@ -0,0 +1,89 @@ + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +void read_avi_header(int no_index){ + +int stream_id=-1; + +//---- AVI header: +avi_header.idx_size=0; +while(1){ + int id=stream_read_dword_le(demuxer->stream); + int chunksize,size2; + static int last_fccType=0; + // + if(stream_eof(demuxer->stream)) break; + // + if(id==mmioFOURCC('L','I','S','T')){ + int len=stream_read_dword_le(demuxer->stream)-4; // list size + id=stream_read_dword_le(demuxer->stream); // list type + if(verbose>=2) printf("LIST %.4s len=%d\n",&id,len); + if(id==listtypeAVIMOVIE){ + // found MOVI header + avi_header.movi_start=stream_tell(demuxer->stream); + avi_header.movi_end=avi_header.movi_start+len; + if(verbose>=1) printf("Found movie at 0x%X - 0x%X\n",avi_header.movi_start,avi_header.movi_end); + len=(len+1)&(~1); + stream_skip(demuxer->stream,len); + } + continue; + } + size2=stream_read_dword_le(demuxer->stream); + if(verbose>=2) printf("CHUNK %.4s len=%d\n",&id,size2); + chunksize=(size2+1)&(~1); + switch(id){ + case ckidAVIMAINHDR: // read 'avih' + stream_read(demuxer->stream,(char*) &avi_header.avih,MIN(size2,sizeof(avi_header.avih))); + chunksize-=MIN(size2,sizeof(avi_header.avih)); + if(verbose) print_avih(&avi_header.avih); + break; + case ckidSTREAMHEADER: { // read 'strh' + AVIStreamHeader h; + stream_read(demuxer->stream,(char*) &h,MIN(size2,sizeof(h))); + chunksize-=MIN(size2,sizeof(h)); + if(h.fccType==streamtypeVIDEO) memcpy(&avi_header.video,&h,sizeof(h));else + if(h.fccType==streamtypeAUDIO) memcpy(&avi_header.audio,&h,sizeof(h)); + last_fccType=h.fccType; + if(verbose>=1) print_strh(&h); + ++stream_id; + break; } + case ckidSTREAMFORMAT: { // read 'strf' + if(last_fccType==streamtypeVIDEO){ + stream_read(demuxer->stream,(char*) &avi_header.bih,MIN(size2,sizeof(avi_header.bih))); + chunksize-=MIN(size2,sizeof(avi_header.bih)); +// init_video_codec(); +// init_video_out(); + if(demuxer->video->id==-1) demuxer->video->id=stream_id; + } else + if(last_fccType==streamtypeAUDIO){ + int z=(chunksize<64)?chunksize:64; + if(verbose>=2) printf("found 'wf', %d bytes of %d\n",chunksize,sizeof(WAVEFORMATEX)); + stream_read(demuxer->stream,(char*) &avi_header.wf_ext,z); + chunksize-=z; + if(verbose>=1) print_wave_header((WAVEFORMATEX*)&avi_header.wf_ext); +// init_audio_codec(); +// init_audio_out(); + if(demuxer->audio->id==-1) demuxer->audio->id=stream_id; + } + break; + } + case ckidAVINEWINDEX: if(!no_index){ + avi_header.idx_size=size2>>4; + if(verbose>=1) printf("Reading INDEX block, %d chunks for %d frames\n", + avi_header.idx_size,avi_header.avih.dwTotalFrames); + avi_header.idx=malloc(avi_header.idx_size<<4); + stream_read(demuxer->stream,(char*)avi_header.idx,avi_header.idx_size<<4); + chunksize-=avi_header.idx_size<<4; + if(verbose>=2) print_index(); + break; + } + } + if(chunksize>0) stream_skip(demuxer->stream,chunksize); else + if(chunksize<0) printf("WARNING!!! chunksize=%d (id=%.4s)\n",chunksize,&id); + +} + +} + +#undef MIN + diff --git a/aviparse.c b/aviparse.c new file mode 100644 index 0000000000..2fd34e9033 --- /dev/null +++ b/aviparse.c @@ -0,0 +1,336 @@ +// AVI Parser tool v0.1 (C) 2000. by A'rpi/ESP-team + +#include <stdio.h> +#include <stdlib.h> + +#include <signal.h> + +#include <sys/ioctl.h> +#include <unistd.h> +#include <sys/mman.h> + +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <linux/cdrom.h> + +#include "config.h" + +#include "loader.h" +#include "wine/avifmt.h" +//#include "libvo/video_out.h" + +#include "linux/timer.h" +#include "linux/shmem.h" + +#include "help_avp.h" + +#define DEBUG if(0) + +//static int show_packets=0; + +typedef struct { + // file: + MainAVIHeader avih; + unsigned int movi_start; + unsigned int movi_end; + // index: + AVIINDEXENTRY* idx; + int idx_size; + int idx_pos; +// int a_idx; +// int v_idx; + // video: + AVIStreamHeader video; + char *video_codec; + BITMAPINFOHEADER bih; // in format + BITMAPINFOHEADER o_bih; // out format + HIC hic; + void *our_out_buffer; + char yuv_supported; // 1 if codec support YUY2 output format + char yuv_hack_needed; // requires for divx & mpeg4 + // audio: + AVIStreamHeader audio; + char *audio_codec; + char wf_ext[64]; // in format + WAVEFORMATEX wf; // out format + HACMSTREAM srcstream; + int audio_minsize; +} avi_header_t; + +avi_header_t avi_header; + +#include "aviprint.c" +//#include "codecs.c" + +//**************************************************************************// +#include "stream.c" +//#include "demuxer.c" +//#include "demux_avi.c" + +static stream_t* stream=NULL; + +//**************************************************************************// + +extern int errno; +static int play_in_bg=0; + +void exit_player(){ +// int tmp; + // restore terminal: + getch2_disable(); + printf("\n\n"); + if(play_in_bg) system("xsetroot -solid \\#000000"); + exit(1); +} + +void exit_sighandler(int x){ + printf("\nmpgplay2 interrupted by signal %d\n",x); + exit_player(); +} + + +int main(int argc,char* argv[]){ +char* filename=NULL; //"MI2-Trailer.avi"; +int i; +//int seek_to_sec=0; +int seek_to_byte=0; +int f; // filedes +int has_audio=1; +//int audio_format=0; +//int alsa=0; +//int audio_buffer_size=-1; +int audio_id=-1; +//int video_id=-1; +//float default_max_pts_correction=0.01f; +//int delay_corrected=0; +//float force_fps=0; +//float default_fps=25; +//float audio_delay=0; +int stream_type; +//int elementary_stream=0; +int vcd_track=0; +#ifdef VCD_CACHE +int vcd_cache_size=128; +#endif +//char* video_driver="mga"; // default +//int out_fmt=0; +int idx_filepos=0; +FILE *audiofile=NULL; +FILE *videofile=NULL; +char *audiofile_name=NULL; +char *videofile_name=NULL; + + printf("%s",banner_text); + +for(i=1;i<argc;i++){ + if(strcmp(argv[i],"-afile")==0) audiofile_name=argv[++i]; else + if(strcmp(argv[i],"-vfile")==0) videofile_name=argv[++i]; else +// if(strcmp(argv[i],"-sb")==0) seek_to_byte=strtol(argv[++i],NULL,0); else + if(strcmp(argv[i],"-aid")==0) audio_id=strtol(argv[++i],NULL,0); else +// if(strcmp(argv[i],"-vid")==0) video_id=strtol(argv[++i],NULL,0); else +// if(strcmp(argv[i],"-afm")==0) audio_format=strtol(argv[++i],NULL,0); else +// if(strcmp(argv[i],"-vcd")==0) vcd_track=strtol(argv[++i],NULL,0); else + if(strcmp(argv[i],"-h")==0) break; else + if(strcmp(argv[i],"--help")==0) break; else + { if(filename){ printf("invalid option: %s\n",filename);exit(1);} + filename=argv[i]; + } +} + +if(!filename){ + if(vcd_track) filename="/dev/cdrom"; +// else +// filename="/4/Film/Joan of Arc [Hun DivX]/Joan of Arc - CD2.avi"; + { printf("%s",help_text); exit(0);} +} + + +if(vcd_track){ +//============ Open VideoCD track ============== + f=open(filename,O_RDONLY); + if(f<0){ printf("Device not found!\n");return 1; } + vcd_read_toc(f); + if(!vcd_seek_to_track(f,vcd_track)){ printf("Error selecting VCD track!\n");return 1;} + seek_to_byte+=VCD_SECTOR_DATA*vcd_get_msf(); + stream_type=STREAMTYPE_VCD; +#ifdef VCD_CACHE + vcd_cache_init(vcd_cache_size); +#endif +} else { +//============ Open plain FILE ============ + f=open(filename,O_RDONLY); + if(f<0){ printf("File not found!\n");return 1; } + stream_type=STREAMTYPE_FILE; +} + +//============ Open & Sync stream and detect file format =============== + +stream=new_stream(f,stream_type); +//=============== Read AVI header: +{ //---- RIFF header: + int id=stream_read_dword_le(stream); // "RIFF" + if(id!=mmioFOURCC('R','I','F','F')){ printf("Not RIFF format file!\n");return 1; } + stream_read_dword_le(stream); //filesize + id=stream_read_dword_le(stream); // "AVI " + if(id!=formtypeAVI){ printf("Not AVI file!\n");return 1; } +} +//---- AVI header: +avi_header.idx_size=0; +while(1){ + int id=stream_read_dword_le(stream); + int chunksize,size2; + static int last_fccType=0; + // + if(stream_eof(stream)) break; + // + if(id==mmioFOURCC('L','I','S','T')){ + int len=stream_read_dword_le(stream)-4; // list size + id=stream_read_dword_le(stream); // list type + printf("LIST %.4s len=%d\n",&id,len); + if(id==listtypeAVIMOVIE){ + // found MOVI header + avi_header.movi_start=stream_tell(stream); + avi_header.movi_end=avi_header.movi_start+len; +// printf("Found movie at 0x%X - 0x%X\n",avi_header.movi_start,avi_header.movi_end); + len=(len+1)&(~1); + stream_skip(stream,len); + } + continue; + } + size2=stream_read_dword_le(stream); + printf("CHUNK %.4s len=%d\n",&id,size2); + chunksize=(size2+1)&(~1); + switch(id){ + case ckidAVIMAINHDR: // read 'avih' + stream_read(stream,(char*) &avi_header.avih,sizeof(avi_header.avih)); + chunksize-=sizeof(avi_header.avih); + print_avih(&avi_header.avih); + break; + case ckidSTREAMHEADER: { // read 'strh' + AVIStreamHeader h; + stream_read(stream,(char*) &h,sizeof(h)); + chunksize-=sizeof(h); + if(h.fccType==streamtypeVIDEO) memcpy(&avi_header.video,&h,sizeof(h));else + if(h.fccType==streamtypeAUDIO) memcpy(&avi_header.audio,&h,sizeof(h)); + last_fccType=h.fccType; + print_strh(&h); + break; } + case ckidSTREAMFORMAT: { // read 'strf' + if(last_fccType==streamtypeVIDEO){ + stream_read(stream,(char*) &avi_header.bih,sizeof(avi_header.bih)); + chunksize-=sizeof(avi_header.bih); +// init_video_codec(); +// init_video_out(); + } else + if(last_fccType==streamtypeAUDIO){ + int z=(chunksize<64)?chunksize:64; + printf("found 'wf', %d bytes of %d\n",chunksize,sizeof(WAVEFORMATEX)); + stream_read(stream,(char*) &avi_header.wf_ext,z); + chunksize-=z; + print_wave_header((WAVEFORMATEX*)&avi_header.wf_ext); +// init_audio_codec(); +// init_audio_out(); + } + break; + } + case ckidAVINEWINDEX: { + avi_header.idx_size=size2>>4; +// printf("Reading INDEX block, %d chunks for %d frames\n", +// avi_header.idx_size,avi_header.avih.dwTotalFrames); + avi_header.idx=malloc(avi_header.idx_size<<4); + idx_filepos=stream_tell(stream); + stream_read(stream,(char*)avi_header.idx,avi_header.idx_size<<4); + chunksize-=avi_header.idx_size<<4; + print_index(); + break; + } + } + if(chunksize>0) stream_skip(stream,chunksize); else + if(chunksize<0) printf("WARNING!!! chunksize=%d (id=%.4s)\n",chunksize,&id); + +} + +printf("----------------------------------------------------------------------\n"); +printf("Found movie at 0x%X - 0x%X\n",avi_header.movi_start,avi_header.movi_end); +if(avi_header.idx_size<=0){ printf("No index block found!\n");return 0;} +printf("Index block at 0x%X, %d entries for %d frames\n",idx_filepos, + avi_header.idx_size,avi_header.avih.dwTotalFrames ); + +stream_reset(stream); +stream_seek(stream,avi_header.movi_start); +avi_header.idx_pos=0; + +if(audiofile_name) audiofile=fopen(audiofile_name,"wb"); +if(videofile_name) videofile=fopen(videofile_name,"wb"); + +for(i=0;i<avi_header.idx_size;i++){ +#if 0 + printf("%.4s %4X %08X %d ", + &avi_header.idx[i].ckid, + avi_header.idx[i].dwFlags, + avi_header.idx[i].dwChunkOffset, + avi_header.idx[i].dwChunkLength + );fflush(stdout); +#endif + if(avi_header.idx[i].ckid&AVIIF_LIST){ +// printf("LIST\n"); + } else { + int id,size; + stream_seek(stream,avi_header.movi_start+avi_header.idx[i].dwChunkOffset-4); + id=stream_read_dword_le(stream); + size=stream_read_dword_le(stream); + if(id!=avi_header.idx[i].ckid){ + printf("ChunkID mismatch! raw=%.4s (0x%X) idx=%.4s (0x%X)\n", + &id,avi_header.movi_start+avi_header.idx[i].dwChunkOffset-4, + &avi_header.idx[i].ckid,idx_filepos+16*i + ); + continue; + } + if(size!=avi_header.idx[i].dwChunkLength){ + printf("ChunkSize mismatch! raw=%d (0x%X) idx=%d (0x%X)\n", + size,avi_header.movi_start+avi_header.idx[i].dwChunkOffset-4, + avi_header.idx[i].dwChunkLength,idx_filepos+16*i + ); + continue; + } + + if(id!=mmioFOURCC('J','U','N','K')) + if(TWOCCFromFOURCC(id)==cktypeWAVEbytes){ + // audio + int aid=StreamFromFOURCC(id); + if(audio_id==-1) audio_id=aid; + if(audio_id==aid){ + if(audiofile){ + void* mem=malloc(size); + stream_read(stream,mem,size); + fwrite(mem,size,1,audiofile); + free(mem); + } + } else { + printf("Invalid audio stream id: %d (%.4s)\n",aid,&id); + } + } else + if(LOWORD(id)==aviTWOCC('0','0')){ + // video + if(videofile){ + void* mem=malloc(size); + stream_read(stream,mem,size); + fwrite(&size,4,1,videofile); + fwrite(mem,size,1,videofile); + free(mem); + } + } else { + // unknown + printf("Unknown chunk: %.4s (%X)\n",&id,id); + } + + } // LIST or CHUNK + +} + +return 0; +} + diff --git a/aviprint.c b/aviprint.c new file mode 100644 index 0000000000..fd110008fe --- /dev/null +++ b/aviprint.c @@ -0,0 +1,88 @@ +void print_avih(MainAVIHeader *h){ + printf("======= AVI Header =======\n"); + printf("us/frame: %d (fps=%5.3f)\n",h->dwMicroSecPerFrame,1000000.0f/(float)h->dwMicroSecPerFrame); + printf("max bytes/sec: %d\n",h->dwMaxBytesPerSec); + printf("padding: %d\n",h->dwPaddingGranularity); + printf("flags: (%d)%s%s%s%s%s%s\n",h->dwFlags, + (h->dwFlags&AVIF_HASINDEX)?" HAS_INDEX":"", + (h->dwFlags&AVIF_MUSTUSEINDEX)?" MUST_USE_INDEX":"", + (h->dwFlags&AVIF_ISINTERLEAVED)?" IS_INTERLEAVED":"", + (h->dwFlags&AVIF_TRUSTCKTYPE)?" TRUST_CKTYPE":"", + (h->dwFlags&AVIF_WASCAPTUREFILE)?" WAS_CAPTUREFILE":"", + (h->dwFlags&AVIF_COPYRIGHTED)?" COPYRIGHTED":"" + ); + printf("frames total: %d initial: %d\n",h->dwTotalFrames,h->dwInitialFrames); + printf("streams: %d\n",h->dwStreams); + printf("Suggested BufferSize: %d\n",h->dwSuggestedBufferSize); + printf("Size: %d x %d\n",h->dwWidth,h->dwHeight); +} + +void print_strh(AVIStreamHeader *h){ + printf("======= STREAM Header =======\n"); + printf("Type: %.4s FCC: %.4s (%X)\n",&h->fccType,&h->fccHandler,h->fccHandler); + printf("Flags: %d\n",h->dwFlags); + printf("Priority: %d Language: %d\n",h->wPriority,h->wLanguage); + printf("InitialFrames: %d\n",h->dwInitialFrames); + printf("Rate: %d/%d = %5.3f\n",h->dwRate,h->dwScale,(float)h->dwRate/(float)h->dwScale); + printf("Start: %d Len: %d\n",h->dwStart,h->dwLength); + printf("Suggested BufferSize: %d\n",h->dwSuggestedBufferSize); + printf("Quality %d\n",h->dwQuality); + printf("Sample size: %d\n",h->dwSampleSize); +} + +void print_wave_header(WAVEFORMATEX *h){ + + printf("======= WAVE Format =======\n"); + + printf("Format Tag: %d (0x%X)\n",h->wFormatTag,h->wFormatTag); + printf("Channels: %d\n",h->nChannels); + printf("Samplerate: %d\n",h->nSamplesPerSec); + printf("avg byte/sec: %d\n",h->nAvgBytesPerSec); + printf("Block align: %d\n",h->nBlockAlign); + printf("bits/sample: %d\n",h->wBitsPerSample); + printf("cbSize: %d\n",h->cbSize); + + switch(h->wFormatTag){ + case 0x01: printf("Audio in PCM format\n");break; + case 0x50: printf("Audio in MPEG Layer 1/2 format\n");break; + case 0x55: printf("Audio in MPEG Layer-3 format\n");break; // ACM + case 0x02: printf("Audio in MS ADPCM format\n");break; // ACM + case 0x11: printf("Audio in IMA ADPCM format\n");break; // ACM + case 0x31: + case 0x32: printf("Audio in MS GSM 6.10 format\n");break; // ACM + case 0x75: printf("Audio in VoxWare format\n");break; // DShow + case 0x160: + case 0x161: printf("Audio in DivX WMA format\n");break; // ACM + default: printf("Audio in UNKNOWN (id=0x%X) format\n",h->wFormatTag); + } + +} + + +void print_video_header(BITMAPINFOHEADER *h){ + printf("======= VIDEO Format ======\n"); + printf(" biSize %d\n", h->biSize); + printf(" biWidth %d\n", h->biWidth); + printf(" biHeight %d\n", h->biHeight); + printf(" biPlanes %d\n", h->biPlanes); + printf(" biBitCount %d\n", h->biBitCount); + printf(" biCompression %d='%.4s'\n", h->biCompression, &h->biCompression); + printf(" biSizeImage %d\n", h->biSizeImage); + printf("===========================\n"); +} + + +void print_index(){ + int i; + for(i=0;i<avi_header.idx_size;i++){ + printf("%5d: %.4s %4X %08X (%08X) %d\n",i, + &avi_header.idx[i].ckid, + avi_header.idx[i].dwFlags, + avi_header.idx[i].dwChunkOffset, + avi_header.idx[i].dwChunkOffset+avi_header.movi_start, + avi_header.idx[i].dwChunkLength + ); + } +} + + diff --git a/aviwrite.c b/aviwrite.c new file mode 100644 index 0000000000..6826bcce0a --- /dev/null +++ b/aviwrite.c @@ -0,0 +1,161 @@ + +void write_avi_chunk(FILE *f,unsigned int id,int len,void* data){ + +fwrite(&id,4,1,f); +fwrite(&len,4,1,f); +if(len>0){ + if(data){ + // DATA + fwrite(data,len,1,f); + if(len&1){ // padding + unsigned char zerobyte=0; + fwrite(&zerobyte,1,1,f); + } + } else { + // JUNK + char *avi_junk_data="[= MPlayer junk data! =]"; + if(len&1) ++len; // padding + while(len>0){ + int l=strlen(avi_junk_data); + if(l>len) l=len; + fwrite(avi_junk_data,l,1,f); + len-=l; + } + } +} + +} + + +void write_avi_list(FILE *f,unsigned int id,int len){ + unsigned int list_id=FOURCC_LIST; + len+=4; // list fix + fwrite(&list_id,4,1,f); + fwrite(&len,4,1,f); + fwrite(&id,4,1,f); +} + +struct { + MainAVIHeader avih; + AVIStreamHeader video; + BITMAPINFOHEADER bih; + unsigned int movi_start; + unsigned int movi_end; + unsigned int file_end; +} wah; + +void write_avi_header(FILE *f){ + unsigned int riff[3]; + // RIFF header: + riff[0]=mmioFOURCC('R','I','F','F'); + riff[1]=wah.file_end; // filesize + riff[2]=formtypeAVI; // 'AVI ' + fwrite(&riff,12,1,f); + // AVI header: + write_avi_list(f,listtypeAVIHEADER,sizeof(wah.avih)+8+12+sizeof(wah.video)+8+sizeof(wah.bih)+8); + write_avi_chunk(f,ckidAVIMAINHDR,sizeof(wah.avih),&wah.avih); + // stream header: + write_avi_list(f,listtypeSTREAMHEADER,sizeof(wah.video)+8+sizeof(wah.bih)+8); + write_avi_chunk(f,ckidSTREAMHEADER,sizeof(wah.video),&wah.video); + write_avi_chunk(f,ckidSTREAMFORMAT,sizeof(wah.bih),&wah.bih); + // JUNK: + write_avi_chunk(f,ckidAVIPADDING,2048-(ftell(f)&2047)-8,NULL); + // 'movi' header: + write_avi_list(f,listtypeAVIMOVIE,wah.movi_end-ftell(f)-12); + wah.movi_start=ftell(f); +} + +// called _before_ encoding: (write placeholders and video info) +void write_avi_header_1(FILE *f,int fcc,float fps,int width,int height){ + int frames=8*3600*fps; // 8 hours + + wah.file_end= + wah.movi_end=0x7f000000; + + wah.avih.dwMicroSecPerFrame=1000000.0f/fps; + wah.avih.dwMaxBytesPerSec=fps*500000; // ????? + wah.avih.dwPaddingGranularity=1; // padding + wah.avih.dwFlags=AVIF_ISINTERLEAVED; + wah.avih.dwTotalFrames=frames; + wah.avih.dwInitialFrames=0; + wah.avih.dwStreams=1; + wah.avih.dwSuggestedBufferSize=0x10000; // 1MB + wah.avih.dwWidth=width; + wah.avih.dwHeight=height; + wah.avih.dwReserved[0]= + wah.avih.dwReserved[1]= + wah.avih.dwReserved[2]= + wah.avih.dwReserved[3]=0; + + wah.video.fccType=streamtypeVIDEO; + wah.video.fccHandler=fcc; + wah.video.dwFlags=0; + wah.video.wPriority=0; + wah.video.wLanguage=0; + wah.video.dwInitialFrames=0; + wah.video.dwScale=10000; + wah.video.dwRate=fps*10000; + wah.video.dwStart=0; + wah.video.dwLength=frames; + wah.video.dwSuggestedBufferSize=0x100000; // 1MB ???? + wah.video.dwQuality=10000; + wah.video.dwSampleSize=width*height*3; + + wah.bih.biSize=sizeof(wah.bih); // 40 ? + wah.bih.biWidth=width; + wah.bih.biHeight=height; + wah.bih.biPlanes=1; + wah.bih.biBitCount=24; + wah.bih.biCompression=fcc; + wah.bih.biSizeImage=3*width*height; + wah.bih.biXPelsPerMeter= + wah.bih.biYPelsPerMeter= + wah.bih.biClrUsed= + wah.bih.biClrImportant=0; + + write_avi_header(f); +} + +void avi_fixate(){ + // append index and fix avi headers: + FILE *f1=fopen(encode_name,"r+"); + FILE *f2; + + if(!f1) return; // error + + fseek(f1,0,SEEK_END); + wah.file_end=wah.movi_end=ftell(f1); + + // index: + if(encode_index_name && (f2=fopen(encode_index_name,"rb"))){ + AVIINDEXENTRY idx; + unsigned int pos=0; + int frames=0; + write_avi_chunk(f1,ckidAVINEWINDEX,0,NULL); + while(fread(&idx,sizeof(idx),1,f2)>0){ + idx.dwChunkOffset-=wah.movi_start-4; + fwrite(&idx,sizeof(idx),1,f1); + ++frames; + } + fclose(f2); + unlink(encode_index_name); + wah.file_end=ftell(f1); + // re-write idx1 length: + pos=wah.file_end-wah.movi_end-8; + fseek(f1,wah.movi_end+4,SEEK_SET); + fwrite(&pos,4,1,f1); + // fixup frames: + wah.avih.dwTotalFrames=frames; + wah.video.dwLength=frames; + } + + // re-write avi header: + fseek(f1,0,SEEK_SET); + write_avi_header(f1); + + fclose(f1); + +} + + + diff --git a/codecctrl.c b/codecctrl.c new file mode 100644 index 0000000000..23b424308f --- /dev/null +++ b/codecctrl.c @@ -0,0 +1,198 @@ + +//#define DEBUG_SIGNALS +#define DEBUG_SIGNALS_SLEEP ; +//#define DEBUG_SIGNALS_SLEEP sleep(2); + +#ifdef DEBUG_SIGNALS +#define DEBUG_SIG if(1) +#else +#define DEBUG_SIG if(0) +#endif + +//======= Interprocess Comminication (IPC) between player & codec ========= + +static int child_pid=0; +static int codec_pid=0; + +// player: +static int data_fifo=-1; +static int control_fifo=-1; +// codec: +static int data_fifo2=-1; +static int control_fifo2=-1; +// keyboard: +static int keyb_fifo_put=-1; +static int keyb_fifo_get=-1; + + +// SIGTERM handler of codec controller (2nd process): +static void codec_ctrl_sighandler(int x){ +DEBUG_SIG printf("\nCTRL: received signal %d, terminating child first:\n",x); + // first terminate the codec: + //kill(child_pid,SIGTERM); + kill(child_pid,x); + usleep(50000); // 50ms must be enough +DEBUG_SIG printf("CTRL: Sending KILL signal to child:\n"); + kill(child_pid,SIGKILL); // worst case + usleep(10000); + // and exit + if(x!=SIGHUP){ +DEBUG_SIG printf("CTRL: Exiting...\n"); + exit(0); + } +} + +static vo_functions_t *codec_video_out_ptr=NULL; + +// SIGTERM handler of the codec (3nd process): +static void codec_sighandler(int x){ +DEBUG_SIG printf("\nCHILD: received signal %d, exiting...\n",x); + if(x==SIGTERM){ + //mpeg2_close(codec_video_out_ptr); + codec_video_out_ptr->uninit(); // closing video_out + } + exit(0); +} + + +static void make_pipe(int* pr,int* pw){ + int temp[2]; + if(pipe(temp)!=0) printf("Cannot make PIPE!\n"); + *pr=temp[0]; + *pw=temp[1]; +} + +static inline int my_write(int fd,unsigned char* mem,int len){ + int total=0; + int len2; + while(len>0){ + len2=write(fd,mem+total,len); if(len2<=0) break; + total+=len2;len-=len2; +// printf("%d bytes received, %d left\n",len2,len); + } + return total; +} + +static inline int my_read(int fd,unsigned char* mem,int len){ + int total=0; + int len2; + while(len>0){ + len2=read(fd,mem+total,len); if(len2<=0) break; + total+=len2;len-=len2; +// printf("%d bytes received, %d left\n",len2,len); + } + return total; +} + + +void send_cmd(int fd,int cmd){ + int fifo_cmd=cmd; + write(fd,&fifo_cmd,4); +// fflush(control_fifo); +} + +void mpeg_codec_controller(vo_functions_t *video_out){ +//================== CODEC Controller: ========================== + signal(SIGTERM,codec_ctrl_sighandler); // set our SIGTERM handler + signal(SIGHUP,codec_ctrl_sighandler); // set our SIGHUP handler + printf("starting video codec...\n"); + while(1){ + int status; + if((child_pid=fork())==0){ + // child: + unsigned int t=0; + codec_video_out_ptr=video_out; +#if 0 + signal(SIGTERM,codec_sighandler); // set our SIGTERM handler + signal(SIGHUP,codec_sighandler); // set our SIGHUP handler +#else + // terminate requests: + signal(SIGTERM,codec_sighandler); // kill + signal(SIGHUP,codec_sighandler); // kill -HUP / xterm closed + signal(SIGINT,codec_sighandler); // Interrupt from keyboard + signal(SIGQUIT,codec_sighandler); // Quit from keyboard + // fatal errors: + signal(SIGBUS,codec_sighandler); // bus error + signal(SIGSEGV,codec_sighandler); // segfault + signal(SIGILL,codec_sighandler); // illegal instruction + signal(SIGFPE,codec_sighandler); // floating point exc. + signal(SIGABRT,codec_sighandler); // abort() +#endif + + send_cmd(control_fifo2,0x22222222); // Send WE_ARE_READY command + send_cmd(control_fifo2,getpid()); // Send out PID + while(1){ + unsigned int syncword=0; + read(data_fifo2,&syncword,4); + if(syncword==0x22222222) break; + printf("codec: drop bad frame (%X)\n",syncword); + } + //printf("codec: connection synced\n"); + + while(1){ + int num_frames; + int len=0; + int len2; + send_cmd(control_fifo2,0x3030303); + len2=my_read(data_fifo2,(unsigned char*) &len,4); + if(len2!=4){ + printf("FATAL: cannot read packet len from data fifo (ret=%d, errno=%d)\n",len2,errno); + break; + } + if(len==0){ printf("mpeg2dec: EOF, exiting...\n");break; } +// printf("mpeg2dec: frame (%d bytes) read\n",len); + t-=GetTimer(); + mpeg2_decode_data(video_out, videobuffer, videobuffer+len); + t+=GetTimer(); + send_cmd(control_fifo2,0); // FRAME_COMPLETED command + send_cmd(control_fifo2,picture->frame_rate); // fps + send_cmd(control_fifo2,100+picture->repeat_count);picture->repeat_count=0; + send_cmd(control_fifo2,t);t=0; + } + video_out->uninit(); + exit(0); // leave process + } + wait(&status); // Waiting for the child! +// printf("restarting video codec...\n"); + } + exit(0); +} + +void mplayer_put_key(int code){ + fd_set rfds; + struct timeval tv; + + /* Watch stdin (fd 0) to see when it has input. */ + FD_ZERO(&rfds); + FD_SET(keyb_fifo_put, &rfds); + tv.tv_sec = 0; + tv.tv_usec = 0; + + //retval = select(keyb_fifo_put+1, &rfds, NULL, NULL, &tv); + if(select(keyb_fifo_put+1, NULL, &rfds, NULL, &tv)){ + write(keyb_fifo_put,&code,4); +// printf("*** key event %d sent ***\n",code); + } else { +// printf("*** key event dropped (FIFO is full) ***\n"); + } +} + +int mplayer_get_key(){ + fd_set rfds; + struct timeval tv; + int code=-1; + + /* Watch stdin (fd 0) to see when it has input. */ + FD_ZERO(&rfds); + FD_SET(keyb_fifo_get, &rfds); + tv.tv_sec = 0; + tv.tv_usec = 0; + + //retval = select(keyb_fifo_put+1, &rfds, NULL, NULL, &tv); + if(select(keyb_fifo_put+1, &rfds, NULL, NULL, &tv)){ + read(keyb_fifo_get,&code,4); +// printf("*** key event %d read ***\n",code); + } + return code; +} + diff --git a/codecs.c b/codecs.c new file mode 100644 index 0000000000..1a5b39e649 --- /dev/null +++ b/codecs.c @@ -0,0 +1,150 @@ +//#define ANGELPOTION + +char* get_vids_codec_name(){ +// unsigned long fccHandler=avi_header.video.fccHandler; + unsigned long fccHandler=avi_header.bih.biCompression; + avi_header.yuv_supported=0; + avi_header.yuv_hack_needed=0; + avi_header.flipped=0; + switch(fccHandler){ + case mmioFOURCC('M', 'P', 'G', '4'): + case mmioFOURCC('m', 'p', 'g', '4'): + case mmioFOURCC('M', 'P', '4', '2'): + case mmioFOURCC('m', 'p', '4', '2'): +// case mmioFOURCC('M', 'P', '4', '3'): +// case mmioFOURCC('m', 'p', '4', '3'): + printf("Video in Microsoft MPEG-4 format\n"); + avi_header.yuv_supported=1; + avi_header.yuv_hack_needed=1; +#ifdef ANGELPOTION + return "APmpg4v1.dll"; +#endif + return "mpg4c32.dll"; + case mmioFOURCC('M', 'P', '4', '3'): + case mmioFOURCC('m', 'p', '4', '3'): + printf("Video in MPEG-4 v3 (really DivX) format\n"); + avi_header.bih.biCompression=mmioFOURCC('d', 'i', 'v', '3'); // hack + avi_header.yuv_supported=1; + avi_header.yuv_hack_needed=1; +#ifdef ANGELPOTION + return "APmpg4v1.dll"; +#endif + return "divxc32.dll"; + + case mmioFOURCC('D', 'I', 'V', 'X'): + case mmioFOURCC('d', 'i', 'v', 'x'): + return "DivX.dll"; + + case mmioFOURCC('D', 'I', 'V', '3'): + case mmioFOURCC('d', 'i', 'v', '3'): + case mmioFOURCC('D', 'I', 'V', '4'): + case mmioFOURCC('d', 'i', 'v', '4'): + case mmioFOURCC('M', 'P', '4', '1'): + case mmioFOURCC('m', 'p', '4', '1'): + printf("Video in DivX ;-) format\n"); + avi_header.yuv_supported=1; + avi_header.yuv_hack_needed=1; +#ifdef ANGELPOTION + return "APmpg4v1.dll"; +#endif + return "divxc32.dll"; + + case mmioFOURCC('I', 'V', '5', '0'): + case mmioFOURCC('i', 'v', '5', '0'): + printf("Video in Indeo Video 5 format\n"); + avi_header.yuv_supported=1; // YUV pic is upside-down :( + return "ir50_32.dll"; + + case mmioFOURCC('I', 'V', '4', '1'): + case mmioFOURCC('i', 'v', '4', '1'): + printf("Video in Indeo Video 4.1 format\n"); + avi_header.flipped=1; + avi_header.no_32bpp_support=1; + return "ir41_32.dll"; + + case mmioFOURCC('I', 'V', '3', '2'): + case mmioFOURCC('i', 'v', '3', '2'): + printf("Video in Indeo Video 3.2 format\n"); + avi_header.flipped=1; + avi_header.no_32bpp_support=1; + return "ir32_32.dll"; + + case mmioFOURCC('c', 'v', 'i', 'd'): + printf("Video in Cinepak format\n"); + avi_header.yuv_supported=1; + return "iccvid.dll"; + +//*** Only 16bit .DLL available (can't load under linux) *** +// case mmioFOURCC('V', 'C', 'R', '1'): +// printf("Video in ATI VCR1 format\n"); +// return "ativcr1.dll"; + + case mmioFOURCC('V', 'C', 'R', '2'): + printf("Video in ATI VCR2 format\n"); + avi_header.yuv_supported=1; + return "ativcr2.dll"; + + case mmioFOURCC('A', 'S', 'V', '1'): + printf("Asus ASV-1 format\n"); +// avi_header.yuv_supported=1; + return "asusasvd.dll"; + + case mmioFOURCC('A', 'S', 'V', '2'): + printf("Asus ASV-2 format\n"); +// avi_header.yuv_supported=1; + avi_header.flipped=1; +// avi_header.bih.biCompression=mmioFOURCC('A', 'S', 'V', '1'); +// return "asusasvd.dll"; + return "asusasv2.dll"; + + case mmioFOURCC('I', '2', '6', '3'): + case mmioFOURCC('i', '2', '6', '3'): + printf("Video in I263 format\n"); + return "i263_32.drv"; + + case mmioFOURCC('M', 'J', 'P', 'G'): + printf("Video in MJPEG format\n"); + avi_header.yuv_supported=1; + return "M3JPEG32.dll"; +// return "mcmjpg32.dll"; +// return "m3jpeg32.dll"; +// return "libavi_mjpeg.so"; + } + printf("UNKNOWN video codec: %.4s (0x%0X)\n",&fccHandler,fccHandler); + printf("If you know this video format and codec, you can edit codecs.c in the source!\n"); + printf("Please contact the author, send this movie to be supported by future version.\n"); + return NULL; +} + +char* get_auds_codec_name(){ + int id=((WAVEFORMATEX*)avi_header.wf_ext)->wFormatTag; + switch (id){ + case 0x161://DivX audio +// ((WAVEFORMATEX*)avi_header.wf_ext)->wFormatTag=0x160; //hack + case 0x160://DivX audio + avi_header.audio_seekable=0; + return "divxa32.acm"; // tested, OK. + case 0x2://MS ADPCM + avi_header.audio_seekable=0; + return "msadp32.acm"; // tested, OK. + case 0x55://MPEG l3 + avi_header.audio_seekable=1; + return "l3codeca.acm"; // tested, OK. faster than mp3lib on intel + case 0x11://IMA ADPCM + return "imaadp32.acm"; // segfault :( + case 0x31://MS GSM + case 0x32://MS GSM + return "msgsm32.acm"; // segfault :( - not req. has internal now! + case 0x75://VoxWare + return "voxmsdec.ax"; // directshow, not yet supported just a try +// case 0x06://??? +// return "lhacm.acm"; +// return "msg711.acm"; +// return "tssoft32.acm"; + } + printf("UNKNOWN audio codec: 0x%0X\n",id); + printf("If you know this audio format and codec, you can edit codecs.c in the source!\n"); + printf("Please contact the author, send this movie to be supported by future version.\n"); + return NULL; +} + diff --git a/config.h b/config.h new file mode 100644 index 0000000000..d9e8785f52 --- /dev/null +++ b/config.h @@ -0,0 +1,70 @@ + +/* -------- Generated by ./configure ----------- */ + +/* Define this to enable avg. byte/sec-based AVI sync method by default: + (use -bps or -nobps commandline option for run-time method selection) */ +#undef AVI_SYNC_BPS + +/* Undefine this if you want soundcard-only timing by default: + You can still change this with the -alsa or -noalsa command-line option! + (This function was originally impemented to solve ALSA driver's big + buffer problems, but it seems to be useful for every soundcard drivers) */ +#define ALSA_TIMER + +/* Undefine this if your soundcard driver has no working select(). + If you have kernel Oops, player hangups, or just no audio, you should + try to recompile MPlayer with this option disabled! */ +#define HAVE_AUDIO_SELECT + +/* You have a choice for MP3 decoding: mp3lib(mpg123) or Win32(l3codeca.acm) + #define this if you prefer mpg123 (with 3Dnow! support) than l3codeca.acm + (with mmx/sse optimizations) + You can still change it runtime using -afm 1 (mpg123) or -afm 4 (l3codeca)*/ +#undef DEFAULT_MPG123 + +/* XMMP support: (test code) */ +#undef USE_XMMP_AUDIO +#define LIBDIR "/usr/local/lib" +#define PLUGINDIR LIBDIR "/xmmp/Plugins" +#define XMMP_AUDIO_DRIVER PLUGINDIR "/Sound/oss.so" + +/* LIRC (remote control, see www.lirc.org) support: */ +#undef HAVE_LIRC + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #define WORDS_BIGENDIAN */ + +#define ARCH_X86 + +///////////////////////////////////////////////////////////////////////////// +// +// NOTE: Instead of modifying these here, use the --enable/--disable options +// of the ./configure script! See ./configure --help for details. +// +///////////////////////////////////////////////////////////////////////////// + +/* termcap flag for getch2.c */ +#define USE_TERMCAP + +/* Extension defines */ +#undef HAVE_MLIB // available only on solaris +#undef HAVE_3DNOW // only define if you have 3DNOW (AMD k6-2, AMD Athlon, iDT WinChip, etc.) +#define HAVE_MMX // only define if you have MMX +#define HAVE_SSE // only define if you have SSE (Intel Pentium III or Celeron II) + +/* libvo options */ +#define SCREEN_SIZE_X 1 +#define SCREEN_SIZE_Y 1 +#define HAVE_X11 +#undef HAVE_XV +#define HAVE_GL +#undef HAVE_SDL +#undef HAVE_3DFX +#define HAVE_MGA +#define HAVE_SYNCFB + +#if defined(HAVE_GL)||defined(HAVE_X11)|defined(HAVE_XV) +#define X11_FULLSCREEN +#endif + diff --git a/config.mak b/config.mak new file mode 100644 index 0000000000..59186c6732 --- /dev/null +++ b/config.mak @@ -0,0 +1,14 @@ + +# -------- Generated by ./configure ----------- + +AR=ar +CC=gcc +# OPTFLAGS=-O4 -march=i686 -mcpu=i686 -pipe -fomit-frame-pointer -ffast-math +OPTFLAGS=-O4 -march=i686 -mcpu=i686 -pipe -ffast-math +# LIBS=-L/usr/lib -L/usr/local/lib -L/usr/X11R6/lib -lGL -lX11 -lXext +X_LIBS=-L/usr/X11R6/lib -lGL -lX11 -lXext +TERMCAP_LIB=-ltermcap +XMM_LIBS = +LIRC_LIBS = +WIN32_PATH=-DWIN32_PATH=\"/usr/lib/win32\" + diff --git a/configure b/configure new file mode 100755 index 0000000000..9e86268bb9 --- /dev/null +++ b/configure @@ -0,0 +1,783 @@ +#!/bin/sh + +# +# MPlayer configurator. (C) 2000 Pontscho/fresh!mindworkz +# pontscho@makacs.poliod.hu +# +# some changes by A'rpi/ESP-team: +# - some english bugfix :) +# - removed _??exists flags, _?? is enough... +# - creating only config.mak files instead of whole Makefiles +# +# some changes by LGB (Gábor Lénárt): +# - SOME gcc may support 'k7', so I added tests for ALL CPU type optimization +# switches with the ability to find out the best optimization for your CPU. +# - Help moved to the begining to avoid tests if user only wants help. +# - A one lined help to indicate detailed help for users +# - Fixed /tmp race (PIDs can be predicted, I added random numbers as well) +# +# some changes by A'rpi/ESP-team: +# - the --win32libdir patch by Aaron Hope applied +# - some english bugfix again :) +# - cpu type selection changed: +# ( k7->k6->k5-> ) || (i686->pentiumpro-> ) pentium-> i486 -> i386 -> error! +# - cpu type for AMD/family=5 changed k6->k5 +# +# some changes by LGB: +# - Ehhh, AMD K6-2 returns with cpuid 5 ;-) Changing back Arpi's last change :) +# More info: AMD K6-2 reports with family 5, duron with 6, so I attached +# much finer CPU type detection based on Linux kernel's one :) +# (k5: 5, model<6, k6: 5, model>=6, k7: 6, model=any) +# - On some exit point (error) temporary files were not deleted. Fixed. +# - $TMP and $TMP2 are renamed to $TMPC and $TMPO ;-) +# - Some useless { ... } are removed +# +# some changes by A'rpi/ESP-team: +# - added 'athlon' target for the new athlongcc [Ian Kumlien] +# - applied _win32libdir=-L patch by Magnus Pfeffer +# +# -- + + +# LGB: Help moved here. + +if [ "$1" = "--help" -o "$1" = "-help" -o "$1" = "-h" ]; then +cat << EOF + +usage: $0 [options] + +params: + --enable-mmx build with mmx support [autodetect] + --enable-3dnow build with 3dnow! support [autodetect] + --enable-sse build with sse support [autodetect] + --enable-gl build with OpenGL render support [autodetect] + --enable-sdl build with SDL render support [def.: disabled!] + --enable-mga build with mga_vid support [autodetect, if /dev/mga_vid + is available] + --enable-xmga build with mga_vid X Window support [autodetect, + if both /dev/mga_vid and x11 are available] + --enable-xv build with Xv render support for X 4.x [autodetect] + --enable-x11 build with X11 render support [autodetect] + --enable-mlib build with MLIB support ( only Solaris ) + + --enable-termcap use termcap database for key codes + --enable-xmmp use XMMP audio drivers + --enable-lirc enable LIRC (remote control) support + + --with-x11libdir=DIR X library files are in DIR + --with-win32libdir=DIR windows codec files + + --size-x=SIZE default screen width + --size-y=SIZE default screen height +EOF +exit 0 +fi + +# LGB: Some inital help + +echo "You can get detailed help on configure with: $0 --help" +echo "Please wait while ./configure discovers your software and hardware environment!" + +# LGB: temporary files + +TMPC="/tmp/mplayer-conf-${RANDOM}-$$-${RANDOM}.c" +TMPO="/tmp/mplayer-conf-${RANDOM}-$$-${RANDOM}.o" + + +# --- + +# config files +CCONF='config.h' +MCONF='config.mak' + +# --- + +TAB=`echo -n -e "\t"` +pname=`cat /proc/cpuinfo | grep 'model name' | cut -d ':' -f 2` +pparam=`cat /proc/cpuinfo | grep 'features' | cut -d ':' -f 2` +if [ -z "$pparam" ]; then + pparam=`cat /proc/cpuinfo | grep 'flags' | cut -d ':' -f 2` +fi +pvendor=`cat /proc/cpuinfo | grep 'vendor_id' | cut -d ':' -f 2 | cut -d ' ' -f 2` +pfamily=`cat /proc/cpuinfo | grep 'cpu family' | cut -d ':' -f 2 | cut -d ' ' -f 2` +pmodel=`cat /proc/cpuinfo | grep "model$TAB" | cut -d ':' -f 2 | cut -d ' ' -f 2` +pstepping=`cat /proc/cpuinfo | grep 'stepping' | cut -d ':' -f 2 | cut -d ' ' -f 2` + +_mmx=no +_3dnow=no +_mtrr=no +_sse=no +_mga=no +_gl=no +_sdl=no +_xv=no +_x11=no +_3dfx=no +_syncfb=no +_mlib=no +_mpg123=no +_xmga=no +_lirc=no + +_x=1 +_y=1 + +_gllib= +_sdllib= +_x11lib= +_xvlib= +_xlibdir= + +for i in `echo $pparam`; do + + case "$i" in + 3dnow) + _3dnow=yes + _mpg123=yes + ;; + mmx) + _mmx=yes + ;; + mtrr) + _mtrr=yes + ;; + k6_mtrr) + _mtrr=yes + ;; + xmm) + _sse=yes + ;; + sse) + _sse=yes + ;; + kni) + _sse=yes + ;; + esac + +done + +if [ -e /usr/X11R6 ]; then + _x11libdir=-L/usr/X11R6/lib +else + if [ -e /usr/X11 ]; then + _x11libdir=-L/usr/X11/lib + fi +fi + +_win32libdirnotify=no +if [ -e /usr/lib/win32 ]; then + _win32libdir=/usr/lib/win32 +else + if [ -e /usr/local/lib/win32 ]; then + _win32libdir=/usr/local/lib/win32 + else +# This is our default: + _win32libdir=/usr/lib/win32 + _win32libdirnotify=yes + fi +fi + + +if [ -e /dev/mga_vid ]; then + _mga=yes + _syncfb=yes +fi + +proc=pentium + +case "$pvendor" in + AuthenticAMD) + case "$pfamily" in + 3) + proc=i386 + ;; + 4) + proc=i486 + ;; + 5) + if [ $pmodel -ge 6 ]; then # LGB: models are: K5/SSA5 K5 K5 K5 ? ? K6 K6 K6-2 K6-3 + proc=k6 + else + proc=k5 + fi + ;; + 6|7) # LGB: Though it seems Athlon CPUs returns with "6" + proc=k7 + ;; + *) + proc=pentium + ;; + esac + ;; + GenuineIntel) + case "$pfamily" in + 3) + proc=i386 + ;; + 4) + proc=i486 + ;; + 5) + proc=pentium + ;; + 6) + proc=i686 + ;; + *) + proc=pentium + ;; + esac + ;; + unknown) # added by Gabucino - upon Tibcu's request + case "$pfamily" in + 3) + proc=i386 + ;; + 4) + proc=i486 + ;; + *) + proc=pentium + ;; + esac + ;; + *) + proc=pentium + ;; +esac + +# --- + +cat > $TMPC << EOF +int main( void ) { return 0; } +EOF + +# check that gcc supports our cpu, if not, fallback to pentium +# LGB: check -mcpu and -march swithing step by step with enabling +# to fall back till 386. + +#echo -n "Checking your GCC CPU optimalization abilities: " +if [ "$proc" = "k7" ]; then +# echo -n "trying k7 " + gcc $TMPC -o $TMPO -march=$proc -mcpu=$proc &> /dev/null || proc=athlon +fi +if [ "$proc" = "athlon" ]; then +# echo -n "trying athlon " + gcc $TMPC -o $TMPO -march=$proc -mcpu=$proc &> /dev/null || proc=k6 +fi +if [ "$proc" = "k6" ]; then +# echo -n "trying k6 " + gcc $TMPC -o $TMPO -march=$proc -mcpu=$proc &> /dev/null || proc=k5 +fi +if [ "$proc" = "k5" ]; then +# echo -n "trying k5 " + gcc $TMPC -o $TMPO -march=$proc -mcpu=$proc &> /dev/null || proc=pentium +fi +if [ "$proc" = "i686" ]; then +# echo -n "trying i686 " + gcc $TMPC -o $TMPO -march=$proc -mcpu=$proc &> /dev/null || proc=pentiumpro +fi +if [ "$proc" = "pentiumpro" ]; then +# echo -n "trying pentiumpro " + gcc $TMPC -o $TMPO -march=$proc -mcpu=$proc &> /dev/null || proc=pentium +fi +if [ "$proc" = "pentium" ]; then +# echo -n "trying pentium " + gcc $TMPC -o $TMPO -march=$proc -mcpu=$proc &> /dev/null || proc=i486 +fi +if [ "$proc" = "i486" ]; then +# echo -n "trying i486 " + gcc $TMPC -o $TMPO -march=$proc -mcpu=$proc &> /dev/null || proc=i386 +fi +if [ "$proc" = "i386" ]; then +# echo -n "trying i386 " + gcc $TMPC -o $TMPO -march=$proc -mcpu=$proc &> /dev/null || proc=error +fi +if [ "$proc" = "error" ]; then + echo + echo "Your gcc does not support even \"i386\" for '-march' and '-mcpu'." >&2 + rm -f $TMPC $TMPO + exit +fi +#echo "DONE (${proc})." + + +# check GL & X11 & Xext & Xv & SDL & termcap libs + +gcc $TMPC -o $TMPO $_x11libdir/ -lGL &> /dev/null && _gl=yes +gcc $TMPC -o $TMPO $_x11libdir -lX11 -lXext &> /dev/null && _x11=yes +gcc $TMPC -o $TMPO $_x11libdir -lXv &> /dev/null && _xv=yes +gcc $TMPC -o $TMPO $_x11libdir -L/usr/local/lib/ -lpthread &> /dev/null || \ + { echo "Lib pthread not found."; rm -f $TMPC $TMPO ; exit 1; } + +# SDL disabled by default (0.11pre22-) because of the compilation problems +# this is very buggy & experimental code, use it only if you really need it!! +_have_sdl=no +gcc $TMPC -o $TMPO $_x11libdir -L/usr/local/lib/ -lSDL -lpthread &> /dev/null && _have_sdl=yes + +_termcap=no +gcc $TMPC -o $TMPO -ltermcap &> /dev/null && _termcap=yes + +_binutils=no +as libac3/downmix/downmix_i386.S -o $TMPO &> /dev/null && _binutils=yes + +cat > $TMPC << EOF +#include <GL/gl.h> +int main( void ) { return 0; } +EOF + +gcc $TMPC -o $TMPO $_x11libdir/ -lGL &> /dev/null || \ + { _gl=no; echo "GL includes not found!";} + +rm -f $TMPC $TMPO + + +if [ $_x11 = 'yes' ]; then + if [ $_mga = 'yes' ]; then + _xmga=yes + fi +fi + +# --- + +# check for the parameters. + +for ac_option +do + case "$ac_option" in + --enable-sse) + _sse=yes + ;; + --enable-3dnow) + _3dnow=yes + ;; + --enable-mmx) + _mmx=yes + ;; + --enable-gl) + _gl=yes + ;; + --enable-sdl) + _sdl=yes + ;; + --enable-mga) + _mga=yes + ;; + --enable-xmga) + _xmga=yes + ;; + --enable-xv) + _xv=yes + ;; + --enable-x11) + _x11=yes + ;; + --enable-3dfx) + _3dfx=yes + ;; + --enable-syncfb) + _syncfb=yes + ;; + --enable-mlib) + _mlib=yes + ;; + --enable-termcap) + _termcap=yes + ;; + --enable-xmmp) + _xmmp=yes + ;; + --enable-lirc) + _lirc=yes + ;; + --disable-sse) + _sse=no + ;; + --disable-3dnow) + _3dnow=no + ;; + --disable-mmx) + _mmx=no + ;; + --disable-gl) + _gl=no + ;; + --disable-sdl) + _sdl=no + ;; + --disable-mga) + _mga=no + ;; + --disable-xmga) + _xmga=no + ;; + --disable-xv) + _xv=no + ;; + --disable-x11) + _x11=no + ;; + --disable-mlib) + _mlib=no + ;; + --disable-termcap) + _termcap=no + ;; + --with-x11libdir=*) + _x11libdir=-L`echo $ac_option | cut -d '=' -f 2` + ;; + --with-win32libdir=*) + _win32libdir=`echo $ac_option | cut -d '=' -f 2` + ;; + --size-x=*) + _x=`echo $ac_option | cut -d '=' -f 2` + ;; + --size-y=*) + _y=`echo $ac_option | cut -d '=' -f 2` + ;; + esac +done + +# to screen. + +echo "Checking for cpu vendor ... $pvendor ( $pfamily:$pmodel:$pstepping )" +echo "Checking for cpu type ... $pname" +echo "Optimizing to ... $proc" +echo "Checking for mmx support ... $_mmx" +echo "Checking for 3dnow support ... $_3dnow" +echo "Checking for sse support ... $_sse" +echo "Checking for mtrr support ... $_mtrr" +echo "Screen size ... ${_x}x${_y}" +echo "Checking for X11 libs ... $_x11libdir" +echo "Checking mga_vid device ... $_mga" +echo "Checking for xmga ... $_xmga" +echo "Checking for SDL ... $_sdl" +echo "Checking for OpenGL ... $_gl" +echo "Checking for Xv ... $_xv" +echo "Checking for X11 ... $_x11" + +# write conf files. + +if [ $_gl = yes ]; then + _gllib='-lGL' +fi + +if [ $_x11 = yes ]; then + _x11lib='-lX11 -lXext' +fi + +if [ $_xv = yes ]; then + _xvlib='-lXv' +fi + +if [ $_sdl = yes ]; then + _sdllib='-lSDL -lpthread' +fi + +if [ "$_termcap" = "yes" ]; then + _termcap='#define USE_TERMCAP' + _libtermcap='-ltermcap' +else + _termcap='#undef USE_TERMCAP' + _libtermcap='' +fi + +if [ "$_xmmp" = "yes" ]; then + _xmmpaudio='#define USE_XMMP_AUDIO' + _xmmplibs='-Llibxmm -lxmm' +else + _xmmpaudio='#undef USE_XMMP_AUDIO' +fi + +if [ "$_lirc" = "yes" ]; then + _lircdefs='#define HAVE_LIRC' + _lirclibs='-llirc_client' +else + _lircdefs='#undef HAVE_LIRC' + _lirclibs='' +fi + + +echo +echo "Creating $MCONF" +cat > $MCONF << EOF + +# -------- Generated by ./configure ----------- + +AR=ar +CC=gcc +# OPTFLAGS=-O4 -march=$proc -mcpu=$proc -pipe -fomit-frame-pointer -ffast-math +OPTFLAGS=-O4 -march=$proc -mcpu=$proc -pipe -ffast-math +# LIBS=-L/usr/lib -L/usr/local/lib $_x11libdir $_gllib $_sdllib $_x11lib $_xvlib +X_LIBS=$_x11libdir $_gllib $_sdllib $_x11lib $_xvlib +TERMCAP_LIB=$_libtermcap +XMM_LIBS = $_xmmplibs +LIRC_LIBS = $_lirclibs +WIN32_PATH=-DWIN32_PATH=\"$_win32libdir\" + +EOF +# echo 'CFLAGS=$(OPTFLAGS) -Wall -DMPG12PLAY' >> config.mak + +echo "Creating $CCONF" + +if [ "$_mmx" = "yes" ]; then + _mmx='#define HAVE_MMX' +else + _mmx='#undef HAVE_MMX' +fi + +if [ $_3dnow = yes ]; then + _3dnowm='#define HAVE_3DNOW' +else + _3dnowm='#undef HAVE_3DNOW' +fi + +if [ $_sse = yes ]; then + _ssem='#define HAVE_SSE' +else + _ssem='#undef HAVE_SSE' +fi + +# --- + +_vosrc='' + +if [ $_mlib = yes ]; then + _mlib='#define HAVE_MLIB' + _vosrc=$_vosrc' yuv2rgb_mlib.c' +else + _mlib='#undef HAVE_MLIB' +fi + +# --- + +if [ $_gl = yes ]; then + _gl='#define HAVE_GL' + _vosrc=$_vosrc' vo_gl.c' +else + _gl='#undef HAVE_GL' +fi + +if [ $_sdl = yes ]; then + _sdldef='#define HAVE_SDL' + _vosrc=$_vosrc' vo_sdl.c' +else + _sdldef='#undef HAVE_SDL' +fi + +if [ $_x11 = yes ]; then + _x11='#define HAVE_X11' + _vosrc=$_vosrc' vo_x11.c' +else + _x11='#undef HAVE_X11' +fi + +if [ $_xv = yes ]; then + _xv='#define HAVE_XV' + _vosrc=$_vosrc' vo_xv.c' +else + _xv='#undef HAVE_XV' +fi + +# --- + +if [ $_mga = yes ]; then + _mga='#define HAVE_MGA' + _vosrc=$_vosrc' vo_mga.c' +else + _mga='#undef HAVE_MGA' +fi +if [ $_xmga = yes ]; then + _vosrc=$_vosrc' vo_xmga.c' +fi + +if [ $_syncfb = yes ]; then + _syncfb='#define HAVE_SYNCFB' + _vosrc=$_vosrc' vo_syncfb.c' +else + _syncfb='#undef HAVE_SYNCFB' +fi + +if [ $_3dfx = yes ]; then + _3dfx='#define HAVE_3DFX' + _vosrc=$_vosrc' vo_3dfx.c' +else + _3dfx='#undef HAVE_3DFX' +fi + +if [ $_mpg123 = yes ]; then + _mpg123='#define DEFAULT_MPG123' +else + _mpg123='#undef DEFAULT_MPG123' +fi + +cat > $CCONF << EOF + +/* -------- Generated by ./configure ----------- */ + +/* Define this to enable avg. byte/sec-based AVI sync method by default: + (use -bps or -nobps commandline option for run-time method selection) */ +#undef AVI_SYNC_BPS + +/* Undefine this if you want soundcard-only timing by default: + You can still change this with the -alsa or -noalsa command-line option! + (This function was originally impemented to solve ALSA driver's big + buffer problems, but it seems to be useful for every soundcard drivers) */ +#define ALSA_TIMER + +/* Undefine this if your soundcard driver has no working select(). + If you have kernel Oops, player hangups, or just no audio, you should + try to recompile MPlayer with this option disabled! */ +#define HAVE_AUDIO_SELECT + +/* You have a choice for MP3 decoding: mp3lib(mpg123) or Win32(l3codeca.acm) + #define this if you prefer mpg123 (with 3Dnow! support) than l3codeca.acm + (with mmx/sse optimizations) + You can still change it runtime using -afm 1 (mpg123) or -afm 4 (l3codeca)*/ +$_mpg123 + +/* XMMP support: (test code) */ +$_xmmpaudio +#define LIBDIR "/usr/local/lib" +#define PLUGINDIR LIBDIR "/xmmp/Plugins" +#define XMMP_AUDIO_DRIVER PLUGINDIR "/Sound/oss.so" + +/* LIRC (remote control, see www.lirc.org) support: */ +$_lircdefs + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #define WORDS_BIGENDIAN */ + +#define ARCH_X86 + +///////////////////////////////////////////////////////////////////////////// +// +// NOTE: Instead of modifying these here, use the --enable/--disable options +// of the ./configure script! See ./configure --help for details. +// +///////////////////////////////////////////////////////////////////////////// + +/* termcap flag for getch2.c */ +$_termcap + +/* Extension defines */ +$_mlib // available only on solaris +$_3dnowm // only define if you have 3DNOW (AMD k6-2, AMD Athlon, iDT WinChip, etc.) +$_mmx // only define if you have MMX +$_ssem // only define if you have SSE (Intel Pentium III or Celeron II) + +/* libvo options */ +#define SCREEN_SIZE_X $_x +#define SCREEN_SIZE_Y $_y +$_x11 +$_xv +$_gl +$_sdldef +$_3dfx +$_mga +$_syncfb + +#if defined(HAVE_GL)||defined(HAVE_X11)|defined(HAVE_XV) +#define X11_FULLSCREEN +#endif + +EOF + +echo "Creating libvo/config.mak" + +_voobj=`echo $_vosrc | sed -e 's/\.c/\.o/g'` + +cat > libvo/config.mak << EOF + +include ../config.mak + +OPTIONAL_SRCS=$_vosrc +OPTIONAL_OBJS=$_voobj + +EOF + +echo "Creating libac3/config.mak" + +if [ $_sse = yes ]; then + _downmixc='downmix/downmix_kni.S' + _downmixo='downmix/downmix_kni.o' +else +if [ $_binutils = yes ]; then + _downmixc='downmix/downmix_i386.S' + _downmixo='downmix/downmix_i386.o' +else +_downmixc='downmix/downmix.c' +_downmixo='downmix/downmix.o' +cat << EOF + +!!! Warning! fallback to slow downmix.c due the old binutils. +!!! Upgrade for better audio decoding performance. + +EOF +fi +fi + +cat > libac3/config.mak << EOF + +include ../config.mak + +OPTIONAL_SRCS = $_downmixc +OPTIONAL_OBJS = $_downmixo + +EOF + +echo "Creating mp3lib/config.mak" + +if [ $_3dnow = yes ]; then + _3dnowobjectsrcs='dct36_3dnow.s dct64_3dnow.s decode_3dnow.s' + _3dnowobjectobjs='dct36_3dnow.o dct64_3dnow.o decode_3dnow.o' +else + _3dnowobjectsrcs= + _3dnowobjectobjs= +fi + +cat > mp3lib/config.mak << EOF + +include ../config.mak + +OPTIONAL_SRCS = $_3dnowobjectsrcs +OPTIONAL_OBJS = $_3dnowobjectobjs + +EOF + +cat << EOF + +Config files successfully generated by ./configure ! +Please check config.h and config.mak files, tune CPU +and optimization flags if you don't like these defaults. +You can compile the program with 'make dep;make' and +install with 'make install'. Good luck! + +EOF + +if [ $_mtrr = yes ]; then + echo "Please check mtrr settings at /proc/mtrr (see DOCS/MTRR)" + echo +fi + +if [ $_sdl = no ]; then +if [ $_have_sdl = yes ]; then + echo "You have libSDL installed, but SDL support is disabled by default." + echo "If you want to compile MPlayer with SDL support, re-run ./configure" + echo "with --enable-sdl. But it's very buggy & experimental code, use it" + echo "only if you really need it! And it works(?) *ONLY* with SDL v1.1.7 !" + echo "(SDL driver is NOT supported, so do NOT report bugs relating to SDL!)" + echo +fi +fi + +if [ $_win32libdirnotify = yes ]; then + echo "Missing WIN32 codecs dir at $_win32libdir !" + echo "Make it and copy DLL files to there! (You can get them from your windows" + echo "directory or download ftp://thot.banki.hu/esp-team/linux/MPlayer/w32codec.zip" +else + echo "Ok, Win32 codecs directory at $_win32libdir already exists." +fi + diff --git a/demux_asf.c b/demux_asf.c new file mode 100644 index 0000000000..ed8532a7a1 --- /dev/null +++ b/demux_asf.c @@ -0,0 +1,268 @@ +// ASF file parser for DEMUXER v0.3 by A'rpi/ESP-team + +// based on asf file-format doc by Eugene [http://divx.euro.ru] + +//static float avi_pts_frametime=1.0f/25.0f; +//static float avi_audio_pts=0; +//static float avi_video_pts=0; + +//static int skip_video_frames=0; + +typedef struct __attribute__((packed)) { + unsigned char streamno; + unsigned char seq; + unsigned long x; + unsigned char flag; +} ASF_segmhdr_t; + + +static int demux_asf_read_packet(demuxer_t *demux,unsigned char *data,int len,int id,int seq,unsigned long time,unsigned short dur,int offs){ + int d; +// int len; + int skip; + float pts=0; + unsigned char c=0; + demux_stream_t *ds=NULL; + + if(verbose>=4) printf("demux_asf.read_packet: id=%d seq=%d len=%d\n",id,seq,len); + +#if 0 + if(demux->video->id==-1) { + demux->video->id=asf_video_id; + if(verbose) printf("ASF video ID = %d\n",demux->video->id); + } + if(demux->audio->id==-1) + if(id!=asf_video_id && id!=demux->video->id){ + demux->audio->id=id; + if(verbose) printf("ASF audio ID = %d\n",demux->audio->id); + } +#endif + + if(id==demux->audio->id){ + // audio + ds=demux->audio; + } else + if(id==demux->video->id){ + // video + ds=demux->video; + } + + if(ds){ + if(ds->asf_packet){ + if(ds->asf_seq!=seq){ + // closed segment, finalize packet: + if(ds==demux->audio) + if(asf_scrambling_h>1 && asf_scrambling_w>1) + asf_descrambling(ds->asf_packet->buffer,ds->asf_packet->len); + ds_add_packet(ds,ds->asf_packet); + ds->asf_packet=NULL; + } else { + // append data to it! + demux_packet_t* dp=ds->asf_packet; + if(dp->len!=offs && offs!=-1) printf("warning! fragment.len=%d BUT next fragment offset=%d \n",dp->len,offs); + dp->buffer=realloc(dp->buffer,dp->len+len); + memcpy(dp->buffer+dp->len,data,len); + if(verbose>=4) printf("data appended! %d+%d\n",dp->len,len); + dp->len+=len; + // we are ready now. + return 1; + } + } + // create new packet: + { demux_packet_t* dp; + if(offs>0){ + printf("warning! broken fragment, %d bytes missing \n",offs); + return 0; + } + dp=new_demux_packet(len); + memcpy(dp->buffer,data,len); + dp->pts=time*0.001f; +// if(ds==demux->video) printf("ASF time: %8d dur: %5d \n",time,dur); + dp->pos=demux->filepos; + ds->asf_packet=dp; + ds->asf_seq=seq; + // we are ready now. + return 1; + } + } + + return 0; +} + +//static int num_elementary_packets100=0; +//static int num_elementary_packets101=0; + +// return value: +// 0 = EOF or no stream found +// 1 = successfully read a packet +int demux_asf_fill_buffer(demuxer_t *demux){ +unsigned int id=0; +unsigned int len; +int skipped=0; +int max_packs=128; +int ret=0; + + demux->filepos=stream_tell(demux->stream); + if(demux->filepos>=demux->endpos){ + demux->stream->eof=1; + return 0; + } + + stream_read(demux->stream,asf_packet,(int)fileh.packetsize); + if(demux->stream->eof) return 0; // EOF + + if(asf_packet[0]==0x82){ + unsigned char flags=asf_packet[3]; + unsigned char segtype=asf_packet[4]; + unsigned char* p=&asf_packet[5]; + unsigned char* p_end=p+(int)fileh.packetsize; + unsigned long time; + unsigned short duration; + int segs=1; + unsigned char segsizetype=0x80; + int seg; + int padding=0; + int plen; + + if(verbose>1){ + int i; + for(i=0;i<16;i++) printf(" %02X",asf_packet[i]); + printf("\n"); + } + + //if(segtype!=0x5d) printf("Warning! packet[4] != 0x5d \n"); + + // Calculate packet size (plen): + if(flags&0x40){ + // Explicit (absoulte) packet size + plen=p[0]|(p[1]<<8); p+=2; + if(verbose>1)printf("Explicit packet size specified: %d \n",plen); + if(plen>fileh.packetsize) printf("Warning! plen>packetsize! (%d>%d) \n",plen,(int)fileh.packetsize); + if(flags&(8|16)){ + padding=p[0];p++; + if(flags&16){ padding|=p[0]<<8; p++;} + if(verbose)printf("Warning! explicit=%d padding=%d \n",plen,fileh.packetsize-padding); + } + } else { + // Padding (relative) size + if(flags&8){ + padding=p[0];++p; + } else + if(flags&16){ + padding=p[0]|(p[1]<<8);p+=2; + } + plen=fileh.packetsize-padding; + } + + time=*((unsigned long*)p);p+=4; + duration=*((unsigned short*)p);p+=2; + if(flags&1){ + segsizetype=p[0] & 0xC0; + segs=p[0] & 0x3F; + ++p; + } + if(verbose>=4) printf("%08X: flag=%02X segs=%d pad=%d time=%d dur=%d\n", + demux->filepos,flags,segs,padding,time,duration); + for(seg=0;seg<segs;seg++){ + //ASF_segmhdr_t* sh; + unsigned char streamno; + unsigned char seq; + int len; + unsigned long x; + unsigned char type; + unsigned long time2; + + if(p>=p_end) printf("Warning! invalid packet 1, sig11 coming soon...\n"); + + if(verbose>1){ + int i; + printf("seg %d:",seg); + for(i=0;i<16;i++) printf(" %02X",p[i]); + printf("\n"); + } + + streamno=p[0]&0x7F; + seq=p[1]; + p+=2; + + switch(segtype){ + case 0x55: + x=*((unsigned char*)p); + p++; + break; + case 0x59: + x=*((unsigned short*)p); + p+=2; + break; + case 0x5D: + x=*((unsigned long*)p); + p+=4; + break; + default: + printf("Warning! unknown segtype == 0x%2X \n",segtype); + } + + type=p[0]; p++; // 0x01: grouping 0x08: single + + switch(type){ + case 0x01: + //printf("grouping: %02X \n",p[0]); + ++p; // skip unknown byte + break; + case 0x08: + //printf("!!! obj_length = %d\n",*((unsigned long*)p)); + p+=4; + time2=*((unsigned long*)p);p+=4; + break; + default: + printf("unknown segment type: 0x%02X \n",type); + } + + if(flags&1){ + // multiple segments + if(segsizetype==0x40){ + len=*((unsigned char*)p);p++; // 1 byte + } else { + len=*((unsigned short*)p);p+=2; // 2 byte + } + } else { + // single segment + len=plen-(p-asf_packet); + } + if(len<0 || (p+len)>=p_end){ + printf("ASF_parser: warning! segment len=%d\n",len); + } + if(verbose>=4) printf(" seg #%d: streamno=%d seq=%d type=%02X len=%d\n",seg,streamno,seq,type,len); + + switch(type){ + case 0x01: + // GROUPING: + //printf("ASF_parser: warning! grouping (flag=1) not yet supported!\n",len); + //printf(" total: %d \n",len); + while(len>0){ + int len2=p[0]; + p++; + //printf(" group part: %d bytes\n",len2); + demux_asf_read_packet(demux,p,len2,streamno,seq,x,duration,-1); + p+=len2; + len-=len2+1; + } + if(len!=0){ + printf("ASF_parser: warning! groups total != len\n"); + } + break; + case 0x08: + // NO GROUPING: + //printf("fragment offset: %d \n",sh->x); + demux_asf_read_packet(demux,p,len,streamno,seq,time2,duration,x); + p+=len; + break; + } + + } // for segs + return 1; // success + } + + printf("%08X: UNKNOWN TYPE %02X %02X %02X %02X %02X...\n",demux->filepos,asf_packet[0],asf_packet[1],asf_packet[2],asf_packet[3],asf_packet[4]); + return 0; +} diff --git a/demux_avi.c b/demux_avi.c new file mode 100644 index 0000000000..d1f29f1ff8 --- /dev/null +++ b/demux_avi.c @@ -0,0 +1,276 @@ +// AVI file parser for DEMUXER v2.6 by A'rpi/ESP-team + +//static float avi_pts_frametime=1.0f/25.0f; +static float avi_audio_pts=0; +static float avi_video_pts=0; + +static int skip_video_frames=0; + +static inline int avi_stream_id(unsigned int id){ + unsigned char *p=(unsigned char *)&id; + unsigned char a,b; + a=p[0]-'0'; b=p[1]-'0'; + if(a>9 || b>9) return 100; // invalid ID + return a*10+b; +} + +// Select ds from ID +static inline demux_stream_t* demux_avi_select_stream(demuxer_t *demux,unsigned int id){ + int stream_id=avi_stream_id(id); + if(stream_id==demux->audio->id) return demux->audio; + if(stream_id==demux->video->id) return demux->video; + if(id!=mmioFOURCC('J','U','N','K')){ + // unknown + if(verbose>=2) printf("Unknown chunk: %.4s (%X)\n",&id,id); + } + return NULL; +} + +static int demux_avi_read_packet(demuxer_t *demux,unsigned int id,unsigned int len,int idxpos){ + int d; +// int len; + int skip; + float pts=0; + unsigned char c=0; + demux_stream_t *ds=demux_avi_select_stream(demux,id); + + if(verbose>=3) printf("demux_avi.read_packet: %X\n",id); + + if(ds==demux->audio){ + pts=avi_audio_pts; + avi_audio_pts=0; + } else + if(ds==demux->video){ + // video + if(skip_video_frames>0){ + // drop frame (seeking) + --skip_video_frames; + ds=NULL; + } else { + pts=avi_video_pts; + } + // ezt a 2 sort lehet hogy fell kell majd cserelni: + //avi_video_pts+=avi_pts_frametime; + avi_video_pts+=(float)avi_header.video.dwScale/(float)avi_header.video.dwRate; + avi_audio_pts=avi_video_pts; + } + +// len=stream_read_dword_le(demux->stream); + skip=(len+1)&(~1); // total bytes in this chunk + + if(ds){ + if(verbose>=2) printf("DEMUX_AVI: Read %d data bytes from packet %04X\n",len,id); + ds_read_packet(ds,demux->stream,len,pts,idxpos); + skip-=len; + } + if(skip){ + if(verbose>=2) printf("DEMUX_AVI: Skipping %d bytes from packet %04X\n",skip,id); + stream_skip(demux->stream,skip); + } + return ds?1:0; +} + +//static int num_elementary_packets100=0; +//static int num_elementary_packets101=0; + +// return value: +// 0 = EOF or no stream found +// 1 = successfully read a packet +int demux_avi_fill_buffer(demuxer_t *demux){ +unsigned int id=0; +unsigned int len; +int skipped=0; +int max_packs=128; +int ret=0; + +do{ + AVIINDEXENTRY *idx=NULL; + demux->filepos=stream_tell(demux->stream); + if(demux->filepos>=demux->endpos){ + demux->stream->eof=1; + return 0; + } + if(stream_eof(demux->stream)) return 0; + if(avi_header.idx_size>0 && avi_header.idx_pos<avi_header.idx_size){ + unsigned int pos; + + //if(avi_header.idx_pos<0) printf("Fatal! idx_pos=%d\n",avi_header.idx_pos); + + idx=&avi_header.idx[avi_header.idx_pos++]; + + //printf("[%d]",avi_header.idx_pos);fflush(stdout); + + //stream_seek(demux->stream,idx.dwChunkOffset); + //printf("IDX pos=%X idx.pos=%X idx.size=%X idx.flags=%X\n",demux->filepos, + // pos-4,idx->dwChunkLength,idx->dwFlags); + if(idx->dwFlags&AVIIF_LIST){ + // LIST + continue; + } + if(!demux_avi_select_stream(demux,idx->ckid)){ + if(verbose>2) printf("Skip chunk %.4s (0x%X) \n",&idx->ckid,idx->ckid); + continue; // skip this chunk + } + + pos=idx->dwChunkOffset+avi_header.idx_offset; + if(pos<avi_header.movi_start || pos>=avi_header.movi_end){ + printf("ChunkOffset out of range! current=0x%X idx=0x%X \n",demux->filepos,pos); + continue; + } +#if 0 + if(pos!=demux->filepos){ + printf("Warning! pos=0x%X idx.pos=0x%X diff=%d \n",demux->filepos,pos,pos-demux->filepos); + } +#endif + stream_seek(demux->stream,pos); + id=stream_read_dword_le(demux->stream); + if(id!=idx->ckid){ + printf("ChunkID mismatch! raw=%.4s idx=%.4s \n",&id,&idx->ckid); + continue; + } + len=stream_read_dword_le(demux->stream); +// if((len&(~1))!=(idx->dwChunkLength&(~1))){ +// if((len)!=(idx->dwChunkLength)){ + if((len!=idx->dwChunkLength)&&((len+1)!=idx->dwChunkLength)){ + printf("ChunkSize mismatch! raw=%d idx=%d \n",len,idx->dwChunkLength); + continue; + } + } else { + id=stream_read_dword_le(demux->stream); + len=stream_read_dword_le(demux->stream); + if(id==mmioFOURCC('L','I','S','T')){ + id=stream_read_dword_le(demux->stream); // list type + continue; + } + } + ret=demux_avi_read_packet(demux,id,len,avi_header.idx_pos-1); + if(!ret && skip_video_frames<=0) + if(--max_packs==0){ + demux->stream->eof=1; + printf("demux: file doesn't contain the selected audio or video stream\n"); + return 0; + } +} while(ret!=1); + return 1; +} + + +// return value: +// 0 = EOF or no stream found +// 1 = successfully read a packet +int demux_avi_fill_buffer_ni(demuxer_t *demux,demux_stream_t* ds){ +unsigned int id=0; +unsigned int len; +int skipped=0; +int max_packs=128; +int ret=0; + +do{ + AVIINDEXENTRY *idx=NULL; + int idx_pos=0; + demux->filepos=stream_tell(demux->stream); + + if(ds==demux->video) idx_pos=avi_header.idx_pos_a++; else + if(ds==demux->audio) idx_pos=avi_header.idx_pos_v++; else + idx_pos=avi_header.idx_pos++; + + if(avi_header.idx_size>0 && idx_pos<avi_header.idx_size){ + unsigned int pos; + idx=&avi_header.idx[idx_pos]; + + if(idx->dwFlags&AVIIF_LIST){ + // LIST + continue; + } + if(ds && demux_avi_select_stream(demux,idx->ckid)!=ds){ + if(verbose>2) printf("Skip chunk %.4s (0x%X) \n",&idx->ckid,idx->ckid); + continue; // skip this chunk + } + + pos=idx->dwChunkOffset+avi_header.idx_offset; + if(pos<avi_header.movi_start || pos>=avi_header.movi_end){ + printf("ChunkOffset out of range! current=0x%X idx=0x%X \n",demux->filepos,pos); + continue; + } +#if 0 + if(pos!=demux->filepos){ + printf("Warning! pos=0x%X idx.pos=0x%X diff=%d \n",demux->filepos,pos,pos-demux->filepos); + } +#endif + stream_seek(demux->stream,pos); + + id=stream_read_dword_le(demux->stream); + + if(stream_eof(demux->stream)) return 0; + + if(id!=idx->ckid){ + printf("ChunkID mismatch! raw=%.4s idx=%.4s \n",&id,&idx->ckid); + continue; + } + len=stream_read_dword_le(demux->stream); +// if((len&(~1))!=(idx->dwChunkLength&(~1))){ +// if((len)!=(idx->dwChunkLength)){ + if((len!=idx->dwChunkLength)&&((len+1)!=idx->dwChunkLength)){ + printf("ChunkSize mismatch! raw=%d idx=%d \n",len,idx->dwChunkLength); + continue; + } + } else return 0; + ret=demux_avi_read_packet(demux,id,len,idx_pos); + if(!ret && skip_video_frames<=0) + if(--max_packs==0){ + demux->stream->eof=1; + printf("demux: file doesn't contain the selected audio or video stream\n"); + return 0; + } +} while(ret!=1); + return 1; +} + + +// return value: +// 0 = EOF or no stream found +// 1 = successfully read a packet +int demux_avi_fill_buffer_nini(demuxer_t *demux,demux_stream_t* ds){ +unsigned int id=0; +unsigned int len; +int skipped=0; +int ret=0; +int *fpos=NULL; + + if(ds==demux->video) fpos=&avi_header.idx_pos_a; else + if(ds==demux->audio) fpos=&avi_header.idx_pos_v; else + return 0; + + stream_seek(demux->stream,fpos[0]); + +do{ + + demux->filepos=stream_tell(demux->stream); + if(demux->filepos>=demux->endpos){ + demux->stream->eof=1; + return 0; + } + if(stream_eof(demux->stream)) return 0; + + id=stream_read_dword_le(demux->stream); + len=stream_read_dword_le(demux->stream); + if(id==mmioFOURCC('L','I','S','T')){ + id=stream_read_dword_le(demux->stream); // list type + continue; + } + + if(ds==demux_avi_select_stream(demux,id)){ + // read it! + ret=demux_avi_read_packet(demux,id,len,avi_header.idx_pos-1); + } else { + // skip it! + int skip=(len+1)&(~1); // total bytes in this chunk + stream_skip(demux->stream,skip); + } + +} while(ret!=1); + fpos[0]=stream_tell(demux->stream); + return 1; +} + + diff --git a/demux_mpg.c b/demux_mpg.c new file mode 100644 index 0000000000..f276541727 --- /dev/null +++ b/demux_mpg.c @@ -0,0 +1,228 @@ +// MPG/VOB file parser for DEMUXER v2.5 by A'rpi/ESP-team + +static unsigned int read_mpeg_timestamp(stream_t *s,int c){ + int d,e; + unsigned int pts; + d=stream_read_word(s); + e=stream_read_word(s); + if( ((c&1)!=1) || ((d&1)!=1) || ((e&1)!=1) ) return 0; // invalid pts + pts=(((c>>1)&7)<<30)|((d>>1)<<15)|(e>>1); + if(verbose>=3) printf("{%d}",pts); + return pts; +} + +static char dvdaudio_table[256]; +//static unsigned int packet_start_pos=0; + +static int demux_mpg_read_packet(demuxer_t *demux,int id){ + int d; + int len; + unsigned char c=0; + unsigned int pts=0; + unsigned int dts=0; + demux_stream_t *ds=NULL; + + if(verbose>=3) printf("demux_read_packet: %X\n",id); + +// if(id==0x1BA) packet_start_pos=stream_tell(demux->stream); + if(id<0x1BC || id>0x1FF) return -1; + if(id==0x1BE) return -1; // padding stream + if(id==0x1BF) return -1; // private2 + + len=stream_read_word(demux->stream); + if(verbose>=3) printf("PACKET len=%d",len); + if(len==0 || len>4096) return -2; // invalid packet !!!!!! + + while(len>0){ // Skip stuFFing bytes + c=stream_read_char(demux->stream);--len; + if(c!=0xFF)break; + } + if((c>>6)==1){ // Read (skip) STD scale & size value +// printf(" STD_scale=%d",(c>>5)&1); + d=((c&0x1F)<<8)|stream_read_char(demux->stream); + len-=2; +// printf(" STD_size=%d",d); + c=stream_read_char(demux->stream); + } + // Read System-1 stream timestamps: + if((c>>4)==2){ + pts=read_mpeg_timestamp(demux->stream,c); + len-=4; + } else + if((c>>4)==3){ + pts=read_mpeg_timestamp(demux->stream,c); + c=stream_read_char(demux->stream); + if((c>>4)!=1) pts=0; //printf("{ERROR4}"); + dts=read_mpeg_timestamp(demux->stream,c); + len-=4+1+4; + } else + if((c>>6)==2){ + int pts_flags; + int hdrlen; + // System-2 (.VOB) stream: + if((c>>4)&3) printf("Warning! Encrypted VOB file! (DeCSS not (yet) supported)\n"); + c=stream_read_char(demux->stream); pts_flags=c>>6; + c=stream_read_char(demux->stream); hdrlen=c; + len-=2; + if(verbose>=3) printf(" hdrlen=%d (len=%d)",hdrlen,len); + if(hdrlen>len) return -1; // invalid header length + if(pts_flags==2){ + c=stream_read_char(demux->stream); + pts=read_mpeg_timestamp(demux->stream,c); + len-=5;hdrlen-=5; + } else + if(pts_flags==3){ + c=stream_read_char(demux->stream); + pts=read_mpeg_timestamp(demux->stream,c); + c=stream_read_char(demux->stream); + dts=read_mpeg_timestamp(demux->stream,c); + len-=10;hdrlen-=10; + } + len-=hdrlen; + if(hdrlen>0) stream_skip(demux->stream,hdrlen); // skip header bytes + + //============== DVD Audio sub-stream ====================== + if(id==0x1BD){ + int aid=stream_read_char(demux->stream)&0x7F;--len; + ds=demux->audio; + if(ds->id==-1) ds->id=aid; + if(!dvdaudio_table[aid]){ + dvdaudio_table[aid]=1; + printf("DVD Audio format: %s ID=%d%s\n", + ((aid&0x70)==0x20)?"PCM":"AC3",aid,(ds->id==aid)?" CURRENT":""); + } + if(len<3) return -1; // invalid audio packet + if(ds->id!=aid){ + // drop packet (not selected channel) + ds=NULL; + } else { + // READ Packet: Skip additional audio header data: + c=stream_read_char(demux->stream); + c=stream_read_char(demux->stream); + c=stream_read_char(demux->stream); + len-=3; + if(ds->type==-1){ + // autodetect type + ds->type=((aid&0x70)==0x20)?2:3; + } + if(ds->type==2 && len>=2){ + // read PCM header + int head; + head=stream_read_char(demux->stream); head=c<<8; + c=stream_read_char(demux->stream); head|=c; len-=2; + while(len>0 && head!=0x180){ + head=c<<8; + c=stream_read_char(demux->stream); + head|=c;--len; + } + if(!len) printf("End of packet while searching for PCM header\n"); + } + } + } + + } else { + //if(c!=0x0f) printf(" {ERROR5,c=%d} \n",c); + } + if(verbose>=3) printf("\n"); + + if(len<=0 || len>4096) return -1; // Invalid packet size + + if(id>=0x1C0 && id<=0x1DF){ + // mpeg audio + int aid=id-0x1C0; + if(demux->audio->id==-1) demux->audio->id=aid; + if(demux->audio->id==aid){ + ds=demux->audio; + if(ds->type==-1) ds->type=1; + } + } else + if(id>=0x1E0 && id<=0x1EF){ + // mpeg video + int aid=id-0x1E0; + if(demux->video->id==-1) demux->video->id=aid; + if(demux->video->id==aid) ds=demux->video; + } + + if(ds){ + if(verbose>=2) printf("DEMUX_MPG: Read %d data bytes from packet %04X\n",len,id); +// printf("packet start = 0x%X \n",stream_tell(demux->stream)-packet_start_pos); + ds_read_packet(ds,demux->stream,len,pts/90000.0f,0); + return 1; + } + if(verbose>=2) printf("DEMUX_MPG: Skipping %d data bytes from packet %04X\n",len,id); + stream_skip(demux->stream,len); + return 0; +} + +static int num_elementary_packets100=0; +static int num_elementary_packets101=0; + +int demux_mpg_es_fill_buffer(demuxer_t *demux){ +//if(demux->type==DEMUXER_TYPE_MPEG_ES) + // Elementary video stream + if(demux->stream->eof) return 0; + demux->filepos=stream_tell(demux->stream); + ds_read_packet(demux->video,demux->stream,4096,0,0); + return 1; +} + +int demux_mpg_fill_buffer(demuxer_t *demux){ +unsigned int head=0; +int skipped=0; +int max_packs=128; +int ret=0; + +// System stream +do{ + demux->filepos=stream_tell(demux->stream); + head=stream_read_dword(demux->stream); + while((head&0xffffff00)!=0x00000100){ + if(stream_eof(demux->stream)) break; + head=(head<<8)|stream_read_char(demux->stream); + ++skipped; ++demux->filepos; + } + if(stream_eof(demux->stream)) break; + // sure: head=0x000001XX + if(demux->synced==0){ + if(head==0x1BA) demux->synced=1; + } else + if(demux->synced==1){ + if(head==0x1BB || (head>=0x1C0 && head<=0x1EF)){ + demux->synced=2; + if(verbose) printf("system stream synced at 0x%X (%d)!\n",demux->filepos,demux->filepos); + } else demux->synced=0; + } // else + if(demux->synced==2){ + ret=demux_mpg_read_packet(demux,head); + if(!ret) + if(--max_packs==0){ + demux->stream->eof=1; + printf("demux: file doesn't contain the selected audio or video stream\n"); + return 0; + } + } else { + if(head>=0x100 && head<0x1B0){ + if(head==0x100) + ++num_elementary_packets100; + else + if(head==0x101) ++num_elementary_packets101; + if(verbose>=3) printf("Opps... elementary video packet found: %03X\n",head); + } +#if 1 + if(num_elementary_packets100>50 && num_elementary_packets101>50 + && skipped>4000000){ + if(verbose) printf("sync_mpeg_ps: seems to be ES stream...\n"); + demux->stream->eof=1; + break; + } +#endif + } +} while(ret!=1); + if(verbose>=2) printf("demux: %d bad bytes skipped\n",skipped); + if(demux->stream->eof){ + if(verbose>=2) printf("MPEG Stream reached EOF\n"); + return 0; + } + return 1; +} + diff --git a/demuxer.c b/demuxer.c new file mode 100644 index 0000000000..54d0314c14 --- /dev/null +++ b/demuxer.c @@ -0,0 +1,285 @@ +//=================== DEMUXER v2.5 ========================= + +#define MAX_PACKS 2048 +#define MAX_PACK_BYTES 0x400000 + +typedef struct demux_packet_st { + int len; + float pts; + int pos; // pozicio indexben (AVI) ill. fileban (MPG) + unsigned char* buffer; + struct demux_packet_st* next; +} demux_packet_t; + +inline demux_packet_t* new_demux_packet(int len){ + demux_packet_t* dp=malloc(sizeof(demux_packet_t)); + dp->len=len; + dp->buffer=malloc(len); + dp->next=NULL; + dp->pts=0; + dp->pos=0; + return dp; +} + +inline void free_demux_packet(demux_packet_t* dp){ + free(dp->buffer); + free(dp); +} + +typedef struct { + int buffer_pos; // current buffer position + int buffer_size; // current buffer size + unsigned char* buffer; // current buffer + float pts; // current buffer's pts + int eof; // end of demuxed stream? (true if all buffer empty) + int pos; // position in the input stream (file) + int dpos; // position in the demuxed stream +//--------------- + int packs; // number of packets in buffer + int bytes; // total bytes of packets in buffer + demux_packet_t *first; // read to current buffer from here + demux_packet_t *last; // append new packets from input stream to here + int id; // stream ID (for multiple audio/video streams) + int type; // stream type (currently used only for audio) + struct demuxer_st *demuxer; // parent demuxer structure (stream handler) +// ---- asf ----- + demux_packet_t *asf_packet; // read asf fragments here + int asf_seq; +} demux_stream_t; + +demux_stream_t* new_demuxer_stream(struct demuxer_st *demuxer,int id){ + demux_stream_t* ds=malloc(sizeof(demux_stream_t)); + ds->buffer_pos=ds->buffer_size=0; + ds->buffer=NULL; + ds->pts=0; + ds->eof=0; + ds->pos=0; + ds->dpos=0; +//--------------- + ds->packs=0; + ds->bytes=0; + ds->first=ds->last=NULL; + ds->id=id; + ds->type=-1; + ds->demuxer=demuxer; +//---------------- + ds->asf_seq=-1; + ds->asf_packet=NULL; + return ds; +} + +#define DEMUXER_TYPE_UNKNOWN 0 +#define DEMUXER_TYPE_MPEG_ES 1 +#define DEMUXER_TYPE_MPEG_PS 2 +#define DEMUXER_TYPE_AVI 3 +#define DEMUXER_TYPE_AVI_NI 4 +#define DEMUXER_TYPE_AVI_NINI 5 +#define DEMUXER_TYPE_ASF 6 + +#define DEMUXER_TIME_NONE 0 +#define DEMUXER_TIME_PTS 1 +#define DEMUXER_TIME_FILE 2 +#define DEMUXER_TIME_BPS 3 + +typedef struct demuxer_st { + stream_t *stream; + int synced; // stream synced (used by mpeg) + int filepos; // input stream current pos. + int endpos; // input stream end pos. (return EOF fi filepos>endpos) + int type; // mpeg system stream, mpeg elementary s., avi raw, avi indexed +// int time_src;// time source (pts/file/bps) + demux_stream_t *audio; + demux_stream_t *video; +} demuxer_t; + +demuxer_t* new_demuxer(stream_t *stream,int type,int a_id,int v_id){ + demuxer_t *d=malloc(sizeof(demuxer_t)); + d->stream=stream; + d->synced=0; + d->filepos=0; + d->audio=new_demuxer_stream(d,a_id); + d->video=new_demuxer_stream(d,v_id); + d->type=type; + return d; +} + +static void ds_add_packet(demux_stream_t *ds,demux_packet_t* dp){ +// demux_packet_t* dp=new_demux_packet(len); +// stream_read(stream,dp->buffer,len); +// dp->pts=pts; //(float)pts/90000.0f; +// dp->pos=pos; + // append packet to DS stream: + ++ds->packs; + ds->bytes+=dp->len; + if(ds->last){ + // next packet in stream + ds->last->next=dp; + ds->last=dp; + } else { + // first packet in stream + ds->first=ds->last=dp; + } + if(verbose>=2) + printf("DEMUX: Append packet to %s, len=%d pts=%5.3f pos=%d [packs: A=%d V=%d]\n", + (ds==ds->demuxer->audio)?"d_audio":"d_video", + dp->len,dp->pts,dp->pos,ds->demuxer->audio->packs,ds->demuxer->video->packs); +} + +static void ds_read_packet(demux_stream_t *ds,stream_t *stream,int len,float pts,int pos){ + demux_packet_t* dp=new_demux_packet(len); + stream_read(stream,dp->buffer,len); + dp->pts=pts; //(float)pts/90000.0f; + dp->pos=pos; + // append packet to DS stream: + ds_add_packet(ds,dp); +} + + +// return value: +// 0 = EOF or no stream found or invalid type +// 1 = successfully read a packet +int demux_mpg_es_fill_buffer(demuxer_t *demux); +int demux_mpg_fill_buffer(demuxer_t *demux); +int demux_avi_fill_buffer(demuxer_t *demux); +int demux_avi_fill_buffer_ni(demuxer_t *demux,demux_stream_t *ds); +int demux_avi_fill_buffer_nini(demuxer_t *demux,demux_stream_t *ds); +int demux_asf_fill_buffer(demuxer_t *demux); + +int demux_fill_buffer(demuxer_t *demux,demux_stream_t *ds){ + // Note: parameter 'ds' can be NULL! + switch(demux->type){ + case DEMUXER_TYPE_MPEG_ES: return demux_mpg_es_fill_buffer(demux); + case DEMUXER_TYPE_MPEG_PS: return demux_mpg_fill_buffer(demux); + case DEMUXER_TYPE_AVI: return demux_avi_fill_buffer(demux); + case DEMUXER_TYPE_AVI_NI: return demux_avi_fill_buffer_ni(demux,ds); + case DEMUXER_TYPE_AVI_NINI: return demux_avi_fill_buffer_nini(demux,ds); + case DEMUXER_TYPE_ASF: return demux_asf_fill_buffer(demux); + } + return 0; +} + +// return value: +// 0 = EOF +// 1 = succesfull +inline static int ds_fill_buffer(demux_stream_t *ds){ + demuxer_t *demux=ds->demuxer; + if(ds->buffer) free(ds->buffer); + if(verbose>2){ + if(ds==demux->audio) printf("ds_fill_buffer(d_audio) called\n");else + if(ds==demux->video) printf("ds_fill_buffer(d_video) called\n");else + printf("ds_fill_buffer(unknown 0x%X) called\n",ds); + } + while(1){ + if(ds->packs){ + demux_packet_t *p=ds->first; + // copy useful data: + ds->buffer=p->buffer; + ds->buffer_pos=0; + ds->buffer_size=p->len; + ds->pos=p->pos; + ds->dpos+=p->len; // !!! + ds->pts=p->pts; + // free packet: + ds->bytes-=p->len; + ds->first=p->next; + if(!ds->first) ds->last=NULL; + free(p); + --ds->packs; + return 1; //ds->buffer_size; + } + if(demux->audio->packs>=MAX_PACKS || demux->audio->bytes>=MAX_PACK_BYTES){ + printf("\nDEMUXER: Too many (%d in %d bytes) audio packets in the buffer!\n",demux->audio->packs,demux->audio->bytes); + printf("(maybe you play a non-interleaved stream/file or audio codec failed)\n"); + break; + } + if(demux->video->packs>=MAX_PACKS || demux->video->bytes>=MAX_PACK_BYTES){ + printf("\nDEMUXER: Too many (%d in %d bytes) video packets in the buffer!\n",demux->video->packs,demux->video->bytes); + printf("(maybe you play a non-interleaved stream/file or video codec failed)\n"); + break; + } + if(!demux_fill_buffer(demux,ds)) break; // EOF + } + ds->buffer_pos=ds->buffer_size=0; + ds->buffer=NULL; + if(verbose) printf("ds_fill_buffer: EOF reached (stream: %s) \n",ds==demux->audio?"audio":"video"); + ds->eof=1; + return 0; +} + +inline int ds_tell(demux_stream_t *ds){ + return (ds->dpos-ds->buffer_size)+ds->buffer_pos; +} + +int demux_read_data(demux_stream_t *ds,char* mem,int len){ +int x; +int bytes=0; +while(len>0){ + x=ds->buffer_size-ds->buffer_pos; + if(x==0){ + if(!ds_fill_buffer(ds)) return bytes; + } else { + if(x>len) x=len; + if(mem) memcpy(mem+bytes,&ds->buffer[ds->buffer_pos],x); + bytes+=x;len-=x;ds->buffer_pos+=x; + } +} +return bytes; +} + + +#if 1 +#define demux_getc(ds) (\ + (ds->buffer_pos<ds->buffer_size) ? ds->buffer[ds->buffer_pos++] \ + :((!ds_fill_buffer(ds))? (-1) : ds->buffer[ds->buffer_pos++] ) ) +#else +inline static int demux_getc(demux_stream_t *ds){ + if(ds->buffer_pos>=ds->buffer_size){ + if(!ds_fill_buffer(ds)){ +// printf("DEMUX_GETC: EOF reached!\n"); + return -1; // EOF + } + } +// printf("[%02X]",ds->buffer[ds->buffer_pos]); + return ds->buffer[ds->buffer_pos++]; +} +#endif + +void ds_free_packs(demux_stream_t *ds){ + demux_packet_t *dp=ds->first; + while(dp){ + demux_packet_t *dn=dp->next; + free(dp->buffer); + free(dp); + dp=dn; + } + if(ds->asf_packet){ + // free unfinished .asf fragments: + free(ds->asf_packet->buffer); + free(ds->asf_packet); + ds->asf_packet=NULL; + } + ds->first=ds->last=NULL; + ds->packs=0; // !!!!! + ds->bytes=0; + if(ds->buffer) free(ds->buffer); + ds->buffer=NULL; + ds->buffer_pos=ds->buffer_size; + ds->pts=0; +} + +int ds_get_packet(demux_stream_t *ds,char **start){ + while(1){ + int len; + if(ds->buffer_pos>=ds->buffer_size){ + if(!ds_fill_buffer(ds)){ + // EOF + *start = NULL; + return -1; + } + } + len=ds->buffer_size-ds->buffer_pos; + *start = &ds->buffer[ds->buffer_pos]; + ds->buffer_pos+=len; + return len; + } +} diff --git a/dll_init.c b/dll_init.c new file mode 100644 index 0000000000..dac4e12d9d --- /dev/null +++ b/dll_init.c @@ -0,0 +1,164 @@ +// ACM audio and VfW video codecs initialization +// based on the avifile library [http://divx.euro.ru] + +int init_audio_codec(){ + HRESULT ret; + WAVEFORMATEX *in_fmt=(WAVEFORMATEX*)&avi_header.wf_ext; + unsigned long srcsize=0; + + if(verbose) printf("======= Win32 (ACM) AUDIO Codec init =======\n"); + + avi_header.srcstream=NULL; + +// if(in_fmt->nSamplesPerSec==0){ printf("Bad WAVE header!\n");exit(1); } +// MSACM_RegisterAllDrivers(); + + avi_header.wf.nChannels=in_fmt->nChannels; + avi_header.wf.nSamplesPerSec=in_fmt->nSamplesPerSec; + avi_header.wf.nAvgBytesPerSec=2*avi_header.wf.nSamplesPerSec*avi_header.wf.nChannels; + avi_header.wf.wFormatTag=WAVE_FORMAT_PCM; + avi_header.wf.nBlockAlign=2*in_fmt->nChannels; + avi_header.wf.wBitsPerSample=16; + avi_header.wf.cbSize=0; + + win32_codec_name = avi_header.audio_codec; + ret=acmStreamOpen(&avi_header.srcstream,(HACMDRIVER)NULL, + in_fmt,&avi_header.wf, + NULL,0,0,0); + if(ret){ + if(ret==ACMERR_NOTPOSSIBLE) + printf("ACM_Decoder: Unappropriate audio format\n"); + else + printf("ACM_Decoder: acmStreamOpen error %d", ret); + avi_header.srcstream=NULL; + return 0; + } + if(verbose) printf("Audio codec opened OK! ;-)\n"); + + srcsize=in_fmt->nBlockAlign; + acmStreamSize(avi_header.srcstream, srcsize, &srcsize, ACM_STREAMSIZEF_SOURCE); + if(srcsize<OUTBURST) srcsize=OUTBURST; + avi_header.audio_out_minsize=srcsize; // audio output min. size + if(verbose) printf("Audio ACM output buffer min. size: %d\n",srcsize); + + acmStreamSize(avi_header.srcstream, srcsize, &srcsize, ACM_STREAMSIZEF_DESTINATION); + avi_header.audio_in_minsize=srcsize; // audio input min. size + if(verbose) printf("Audio ACM input buffer min. size: %d\n",srcsize); + + return 1; +} + + +int init_video_codec(int outfmt){ + HRESULT ret; + + if(verbose) printf("======= Win32 (VFW) VIDEO Codec init =======\n"); + + memset(&avi_header.o_bih, 0, sizeof(BITMAPINFOHEADER)); + avi_header.o_bih.biSize = sizeof(BITMAPINFOHEADER); + + win32_codec_name = avi_header.video_codec; + avi_header.hic = ICOpen( 0x63646976, avi_header.bih.biCompression, ICMODE_FASTDECOMPRESS); +// avi_header.hic = ICOpen( 0x63646976, avi_header.bih.biCompression, ICMODE_DECOMPRESS); + if(!avi_header.hic){ + printf("ICOpen failed! unknown codec / wrong parameters?\n"); + return 0; + } + +// avi_header.bih.biBitCount=32; + + ret = ICDecompressGetFormat(avi_header.hic, &avi_header.bih, &avi_header.o_bih); + if(ret){ + printf("ICDecompressGetFormat failed: Error %d\n", ret); + return 0; + } + if(verbose) printf("ICDecompressGetFormat OK\n"); + +// printf("ICM_DECOMPRESS_QUERY=0x%X",ICM_DECOMPRESS_QUERY); + +// avi_header.o_bih.biWidth=avi_header.bih.biWidth; +// avi_header.o_bih.biCompression = 0x32315659; // mmioFOURCC('U','Y','V','Y'); +// ret=ICDecompressGetFormatSize(avi_header.hic,&avi_header.o_bih); +// avi_header.o_bih.biCompression = 3; //0x32315659; +// avi_header.o_bih.biCompression = mmioFOURCC('U','Y','V','Y'); +// avi_header.o_bih.biCompression = mmioFOURCC('U','Y','V','Y'); +// avi_header.o_bih.biCompression = mmioFOURCC('Y','U','Y','2'); +// avi_header.o_bih.biPlanes=3; +// avi_header.o_bih.biBitCount=16; + + if(outfmt==IMGFMT_YUY2) + avi_header.o_bih.biBitCount=16; + else + avi_header.o_bih.biBitCount=outfmt&0xFF;// //24; + + avi_header.o_bih.biSizeImage=avi_header.o_bih.biWidth*avi_header.o_bih.biHeight*(avi_header.o_bih.biBitCount/8); + + if(!avi_header.flipped) + avi_header.o_bih.biHeight=-avi_header.bih.biHeight; // flip image! + + if(outfmt==IMGFMT_YUY2 && !avi_header.yuv_hack_needed) + avi_header.o_bih.biCompression = mmioFOURCC('Y','U','Y','2'); + +// avi_header.o_bih.biCompression = mmioFOURCC('U','Y','V','Y'); + + + if(verbose) { + printf("Starting decompression, format:\n"); + printf(" biSize %d\n", avi_header.bih.biSize); + printf(" biWidth %d\n", avi_header.bih.biWidth); + printf(" biHeight %d\n", avi_header.bih.biHeight); + printf(" biPlanes %d\n", avi_header.bih.biPlanes); + printf(" biBitCount %d\n", avi_header.bih.biBitCount); + printf(" biCompression %d='%.4s'\n", avi_header.bih.biCompression, &avi_header.bih.biCompression); + printf(" biSizeImage %d\n", avi_header.bih.biSizeImage); + printf("Dest fmt:\n"); + printf(" biSize %d\n", avi_header.o_bih.biSize); + printf(" biWidth %d\n", avi_header.o_bih.biWidth); + printf(" biHeight %d\n", avi_header.o_bih.biHeight); + printf(" biPlanes %d\n", avi_header.o_bih.biPlanes); + printf(" biBitCount %d\n", avi_header.o_bih.biBitCount); + printf(" biCompression %d='%.4s'\n", avi_header.o_bih.biCompression, &avi_header.o_bih.biCompression); + printf(" biSizeImage %d\n", avi_header.o_bih.biSizeImage); + } + + ret = ICDecompressQuery(avi_header.hic, &avi_header.bih, &avi_header.o_bih); + if(ret){ + printf("ICDecompressQuery failed: Error %d\n", ret); + return 0; + } + if(verbose) printf("ICDecompressQuery OK\n"); + + + ret = ICDecompressBegin(avi_header.hic, &avi_header.bih, &avi_header.o_bih); + if(ret){ + printf("ICDecompressBegin failed: Error %d\n", ret); + return 0; + } + +#if 0 + +//avi_header.hic +//ICSendMessage(HIC hic,unsigned int msg,long lParam1,long lParam2) +{ int i; + for(i=73;i<256;i++){ + printf("Calling ICM_USER+%d function...",i);fflush(stdout); + ret = ICSendMessage(avi_header.hic,ICM_USER+i,NULL,NULL); + printf(" ret=%d\n",ret); + } +} +#endif + + avi_header.our_out_buffer = malloc(avi_header.o_bih.biSizeImage); + if(!avi_header.our_out_buffer){ + printf("not enough memory for decoded picture buffer (%d bytes)\n", avi_header.o_bih.biSizeImage); + return 0; + } + + if(outfmt==IMGFMT_YUY2 && avi_header.yuv_hack_needed) + avi_header.o_bih.biCompression = mmioFOURCC('Y','U','Y','2'); + +// avi_header.our_in_buffer=malloc(avi_header.video.dwSuggestedBufferSize); // FIXME!!!! + + if(verbose) printf("VIDEO CODEC Init OK!!! ;-)\n"); + return 1; +} diff --git a/drivers/3dfx.h b/drivers/3dfx.h new file mode 100644 index 0000000000..0097f4f39e --- /dev/null +++ b/drivers/3dfx.h @@ -0,0 +1,154 @@ +/* + * 3dfx.h + * + * Copyright (C) Colin Cross Apr 2000 + * + * mpeg2dec 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. + * + * mpeg2dec 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 VOODOO_IO_REG_OFFSET ((unsigned long int)0x0000000) +#define VOODOO_YUV_REG_OFFSET ((unsigned long int)0x0080100) +#define VOODOO_AGP_REG_OFFSET ((unsigned long int)0x0080000) +#define VOODOO_2D_REG_OFFSET ((unsigned long int)0x0100000) +#define VOODOO_YUV_PLANE_OFFSET ((unsigned long int)0x0C00000) + +#define VOODOO_BLT_FORMAT_YUYV (8<<16) +#define VOODOO_BLT_FORMAT_16 (3<<16) + +#define VOODOO_YUV_STRIDE (1024>>2) + +struct voodoo_yuv_fb_t { + uint32_t Y[0x0040000]; + uint32_t U[0x0040000]; + uint32_t V[0x0040000]; +}; + +struct voodoo_yuv_reg_t { + uint32_t yuvBaseAddr; + uint32_t yuvStride; +}; + +struct voodoo_2d_reg_t { + uint32_t status; + uint32_t intCtrl; + uint32_t clip0Min; + uint32_t clip0Max; + uint32_t dstBaseAddr; + uint32_t dstFormat; + uint32_t srcColorkeyMin; + uint32_t srcColorkeyMax; + uint32_t dstColorkeyMin; + uint32_t dstColorkeyMax; + signed long bresError0; + signed long bresError1; + uint32_t rop; + uint32_t srcBaseAddr; + uint32_t commandExtra; + uint32_t lineStipple; + uint32_t lineStyle; + uint32_t pattern0Alias; + uint32_t pattern1Alias;; + uint32_t clip1Min; + uint32_t clip1Max; + uint32_t srcFormat; + uint32_t srcSize; + uint32_t srcXY; + uint32_t colorBack; + uint32_t colorFore; + uint32_t dstSize; + uint32_t dstXY; + uint32_t command; + uint32_t RESERVED1; + uint32_t RESERVED2; + uint32_t RESERVED3; + uint8_t launchArea[128]; +}; + + +struct voodoo_io_reg_t { + uint32_t status; + uint32_t pciInit0; + uint32_t sipMonitor; + uint32_t lfbMemoryConfig; + uint32_t miscInit0; + uint32_t miscInit1; + uint32_t dramInit0; + uint32_t dramInit1; + uint32_t agpInit; + uint32_t tmuGbeInit; + uint32_t vgaInit0; + uint32_t vgaInit1; + uint32_t dramCommand; + uint32_t dramData; + uint32_t RESERVED1; + uint32_t RESERVED2; + + uint32_t pllCtrl0; + uint32_t pllCtrl1; + uint32_t pllCtrl2; + uint32_t dacMode; + uint32_t dacAddr; + uint32_t dacData; + + uint32_t rgbMaxDelta; + uint32_t vidProcCfg; + uint32_t hwCurPatAddr; + uint32_t hwCurLoc; + uint32_t hwCurC0; + uint32_t hwCurC1; + uint32_t vidInFormat; + uint32_t vidInStatus; + uint32_t vidSerialParallelPort; + uint32_t vidInXDecimDeltas; + uint32_t vidInDecimInitErrs; + uint32_t vidInYDecimDeltas; + uint32_t vidPixelBufThold; + uint32_t vidChromaMin; + uint32_t vidChromaMax; + uint32_t vidCurrentLine; + uint32_t vidScreenSize; + uint32_t vidOverlayStartCoords; + uint32_t vidOverlayEndScreenCoord; + uint32_t vidOverlayDudx; + uint32_t vidOverlayDudxOffsetSrcWidth; + uint32_t vidOverlayDvdy; + + uint32_t vga_registers_not_mem_mapped[12]; + uint32_t vidOverlayDvdyOffset; + uint32_t vidDesktopStartAddr; + uint32_t vidDesktopOverlayStride; + uint32_t vidInAddr0; + uint32_t vidInAddr1; + uint32_t vidInAddr2; + uint32_t vidInStride; + uint32_t vidCurrOverlayStartAddr; +}; + + +struct pioData_t { + short port; + short size; + int device; + void *value; +}; + +typedef struct pioData_t pioData; +typedef struct voodoo_2d_reg_t voodoo_2d_reg; +typedef struct voodoo_io_reg_t voodoo_io_reg; +typedef struct voodoo_yuv_reg_t voodoo_yuv_reg; +typedef struct voodoo_yuv_fb_t voodoo_yuv_fb; + diff --git a/drivers/Makefile b/drivers/Makefile new file mode 100644 index 0000000000..67deaf85cf --- /dev/null +++ b/drivers/Makefile @@ -0,0 +1,22 @@ + +CC = gcc +KERNEL_INCLUDES = /usr/src/linux/include +INCLUDES = -I$(KERNEL_INCLUDES) +CFLAGS = -g -O2 -Wall -D__KERNEL__ -DMODULE -include $(KERNEL_INCLUDES)/linux/modversions.h + +all: mga_vid.o mga_vid_test sis_vid.o + +mga_vid.o: mga_vid.c mga_vid.h + $(CC) $(CFLAGS) $(INCLUDES) -c $(basename $@).c + +sis_vid.o: sis_vid.c sis_vid.h + $(CC) $(CFLAGS) $(INCLUDES) -c $(basename $@).c + +mga_vid_test: mga_vid_test.c + $(CC) -g -O -Wall $(INCLUDES) -o $@ $@.c + +clean: + rm -f *.o *~ + +distclean: clean + rm -f mga_vid_test diff --git a/drivers/README b/drivers/README new file mode 100644 index 0000000000..bea354f489 --- /dev/null +++ b/drivers/README @@ -0,0 +1,40 @@ + +mga_vid - MGA G200/G400 YUV Overlay kernel module + + Author: + Aaron Holtzman <aholtzma@ess.engr.uvic.ca>, Oct 1999 + + Contributions by: + Fredrik Vraalsen <vraalsen@cs.uiuc.edu> + Alan Cox <alan@lxorguk.ukuu.org.uk> + + WARNING ----- WARNING + +This code messes with your video card and your xserver. It will probably +lock up your box, format your hard drive, and cause your brand new g400 +MAX to spout 6 inch flames. You have been warned. + + WARNING ----- WARNING + +What does this code do? + + mga_vid is a kernel module that utilitizes the Matrox g200/g400 video + scaler/overlay unit to perform YUV->RGB colorspace conversion and + arbitrary video scaling. + + mga_vid is also a monster hack. + +How does mga_vid work? + + This kernel module sets up the BES (backend scaler) with approriate values + based on parameters supplied via ioctl. It also maps a chunk of video + memory into userspace via mmap. This memory is stolen from X (which may + decide to write to it later). The application can then write image data + directly to the frame buffer (if it knows the right padding, etc). + + +How do I know if mga_vid works on my system? + + There are test applications called mga_vid_test_g400 and mga_vid_test_g200. + Use the appropriate one for your card. This test code should draw some + nice 256x256 images for you if all is working well. diff --git a/drivers/mga_vid.c b/drivers/mga_vid.c new file mode 100644 index 0000000000..1a5bf7162e --- /dev/null +++ b/drivers/mga_vid.c @@ -0,0 +1,877 @@ +// YUY2 support (see config.format) added by A'rpi/ESP-team + +/* + * + * mga_vid.c + * + * Copyright (C) 1999 Aaron Holtzman + * + * Module skeleton based on gutted agpgart module by Jeff Hartmann + * <slicer@ionet.net> + * + * Matrox MGA G200/G400 YUV Video Interface module Version 0.1.0 + * + * BES == Back End Scaler + * + * This software has been released under the terms of the GNU Public + * license. See http://www.gnu.org/copyleft/gpl.html for details. + */ + +//It's entirely possible this major conflicts with something else +/* mknod /dev/mga_vid c 178 0 */ + +#include <linux/config.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/malloc.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/videodev.h> + +#include "mga_vid.h" + +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/io.h> + +#define TRUE 1 +#define FALSE 0 + +#define MGA_VID_MAJOR 178 + +#define MGA_VIDMEM_SIZE mga_ram_size + +#ifndef PCI_DEVICE_ID_MATROX_G200_PCI +#define PCI_DEVICE_ID_MATROX_G200_PCI 0x0520 +#endif + +#ifndef PCI_DEVICE_ID_MATROX_G200_AGP +#define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521 +#endif + +#ifndef PCI_DEVICE_ID_MATROX_G400 +#define PCI_DEVICE_ID_MATROX_G400 0x0525 +#endif + +MODULE_AUTHOR("Aaron Holtzman <aholtzma@engr.uvic.ca>"); + + +typedef struct bes_registers_s +{ + //BES Control + uint32_t besctl; + //BES Global control + uint32_t besglobctl; + //Luma control (brightness and contrast) + uint32_t beslumactl; + //Line pitch + uint32_t bespitch; + + //Buffer A-1 Chroma 3 plane org + uint32_t besa1c3org; + //Buffer A-1 Chroma org + uint32_t besa1corg; + //Buffer A-1 Luma org + uint32_t besa1org; + + //Buffer A-2 Chroma 3 plane org + uint32_t besa2c3org; + //Buffer A-2 Chroma org + uint32_t besa2corg; + //Buffer A-2 Luma org + uint32_t besa2org; + + //Buffer B-1 Chroma 3 plane org + uint32_t besb1c3org; + //Buffer B-1 Chroma org + uint32_t besb1corg; + //Buffer B-1 Luma org + uint32_t besb1org; + + //Buffer B-2 Chroma 3 plane org + uint32_t besb2c3org; + //Buffer B-2 Chroma org + uint32_t besb2corg; + //Buffer B-2 Luma org + uint32_t besb2org; + + //BES Horizontal coord + uint32_t beshcoord; + //BES Horizontal inverse scaling [5.14] + uint32_t beshiscal; + //BES Horizontal source start [10.14] (for scaling) + uint32_t beshsrcst; + //BES Horizontal source ending [10.14] (for scaling) + uint32_t beshsrcend; + //BES Horizontal source last + uint32_t beshsrclst; + + + //BES Vertical coord + uint32_t besvcoord; + //BES Vertical inverse scaling [5.14] + uint32_t besviscal; + //BES Field 1 vertical source last position + uint32_t besv1srclst; + //BES Field 1 weight start + uint32_t besv1wght; + //BES Field 2 vertical source last position + uint32_t besv2srclst; + //BES Field 2 weight start + uint32_t besv2wght; + +} bes_registers_t; + +static bes_registers_t regs; +static uint32_t mga_vid_in_use = 0; +static uint32_t is_g400 = 0; +static uint32_t vid_src_ready = 0; +static uint32_t vid_overlay_on = 0; + +static uint8_t *mga_mmio_base = 0; +static uint32_t mga_mem_base = 0; +static uint32_t mga_src_base = 0; + +static uint32_t mga_ram_size = 0; + +static struct pci_dev *pci_dev; + +static struct video_window mga_win; +static mga_vid_config_t mga_config; + + +//All register offsets are converted to word aligned offsets (32 bit) +//because we want all our register accesses to be 32 bits +#define VCOUNT 0x1e20 + +#define PALWTADD 0x3c00 // Index register for X_DATAREG port +#define X_DATAREG 0x3c0a + +#define XMULCTRL 0x19 +#define BPP_8 0x00 +#define BPP_15 0x01 +#define BPP_16 0x02 +#define BPP_24 0x03 +#define BPP_32_DIR 0x04 +#define BPP_32_PAL 0x07 + +#define XCOLMSK 0x40 +#define X_COLKEY 0x42 +#define XKEYOPMODE 0x51 +#define XCOLMSK0RED 0x52 +#define XCOLMSK0GREEN 0x53 +#define XCOLMSK0BLUE 0x54 +#define XCOLKEY0RED 0x55 +#define XCOLKEY0GREEN 0x56 +#define XCOLKEY0BLUE 0x57 + +// Backend Scaler registers +#define BESCTL 0x3d20 +#define BESGLOBCTL 0x3dc0 +#define BESLUMACTL 0x3d40 +#define BESPITCH 0x3d24 +#define BESA1C3ORG 0x3d60 +#define BESA1CORG 0x3d10 +#define BESA1ORG 0x3d00 +#define BESA2C3ORG 0x3d64 +#define BESA2CORG 0x3d14 +#define BESA2ORG 0x3d04 +#define BESB1C3ORG 0x3d68 +#define BESB1CORG 0x3d18 +#define BESB1ORG 0x3d08 +#define BESB2C3ORG 0x3d6C +#define BESB2CORG 0x3d1C +#define BESB2ORG 0x3d0C +#define BESHCOORD 0x3d28 +#define BESHISCAL 0x3d30 +#define BESHSRCEND 0x3d3C +#define BESHSRCLST 0x3d50 +#define BESHSRCST 0x3d38 +#define BESV1WGHT 0x3d48 +#define BESV2WGHT 0x3d4c +#define BESV1SRCLST 0x3d54 +#define BESV2SRCLST 0x3d58 +#define BESVISCAL 0x3d34 +#define BESVCOORD 0x3d2c +#define BESSTATUS 0x3dc4 + + +static void mga_vid_frame_sel(int frame) +{ + //we don't need the vcount protection as we're only hitting + //one register (and it doesn't seem to be double buffered) + regs.besctl = (regs.besctl & ~0x07000000) + (frame << 25); + writel( regs.besctl, mga_mmio_base + BESCTL ); +} + + +static void mga_vid_write_regs(void) +{ + //Make sure internal registers don't get updated until we're done + writel( (readl(mga_mmio_base + VCOUNT)-1)<<16, + mga_mmio_base + BESGLOBCTL); + + // color or coordinate keying + writeb( XKEYOPMODE, mga_mmio_base + PALWTADD); + writeb( mga_config.colkey_on, mga_mmio_base + X_DATAREG); + if ( mga_config.colkey_on ) + { + uint32_t r=0, g=0, b=0; + + writeb( XMULCTRL, mga_mmio_base + PALWTADD); + switch (readb (mga_mmio_base + X_DATAREG)) + { + case BPP_8: + /* Need to look up the color index, just using + color 0 for now. */ + break; + + case BPP_15: + r = mga_config.colkey_red >> 3; + g = mga_config.colkey_green >> 3; + b = mga_config.colkey_blue >> 3; + break; + + case BPP_16: + r = mga_config.colkey_red >> 3; + g = mga_config.colkey_green >> 2; + b = mga_config.colkey_blue >> 3; + break; + + case BPP_24: + case BPP_32_DIR: + case BPP_32_PAL: + r = mga_config.colkey_red; + g = mga_config.colkey_green; + b = mga_config.colkey_blue; + break; + } + + // Disable color keying on alpha channel + writeb( XCOLMSK, mga_mmio_base + PALWTADD); + writeb( 0x00, mga_mmio_base + X_DATAREG); + writeb( X_COLKEY, mga_mmio_base + PALWTADD); + writeb( 0x00, mga_mmio_base + X_DATAREG); + + // Set up color key registers + writeb( XCOLKEY0RED, mga_mmio_base + PALWTADD); + writeb( r, mga_mmio_base + X_DATAREG); + writeb( XCOLKEY0GREEN, mga_mmio_base + PALWTADD); + writeb( g, mga_mmio_base + X_DATAREG); + writeb( XCOLKEY0BLUE, mga_mmio_base + PALWTADD); + writeb( b, mga_mmio_base + X_DATAREG); + + // Set up color key mask registers + writeb( XCOLMSK0RED, mga_mmio_base + PALWTADD); + writeb( 0xff, mga_mmio_base + X_DATAREG); + writeb( XCOLMSK0GREEN, mga_mmio_base + PALWTADD); + writeb( 0xff, mga_mmio_base + X_DATAREG); + writeb( XCOLMSK0BLUE, mga_mmio_base + PALWTADD); + writeb( 0xff, mga_mmio_base + X_DATAREG); + } + + // Backend Scaler + writel( regs.besctl, mga_mmio_base + BESCTL); + if(is_g400) + writel( regs.beslumactl, mga_mmio_base + BESLUMACTL); + writel( regs.bespitch, mga_mmio_base + BESPITCH); + + writel( regs.besa1org, mga_mmio_base + BESA1ORG); + writel( regs.besa1corg, mga_mmio_base + BESA1CORG); + writel( regs.besb1org, mga_mmio_base + BESB1ORG); + writel( regs.besb1corg, mga_mmio_base + BESB1CORG); + if(is_g400) + { + writel( regs.besa1c3org, mga_mmio_base + BESA1C3ORG); + writel( regs.besb1c3org, mga_mmio_base + BESB1C3ORG); + } + + writel( regs.beshcoord, mga_mmio_base + BESHCOORD); + writel( regs.beshiscal, mga_mmio_base + BESHISCAL); + writel( regs.beshsrcst, mga_mmio_base + BESHSRCST); + writel( regs.beshsrcend, mga_mmio_base + BESHSRCEND); + writel( regs.beshsrclst, mga_mmio_base + BESHSRCLST); + + writel( regs.besvcoord, mga_mmio_base + BESVCOORD); + writel( regs.besviscal, mga_mmio_base + BESVISCAL); + writel( regs.besv1srclst, mga_mmio_base + BESV1SRCLST); + writel( regs.besv1wght, mga_mmio_base + BESV1WGHT); + + //update the registers somewhere between 1 and 2 frames from now. + writel( regs.besglobctl + ((readl(mga_mmio_base + VCOUNT)+2)<<16), + mga_mmio_base + BESGLOBCTL); + + printk("mga_vid: wrote BES registers\n"); + printk("mga_vid: BESCTL = 0x%08x\n", + readl(mga_mmio_base + BESCTL)); + printk("mga_vid: BESGLOBCTL = 0x%08x\n", + readl(mga_mmio_base + BESGLOBCTL)); + printk("mga_vid: BESSTATUS= 0x%08x\n", + readl(mga_mmio_base + BESSTATUS)); +} + +static int mga_vid_set_config(mga_vid_config_t *config) +{ + int x, y, sw, sh, dw, dh; + int besleft, bestop, ifactor, ofsleft, ofstop, baseadrofs, weight, weights; + int frame_size; + x = config->x_org; + y = config->y_org; + sw = config->src_width; + sh = config->src_height; + dw = config->dest_width; + dh = config->dest_height; + + printk("mga_vid: Setting up a %dx%d+%d+%d video window (src %dx%d) format %X\n", + dw, dh, x, y, sw, sh, config->format); + + //FIXME check that window is valid and inside desktop + + //FIXME figure out a better way to allocate memory on card + //allocate 2 megs + //mga_src_base = mga_mem_base + (MGA_VIDMEM_SIZE-2) * 0x100000; + mga_src_base = (MGA_VIDMEM_SIZE-2) * 0x100000; + + + //Setup the BES registers for a three plane 4:2:0 video source + +switch(config->format){ + case MGA_VID_FORMAT_YV12: + regs.besctl = 1 // BES enabled + + (0<<6) // even start polarity + + (1<<10) // x filtering enabled + + (1<<11) // y filtering enabled + + (1<<16) // chroma upsampling + + (1<<17) // 4:2:0 mode + + (1<<18); // dither enabled + + if(is_g400) + { + //zoom disabled, zoom filter disabled, 420 3 plane format, proc amp + //disabled, rgb mode disabled + regs.besglobctl = (1<<5); + } + else + { + //zoom disabled, zoom filter disabled, Cb samples in 0246, Cr + //in 1357, BES register update on besvcnt + regs.besglobctl = 0; + } + break; + + case MGA_VID_FORMAT_YUY2: + regs.besctl = 1 // BES enabled + + (0<<6) // even start polarity + + (1<<10) // x filtering enabled + + (1<<11) // y filtering enabled + + (1<<16) // chroma upsampling + + (0<<17) // 4:2:2 mode + + (1<<18); // dither enabled + + regs.besglobctl = 0; // YUY2 format selected + break; + default: + return -1; +} + + + //Disable contrast and brightness control + regs.besglobctl = (1<<5) + (1<<7); + regs.beslumactl = (0x7f << 16) + (0x80<<0); + regs.beslumactl = 0x80<<0; + + //Setup destination window boundaries + besleft = x > 0 ? x : 0; + bestop = y > 0 ? y : 0; + regs.beshcoord = (besleft<<16) + (x + dw-1); + regs.besvcoord = (bestop<<16) + (y + dh-1); + + //Setup source dimensions + regs.beshsrclst = (sw - 1) << 16; + regs.bespitch = (sw + 31) & ~31 ; + + //Setup horizontal scaling + ifactor = ((sw-1)<<14)/(dw-1); + ofsleft = besleft - x; + + regs.beshiscal = ifactor<<2; + regs.beshsrcst = (ofsleft*ifactor)<<2; + regs.beshsrcend = regs.beshsrcst + (((dw - ofsleft - 1) * ifactor) << 2); + + //Setup vertical scaling + ifactor = ((sh-1)<<14)/(dh-1); + ofstop = bestop - y; + + regs.besviscal = ifactor<<2; + + baseadrofs = ((ofstop*regs.besviscal)>>16)*regs.bespitch; + frame_size = ((sw + 31) & ~31) * sh + (((sw + 31) & ~31) * sh) / 2; + regs.besa1org = (uint32_t) mga_src_base + baseadrofs; + regs.besb1org = (uint32_t) mga_src_base + baseadrofs + frame_size; + + if (is_g400) + baseadrofs = (((ofstop*regs.besviscal)/4)>>16)*regs.bespitch; + else + baseadrofs = (((ofstop*regs.besviscal)/2)>>16)*regs.bespitch; + + regs.besa1corg = (uint32_t) mga_src_base + baseadrofs + regs.bespitch * sh ; + regs.besb1corg = (uint32_t) mga_src_base + baseadrofs + frame_size + regs.bespitch * sh; + regs.besa1c3org = regs.besa1corg + ((regs.bespitch * sh) / 4); + regs.besb1c3org = regs.besb1corg + ((regs.bespitch * sh) / 4); + + weight = ofstop * (regs.besviscal >> 2); + weights = weight < 0 ? 1 : 0; + regs.besv1wght = (weights << 16) + ((weight & 0x3FFF) << 2); + regs.besv1srclst = sh - 1 - (((ofstop * regs.besviscal) >> 16) & 0x03FF); + + mga_vid_write_regs(); + return 0; +} + + +static int mga_vid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int frame; + + switch(cmd) + { + case MGA_VID_CONFIG: + //FIXME remove + printk("vcount = %d\n",readl(mga_mmio_base + VCOUNT)); + printk("mga_mmio_base = %p\n",mga_mmio_base); + printk("mga_mem_base = %08lx\n",mga_mem_base); + //FIXME remove + + printk("mga_vid: Received configuration\n"); + + if(copy_from_user(&mga_config,(mga_vid_config_t*) arg,sizeof(mga_vid_config_t))) + { + printk("mga_vid: failed copy from userspace\n"); + return(-EFAULT); + } + if (is_g400) + mga_config.card_type = MGA_G400; + else + mga_config.card_type = MGA_G200; + + mga_config.ram_size = mga_ram_size; + + if (copy_to_user((mga_vid_config_t *) arg, &mga_config, sizeof(mga_vid_config_t))) + { + printk("mga_vid: failed copy to userspace\n"); + return(-EFAULT); + } + return mga_vid_set_config(&mga_config); + break; + + case MGA_VID_ON: + printk("mga_vid: Video ON\n"); + vid_src_ready = 1; + if(vid_overlay_on) + { + regs.besctl |= 1; + mga_vid_write_regs(); + } + break; + + case MGA_VID_OFF: + printk("mga_vid: Video OFF\n"); + vid_src_ready = 0; + regs.besctl &= ~1; + mga_vid_write_regs(); + break; + + case MGA_VID_FSEL: + if(copy_from_user(&frame,(int *) arg,sizeof(int))) + { + printk("mga_vid: FSEL failed copy from userspace\n"); + return(-EFAULT); + } + + mga_vid_frame_sel(frame); + break; + + default: + printk("mga_vid: Invalid ioctl\n"); + return (-EINVAL); + } + + return 0; +} + + +static int mga_vid_find_card(void) +{ + struct pci_dev *dev = NULL; + unsigned int card_option, temp; + + if((dev = pci_find_device(PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, NULL))) + { + is_g400 = 1; + printk("mga_vid: Found MGA G400\n"); + } + else if((dev = pci_find_device(PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, NULL))) + { + is_g400 = 0; + printk("mga_vid: Found MGA G200 AGP\n"); + } + else if((dev = pci_find_device(PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, NULL))) + { + is_g400 = 0; + printk("mga_vid: Found MGA G200 PCI\n"); + } + else + { + printk("mga_vid: No supported cards found\n"); + return FALSE; + } + + pci_dev = dev; + +#if LINUX_VERSION_CODE >= 0x020300 + mga_mmio_base = ioremap_nocache(dev->resource[1].start,0x4000); + mga_mem_base = dev->resource[0].start; +#else + mga_mmio_base = ioremap_nocache(dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK,0x4000); + mga_mem_base = dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK; +#endif + printk("mga_vid: MMIO at 0x%p\n", mga_mmio_base); + printk("mga_vid: Frame Buffer at 0x%08lX\n", mga_mem_base); + + pci_read_config_dword(dev, 0x40, &card_option); + printk("OPTION word: 0x%08x\n", card_option); + + temp = (card_option >> 10) & 0x17; + + if (is_g400) + { + switch(temp) + { + default: + mga_ram_size = 16; + } + } + else + { + // a g200 + switch(temp) + { + default: + mga_ram_size = 8; + } + } + + printk("mga_vid: RAMSIZE seems to be %d MB\n", (unsigned int) mga_ram_size); + + return TRUE; +} + + +static ssize_t mga_vid_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static ssize_t mga_vid_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static int mga_vid_mmap(struct file *file, struct vm_area_struct *vma) +{ + + printk("mga_vid: mapping video memory into userspace\n"); + if(remap_page_range(vma->vm_start, mga_mem_base + (MGA_VIDMEM_SIZE-2) * 0x100000, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) + { + printk("mga_vid: error mapping video memory\n"); + return(-EAGAIN); + } + + return(0); +} + +static int mga_vid_release(struct inode *inode, struct file *file) +{ + //Close the window just in case + vid_src_ready = 0; + regs.besctl &= ~1; + mga_vid_write_regs(); + mga_vid_in_use = 0; + + //FIXME put back in! + //MOD_DEC_USE_COUNT; + return 0; +} + +static long long mga_vid_lseek(struct file *file, long long offset, int origin) +{ + return -ESPIPE; +} + +static int mga_vid_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + + if(minor != 0) + return(-ENXIO); + + if(mga_vid_in_use == 1) + return(-EBUSY); + + mga_vid_in_use = 1; + //FIXME turn me back on! + //MOD_INC_USE_COUNT; + return(0); +} + +#if LINUX_VERSION_CODE >= 0x020400 +static struct file_operations mga_vid_fops = +{ + llseek: mga_vid_lseek, + read: mga_vid_read, + write: mga_vid_write, + ioctl: mga_vid_ioctl, + mmap: mga_vid_mmap, + open: mga_vid_open, + release: mga_vid_release +}; +#else +static struct file_operations mga_vid_fops = +{ + mga_vid_lseek, + mga_vid_read, + mga_vid_write, + NULL, + NULL, + mga_vid_ioctl, + mga_vid_mmap, + mga_vid_open, + NULL, + mga_vid_release +}; +#endif + +static long mga_v4l_read(struct video_device *v, char *buf, unsigned long count, + int noblock) +{ + return -EINVAL; +} + +static long mga_v4l_write(struct video_device *v, const char *buf, unsigned long count, int noblock) +{ + return -EINVAL; +} + +static int mga_v4l_open(struct video_device *dev, int mode) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static void mga_v4l_close(struct video_device *dev) +{ + regs.besctl &= ~1; + mga_vid_write_regs(); + vid_overlay_on = 0; + MOD_DEC_USE_COUNT; + return; +} + +static int mga_v4l_init_done(struct video_device *dev) +{ + return 0; +} + +static int mga_v4l_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + switch(cmd) + { + case VIDIOCGCAP: + { + struct video_capability b; + strcpy(b.name, "Matrox G200/400"); + b.type = VID_TYPE_SCALES|VID_TYPE_OVERLAY|VID_TYPE_CHROMAKEY; + b.channels = 0; + b.audios = 0; + b.maxwidth = 1024; /* GUESS ?? */ + b.maxheight = 768; + b.minwidth = 32; + b.minheight = 16; /* GUESS ?? */ + if(copy_to_user(arg,&b,sizeof(b))) + return -EFAULT; + return 0; + } + case VIDIOCGPICT: + { + /* + * Default values.. if we can change this we + * can add the feature later + */ + struct video_picture vp; + vp.brightness = 0x8000; + vp.hue = 0x8000; + vp.colour = 0x8000; + vp.whiteness = 0x8000; + vp.depth = 8; + /* Format is a guess */ + vp.palette = VIDEO_PALETTE_YUV420P; + if(copy_to_user(arg, &vp, sizeof(vp))) + return -EFAULT; + return 0; + } + case VIDIOCSPICT: + { + return -EINVAL; + } + case VIDIOCSWIN: + { + struct video_window vw; + if(copy_from_user(&vw, arg, sizeof(vw))) + return -EFAULT; + if(vw.x <0 || vw.y <0 || vw.width < 32 + || vw.height < 16) + return -EINVAL; + memcpy(&mga_win, &vw, sizeof(mga_win)); + + mga_config.x_org = vw.x; + mga_config.y_org = vw.y; + mga_config.dest_width = vw.width; + mga_config.dest_height = vw.height; + + /* + * May have to add + * + * #define VIDEO_WINDOW_CHROMAKEY 16 + * + * to <linux/videodev.h> + */ + + //add it here for now + #define VIDEO_WINDOW_CHROMAKEY 16 + + if (vw.flags & VIDEO_WINDOW_CHROMAKEY) + mga_config.colkey_on = 1; + else + mga_config.colkey_on = 0; + + mga_config.colkey_red = (vw.chromakey >> 24) & 0xFF; + mga_config.colkey_green = (vw.chromakey >> 16) & 0xFF; + mga_config.colkey_blue = (vw.chromakey >> 8) & 0xFF; + mga_vid_set_config(&mga_config); + return 0; + + } + case VIDIOCGWIN: + { + if(copy_to_user(arg, &mga_win, sizeof(mga_win))) + return -EFAULT; + return 0; + } + case VIDIOCCAPTURE: + { + int v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + vid_overlay_on = v; + if(vid_overlay_on && vid_src_ready) + { + regs.besctl |= 1; + mga_vid_write_regs(); + } + else + { + regs.besctl &= ~1; + mga_vid_write_regs(); + } + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +static struct video_device mga_v4l_dev = +{ + "Matrox G200/G400", + VID_TYPE_CAPTURE, + VID_HARDWARE_BT848, /* This is a lie for now */ + mga_v4l_open, + mga_v4l_close, + mga_v4l_read, + mga_v4l_write, + NULL, + mga_v4l_ioctl, + NULL, + mga_v4l_init_done, + NULL, + 0, + 0 +}; + + + +/* + * Main Initialization Function + */ + + +static int mga_vid_initialize(void) +{ + mga_vid_in_use = 0; + + printk( "Matrox MGA G200/G400 YUV Video interface v0.01 (c) Aaron Holtzman \n"); + if(register_chrdev(MGA_VID_MAJOR, "mga_vid", &mga_vid_fops)) + { + printk("mga_vid: unable to get major: %d\n", MGA_VID_MAJOR); + return -EIO; + } + + if (!mga_vid_find_card()) + { + printk("mga_vid: no supported devices found\n"); + unregister_chrdev(MGA_VID_MAJOR, "mga_vid"); + return -EINVAL; + } + +#if 0 + if (video_register_device(&mga_v4l_dev, VFL_TYPE_GRABBER)<0) + { + printk("mga_vid: unable to register.\n"); + unregister_chrdev(MGA_VID_MAJOR, "mga_vid"); + if(mga_mmio_base) + iounmap(mga_mmio_base); + mga_mmio_base = 0; + return -EINVAL; + } +#endif + + return(0); +} + +int init_module(void) +{ + return mga_vid_initialize(); +} + +void cleanup_module(void) +{ +// video_unregister_device(&mga_v4l_dev); + if(mga_mmio_base) + iounmap(mga_mmio_base); + + //FIXME turn off BES + printk("mga_vid: Cleaning up module\n"); + unregister_chrdev(MGA_VID_MAJOR, "mga_vid"); +} + diff --git a/drivers/mga_vid.h b/drivers/mga_vid.h new file mode 100644 index 0000000000..5f1a0b540d --- /dev/null +++ b/drivers/mga_vid.h @@ -0,0 +1,48 @@ +/* + * + * mga_vid.h + * + * Copyright (C) 1999 Aaron Holtzman + * + * Matrox MGA G200/G400 YUV Video Interface module Version 0.1.0 + * + * BES == Back End Scaler + * + * This software has been released under the terms of the GNU Public + * license. See http://www.gnu.org/copyleft/gpl.html for details. + */ + +#ifndef __LINUX_MGAVID_H +#define __LINUX_MGAVID_H + +#include <inttypes.h> + +typedef struct mga_vid_config_s +{ +uint32_t card_type; +uint32_t ram_size; +uint32_t src_width; +uint32_t src_height; +uint32_t dest_width; +uint32_t dest_height; +uint32_t x_org; +uint32_t y_org; +uint8_t colkey_on; +uint8_t colkey_red; +uint8_t colkey_green; +uint8_t colkey_blue; +uint32_t format; +} mga_vid_config_t; + +#define MGA_VID_FORMAT_YV12 0x32315659 +#define MGA_VID_FORMAT_YUY2 (('Y'<<24)|('U'<<16)|('Y'<<8)|'2') + +#define MGA_VID_CONFIG _IOR('J', 1, mga_vid_config_t) +#define MGA_VID_ON _IO ('J', 2) +#define MGA_VID_OFF _IO ('J', 3) +#define MGA_VID_FSEL _IOR('J', 4, int) + +#define MGA_G200 0x1234 +#define MGA_G400 0x5678 + +#endif diff --git a/drivers/mga_vid_test.c b/drivers/mga_vid_test.c new file mode 100644 index 0000000000..c1057a9cf7 --- /dev/null +++ b/drivers/mga_vid_test.c @@ -0,0 +1,221 @@ +/* + * + * mga_vid_test.c + * + * Aaron Holtzman <aholtzma@ess.engr.uvic.ca> + * Sept 1999 + * + * This software has been released under the terms of the GNU Public + * license. See http://www.gnu.org/copyleft/gpl.html for details. + */ + +//#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/mman.h> +#include "mga_vid.h" + +mga_vid_config_t config; +uint8_t *mga_vid_base; +uint32_t is_g400; + +#define SRC_IMAGE_WIDTH 256 +#define SRC_IMAGE_HEIGHT 256 + +uint8_t y_image[SRC_IMAGE_WIDTH * SRC_IMAGE_HEIGHT]; +uint8_t cr_image[SRC_IMAGE_WIDTH * SRC_IMAGE_HEIGHT]; +uint8_t cb_image[SRC_IMAGE_WIDTH * SRC_IMAGE_HEIGHT]; + + +void +write_frame_g200(uint8_t *y,uint8_t *cr, uint8_t *cb) +{ + uint8_t *dest; + uint32_t bespitch,h,w; + + dest = mga_vid_base; + bespitch = (config.src_width + 31) & ~31; + + for(h=0; h < config.src_height; h++) + { + memcpy(dest, y, config.src_width); + y += config.src_width; + dest += bespitch; + } + + for(h=0; h < config.src_height/2; h++) + { + for(w=0; w < config.src_width/2; w++) + { + *dest++ = *cb++; + *dest++ = *cr++; + } + dest += bespitch - config.src_width; + } +} + +void +write_frame_g400(uint8_t *y,uint8_t *cr, uint8_t *cb) +{ + uint8_t *dest; + uint32_t bespitch,h; + + dest = mga_vid_base; + bespitch = (config.src_width + 31) & ~31; + + for(h=0; h < config.src_height; h++) + { + memcpy(dest, y, config.src_width); + y += config.src_width; + dest += bespitch; + } + + for(h=0; h < config.src_height/2; h++) + { + memcpy(dest, cb, config.src_width/2); + cb += config.src_width/2; + dest += bespitch/2; + } + + for(h=0; h < config.src_height/2; h++) + { + memcpy(dest, cr, config.src_width/2); + cr += config.src_width/2; + dest += bespitch/2; + } +} + +void write_frame(uint8_t *y,uint8_t *cr, uint8_t *cb) +{ + if(is_g400) + write_frame_g400(y,cr,cb); + else + write_frame_g200(y,cr,cb); +} + +void +draw_cool_pattern(void) +{ + int i,x,y; + + i = 0; + for (y=0; y<config.src_height; y++) { + for (x=0; x<config.src_width; x++) { + y_image[i++] = x*x/2 + y*y/2 - 128; + } + } + + i = 0; + for (y=0; y<config.src_height/2; y++) + for (x=0; x<config.src_width/2; x++) + { + cr_image[i++] = x - 128; + } + + i = 0; + for (y=0; y<config.src_height/2; y++) + for (x=0; x<config.src_width/2; x++) + { + cb_image[i++] = y - 128; + } +} + +void +draw_color_blend(void) +{ + int i,x,y; + + i = 0; + for (y=0; y<config.src_height; y++) { + for (x=0; x<config.src_width; x++) { + y_image[i++] = 0; + } + } + + i = 0; + for (y=0; y<config.src_height/2; y++) + for (x=0; x<config.src_width/2; x++) + { + cr_image[i++] = x - 128; + } + + i = 0; + for (y=0; y<config.src_height/2; y++) + for (x=0; x<config.src_width/2; x++) + { + cb_image[i++] = y - 128; + } +} + + +int +main(int argc, char *argv[]) +{ + int f; + + f = open("/dev/mga_vid",O_RDWR); + + if(f == -1) + { + fprintf(stderr,"Couldn't open driver\n"); + exit(1); + } + + config.src_width = SRC_IMAGE_WIDTH; + config.src_height= SRC_IMAGE_HEIGHT; + config.dest_width = SRC_IMAGE_WIDTH; + config.dest_height = SRC_IMAGE_HEIGHT; + config.x_org= 10; + config.y_org= 10; + config.colkey_on = 0; + config.format = MGA_VID_FORMAT_YV12; + + if (ioctl(f,MGA_VID_CONFIG,&config)) + { + perror("Error in config ioctl"); + } + + if (config.card_type == MGA_G200) + { + printf("Testing MGA G200 Backend Scaler with %d MB of RAM\n", config.ram_size); + is_g400 = 0; + } + else + { + printf("Testing MGA G400 Backend Scaler with %d MB of RAM\n", config.ram_size); + is_g400 = 1; + } + + ioctl(f,MGA_VID_ON,0); + mga_vid_base = (uint8_t*)mmap(0,256 * 4096,PROT_WRITE,MAP_SHARED,f,0); + printf("mga_vid_base = %8p\n",mga_vid_base); + + + //memset(y_image,80,256 * 128); + //memset(cr_image,80,256/2 * 20); + //memset(cb_image,80,256/2 * 20); + write_frame(y_image,cr_image,cb_image); + printf("(1) There should be a green square, offset by 10 pixels from\n" + " the upper left corner displayed\n"); + sleep(3); + + + draw_cool_pattern(); + write_frame(y_image,cr_image,cb_image); + printf("(2) There should be a cool mosaic like pattern now.\n"); + sleep(3); + + draw_color_blend(); + write_frame(y_image,cr_image,cb_image); + printf("(3) There should be a color blend with black, red, purple, blue\n" + " corners (starting top left going CW)\n"); + sleep(3); + + ioctl(f,MGA_VID_OFF,0); + + close(f); + return 0; +} diff --git a/drivers/sis_vid.c b/drivers/sis_vid.c new file mode 100644 index 0000000000..5b9eace81a --- /dev/null +++ b/drivers/sis_vid.c @@ -0,0 +1,645 @@ +/* + * + * sis_vid.c + * + * Copyright (C) 2000 Aaron Holtzman + * + * This software has been released under the terms of the GNU Public + * license. See http://www.gnu.org/copyleft/gpl.html for details. + */ + +// video4linux interface disabled by A'rpi/ESP-team + + +//It's entirely possible this major conflicts with something else +/* mknod /dev/mga_vid c 178 0 */ + +#include <linux/config.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/malloc.h> +#include <linux/pci.h> +#include <linux/init.h> +//#include <linux/videodev.h> + +#include "sis_vid.h" + +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/io.h> + +#define TRUE 1 +#define FALSE 0 + +#define MGA_VID_MAJOR 178 + + +#ifndef PCI_DEVICE_ID_SI_6323 +#define PCI_DEVICE_ID_SI_6323 0x6326 +#endif + + +MODULE_AUTHOR("Aaron Holtzman <aholtzma@engr.uvic.ca>"); + + +typedef struct bes_registers_s +{ + //base address of yuv framebuffer + uint32_t yuv_base; + uint32_t u_base; + uint32_t v_base; + uint32_t fb_end;; + + //frame buffer pitch + uint32_t pitch; + + //window boundaries + uint32_t left; + uint32_t right; + uint32_t top; + uint32_t bottom; + + //control registers + uint32_t misc_0; + uint32_t misc_1; + uint32_t misc_3; + uint32_t misc_4; + + //key overlay mode + uint32_t key_mode; + +} bes_registers_t; + +static bes_registers_t regs; +static uint32_t mga_vid_in_use = 0; +static uint32_t vid_src_ready = 0; +static uint32_t vid_overlay_on = 0; + +static uint8_t *mga_mmio_base = 0; +static uint32_t mga_mem_base = 0; +static uint32_t mga_src_base = 0; + +static uint32_t mga_ram_size = 0; + +static struct pci_dev *pci_dev; + +//static struct video_window mga_win; +static mga_vid_config_t mga_config; + + + +// Backend Scaler registers + +#define MISC_0 0x98 +#define MISC_1 0x99 +#define MISC_3 0x9d +#define MISC_4 0xb6 + + + + +static void mga_vid_frame_sel(int frame) +{ + //we don't need the vcount protection as we're only hitting + //one register (and it doesn't seem to be double buffered) + //regs.besctl = (regs.besctl & ~0x07000000) + (frame << 25); + //writel( regs.besctl, mga_mmio_base + BESCTL ); +} + + +#define WRITE_REG(x,y,z) {outb((y),(x));outb((z),(x+1));} +#define READ_REG(x,y) (outb((y),(x)),inb(x+1)) +#define VIDEO_ACCEL 0x3d4 + +static void mga_vid_write_regs(void) +{ + uint32_t foo; + + //unlock the video accel registers + WRITE_REG(VIDEO_ACCEL,0x80,0x86); + foo = READ_REG(VIDEO_ACCEL,0x80); + + if(foo != 0xa1) + return; //something bad happened + + //setup the horizontal window bounds + WRITE_REG(VIDEO_ACCEL,0x81,regs.left & 0xff); + WRITE_REG(VIDEO_ACCEL,0x82,regs.right & 0xff); + WRITE_REG(VIDEO_ACCEL,0x83,(regs.left >> 8) | ((regs.right>>4) & 0x70)); + + //setup the vertical window bounds + WRITE_REG(VIDEO_ACCEL,0x84,regs.top & 0xff); + WRITE_REG(VIDEO_ACCEL,0x85,regs.bottom & 0xff); + WRITE_REG(VIDEO_ACCEL,0x86,(regs.top >> 8) | ((regs.bottom>>4) & 0x70)); + + //setup the framebuffer base addresses + WRITE_REG(VIDEO_ACCEL,0x8a,regs.yuv_base & 0xff); + WRITE_REG(VIDEO_ACCEL,0x8b,(regs.yuv_base >> 8) & 0xff); + WRITE_REG(VIDEO_ACCEL,0x89,(regs.yuv_base >> 12) & 0xf0); + + WRITE_REG(VIDEO_ACCEL,0xb7,regs.u_base & 0xff); + WRITE_REG(VIDEO_ACCEL,0xb8,(regs.u_base >> 8) & 0xff); + + WRITE_REG(VIDEO_ACCEL,0xba,regs.v_base & 0xff); + WRITE_REG(VIDEO_ACCEL,0xbb,(regs.v_base >> 8) & 0xff); + WRITE_REG(VIDEO_ACCEL,0xb9,((regs.v_base >> 12) & 0xf0) + ((regs.u_base >> 16) & 0xf)); + + WRITE_REG(VIDEO_ACCEL,0x8d,regs.fb_end); + + //setup framebuffer pitch + WRITE_REG(VIDEO_ACCEL,0x8c,regs.pitch & 0xff); + WRITE_REG(VIDEO_ACCEL,0x8e,(regs.pitch >> 8) & 0x0f); + WRITE_REG(VIDEO_ACCEL,0xbc,(regs.pitch) & 0xff); + WRITE_REG(VIDEO_ACCEL,0xbd,((regs.pitch) >> 8) & 0x0f); + + + //write key overlay register + WRITE_REG(VIDEO_ACCEL,0xa9,regs.key_mode); + + WRITE_REG(VIDEO_ACCEL,0x93,0x40); + WRITE_REG(VIDEO_ACCEL,0x94,1); + WRITE_REG(VIDEO_ACCEL,0x9e,0); + WRITE_REG(VIDEO_ACCEL,0x9f,0); + + //write config registers + WRITE_REG(VIDEO_ACCEL,MISC_0,regs.misc_0); + WRITE_REG(VIDEO_ACCEL,MISC_1,regs.misc_1); + WRITE_REG(VIDEO_ACCEL,MISC_3,regs.misc_3); + WRITE_REG(VIDEO_ACCEL,MISC_4,regs.misc_4); + + //setup the video line buffer + WRITE_REG(VIDEO_ACCEL,0xa0,(regs.right - regs.left)/ 8); + +} + +static int mga_vid_set_config(mga_vid_config_t *config) +{ + uint32_t x, y, frame_size; + + x = config->x_org; + y = config->y_org; + + regs.left = x; + regs.right= config->src_width + x; + regs.top = y; + regs.bottom = config->src_height + y; + + printk("mga_vid: Setting up a %dx%d+%d+%d video window (src %dx%d)\n", + config->dest_width, config->dest_height, config->x_org, config->y_org, + config->src_width, config->src_height); + + + regs.pitch = ((config->src_width + 31) & ~31) / 4 ; + + //frame size in pixels + frame_size = regs.pitch * config->src_height * 4; + + regs.yuv_base = (mga_src_base) >> 2; + regs.u_base = (mga_src_base + frame_size) >> 2; + regs.v_base = (mga_src_base + frame_size/4) >> 2; + regs.fb_end = (mga_src_base + (3*frame_size)/2) >> 14; + + //disable video capture, enable video display, enable graphics display, + //select yuv format, odd parity + regs.misc_0 = (1 << 1) + (1<<6) + (1<<4); + + //disable dithering, no filtering, no interrupts + regs.misc_1 = 0; + + //select 2's complement format YUV for playback + regs.misc_3 = (1<<1); + + //select 4:2:0 video format, + yuv4:2:2 cpu writes + regs.misc_4 = (1<<2); + + //disable keying + regs.key_mode = 0xf; + + mga_vid_write_regs(); + return 0; +} + + +static int mga_vid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int frame; + + switch(cmd) + { + case MGA_VID_CONFIG: + //FIXME remove + printk("mga_mmio_base = %p\n",mga_mmio_base); + printk("mga_mem_base = %08x\n",mga_mem_base); + //FIXME remove + + printk("mga_vid: Received configuration\n"); + + if(copy_from_user(&mga_config,(mga_vid_config_t*) arg,sizeof(mga_vid_config_t))) + { + printk("mga_vid: failed copy from userspace\n"); + return(-EFAULT); + } + + mga_config.ram_size = mga_ram_size; + //XXX make it look like a g400 + mga_config.card_type = MGA_G400;; + + if (copy_to_user((mga_vid_config_t *) arg, &mga_config, sizeof(mga_vid_config_t))) + { + printk("mga_vid: failed copy to userspace\n"); + return(-EFAULT); + } + return mga_vid_set_config(&mga_config); + break; + + case MGA_VID_ON: + printk("mga_vid: Video ON\n"); + vid_src_ready = 1; + if(vid_overlay_on) + { + //regs.besctl |= 1; + mga_vid_write_regs(); + } + break; + + case MGA_VID_OFF: + printk("mga_vid: Video OFF\n"); + vid_src_ready = 0; + //regs.besctl &= ~1; + mga_vid_write_regs(); + break; + + case MGA_VID_FSEL: + if(copy_from_user(&frame,(int *) arg,sizeof(int))) + { + printk("mga_vid: FSEL failed copy from userspace\n"); + return(-EFAULT); + } + + mga_vid_frame_sel(frame); + break; + + default: + printk("mga_vid: Invalid ioctl\n"); + return (-EINVAL); + } + + return 0; +} + + +static int mga_vid_find_card(void) +{ + struct pci_dev *dev = NULL; + + if((dev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_6323, NULL))) + { + printk("sis_vid: Found SiS 6326\n"); + } + else + { + printk("sis_vid: No supported cards found\n"); + return FALSE; + } + + pci_dev = dev; + +#if LINUX_VERSION_CODE >= 0x020300 + mga_mmio_base = ioremap_nocache(dev->resource[1].start,0x10000); + mga_mem_base = dev->resource[0].start; +#else + mga_mmio_base = ioremap_nocache(dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK,0x10000); + mga_mem_base = dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK; +#endif + printk("mga_vid: MMIO at 0x%p\n", mga_mmio_base); + printk("mga_vid: Frame Buffer at 0x%08x\n", mga_mem_base); + + //FIXME set ram size properly + mga_ram_size = 4; + mga_src_base = (mga_ram_size - 1) * 0x100000; + + //FIXME remove + if(1) + { + mga_vid_config_t config ={0,0,256,256,256,256,10,10,0,0,0,0}; + + mga_vid_set_config(&config); + mga_vid_write_regs(); + //regs.misc_0 ^= 2; + //mga_vid_write_regs(); + } + //FIXME remove + + return TRUE; +} + + +static ssize_t mga_vid_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static ssize_t mga_vid_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static int mga_vid_mmap(struct file *file, struct vm_area_struct *vma) +{ + + printk("mga_vid: mapping video memory into userspace\n"); + if(remap_page_range(vma->vm_start, mga_mem_base + mga_src_base, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) + { + printk("mga_vid: error mapping video memory\n"); + return(-EAGAIN); + } + + return(0); +} + +static int mga_vid_release(struct inode *inode, struct file *file) +{ + //Close the window just in case + vid_src_ready = 0; + regs.misc_0 &= 0xed; + mga_vid_write_regs(); + mga_vid_in_use = 0; + + //FIXME put back in! + //MOD_DEC_USE_COUNT; + return 0; +} + +static long long mga_vid_lseek(struct file *file, long long offset, int origin) +{ + return -ESPIPE; +} + +static int mga_vid_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + + if(minor != 0) + return(-ENXIO); + + if(mga_vid_in_use == 1) + return(-EBUSY); + + mga_vid_in_use = 1; + //FIXME turn me back on! + //MOD_INC_USE_COUNT; + return(0); +} + +#if LINUX_VERSION_CODE >= 0x020400 +static struct file_operations mga_vid_fops = +{ + llseek: mga_vid_lseek, + read: mga_vid_read, + write: mga_vid_write, + ioctl: mga_vid_ioctl, + mmap: mga_vid_mmap, + open: mga_vid_open, + release: mga_vid_release +}; +#else +static struct file_operations mga_vid_fops = +{ + mga_vid_lseek, + mga_vid_read, + mga_vid_write, + NULL, + NULL, + mga_vid_ioctl, + mga_vid_mmap, + mga_vid_open, + NULL, + mga_vid_release +}; +#endif + +#if 0 +static long mga_v4l_read(struct video_device *v, char *buf, unsigned long count, + int noblock) +{ + return -EINVAL; +} + +static long mga_v4l_write(struct video_device *v, const char *buf, unsigned long count, int noblock) +{ + return -EINVAL; +} + +static int mga_v4l_open(struct video_device *dev, int mode) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static void mga_v4l_close(struct video_device *dev) +{ + //regs.besctl &= ~1; + mga_vid_write_regs(); + vid_overlay_on = 0; + MOD_DEC_USE_COUNT; + return; +} + +static int mga_v4l_init_done(struct video_device *dev) +{ + return 0; +} + +static int mga_v4l_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + switch(cmd) + { + case VIDIOCGCAP: + { + struct video_capability b; + strcpy(b.name, "Matrox G200/400"); + b.type = VID_TYPE_SCALES|VID_TYPE_OVERLAY|VID_TYPE_CHROMAKEY; + b.channels = 0; + b.audios = 0; + b.maxwidth = 1024; /* GUESS ?? */ + b.maxheight = 768; + b.minwidth = 32; + b.minheight = 16; /* GUESS ?? */ + if(copy_to_user(arg,&b,sizeof(b))) + return -EFAULT; + return 0; + } + case VIDIOCGPICT: + { + /* + * Default values.. if we can change this we + * can add the feature later + */ + struct video_picture vp; + vp.brightness = 0x8000; + vp.hue = 0x8000; + vp.colour = 0x8000; + vp.whiteness = 0x8000; + vp.depth = 8; + /* Format is a guess */ + vp.palette = VIDEO_PALETTE_YUV420P; + if(copy_to_user(arg, &vp, sizeof(vp))) + return -EFAULT; + return 0; + } + case VIDIOCSPICT: + { + return -EINVAL; + } + case VIDIOCSWIN: + { + struct video_window vw; + if(copy_from_user(&vw, arg, sizeof(vw))) + return -EFAULT; + if(vw.x <0 || vw.y <0 || vw.width < 32 + || vw.height < 16) + return -EINVAL; + memcpy(&mga_win, &vw, sizeof(mga_win)); + + mga_config.x_org = vw.x; + mga_config.y_org = vw.y; + mga_config.dest_width = vw.width; + mga_config.dest_height = vw.height; + + /* + * May have to add + * + * #define VIDEO_WINDOW_CHROMAKEY 16 + * + * to <linux/videodev.h> + */ + + //add it here for now + #define VIDEO_WINDOW_CHROMAKEY 16 + + if (vw.flags & VIDEO_WINDOW_CHROMAKEY) + mga_config.colkey_on = 1; + else + mga_config.colkey_on = 0; + + mga_config.colkey_red = (vw.chromakey >> 24) & 0xFF; + mga_config.colkey_green = (vw.chromakey >> 16) & 0xFF; + mga_config.colkey_blue = (vw.chromakey >> 8) & 0xFF; + mga_vid_set_config(&mga_config); + return 0; + + } + case VIDIOCGWIN: + { + if(copy_to_user(arg, &mga_win, sizeof(mga_win))) + return -EFAULT; + return 0; + } + case VIDIOCCAPTURE: + { + int v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + vid_overlay_on = v; + if(vid_overlay_on && vid_src_ready) + { + //regs.besctl |= 1; + mga_vid_write_regs(); + } + else + { + //regs.besctl &= ~1; + mga_vid_write_regs(); + } + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +static struct video_device mga_v4l_dev = +{ + "Matrox G200/G400", + VID_TYPE_CAPTURE, + VID_HARDWARE_BT848, /* This is a lie for now */ + mga_v4l_open, + mga_v4l_close, + mga_v4l_read, + mga_v4l_write, + NULL, + mga_v4l_ioctl, + NULL, + mga_v4l_init_done, + NULL, + 0, + 0 +}; + +#endif + +/* + * Main Initialization Function + */ + + +static int mga_vid_initialize(void) +{ + mga_vid_in_use = 0; + + printk( "SiS 6326 YUV Video interface v0.01 (c) Aaron Holtzman \n"); + if(register_chrdev(MGA_VID_MAJOR, "mga_vid", &mga_vid_fops)) + { + printk("sis_vid: unable to get major: %d\n", MGA_VID_MAJOR); + return -EIO; + } + + if (!mga_vid_find_card()) + { + printk("sis_vid: no supported devices found\n"); + unregister_chrdev(MGA_VID_MAJOR, "mga_vid"); + return -EINVAL; + } + +#if 0 + if (video_register_device(&mga_v4l_dev, VFL_TYPE_GRABBER)<0) + { + printk("sis_vid: unable to register.\n"); + unregister_chrdev(MGA_VID_MAJOR, "mga_vid"); + if(mga_mmio_base) + iounmap(mga_mmio_base); + mga_mmio_base = 0; + return -EINVAL; + } +#endif + + return(0); +} + +int init_module(void) +{ + return mga_vid_initialize(); +} + +void cleanup_module(void) +{ +// video_unregister_device(&mga_v4l_dev); + if(mga_mmio_base) + iounmap(mga_mmio_base); + + //FIXME turn off BES + printk("mga_vid: Cleaning up module\n"); + unregister_chrdev(MGA_VID_MAJOR, "mga_vid"); +} + diff --git a/drivers/sis_vid.h b/drivers/sis_vid.h new file mode 100644 index 0000000000..a4c42cf901 --- /dev/null +++ b/drivers/sis_vid.h @@ -0,0 +1,37 @@ +/* + * + * sis_vid.h + * + * Copyright (C) 2000 Aaron Holtzman + * + * YUV Framebuffer driver for SiS 6326 cards + * + * This software has been released under the terms of the GNU Public + * license. See http://www.gnu.org/copyleft/gpl.html for details. + */ + +#include <inttypes.h> + +typedef struct mga_vid_config_s +{ +uint32_t card_type; +uint32_t ram_size; +uint32_t src_width; +uint32_t src_height; +uint32_t dest_width; +uint32_t dest_height; +uint32_t x_org; +uint32_t y_org; +uint8_t colkey_on; +uint8_t colkey_red; +uint8_t colkey_green; +uint8_t colkey_blue; +} mga_vid_config_t; + +#define MGA_VID_CONFIG _IOR('J', 1, mga_vid_config_t) +#define MGA_VID_ON _IO ('J', 2) +#define MGA_VID_OFF _IO ('J', 3) +#define MGA_VID_FSEL _IOR('J', 4, int) + +#define MGA_G200 0x1234 +#define MGA_G400 0x5678 diff --git a/help_avp.h b/help_avp.h new file mode 100644 index 0000000000..23175f6d2f --- /dev/null +++ b/help_avp.h @@ -0,0 +1,32 @@ +static char* banner_text= +"\n" +"MPlayer v0.10 [AVI parser] (C) 2000. Arpad Gereoffy <arpi@esp-team.scene.hu>\n" +"\n"; + +static char* help_text= +"Usage: aviparse [options] [path/]name\n" +"\n" +" Options:\n" +//" -o <driver> select output driver (see '-o help' for driver list)\n" +//" -vcd <track> play video cd track from device instead of plain file\n" +//" -bg play in background (X11 only!)\n" +//" -sb <bytepos> seek to byte position\n" +//" -ss <timepos> seek to second position (with timestamp)\n" +//" -nosound don't play sound\n" +//" -abs <bytes> audio buffer size (in bytes, default: measuring)\n" +//" -delay <secs> audio delay in seconds (may be +/- float value)\n" +//" -alsa enable timing code (works better with ALSA)\n" +" -aid <1-99> select audio channel\n" +" -afile <name> dump raw audio data to file\n" +" -vfile <name> dump raw video data to file\n" +//" -vid <0-15> select video channel\n" +//" -fps <value> force frame rate (if value is wrong in mpeg header)\n" +//" -mc <s/5f> maximum sync correction per 5 frames (in seconds)\n" +//" -afm <1-3> force audio format 1:MPEG 2:PCM 3:AC3 4:Win32\n" +//"\n" +//" Keys:\n" +//" <- or -> seek backward/forward 10 seconds\n" +//" up or down seek backward/forward 1 minute\n" +//" p or SPACE pause movie (press any key to continue)\n" +//" q or ^C stop playing and quit program\n" +"\n"; diff --git a/help_mp.h b/help_mp.h new file mode 100644 index 0000000000..a8de5045fc --- /dev/null +++ b/help_mp.h @@ -0,0 +1,44 @@ +static char* banner_text= +"\n" +"MPlayer " VERSION " (C) 2000-2001 Arpad Gereoffy <arpi@esp-team.scene.hu>\n" +"\n"; + +static char* help_text= +"Usage: mplayer [options] [path/]name\n" +"\n" +" Options:\n" +" -vo <driver> select output driver (see '-vo help' for driver list)\n" +" -vcd <track> play video cd track from device instead of plain file\n" +//" -bg play in background (X11 only!)\n" +" -sb <bytepos> seek to byte position\n" +//" -ss <timepos> seek to second position (with timestamp)\n" +" -nosound don't play sound\n" +" -abs <bytes> audio buffer size (in bytes, default: measuring)\n" +" -delay <secs> audio delay in seconds (may be +/- float value)\n" +#ifdef AVI_SYNC_BPS +" -nobps do not use avg. byte/sec value for A-V sync (AVI)\n" +#else +" -bps use avg. byte/sec value for A-V sync (AVI)\n" +#endif +#ifdef ALSA_TIMER +" -noalsa disable timing code\n" +#else +" -alsa enable timing code (works better with ALSA)\n" +#endif +" -aid <id> select audio channel [MPG: 0-31 AVI: 1-99]\n" +" -vid <id> select video channel [MPG: 0-15 AVI: -- ]\n" +" -fps <value> force frame rate (if value is wrong in the header)\n" +" -mc <s/5f> maximum sync correction per 5 frames (in seconds)\n" +" -afm <1-5> force audio format 1:MPEG 2:PCM 3:AC3 4:Win32 5:aLaw\n" +#ifdef X11_FULLSCREEN +" -fs fullscreen playing (only gl, xmga and xv drivers)\n" +#endif +" -x <x> -y <y> scale image to <x> * <y> resolution [if scalable!]\n" +"\n" +" Keys:\n" +" <- or -> seek backward/forward 10 seconds\n" +" up or down seek backward/forward 1 minute\n" +" p or SPACE pause movie (press any key to continue)\n" +" q or ESC stop playing and quit program\n" +" + or - adjust audio delay by +/- 0.1 second\n" +"\n"; diff --git a/liba52/srfftp.h b/liba52/srfftp.h new file mode 100644 index 0000000000..ffb228eaaa --- /dev/null +++ b/liba52/srfftp.h @@ -0,0 +1,303 @@ + +/* + * srfftp.h + * + * Copyright (C) Yuqing Deng <Yuqing_Deng@brown.edu> - April 2000 + * + * 64 and 128 point split radix fft for ac3dec + * + * The algorithm is desribed in the book: + * "Computational Frameworks of the Fast Fourier Transform". + * + * The ideas and the the organization of code borrowed from djbfft written by + * D. J. Bernstein <djb@cr.py.to>. djbff can be found at + * http://cr.yp.to/djbfft.html. + * + * srfftp.h 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. + * + * srfftp.h 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. + * + */ + +#ifndef SRFFTP_H__ +#define SRFFTP_H__ + +static complex_t delta16[4] = + { {1.00000000000000, 0.00000000000000}, + {0.92387953251129, -0.38268343236509}, + {0.70710678118655, -0.70710678118655}, + {0.38268343236509, -0.92387953251129}}; + +static complex_t delta16_3[4] = + { {1.00000000000000, 0.00000000000000}, + {0.38268343236509, -0.92387953251129}, + {-0.70710678118655, -0.70710678118655}, + {-0.92387953251129, 0.38268343236509}}; + +static complex_t delta32[8] = + { {1.00000000000000, 0.00000000000000}, + {0.98078528040323, -0.19509032201613}, + {0.92387953251129, -0.38268343236509}, + {0.83146961230255, -0.55557023301960}, + {0.70710678118655, -0.70710678118655}, + {0.55557023301960, -0.83146961230255}, + {0.38268343236509, -0.92387953251129}, + {0.19509032201613, -0.98078528040323}}; + +static complex_t delta32_3[8] = + { {1.00000000000000, 0.00000000000000}, + {0.83146961230255, -0.55557023301960}, + {0.38268343236509, -0.92387953251129}, + {-0.19509032201613, -0.98078528040323}, + {-0.70710678118655, -0.70710678118655}, + {-0.98078528040323, -0.19509032201613}, + {-0.92387953251129, 0.38268343236509}, + {-0.55557023301960, 0.83146961230255}}; + +static complex_t delta64[16] = + { {1.00000000000000, 0.00000000000000}, + {0.99518472667220, -0.09801714032956}, + {0.98078528040323, -0.19509032201613}, + {0.95694033573221, -0.29028467725446}, + {0.92387953251129, -0.38268343236509}, + {0.88192126434836, -0.47139673682600}, + {0.83146961230255, -0.55557023301960}, + {0.77301045336274, -0.63439328416365}, + {0.70710678118655, -0.70710678118655}, + {0.63439328416365, -0.77301045336274}, + {0.55557023301960, -0.83146961230255}, + {0.47139673682600, -0.88192126434835}, + {0.38268343236509, -0.92387953251129}, + {0.29028467725446, -0.95694033573221}, + {0.19509032201613, -0.98078528040323}, + {0.09801714032956, -0.99518472667220}}; + +static complex_t delta64_3[16] = + { {1.00000000000000, 0.00000000000000}, + {0.95694033573221, -0.29028467725446}, + {0.83146961230255, -0.55557023301960}, + {0.63439328416365, -0.77301045336274}, + {0.38268343236509, -0.92387953251129}, + {0.09801714032956, -0.99518472667220}, + {-0.19509032201613, -0.98078528040323}, + {-0.47139673682600, -0.88192126434836}, + {-0.70710678118655, -0.70710678118655}, + {-0.88192126434835, -0.47139673682600}, + {-0.98078528040323, -0.19509032201613}, + {-0.99518472667220, 0.09801714032956}, + {-0.92387953251129, 0.38268343236509}, + {-0.77301045336274, 0.63439328416365}, + {-0.55557023301960, 0.83146961230255}, + {-0.29028467725446, 0.95694033573221}}; + +static complex_t delta128[32] = + { {1.00000000000000, 0.00000000000000}, + {0.99879545620517, -0.04906767432742}, + {0.99518472667220, -0.09801714032956}, + {0.98917650996478, -0.14673047445536}, + {0.98078528040323, -0.19509032201613}, + {0.97003125319454, -0.24298017990326}, + {0.95694033573221, -0.29028467725446}, + {0.94154406518302, -0.33688985339222}, + {0.92387953251129, -0.38268343236509}, + {0.90398929312344, -0.42755509343028}, + {0.88192126434836, -0.47139673682600}, + {0.85772861000027, -0.51410274419322}, + {0.83146961230255, -0.55557023301960}, + {0.80320753148064, -0.59569930449243}, + {0.77301045336274, -0.63439328416365}, + {0.74095112535496, -0.67155895484702}, + {0.70710678118655, -0.70710678118655}, + {0.67155895484702, -0.74095112535496}, + {0.63439328416365, -0.77301045336274}, + {0.59569930449243, -0.80320753148064}, + {0.55557023301960, -0.83146961230255}, + {0.51410274419322, -0.85772861000027}, + {0.47139673682600, -0.88192126434835}, + {0.42755509343028, -0.90398929312344}, + {0.38268343236509, -0.92387953251129}, + {0.33688985339222, -0.94154406518302}, + {0.29028467725446, -0.95694033573221}, + {0.24298017990326, -0.97003125319454}, + {0.19509032201613, -0.98078528040323}, + {0.14673047445536, -0.98917650996478}, + {0.09801714032956, -0.99518472667220}, + {0.04906767432742, -0.99879545620517}}; + +static complex_t delta128_3[32] = + { {1.00000000000000, 0.00000000000000}, + {0.98917650996478, -0.14673047445536}, + {0.95694033573221, -0.29028467725446}, + {0.90398929312344, -0.42755509343028}, + {0.83146961230255, -0.55557023301960}, + {0.74095112535496, -0.67155895484702}, + {0.63439328416365, -0.77301045336274}, + {0.51410274419322, -0.85772861000027}, + {0.38268343236509, -0.92387953251129}, + {0.24298017990326, -0.97003125319454}, + {0.09801714032956, -0.99518472667220}, + {-0.04906767432742, -0.99879545620517}, + {-0.19509032201613, -0.98078528040323}, + {-0.33688985339222, -0.94154406518302}, + {-0.47139673682600, -0.88192126434836}, + {-0.59569930449243, -0.80320753148065}, + {-0.70710678118655, -0.70710678118655}, + {-0.80320753148065, -0.59569930449243}, + {-0.88192126434835, -0.47139673682600}, + {-0.94154406518302, -0.33688985339222}, + {-0.98078528040323, -0.19509032201613}, + {-0.99879545620517, -0.04906767432742}, + {-0.99518472667220, 0.09801714032956}, + {-0.97003125319454, 0.24298017990326}, + {-0.92387953251129, 0.38268343236509}, + {-0.85772861000027, 0.51410274419322}, + {-0.77301045336274, 0.63439328416365}, + {-0.67155895484702, 0.74095112535496}, + {-0.55557023301960, 0.83146961230255}, + {-0.42755509343028, 0.90398929312344}, + {-0.29028467725446, 0.95694033573221}, + {-0.14673047445536, 0.98917650996478}}; + +#define HSQRT2 0.707106781188; + +#define TRANSZERO(A0,A4,A8,A12) { \ + u_r = wTB[0].re; \ + v_i = u_r - wTB[k*2].re; \ + u_r += wTB[k*2].re; \ + u_i = wTB[0].im; \ + v_r = wTB[k*2].im - u_i; \ + u_i += wTB[k*2].im; \ + a_r = A0.re; \ + a_i = A0.im; \ + a1_r = a_r; \ + a1_r += u_r; \ + A0.re = a1_r; \ + a_r -= u_r; \ + A8.re = a_r; \ + a1_i = a_i; \ + a1_i += u_i; \ + A0.im = a1_i; \ + a_i -= u_i; \ + A8.im = a_i; \ + a1_r = A4.re; \ + a1_i = A4.im; \ + a_r = a1_r; \ + a_r -= v_r; \ + A4.re = a_r; \ + a1_r += v_r; \ + A12.re = a1_r; \ + a_i = a1_i; \ + a_i -= v_i; \ + A4.im = a_i; \ + a1_i += v_i; \ + A12.im = a1_i; \ + } + +#define TRANSHALF_16(A2,A6,A10,A14) {\ + u_r = wTB[2].re; \ + a_r = u_r; \ + u_i = wTB[2].im; \ + u_r += u_i; \ + u_i -= a_r; \ + a_r = wTB[6].re; \ + a1_r = a_r; \ + a_i = wTB[6].im; \ + a_r = a_i - a_r; \ + a_i += a1_r; \ + v_i = u_r - a_r; \ + u_r += a_r; \ + v_r = u_i + a_i; \ + u_i -= a_i; \ + v_i *= HSQRT2; \ + v_r *= HSQRT2; \ + u_r *= HSQRT2; \ + u_i *= HSQRT2; \ + a_r = A2.re; \ + a_i = A2.im; \ + a1_r = a_r; \ + a1_r += u_r; \ + A2.re = a1_r; \ + a_r -= u_r; \ + A10.re = a_r; \ + a1_i = a_i; \ + a1_i += u_i; \ + A2.im = a1_i; \ + a_i -= u_i; \ + A10.im = a_i; \ + a1_r = A6.re; \ + a1_i = A6.im; \ + a_r = a1_r; \ + a1_r += v_r; \ + A6.re = a1_r; \ + a_r -= v_r; \ + A14.re = a_r; \ + a_i = a1_i; \ + a1_i -= v_i; \ + A6.im = a1_i; \ + a_i += v_i; \ + A14.im = a_i; \ + } + +#define TRANS(A1,A5,A9,A13,WT,WB,D,D3) { \ + u_r = WT.re; \ + a_r = u_r; \ + a_r *= D.im; \ + u_r *= D.re; \ + a_i = WT.im; \ + a1_i = a_i; \ + a1_i *= D.re; \ + a_i *= D.im; \ + u_r -= a_i; \ + u_i = a_r; \ + u_i += a1_i; \ + a_r = WB.re; \ + a1_r = a_r; \ + a1_r *= D3.re; \ + a_r *= D3.im; \ + a_i = WB.im; \ + a1_i = a_i; \ + a_i *= D3.re; \ + a1_i *= D3.im; \ + a1_r -= a1_i; \ + a_r += a_i; \ + v_i = u_r - a1_r; \ + u_r += a1_r; \ + v_r = a_r - u_i; \ + u_i += a_r; \ + a_r = A1.re; \ + a_i = A1.im; \ + a1_r = a_r; \ + a1_r += u_r; \ + A1.re = a1_r; \ + a_r -= u_r; \ + A9.re = a_r; \ + a1_i = a_i; \ + a1_i += u_i; \ + A1.im = a1_i; \ + a_i -= u_i; \ + A9.im = a_i; \ + a1_r = A5.re; \ + a1_i = A5.im; \ + a_r = a1_r; \ + a1_r -= v_r; \ + A5.re = a1_r; \ + a_r += v_r; \ + A13.re = a_r; \ + a_i = a1_i; \ + a1_i -= v_i; \ + A5.im = a1_i; \ + a_i += v_i; \ + A13.im = a_i; \ + } + +#endif diff --git a/libmpeg2/Makefile b/libmpeg2/Makefile new file mode 100644 index 0000000000..5e2f8e8cfc --- /dev/null +++ b/libmpeg2/Makefile @@ -0,0 +1,35 @@ + +LIBNAME = libmpeg2.a + +include ../config.mak + +SRCS = decode.c header.c idct.c idct_mmx.c motion_comp.c motion_comp_mmx.c slice.c stats.c +OBJS = decode.o header.o idct.o idct_mmx.o motion_comp.o motion_comp_mmx.o slice.o stats.o +CFLAGS = $(OPTFLAGS) -DMPG12PLAY +INCLUDE = -I. -I../libvo -I.. + +.SUFFIXES: .c .o + +# .PHONY: all clean + +.c.o: + $(CC) -c $(CFLAGS) $(INCLUDE) -o $@ $< + +$(LIBNAME): $(OBJS) + $(AR) r $(LIBNAME) $(OBJS) + +all: $(LIBNAME) + +clean: + rm -f *.o *.a *~ + +distclean: + makedepend + rm -f Makefile.bak *.o *.a *~ + +dep: depend + +depend: + makedepend -- $(CFLAGS) -- $(SRCS) &> /dev/null + +# DO NOT DELETE diff --git a/libmpeg2/attributes.h b/libmpeg2/attributes.h new file mode 100644 index 0000000000..dfbf129411 --- /dev/null +++ b/libmpeg2/attributes.h @@ -0,0 +1,31 @@ +/* + * attributes.h + * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec 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. + * + * mpeg2dec 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 + */ + +//use gcc attribs to align critical data structures + +/* maximum supported data alignment */ +#define ATTRIBUTE_ALIGNED_MAX 64 + +#ifdef ATTRIBUTE_ALIGNED_MAX +#define ATTR_ALIGN(align) __attribute__ ((__aligned__ ((ATTRIBUTE_ALIGNED_MAX < align) ? ATTRIBUTE_ALIGNED_MAX : align))) +#else +#define ATTR_ALIGN(align) +#endif diff --git a/libmpeg2/decode.c b/libmpeg2/decode.c new file mode 100644 index 0000000000..e8bbb02112 --- /dev/null +++ b/libmpeg2/decode.c @@ -0,0 +1,319 @@ +/* Copyright (C) Aaron Holtzman <aholtzma@ess.engr.uvic.ca> - Nov 1999 */ +/* Some cleanup & hacking by A'rpi/ESP-team - Oct 2000 */ + +/* mpeg2dec version: */ +#define PACKAGE "mpeg2dec" +//#define VERSION "0.1.7-cvs" +#define VERSION "0.1.8-cvs" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +#include "config.h" + +//#include "video_out.h" + +#include "mpeg2.h" +#include "mpeg2_internal.h" + +#include "../linux/shmem.h" + +//#include "motion_comp.h" +//#include "idct.h" +//#include "header.h" +//#include "slice.h" +//#include "stats.h" + +#include "attributes.h" +#ifdef __i386__ +#include "mmx.h" +#endif + +//this is where we keep the state of the decoder +//picture_t picture_data; +//picture_t *picture=&picture_data; +picture_t *picture=NULL; + +//global config struct +mpeg2_config_t config; + +// the maximum chunk size is determined by vbv_buffer_size which is 224K for +// MP@ML streams. (we make no pretenses ofdecoding anything more than that) +//static uint8_t chunk_buffer[224 * 1024 + 4]; +//static uint32_t shift = 0; + +static int drop_flag = 0; +static int drop_frame = 0; + +int quant_store[MBR+1][MBC+1]; // [Review] + +void mpeg2_init (void) +{ + + printf (PACKAGE"-"VERSION" (C) 2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>\n"); + config.flags = 0; +#ifdef HAVE_MMX + config.flags |= MM_ACCEL_X86_MMX; +#endif +#ifdef HAVE_SSE + config.flags |= MM_ACCEL_X86_MMXEXT; +#endif +#ifdef HAVE_3DNOW + config.flags |= MM_ACCEL_X86_3DNOW; +#endif +#ifdef HAVE_MLIB + config.flags |= MM_ACCEL_MLIB; +#endif + + printf("libmpeg2 config flags = 0x%X\n",config.flags); + + picture=shmem_alloc(sizeof(picture_t)); // !!! NEW HACK :) !!! + + header_state_init (picture); + picture->repeat_count=0; + + picture->pp_options=0; + + idct_init (); + motion_comp_init (); +} + +void mpeg2_allocate_image_buffers (picture_t * picture) +{ + int frame_size,buff_size; + unsigned char *base=NULL; + + // height+1 requires for yuv2rgb_mmx code (it reads next line after last) + frame_size = picture->coded_picture_width * (1+picture->coded_picture_height); + frame_size = (frame_size+31)&(~31); // align to 32 byte boundary + buff_size = frame_size + (frame_size/4)*2; // 4Y + 1U + 1V + + // allocate images in YV12 format + base = shmem_alloc(buff_size); + picture->throwaway_frame[0] = base; + picture->throwaway_frame[1] = base + frame_size * 5 / 4; + picture->throwaway_frame[2] = base + frame_size; + + base = shmem_alloc(buff_size); + picture->backward_reference_frame[0] = base; + picture->backward_reference_frame[1] = base + frame_size * 5 / 4; + picture->backward_reference_frame[2] = base + frame_size; + + base = shmem_alloc(buff_size); + picture->forward_reference_frame[0] = base; + picture->forward_reference_frame[1] = base + frame_size * 5 / 4; + picture->forward_reference_frame[2] = base + frame_size; + + base = shmem_alloc(buff_size); + picture->pp_frame[0] = base; + picture->pp_frame[1] = base + frame_size * 5 / 4; + picture->pp_frame[2] = base + frame_size; + +} + +static void decode_reorder_frames (void) +{ + if (picture->picture_coding_type != B_TYPE) { + + //reuse the soon to be outdated forward reference frame + picture->current_frame[0] = picture->forward_reference_frame[0]; + picture->current_frame[1] = picture->forward_reference_frame[1]; + picture->current_frame[2] = picture->forward_reference_frame[2]; + + //make the backward reference frame the new forward reference frame + picture->forward_reference_frame[0] = + picture->backward_reference_frame[0]; + picture->forward_reference_frame[1] = + picture->backward_reference_frame[1]; + picture->forward_reference_frame[2] = + picture->backward_reference_frame[2]; + + picture->backward_reference_frame[0] = picture->current_frame[0]; + picture->backward_reference_frame[1] = picture->current_frame[1]; + picture->backward_reference_frame[2] = picture->current_frame[2]; + + } else { + + picture->current_frame[0] = picture->throwaway_frame[0]; + picture->current_frame[1] = picture->throwaway_frame[1]; + picture->current_frame[2] = picture->throwaway_frame[2]; + + } +} + +static int in_slice_flag=0; + +static int parse_chunk (vo_functions_t * output, int code, uint8_t * buffer) +{ + int is_frame_done = 0; + + stats_header (code, buffer); + + is_frame_done = in_slice_flag && ((!code) || (code >= 0xb0)); + if (is_frame_done) { + in_slice_flag = 0; + + if(picture->picture_structure != FRAME_PICTURE) printf("Field! %d \n",picture->second_field); + + if ( ((HACK_MODE == 2) || (picture->mpeg1)) + && ((picture->picture_structure == FRAME_PICTURE) || + (picture->second_field)) + ) { + uint8_t ** bar; + int stride[3]; + + if (picture->picture_coding_type == B_TYPE) + bar = picture->throwaway_frame; + else + bar = picture->forward_reference_frame; + + stride[0]=picture->coded_picture_width; + stride[1]=stride[2]=stride[0]/2; + + if(picture->pp_options){ + // apply OpenDivX postprocess filter + postprocess(bar, stride[0], + picture->pp_frame, stride[0], + picture->coded_picture_width, picture->coded_picture_height, + &quant_store[1][1], (MBC+1), picture->pp_options); + output->draw_slice (picture->pp_frame, stride, + picture->display_picture_width, + picture->display_picture_height, 0, 0); + } else { + output->draw_slice (bar, stride, + picture->display_picture_width, + picture->display_picture_height, 0, 0); + } + + } +#ifdef ARCH_X86 + if (config.flags & MM_ACCEL_X86_MMX) emms (); +#endif + output->flip_page (); + } + + switch (code) { + case 0x00: /* picture_start_code */ + if (header_process_picture_header (picture, buffer)) { + printf ("bad picture header\n"); + exit (1); + } + + drop_frame = drop_flag && (picture->picture_coding_type == B_TYPE); + //decode_reorder_frames (); + break; + + case 0xb3: /* sequence_header_code */ + if (header_process_sequence_header (picture, buffer)) { + printf ("bad sequence header\n"); + exit (1); + } + break; + + case 0xb5: /* extension_start_code */ + if (header_process_extension (picture, buffer)) { + printf ("bad extension\n"); + exit (1); + } + break; + + default: +// if (code >= 0xb9) printf ("stream not demultiplexed ?\n"); + if (code >= 0xb0) break; + + if (!(in_slice_flag)) { + in_slice_flag = 1; + + if(!(picture->second_field)) decode_reorder_frames (); + } + + if (!drop_frame) { + uint8_t ** bar; + + slice_process (picture, code, buffer); + + if ((HACK_MODE < 2) && (!(picture->mpeg1))) { + uint8_t * foo[3]; + uint8_t ** bar; + //frame_t * bar; + int stride[3]; + int offset; + + if (picture->picture_coding_type == B_TYPE) + bar = picture->throwaway_frame; + else + bar = picture->forward_reference_frame; + + offset = (code-1) * 4 * picture->coded_picture_width; + if ((! HACK_MODE) && (picture->picture_coding_type == B_TYPE)) + offset = 0; + + foo[0] = bar[0] + 4 * offset; + foo[1] = bar[1] + offset; + foo[2] = bar[2] + offset; + + stride[0]=picture->coded_picture_width; + stride[1]=stride[2]=stride[0]/2; + + output->draw_slice (foo, stride, + picture->display_picture_width, 16, 0, (code-1)*16); + } +#ifdef ARCH_X86 + if (config.flags & MM_ACCEL_X86_MMX) emms (); +#endif + + } + } + + return is_frame_done; +} + + +int mpeg2_decode_data (vo_functions_t *output, uint8_t *current, uint8_t *end) +{ + //static uint8_t code = 0xff; + //static uint8_t chunk_buffer[65536]; + //static uint8_t *chunk_ptr = chunk_buffer; + //static uint32_t shift = 0; + uint8_t code; + uint8_t *pos=NULL; + uint8_t *start=current; + int ret = 0; + +// printf("RCVD %d bytes\n",end-current); + +while(current<end){ + // FIND NEXT HEAD: + unsigned int head=-1; + uint8_t c; + //-------------------- + while(current<end){ + c=current[0]; + ++current; + head<<=8; + if(head==0x100) break; // synced + head|=c; + } + //-------------------- + if(pos){ + //if((code&0x100)!=0x100) printf("libmpeg2: FATAL! code=%X\n",code); + //printf("pos=%d chunk %3X size=%d next-code=%X\n",pos-start,code,current-pos,head|c); + ret+=parse_chunk(output, code&0xFF, pos); + } + //-------------------- + pos=current;code=head|c; +} + + if(code==0x1FF) ret+=parse_chunk(output, 0xFF, NULL); // send 'end of frame' + + return ret; +} + +void mpeg2_drop (int flag) +{ + drop_flag = flag; +} + diff --git a/libmpeg2/header.c b/libmpeg2/header.c new file mode 100644 index 0000000000..8f5b34359e --- /dev/null +++ b/libmpeg2/header.c @@ -0,0 +1,273 @@ +/* + * slice.c + * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec 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. + * + * mpeg2dec 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 + */ + +#include "config.h" + +#include <inttypes.h> + +#include "mpeg2_internal.h" +#include "attributes.h" + +// default intra quant matrix, in zig-zag order +static uint8_t default_intra_quantizer_matrix[64] ATTR_ALIGN(16) = { + 8, + 16, 16, + 19, 16, 19, + 22, 22, 22, 22, + 22, 22, 26, 24, 26, + 27, 27, 27, 26, 26, 26, + 26, 27, 27, 27, 29, 29, 29, + 34, 34, 34, 29, 29, 29, 27, 27, + 29, 29, 32, 32, 34, 34, 37, + 38, 37, 35, 35, 34, 35, + 38, 38, 40, 40, 40, + 48, 48, 46, 46, + 56, 56, 58, + 69, 69, + 83 +}; + +uint8_t scan_norm[64] ATTR_ALIGN(16) = +{ + // Zig-Zag scan pattern + 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 +}; + +uint8_t scan_alt[64] ATTR_ALIGN(16) = +{ + // Alternate scan pattern + 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 +}; + +void header_state_init (picture_t * picture) +{ + //FIXME we should set pointers to the real scan matrices here (mmx vs + //normal) instead of the ifdefs in header_process_picture_coding_extension + + picture->scan = scan_norm; +} + +static const int frameratecode2framerate[16] = { + 0, 24000*10000/1001, 24*10000,25*10000, 30000*10000/1001, 30*10000,50*10000,60000*10000/1001, + 60*10000, 0,0,0,0,0,0,0 +}; + +int header_process_sequence_header (picture_t * picture, uint8_t * buffer) +{ + unsigned int h_size; + unsigned int v_size; + int i; + + if ((buffer[6] & 0x20) != 0x20) + return 1; // missing marker_bit + + v_size = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2]; + + picture->display_picture_width = (v_size >> 12); + picture->display_picture_height = (v_size & 0xfff); + + h_size = ((v_size >> 12) + 15) & ~15; + v_size = ((v_size & 0xfff) + 15) & ~15; + + if ((h_size > 768) || (v_size > 576)) + return 1; // size restrictions for MP@ML or MPEG1 + + //XXX this needs field fixups + picture->coded_picture_width = h_size; + picture->coded_picture_height = v_size; + picture->last_mba = ((h_size * v_size) >> 8) - 1; + + // this is not used by the decoder + picture->aspect_ratio_information = buffer[3] >> 4; + picture->frame_rate_code = buffer[3] & 15; + picture->frame_rate = frameratecode2framerate[picture->frame_rate_code]; + + picture->bitrate = (buffer[4]<<10)|(buffer[5]<<2)|(buffer[6]>>6); + + if (buffer[7] & 2) { + for (i = 0; i < 64; i++) + picture->intra_quantizer_matrix[scan_norm[i]] = + (buffer[i+7] << 7) | (buffer[i+8] >> 1); + buffer += 64; + } else { + for (i = 0; i < 64; i++) + picture->intra_quantizer_matrix[scan_norm[i]] = + default_intra_quantizer_matrix [i]; + } + + if (buffer[7] & 1) { + for (i = 0; i < 64; i++) + picture->non_intra_quantizer_matrix[scan_norm[i]] = + buffer[i+8]; + } else { + for (i = 0; i < 64; i++) + picture->non_intra_quantizer_matrix[i] = 16; + } + + // MPEG1 - for testing only + picture->mpeg1 = 1; + picture->intra_dc_precision = 0; + picture->frame_pred_frame_dct = 1; + picture->q_scale_type = 0; + picture->concealment_motion_vectors = 0; + //picture->alternate_scan = 0; + picture->picture_structure = FRAME_PICTURE; + //picture->second_field = 0; + + return 0; +} + +static int header_process_sequence_extension (picture_t * picture, + uint8_t * buffer) +{ + // MPEG1 - for testing only + picture->mpeg1 = 0; + + // check chroma format, size extensions, marker bit + if(((buffer[1]>>1)&3)!=1){ + printf("This CHROMA format not yet supported :(\n"); + return 1; + } + if ((buffer[1] & 1) || (buffer[2] & 0xe0)){ + printf("Big resolution video not yet supported :(\n"); + return 1; + } + if((buffer[3] & 0x01) != 0x01) return 1; // marker bit + + + // this is not used by the decoder + picture->progressive_sequence = (buffer[1] >> 3) & 1; + + if (picture->progressive_sequence) + picture->coded_picture_height = + (picture->coded_picture_height + 31) & ~31; + picture->bitrate>>=1; // hack + + return 0; +} + +static int header_process_quant_matrix_extension (picture_t * picture, + uint8_t * buffer) +{ + int i; + + if (buffer[0] & 8) { + for (i = 0; i < 64; i++) + picture->intra_quantizer_matrix[scan_norm[i]] = + (buffer[i] << 5) | (buffer[i+1] >> 3); + buffer += 64; + } + + if (buffer[0] & 4) { + for (i = 0; i < 64; i++) + picture->non_intra_quantizer_matrix[scan_norm[i]] = + (buffer[i] << 6) | (buffer[i+1] >> 2); + } + + return 0; +} + +static int header_process_picture_coding_extension (picture_t * picture, uint8_t * buffer) +{ + //pre subtract 1 for use later in compute_motion_vector + picture->f_code[0][0] = (buffer[0] & 15) - 1; + picture->f_code[0][1] = (buffer[1] >> 4) - 1; + picture->f_code[1][0] = (buffer[1] & 15) - 1; + picture->f_code[1][1] = (buffer[2] >> 4) - 1; + + picture->intra_dc_precision = (buffer[2] >> 2) & 3; + picture->picture_structure = buffer[2] & 3; + picture->frame_pred_frame_dct = (buffer[3] >> 6) & 1; + picture->concealment_motion_vectors = (buffer[3] >> 5) & 1; + picture->q_scale_type = (buffer[3] >> 4) & 1; + picture->intra_vlc_format = (buffer[3] >> 3) & 1; + + if (buffer[3] & 4) // alternate_scan + picture->scan = scan_alt; + else + picture->scan = scan_norm; + + // these are not used by the decoder + picture->top_field_first = buffer[3] >> 7; + picture->repeat_first_field = (buffer[3] >> 1) & 1; + picture->progressive_frame = buffer[4] >> 7; + + // repeat_first implementation by A'rpi/ESP-team, based on libmpeg3: + if(picture->repeat_count>=100) picture->repeat_count=0; + if(picture->repeat_first_field){ + if(picture->progressive_sequence){ + if(picture->top_field_first) + picture->repeat_count+=200; + else + picture->repeat_count+=100; + } else + if(picture->progressive_frame){ + picture->repeat_count+=50; + } + } + + return 0; +} + +int header_process_extension (picture_t * picture, uint8_t * buffer) +{ + switch (buffer[0] & 0xf0) { + case 0x10: // sequence extension + return header_process_sequence_extension (picture, buffer); + + case 0x30: // quant matrix extension + return header_process_quant_matrix_extension (picture, buffer); + + case 0x80: // picture coding extension + return header_process_picture_coding_extension (picture, buffer); + } + + return 0; +} + +int header_process_picture_header (picture_t *picture, uint8_t * buffer) +{ + picture->picture_coding_type = (buffer [1] >> 3) & 7; + + // forward_f_code and backward_f_code - used in mpeg1 only + picture->f_code[0][1] = (buffer[3] >> 2) & 1; + picture->f_code[0][0] = + (((buffer[3] << 1) | (buffer[4] >> 7)) & 7) - 1; + picture->f_code[1][1] = (buffer[4] >> 6) & 1; + picture->f_code[1][0] = ((buffer[4] >> 3) & 7) - 1; + + // move in header_process_picture_header + picture->second_field = + (picture->picture_structure != FRAME_PICTURE) && + !(picture->second_field); + + return 0; +} diff --git a/libmpeg2/idct.c b/libmpeg2/idct.c new file mode 100644 index 0000000000..7411e176dd --- /dev/null +++ b/libmpeg2/idct.c @@ -0,0 +1,289 @@ +/* + * idct.c + * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> + * + * Portions of this code are from the MPEG software simulation group + * idct implementation. This code will be replaced with a new + * implementation soon. + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec 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. + * + * mpeg2dec 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 + */ + +/**********************************************************/ +/* inverse two dimensional DCT, Chen-Wang algorithm */ +/* (cf. IEEE ASSP-32, pp. 803-816, Aug. 1984) */ +/* 32-bit integer arithmetic (8 bit coefficients) */ +/* 11 mults, 29 adds per DCT */ +/* sE, 18.8.91 */ +/**********************************************************/ +/* coefficients extended to 12 bit for IEEE1180-1990 */ +/* compliance sE, 2.1.94 */ +/**********************************************************/ + +/* this code assumes >> to be a two's-complement arithmetic */ +/* right shift: (-2)>>1 == -1 , (-3)>>1 == -2 */ + +#include "config.h" + +#include <stdio.h> +#include <inttypes.h> + +#include "mpeg2_internal.h" +#include "mm_accel.h" + +#define W1 2841 /* 2048*sqrt (2)*cos (1*pi/16) */ +#define W2 2676 /* 2048*sqrt (2)*cos (2*pi/16) */ +#define W3 2408 /* 2048*sqrt (2)*cos (3*pi/16) */ +#define W5 1609 /* 2048*sqrt (2)*cos (5*pi/16) */ +#define W6 1108 /* 2048*sqrt (2)*cos (6*pi/16) */ +#define W7 565 /* 2048*sqrt (2)*cos (7*pi/16) */ + + +// idct main entry point +void (*idct_block_copy) (int16_t * block, uint8_t * dest, int stride); +void (*idct_block_add) (int16_t * block, uint8_t * dest, int stride); + +static void idct_block_copy_c (int16_t *block, uint8_t * dest, int stride); +static void idct_block_add_c (int16_t *block, uint8_t * dest, int stride); + +static uint8_t clip_lut[1024]; +#define CLIP(i) ((clip_lut+384)[ (i)]) + +void idct_init (void) +{ +#ifdef ARCH_X86 + if (config.flags & MM_ACCEL_X86_MMXEXT) { + fprintf (stderr, "Using MMXEXT for IDCT transform\n"); + idct_block_copy = idct_block_copy_mmxext; + idct_block_add = idct_block_add_mmxext; + idct_mmx_init (); + } else if (config.flags & MM_ACCEL_X86_MMX) { + fprintf (stderr, "Using MMX for IDCT transform\n"); + idct_block_copy = idct_block_copy_mmx; + idct_block_add = idct_block_add_mmx; + idct_mmx_init (); + } else +#endif +#ifdef LIBMPEG2_MLIB + if (config.flags & MM_ACCEL_MLIB) { + fprintf (stderr, "Using mlib for IDCT transform\n"); + idct_block_copy = idct_block_copy_mlib; + idct_block_add = idct_block_add_mlib; + } else +#endif + { + int i; + + fprintf (stderr, "No accelerated IDCT transform found\n"); + idct_block_copy = idct_block_copy_c; + idct_block_add = idct_block_add_c; + for (i = -384; i < 640; i++) + clip_lut[i+384] = (i < 0) ? 0 : ((i > 255) ? 255 : i); + } +} + +/* row (horizontal) IDCT + * + * 7 pi 1 + * dst[k] = sum c[l] * src[l] * cos ( -- * ( k + - ) * l ) + * l=0 8 2 + * + * where: c[0] = 128 + * c[1..7] = 128*sqrt (2) + */ + +static void inline idct_row (int16_t * block) +{ + int x0, x1, x2, x3, x4, x5, x6, x7, x8; + + x1 = block[4] << 11; + x2 = block[6]; + x3 = block[2]; + x4 = block[1]; + x5 = block[7]; + x6 = block[5]; + x7 = block[3]; + + /* shortcut */ + if (! (x1 | x2 | x3 | x4 | x5 | x6 | x7 )) { + block[0] = block[1] = block[2] = block[3] = block[4] = + block[5] = block[6] = block[7] = block[0]<<3; + return; + } + + x0 = (block[0] << 11) + 128; /* for proper rounding in the fourth stage */ + + /* first stage */ + x8 = W7 * (x4 + x5); + x4 = x8 + (W1 - W7) * x4; + x5 = x8 - (W1 + W7) * x5; + x8 = W3 * (x6 + x7); + x6 = x8 - (W3 - W5) * x6; + x7 = x8 - (W3 + W5) * x7; + + /* second stage */ + x8 = x0 + x1; + x0 -= x1; + x1 = W6 * (x3 + x2); + x2 = x1 - (W2 + W6) * x2; + x3 = x1 + (W2 - W6) * x3; + x1 = x4 + x6; + x4 -= x6; + x6 = x5 + x7; + x5 -= x7; + + /* third stage */ + x7 = x8 + x3; + x8 -= x3; + x3 = x0 + x2; + x0 -= x2; + x2 = (181 * (x4 + x5) + 128) >> 8; + x4 = (181 * (x4 - x5) + 128) >> 8; + + /* fourth stage */ + block[0] = (x7 + x1) >> 8; + block[1] = (x3 + x2) >> 8; + block[2] = (x0 + x4) >> 8; + block[3] = (x8 + x6) >> 8; + block[4] = (x8 - x6) >> 8; + block[5] = (x0 - x4) >> 8; + block[6] = (x3 - x2) >> 8; + block[7] = (x7 - x1) >> 8; +} + +/* column (vertical) IDCT + * + * 7 pi 1 + * dst[8*k] = sum c[l] * src[8*l] * cos ( -- * ( k + - ) * l ) + * l=0 8 2 + * + * where: c[0] = 1/1024 + * c[1..7] = (1/1024)*sqrt (2) + */ + +static void inline idct_col (int16_t *block) +{ + int x0, x1, x2, x3, x4, x5, x6, x7, x8; + + /* shortcut */ + x1 = block [8*4] << 8; + x2 = block [8*6]; + x3 = block [8*2]; + x4 = block [8*1]; + x5 = block [8*7]; + x6 = block [8*5]; + x7 = block [8*3]; + +#if 0 + if (! (x1 | x2 | x3 | x4 | x5 | x6 | x7 )) { + block[8*0] = block[8*1] = block[8*2] = block[8*3] = block[8*4] = + block[8*5] = block[8*6] = block[8*7] = (block[8*0] + 32) >> 6; + return; + } +#endif + + x0 = (block[8*0] << 8) + 8192; + + /* first stage */ + x8 = W7 * (x4 + x5) + 4; + x4 = (x8 + (W1 - W7) * x4) >> 3; + x5 = (x8 - (W1 + W7) * x5) >> 3; + x8 = W3 * (x6 + x7) + 4; + x6 = (x8 - (W3 - W5) * x6) >> 3; + x7 = (x8 - (W3 + W5) * x7) >> 3; + + /* second stage */ + x8 = x0 + x1; + x0 -= x1; + x1 = W6 * (x3 + x2) + 4; + x2 = (x1 - (W2 + W6) * x2) >> 3; + x3 = (x1 + (W2 - W6) * x3) >> 3; + x1 = x4 + x6; + x4 -= x6; + x6 = x5 + x7; + x5 -= x7; + + /* third stage */ + x7 = x8 + x3; + x8 -= x3; + x3 = x0 + x2; + x0 -= x2; + x2 = (181 * (x4 + x5) + 128) >> 8; + x4 = (181 * (x4 - x5) + 128) >> 8; + + /* fourth stage */ + block[8*0] = (x7 + x1) >> 14; + block[8*1] = (x3 + x2) >> 14; + block[8*2] = (x0 + x4) >> 14; + block[8*3] = (x8 + x6) >> 14; + block[8*4] = (x8 - x6) >> 14; + block[8*5] = (x0 - x4) >> 14; + block[8*6] = (x3 - x2) >> 14; + block[8*7] = (x7 - x1) >> 14; +} + +void idct_block_copy_c (int16_t * block, uint8_t * dest, int stride) +{ + int i; + + for (i = 0; i < 8; i++) + idct_row (block + 8 * i); + + for (i = 0; i < 8; i++) + idct_col (block + i); + + i = 8; + do { + dest[0] = CLIP (block[0]); + dest[1] = CLIP (block[1]); + dest[2] = CLIP (block[2]); + dest[3] = CLIP (block[3]); + dest[4] = CLIP (block[4]); + dest[5] = CLIP (block[5]); + dest[6] = CLIP (block[6]); + dest[7] = CLIP (block[7]); + + dest += stride; + block += 8; + } while (--i); +} + +void idct_block_add_c (int16_t * block, uint8_t * dest, int stride) +{ + int i; + + for (i = 0; i < 8; i++) + idct_row (block + 8 * i); + + for (i = 0; i < 8; i++) + idct_col (block + i); + + i = 8; + do { + dest[0] = CLIP (block[0] + dest[0]); + dest[1] = CLIP (block[1] + dest[1]); + dest[2] = CLIP (block[2] + dest[2]); + dest[3] = CLIP (block[3] + dest[3]); + dest[4] = CLIP (block[4] + dest[4]); + dest[5] = CLIP (block[5] + dest[5]); + dest[6] = CLIP (block[6] + dest[6]); + dest[7] = CLIP (block[7] + dest[7]); + + dest += stride; + block += 8; + } while (--i); +} diff --git a/libmpeg2/idct_mlib.c b/libmpeg2/idct_mlib.c new file mode 100644 index 0000000000..055ee75fa6 --- /dev/null +++ b/libmpeg2/idct_mlib.c @@ -0,0 +1,47 @@ +/* + * idct_mlib.c + * Copyright (C) 1999 Håkan Hjort <d95hjort@dtek.chalmers.se> + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec 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. + * + * mpeg2dec 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 + */ + +#include "config.h" + +#ifdef LIBMPEG2_MLIB + +#include <inttypes.h> +#include <mlib_types.h> +#include <mlib_status.h> +#include <mlib_sys.h> +#include <mlib_video.h> + +#include "mpeg2_internal.h" + +void idct_block_copy_mlib (int16_t * block, uint8_t * dest, int stride) +{ + mlib_VideoIDCT8x8_U8_S16 (dest, block, stride); +} + +void idct_block_add_mlib (int16_t * block, uint8_t * dest, int stride) +{ + // Should we use mlib_VideoIDCT_IEEE_S16_S16 here ?? + // it's ~30% slower. + mlib_VideoIDCT8x8_S16_S16 (block, block); + mlib_VideoAddBlock_U8_S16 (dest, block, stride); +} + +#endif diff --git a/libmpeg2/idct_mmx.c b/libmpeg2/idct_mmx.c new file mode 100644 index 0000000000..03ea5d7580 --- /dev/null +++ b/libmpeg2/idct_mmx.c @@ -0,0 +1,706 @@ +/* + * idct_mmx.c + * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec 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. + * + * mpeg2dec 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 + */ + +#include "config.h" + +#ifdef ARCH_X86 + +#include <inttypes.h> + +#include "mpeg2_internal.h" +#include "attributes.h" +#include "mmx.h" + +#define ROW_SHIFT 11 +#define COL_SHIFT 6 + +#define round(bias) ((int)(((bias)+0.5) * (1<<ROW_SHIFT))) +#define rounder(bias) {round (bias), round (bias)} + + +#if 0 +// C row IDCT - its just here to document the MMXEXT and MMX versions +static inline void idct_row (int16_t * row, int offset, + int16_t * table, int32_t * rounder) +{ + int C1, C2, C3, C4, C5, C6, C7; + int a0, a1, a2, a3, b0, b1, b2, b3; + + row += offset; + + C1 = table[1]; + C2 = table[2]; + C3 = table[3]; + C4 = table[4]; + C5 = table[5]; + C6 = table[6]; + C7 = table[7]; + + a0 = C4*row[0] + C2*row[2] + C4*row[4] + C6*row[6] + *rounder; + a1 = C4*row[0] + C6*row[2] - C4*row[4] - C2*row[6] + *rounder; + a2 = C4*row[0] - C6*row[2] - C4*row[4] + C2*row[6] + *rounder; + a3 = C4*row[0] - C2*row[2] + C4*row[4] - C6*row[6] + *rounder; + + b0 = C1*row[1] + C3*row[3] + C5*row[5] + C7*row[7]; + b1 = C3*row[1] - C7*row[3] - C1*row[5] - C5*row[7]; + b2 = C5*row[1] - C1*row[3] + C7*row[5] + C3*row[7]; + b3 = C7*row[1] - C5*row[3] + C3*row[5] - C1*row[7]; + + row[0] = (a0 + b0) >> ROW_SHIFT; + row[1] = (a1 + b1) >> ROW_SHIFT; + row[2] = (a2 + b2) >> ROW_SHIFT; + row[3] = (a3 + b3) >> ROW_SHIFT; + row[4] = (a3 - b3) >> ROW_SHIFT; + row[5] = (a2 - b2) >> ROW_SHIFT; + row[6] = (a1 - b1) >> ROW_SHIFT; + row[7] = (a0 - b0) >> ROW_SHIFT; +} +#endif + + +// MMXEXT row IDCT + +#define mmxext_table(c1,c2,c3,c4,c5,c6,c7) { c4, c2, -c4, -c2, \ + c4, c6, c4, c6, \ + c1, c3, -c1, -c5, \ + c5, c7, c3, -c7, \ + c4, -c6, c4, -c6, \ + -c4, c2, c4, -c2, \ + c5, -c1, c3, -c1, \ + c7, c3, c7, -c5 } + +static inline void mmxext_row_head (int16_t * row, int offset, int16_t * table) +{ + movq_m2r (*(row+offset), mm2); // mm2 = x6 x4 x2 x0 + + movq_m2r (*(row+offset+4), mm5); // mm5 = x7 x5 x3 x1 + movq_r2r (mm2, mm0); // mm0 = x6 x4 x2 x0 + + movq_m2r (*table, mm3); // mm3 = -C2 -C4 C2 C4 + movq_r2r (mm5, mm6); // mm6 = x7 x5 x3 x1 + + movq_m2r (*(table+4), mm4); // mm4 = C6 C4 C6 C4 + pmaddwd_r2r (mm0, mm3); // mm3 = -C4*x4-C2*x6 C4*x0+C2*x2 + + pshufw_r2r (mm2, mm2, 0x4e); // mm2 = x2 x0 x6 x4 +} + +static inline void mmxext_row (int16_t * table, int32_t * rounder) +{ + movq_m2r (*(table+8), mm1); // mm1 = -C5 -C1 C3 C1 + pmaddwd_r2r (mm2, mm4); // mm4 = C4*x0+C6*x2 C4*x4+C6*x6 + + pmaddwd_m2r (*(table+16), mm0); // mm0 = C4*x4-C6*x6 C4*x0-C6*x2 + pshufw_r2r (mm6, mm6, 0x4e); // mm6 = x3 x1 x7 x5 + + movq_m2r (*(table+12), mm7); // mm7 = -C7 C3 C7 C5 + pmaddwd_r2r (mm5, mm1); // mm1 = -C1*x5-C5*x7 C1*x1+C3*x3 + + paddd_m2r (*rounder, mm3); // mm3 += rounder + pmaddwd_r2r (mm6, mm7); // mm7 = C3*x1-C7*x3 C5*x5+C7*x7 + + pmaddwd_m2r (*(table+20), mm2); // mm2 = C4*x0-C2*x2 -C4*x4+C2*x6 + paddd_r2r (mm4, mm3); // mm3 = a1 a0 + rounder + + pmaddwd_m2r (*(table+24), mm5); // mm5 = C3*x5-C1*x7 C5*x1-C1*x3 + movq_r2r (mm3, mm4); // mm4 = a1 a0 + rounder + + pmaddwd_m2r (*(table+28), mm6); // mm6 = C7*x1-C5*x3 C7*x5+C3*x7 + paddd_r2r (mm7, mm1); // mm1 = b1 b0 + + paddd_m2r (*rounder, mm0); // mm0 += rounder + psubd_r2r (mm1, mm3); // mm3 = a1-b1 a0-b0 + rounder + + psrad_i2r (ROW_SHIFT, mm3); // mm3 = y6 y7 + paddd_r2r (mm4, mm1); // mm1 = a1+b1 a0+b0 + rounder + + paddd_r2r (mm2, mm0); // mm0 = a3 a2 + rounder + psrad_i2r (ROW_SHIFT, mm1); // mm1 = y1 y0 + + paddd_r2r (mm6, mm5); // mm5 = b3 b2 + movq_r2r (mm0, mm4); // mm4 = a3 a2 + rounder + + paddd_r2r (mm5, mm0); // mm0 = a3+b3 a2+b2 + rounder + psubd_r2r (mm5, mm4); // mm4 = a3-b3 a2-b2 + rounder +} + +static inline void mmxext_row_tail (int16_t * row, int store) +{ + psrad_i2r (ROW_SHIFT, mm0); // mm0 = y3 y2 + + psrad_i2r (ROW_SHIFT, mm4); // mm4 = y4 y5 + + packssdw_r2r (mm0, mm1); // mm1 = y3 y2 y1 y0 + + packssdw_r2r (mm3, mm4); // mm4 = y6 y7 y4 y5 + + movq_r2m (mm1, *(row+store)); // save y3 y2 y1 y0 + pshufw_r2r (mm4, mm4, 0xb1); // mm4 = y7 y6 y5 y4 + + // slot + + movq_r2m (mm4, *(row+store+4)); // save y7 y6 y5 y4 +} + +static inline void mmxext_row_mid (int16_t * row, int store, + int offset, int16_t * table) +{ + movq_m2r (*(row+offset), mm2); // mm2 = x6 x4 x2 x0 + psrad_i2r (ROW_SHIFT, mm0); // mm0 = y3 y2 + + movq_m2r (*(row+offset+4), mm5); // mm5 = x7 x5 x3 x1 + psrad_i2r (ROW_SHIFT, mm4); // mm4 = y4 y5 + + packssdw_r2r (mm0, mm1); // mm1 = y3 y2 y1 y0 + movq_r2r (mm5, mm6); // mm6 = x7 x5 x3 x1 + + packssdw_r2r (mm3, mm4); // mm4 = y6 y7 y4 y5 + movq_r2r (mm2, mm0); // mm0 = x6 x4 x2 x0 + + movq_r2m (mm1, *(row+store)); // save y3 y2 y1 y0 + pshufw_r2r (mm4, mm4, 0xb1); // mm4 = y7 y6 y5 y4 + + movq_m2r (*table, mm3); // mm3 = -C2 -C4 C2 C4 + movq_r2m (mm4, *(row+store+4)); // save y7 y6 y5 y4 + + pmaddwd_r2r (mm0, mm3); // mm3 = -C4*x4-C2*x6 C4*x0+C2*x2 + + movq_m2r (*(table+4), mm4); // mm4 = C6 C4 C6 C4 + pshufw_r2r (mm2, mm2, 0x4e); // mm2 = x2 x0 x6 x4 +} + + +// MMX row IDCT + +#define mmx_table(c1,c2,c3,c4,c5,c6,c7) { c4, c2, c4, c6, \ + c4, c6, -c4, -c2, \ + c1, c3, c3, -c7, \ + c5, c7, -c1, -c5, \ + c4, -c6, c4, -c2, \ + -c4, c2, c4, -c6, \ + c5, -c1, c7, -c5, \ + c7, c3, c3, -c1 } + +static inline void mmx_row_head (int16_t * row, int offset, int16_t * table) +{ + movq_m2r (*(row+offset), mm2); // mm2 = x6 x4 x2 x0 + + movq_m2r (*(row+offset+4), mm5); // mm5 = x7 x5 x3 x1 + movq_r2r (mm2, mm0); // mm0 = x6 x4 x2 x0 + + movq_m2r (*table, mm3); // mm3 = C6 C4 C2 C4 + movq_r2r (mm5, mm6); // mm6 = x7 x5 x3 x1 + + punpckldq_r2r (mm0, mm0); // mm0 = x2 x0 x2 x0 + + movq_m2r (*(table+4), mm4); // mm4 = -C2 -C4 C6 C4 + pmaddwd_r2r (mm0, mm3); // mm3 = C4*x0+C6*x2 C4*x0+C2*x2 + + movq_m2r (*(table+8), mm1); // mm1 = -C7 C3 C3 C1 + punpckhdq_r2r (mm2, mm2); // mm2 = x6 x4 x6 x4 +} + +static inline void mmx_row (int16_t * table, int32_t * rounder) +{ + pmaddwd_r2r (mm2, mm4); // mm4 = -C4*x4-C2*x6 C4*x4+C6*x6 + punpckldq_r2r (mm5, mm5); // mm5 = x3 x1 x3 x1 + + pmaddwd_m2r (*(table+16), mm0); // mm0 = C4*x0-C2*x2 C4*x0-C6*x2 + punpckhdq_r2r (mm6, mm6); // mm6 = x7 x5 x7 x5 + + movq_m2r (*(table+12), mm7); // mm7 = -C5 -C1 C7 C5 + pmaddwd_r2r (mm5, mm1); // mm1 = C3*x1-C7*x3 C1*x1+C3*x3 + + paddd_m2r (*rounder, mm3); // mm3 += rounder + pmaddwd_r2r (mm6, mm7); // mm7 = -C1*x5-C5*x7 C5*x5+C7*x7 + + pmaddwd_m2r (*(table+20), mm2); // mm2 = C4*x4-C6*x6 -C4*x4+C2*x6 + paddd_r2r (mm4, mm3); // mm3 = a1 a0 + rounder + + pmaddwd_m2r (*(table+24), mm5); // mm5 = C7*x1-C5*x3 C5*x1-C1*x3 + movq_r2r (mm3, mm4); // mm4 = a1 a0 + rounder + + pmaddwd_m2r (*(table+28), mm6); // mm6 = C3*x5-C1*x7 C7*x5+C3*x7 + paddd_r2r (mm7, mm1); // mm1 = b1 b0 + + paddd_m2r (*rounder, mm0); // mm0 += rounder + psubd_r2r (mm1, mm3); // mm3 = a1-b1 a0-b0 + rounder + + psrad_i2r (ROW_SHIFT, mm3); // mm3 = y6 y7 + paddd_r2r (mm4, mm1); // mm1 = a1+b1 a0+b0 + rounder + + paddd_r2r (mm2, mm0); // mm0 = a3 a2 + rounder + psrad_i2r (ROW_SHIFT, mm1); // mm1 = y1 y0 + + paddd_r2r (mm6, mm5); // mm5 = b3 b2 + movq_r2r (mm0, mm7); // mm7 = a3 a2 + rounder + + paddd_r2r (mm5, mm0); // mm0 = a3+b3 a2+b2 + rounder + psubd_r2r (mm5, mm7); // mm7 = a3-b3 a2-b2 + rounder +} + +static inline void mmx_row_tail (int16_t * row, int store) +{ + psrad_i2r (ROW_SHIFT, mm0); // mm0 = y3 y2 + + psrad_i2r (ROW_SHIFT, mm7); // mm7 = y4 y5 + + packssdw_r2r (mm0, mm1); // mm1 = y3 y2 y1 y0 + + packssdw_r2r (mm3, mm7); // mm7 = y6 y7 y4 y5 + + movq_r2m (mm1, *(row+store)); // save y3 y2 y1 y0 + movq_r2r (mm7, mm4); // mm4 = y6 y7 y4 y5 + + pslld_i2r (16, mm7); // mm7 = y7 0 y5 0 + + psrld_i2r (16, mm4); // mm4 = 0 y6 0 y4 + + por_r2r (mm4, mm7); // mm7 = y7 y6 y5 y4 + + // slot + + movq_r2m (mm7, *(row+store+4)); // save y7 y6 y5 y4 +} + +static inline void mmx_row_mid (int16_t * row, int store, + int offset, int16_t * table) +{ + movq_m2r (*(row+offset), mm2); // mm2 = x6 x4 x2 x0 + psrad_i2r (ROW_SHIFT, mm0); // mm0 = y3 y2 + + movq_m2r (*(row+offset+4), mm5); // mm5 = x7 x5 x3 x1 + psrad_i2r (ROW_SHIFT, mm7); // mm7 = y4 y5 + + packssdw_r2r (mm0, mm1); // mm1 = y3 y2 y1 y0 + movq_r2r (mm5, mm6); // mm6 = x7 x5 x3 x1 + + packssdw_r2r (mm3, mm7); // mm7 = y6 y7 y4 y5 + movq_r2r (mm2, mm0); // mm0 = x6 x4 x2 x0 + + movq_r2m (mm1, *(row+store)); // save y3 y2 y1 y0 + movq_r2r (mm7, mm1); // mm1 = y6 y7 y4 y5 + + punpckldq_r2r (mm0, mm0); // mm0 = x2 x0 x2 x0 + psrld_i2r (16, mm7); // mm7 = 0 y6 0 y4 + + movq_m2r (*table, mm3); // mm3 = C6 C4 C2 C4 + pslld_i2r (16, mm1); // mm1 = y7 0 y5 0 + + movq_m2r (*(table+4), mm4); // mm4 = -C2 -C4 C6 C4 + por_r2r (mm1, mm7); // mm7 = y7 y6 y5 y4 + + movq_m2r (*(table+8), mm1); // mm1 = -C7 C3 C3 C1 + punpckhdq_r2r (mm2, mm2); // mm2 = x6 x4 x6 x4 + + movq_r2m (mm7, *(row+store+4)); // save y7 y6 y5 y4 + pmaddwd_r2r (mm0, mm3); // mm3 = C4*x0+C6*x2 C4*x0+C2*x2 +} + + +#if 0 +// C column IDCT - its just here to document the MMXEXT and MMX versions +static inline void idct_col (int16_t * col, int offset) +{ +// multiplication - as implemented on mmx +#define F(c,x) (((c) * (x)) >> 16) + +// saturation - it helps us handle torture test cases +#define S(x) (((x)>32767) ? 32767 : ((x)<-32768) ? -32768 : (x)) + + int16_t x0, x1, x2, x3, x4, x5, x6, x7; + int16_t y0, y1, y2, y3, y4, y5, y6, y7; + int16_t a0, a1, a2, a3, b0, b1, b2, b3; + int16_t u04, v04, u26, v26, u17, v17, u35, v35, u12, v12; + + col += offset; + + x0 = col[0*8]; + x1 = col[1*8]; + x2 = col[2*8]; + x3 = col[3*8]; + x4 = col[4*8]; + x5 = col[5*8]; + x6 = col[6*8]; + x7 = col[7*8]; + + u04 = S (x0 + x4); + v04 = S (x0 - x4); + u26 = S (F (T2, x6) + x2); // -0.5 + v26 = S (F (T2, x2) - x6); // -0.5 + + a0 = S (u04 + u26); + a1 = S (v04 + v26); + a2 = S (v04 - v26); + a3 = S (u04 - u26); + + u17 = S (F (T1, x7) + x1); // -0.5 + v17 = S (F (T1, x1) - x7); // -0.5 + u35 = S (F (T3, x5) + x3); // -0.5 + v35 = S (F (T3, x3) - x5); // -0.5 + + b0 = S (u17 + u35); + b3 = S (v17 - v35); + u12 = S (u17 - u35); + v12 = S (v17 + v35); + u12 = S (2 * F (C4, u12)); // -0.5 + v12 = S (2 * F (C4, v12)); // -0.5 + b1 = S (u12 + v12); + b2 = S (u12 - v12); + + y0 = S (a0 + b0) >> COL_SHIFT; + y1 = S (a1 + b1) >> COL_SHIFT; + y2 = S (a2 + b2) >> COL_SHIFT; + y3 = S (a3 + b3) >> COL_SHIFT; + + y4 = S (a3 - b3) >> COL_SHIFT; + y5 = S (a2 - b2) >> COL_SHIFT; + y6 = S (a1 - b1) >> COL_SHIFT; + y7 = S (a0 - b0) >> COL_SHIFT; + + col[0*8] = y0; + col[1*8] = y1; + col[2*8] = y2; + col[3*8] = y3; + col[4*8] = y4; + col[5*8] = y5; + col[6*8] = y6; + col[7*8] = y7; +} +#endif + + +// MMX column IDCT +static inline void idct_col (int16_t * col, int offset) +{ +#define T1 13036 +#define T2 27146 +#define T3 43790 +#define C4 23170 + + static short _T1[] ATTR_ALIGN(8) = {T1,T1,T1,T1}; + static short _T2[] ATTR_ALIGN(8) = {T2,T2,T2,T2}; + static short _T3[] ATTR_ALIGN(8) = {T3,T3,T3,T3}; + static short _C4[] ATTR_ALIGN(8) = {C4,C4,C4,C4}; + static mmx_t scratch0, scratch1; + + /* column code adapted from peter gubanov */ + /* http://www.elecard.com/peter/idct.shtml */ + + movq_m2r (*_T1, mm0); // mm0 = T1 + + movq_m2r (*(col+offset+1*8), mm1); // mm1 = x1 + movq_r2r (mm0, mm2); // mm2 = T1 + + movq_m2r (*(col+offset+7*8), mm4); // mm4 = x7 + pmulhw_r2r (mm1, mm0); // mm0 = T1*x1 + + movq_m2r (*_T3, mm5); // mm5 = T3 + pmulhw_r2r (mm4, mm2); // mm2 = T1*x7 + + movq_m2r (*(col+offset+5*8), mm6); // mm6 = x5 + movq_r2r (mm5, mm7); // mm7 = T3-1 + + movq_m2r (*(col+offset+3*8), mm3); // mm3 = x3 + psubsw_r2r (mm4, mm0); // mm0 = v17 + + movq_m2r (*_T2, mm4); // mm4 = T2 + pmulhw_r2r (mm3, mm5); // mm5 = (T3-1)*x3 + + paddsw_r2r (mm2, mm1); // mm1 = u17 + pmulhw_r2r (mm6, mm7); // mm7 = (T3-1)*x5 + + // slot + + movq_r2r (mm4, mm2); // mm2 = T2 + paddsw_r2r (mm3, mm5); // mm5 = T3*x3 + + pmulhw_m2r (*(col+offset+2*8), mm4);// mm4 = T2*x2 + paddsw_r2r (mm6, mm7); // mm7 = T3*x5 + + psubsw_r2r (mm6, mm5); // mm5 = v35 + paddsw_r2r (mm3, mm7); // mm7 = u35 + + movq_m2r (*(col+offset+6*8), mm3); // mm3 = x6 + movq_r2r (mm0, mm6); // mm6 = v17 + + pmulhw_r2r (mm3, mm2); // mm2 = T2*x6 + psubsw_r2r (mm5, mm0); // mm0 = b3 + + psubsw_r2r (mm3, mm4); // mm4 = v26 + paddsw_r2r (mm6, mm5); // mm5 = v12 + + movq_r2m (mm0, scratch0); // save b3 + movq_r2r (mm1, mm6); // mm6 = u17 + + paddsw_m2r (*(col+offset+2*8), mm2);// mm2 = u26 + paddsw_r2r (mm7, mm6); // mm6 = b0 + + psubsw_r2r (mm7, mm1); // mm1 = u12 + movq_r2r (mm1, mm7); // mm7 = u12 + + movq_m2r (*(col+offset+0*8), mm3); // mm3 = x0 + paddsw_r2r (mm5, mm1); // mm1 = u12+v12 + + movq_m2r (*_C4, mm0); // mm0 = C4/2 + psubsw_r2r (mm5, mm7); // mm7 = u12-v12 + + movq_r2m (mm6, scratch1); // save b0 + pmulhw_r2r (mm0, mm1); // mm1 = b1/2 + + movq_r2r (mm4, mm6); // mm6 = v26 + pmulhw_r2r (mm0, mm7); // mm7 = b2/2 + + movq_m2r (*(col+offset+4*8), mm5); // mm5 = x4 + movq_r2r (mm3, mm0); // mm0 = x0 + + psubsw_r2r (mm5, mm3); // mm3 = v04 + paddsw_r2r (mm5, mm0); // mm0 = u04 + + paddsw_r2r (mm3, mm4); // mm4 = a1 + movq_r2r (mm0, mm5); // mm5 = u04 + + psubsw_r2r (mm6, mm3); // mm3 = a2 + paddsw_r2r (mm2, mm5); // mm5 = a0 + + paddsw_r2r (mm1, mm1); // mm1 = b1 + psubsw_r2r (mm2, mm0); // mm0 = a3 + + paddsw_r2r (mm7, mm7); // mm7 = b2 + movq_r2r (mm3, mm2); // mm2 = a2 + + movq_r2r (mm4, mm6); // mm6 = a1 + paddsw_r2r (mm7, mm3); // mm3 = a2+b2 + + psraw_i2r (COL_SHIFT, mm3); // mm3 = y2 + paddsw_r2r (mm1, mm4); // mm4 = a1+b1 + + psraw_i2r (COL_SHIFT, mm4); // mm4 = y1 + psubsw_r2r (mm1, mm6); // mm6 = a1-b1 + + movq_m2r (scratch1, mm1); // mm1 = b0 + psubsw_r2r (mm7, mm2); // mm2 = a2-b2 + + psraw_i2r (COL_SHIFT, mm6); // mm6 = y6 + movq_r2r (mm5, mm7); // mm7 = a0 + + movq_r2m (mm4, *(col+offset+1*8)); // save y1 + psraw_i2r (COL_SHIFT, mm2); // mm2 = y5 + + movq_r2m (mm3, *(col+offset+2*8)); // save y2 + paddsw_r2r (mm1, mm5); // mm5 = a0+b0 + + movq_m2r (scratch0, mm4); // mm4 = b3 + psubsw_r2r (mm1, mm7); // mm7 = a0-b0 + + psraw_i2r (COL_SHIFT, mm5); // mm5 = y0 + movq_r2r (mm0, mm3); // mm3 = a3 + + movq_r2m (mm2, *(col+offset+5*8)); // save y5 + psubsw_r2r (mm4, mm3); // mm3 = a3-b3 + + psraw_i2r (COL_SHIFT, mm7); // mm7 = y7 + paddsw_r2r (mm0, mm4); // mm4 = a3+b3 + + movq_r2m (mm5, *(col+offset+0*8)); // save y0 + psraw_i2r (COL_SHIFT, mm3); // mm3 = y4 + + movq_r2m (mm6, *(col+offset+6*8)); // save y6 + psraw_i2r (COL_SHIFT, mm4); // mm4 = y3 + + movq_r2m (mm7, *(col+offset+7*8)); // save y7 + + movq_r2m (mm3, *(col+offset+4*8)); // save y4 + + movq_r2m (mm4, *(col+offset+3*8)); // save y3 +} + + +static int32_t rounder0[] ATTR_ALIGN(8) = + rounder ((1 << (COL_SHIFT - 1)) - 0.5); +static int32_t rounder4[] ATTR_ALIGN(8) = rounder (0); +static int32_t rounder1[] ATTR_ALIGN(8) = + rounder (1.25683487303); // C1*(C1/C4+C1+C7)/2 +static int32_t rounder7[] ATTR_ALIGN(8) = + rounder (-0.25); // C1*(C7/C4+C7-C1)/2 +static int32_t rounder2[] ATTR_ALIGN(8) = + rounder (0.60355339059); // C2 * (C6+C2)/2 +static int32_t rounder6[] ATTR_ALIGN(8) = + rounder (-0.25); // C2 * (C6-C2)/2 +static int32_t rounder3[] ATTR_ALIGN(8) = + rounder (0.087788325588); // C3*(-C3/C4+C3+C5)/2 +static int32_t rounder5[] ATTR_ALIGN(8) = + rounder (-0.441341716183); // C3*(-C5/C4+C5-C3)/2 + + +#define declare_idct(idct,table,idct_row_head,idct_row,idct_row_tail,idct_row_mid) \ +static inline void idct (int16_t * block) \ +{ \ + static int16_t table04[] ATTR_ALIGN(16) = \ + table (22725, 21407, 19266, 16384, 12873, 8867, 4520); \ + static int16_t table17[] ATTR_ALIGN(16) = \ + table (31521, 29692, 26722, 22725, 17855, 12299, 6270); \ + static int16_t table26[] ATTR_ALIGN(16) = \ + table (29692, 27969, 25172, 21407, 16819, 11585, 5906); \ + static int16_t table35[] ATTR_ALIGN(16) = \ + table (26722, 25172, 22654, 19266, 15137, 10426, 5315); \ + \ + idct_row_head (block, 0*8, table04); \ + idct_row (table04, rounder0); \ + idct_row_mid (block, 0*8, 4*8, table04); \ + idct_row (table04, rounder4); \ + idct_row_mid (block, 4*8, 1*8, table17); \ + idct_row (table17, rounder1); \ + idct_row_mid (block, 1*8, 7*8, table17); \ + idct_row (table17, rounder7); \ + idct_row_mid (block, 7*8, 2*8, table26); \ + idct_row (table26, rounder2); \ + idct_row_mid (block, 2*8, 6*8, table26); \ + idct_row (table26, rounder6); \ + idct_row_mid (block, 6*8, 3*8, table35); \ + idct_row (table35, rounder3); \ + idct_row_mid (block, 3*8, 5*8, table35); \ + idct_row (table35, rounder5); \ + idct_row_tail (block, 5*8); \ + \ + idct_col (block, 0); \ + idct_col (block, 4); \ +} + + +#define COPY_MMX(offset,r0,r1,r2) \ +do { \ + movq_m2r (*(block+offset), r0); \ + dest += stride; \ + movq_m2r (*(block+offset+4), r1); \ + movq_r2m (r2, *dest); \ + packuswb_r2r (r1, r0); \ +} while (0) + +static void block_copy (int16_t * block, uint8_t * dest, int stride) +{ + movq_m2r (*(block+0*8), mm0); + movq_m2r (*(block+0*8+4), mm1); + movq_m2r (*(block+1*8), mm2); + packuswb_r2r (mm1, mm0); + movq_m2r (*(block+1*8+4), mm3); + movq_r2m (mm0, *dest); + packuswb_r2r (mm3, mm2); + COPY_MMX (2*8, mm0, mm1, mm2); + COPY_MMX (3*8, mm2, mm3, mm0); + COPY_MMX (4*8, mm0, mm1, mm2); + COPY_MMX (5*8, mm2, mm3, mm0); + COPY_MMX (6*8, mm0, mm1, mm2); + COPY_MMX (7*8, mm2, mm3, mm0); + movq_r2m (mm2, *(dest+stride)); +} + + +#define ADD_MMX(offset,r1,r2,r3,r4) \ +do { \ + movq_m2r (*(dest+2*stride), r1); \ + packuswb_r2r (r4, r3); \ + movq_r2r (r1, r2); \ + dest += stride; \ + movq_r2m (r3, *dest); \ + punpcklbw_r2r (mm0, r1); \ + paddsw_m2r (*(block+offset), r1); \ + punpckhbw_r2r (mm0, r2); \ + paddsw_m2r (*(block+offset+4), r2); \ +} while (0) + +static void block_add (int16_t * block, uint8_t * dest, int stride) +{ + movq_m2r (*dest, mm1); + pxor_r2r (mm0, mm0); + movq_m2r (*(dest+stride), mm3); + movq_r2r (mm1, mm2); + punpcklbw_r2r (mm0, mm1); + movq_r2r (mm3, mm4); + paddsw_m2r (*(block+0*8), mm1); + punpckhbw_r2r (mm0, mm2); + paddsw_m2r (*(block+0*8+4), mm2); + punpcklbw_r2r (mm0, mm3); + paddsw_m2r (*(block+1*8), mm3); + packuswb_r2r (mm2, mm1); + punpckhbw_r2r (mm0, mm4); + movq_r2m (mm1, *dest); + paddsw_m2r (*(block+1*8+4), mm4); + ADD_MMX (2*8, mm1, mm2, mm3, mm4); + ADD_MMX (3*8, mm3, mm4, mm1, mm2); + ADD_MMX (4*8, mm1, mm2, mm3, mm4); + ADD_MMX (5*8, mm3, mm4, mm1, mm2); + ADD_MMX (6*8, mm1, mm2, mm3, mm4); + ADD_MMX (7*8, mm3, mm4, mm1, mm2); + packuswb_r2r (mm4, mm3); + movq_r2m (mm3, *(dest+stride)); +} + + +declare_idct (mmxext_idct, mmxext_table, + mmxext_row_head, mmxext_row, mmxext_row_tail, mmxext_row_mid) + +void idct_block_copy_mmxext (int16_t * block, uint8_t * dest, int stride) +{ + mmxext_idct (block); + block_copy (block, dest, stride); +} + +void idct_block_add_mmxext (int16_t * block, uint8_t * dest, int stride) +{ + mmxext_idct (block); + block_add (block, dest, stride); +} + + +declare_idct (mmx_idct, mmx_table, + mmx_row_head, mmx_row, mmx_row_tail, mmx_row_mid) + +void idct_block_copy_mmx (int16_t * block, uint8_t * dest, int stride) +{ + mmx_idct (block); + block_copy (block, dest, stride); +} + +void idct_block_add_mmx (int16_t * block, uint8_t * dest, int stride) +{ + mmx_idct (block); + block_add (block, dest, stride); +} + + +void idct_mmx_init (void) +{ + extern uint8_t scan_norm[64]; + extern uint8_t scan_alt[64]; + int i, j; + + // the mmx/mmxext idct uses a reordered input, so we patch scan tables + + for (i = 0; i < 64; i++) { + j = scan_norm[i]; + scan_norm[i] = (j & 0x38) | ((j & 6) >> 1) | ((j & 1) << 2); + j = scan_alt[i]; + scan_alt[i] = (j & 0x38) | ((j & 6) >> 1) | ((j & 1) << 2); + } +} + +#endif diff --git a/libmpeg2/mm_accel.h b/libmpeg2/mm_accel.h new file mode 100644 index 0000000000..133d6acb03 --- /dev/null +++ b/libmpeg2/mm_accel.h @@ -0,0 +1,30 @@ +/* + * oms_accel.h + * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec 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. + * + * mpeg2dec 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 + */ + +// generic accelerations +#define MM_ACCEL_MLIB 0x00000001 + +// x86 accelerations +#define MM_ACCEL_X86_MMX 0x80000000 +#define MM_ACCEL_X86_3DNOW 0x40000000 +#define MM_ACCEL_X86_MMXEXT 0x20000000 + +//uint32_t mm_accel (void); diff --git a/libmpeg2/mmx.h b/libmpeg2/mmx.h new file mode 100644 index 0000000000..bab97b8b1f --- /dev/null +++ b/libmpeg2/mmx.h @@ -0,0 +1,255 @@ +/* + * mmx.h + * Copyright (C) 1997-1999 H. Dietz and R. Fisher + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec 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. + * + * mpeg2dec 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 + */ + +/* + * 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 */ +} ATTR_ALIGN(8) mmx_t; /* On an 8-byte (64-bit) boundary */ + + +#define mmx_i2r(op,imm,reg) \ + __asm__ __volatile__ (#op " %0, %%" #reg \ + : /* nothing */ \ + : "X" (imm) ) + +#define mmx_m2r(op,mem,reg) \ + __asm__ __volatile__ (#op " %0, %%" #reg \ + : /* nothing */ \ + : "X" (mem)) + +#define mmx_r2m(op,reg,mem) \ + __asm__ __volatile__ (#op " %%" #reg ", %0" \ + : "=X" (mem) \ + : /* nothing */ ) + +#define mmx_r2r(op,regs,regd) \ + __asm__ __volatile__ (#op " %" #regs ", %" #regd) + + +#define emms() __asm__ __volatile__ ("emms") + +#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 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 packssdw_m2r(var,reg) mmx_m2r (packssdw, var, reg) +#define packssdw_r2r(regs,regd) mmx_r2r (packssdw, regs, regd) +#define packsswb_m2r(var,reg) mmx_m2r (packsswb, var, reg) +#define packsswb_r2r(regs,regd) mmx_r2r (packsswb, regs, regd) + +#define packuswb_m2r(var,reg) mmx_m2r (packuswb, var, reg) +#define packuswb_r2r(regs,regd) mmx_r2r (packuswb, regs, regd) + +#define paddb_m2r(var,reg) mmx_m2r (paddb, var, reg) +#define paddb_r2r(regs,regd) mmx_r2r (paddb, regs, regd) +#define paddd_m2r(var,reg) mmx_m2r (paddd, var, reg) +#define paddd_r2r(regs,regd) mmx_r2r (paddd, regs, regd) +#define paddw_m2r(var,reg) mmx_m2r (paddw, var, reg) +#define paddw_r2r(regs,regd) mmx_r2r (paddw, regs, regd) + +#define paddsb_m2r(var,reg) mmx_m2r (paddsb, var, reg) +#define paddsb_r2r(regs,regd) mmx_r2r (paddsb, regs, regd) +#define paddsw_m2r(var,reg) mmx_m2r (paddsw, var, reg) +#define paddsw_r2r(regs,regd) mmx_r2r (paddsw, regs, regd) + +#define paddusb_m2r(var,reg) mmx_m2r (paddusb, var, reg) +#define paddusb_r2r(regs,regd) mmx_r2r (paddusb, regs, regd) +#define paddusw_m2r(var,reg) mmx_m2r (paddusw, var, reg) +#define paddusw_r2r(regs,regd) mmx_r2r (paddusw, regs, regd) + +#define pand_m2r(var,reg) mmx_m2r (pand, var, reg) +#define pand_r2r(regs,regd) mmx_r2r (pand, regs, regd) + +#define pandn_m2r(var,reg) mmx_m2r (pandn, var, reg) +#define pandn_r2r(regs,regd) mmx_r2r (pandn, regs, regd) + +#define pcmpeqb_m2r(var,reg) mmx_m2r (pcmpeqb, var, reg) +#define pcmpeqb_r2r(regs,regd) mmx_r2r (pcmpeqb, regs, regd) +#define pcmpeqd_m2r(var,reg) mmx_m2r (pcmpeqd, var, reg) +#define pcmpeqd_r2r(regs,regd) mmx_r2r (pcmpeqd, regs, regd) +#define pcmpeqw_m2r(var,reg) mmx_m2r (pcmpeqw, var, reg) +#define pcmpeqw_r2r(regs,regd) mmx_r2r (pcmpeqw, regs, regd) + +#define pcmpgtb_m2r(var,reg) mmx_m2r (pcmpgtb, var, reg) +#define pcmpgtb_r2r(regs,regd) mmx_r2r (pcmpgtb, regs, regd) +#define pcmpgtd_m2r(var,reg) mmx_m2r (pcmpgtd, var, reg) +#define pcmpgtd_r2r(regs,regd) mmx_r2r (pcmpgtd, regs, regd) +#define pcmpgtw_m2r(var,reg) mmx_m2r (pcmpgtw, var, reg) +#define pcmpgtw_r2r(regs,regd) mmx_r2r (pcmpgtw, regs, regd) + +#define pmaddwd_m2r(var,reg) mmx_m2r (pmaddwd, var, reg) +#define pmaddwd_r2r(regs,regd) mmx_r2r (pmaddwd, regs, regd) + +#define pmulhw_m2r(var,reg) mmx_m2r (pmulhw, var, reg) +#define pmulhw_r2r(regs,regd) mmx_r2r (pmulhw, regs, regd) + +#define pmullw_m2r(var,reg) mmx_m2r (pmullw, var, reg) +#define pmullw_r2r(regs,regd) mmx_r2r (pmullw, regs, regd) + +#define por_m2r(var,reg) mmx_m2r (por, var, reg) +#define por_r2r(regs,regd) mmx_r2r (por, regs, regd) + +#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 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 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 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 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 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 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 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 psubb_m2r(var,reg) mmx_m2r (psubb, var, reg) +#define psubb_r2r(regs,regd) mmx_r2r (psubb, regs, regd) +#define psubd_m2r(var,reg) mmx_m2r (psubd, var, reg) +#define psubd_r2r(regs,regd) mmx_r2r (psubd, regs, regd) +#define psubw_m2r(var,reg) mmx_m2r (psubw, var, reg) +#define psubw_r2r(regs,regd) mmx_r2r (psubw, regs, regd) + +#define psubsb_m2r(var,reg) mmx_m2r (psubsb, var, reg) +#define psubsb_r2r(regs,regd) mmx_r2r (psubsb, regs, regd) +#define psubsw_m2r(var,reg) mmx_m2r (psubsw, var, reg) +#define psubsw_r2r(regs,regd) mmx_r2r (psubsw, regs, regd) + +#define psubusb_m2r(var,reg) mmx_m2r (psubusb, var, reg) +#define psubusb_r2r(regs,regd) mmx_r2r (psubusb, regs, regd) +#define psubusw_m2r(var,reg) mmx_m2r (psubusw, var, reg) +#define psubusw_r2r(regs,regd) mmx_r2r (psubusw, regs, regd) + +#define punpckhbw_m2r(var,reg) mmx_m2r (punpckhbw, var, reg) +#define punpckhbw_r2r(regs,regd) mmx_r2r (punpckhbw, regs, regd) +#define punpckhdq_m2r(var,reg) mmx_m2r (punpckhdq, var, reg) +#define punpckhdq_r2r(regs,regd) mmx_r2r (punpckhdq, regs, regd) +#define punpckhwd_m2r(var,reg) mmx_m2r (punpckhwd, var, reg) +#define punpckhwd_r2r(regs,regd) mmx_r2r (punpckhwd, regs, regd) + +#define punpcklbw_m2r(var,reg) mmx_m2r (punpcklbw, var, reg) +#define punpcklbw_r2r(regs,regd) mmx_r2r (punpcklbw, regs, regd) +#define punpckldq_m2r(var,reg) mmx_m2r (punpckldq, var, reg) +#define punpckldq_r2r(regs,regd) mmx_r2r (punpckldq, regs, regd) +#define punpcklwd_m2r(var,reg) mmx_m2r (punpcklwd, var, reg) +#define punpcklwd_r2r(regs,regd) mmx_r2r (punpcklwd, regs, regd) + +#define pxor_m2r(var,reg) mmx_m2r (pxor, var, reg) +#define pxor_r2r(regs,regd) mmx_r2r (pxor, regs, regd) + + +/* 3DNOW extensions */ + +#define pavgusb_m2r(var,reg) mmx_m2r (pavgusb, var, reg) +#define pavgusb_r2r(regs,regd) mmx_r2r (pavgusb, regs, regd) + + +/* AMD MMX extensions - also available in intel SSE */ + + +#define mmx_m2ri(op,mem,reg,imm) \ + __asm__ __volatile__ (#op " %1, %0, %%" #reg \ + : /* nothing */ \ + : "X" (mem), "X" (imm)) +#define mmx_r2ri(op,regs,regd,imm) \ + __asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \ + : /* nothing */ \ + : "X" (imm) ) + +#define mmx_fetch(mem,hint) \ + __asm__ __volatile__ ("prefetch" #hint " %0" \ + : /* nothing */ \ + : "X" (mem)) + + +#define maskmovq(regs,maskreg) mmx_r2ri (maskmovq, regs, maskreg) + +#define movntq_r2m(mmreg,var) mmx_r2m (movntq, mmreg, var) + +#define pavgb_m2r(var,reg) mmx_m2r (pavgb, var, reg) +#define pavgb_r2r(regs,regd) mmx_r2r (pavgb, regs, regd) +#define pavgw_m2r(var,reg) mmx_m2r (pavgw, var, reg) +#define pavgw_r2r(regs,regd) mmx_r2r (pavgw, regs, regd) + +#define pextrw_r2r(mmreg,reg,imm) mmx_r2ri (pextrw, mmreg, reg, imm) + +#define pinsrw_r2r(reg,mmreg,imm) mmx_r2ri (pinsrw, reg, mmreg, imm) + +#define pmaxsw_m2r(var,reg) mmx_m2r (pmaxsw, var, reg) +#define pmaxsw_r2r(regs,regd) mmx_r2r (pmaxsw, regs, regd) + +#define pmaxub_m2r(var,reg) mmx_m2r (pmaxub, var, reg) +#define pmaxub_r2r(regs,regd) mmx_r2r (pmaxub, regs, regd) + +#define pminsw_m2r(var,reg) mmx_m2r (pminsw, var, reg) +#define pminsw_r2r(regs,regd) mmx_r2r (pminsw, regs, regd) + +#define pminub_m2r(var,reg) mmx_m2r (pminub, var, reg) +#define pminub_r2r(regs,regd) mmx_r2r (pminub, regs, regd) + +#define pmovmskb(mmreg,reg) \ + __asm__ __volatile__ ("movmskps %" #mmreg ", %" #reg) + +#define pmulhuw_m2r(var,reg) mmx_m2r (pmulhuw, var, reg) +#define pmulhuw_r2r(regs,regd) mmx_r2r (pmulhuw, regs, regd) + +#define prefetcht0(mem) mmx_fetch (mem, t0) +#define prefetcht1(mem) mmx_fetch (mem, t1) +#define prefetcht2(mem) mmx_fetch (mem, t2) +#define prefetchnta(mem) mmx_fetch (mem, nta) + +#define psadbw_m2r(var,reg) mmx_m2r (psadbw, var, reg) +#define psadbw_r2r(regs,regd) mmx_r2r (psadbw, regs, regd) + +#define pshufw_m2r(var,reg,imm) mmx_m2ri(pshufw, var, reg, imm) +#define pshufw_r2r(regs,regd,imm) mmx_r2ri(pshufw, regs, regd, imm) + +#define sfence() __asm__ __volatile__ ("sfence\n\t") diff --git a/libmpeg2/motion_comp.c b/libmpeg2/motion_comp.c new file mode 100644 index 0000000000..816335c6dc --- /dev/null +++ b/libmpeg2/motion_comp.c @@ -0,0 +1,125 @@ +/* + * motion_comp.c + * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec 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. + * + * mpeg2dec 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 + */ + +#include "config.h" + +#include <stdio.h> +#include <inttypes.h> + +#include "mpeg2_internal.h" +#include "mm_accel.h" + +mc_functions_t mc_functions; + +void motion_comp_init (void) +{ + +#ifdef ARCH_X86 + if (config.flags & MM_ACCEL_X86_MMXEXT) { + fprintf (stderr, "Using MMXEXT for motion compensation\n"); + mc_functions = mc_functions_mmxext; + } else if (config.flags & MM_ACCEL_X86_3DNOW) { + fprintf (stderr, "Using 3DNOW for motion compensation\n"); + mc_functions = mc_functions_3dnow; + } else if (config.flags & MM_ACCEL_X86_MMX) { + fprintf (stderr, "Using MMX for motion compensation\n"); + mc_functions = mc_functions_mmx; + } else +#endif +#ifdef LIBMPEG2_MLIB + if (config.flags & MM_ACCEL_MLIB) { + fprintf (stderr, "Using mlib for motion compensation\n"); + mc_functions = mc_functions_mlib; + } else +#endif + { + fprintf (stderr, "No accelerated motion compensation found\n"); + mc_functions = mc_functions_c; + } +} + +#define avg2(a,b) ((a+b+1)>>1) +#define avg4(a,b,c,d) ((a+b+c+d+2)>>2) + +#define predict_(i) (ref[i]) +#define predict_x(i) (avg2 (ref[i], ref[i+1])) +#define predict_y(i) (avg2 (ref[i], (ref+stride)[i])) +#define predict_xy(i) (avg4 (ref[i], ref[i+1], (ref+stride)[i], (ref+stride)[i+1])) + +#define put(predictor,i) dest[i] = predictor (i) +#define avg(predictor,i) dest[i] = avg2 (predictor (i), dest[i]) + +// mc function template + +#define MC_FUNC(op,xy) \ +static void MC_##op##_##xy##16_c (uint8_t * dest, uint8_t * ref,\ + int stride, int height) \ +{ \ + do { \ + op (predict_##xy, 0); \ + op (predict_##xy, 1); \ + op (predict_##xy, 2); \ + op (predict_##xy, 3); \ + op (predict_##xy, 4); \ + op (predict_##xy, 5); \ + op (predict_##xy, 6); \ + op (predict_##xy, 7); \ + op (predict_##xy, 8); \ + op (predict_##xy, 9); \ + op (predict_##xy, 10); \ + op (predict_##xy, 11); \ + op (predict_##xy, 12); \ + op (predict_##xy, 13); \ + op (predict_##xy, 14); \ + op (predict_##xy, 15); \ + ref += stride; \ + dest += stride; \ + } while (--height); \ +} \ +static void MC_##op##_##xy##8_c (uint8_t * dest, uint8_t * ref, \ + int stride, int height) \ +{ \ + do { \ + op (predict_##xy, 0); \ + op (predict_##xy, 1); \ + op (predict_##xy, 2); \ + op (predict_##xy, 3); \ + op (predict_##xy, 4); \ + op (predict_##xy, 5); \ + op (predict_##xy, 6); \ + op (predict_##xy, 7); \ + ref += stride; \ + dest += stride; \ + } while (--height); \ +} + +// definitions of the actual mc functions + +MC_FUNC (put,) +MC_FUNC (avg,) +MC_FUNC (put,x) +MC_FUNC (avg,x) +MC_FUNC (put,y) +MC_FUNC (avg,y) +MC_FUNC (put,xy) +MC_FUNC (avg,xy) + +MOTION_COMP_EXTERN (c) diff --git a/libmpeg2/motion_comp_mlib.c b/libmpeg2/motion_comp_mlib.c new file mode 100644 index 0000000000..e079119eb9 --- /dev/null +++ b/libmpeg2/motion_comp_mlib.c @@ -0,0 +1,180 @@ +/* + * MC_mlib.c + * Copyright (C) 2000 Håkan Hjort <d95hjort@dtek.chalmers.se> + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec 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. + * + * mpeg2dec 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 + */ + +#include "config.h" + +#ifdef LIBMPEG2_MLIB + +#include <inttypes.h> +#include <mlib_types.h> +#include <mlib_status.h> +#include <mlib_sys.h> +#include <mlib_video.h> + +#include "mpeg2_internal.h" + +static void MC_put_16_mlib (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + if (height == 16) + mlib_VideoCopyRef_U8_U8_16x16 (dest, ref, stride); + else + mlib_VideoCopyRef_U8_U8_16x8 (dest, ref, stride); +} + +static void MC_put_x16_mlib (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + if (height == 16) + mlib_VideoInterpX_U8_U8_16x16 (dest, ref, stride, stride); + else + mlib_VideoInterpX_U8_U8_16x8 (dest, ref, stride, stride); +} + +static void MC_put_y16_mlib (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + if (height == 16) + mlib_VideoInterpY_U8_U8_16x16 (dest, ref, stride, stride); + else + mlib_VideoInterpY_U8_U8_16x8 (dest, ref, stride, stride); +} + +static void MC_put_xy16_mlib (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + if (height == 16) + mlib_VideoInterpXY_U8_U8_16x16 (dest, ref, stride, stride); + else + mlib_VideoInterpXY_U8_U8_16x8 (dest, ref, stride, stride); +} + +static void MC_put_8_mlib (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + if (height == 8) + mlib_VideoCopyRef_U8_U8_8x8 (dest, ref, stride); + else + mlib_VideoCopyRef_U8_U8_8x4 (dest, ref, stride); +} + +static void MC_put_x8_mlib (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + if (height == 8) + mlib_VideoInterpX_U8_U8_8x8 (dest, ref, stride, stride); + else + mlib_VideoInterpX_U8_U8_8x4 (dest, ref, stride, stride); +} + +static void MC_put_y8_mlib (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + if (height == 8) + mlib_VideoInterpY_U8_U8_8x8 (dest, ref, stride, stride); + else + mlib_VideoInterpY_U8_U8_8x4 (dest, ref, stride, stride); +} + +static void MC_put_xy8_mlib (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + if (height == 8) + mlib_VideoInterpXY_U8_U8_8x8 (dest, ref, stride, stride); + else + mlib_VideoInterpXY_U8_U8_8x4 (dest, ref, stride, stride); +} + +static void MC_avg_16_mlib (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + if (height == 16) + mlib_VideoCopyRefAve_U8_U8_16x16 (dest, ref, stride); + else + mlib_VideoCopyRefAve_U8_U8_16x8 (dest, ref, stride); +} + +static void MC_avg_x16_mlib (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + if (height == 16) + mlib_VideoInterpAveX_U8_U8_16x16 (dest, ref, stride, stride); + else + mlib_VideoInterpAveX_U8_U8_16x8 (dest, ref, stride, stride); +} + +static void MC_avg_y16_mlib (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + if (height == 16) + mlib_VideoInterpAveY_U8_U8_16x16 (dest, ref, stride, stride); + else + mlib_VideoInterpAveY_U8_U8_16x8 (dest, ref, stride, stride); +} + +static void MC_avg_xy16_mlib (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + if (height == 16) + mlib_VideoInterpAveXY_U8_U8_16x16 (dest, ref, stride, stride); + else + mlib_VideoInterpAveXY_U8_U8_16x8 (dest, ref, stride, stride); +} + +static void MC_avg_8_mlib (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + if (height == 8) + mlib_VideoCopyRefAve_U8_U8_8x8 (dest, ref, stride); + else + mlib_VideoCopyRefAve_U8_U8_8x4 (dest, ref, stride); +} + +static void MC_avg_x8_mlib (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + if (height == 8) + mlib_VideoInterpAveX_U8_U8_8x8 (dest, ref, stride, stride); + else + mlib_VideoInterpAveX_U8_U8_8x4 (dest, ref, stride, stride); +} + +static void MC_avg_y8_mlib (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + if (height == 8) + mlib_VideoInterpAveY_U8_U8_8x8 (dest, ref, stride, stride); + else + mlib_VideoInterpAveY_U8_U8_8x4 (dest, ref, stride, stride); +} + +static void MC_avg_xy8_mlib (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + if (height == 8) + mlib_VideoInterpAveXY_U8_U8_8x8 (dest, ref, stride, stride); + else + mlib_VideoInterpAveXY_U8_U8_8x4 (dest, ref, stride, stride); +} + +MOTION_COMP_EXTERN (mlib) + +#endif diff --git a/libmpeg2/motion_comp_mmx.c b/libmpeg2/motion_comp_mmx.c new file mode 100644 index 0000000000..f635692045 --- /dev/null +++ b/libmpeg2/motion_comp_mmx.c @@ -0,0 +1,1025 @@ +/* + * motion_comp_mmx.c + * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec 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. + * + * mpeg2dec 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 + */ + +#include "config.h" + +#ifdef ARCH_X86 + +#include <inttypes.h> + +#include "mpeg2_internal.h" +#include "attributes.h" +#include "mmx.h" + +#define CPU_MMXEXT 0 +#define CPU_3DNOW 1 + + +//MMX code - needs a rewrite + + + + + + + +// some rounding constants +mmx_t round1 = {0x0001000100010001LL}; +mmx_t round4 = {0x0002000200020002LL}; + +/* + * This code should probably be compiled with loop unrolling + * (ie, -funroll-loops in gcc)becuase some of the loops + * use a small static number of iterations. This was written + * with the assumption the compiler knows best about when + * unrolling will help + */ + +static inline void mmx_zero_reg () +{ + // load 0 into mm0 + pxor_r2r (mm0, mm0); +} + +static inline void mmx_average_2_U8 (uint8_t * dest, + uint8_t * src1, uint8_t * src2) +{ + // + // *dest = (*src1 + *src2 + 1)/ 2; + // + + movq_m2r (*src1, mm1); // load 8 src1 bytes + movq_r2r (mm1, mm2); // copy 8 src1 bytes + + movq_m2r (*src2, mm3); // load 8 src2 bytes + movq_r2r (mm3, mm4); // copy 8 src2 bytes + + punpcklbw_r2r (mm0, mm1); // unpack low src1 bytes + punpckhbw_r2r (mm0, mm2); // unpack high src1 bytes + + punpcklbw_r2r (mm0, mm3); // unpack low src2 bytes + punpckhbw_r2r (mm0, mm4); // unpack high src2 bytes + + paddw_r2r (mm3, mm1); // add lows to mm1 + paddw_m2r (round1, mm1); + psraw_i2r (1, mm1); // /2 + + paddw_r2r (mm4, mm2); // add highs to mm2 + paddw_m2r (round1, mm2); + psraw_i2r (1, mm2); // /2 + + packuswb_r2r (mm2, mm1); // pack (w/ saturation) + movq_r2m (mm1, *dest); // store result in dest +} + +static inline void mmx_interp_average_2_U8 (uint8_t * dest, + uint8_t * src1, uint8_t * src2) +{ + // + // *dest = (*dest + (*src1 + *src2 + 1)/ 2 + 1)/ 2; + // + + movq_m2r (*dest, mm1); // load 8 dest bytes + movq_r2r (mm1, mm2); // copy 8 dest bytes + + movq_m2r (*src1, mm3); // load 8 src1 bytes + movq_r2r (mm3, mm4); // copy 8 src1 bytes + + movq_m2r (*src2, mm5); // load 8 src2 bytes + movq_r2r (mm5, mm6); // copy 8 src2 bytes + + punpcklbw_r2r (mm0, mm1); // unpack low dest bytes + punpckhbw_r2r (mm0, mm2); // unpack high dest bytes + + punpcklbw_r2r (mm0, mm3); // unpack low src1 bytes + punpckhbw_r2r (mm0, mm4); // unpack high src1 bytes + + punpcklbw_r2r (mm0, mm5); // unpack low src2 bytes + punpckhbw_r2r (mm0, mm6); // unpack high src2 bytes + + paddw_r2r (mm5, mm3); // add lows + paddw_m2r (round1, mm3); + psraw_i2r (1, mm3); // /2 + + paddw_r2r (mm6, mm4); // add highs + paddw_m2r (round1, mm4); + psraw_i2r (1, mm4); // /2 + + paddw_r2r (mm3, mm1); // add lows + paddw_m2r (round1, mm1); + psraw_i2r (1, mm1); // /2 + + paddw_r2r (mm4, mm2); // add highs + paddw_m2r (round1, mm2); + psraw_i2r (1, mm2); // /2 + + packuswb_r2r (mm2, mm1); // pack (w/ saturation) + movq_r2m (mm1, *dest); // store result in dest +} + +static inline void mmx_average_4_U8 (uint8_t * dest, + uint8_t * src1, uint8_t * src2, + uint8_t * src3, uint8_t * src4) +{ + // + // *dest = (*src1 + *src2 + *src3 + *src4 + 2)/ 4; + // + + movq_m2r (*src1, mm1); // load 8 src1 bytes + movq_r2r (mm1, mm2); // copy 8 src1 bytes + + punpcklbw_r2r (mm0, mm1); // unpack low src1 bytes + punpckhbw_r2r (mm0, mm2); // unpack high src1 bytes + + movq_m2r (*src2, mm3); // load 8 src2 bytes + movq_r2r (mm3, mm4); // copy 8 src2 bytes + + punpcklbw_r2r (mm0, mm3); // unpack low src2 bytes + punpckhbw_r2r (mm0, mm4); // unpack high src2 bytes + + paddw_r2r (mm3, mm1); // add lows + paddw_r2r (mm4, mm2); // add highs + + // now have partials in mm1 and mm2 + + movq_m2r (*src3, mm3); // load 8 src3 bytes + movq_r2r (mm3, mm4); // copy 8 src3 bytes + + punpcklbw_r2r (mm0, mm3); // unpack low src3 bytes + punpckhbw_r2r (mm0, mm4); // unpack high src3 bytes + + paddw_r2r (mm3, mm1); // add lows + paddw_r2r (mm4, mm2); // add highs + + movq_m2r (*src4, mm5); // load 8 src4 bytes + movq_r2r (mm5, mm6); // copy 8 src4 bytes + + punpcklbw_r2r (mm0, mm5); // unpack low src4 bytes + punpckhbw_r2r (mm0, mm6); // unpack high src4 bytes + + paddw_r2r (mm5, mm1); // add lows + paddw_r2r (mm6, mm2); // add highs + + // now have subtotal in mm1 and mm2 + + paddw_m2r (round4, mm1); + psraw_i2r (2, mm1); // /4 + paddw_m2r (round4, mm2); + psraw_i2r (2, mm2); // /4 + + packuswb_r2r (mm2, mm1); // pack (w/ saturation) + movq_r2m (mm1, *dest); // store result in dest +} + +static inline void mmx_interp_average_4_U8 (uint8_t * dest, + uint8_t * src1, uint8_t * src2, + uint8_t * src3, uint8_t * src4) +{ + // + // *dest = (*dest + (*src1 + *src2 + *src3 + *src4 + 2)/ 4 + 1)/ 2; + // + + movq_m2r (*src1, mm1); // load 8 src1 bytes + movq_r2r (mm1, mm2); // copy 8 src1 bytes + + punpcklbw_r2r (mm0, mm1); // unpack low src1 bytes + punpckhbw_r2r (mm0, mm2); // unpack high src1 bytes + + movq_m2r (*src2, mm3); // load 8 src2 bytes + movq_r2r (mm3, mm4); // copy 8 src2 bytes + + punpcklbw_r2r (mm0, mm3); // unpack low src2 bytes + punpckhbw_r2r (mm0, mm4); // unpack high src2 bytes + + paddw_r2r (mm3, mm1); // add lows + paddw_r2r (mm4, mm2); // add highs + + // now have partials in mm1 and mm2 + + movq_m2r (*src3, mm3); // load 8 src3 bytes + movq_r2r (mm3, mm4); // copy 8 src3 bytes + + punpcklbw_r2r (mm0, mm3); // unpack low src3 bytes + punpckhbw_r2r (mm0, mm4); // unpack high src3 bytes + + paddw_r2r (mm3, mm1); // add lows + paddw_r2r (mm4, mm2); // add highs + + movq_m2r (*src4, mm5); // load 8 src4 bytes + movq_r2r (mm5, mm6); // copy 8 src4 bytes + + punpcklbw_r2r (mm0, mm5); // unpack low src4 bytes + punpckhbw_r2r (mm0, mm6); // unpack high src4 bytes + + paddw_r2r (mm5, mm1); // add lows + paddw_r2r (mm6, mm2); // add highs + + paddw_m2r (round4, mm1); + psraw_i2r (2, mm1); // /4 + paddw_m2r (round4, mm2); + psraw_i2r (2, mm2); // /4 + + // now have subtotal/4 in mm1 and mm2 + + movq_m2r (*dest, mm3); // load 8 dest bytes + movq_r2r (mm3, mm4); // copy 8 dest bytes + + punpcklbw_r2r (mm0, mm3); // unpack low dest bytes + punpckhbw_r2r (mm0, mm4); // unpack high dest bytes + + paddw_r2r (mm3, mm1); // add lows + paddw_r2r (mm4, mm2); // add highs + + paddw_m2r (round1, mm1); + psraw_i2r (1, mm1); // /2 + paddw_m2r (round1, mm2); + psraw_i2r (1, mm2); // /2 + + // now have end value in mm1 and mm2 + + packuswb_r2r (mm2, mm1); // pack (w/ saturation) + movq_r2m (mm1,*dest); // store result in dest +} + +//----------------------------------------------------------------------- + +static inline void MC_avg_mmx (int width, int height, + uint8_t * dest, uint8_t * ref, int stride) +{ + mmx_zero_reg (); + + do { + mmx_average_2_U8 (dest, dest, ref); + + if (width == 16) + mmx_average_2_U8 (dest+8, dest+8, ref+8); + + dest += stride; + ref += stride; + } while (--height); +} + +static void MC_avg_16_mmx (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg_mmx (16, height, dest, ref, stride); +} + +static void MC_avg_8_mmx (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg_mmx (8, height, dest, ref, stride); +} + +//----------------------------------------------------------------------- + +static inline void MC_put_mmx (int width, int height, + uint8_t * dest, uint8_t * ref, int stride) +{ + mmx_zero_reg (); + + do { + movq_m2r (* ref, mm1); // load 8 ref bytes + movq_r2m (mm1,* dest); // store 8 bytes at curr + + if (width == 16) + { + movq_m2r (* (ref+8), mm1); // load 8 ref bytes + movq_r2m (mm1,* (dest+8)); // store 8 bytes at curr + } + + dest += stride; + ref += stride; + } while (--height); +} + +static void MC_put_16_mmx (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put_mmx (16, height, dest, ref, stride); +} + +static void MC_put_8_mmx (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put_mmx (8, height, dest, ref, stride); +} + +//----------------------------------------------------------------------- + +// Half pixel interpolation in the x direction +static inline void MC_avg_x_mmx (int width, int height, + uint8_t * dest, uint8_t * ref, int stride) +{ + mmx_zero_reg (); + + do { + mmx_interp_average_2_U8 (dest, ref, ref+1); + + if (width == 16) + mmx_interp_average_2_U8 (dest+8, ref+8, ref+9); + + dest += stride; + ref += stride; + } while (--height); +} + +static void MC_avg_x16_mmx (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg_x_mmx (16, height, dest, ref, stride); +} + +static void MC_avg_x8_mmx (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg_x_mmx (8, height, dest, ref, stride); +} + +//----------------------------------------------------------------------- + +static inline void MC_put_x_mmx (int width, int height, + uint8_t * dest, uint8_t * ref, int stride) +{ + mmx_zero_reg (); + + do { + mmx_average_2_U8 (dest, ref, ref+1); + + if (width == 16) + mmx_average_2_U8 (dest+8, ref+8, ref+9); + + dest += stride; + ref += stride; + } while (--height); +} + +static void MC_put_x16_mmx (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put_x_mmx (16, height, dest, ref, stride); +} + +static void MC_put_x8_mmx (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put_x_mmx (8, height, dest, ref, stride); +} + +//----------------------------------------------------------------------- + +static inline void MC_avg_xy_mmx (int width, int height, + uint8_t * dest, uint8_t * ref, int stride) +{ + uint8_t * ref_next = ref+stride; + + mmx_zero_reg (); + + do { + mmx_interp_average_4_U8 (dest, ref, ref+1, ref_next, ref_next+1); + + if (width == 16) + mmx_interp_average_4_U8 (dest+8, ref+8, ref+9, + ref_next+8, ref_next+9); + + dest += stride; + ref += stride; + ref_next += stride; + } while (--height); +} + +static void MC_avg_xy16_mmx (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg_xy_mmx (16, height, dest, ref, stride); +} + +static void MC_avg_xy8_mmx (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg_xy_mmx (8, height, dest, ref, stride); +} + +//----------------------------------------------------------------------- + +static inline void MC_put_xy_mmx (int width, int height, + uint8_t * dest, uint8_t * ref, int stride) +{ + uint8_t * ref_next = ref+stride; + + mmx_zero_reg (); + + do { + mmx_average_4_U8 (dest, ref, ref+1, ref_next, ref_next+1); + + if (width == 16) + mmx_average_4_U8 (dest+8, ref+8, ref+9, ref_next+8, ref_next+9); + + dest += stride; + ref += stride; + ref_next += stride; + } while (--height); +} + +static void MC_put_xy16_mmx (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put_xy_mmx (16, height, dest, ref, stride); +} + +static void MC_put_xy8_mmx (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put_xy_mmx (8, height, dest, ref, stride); +} + +//----------------------------------------------------------------------- + +static inline void MC_avg_y_mmx (int width, int height, + uint8_t * dest, uint8_t * ref, int stride) +{ + uint8_t * ref_next = ref+stride; + + mmx_zero_reg (); + + do { + mmx_interp_average_2_U8 (dest, ref, ref_next); + + if (width == 16) + mmx_interp_average_2_U8 (dest+8, ref+8, ref_next+8); + + dest += stride; + ref += stride; + ref_next += stride; + } while (--height); +} + +static void MC_avg_y16_mmx (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg_y_mmx (16, height, dest, ref, stride); +} + +static void MC_avg_y8_mmx (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg_y_mmx (8, height, dest, ref, stride); +} + +//----------------------------------------------------------------------- + +static inline void MC_put_y_mmx (int width, int height, + uint8_t * dest, uint8_t * ref, int stride) +{ + uint8_t * ref_next = ref+stride; + + mmx_zero_reg (); + + do { + mmx_average_2_U8 (dest, ref, ref_next); + + if (width == 16) + mmx_average_2_U8 (dest+8, ref+8, ref_next+8); + + dest += stride; + ref += stride; + ref_next += stride; + } while (--height); +} + +static void MC_put_y16_mmx (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put_y_mmx (16, height, dest, ref, stride); +} + +static void MC_put_y8_mmx (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put_y_mmx (8, height, dest, ref, stride); +} + + +MOTION_COMP_EXTERN (mmx) + + + + + + + +//CPU_MMXEXT/CPU_3DNOW adaptation layer + +#define pavg_r2r(src,dest) \ +do { \ + if (cpu == CPU_MMXEXT) \ + pavgb_r2r (src, dest); \ + else \ + pavgusb_r2r (src, dest); \ +} while (0) + +#define pavg_m2r(src,dest) \ +do { \ + if (cpu == CPU_MMXEXT) \ + pavgb_m2r (src, dest); \ + else \ + pavgusb_m2r (src, dest); \ +} while (0) + + +//CPU_MMXEXT code + + +static inline void MC_put1_8 (int height, uint8_t * dest, uint8_t * ref, + int stride) +{ + do { + movq_m2r (*ref, mm0); + movq_r2m (mm0, *dest); + ref += stride; + dest += stride; + } while (--height); +} + +static inline void MC_put1_16 (int height, uint8_t * dest, uint8_t * ref, + int stride) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+8), mm1); + ref += stride; + movq_r2m (mm0, *dest); + movq_r2m (mm1, *(dest+8)); + dest += stride; + } while (--height); +} + +static inline void MC_avg1_8 (int height, uint8_t * dest, uint8_t * ref, + int stride, int cpu) +{ + do { + movq_m2r (*ref, mm0); + pavg_m2r (*dest, mm0); + ref += stride; + movq_r2m (mm0, *dest); + dest += stride; + } while (--height); +} + +static inline void MC_avg1_16 (int height, uint8_t * dest, uint8_t * ref, + int stride, int cpu) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+8), mm1); + pavg_m2r (*dest, mm0); + pavg_m2r (*(dest+8), mm1); + movq_r2m (mm0, *dest); + ref += stride; + movq_r2m (mm1, *(dest+8)); + dest += stride; + } while (--height); +} + +static inline void MC_put2_8 (int height, uint8_t * dest, uint8_t * ref, + int stride, int offset, int cpu) +{ + do { + movq_m2r (*ref, mm0); + pavg_m2r (*(ref+offset), mm0); + ref += stride; + movq_r2m (mm0, *dest); + dest += stride; + } while (--height); +} + +static inline void MC_put2_16 (int height, uint8_t * dest, uint8_t * ref, + int stride, int offset, int cpu) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+8), mm1); + pavg_m2r (*(ref+offset), mm0); + pavg_m2r (*(ref+offset+8), mm1); + movq_r2m (mm0, *dest); + ref += stride; + movq_r2m (mm1, *(dest+8)); + dest += stride; + } while (--height); +} + +static inline void MC_avg2_8 (int height, uint8_t * dest, uint8_t * ref, + int stride, int offset, int cpu) +{ + do { + movq_m2r (*ref, mm0); + pavg_m2r (*(ref+offset), mm0); + pavg_m2r (*dest, mm0); + ref += stride; + movq_r2m (mm0, *dest); + dest += stride; + } while (--height); +} + +static inline void MC_avg2_16 (int height, uint8_t * dest, uint8_t * ref, + int stride, int offset, int cpu) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+8), mm1); + pavg_m2r (*(ref+offset), mm0); + pavg_m2r (*(ref+offset+8), mm1); + pavg_m2r (*dest, mm0); + pavg_m2r (*(dest+8), mm1); + ref += stride; + movq_r2m (mm0, *dest); + movq_r2m (mm1, *(dest+8)); + dest += stride; + } while (--height); +} + +static mmx_t mask_one = {0x0101010101010101LL}; + +static inline void MC_put4_8 (int height, uint8_t * dest, uint8_t * ref, + int stride, int cpu) +{ + movq_m2r (*ref, mm0); + movq_m2r (*(ref+1), mm1); + movq_r2r (mm0, mm7); + pxor_r2r (mm1, mm7); + pavg_r2r (mm1, mm0); + ref += stride; + + do { + movq_m2r (*ref, mm2); + movq_r2r (mm0, mm5); + + movq_m2r (*(ref+1), mm3); + movq_r2r (mm2, mm6); + + pxor_r2r (mm3, mm6); + pavg_r2r (mm3, mm2); + + por_r2r (mm6, mm7); + pxor_r2r (mm2, mm5); + + pand_r2r (mm5, mm7); + pavg_r2r (mm2, mm0); + + pand_m2r (mask_one, mm7); + + psubusb_r2r (mm7, mm0); + + ref += stride; + movq_r2m (mm0, *dest); + dest += stride; + + movq_r2r (mm6, mm7); // unroll ! + movq_r2r (mm2, mm0); // unroll ! + } while (--height); +} + +static inline void MC_put4_16 (int height, uint8_t * dest, uint8_t * ref, + int stride, int cpu) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+stride+1), mm1); + movq_r2r (mm0, mm7); + movq_m2r (*(ref+1), mm2); + pxor_r2r (mm1, mm7); + movq_m2r (*(ref+stride), mm3); + movq_r2r (mm2, mm6); + pxor_r2r (mm3, mm6); + pavg_r2r (mm1, mm0); + pavg_r2r (mm3, mm2); + por_r2r (mm6, mm7); + movq_r2r (mm0, mm6); + pxor_r2r (mm2, mm6); + pand_r2r (mm6, mm7); + pand_m2r (mask_one, mm7); + pavg_r2r (mm2, mm0); + psubusb_r2r (mm7, mm0); + movq_r2m (mm0, *dest); + + movq_m2r (*(ref+8), mm0); + movq_m2r (*(ref+stride+9), mm1); + movq_r2r (mm0, mm7); + movq_m2r (*(ref+9), mm2); + pxor_r2r (mm1, mm7); + movq_m2r (*(ref+stride+8), mm3); + movq_r2r (mm2, mm6); + pxor_r2r (mm3, mm6); + pavg_r2r (mm1, mm0); + pavg_r2r (mm3, mm2); + por_r2r (mm6, mm7); + movq_r2r (mm0, mm6); + pxor_r2r (mm2, mm6); + pand_r2r (mm6, mm7); + pand_m2r (mask_one, mm7); + pavg_r2r (mm2, mm0); + psubusb_r2r (mm7, mm0); + ref += stride; + movq_r2m (mm0, *(dest+8)); + dest += stride; + } while (--height); +} + +static inline void MC_avg4_8 (int height, uint8_t * dest, uint8_t * ref, + int stride, int cpu) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+stride+1), mm1); + movq_r2r (mm0, mm7); + movq_m2r (*(ref+1), mm2); + pxor_r2r (mm1, mm7); + movq_m2r (*(ref+stride), mm3); + movq_r2r (mm2, mm6); + pxor_r2r (mm3, mm6); + pavg_r2r (mm1, mm0); + pavg_r2r (mm3, mm2); + por_r2r (mm6, mm7); + movq_r2r (mm0, mm6); + pxor_r2r (mm2, mm6); + pand_r2r (mm6, mm7); + pand_m2r (mask_one, mm7); + pavg_r2r (mm2, mm0); + psubusb_r2r (mm7, mm0); + movq_m2r (*dest, mm1); + pavg_r2r (mm1, mm0); + ref += stride; + movq_r2m (mm0, *dest); + dest += stride; + } while (--height); +} + +static inline void MC_avg4_16 (int height, uint8_t * dest, uint8_t * ref, + int stride, int cpu) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+stride+1), mm1); + movq_r2r (mm0, mm7); + movq_m2r (*(ref+1), mm2); + pxor_r2r (mm1, mm7); + movq_m2r (*(ref+stride), mm3); + movq_r2r (mm2, mm6); + pxor_r2r (mm3, mm6); + pavg_r2r (mm1, mm0); + pavg_r2r (mm3, mm2); + por_r2r (mm6, mm7); + movq_r2r (mm0, mm6); + pxor_r2r (mm2, mm6); + pand_r2r (mm6, mm7); + pand_m2r (mask_one, mm7); + pavg_r2r (mm2, mm0); + psubusb_r2r (mm7, mm0); + movq_m2r (*dest, mm1); + pavg_r2r (mm1, mm0); + movq_r2m (mm0, *dest); + + movq_m2r (*(ref+8), mm0); + movq_m2r (*(ref+stride+9), mm1); + movq_r2r (mm0, mm7); + movq_m2r (*(ref+9), mm2); + pxor_r2r (mm1, mm7); + movq_m2r (*(ref+stride+8), mm3); + movq_r2r (mm2, mm6); + pxor_r2r (mm3, mm6); + pavg_r2r (mm1, mm0); + pavg_r2r (mm3, mm2); + por_r2r (mm6, mm7); + movq_r2r (mm0, mm6); + pxor_r2r (mm2, mm6); + pand_r2r (mm6, mm7); + pand_m2r (mask_one, mm7); + pavg_r2r (mm2, mm0); + psubusb_r2r (mm7, mm0); + movq_m2r (*(dest+8), mm1); + pavg_r2r (mm1, mm0); + ref += stride; + movq_r2m (mm0, *(dest+8)); + dest += stride; + } while (--height); +} + +static void MC_avg_16_mmxext (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg1_16 (height, dest, ref, stride, CPU_MMXEXT); +} + +static void MC_avg_8_mmxext (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg1_8 (height, dest, ref, stride, CPU_MMXEXT); +} + +static void MC_put_16_mmxext (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put1_16 (height, dest, ref, stride); +} + +static void MC_put_8_mmxext (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put1_8 (height, dest, ref, stride); +} + +static void MC_avg_x16_mmxext (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg2_16 (height, dest, ref, stride, 1, CPU_MMXEXT); +} + +static void MC_avg_x8_mmxext (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg2_8 (height, dest, ref, stride, 1, CPU_MMXEXT); +} + +static void MC_put_x16_mmxext (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put2_16 (height, dest, ref, stride, 1, CPU_MMXEXT); +} + +static void MC_put_x8_mmxext (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put2_8 (height, dest, ref, stride, 1, CPU_MMXEXT); +} + +static void MC_avg_y16_mmxext (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg2_16 (height, dest, ref, stride, stride, CPU_MMXEXT); +} + +static void MC_avg_y8_mmxext (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg2_8 (height, dest, ref, stride, stride, CPU_MMXEXT); +} + +static void MC_put_y16_mmxext (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put2_16 (height, dest, ref, stride, stride, CPU_MMXEXT); +} + +static void MC_put_y8_mmxext (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put2_8 (height, dest, ref, stride, stride, CPU_MMXEXT); +} + +static void MC_avg_xy16_mmxext (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg4_16 (height, dest, ref, stride, CPU_MMXEXT); +} + +static void MC_avg_xy8_mmxext (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg4_8 (height, dest, ref, stride, CPU_MMXEXT); +} + +static void MC_put_xy16_mmxext (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put4_16 (height, dest, ref, stride, CPU_MMXEXT); +} + +static void MC_put_xy8_mmxext (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put4_8 (height, dest, ref, stride, CPU_MMXEXT); +} + + +MOTION_COMP_EXTERN (mmxext) + + + +static void MC_avg_16_3dnow (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg1_16 (height, dest, ref, stride, CPU_3DNOW); +} + +static void MC_avg_8_3dnow (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg1_8 (height, dest, ref, stride, CPU_3DNOW); +} + +static void MC_put_16_3dnow (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put1_16 (height, dest, ref, stride); +} + +static void MC_put_8_3dnow (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put1_8 (height, dest, ref, stride); +} + +static void MC_avg_x16_3dnow (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg2_16 (height, dest, ref, stride, 1, CPU_3DNOW); +} + +static void MC_avg_x8_3dnow (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg2_8 (height, dest, ref, stride, 1, CPU_3DNOW); +} + +static void MC_put_x16_3dnow (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put2_16 (height, dest, ref, stride, 1, CPU_3DNOW); +} + +static void MC_put_x8_3dnow (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put2_8 (height, dest, ref, stride, 1, CPU_3DNOW); +} + +static void MC_avg_y16_3dnow (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg2_16 (height, dest, ref, stride, stride, CPU_3DNOW); +} + +static void MC_avg_y8_3dnow (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg2_8 (height, dest, ref, stride, stride, CPU_3DNOW); +} + +static void MC_put_y16_3dnow (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put2_16 (height, dest, ref, stride, stride, CPU_3DNOW); +} + +static void MC_put_y8_3dnow (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put2_8 (height, dest, ref, stride, stride, CPU_3DNOW); +} + +static void MC_avg_xy16_3dnow (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg4_16 (height, dest, ref, stride, CPU_3DNOW); +} + +static void MC_avg_xy8_3dnow (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_avg4_8 (height, dest, ref, stride, CPU_3DNOW); +} + +static void MC_put_xy16_3dnow (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put4_16 (height, dest, ref, stride, CPU_3DNOW); +} + +static void MC_put_xy8_3dnow (uint8_t * dest, uint8_t * ref, + int stride, int height) +{ + MC_put4_8 (height, dest, ref, stride, CPU_3DNOW); +} + + +MOTION_COMP_EXTERN (3dnow) + +#endif diff --git a/libmpeg2/mpeg2.h b/libmpeg2/mpeg2.h new file mode 100644 index 0000000000..68f74289c8 --- /dev/null +++ b/libmpeg2/mpeg2.h @@ -0,0 +1,57 @@ +/* + * mpeg2.h + * + * Copyright (C) Aaron Holtzman <aholtzma@ess.engr.uvic.ca> - Mar 2000 + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec 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. + * + * mpeg2dec 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, + * + */ + +#ifdef __OMS__ +#include <oms/plugin/output_video.h> +#ifndef vo_functions_t +#define vo_functions_t plugin_output_video_t +#endif +#else +//FIXME normally I wouldn't nest includes, but we'll leave this here until I get +//another chance to move things around +#include "video_out.h" +#endif + +#include <inttypes.h> +#ifdef __OMS__ +#include <oms/accel.h> +#else +#include "mm_accel.h" +#endif + +//config flags +#define MPEG2_MLIB_ENABLE MM_ACCEL_MLIB +#define MPEG2_MMX_ENABLE MM_ACCEL_X86_MMX +#define MPEG2_3DNOW_ENABLE MM_ACCEL_X86_3DNOW +#define MPEG2_SSE_ENABLE MM_ACCEL_X86_MMXEXT + +//typedef struct mpeg2_config_s { +// //Bit flags that enable various things +// uint32_t flags; +//} mpeg2_config_t; + +void mpeg2_init (void); +//void mpeg2_allocate_image_buffers (picture_t * picture); +int mpeg2_decode_data (vo_functions_t *, uint8_t * data_start, uint8_t * data_end); +//void mpeg2_close (vo_functions_t *); +void mpeg2_drop (int flag); diff --git a/libmpeg2/mpeg2_internal.h b/libmpeg2/mpeg2_internal.h new file mode 100644 index 0000000000..290bb22450 --- /dev/null +++ b/libmpeg2/mpeg2_internal.h @@ -0,0 +1,220 @@ +#include <inttypes.h> +/* + * mpeg2_internal.h + * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec 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. + * + * mpeg2dec 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 + */ + +// hack mode - temporary +// 0 = decode B pictures in a small slice buffer, display slice per slice +// 1 = decode in a frame buffer, display slice per slice +// 2 = decode in a frame buffer, display whole frames +#define HACK_MODE 0 + +// macroblock modes +#define MACROBLOCK_INTRA 1 +#define MACROBLOCK_PATTERN 2 +#define MACROBLOCK_MOTION_BACKWARD 4 +#define MACROBLOCK_MOTION_FORWARD 8 +#define MACROBLOCK_QUANT 16 +#define DCT_TYPE_INTERLACED 32 +// motion_type +#define MOTION_TYPE_MASK (3*64) +#define MOTION_TYPE_BASE 64 +#define MC_FIELD (1*64) +#define MC_FRAME (2*64) +#define MC_16X8 (2*64) +#define MC_DMV (3*64) + +//picture structure +#define TOP_FIELD 1 +#define BOTTOM_FIELD 2 +#define FRAME_PICTURE 3 + +//picture coding type +#define I_TYPE 1 +#define P_TYPE 2 +#define B_TYPE 3 +#define D_TYPE 4 + +//The picture struct contains all of the top level state +//information (ie everything except slice and macroblock +//state) +typedef struct picture_s { + //-- sequence header stuff -- + uint8_t intra_quantizer_matrix [64]; + uint8_t non_intra_quantizer_matrix [64]; + + //The width and height of the picture snapped to macroblock units + int coded_picture_width; + int coded_picture_height; + + //-- picture header stuff -- + + //what type of picture this is (I,P,or B) D from MPEG-1 isn't supported + int picture_coding_type; + + //-- picture coding extension stuff -- + + //quantization factor for motion vectors + int f_code[2][2]; + //quantization factor for intra dc coefficients + int intra_dc_precision; + //top/bottom/both fields + int picture_structure; + //bool to indicate all predictions are frame based + int frame_pred_frame_dct; + //bool to indicate whether intra blocks have motion vectors + // (for concealment) + int concealment_motion_vectors; + //bit to indicate which quantization table to use + int q_scale_type; + //bool to use different vlc tables + int intra_vlc_format; + + //last macroblock in the picture + int last_mba; + //width of picture in macroblocks + int mb_width; + + //stuff derived from bitstream + + //pointer to the zigzag scan we're supposed to be using + uint8_t * scan; + + //Pointer to the current planar frame buffer (Y,Cr,CB) + uint8_t * current_frame[3]; + //storage for reference frames plus a b-frame + uint8_t * forward_reference_frame[3]; + uint8_t * backward_reference_frame[3]; + uint8_t * throwaway_frame[3]; + uint8_t * pp_frame[3]; // postprocess + //uint8_t * throwaway_frame; + + int pp_options; // postprocess + + int second_field; + + // MPEG1 - testing + uint8_t mpeg1; + + //these things are not needed by the decoder + //NOTICE : this is a temporary interface, we will build a better one later. + int aspect_ratio_information; + int frame_rate_code; + int progressive_sequence; + int top_field_first; // this one is actually used for DMV MC + int repeat_first_field; + int progressive_frame; + // added by A'rpi/ESP-team: + int repeat_count; + int bitrate; + int frame_rate; + int display_picture_width; + int display_picture_height; +} picture_t; + +typedef struct motion_s { + uint8_t * ref[2][3]; + int pmv[2][2]; + int f_code[2]; +} motion_t; + +// state that is carried from one macroblock to the next inside of a same slice +typedef struct slice_s { + // bit parsing stuff + uint32_t bitstream_buf; // current 32 bit working set of buffer + int bitstream_bits; // used bits in working set + uint8_t * bitstream_ptr; // buffer with stream data + + //Motion vectors + //The f_ and b_ correspond to the forward and backward motion + //predictors + motion_t b_motion; + motion_t f_motion; + + // predictor for DC coefficients in intra blocks + int16_t dc_dct_pred[3]; + + uint16_t quantizer_scale; // remove +} slice_t; + +typedef struct mpeg2_config_s { + //Bit flags that enable various things + uint32_t flags; +} mpeg2_config_t; + +//The only global variable, +//the config struct +extern mpeg2_config_t config; + + + +// slice.c +void header_state_init (picture_t * picture); +int header_process_picture_header (picture_t * picture, uint8_t * buffer); +int header_process_sequence_header (picture_t * picture, uint8_t * buffer); +int header_process_extension (picture_t * picture, uint8_t * buffer); + +// idct.c +void idct_init (void); + +// idct_mlib.c +void idct_block_copy_mlib (int16_t * block, uint8_t * dest, int stride); +void idct_block_add_mlib (int16_t * block, uint8_t * dest, int stride); + +// idct_mmx.c +void idct_block_copy_mmxext (int16_t *block, uint8_t * dest, int stride); +void idct_block_add_mmxext (int16_t *block, uint8_t * dest, int stride); +void idct_block_copy_mmx (int16_t *block, uint8_t * dest, int stride); +void idct_block_add_mmx (int16_t *block, uint8_t * dest, int stride); +void idct_mmx_init (void); + +// motion_comp.c +void motion_comp_init (void); + +typedef struct mc_functions_s +{ + void (* put [8]) (uint8_t *dst, uint8_t *, int32_t, int32_t); + void (* avg [8]) (uint8_t *dst, uint8_t *, int32_t, int32_t); +} mc_functions_t; + +#define MOTION_COMP_EXTERN(x) mc_functions_t mc_functions_##x = \ +{ \ + {MC_put_16_##x, MC_put_x16_##x, MC_put_y16_##x, MC_put_xy16_##x, \ + MC_put_8_##x, MC_put_x8_##x, MC_put_y8_##x, MC_put_xy8_##x}, \ + {MC_avg_16_##x, MC_avg_x16_##x, MC_avg_y16_##x, MC_avg_xy16_##x, \ + MC_avg_8_##x, MC_avg_x8_##x, MC_avg_y8_##x, MC_avg_xy8_##x} \ +}; + +extern mc_functions_t mc_functions_c; +extern mc_functions_t mc_functions_mmx; +extern mc_functions_t mc_functions_mmxext; +extern mc_functions_t mc_functions_3dnow; +extern mc_functions_t mc_functions_mlib; + +// slice.c +int slice_process (picture_t *picture, uint8_t code, uint8_t * buffer); + +// stats.c +void stats_header (uint8_t code, uint8_t * buffer); + +#define MBC 45 +#define MBR 36 +extern int quant_store[MBR+1][MBC+1]; // [Review] + diff --git a/libmpeg2/slice.c b/libmpeg2/slice.c new file mode 100644 index 0000000000..13940b3387 --- /dev/null +++ b/libmpeg2/slice.c @@ -0,0 +1,1797 @@ +/* + * slice.c + * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec 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. + * + * mpeg2dec 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 + */ + +#include "config.h" + +#include <string.h> +#include <inttypes.h> + +#include "mpeg2_internal.h" +#include "attributes.h" + +extern mc_functions_t mc_functions; +extern void (* idct_block_copy) (int16_t * block, uint8_t * dest, int stride); +extern void (* idct_block_add) (int16_t * block, uint8_t * dest, int stride); + +static int16_t DCTblock[64] ATTR_ALIGN(16); + +#include "vlc.h" + +static int non_linear_quantizer_scale [] = { + 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 +}; + +static inline int get_macroblock_modes (slice_t * slice, int picture_structure, + int picture_coding_type, + int frame_pred_frame_dct) +{ +#define bit_buf (slice->bitstream_buf) +#define bits (slice->bitstream_bits) +#define bit_ptr (slice->bitstream_ptr) + int macroblock_modes; + MBtab * tab; + + switch (picture_coding_type) { + case I_TYPE: + + tab = MB_I + UBITS (bit_buf, 1); + DUMPBITS (bit_buf, bits, tab->len); + macroblock_modes = tab->modes; + + if ((! frame_pred_frame_dct) && (picture_structure == FRAME_PICTURE)) { + macroblock_modes |= UBITS (bit_buf, 1) * DCT_TYPE_INTERLACED; + DUMPBITS (bit_buf, bits, 1); + } + + return macroblock_modes; + + case P_TYPE: + + tab = MB_P + UBITS (bit_buf, 5); + DUMPBITS (bit_buf, bits, tab->len); + macroblock_modes = tab->modes; + + if (picture_structure != FRAME_PICTURE) { + if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) { + macroblock_modes |= UBITS (bit_buf, 2) * MOTION_TYPE_BASE; + DUMPBITS (bit_buf, bits, 2); + } + return macroblock_modes; + } else if (frame_pred_frame_dct) { + if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) + macroblock_modes |= MC_FRAME; + return macroblock_modes; + } else { + if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) { + macroblock_modes |= UBITS (bit_buf, 2) * MOTION_TYPE_BASE; + DUMPBITS (bit_buf, bits, 2); + } + if (macroblock_modes & (MACROBLOCK_INTRA | MACROBLOCK_PATTERN)) { + macroblock_modes |= UBITS (bit_buf, 1) * DCT_TYPE_INTERLACED; + DUMPBITS (bit_buf, bits, 1); + } + return macroblock_modes; + } + + case B_TYPE: + + tab = MB_B + UBITS (bit_buf, 6); + DUMPBITS (bit_buf, bits, tab->len); + macroblock_modes = tab->modes; + + if (picture_structure != FRAME_PICTURE) { + if (! (macroblock_modes & MACROBLOCK_INTRA)) { + macroblock_modes |= UBITS (bit_buf, 2) * MOTION_TYPE_BASE; + DUMPBITS (bit_buf, bits, 2); + } + return macroblock_modes; + } else if (frame_pred_frame_dct) { + //if (! (macroblock_modes & MACROBLOCK_INTRA)) + macroblock_modes |= MC_FRAME; + return macroblock_modes; + } else { + if (macroblock_modes & MACROBLOCK_INTRA) + goto intra; + macroblock_modes |= UBITS (bit_buf, 2) * MOTION_TYPE_BASE; + DUMPBITS (bit_buf, bits, 2); + if (macroblock_modes & (MACROBLOCK_INTRA | MACROBLOCK_PATTERN)) { + intra: + macroblock_modes |= UBITS (bit_buf, 1) * DCT_TYPE_INTERLACED; + DUMPBITS (bit_buf, bits, 1); + } + return macroblock_modes; + } + + case D_TYPE: + + DUMPBITS (bit_buf, bits, 1); + return MACROBLOCK_INTRA; + + default: + return 0; + } +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static inline int get_quantizer_scale (slice_t * slice, int q_scale_type) +{ +#define bit_buf (slice->bitstream_buf) +#define bits (slice->bitstream_bits) +#define bit_ptr (slice->bitstream_ptr) + + int quantizer_scale_code; + + quantizer_scale_code = UBITS (bit_buf, 5); + DUMPBITS (bit_buf, bits, 5); + + if (q_scale_type) + return non_linear_quantizer_scale [quantizer_scale_code]; + else + return quantizer_scale_code << 1; +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static inline int get_motion_delta (slice_t * slice, int f_code) +{ +#define bit_buf (slice->bitstream_buf) +#define bits (slice->bitstream_bits) +#define bit_ptr (slice->bitstream_ptr) + + int delta; + int sign; + MVtab * tab; + + if (bit_buf & 0x80000000) { + DUMPBITS (bit_buf, bits, 1); + return 0; + } else if (bit_buf >= 0x0c000000) { + + tab = MV_4 + UBITS (bit_buf, 4); + delta = (tab->delta << f_code) + 1; + bits += tab->len + f_code + 1; + bit_buf <<= tab->len; + + sign = SBITS (bit_buf, 1); + bit_buf <<= 1; + + if (f_code) + delta += UBITS (bit_buf, f_code); + bit_buf <<= f_code; + + return (delta ^ sign) - sign; + + } else { + + tab = MV_10 + UBITS (bit_buf, 10); + delta = (tab->delta << f_code) + 1; + bits += tab->len + 1; + bit_buf <<= tab->len; + + sign = SBITS (bit_buf, 1); + bit_buf <<= 1; + + if (f_code) { + NEEDBITS (bit_buf, bits, bit_ptr); + delta += UBITS (bit_buf, f_code); + DUMPBITS (bit_buf, bits, f_code); + } + + return (delta ^ sign) - sign; + + } +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static inline int bound_motion_vector (int vector, int f_code) +{ +#if 1 + int limit; + + limit = 16 << f_code; + + if (vector >= limit) + return vector - 2*limit; + else if (vector < -limit) + return vector + 2*limit; + else return vector; +#else + return (vector << (27 - f_code)) >> (27 - f_code); +#endif +} + +static inline int get_dmv (slice_t * slice) +{ +#define bit_buf (slice->bitstream_buf) +#define bits (slice->bitstream_bits) +#define bit_ptr (slice->bitstream_ptr) + + DMVtab * tab; + + tab = DMV_2 + UBITS (bit_buf, 2); + DUMPBITS (bit_buf, bits, tab->len); + return tab->dmv; +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static inline int get_coded_block_pattern (slice_t * slice) +{ +#define bit_buf (slice->bitstream_buf) +#define bits (slice->bitstream_bits) +#define bit_ptr (slice->bitstream_ptr) + + CBPtab * tab; + + NEEDBITS (bit_buf, bits, bit_ptr); + + if (bit_buf >= 0x20000000) { + + tab = CBP_7 - 16 + UBITS (bit_buf, 7); + DUMPBITS (bit_buf, bits, tab->len); + return tab->cbp; + + } else { + + tab = CBP_9 + UBITS (bit_buf, 9); + DUMPBITS (bit_buf, bits, tab->len); + return tab->cbp; + } + +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static inline int get_luma_dc_dct_diff (slice_t * slice) +{ +#define bit_buf (slice->bitstream_buf) +#define bits (slice->bitstream_bits) +#define bit_ptr (slice->bitstream_ptr) + DCtab * tab; + int size; + int dc_diff; + + if (bit_buf < 0xf8000000) { + tab = DC_lum_5 + UBITS (bit_buf, 5); + size = tab->size; + if (size) { + bits += tab->len + size; + bit_buf <<= tab->len; + dc_diff = + UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); + bit_buf <<= size; + return dc_diff; + } else { + DUMPBITS (bit_buf, bits, 3); + return 0; + } + } else { + tab = DC_long - 0x1e0 + UBITS (bit_buf, 9); + size = tab->size; + DUMPBITS (bit_buf, bits, tab->len); + NEEDBITS (bit_buf, bits, bit_ptr); + dc_diff = UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); + DUMPBITS (bit_buf, bits, size); + return dc_diff; + } +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static inline int get_chroma_dc_dct_diff (slice_t * slice) +{ +#define bit_buf (slice->bitstream_buf) +#define bits (slice->bitstream_bits) +#define bit_ptr (slice->bitstream_ptr) + DCtab * tab; + int size; + int dc_diff; + + if (bit_buf < 0xf8000000) { + tab = DC_chrom_5 + UBITS (bit_buf, 5); + size = tab->size; + if (size) { + bits += tab->len + size; + bit_buf <<= tab->len; + dc_diff = + UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); + bit_buf <<= size; + return dc_diff; + } else { + DUMPBITS (bit_buf, bits, 2); + return 0; + } + } else { + tab = DC_long - 0x3e0 + UBITS (bit_buf, 10); + size = tab->size; + DUMPBITS (bit_buf, bits, tab->len + 1); + NEEDBITS (bit_buf, bits, bit_ptr); + dc_diff = UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); + DUMPBITS (bit_buf, bits, size); + return dc_diff; + } +#undef bit_buf +#undef bits +#undef bit_ptr +} + +#define SATURATE(val) \ +do { \ + if (val > 2047) \ + val = 2047; \ + else if (val < -2048) \ + val = -2048; \ +} while (0) + +static void get_intra_block_B14 (picture_t * picture, slice_t * slice, + int16_t * dest) +{ + int i; + int j; + int val; + uint8_t * scan = picture->scan; + uint8_t * quant_matrix = picture->intra_quantizer_matrix; + int quantizer_scale = slice->quantizer_scale; + int mismatch; + DCTtab * tab; + uint32_t bit_buf; + int bits; + uint8_t * bit_ptr; + + i = 0; + mismatch = ~dest[0]; + + bit_buf = slice->bitstream_buf; + bits = slice->bitstream_bits; + bit_ptr = slice->bitstream_ptr; + + NEEDBITS (bit_buf, bits, bit_ptr); + + while (1) { + if (bit_buf >= 0x28000000) { + + tab = DCT_B14AC_5 - 5 + UBITS (bit_buf, 5); + + i += tab->run; + if (i >= 64) + break; // end of block + + normal_code: + j = scan[i]; + bit_buf <<= tab->len; + bits += tab->len + 1; + val = (tab->level * quantizer_scale * quant_matrix[j]) >> 4; + + // if (bitstream_get (1)) val = -val; + val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); + + SATURATE (val); + dest[j] = val; + mismatch ^= val; + + bit_buf <<= 1; + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else if (bit_buf >= 0x04000000) { + + tab = DCT_B14_8 - 4 + UBITS (bit_buf, 8); + + i += tab->run; + if (i < 64) + goto normal_code; + + // escape code + + i += UBITS (bit_buf << 6, 6) - 64; + if (i >= 64) + break; // illegal, but check needed to avoid buffer overflow + + j = scan[i]; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + val = (SBITS (bit_buf, 12) * + quantizer_scale * quant_matrix[j]) / 16; + + SATURATE (val); + dest[j] = val; + mismatch ^= val; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else if (bit_buf >= 0x02000000) { + tab = DCT_B14_10 - 8 + UBITS (bit_buf, 10); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00800000) { + tab = DCT_13 - 16 + UBITS (bit_buf, 13); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00200000) { + tab = DCT_15 - 16 + UBITS (bit_buf, 15); + i += tab->run; + if (i < 64) + goto normal_code; + } else { + tab = DCT_16 + UBITS (bit_buf, 16); + bit_buf <<= 16; + GETWORD (bit_buf, bits + 16, bit_ptr); + i += tab->run; + if (i < 64) + goto normal_code; + } + break; // illegal, but check needed to avoid buffer overflow + } + dest[63] ^= mismatch & 1; + DUMPBITS (bit_buf, bits, 2); // dump end of block code + slice->bitstream_buf = bit_buf; + slice->bitstream_bits = bits; + slice->bitstream_ptr = bit_ptr; +} + +static void get_intra_block_B15 (picture_t * picture, slice_t * slice, + int16_t * dest) +{ + int i; + int j; + int val; + uint8_t * scan = picture->scan; + uint8_t * quant_matrix = picture->intra_quantizer_matrix; + int quantizer_scale = slice->quantizer_scale; + int mismatch; + DCTtab * tab; + uint32_t bit_buf; + int bits; + uint8_t * bit_ptr; + + i = 0; + mismatch = ~dest[0]; + + bit_buf = slice->bitstream_buf; + bits = slice->bitstream_bits; + bit_ptr = slice->bitstream_ptr; + + NEEDBITS (bit_buf, bits, bit_ptr); + + while (1) { + if (bit_buf >= 0x04000000) { + + tab = DCT_B15_8 - 4 + UBITS (bit_buf, 8); + + i += tab->run; + if (i < 64) { + + normal_code: + j = scan[i]; + bit_buf <<= tab->len; + bits += tab->len + 1; + val = (tab->level * quantizer_scale * quant_matrix[j]) >> 4; + + // if (bitstream_get (1)) val = -val; + val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); + + SATURATE (val); + dest[j] = val; + mismatch ^= val; + + bit_buf <<= 1; + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else { + + // end of block. I commented out this code because if we + // dont exit here we will still exit at the later test :) + + //if (i >= 128) break; // end of block + + // escape code + + i += UBITS (bit_buf << 6, 6) - 64; + if (i >= 64) + break; // illegal, but check against buffer overflow + + j = scan[i]; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + val = (SBITS (bit_buf, 12) * + quantizer_scale * quant_matrix[j]) / 16; + + SATURATE (val); + dest[j] = val; + mismatch ^= val; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } + } else if (bit_buf >= 0x02000000) { + tab = DCT_B15_10 - 8 + UBITS (bit_buf, 10); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00800000) { + tab = DCT_13 - 16 + UBITS (bit_buf, 13); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00200000) { + tab = DCT_15 - 16 + UBITS (bit_buf, 15); + i += tab->run; + if (i < 64) + goto normal_code; + } else { + tab = DCT_16 + UBITS (bit_buf, 16); + bit_buf <<= 16; + GETWORD (bit_buf, bits + 16, bit_ptr); + i += tab->run; + if (i < 64) + goto normal_code; + } + break; // illegal, but check needed to avoid buffer overflow + } + dest[63] ^= mismatch & 1; + DUMPBITS (bit_buf, bits, 4); // dump end of block code + slice->bitstream_buf = bit_buf; + slice->bitstream_bits = bits; + slice->bitstream_ptr = bit_ptr; +} + +static void get_non_intra_block (picture_t * picture, slice_t * slice, + int16_t * dest) +{ + int i; + int j; + int val; + uint8_t * scan = picture->scan; + uint8_t * quant_matrix = picture->non_intra_quantizer_matrix; + int quantizer_scale = slice->quantizer_scale; + int mismatch; + DCTtab * tab; + uint32_t bit_buf; + int bits; + uint8_t * bit_ptr; + + i = -1; + mismatch = 1; + + bit_buf = slice->bitstream_buf; + bits = slice->bitstream_bits; + bit_ptr = slice->bitstream_ptr; + + NEEDBITS (bit_buf, bits, bit_ptr); + if (bit_buf >= 0x28000000) { + tab = DCT_B14DC_5 - 5 + UBITS (bit_buf, 5); + goto entry_1; + } else + goto entry_2; + + while (1) { + if (bit_buf >= 0x28000000) { + + tab = DCT_B14AC_5 - 5 + UBITS (bit_buf, 5); + + entry_1: + i += tab->run; + if (i >= 64) + break; // end of block + + normal_code: + j = scan[i]; + bit_buf <<= tab->len; + bits += tab->len + 1; + val = ((2*tab->level+1) * quantizer_scale * quant_matrix[j]) >> 5; + + // if (bitstream_get (1)) val = -val; + val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); + + SATURATE (val); + dest[j] = val; + mismatch ^= val; + + bit_buf <<= 1; + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } + + entry_2: + if (bit_buf >= 0x04000000) { + + tab = DCT_B14_8 - 4 + UBITS (bit_buf, 8); + + i += tab->run; + if (i < 64) + goto normal_code; + + // escape code + + i += UBITS (bit_buf << 6, 6) - 64; + if (i >= 64) + break; // illegal, but check needed to avoid buffer overflow + + j = scan[i]; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + val = 2 * (SBITS (bit_buf, 12) + SBITS (bit_buf, 1)) + 1; + val = (val * quantizer_scale * quant_matrix[j]) / 32; + + SATURATE (val); + dest[j] = val; + mismatch ^= val; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else if (bit_buf >= 0x02000000) { + tab = DCT_B14_10 - 8 + UBITS (bit_buf, 10); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00800000) { + tab = DCT_13 - 16 + UBITS (bit_buf, 13); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00200000) { + tab = DCT_15 - 16 + UBITS (bit_buf, 15); + i += tab->run; + if (i < 64) + goto normal_code; + } else { + tab = DCT_16 + UBITS (bit_buf, 16); + bit_buf <<= 16; + GETWORD (bit_buf, bits + 16, bit_ptr); + i += tab->run; + if (i < 64) + goto normal_code; + } + break; // illegal, but check needed to avoid buffer overflow + } + dest[63] ^= mismatch & 1; + DUMPBITS (bit_buf, bits, 2); // dump end of block code + slice->bitstream_buf = bit_buf; + slice->bitstream_bits = bits; + slice->bitstream_ptr = bit_ptr; +} + +static void get_mpeg1_intra_block (picture_t * picture, slice_t * slice, + int16_t * dest) +{ + int i; + int j; + int val; + uint8_t * scan = picture->scan; + uint8_t * quant_matrix = picture->intra_quantizer_matrix; + int quantizer_scale = slice->quantizer_scale; + DCTtab * tab; + uint32_t bit_buf; + int bits; + uint8_t * bit_ptr; + + i = 0; + + bit_buf = slice->bitstream_buf; + bits = slice->bitstream_bits; + bit_ptr = slice->bitstream_ptr; + + NEEDBITS (bit_buf, bits, bit_ptr); + + while (1) { + if (bit_buf >= 0x28000000) { + + tab = DCT_B14AC_5 - 5 + UBITS (bit_buf, 5); + + i += tab->run; + if (i >= 64) + break; // end of block + + normal_code: + j = scan[i]; + bit_buf <<= tab->len; + bits += tab->len + 1; + val = (tab->level * quantizer_scale * quant_matrix[j]) >> 4; + + // oddification + val = (val - 1) | 1; + + // if (bitstream_get (1)) val = -val; + val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); + + SATURATE (val); + dest[j] = val; + + bit_buf <<= 1; + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else if (bit_buf >= 0x04000000) { + + tab = DCT_B14_8 - 4 + UBITS (bit_buf, 8); + + i += tab->run; + if (i < 64) + goto normal_code; + + // escape code + + i += UBITS (bit_buf << 6, 6) - 64; + if (i >= 64) + break; // illegal, but check needed to avoid buffer overflow + + j = scan[i]; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + val = SBITS (bit_buf, 8); + if (! (val & 0x7f)) { + DUMPBITS (bit_buf, bits, 8); + val = UBITS (bit_buf, 8) + 2 * val; + } + val = (val * quantizer_scale * quant_matrix[j]) / 16; + + // oddification + val = (val + ~SBITS (val, 1)) | 1; + + SATURATE (val); + dest[j] = val; + + DUMPBITS (bit_buf, bits, 8); + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else if (bit_buf >= 0x02000000) { + tab = DCT_B14_10 - 8 + UBITS (bit_buf, 10); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00800000) { + tab = DCT_13 - 16 + UBITS (bit_buf, 13); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00200000) { + tab = DCT_15 - 16 + UBITS (bit_buf, 15); + i += tab->run; + if (i < 64) + goto normal_code; + } else { + tab = DCT_16 + UBITS (bit_buf, 16); + bit_buf <<= 16; + GETWORD (bit_buf, bits + 16, bit_ptr); + i += tab->run; + if (i < 64) + goto normal_code; + } + break; // illegal, but check needed to avoid buffer overflow + } + DUMPBITS (bit_buf, bits, 2); // dump end of block code + slice->bitstream_buf = bit_buf; + slice->bitstream_bits = bits; + slice->bitstream_ptr = bit_ptr; +} + +static void get_mpeg1_non_intra_block (picture_t * picture, slice_t * slice, + int16_t * dest) +{ + int i; + int j; + int val; + uint8_t * scan = picture->scan; + uint8_t * quant_matrix = picture->non_intra_quantizer_matrix; + int quantizer_scale = slice->quantizer_scale; + DCTtab * tab; + uint32_t bit_buf; + int bits; + uint8_t * bit_ptr; + + i = -1; + + bit_buf = slice->bitstream_buf; + bits = slice->bitstream_bits; + bit_ptr = slice->bitstream_ptr; + + NEEDBITS (bit_buf, bits, bit_ptr); + if (bit_buf >= 0x28000000) { + tab = DCT_B14DC_5 - 5 + UBITS (bit_buf, 5); + goto entry_1; + } else + goto entry_2; + + while (1) { + if (bit_buf >= 0x28000000) { + + tab = DCT_B14AC_5 - 5 + UBITS (bit_buf, 5); + + entry_1: + i += tab->run; + if (i >= 64) + break; // end of block + + normal_code: + j = scan[i]; + bit_buf <<= tab->len; + bits += tab->len + 1; + val = ((2*tab->level+1) * quantizer_scale * quant_matrix[j]) >> 5; + + // oddification + val = (val - 1) | 1; + + // if (bitstream_get (1)) val = -val; + val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); + + SATURATE (val); + dest[j] = val; + + bit_buf <<= 1; + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } + + entry_2: + if (bit_buf >= 0x04000000) { + + tab = DCT_B14_8 - 4 + UBITS (bit_buf, 8); + + i += tab->run; + if (i < 64) + goto normal_code; + + // escape code + + i += UBITS (bit_buf << 6, 6) - 64; + if (i >= 64) + break; // illegal, but check needed to avoid buffer overflow + + j = scan[i]; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + val = SBITS (bit_buf, 8); + if (! (val & 0x7f)) { + DUMPBITS (bit_buf, bits, 8); + val = UBITS (bit_buf, 8) + 2 * val; + } + val = 2 * (val + SBITS (val, 1)) + 1; + val = (val * quantizer_scale * quant_matrix[j]) / 32; + + // oddification + val = (val + ~SBITS (val, 1)) | 1; + + SATURATE (val); + dest[j] = val; + + DUMPBITS (bit_buf, bits, 8); + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else if (bit_buf >= 0x02000000) { + tab = DCT_B14_10 - 8 + UBITS (bit_buf, 10); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00800000) { + tab = DCT_13 - 16 + UBITS (bit_buf, 13); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00200000) { + tab = DCT_15 - 16 + UBITS (bit_buf, 15); + i += tab->run; + if (i < 64) + goto normal_code; + } else { + tab = DCT_16 + UBITS (bit_buf, 16); + bit_buf <<= 16; + GETWORD (bit_buf, bits + 16, bit_ptr); + i += tab->run; + if (i < 64) + goto normal_code; + } + break; // illegal, but check needed to avoid buffer overflow + } + DUMPBITS (bit_buf, bits, 2); // dump end of block code + slice->bitstream_buf = bit_buf; + slice->bitstream_bits = bits; + slice->bitstream_ptr = bit_ptr; +} + +static inline int get_macroblock_address_increment (slice_t * slice) +{ +#define bit_buf (slice->bitstream_buf) +#define bits (slice->bitstream_bits) +#define bit_ptr (slice->bitstream_ptr) + + MBAtab * tab; + int mba; + + mba = 0; + + while (1) { + if (bit_buf >= 0x10000000) { + tab = MBA_5 - 2 + UBITS (bit_buf, 5); + DUMPBITS (bit_buf, bits, tab->len); + return mba + tab->mba; + } else if (bit_buf >= 0x03000000) { + tab = MBA_11 - 24 + UBITS (bit_buf, 11); + DUMPBITS (bit_buf, bits, tab->len); + return mba + tab->mba; + } else switch (UBITS (bit_buf, 11)) { + case 8: // macroblock_escape + mba += 33; + // no break here on purpose + case 15: // macroblock_stuffing (MPEG1 only) + DUMPBITS (bit_buf, bits, 11); + NEEDBITS (bit_buf, bits, bit_ptr); + break; + default: // end of slice, or error + return 0; + } + } + +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static inline void slice_intra_DCT (picture_t * picture, slice_t * slice, + int cc, uint8_t * dest, int stride) +{ +#define bit_buf (slice->bitstream_buf) +#define bits (slice->bitstream_bits) +#define bit_ptr (slice->bitstream_ptr) + NEEDBITS (bit_buf, bits, bit_ptr); + //Get the intra DC coefficient and inverse quantize it + if (cc == 0) + slice->dc_dct_pred[0] += get_luma_dc_dct_diff (slice); + else + slice->dc_dct_pred[cc] += get_chroma_dc_dct_diff (slice); + DCTblock[0] = slice->dc_dct_pred[cc] << (3 - picture->intra_dc_precision); + + if (picture->mpeg1) { + if (picture->picture_coding_type != D_TYPE) + get_mpeg1_intra_block (picture, slice, DCTblock); + } else if (picture->intra_vlc_format) + get_intra_block_B15 (picture, slice, DCTblock); + else + get_intra_block_B14 (picture, slice, DCTblock); + idct_block_copy (DCTblock, dest, stride); + memset (DCTblock, 0, sizeof (DCTblock)); +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static inline void slice_non_intra_DCT (picture_t * picture, slice_t * slice, + uint8_t * dest, int stride) +{ + if (picture->mpeg1) + get_mpeg1_non_intra_block (picture, slice, DCTblock); + else + get_non_intra_block (picture, slice, DCTblock); + idct_block_add (DCTblock, dest, stride); + memset (DCTblock, 0, sizeof (DCTblock)); +} + +static inline void motion_block (void (** table) (uint8_t *, uint8_t *, + int32_t, int32_t), + int x_pred, int y_pred, + uint8_t * dest[3], int dest_offset, + uint8_t * src[3], int src_offset, + int stride, int height, int second_half) +{ + int xy_half; + uint8_t * src1; + uint8_t * src2; + + xy_half = ((y_pred & 1) << 1) | (x_pred & 1); + + src1 = src[0] + src_offset + (x_pred >> 1) + (y_pred >> 1) * stride + + second_half * (stride << 3); + + table[xy_half] (dest[0] + dest_offset + second_half * (stride << 3), + src1, stride, height); + + x_pred /= 2; + y_pred /= 2; + + xy_half = ((y_pred & 1) << 1) | (x_pred & 1); + stride >>= 1; + height >>= 1; + src_offset >>= 1; src_offset += second_half * (stride << 2); + dest_offset >>= 1; dest_offset += second_half * (stride << 2); + + src1 = src[1] + src_offset + (x_pred >> 1) + (y_pred >> 1) * stride; + src2 = src[2] + src_offset + (x_pred >> 1) + (y_pred >> 1) * stride; + + table[4+xy_half] (dest[1] + dest_offset, src1, stride, height); + table[4+xy_half] (dest[2] + dest_offset, src2, stride, height); +} + + +static void motion_mp1 (slice_t * slice, motion_t * motion, + uint8_t * dest[3], int offset, int width, + void (** table) (uint8_t *, uint8_t *, int, int)) +{ +#define bit_buf (slice->bitstream_buf) +#define bits (slice->bitstream_bits) +#define bit_ptr (slice->bitstream_ptr) + int motion_x, motion_y; + + NEEDBITS (bit_buf, bits, bit_ptr); + motion_x = motion->pmv[0][0] + get_motion_delta (slice, motion->f_code[0]); + motion_x = bound_motion_vector (motion_x, motion->f_code[0]); + motion->pmv[0][0] = motion_x; + + NEEDBITS (bit_buf, bits, bit_ptr); + motion_y = motion->pmv[0][1] + get_motion_delta (slice, motion->f_code[0]); + motion_y = bound_motion_vector (motion_y, motion->f_code[0]); + motion->pmv[0][1] = motion_y; + + if (motion->f_code[1]) { + motion_x <<= 1; + motion_y <<= 1; + } + + motion_block (table, motion_x, motion_y, dest, offset, + motion->ref[0], offset, width, 16, 0); +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static void motion_mp1_reuse (slice_t * slice, motion_t * motion, + uint8_t * dest[3], int offset, int width, + void (** table) (uint8_t *, uint8_t *, int, int)) +{ + int motion_x, motion_y; + + motion_x = motion->pmv[0][0]; + motion_y = motion->pmv[0][1]; + + if (motion->f_code[1]) { + motion_x <<= 1; + motion_y <<= 1; + } + + motion_block (table, motion_x, motion_y, dest, offset, + motion->ref[0], offset, width, 16, 0); +} + +static void motion_fr_frame (slice_t * slice, motion_t * motion, + uint8_t * dest[3], int offset, int width, + void (** table) (uint8_t *, uint8_t *, int, int)) +{ +#define bit_buf (slice->bitstream_buf) +#define bits (slice->bitstream_bits) +#define bit_ptr (slice->bitstream_ptr) + int motion_x, motion_y; + + NEEDBITS (bit_buf, bits, bit_ptr); + motion_x = motion->pmv[0][0] + get_motion_delta (slice, motion->f_code[0]); + motion_x = bound_motion_vector (motion_x, motion->f_code[0]); + motion->pmv[1][0] = motion->pmv[0][0] = motion_x; + + NEEDBITS (bit_buf, bits, bit_ptr); + motion_y = motion->pmv[0][1] + get_motion_delta (slice, motion->f_code[1]); + motion_y = bound_motion_vector (motion_y, motion->f_code[1]); + motion->pmv[1][1] = motion->pmv[0][1] = motion_y; + + motion_block (table, motion_x, motion_y, dest, offset, + motion->ref[0], offset, width, 16, 0); +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static void motion_fr_field (slice_t * slice, motion_t * motion, + uint8_t * dest[3], int offset, int width, + void (** table) (uint8_t *, uint8_t *, int, int)) +{ +#define bit_buf (slice->bitstream_buf) +#define bits (slice->bitstream_bits) +#define bit_ptr (slice->bitstream_ptr) + int motion_x, motion_y; + int field_select; + + NEEDBITS (bit_buf, bits, bit_ptr); + field_select = SBITS (bit_buf, 1); + DUMPBITS (bit_buf, bits, 1); + + motion_x = motion->pmv[0][0] + get_motion_delta (slice, motion->f_code[0]); + motion_x = bound_motion_vector (motion_x, motion->f_code[0]); + motion->pmv[0][0] = motion_x; + + NEEDBITS (bit_buf, bits, bit_ptr); + motion_y = (motion->pmv[0][1] >> 1) + get_motion_delta (slice, + motion->f_code[1]); + //motion_y = bound_motion_vector (motion_y, motion->f_code[1]); + motion->pmv[0][1] = motion_y << 1; + + motion_block (table, motion_x, motion_y, dest, offset, + motion->ref[0], offset + (field_select & width), + width * 2, 8, 0); + + NEEDBITS (bit_buf, bits, bit_ptr); + field_select = SBITS (bit_buf, 1); + DUMPBITS (bit_buf, bits, 1); + + motion_x = motion->pmv[1][0] + get_motion_delta (slice, motion->f_code[0]); + motion_x = bound_motion_vector (motion_x, motion->f_code[0]); + motion->pmv[1][0] = motion_x; + + NEEDBITS (bit_buf, bits, bit_ptr); + motion_y = (motion->pmv[1][1] >> 1) + get_motion_delta (slice, + motion->f_code[1]); + //motion_y = bound_motion_vector (motion_y, motion->f_code[1]); + motion->pmv[1][1] = motion_y << 1; + + motion_block (table, motion_x, motion_y, dest, offset + width, + motion->ref[0], offset + (field_select & width), + width * 2, 8, 0); +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static int motion_dmv_top_field_first; +static void motion_fr_dmv (slice_t * slice, motion_t * motion, + uint8_t * dest[3], int offset, int width, + void (** table) (uint8_t *, uint8_t *, int, int)) +{ +#define bit_buf (slice->bitstream_buf) +#define bits (slice->bitstream_bits) +#define bit_ptr (slice->bitstream_ptr) + int motion_x, motion_y; + int dmv_x, dmv_y; + int m; + int other_x, other_y; + + NEEDBITS (bit_buf, bits, bit_ptr); + motion_x = motion->pmv[0][0] + get_motion_delta (slice, motion->f_code[0]); + motion_x = bound_motion_vector (motion_x, motion->f_code[0]); + motion->pmv[1][0] = motion->pmv[0][0] = motion_x; + + NEEDBITS (bit_buf, bits, bit_ptr); + dmv_x = get_dmv (slice); + + NEEDBITS (bit_buf, bits, bit_ptr); + motion_y = (motion->pmv[0][1] >> 1) + get_motion_delta (slice, + motion->f_code[1]); + //motion_y = bound_motion_vector (motion_y, motion->f_code[1]); + motion->pmv[1][1] = motion->pmv[0][1] = motion_y << 1; + + NEEDBITS (bit_buf, bits, bit_ptr); + dmv_y = get_dmv (slice); + + motion_block (mc_functions.put, motion_x, motion_y, dest, offset, + motion->ref[0], offset, width * 2, 8, 0); + + m = motion_dmv_top_field_first ? 1 : 3; + other_x = ((motion_x * m + (motion_x > 0)) >> 1) + dmv_x; + other_y = ((motion_y * m + (motion_y > 0)) >> 1) + dmv_y - 1; + motion_block (mc_functions.avg, other_x, other_y, dest, offset, + motion->ref[0], offset + width, width * 2, 8, 0); + + motion_block (mc_functions.put, motion_x, motion_y, dest, offset + width, + motion->ref[0], offset + width, width * 2, 8, 0); + + m = motion_dmv_top_field_first ? 3 : 1; + other_x = ((motion_x * m + (motion_x > 0)) >> 1) + dmv_x; + other_y = ((motion_y * m + (motion_y > 0)) >> 1) + dmv_y + 1; + motion_block (mc_functions.avg, other_x, other_y, dest, offset + width, + motion->ref[0], offset, width * 2, 8, 0); +#undef bit_buf +#undef bits +#undef bit_ptr +} + +// like motion_frame, but reuse previous motion vectors +static void motion_fr_reuse (slice_t * slice, motion_t * motion, + uint8_t * dest[3], int offset, int width, + void (** table) (uint8_t *, uint8_t *, int, int)) +{ + motion_block (table, motion->pmv[0][0], motion->pmv[0][1], dest, offset, + motion->ref[0], offset, width, 16, 0); +} + +// like motion_frame, but use null motion vectors +static void motion_fr_zero (slice_t * slice, motion_t * motion, + uint8_t * dest[3], int offset, int width, + void (** table) (uint8_t *, uint8_t *, int, int)) +{ + motion_block (table, 0, 0, dest, offset, + motion->ref[0], offset, width, 16, 0); +} + +// like motion_frame, but parsing without actual motion compensation +static void motion_fr_conceal (slice_t * slice, motion_t * motion) +{ +#define bit_buf (slice->bitstream_buf) +#define bits (slice->bitstream_bits) +#define bit_ptr (slice->bitstream_ptr) + int tmp; + + NEEDBITS (bit_buf, bits, bit_ptr); + tmp = motion->pmv[0][0] + get_motion_delta (slice, motion->f_code[0]); + tmp = bound_motion_vector (tmp, motion->f_code[0]); + motion->pmv[1][0] = motion->pmv[0][0] = tmp; + + NEEDBITS (bit_buf, bits, bit_ptr); + tmp = motion->pmv[0][1] + get_motion_delta (slice, motion->f_code[1]); + tmp = bound_motion_vector (tmp, motion->f_code[1]); + motion->pmv[1][1] = motion->pmv[0][1] = tmp; + + DUMPBITS (bit_buf, bits, 1); // remove marker_bit +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static void motion_fi_field (slice_t * slice, motion_t * motion, + uint8_t * dest[3], int offset, int width, + void (** table) (uint8_t *, uint8_t *, int, int)) +{ +#define bit_buf (slice->bitstream_buf) +#define bits (slice->bitstream_bits) +#define bit_ptr (slice->bitstream_ptr) + int motion_x, motion_y; + int field_select; + + NEEDBITS (bit_buf, bits, bit_ptr); + field_select = UBITS (bit_buf, 1); + DUMPBITS (bit_buf, bits, 1); + + NEEDBITS (bit_buf, bits, bit_ptr); + motion_x = motion->pmv[0][0] + get_motion_delta (slice, motion->f_code[0]); + motion_x = bound_motion_vector (motion_x, motion->f_code[0]); + motion->pmv[1][0] = motion->pmv[0][0] = motion_x; + + NEEDBITS (bit_buf, bits, bit_ptr); + motion_y = motion->pmv[0][1] + get_motion_delta (slice, motion->f_code[1]); + motion_y = bound_motion_vector (motion_y, motion->f_code[1]); + motion->pmv[1][1] = motion->pmv[0][1] = motion_y; + + motion_block (table, motion_x, motion_y, dest, offset, + motion->ref[field_select], offset, width, 16, 0); +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static void motion_fi_16x8 (slice_t * slice, motion_t * motion, + uint8_t * dest[3], int offset, int width, + void (** table) (uint8_t *, uint8_t *, int, int)) +{ +#define bit_buf (slice->bitstream_buf) +#define bits (slice->bitstream_bits) +#define bit_ptr (slice->bitstream_ptr) + int motion_x, motion_y; + int field_select; + + NEEDBITS (bit_buf, bits, bit_ptr); + field_select = UBITS (bit_buf, 1); + DUMPBITS (bit_buf, bits, 1); + + NEEDBITS (bit_buf, bits, bit_ptr); + motion_x = motion->pmv[0][0] + get_motion_delta (slice, motion->f_code[0]); + motion_x = bound_motion_vector (motion_x, motion->f_code[0]); + motion->pmv[0][0] = motion_x; + + NEEDBITS (bit_buf, bits, bit_ptr); + motion_y = motion->pmv[0][1] + get_motion_delta (slice, motion->f_code[1]); + motion_y = bound_motion_vector (motion_y, motion->f_code[1]); + motion->pmv[0][1] = motion_y; + + motion_block (table, motion_x, motion_y, dest, offset, + motion->ref[field_select], offset, width, 8, 0); + + NEEDBITS (bit_buf, bits, bit_ptr); + field_select = UBITS (bit_buf, 1); + DUMPBITS (bit_buf, bits, 1); + + NEEDBITS (bit_buf, bits, bit_ptr); + motion_x = motion->pmv[1][0] + get_motion_delta (slice, motion->f_code[0]); + motion_x = bound_motion_vector (motion_x, motion->f_code[0]); + motion->pmv[1][0] = motion_x; + + NEEDBITS (bit_buf, bits, bit_ptr); + motion_y = motion->pmv[1][1] + get_motion_delta (slice, motion->f_code[1]); + motion_y = bound_motion_vector (motion_y, motion->f_code[1]); + motion->pmv[1][1] = motion_y; + + motion_block (table, motion_x, motion_y, dest, offset, + motion->ref[field_select], offset, width, 8, 1); +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static int current_field = 0; +static void motion_fi_dmv (slice_t * slice, motion_t * motion, + uint8_t * dest[3], int offset, int width, + void (** table) (uint8_t *, uint8_t *, int, int)) +{ +#define bit_buf (slice->bitstream_buf) +#define bits (slice->bitstream_bits) +#define bit_ptr (slice->bitstream_ptr) + int motion_x, motion_y; + int dmv_x, dmv_y; + + NEEDBITS (bit_buf, bits, bit_ptr); + motion_x = motion->pmv[0][0] + get_motion_delta (slice, motion->f_code[0]); + motion_x = bound_motion_vector (motion_x, motion->f_code[0]); + motion->pmv[1][0] = motion->pmv[0][0] = motion_x; + + NEEDBITS (bit_buf, bits, bit_ptr); + dmv_x = get_dmv (slice); + + NEEDBITS (bit_buf, bits, bit_ptr); + motion_y = motion->pmv[0][1] + get_motion_delta (slice, motion->f_code[1]); + motion_y = bound_motion_vector (motion_y, motion->f_code[1]); + motion->pmv[1][1] = motion->pmv[0][1] = motion_y; + + NEEDBITS (bit_buf, bits, bit_ptr); + dmv_y = get_dmv (slice); + + motion_block (mc_functions.put, motion_x, motion_y, dest, offset, + motion->ref[current_field], offset, width, 16, 0); + + motion_x = ((motion_x + (motion_x > 0)) >> 1) + dmv_x; + motion_y = ((motion_y + (motion_y > 0)) >> 1) + dmv_y + + 2 * current_field - 1; + motion_block (mc_functions.avg, motion_x, motion_y, dest, offset, + motion->ref[!current_field], offset, width, 16, 0); +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static void motion_fi_reuse (slice_t * slice, motion_t * motion, + uint8_t * dest[3], int offset, int width, + void (** table) (uint8_t *, uint8_t *, int, int)) +{ + motion_block (table, motion->pmv[0][0], motion->pmv[0][1], dest, offset, + motion->ref[current_field], offset, width, 16, 0); +} + +static void motion_fi_zero (slice_t * slice, motion_t * motion, + uint8_t * dest[3], int offset, int width, + void (** table) (uint8_t *, uint8_t *, int, int)) +{ + motion_block (table, 0, 0, dest, offset, + motion->ref[current_field], offset, width, 16, 0); +} + +static void motion_fi_conceal (slice_t * slice, motion_t * motion) +{ +#define bit_buf (slice->bitstream_buf) +#define bits (slice->bitstream_bits) +#define bit_ptr (slice->bitstream_ptr) + int tmp; + + NEEDBITS (bit_buf, bits, bit_ptr); + DUMPBITS (bit_buf, bits, 1); // remove field_select + + NEEDBITS (bit_buf, bits, bit_ptr); + tmp = motion->pmv[0][0] + get_motion_delta (slice, motion->f_code[0]); + tmp = bound_motion_vector (tmp, motion->f_code[0]); + motion->pmv[1][0] = motion->pmv[0][0] = tmp; + + NEEDBITS (bit_buf, bits, bit_ptr); + tmp = motion->pmv[0][1] + get_motion_delta (slice, motion->f_code[1]); + tmp = bound_motion_vector (tmp, motion->f_code[1]); + motion->pmv[1][1] = motion->pmv[0][1] = tmp; + + DUMPBITS (bit_buf, bits, 1); // remove marker_bit +#undef bit_buf +#undef bits +#undef bit_ptr +} + +#define MOTION(routine,direction,slice,dest,offset,stride) \ +do { \ + if ((direction) & MACROBLOCK_MOTION_FORWARD) \ + routine (&slice, &((slice).f_motion), dest, offset, stride, \ + mc_functions.put); \ + if ((direction) & MACROBLOCK_MOTION_BACKWARD) \ + routine (&slice, &((slice).b_motion), dest, offset, stride, \ + ((direction) & MACROBLOCK_MOTION_FORWARD ? \ + mc_functions.avg : mc_functions.put)); \ +} while (0) + +#define CHECK_DISPLAY \ +do { \ + if (offset == width) { \ + slice.f_motion.ref[0][0] += 16 * offset; \ + slice.f_motion.ref[0][1] += 4 * offset; \ + slice.f_motion.ref[0][2] += 4 * offset; \ + slice.b_motion.ref[0][0] += 16 * offset; \ + slice.b_motion.ref[0][1] += 4 * offset; \ + slice.b_motion.ref[0][2] += 4 * offset; \ + dest[0] += 16 * offset; \ + dest[1] += 4 * offset; \ + dest[2] += 4 * offset; \ + offset = 0; ++ypos; \ + } \ +} while (0) + +int slice_process (picture_t * picture, uint8_t code, uint8_t * buffer) +{ +#define bit_buf (slice.bitstream_buf) +#define bits (slice.bitstream_bits) +#define bit_ptr (slice.bitstream_ptr) + slice_t slice; + int macroblock_modes; + int width; + int ypos=code-1; + uint8_t * dest[3]; + int offset; + uint8_t ** forward_ref[2]; + + width = picture->coded_picture_width; + offset = ypos * width * 4; + + forward_ref[0] = picture->forward_reference_frame; + if (picture->picture_structure != FRAME_PICTURE) { + offset <<= 1; + forward_ref[1] = picture->forward_reference_frame; + current_field = (picture->picture_structure == BOTTOM_FIELD); + if ((picture->second_field) && + (picture->picture_coding_type != B_TYPE)) + forward_ref[picture->picture_structure == TOP_FIELD] = + picture->current_frame; + slice.f_motion.ref[1][0] = forward_ref[1][0] + offset * 4 + width; + slice.f_motion.ref[1][1] = forward_ref[1][1] + offset + (width >> 1); + slice.f_motion.ref[1][2] = forward_ref[1][2] + offset + (width >> 1); + slice.b_motion.ref[1][0] = + picture->backward_reference_frame[0] + offset * 4 + width; + slice.b_motion.ref[1][1] = + picture->backward_reference_frame[1] + offset + (width >> 1); + slice.b_motion.ref[1][2] = + picture->backward_reference_frame[2] + offset + (width >> 1); + } + + slice.f_motion.ref[0][0] = forward_ref[0][0] + offset * 4; + slice.f_motion.ref[0][1] = forward_ref[0][1] + offset; + slice.f_motion.ref[0][2] = forward_ref[0][2] + offset; + slice.f_motion.f_code[0] = picture->f_code[0][0]; + slice.f_motion.f_code[1] = picture->f_code[0][1]; + slice.f_motion.pmv[0][0] = slice.f_motion.pmv[0][1] = 0; + slice.f_motion.pmv[1][0] = slice.f_motion.pmv[1][1] = 0; + slice.b_motion.ref[0][0] = + picture->backward_reference_frame[0] + offset * 4; + slice.b_motion.ref[0][1] = + picture->backward_reference_frame[1] + offset; + slice.b_motion.ref[0][2] = + picture->backward_reference_frame[2] + offset; + slice.b_motion.f_code[0] = picture->f_code[1][0]; + slice.b_motion.f_code[1] = picture->f_code[1][1]; + slice.b_motion.pmv[0][0] = slice.b_motion.pmv[0][1] = 0; + slice.b_motion.pmv[1][0] = slice.b_motion.pmv[1][1] = 0; + + if ((! HACK_MODE) && (!picture->mpeg1) && + (picture->picture_coding_type == B_TYPE)) + offset = 0; + + dest[0] = picture->current_frame[0] + offset * 4; + dest[1] = picture->current_frame[1] + offset; + dest[2] = picture->current_frame[2] + offset; + + switch (picture->picture_structure) { + case BOTTOM_FIELD: + dest[0] += width; + dest[1] += width >> 1; + dest[2] += width >> 1; + // follow thru + case TOP_FIELD: + width <<= 1; + } + + //reset intra dc predictor + slice.dc_dct_pred[0]=slice.dc_dct_pred[1]=slice.dc_dct_pred[2]= + 1<< (picture->intra_dc_precision + 7) ; + + bitstream_init (&slice, buffer); + + slice.quantizer_scale = get_quantizer_scale (&slice, + picture->q_scale_type); + + //Ignore intra_slice and all the extra data + while (bit_buf & 0x80000000) { + DUMPBITS (bit_buf, bits, 9); + NEEDBITS (bit_buf, bits, bit_ptr); + } + DUMPBITS (bit_buf, bits, 1); + + NEEDBITS (bit_buf, bits, bit_ptr); + offset = get_macroblock_address_increment (&slice) << 4; + + while (1) { + NEEDBITS (bit_buf, bits, bit_ptr); + + macroblock_modes = + get_macroblock_modes (&slice, picture->picture_structure, + picture->picture_coding_type, + picture->frame_pred_frame_dct); + + // maybe integrate MACROBLOCK_QUANT test into get_macroblock_modes ? + if (macroblock_modes & MACROBLOCK_QUANT) + slice.quantizer_scale = + get_quantizer_scale (&slice, picture->q_scale_type); + + if (macroblock_modes & MACROBLOCK_INTRA) { + + int DCT_offset, DCT_stride; + + if (picture->concealment_motion_vectors) { + if (picture->picture_structure == FRAME_PICTURE) + motion_fr_conceal (&slice, &slice.f_motion); + else + motion_fi_conceal (&slice, &slice.f_motion); + } else { + slice.f_motion.pmv[0][0] = slice.f_motion.pmv[0][1] = 0; + slice.f_motion.pmv[1][0] = slice.f_motion.pmv[1][1] = 0; + slice.b_motion.pmv[0][0] = slice.b_motion.pmv[0][1] = 0; + slice.b_motion.pmv[1][0] = slice.b_motion.pmv[1][1] = 0; + } + + if (macroblock_modes & DCT_TYPE_INTERLACED) { + DCT_offset = width; + DCT_stride = width * 2; + } else { + DCT_offset = width * 8; + DCT_stride = width; + } + + // Decode lum blocks + slice_intra_DCT (picture, &slice, 0, + dest[0] + offset, DCT_stride); + slice_intra_DCT (picture, &slice, 0, + dest[0] + offset + 8, DCT_stride); + slice_intra_DCT (picture, &slice, 0, + dest[0] + offset + DCT_offset, DCT_stride); + slice_intra_DCT (picture, &slice, 0, + dest[0] + offset + DCT_offset + 8, DCT_stride); + + // Decode chroma blocks + slice_intra_DCT (picture, &slice, 1, + dest[1] + (offset>>1), width>>1); + slice_intra_DCT (picture, &slice, 2, + dest[2] + (offset>>1), width>>1); + + if (picture->picture_coding_type == D_TYPE) { + NEEDBITS (bit_buf, bits, bit_ptr); + DUMPBITS (bit_buf, bits, 1); + } + } else { + + if (picture->mpeg1) { + if ((macroblock_modes & MOTION_TYPE_MASK) == MC_FRAME) + MOTION (motion_mp1, macroblock_modes, slice, + dest, offset,width); + else { + // non-intra mb without forward mv in a P picture + slice.f_motion.pmv[0][0] = slice.f_motion.pmv[0][1] = 0; + slice.f_motion.pmv[1][0] = slice.f_motion.pmv[1][1] = 0; + + MOTION (motion_fr_zero, MACROBLOCK_MOTION_FORWARD, slice, + dest, offset, width); + } + } else if (picture->picture_structure == FRAME_PICTURE) + switch (macroblock_modes & MOTION_TYPE_MASK) { + case MC_FRAME: + MOTION (motion_fr_frame, macroblock_modes, slice, + dest, offset, width); + break; + + case MC_FIELD: + MOTION (motion_fr_field, macroblock_modes, slice, + dest, offset, width); + break; + + case MC_DMV: + motion_dmv_top_field_first = picture->top_field_first; + MOTION (motion_fr_dmv, MACROBLOCK_MOTION_FORWARD, slice, + dest, offset, width); + break; + + case 0: + // non-intra mb without forward mv in a P picture + slice.f_motion.pmv[0][0] = slice.f_motion.pmv[0][1] = 0; + slice.f_motion.pmv[1][0] = slice.f_motion.pmv[1][1] = 0; + + MOTION (motion_fr_zero, MACROBLOCK_MOTION_FORWARD, slice, + dest, offset, width); + break; + } + else + switch (macroblock_modes & MOTION_TYPE_MASK) { + case MC_FIELD: + MOTION (motion_fi_field, macroblock_modes, slice, + dest, offset, width); + break; + + case MC_16X8: + MOTION (motion_fi_16x8, macroblock_modes, slice, + dest, offset, width); + break; + + case MC_DMV: + motion_dmv_top_field_first = picture->top_field_first; + MOTION (motion_fi_dmv, MACROBLOCK_MOTION_FORWARD, slice, + dest, offset, width); + break; + + case 0: + // non-intra mb without forward mv in a P picture + slice.f_motion.pmv[0][0] = slice.f_motion.pmv[0][1] = 0; + slice.f_motion.pmv[1][0] = slice.f_motion.pmv[1][1] = 0; + + MOTION (motion_fi_zero, MACROBLOCK_MOTION_FORWARD, slice, + dest, offset, width); + break; + } + + //6.3.17.4 Coded block pattern + if (macroblock_modes & MACROBLOCK_PATTERN) { + int coded_block_pattern; + int DCT_offset, DCT_stride; + + if (macroblock_modes & DCT_TYPE_INTERLACED) { + DCT_offset = width; + DCT_stride = width * 2; + } else { + DCT_offset = width * 8; + DCT_stride = width; + } + + coded_block_pattern = get_coded_block_pattern (&slice); + + // Decode lum blocks + + if (coded_block_pattern & 0x20) + slice_non_intra_DCT (picture, &slice, + dest[0] + offset, DCT_stride); + if (coded_block_pattern & 0x10) + slice_non_intra_DCT (picture, &slice, + dest[0] + offset + 8, DCT_stride); + if (coded_block_pattern & 0x08) + slice_non_intra_DCT (picture, &slice, + dest[0] + offset + DCT_offset, + DCT_stride); + if (coded_block_pattern & 0x04) + slice_non_intra_DCT (picture, &slice, + dest[0] + offset + DCT_offset + 8, + DCT_stride); + + // Decode chroma blocks + + if (coded_block_pattern & 0x2) + slice_non_intra_DCT (picture, &slice, + dest[1] + (offset>>1), width >> 1); + if (coded_block_pattern & 0x1) + slice_non_intra_DCT (picture, &slice, + dest[2] + (offset>>1), width >> 1); + } + + slice.dc_dct_pred[0]=slice.dc_dct_pred[1]=slice.dc_dct_pred[2]= + 1 << (picture->intra_dc_precision + 7); + } + +// printf("[%d]",slice.quantizer_scale); +// printf("[%d,%d]",offset>>4,ypos); + quant_store[ypos+1][(offset>>4)+1] = slice.quantizer_scale; + + offset += 16; + CHECK_DISPLAY; + + NEEDBITS (bit_buf, bits, bit_ptr); + + if (bit_buf & 0x80000000) { + DUMPBITS (bit_buf, bits, 1); + } else { + int mba_inc; + + mba_inc = get_macroblock_address_increment (&slice); + if (!mba_inc) + break; + + //reset intra dc predictor on skipped block + slice.dc_dct_pred[0]=slice.dc_dct_pred[1]=slice.dc_dct_pred[2]= + 1<< (picture->intra_dc_precision + 7); + + //handling of skipped mb's differs between P_TYPE and B_TYPE + //pictures + if (picture->picture_coding_type == P_TYPE) { + slice.f_motion.pmv[0][0] = slice.f_motion.pmv[0][1] = 0; + slice.f_motion.pmv[1][0] = slice.f_motion.pmv[1][1] = 0; + + do { + if (picture->picture_structure == FRAME_PICTURE) + MOTION (motion_fr_zero, MACROBLOCK_MOTION_FORWARD, + slice, dest, offset, width); + else + MOTION (motion_fi_zero, MACROBLOCK_MOTION_FORWARD, + slice, dest, offset, width); + + quant_store[ypos+1][(offset>>4)+1] = slice.quantizer_scale; +// printf("[%d,%d]",offset>>4,ypos); + offset += 16; + CHECK_DISPLAY; + } while (--mba_inc); + } else { + do { + if (picture->mpeg1) + MOTION (motion_mp1_reuse, macroblock_modes, + slice, dest, offset, width); + else if (picture->picture_structure == FRAME_PICTURE) + MOTION (motion_fr_reuse, macroblock_modes, + slice, dest, offset, width); + else + MOTION (motion_fi_reuse, macroblock_modes, + slice, dest, offset, width); + + quant_store[ypos+1][(offset>>4)+1] = slice.quantizer_scale; +// printf("[%d,%d]",offset>>4,ypos); + offset += 16; + CHECK_DISPLAY; + } while (--mba_inc); + } + } + } + + return 0; +#undef bit_buf +#undef bits +#undef bit_ptr +} diff --git a/libmpeg2/sse.h b/libmpeg2/sse.h new file mode 100644 index 0000000000..51540dca08 --- /dev/null +++ b/libmpeg2/sse.h @@ -0,0 +1,256 @@ +/* + * sse.h + * Copyright (C) 1999 R. Fisher + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec 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. + * + * mpeg2dec 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 + */ + + +typedef union { + float sf[4]; /* Single-precision (32-bit) value */ +} ATTR_ALIGN(16) sse_t; /* On a 16 byte (128-bit) boundary */ + + +#define sse_i2r(op, imm, reg) \ + __asm__ __volatile__ (#op " %0, %%" #reg \ + : /* nothing */ \ + : "X" (imm) ) + +#define sse_m2r(op, mem, reg) \ + __asm__ __volatile__ (#op " %0, %%" #reg \ + : /* nothing */ \ + : "X" (mem)) + +#define sse_r2m(op, reg, mem) \ + __asm__ __volatile__ (#op " %%" #reg ", %0" \ + : "=X" (mem) \ + : /* nothing */ ) + +#define sse_r2r(op, regs, regd) \ + __asm__ __volatile__ (#op " %" #regs ", %" #regd) + +#define sse_r2ri(op, regs, regd, imm) \ + __asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \ + : /* nothing */ \ + : "X" (imm) ) + +#define sse_m2ri(op, mem, reg, subop) \ + __asm__ __volatile__ (#op " %0, %%" #reg ", " #subop \ + : /* nothing */ \ + : "X" (mem)) + + +#define movaps_m2r(var, reg) sse_m2r(movaps, var, reg) +#define movaps_r2m(reg, var) sse_r2m(movaps, reg, var) +#define movaps_r2r(regs, regd) sse_r2r(movaps, regs, regd) + +#define movntps_r2m(xmmreg, var) sse_r2m(movntps, xmmreg, var) + +#define movups_m2r(var, reg) sse_m2r(movups, var, reg) +#define movups_r2m(reg, var) sse_r2m(movups, reg, var) +#define movups_r2r(regs, regd) sse_r2r(movups, regs, regd) + +#define movhlps_r2r(regs, regd) sse_r2r(movhlps, regs, regd) + +#define movlhps_r2r(regs, regd) sse_r2r(movlhps, regs, regd) + +#define movhps_m2r(var, reg) sse_m2r(movhps, var, reg) +#define movhps_r2m(reg, var) sse_r2m(movhps, reg, var) + +#define movlps_m2r(var, reg) sse_m2r(movlps, var, reg) +#define movlps_r2m(reg, var) sse_r2m(movlps, reg, var) + +#define movss_m2r(var, reg) sse_m2r(movss, var, reg) +#define movss_r2m(reg, var) sse_r2m(movss, reg, var) +#define movss_r2r(regs, regd) sse_r2r(movss, regs, regd) + +#define shufps_m2r(var, reg, index) sse_m2ri(shufps, var, reg, index) +#define shufps_r2r(regs, regd, index) sse_r2ri(shufps, regs, regd, index) + +#define cvtpi2ps_m2r(var, xmmreg) sse_m2r(cvtpi2ps, var, xmmreg) +#define cvtpi2ps_r2r(mmreg, xmmreg) sse_r2r(cvtpi2ps, mmreg, xmmreg) + +#define cvtps2pi_m2r(var, mmreg) sse_m2r(cvtps2pi, var, mmreg) +#define cvtps2pi_r2r(xmmreg, mmreg) sse_r2r(cvtps2pi, mmreg, xmmreg) + +#define cvttps2pi_m2r(var, mmreg) sse_m2r(cvttps2pi, var, mmreg) +#define cvttps2pi_r2r(xmmreg, mmreg) sse_r2r(cvttps2pi, mmreg, xmmreg) + +#define cvtsi2ss_m2r(var, xmmreg) sse_m2r(cvtsi2ss, var, xmmreg) +#define cvtsi2ss_r2r(reg, xmmreg) sse_r2r(cvtsi2ss, reg, xmmreg) + +#define cvtss2si_m2r(var, reg) sse_m2r(cvtss2si, var, reg) +#define cvtss2si_r2r(xmmreg, reg) sse_r2r(cvtss2si, xmmreg, reg) + +#define cvttss2si_m2r(var, reg) sse_m2r(cvtss2si, var, reg) +#define cvttss2si_r2r(xmmreg, reg) sse_r2r(cvtss2si, xmmreg, reg) + +#define movmskps(xmmreg, reg) \ + __asm__ __volatile__ ("movmskps %" #xmmreg ", %" #reg) + +#define addps_m2r(var, reg) sse_m2r(addps, var, reg) +#define addps_r2r(regs, regd) sse_r2r(addps, regs, regd) + +#define addss_m2r(var, reg) sse_m2r(addss, var, reg) +#define addss_r2r(regs, regd) sse_r2r(addss, regs, regd) + +#define subps_m2r(var, reg) sse_m2r(subps, var, reg) +#define subps_r2r(regs, regd) sse_r2r(subps, regs, regd) + +#define subss_m2r(var, reg) sse_m2r(subss, var, reg) +#define subss_r2r(regs, regd) sse_r2r(subss, regs, regd) + +#define mulps_m2r(var, reg) sse_m2r(mulps, var, reg) +#define mulps_r2r(regs, regd) sse_r2r(mulps, regs, regd) + +#define mulss_m2r(var, reg) sse_m2r(mulss, var, reg) +#define mulss_r2r(regs, regd) sse_r2r(mulss, regs, regd) + +#define divps_m2r(var, reg) sse_m2r(divps, var, reg) +#define divps_r2r(regs, regd) sse_r2r(divps, regs, regd) + +#define divss_m2r(var, reg) sse_m2r(divss, var, reg) +#define divss_r2r(regs, regd) sse_r2r(divss, regs, regd) + +#define rcpps_m2r(var, reg) sse_m2r(rcpps, var, reg) +#define rcpps_r2r(regs, regd) sse_r2r(rcpps, regs, regd) + +#define rcpss_m2r(var, reg) sse_m2r(rcpss, var, reg) +#define rcpss_r2r(regs, regd) sse_r2r(rcpss, regs, regd) + +#define rsqrtps_m2r(var, reg) sse_m2r(rsqrtps, var, reg) +#define rsqrtps_r2r(regs, regd) sse_r2r(rsqrtps, regs, regd) + +#define rsqrtss_m2r(var, reg) sse_m2r(rsqrtss, var, reg) +#define rsqrtss_r2r(regs, regd) sse_r2r(rsqrtss, regs, regd) + +#define sqrtps_m2r(var, reg) sse_m2r(sqrtps, var, reg) +#define sqrtps_r2r(regs, regd) sse_r2r(sqrtps, regs, regd) + +#define sqrtss_m2r(var, reg) sse_m2r(sqrtss, var, reg) +#define sqrtss_r2r(regs, regd) sse_r2r(sqrtss, regs, regd) + +#define andps_m2r(var, reg) sse_m2r(andps, var, reg) +#define andps_r2r(regs, regd) sse_r2r(andps, regs, regd) + +#define andnps_m2r(var, reg) sse_m2r(andnps, var, reg) +#define andnps_r2r(regs, regd) sse_r2r(andnps, regs, regd) + +#define orps_m2r(var, reg) sse_m2r(orps, var, reg) +#define orps_r2r(regs, regd) sse_r2r(orps, regs, regd) + +#define xorps_m2r(var, reg) sse_m2r(xorps, var, reg) +#define xorps_r2r(regs, regd) sse_r2r(xorps, regs, regd) + +#define maxps_m2r(var, reg) sse_m2r(maxps, var, reg) +#define maxps_r2r(regs, regd) sse_r2r(maxps, regs, regd) + +#define maxss_m2r(var, reg) sse_m2r(maxss, var, reg) +#define maxss_r2r(regs, regd) sse_r2r(maxss, regs, regd) + +#define minps_m2r(var, reg) sse_m2r(minps, var, reg) +#define minps_r2r(regs, regd) sse_r2r(minps, regs, regd) + +#define minss_m2r(var, reg) sse_m2r(minss, var, reg) +#define minss_r2r(regs, regd) sse_r2r(minss, regs, regd) + +#define cmpps_m2r(var, reg, op) sse_m2ri(cmpps, var, reg, op) +#define cmpps_r2r(regs, regd, op) sse_r2ri(cmpps, regs, regd, op) + +#define cmpeqps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 0) +#define cmpeqps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 0) + +#define cmpltps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 1) +#define cmpltps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 1) + +#define cmpleps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 2) +#define cmpleps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 2) + +#define cmpunordps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 3) +#define cmpunordps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 3) + +#define cmpneqps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 4) +#define cmpneqps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 4) + +#define cmpnltps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 5) +#define cmpnltps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 5) + +#define cmpnleps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 6) +#define cmpnleps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 6) + +#define cmpordps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 7) +#define cmpordps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 7) + +#define cmpss_m2r(var, reg, op) sse_m2ri(cmpss, var, reg, op) +#define cmpss_r2r(regs, regd, op) sse_r2ri(cmpss, regs, regd, op) + +#define cmpeqss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 0) +#define cmpeqss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 0) + +#define cmpltss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 1) +#define cmpltss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 1) + +#define cmpless_m2r(var, reg) sse_m2ri(cmpss, var, reg, 2) +#define cmpless_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 2) + +#define cmpunordss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 3) +#define cmpunordss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 3) + +#define cmpneqss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 4) +#define cmpneqss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 4) + +#define cmpnltss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 5) +#define cmpnltss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 5) + +#define cmpnless_m2r(var, reg) sse_m2ri(cmpss, var, reg, 6) +#define cmpnless_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 6) + +#define cmpordss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 7) +#define cmpordss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 7) + +#define comiss_m2r(var, reg) sse_m2r(comiss, var, reg) +#define comiss_r2r(regs, regd) sse_r2r(comiss, regs, regd) + +#define ucomiss_m2r(var, reg) sse_m2r(ucomiss, var, reg) +#define ucomiss_r2r(regs, regd) sse_r2r(ucomiss, regs, regd) + +#define unpcklps_m2r(var, reg) sse_m2r(unpcklps, var, reg) +#define unpcklps_r2r(regs, regd) sse_r2r(unpcklps, regs, regd) + +#define unpckhps_m2r(var, reg) sse_m2r(unpckhps, var, reg) +#define unpckhps_r2r(regs, regd) sse_r2r(unpckhps, regs, regd) + +#define fxrstor(mem) \ + __asm__ __volatile__ ("fxrstor %0" \ + : /* nothing */ \ + : "X" (mem)) + +#define fxsave(mem) \ + __asm__ __volatile__ ("fxsave %0" \ + : /* nothing */ \ + : "X" (mem)) + +#define stmxcsr(mem) \ + __asm__ __volatile__ ("stmxcsr %0" \ + : /* nothing */ \ + : "X" (mem)) + +#define ldmxcsr(mem) \ + __asm__ __volatile__ ("ldmxcsr %0" \ + : /* nothing */ \ + : "X" (mem)) + diff --git a/libmpeg2/stats.c b/libmpeg2/stats.c new file mode 100644 index 0000000000..b342bef7a2 --- /dev/null +++ b/libmpeg2/stats.c @@ -0,0 +1,316 @@ +/* + * stats.c + * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec 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. + * + * mpeg2dec 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 + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <inttypes.h> + +#include "mpeg2_internal.h" + +static int debug_level = -1; + +// Determine is debug output is required. +// We could potentially have multiple levels of debug info +static int debug_is_on (void) +{ + char * env_var; + + if (debug_level < 0) { + env_var = getenv ("MPEG2_DEBUG"); + + if (env_var) + debug_level = 1; + else + debug_level = 0; + } + + return debug_level; +} + +static void stats_picture (uint8_t * buffer) +{ + static char * picture_coding_type_str [8] = { + "Invalid picture type", + "I-type", + "P-type", + "B-type", + "D (very bad)", + "Invalid","Invalid","Invalid" + }; + + int picture_coding_type; + int temporal_reference; + int vbv_delay; + + temporal_reference = (buffer[0] << 2) | (buffer[1] >> 6); + picture_coding_type = (buffer [1] >> 3) & 7; + vbv_delay = ((buffer[1] << 13) | (buffer[2] << 5) | + (buffer[3] >> 3)) & 0xffff; + + fprintf (stderr, " (picture) %s temporal_reference %d, vbv_delay %d\n", + picture_coding_type_str [picture_coding_type], + temporal_reference, vbv_delay); +} + +static void stats_user_data (uint8_t * buffer) +{ + fprintf (stderr, " (user_data)\n"); +} + +static void stats_sequence (uint8_t * buffer) +{ + static char * aspect_ratio_information_str[8] = { + "Invalid Aspect Ratio", + "1:1", + "4:3", + "16:9", + "2.21:1", + "Invalid Aspect Ratio", + "Invalid Aspect Ratio", + "Invalid Aspect Ratio" + }; + static char * frame_rate_str[16] = { + "Invalid frame_rate_code", + "23.976", "24", "25" , "29.97", + "30" , "50", "59.94", "60" , + "Invalid frame_rate_code", "Invalid frame_rate_code", + "Invalid frame_rate_code", "Invalid frame_rate_code", + "Invalid frame_rate_code", "Invalid frame_rate_code", + "Invalid frame_rate_code" + }; + + int horizontal_size; + int vertical_size; + int aspect_ratio_information; + int frame_rate_code; + int bit_rate_value; + int vbv_buffer_size_value; + int constrained_parameters_flag; + int load_intra_quantizer_matrix; + int load_non_intra_quantizer_matrix; + + vertical_size = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2]; + horizontal_size = vertical_size >> 12; + vertical_size &= 0xfff; + aspect_ratio_information = buffer[3] >> 4; + frame_rate_code = buffer[3] & 15; + bit_rate_value = (buffer[4] << 10) | (buffer[5] << 2) | (buffer[6] >> 6); + vbv_buffer_size_value = ((buffer[6] << 5) | (buffer[7] >> 3)) & 0x3ff; + constrained_parameters_flag = buffer[7] & 4; + load_intra_quantizer_matrix = buffer[7] & 2; + if (load_intra_quantizer_matrix) + buffer += 64; + load_non_intra_quantizer_matrix = buffer[7] & 1; + + fprintf (stderr, " (seq) %dx%d %s, %s fps, %5.0f kbps, VBV %d kB%s%s%s\n", + horizontal_size, vertical_size, + aspect_ratio_information_str [aspect_ratio_information], + frame_rate_str [frame_rate_code], + bit_rate_value * 400.0 / 1000.0, + 2 * vbv_buffer_size_value, + constrained_parameters_flag ? " , CP":"", + load_intra_quantizer_matrix ? " , Custom Intra Matrix":"", + load_non_intra_quantizer_matrix ? " , Custom Non-Intra Matrix":""); +} + +static void stats_sequence_error (uint8_t * buffer) +{ + fprintf (stderr, " (sequence_error)\n"); +} + +static void stats_sequence_end (uint8_t * buffer) +{ + fprintf (stderr, " (sequence_end)\n"); +} + +static void stats_group (uint8_t * buffer) +{ + fprintf (stderr, " (group)%s%s\n", + (buffer[4] & 0x40) ? " closed_gop" : "", + (buffer[4] & 0x20) ? " broken_link" : ""); +} + +static void stats_slice (uint8_t code, uint8_t * buffer) +{ + //fprintf (stderr, " (slice %d)\n", code); +} + +static void stats_sequence_extension (uint8_t * buffer) +{ + static char * chroma_format_str[4] = { + "Invalid Chroma Format", + "4:2:0 Chroma", + "4:2:2 Chroma", + "4:4:4 Chroma" + }; + + int progressive_sequence; + int chroma_format; + + progressive_sequence = (buffer[1] >> 3) & 1; + chroma_format = (buffer[1] >> 1) & 3; + + fprintf (stderr, " (seq_ext) progressive_sequence %d, %s\n", + progressive_sequence, chroma_format_str [chroma_format]); +} + +static void stats_sequence_display_extension (uint8_t * buffer) +{ + fprintf (stderr, " (sequence_display_extension)\n"); +} + +static void stats_quant_matrix_extension (uint8_t * buffer) +{ + fprintf (stderr, " (quant_matrix_extension)\n"); +} + +static void stats_copyright_extension (uint8_t * buffer) +{ + fprintf (stderr, " (copyright_extension)\n"); +} + + +static void stats_sequence_scalable_extension (uint8_t * buffer) +{ + fprintf (stderr, " (sequence_scalable_extension)\n"); +} + +static void stats_picture_display_extension (uint8_t * buffer) +{ + fprintf (stderr, " (picture_display_extension)\n"); +} + +static void stats_picture_coding_extension (uint8_t * buffer) +{ + static char * picture_structure_str[4] = { + "Invalid Picture Structure", + "Top field", + "Bottom field", + "Frame Picture" + }; + + int f_code[2][2]; + int intra_dc_precision; + int picture_structure; + int top_field_first; + int frame_pred_frame_dct; + int concealment_motion_vectors; + int q_scale_type; + int intra_vlc_format; + int alternate_scan; + int repeat_first_field; + int progressive_frame; + + f_code[0][0] = buffer[0] & 15; + f_code[0][1] = buffer[1] >> 4; + f_code[1][0] = buffer[1] & 15; + f_code[1][1] = buffer[2] >> 4; + intra_dc_precision = (buffer[2] >> 2) & 3; + picture_structure = buffer[2] & 3; + top_field_first = buffer[3] >> 7; + frame_pred_frame_dct = (buffer[3] >> 6) & 1; + concealment_motion_vectors = (buffer[3] >> 5) & 1; + q_scale_type = (buffer[3] >> 4) & 1; + intra_vlc_format = (buffer[3] >> 3) & 1; + alternate_scan = (buffer[3] >> 2) & 1; + repeat_first_field = (buffer[3] >> 1) & 1; + progressive_frame = buffer[4] >> 7; + + fprintf (stderr, + " (pic_ext) %s\n", picture_structure_str [picture_structure]); + fprintf (stderr, + " (pic_ext) forward horizontal f_code % d, forward vertical f_code % d\n", + f_code[0][0], f_code[0][1]); + fprintf (stderr, + " (pic_ext) backward horizontal f_code % d, backward vertical f_code % d\n", + f_code[1][0], f_code[1][1]); + fprintf (stderr, + " (pic_ext) intra_dc_precision %d, top_field_first %d, frame_pred_frame_dct %d\n", + intra_dc_precision, top_field_first, frame_pred_frame_dct); + fprintf (stderr, + " (pic_ext) concealment_motion_vectors %d, q_scale_type %d, intra_vlc_format %d\n", + concealment_motion_vectors, q_scale_type, intra_vlc_format); + fprintf (stderr, + " (pic_ext) alternate_scan %d, repeat_first_field %d, progressive_frame %d\n", + alternate_scan, repeat_first_field, progressive_frame); +} + +void stats_header (uint8_t code, uint8_t * buffer) +{ + if (! (debug_is_on ())) + return; + + switch (code) { + case 0x00: + stats_picture (buffer); + break; + case 0xb2: + stats_user_data (buffer); + break; + case 0xb3: + stats_sequence (buffer); + break; + case 0xb4: + stats_sequence_error (buffer); + break; + case 0xb5: + //stats_extension (buffer); + switch (buffer[0] >> 4) { + case 1: + stats_sequence_extension (buffer); + break; + case 2: + stats_sequence_display_extension (buffer); + break; + case 3: + stats |