summaryrefslogtreecommitdiff
path: root/recordmydesktop
diff options
context:
space:
mode:
Diffstat (limited to 'recordmydesktop')
-rw-r--r--recordmydesktop/AUTHORS2
-rw-r--r--recordmydesktop/COPYING340
-rw-r--r--recordmydesktop/ChangeLog3
-rw-r--r--recordmydesktop/INSTALL33
-rw-r--r--recordmydesktop/Makefile.am4
-rw-r--r--recordmydesktop/NEWS3
-rw-r--r--recordmydesktop/README3
-rw-r--r--recordmydesktop/TODO2
-rw-r--r--recordmydesktop/autogen.sh7
-rw-r--r--recordmydesktop/configure.ac58
-rw-r--r--recordmydesktop/doc/Makefile.am2
-rw-r--r--recordmydesktop/doc/recordmydesktop.1338
-rw-r--r--recordmydesktop/include/recordmydesktop.h367
-rw-r--r--recordmydesktop/src/Makefile.am28
-rw-r--r--recordmydesktop/src/bgr_to_yuv.c74
-rw-r--r--recordmydesktop/src/capture_sound.c106
-rw-r--r--recordmydesktop/src/encode_image_buffer.c33
-rw-r--r--recordmydesktop/src/encode_sound_buffer.c64
-rw-r--r--recordmydesktop/src/flush_to_ogg.c64
-rw-r--r--recordmydesktop/src/get_frame.c125
-rw-r--r--recordmydesktop/src/getzpixmap.c55
-rw-r--r--recordmydesktop/src/init_encoder.c169
-rw-r--r--recordmydesktop/src/make_dummy_pointer.c68
-rw-r--r--recordmydesktop/src/opendev.c98
-rw-r--r--recordmydesktop/src/parseargs.c380
-rw-r--r--recordmydesktop/src/poll_damage.c57
-rw-r--r--recordmydesktop/src/queryextensions.c40
-rw-r--r--recordmydesktop/src/recordmydesktop.c215
-rw-r--r--recordmydesktop/src/rectinsert.c469
-rw-r--r--recordmydesktop/src/register_callbacks.c75
-rw-r--r--recordmydesktop/src/setbrwindow.c90
-rw-r--r--recordmydesktop/src/update_image.c72
-rw-r--r--recordmydesktop/src/zpixmaptobmp.c78
33 files changed, 3522 insertions, 0 deletions
diff --git a/recordmydesktop/AUTHORS b/recordmydesktop/AUTHORS
new file mode 100644
index 0000000..bd3dbbc
--- /dev/null
+++ b/recordmydesktop/AUTHORS
@@ -0,0 +1,2 @@
+NAME EMAIL
+John Varouhakis biocrasher@gmail.com
diff --git a/recordmydesktop/COPYING b/recordmydesktop/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/recordmydesktop/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/recordmydesktop/ChangeLog b/recordmydesktop/ChangeLog
new file mode 100644
index 0000000..b28b04f
--- /dev/null
+++ b/recordmydesktop/ChangeLog
@@ -0,0 +1,3 @@
+
+
+
diff --git a/recordmydesktop/INSTALL b/recordmydesktop/INSTALL
new file mode 100644
index 0000000..fe3d120
--- /dev/null
+++ b/recordmydesktop/INSTALL
@@ -0,0 +1,33 @@
+To compile the program you have to go through the regular drill:
+
+~$ gzip -d recordmydesktop-x.y.z.tar.gz
+~$ tar -x recordmydesktop-x.y.z.tar
+~$ cd recordmydesktop-x.y.z
+~$ ./configure
+~$ make
+~$ sudo make install
+
+
+You will need the development headers for the following:
+alsa (libasound)
+X
+libXext
+libXdamage
+libogg
+libvorbis
+libtheora
+
+As well the regular headers, plus the ones for pthreads
+(both of which you should have if you have compiled anything else before).
+
+Of the above, the most likely to be missing are probably those of libXdamage and libtheora
+but any recent linux distribution should offer an easy way to get them.
+
+
+
+
+Compiling on *BSD or other *nix flavors is not going to work(because of the alsa dependency)
+but it shouldn't be too much of a hassle to change that(at least by disabling sound capture).
+Future versions might include support for OSS-based sound capture.
+
+
diff --git a/recordmydesktop/Makefile.am b/recordmydesktop/Makefile.am
new file mode 100644
index 0000000..86af0cd
--- /dev/null
+++ b/recordmydesktop/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = src doc
+
+EXTRA_DIST=include
+
diff --git a/recordmydesktop/NEWS b/recordmydesktop/NEWS
new file mode 100644
index 0000000..b28b04f
--- /dev/null
+++ b/recordmydesktop/NEWS
@@ -0,0 +1,3 @@
+
+
+
diff --git a/recordmydesktop/README b/recordmydesktop/README
new file mode 100644
index 0000000..625990c
--- /dev/null
+++ b/recordmydesktop/README
@@ -0,0 +1,3 @@
+To see examples of usage and explanation of the options check the manpage in the doc directory.
+
+
diff --git a/recordmydesktop/TODO b/recordmydesktop/TODO
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/recordmydesktop/TODO
@@ -0,0 +1,2 @@
+
+
diff --git a/recordmydesktop/autogen.sh b/recordmydesktop/autogen.sh
new file mode 100644
index 0000000..06af23f
--- /dev/null
+++ b/recordmydesktop/autogen.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+
+aclocal
+autoheader
+automake --copy --add-missing
+autoconf \ No newline at end of file
diff --git a/recordmydesktop/configure.ac b/recordmydesktop/configure.ac
new file mode 100644
index 0000000..2b246e9
--- /dev/null
+++ b/recordmydesktop/configure.ac
@@ -0,0 +1,58 @@
+ # -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.59)
+AC_INIT(src/recordmydesktop.c)
+AM_INIT_AUTOMAKE(recordmydesktop,0.2.0,)
+
+AC_CONFIG_SRCDIR([src/recordmydesktop.c])
+AM_CONFIG_HEADER(config.h)
+
+
+
+# Checks for programs.
+
+AC_PROG_CC
+
+# Checks for header files.
+
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+
+AC_PATH_X
+AC_CHECK_HEADER([png.h])
+AC_CHECK_HEADER([alsa/asoundlib.h])
+AC_CHECK_HEADERS([sys/time.h unistd.h vorbis/vorbisfile.h ])
+
+LDFLAGS="$LD_FLAGS -L$x_libraries "
+
+CFLAGS="${CFLAGS} -O3 -Wall -D_THREAD_SAFE -pthread"
+
+# Checks for libraries.
+
+AC_CHECK_LIB([m],[isnan],,)
+AC_CHECK_LIB([z],[deflate],,)
+AC_CHECK_LIB([X11],[XOpenDisplay],,AC_MSG_ERROR([Can't find libX11]))
+AC_CHECK_LIB([Xext],[XShmQueryVersion],,AC_MSG_ERROR([Can't find libXext]))
+AC_CHECK_LIB([Xdamage], [XDamageQueryExtension],,AC_MSG_ERROR([Can't find libXdamage]))
+AC_CHECK_LIB([vorbis],[vorbis_info_clear],,AC_MSG_ERROR([Can't find libvorbis]))
+AC_CHECK_LIB([vorbisfile],[ov_open],,AC_MSG_ERROR([Can't find libvorbisfile]),-lvorbis)
+AC_CHECK_LIB([vorbisenc],[vorbis_encode_init],,AC_MSG_ERROR([Can't find libvorbisenc]),-lvorbis)
+AC_CHECK_LIB([ogg],[ogg_stream_init],,AC_MSG_ERROR([Can't find libogg]))
+AC_CHECK_LIB([theora],[theora_encode_YUVin],,AC_MSG_ERROR([Can't find libtheora]))
+AC_CHECK_LIB([pthread],[pthread_mutex_lock],,AC_MSG_ERROR([Can't find libpthread]))
+
+AC_CHECK_LIB([asound],[snd_pcm_drain],,AC_MSG_ERROR([Can't find libasound]))
+
+
+# Checks for typedefs, structures, and compiler characteristics.
+
+# Checks for library functions.
+AC_FUNC_CLOSEDIR_VOID
+AC_FUNC_MALLOC
+
+AC_CONFIG_FILES([Makefile
+ src/Makefile
+ doc/Makefile ])
+AC_OUTPUT
+
diff --git a/recordmydesktop/doc/Makefile.am b/recordmydesktop/doc/Makefile.am
new file mode 100644
index 0000000..9780b6c
--- /dev/null
+++ b/recordmydesktop/doc/Makefile.am
@@ -0,0 +1,2 @@
+man_MANS = recordmydesktop.1
+EXTRA_DIST = $(man_MANS)
diff --git a/recordmydesktop/doc/recordmydesktop.1 b/recordmydesktop/doc/recordmydesktop.1
new file mode 100644
index 0000000..809077e
--- /dev/null
+++ b/recordmydesktop/doc/recordmydesktop.1
@@ -0,0 +1,338 @@
+.TH "RECORDMYDESKTOP" 1 "13/7/2006" "Linux"
+
+
+.SH NAME
+recordMyDesktop \- record desktop sessions to an Ogg\-Theora\-Vorbis file.
+
+
+.SH SYNOPSIS
+
+.B recordmydesktop
+[
+.B
+Options
+]^
+.B
+filename
+.br
+.br
+.SH DESCRIPTION
+.PP
+ recordMyDesktop produces a file(default out.ogg) that contains a video and audio recording
+.br
+of a linux desktop session. The default behavior of recording is to mark areas that have changed(through libxdamage)
+.br
+and update the frame. This behavior can be changed (option
+.B
+\-\-full\-shots
+) to produce a more accurate result
+.br
+or capture windows that do not generate events on change(windows with 3d context or video display)
+.br
+but this will notably increase the workload. In this case, enabling the
+.B
+\-\-with\-shared
+option is recommended
+.br
+(by default this option is disabled since copying small areas of display is faster
+.br
+than uploading the whole image from video memory).
+.br
+.br
+recordMyDesktop doesn't have a commandline interface.
+.br
+After startup, it can be controled only through the following signals:
+.br
+.br
+.B
+SIGUSR1
+causes the program to pause if it's currently recording, and vice-versa.
+.br
+.B
+SIGTERM
+causes normal termination of the recording.
+.br
+.B
+SIGINT
+also causes normal termination.
+.br
+.B
+SIGABRT
+terminates the program and removes the specified output file.
+.br
+.br
+.br
+A typical scenario of recording can be a command as simple as:
+.br
+.B
+~$ recordmydesktop
+.br
+which will produce a fullscreen recording named out.ogg
+.br
+while a command like:
+.br
+.B
+~$ recordmydesktop foo.ogg
+.br
+will write output to foo.ogg
+.br
+To specify a region for recording you can type this:
+.br
+.B
+~$ recordmydesktop -x X_pos -y Y_pos -width WIDTH -height HEIGHT -o foo.ogg
+.br
+where X_pos and Y_pos specify the offset in pixels from the upper left
+.br
+corner of your screen and WIDTH and HEIGHT the size of the window to be recorded(again in pixels).
+.br
+If the area extends beyond your current resolution, you will be notified appropriately and nothing will happen.
+.br
+Notice also, that if any option is entered you have to specify the output file with the \-o switch.
+.br
+.br
+.B
+To normally end a recording you can press ctl-c.
+.br
+(which will send a
+.B
+SIGINT
+to the program).
+.br
+.br
+For further manipulation of the end result look at the
+.B
+OPTIONS
+and
+.B
+NOTES
+sections.
+.br
+.br
+.br
+.SH EXIT STATUS
+0 is success
+.br
+Non-zero means an error occurred, which is printed in stderr.
+.br
+.SH OPTIONS
+.PP
+.B
+Generic Options:
+.br
+.TP
+.B
+ \-h or \-\-help
+ Print help summary and exit.
+.br
+.TP
+.B
+ \-\-version
+ Print program version and exit.
+.br
+.PP
+.br
+.B
+Image Options:
+.br
+.TP
+.B
+ \-windowid id_of_window
+ id of window to be recorded.
+.br
+.TP
+.B
+ \-display DISPLAY
+ Display to connect to.
+.br
+.TP
+.B
+ \-x X
+ Offset in x direction.
+.br
+.TP
+.B
+ \-y Y
+ Offset in y direction.
+.br
+.TP
+.B
+ \-width N
+ Width of recorded window.
+.br
+.TP
+.B
+ \-height N
+ Height of recorded window.
+.br
+.TP
+.B
+.br
+.br
+.TP
+.B
+ \-dummy\-cursor color
+ Color of the dummy cursor [black|white](default black)
+.br
+.TP
+.B
+ \-\-no\-dummy\-cursor
+ Disable drawing of a dummy cursor.
+.br
+.TP
+.B
+ \-\-with\-shared
+ Enable usage of MIT\-shared memory extension.
+.br
+.TP
+.B
+ \-\-full\-shots
+ Take full screenshot at every frame(Not recomended!).
+.br
+.TP
+.B
+ \-fps N(number>0.0)
+ A positive number denoting desired framerate.
+.br
+.br
+.PP
+.B
+Sound Options:
+.br
+.TP
+.B
+ \-channels N(number>0)
+ A positive number denoting desired sound channels in recording.
+.br
+.TP
+.B
+ \-freq N(number>0)
+ A positive number denoting desired sound frequency.
+.br
+.TP
+.B
+ \-device SOUND_DEVICE
+ Sound device(default hw0:0).
+.br
+.TP
+.B
+ \-\-nosound
+ Do not record sound.
+.br
+.PP
+.br
+.B
+Encoding Options:
+.br
+.TP
+.B
+ \-v_quality n
+ A number from 0 to 63 for desired encoded video quality(default 63).
+.br
+.TP
+.B
+ \-v_bitrate n
+ A number from 45000 to 2000000 for desired encoded video bitrate(default 45000).
+.br
+.TP
+.B
+ \-s_quality n
+ Desired audio quality(\-1 to 10).
+.br
+.PP
+.br
+.B
+Misc Options:
+.br
+.TP
+.B
+ \-delay n[H|h|M|m]
+ Number of secs(default),minutes or hours before capture starts(number can be float).
+.br
+.TP
+.B
+ \-\-scshot
+ Take a bitmap screenshot(default rmdout.bmp) and exit.
+.br
+.TP
+.B
+ \-scale\-shot N
+ Factor by which screenshot is scaled down(1<=number<=64,power of 2).
+.br
+.TP
+.B
+ \-o filename
+ Name of recorded video(default out.ogg).
+
+
+
+.PP
+.br
+If no other option is specified, filename can be given without the \-o switch.
+.br
+.br
+.SH USAGE
+.TP
+.B recordmydesktop
+.br
+[\-h| \-\-help| \-\-version| \-delay n[H|h|M|m]| \-windowid id_of_window|
+.br
+\-display DISPLAY| \-x X| \-y Y|\-width N| \-height N| \-fps N(number>0)|
+.br
+\-v_quality n| \-s_quality n| \-v_bitrate n| \-dummy\-cursor color| \-\-no\-dummy\-cursor|
+.br
+\-freq N(number>0)| \-channels N(number>0)| \-device SOUND_DEVICE| \-\-nosound|
+.br
+\-\-with\-shared| \-\-full\-shots| \-\-scshot| \-scale\-shot N| \-o filename]^filename
+.br
+.br
+.br
+.SH ENVIRONMENT
+.TP
+.B
+DISPLAY
+.br
+Display environment variable, specifying X server to connect to.
+.br
+.SH NOTES
+.br
+ Recording a window using the \-windowid option, doesn't track the window itself, but the region that it covers.
+.br
+Also when using that option the \-x,\-y,\-width and \-height options are relative to the specified window area.
+.br
+An easy way to find out the id of a window, is by using the
+.B
+xwininfo
+program.
+.br
+Running a command like :
+.br
+.B
+xwininfo |grep "Window id:"|sed \-e "s/xwininfo\\:\\ Window id:\\ // ;s/\\ \.*//"
+.br
+will give you only the id of the window(which should look like this: 0x4800005)
+.br
+More conviniently you can put all that in the command that launches recordMyDesktop like this:
+.br
+.B
+~$recordmydesktop -windowid $(xwininfo |grep "Window id:"|sed \-e "s/xwininfo\\:\\ Window id:\\ // ;s/\\ \.*//" )
+.br
+.br
+ Also, the lower quality you select on a video recording (
+.B
+-v_quality
+option), the highest CPU-power that you will need.
+.br
+So it's always better to start with default values and manipulate the end\-result with another program.
+.br
+.br
+.SH BUGS
+Too resource intensive,outcome quality is not what it should be.
+.br
+(font colouring is somewhat fuzzy and occasionally borderlines remain unupdated when a window closes)
+.br
+.SH AUTHORS
+John Varouhakis(biocrasher@gmail.com)
+.br
+.SH SEE ALSO
+.BR xwininfo(1)
+.br \ No newline at end of file
diff --git a/recordmydesktop/include/recordmydesktop.h b/recordmydesktop/include/recordmydesktop.h
new file mode 100644
index 0000000..1740762
--- /dev/null
+++ b/recordmydesktop/include/recordmydesktop.h
@@ -0,0 +1,367 @@
+/*********************************************************************************
+* recordMyDesktop *
+**********************************************************************************
+* *
+* Copyright (C) 2006 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+* *
+* *
+* *
+* For further information contact me at biocrasher@gmail.com *
+**********************************************************************************/
+
+
+#ifndef RECORDMYDESKTOP_H
+#define RECORDMYDESKTOP_H 1
+
+#ifdef HAVE_CONFIG_H
+ #include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <pthread.h>
+#include <X11/Xlib.h>
+#include <X11/Xlibint.h>
+#include <X11/extensions/Xdamage.h>
+#include <X11/extensions/XShm.h>
+#include <theora/theora.h>
+#include <vorbis/codec.h>
+#include <vorbis/vorbisenc.h>
+#include <ogg/ogg.h>
+#include <alsa/asoundlib.h>
+
+
+enum {UNSPECIFIED,OGG_THEORA_VORBIS};
+
+
+/**Structs*/
+
+typedef struct _DisplaySpecs{ //this struct holds some basic information
+ int screen; //about the display,needed mostly for
+ uint width; //validity checks at startup
+ uint height;
+ Window root;
+ Visual *visual;
+ GC gc;
+ int depth;
+ unsigned long bpixel;
+ unsigned long wpixel;
+}DisplaySpecs;
+
+typedef struct _WGeometry{ //basic geometry of a window or area
+ int x;
+ int y;
+ int width;
+ int height;
+}WGeometry;
+
+typedef struct _RectArea{ //an area that has been damaged gets stored
+ WGeometry geom; //in a list comprised of structs of this type
+ struct _RectArea *prev,*next;
+}RectArea;
+
+typedef struct _BRWindow{ //a window to be recorded specs
+ WGeometry geom; //window attributes
+ WGeometry rgeom; //part of window that is recorded
+ int nbytes; //size of zpixmap when screenshoting
+ Window windowid; //id
+}BRWindow;
+
+
+typedef struct _ProgArgs{
+ int delay; //start up delay
+ Window windowid; //window to record(default root)
+ char *display; //display to connect(default :0)
+ int x,y; //x,y offset(default 0,0)
+ int width,height; //defaults to window width and height
+ int quietmode; //no messages to stderr,stdout
+ char *filename; //output file(default out.[ogg|*])
+ int encoding; //encoding(default OGG_THEORA_VORBIS)
+ int cursor_color; //black or white=>1 or 0
+ int have_dummy_cursor;//disable/enable drawing the dummy cursor
+ float fps; //desired framerate(default 15)
+ unsigned int frequency; //desired frequency (default 22050)
+ unsigned int channels; //no of channels(default 2)
+ char *device; //default sound device(default according to alsa or oss)
+ int nosound; //do not record sound(default 0)
+ int noshared; //do not use shared memory extension(default disabled)
+ int full_shots; //do not poll damage, take full screenshots
+ int scshot; //take screenshot and exit(default 0)
+ int scale_shot; //screenshot subscale factor(default 1)
+ int v_bitrate,v_quality,s_quality;//video bitrate,video-sound quality
+}ProgArgs;
+
+
+//this struct will hold anything related to encoding AND
+//writting out to file.
+//**TODO add vorbis specifics*/
+typedef struct _EncData{
+ ogg_stream_state m_ogg_ts;//theora
+ ogg_stream_state m_ogg_vs;//vorbis
+ ogg_page m_ogg_pg;
+ ogg_packet m_ogg_pckt1;
+ ogg_packet m_ogg_pckt2;
+
+ theora_state m_th_st;
+ theora_info m_th_inf;
+ theora_comment m_th_cmmnt;
+ yuv_buffer yuv;
+
+ vorbis_info m_vo_inf;
+ vorbis_comment m_vo_cmmnt;
+ vorbis_dsp_state m_vo_dsp;
+ vorbis_block m_vo_block;
+
+
+ FILE *fp;
+}EncData;
+
+typedef struct _SndBuffer{
+ signed char *data;
+ struct _SndBuffer *next;
+}SndBuffer;
+
+//this structure holds any data related to the program
+//It's usage is mostly to be given as an argument to the
+//threads,so they will have access to the program data, avoiding
+//at the same time usage of any globals.
+typedef struct _ProgData{
+ ProgArgs args;//the program arguments
+ DisplaySpecs specs;//Display specific information
+ BRWindow brwin;//recording window
+ Display *dpy;//curtrent display
+ XImage *image;//the image that holds the current full screenshot
+ unsigned char *dummy_pointer;//a dummy pointer to be drawn in every frame
+ //data is casted to unsigned for later use in YUV buffer
+ int dummy_p_size;//initially 16x16,always square
+ unsigned char npxl;//this is the no pixel convention when drawing the dummy pointer
+ char *datamain,//the data of the image above
+ *datatemp;//buffer for the temporary image,which will be
+ //preallocated in case shared memory is not used.
+ RectArea *rect_root[2];//the interchanging list roots for storing the changed regions
+ int list_selector,//selector for the above
+ damage_event,//damage event base code
+ damage_error,//damage error base code
+ running;
+ SndBuffer *sound_buffer;
+ EncData *enc_data;
+ int hard_pause;//if sound device doesn't support pause
+ //we have to close and reopen
+ unsigned int periodtime,
+ frametime;
+ pthread_mutex_t list_mutex[2],//mutexes for concurrency protection of the lists
+ sound_buffer_mutex,
+ yuv_mutex;
+ pthread_cond_t time_cond,//this gets a broadcast by the handler whenever it's time to get a screenshot
+ pause_cond,//this is blocks execution, when program is paused
+ sound_buffer_ready,//sound encoding finished
+ sound_data_read,//a buffer is ready for proccessing
+ image_buffer_ready;//image encoding finished
+ snd_pcm_t *sound_handle;
+ snd_pcm_uframes_t periodsize;
+}ProgData;
+
+/**Globals*/
+//I've read somewhere that I'll go to hell for using globals...
+
+int Paused,*Running,Aborted;
+pthread_cond_t *time_cond,*pause_cond;
+int avd;
+
+/**Macros*/
+
+#define CLIP_EVENT_AREA(e,brwin,wgeom){\
+ if(((e)->area.x<=(brwin)->rgeom.x)&&((e)->area.y<=(brwin)->rgeom.y)&&\
+ ((e)->area.width>=(brwin)->rgeom.width)&&((e)->area.height<(brwin)->rgeom.height)){\
+ (wgeom)->x=(brwin)->rgeom.x;\
+ (wgeom)->y=(brwin)->rgeom.y;\
+ (wgeom)->width=(brwin)->rgeom.width;\
+ (wgeom)->height=(brwin)->rgeom.height;\
+ }\
+ else{\
+ (wgeom)->x=((((e)->area.x+(e)->area.width>=(brwin)->rgeom.x)&&\
+ ((e)->area.x<=(brwin)->rgeom.x+(brwin)->rgeom.width))?\
+ (((e)->area.x<=(brwin)->rgeom.x)?(brwin)->rgeom.x:(e)->area.x):-1);\
+ \
+ (wgeom)->y=((((e)->area.y+(e)->area.height>=(brwin)->rgeom.y)&&\
+ ((e)->area.y<=(brwin)->rgeom.y+(brwin)->rgeom.height))?\
+ (((e)->area.y<=(brwin)->rgeom.y)?(brwin)->rgeom.y:(e)->area.y):-1);\
+ \
+ (wgeom)->width=((e)->area.x<=(brwin)->rgeom.x)?\
+ (e)->area.width-((brwin)->rgeom.x-(e)->area.x):\
+ ((e)->area.x<=(brwin)->rgeom.x+(brwin)->rgeom.width)?\
+ (((brwin)->rgeom.width-(e)->area.x+(brwin)->rgeom.x<(e)->area.width)?\
+ (brwin)->rgeom.width-(e)->area.x+(brwin)->rgeom.x:e->area.width):-1;\
+ \
+ (wgeom)->height=((e)->area.y<=(brwin)->rgeom.y)?\
+ (e)->area.height-((brwin)->rgeom.y-(e)->area.y):\
+ ((e)->area.y<=(brwin)->rgeom.y+(brwin)->rgeom.height)?\
+ (((brwin)->rgeom.height-(e)->area.y+(brwin)->rgeom.y<(e)->area.height)?\
+ ((brwin)->rgeom.height-(e)->area.y+(brwin)->rgeom.y<(e)->area.height):(e)->area.height):-1;\
+ \
+ if((wgeom)->width>(brwin)->rgeom.width)(wgeom)->width=(brwin)->rgeom.width;\
+ if((wgeom)->height>(brwin)->rgeom.height)(wgeom)->height=(brwin)->rgeom.height;\
+ }\
+}
+
+#define CLIP_DUMMY_POINTER_AREA(dummy_p_area,brwin,wgeom){\
+ (wgeom)->x=((((dummy_p_area).x+(dummy_p_area).width>=(brwin)->rgeom.x)&&\
+ ((dummy_p_area).x<=(brwin)->rgeom.x+(brwin)->rgeom.width))?\
+ (((dummy_p_area).x<=(brwin)->rgeom.x)?(brwin)->rgeom.x:(dummy_p_area).x):-1);\
+ (wgeom)->y=((((dummy_p_area).y+(dummy_p_area).height>=(brwin)->rgeom.y)&&\
+ ((dummy_p_area).y<=(brwin)->rgeom.y+(brwin)->rgeom.height))?\
+ (((dummy_p_area).y<=(brwin)->rgeom.y)?(brwin)->rgeom.y:(dummy_p_area).y):-1);\
+ (wgeom)->width=((dummy_p_area).x<=(brwin)->rgeom.x)?\
+ (dummy_p_area).width-((brwin)->rgeom.x-(dummy_p_area).x):\
+ ((dummy_p_area).x<=(brwin)->rgeom.x+(brwin)->rgeom.width)?\
+ ((brwin)->rgeom.width-(dummy_p_area).x+(brwin)->rgeom.x<(dummy_p_area).width)?\
+ (brwin)->rgeom.width-(dummy_p_area).x+(brwin)->rgeom.x:(dummy_p_area).width:-1;\
+ (wgeom)->height=((dummy_p_area).y<=(brwin)->rgeom.y)?\
+ (dummy_p_area).height-((brwin)->rgeom.y-(dummy_p_area).y):\
+ ((dummy_p_area).y<=(brwin)->rgeom.y+(brwin)->rgeom.height)?\
+ ((brwin)->rgeom.height-(dummy_p_area).y+(brwin)->rgeom.y<(dummy_p_area).height)?\
+ ((brwin)->rgeom.height-(dummy_p_area).y+(brwin)->rgeom.y<(dummy_p_area).height):(dummy_p_area).height:-1;\
+ if((wgeom)->width>(brwin)->rgeom.width)(wgeom)->width=(brwin)->rgeom.width;\
+ if((wgeom)->height>(brwin)->rgeom.height)(wgeom)->height=(brwin)->rgeom.height;\
+}
+
+
+
+#define DEFAULT_ARGS(args){\
+ (args)->delay=0;\
+ (args)->display=(char *)malloc(strlen(getenv("DISPLAY"))+1);\
+ strcpy((args)->display,getenv("DISPLAY"));\
+ (args)->windowid=(args)->x=(args)->y\
+ =(args)->width=(args)->height=(args)->quietmode\
+ =(args)->nosound=(args)->scshot=(args)->full_shots=0;\
+ (args)->noshared=(args)->scale_shot=1;\
+ (args)->filename=(char *)malloc(8);\
+ strcpy((args)->filename,"out.ogg");\
+ (args)->encoding=OGG_THEORA_VORBIS;\
+ (args)->cursor_color=1;\
+ (args)->have_dummy_cursor=1;\
+ (args)->device=(char *)malloc(8);\
+ strcpy((args)->device,"hw:0,0");\
+ (args)->fps=15;\
+ (args)->channels=1;\
+ (args)->frequency=22050;\
+ (args)->v_bitrate=45000;\
+ (args)->v_quality=63;\
+ (args)->s_quality=10;\
+}
+
+#define QUERY_DISPLAY_SPECS(display,specstruct){\
+ (specstruct)->screen=DefaultScreen(display);\
+ (specstruct)->width=DisplayWidth(display,(specstruct)->screen);\
+ (specstruct)->height=DisplayHeight(display,(specstruct)->screen);\
+ (specstruct)->root=RootWindow(display,(specstruct)->screen);\
+ (specstruct)->visual=DefaultVisual(display,(specstruct)->screen);\
+ (specstruct)->gc=DefaultGC(display,(specstruct)->screen);\
+ (specstruct)->depth=DefaultDepth(display,(specstruct)->screen);\
+ (specstruct)->bpixel=XBlackPixel(display,(specstruct)->screen);\
+ (specstruct)->wpixel=XWhitePixel(display,(specstruct)->screen);\
+}
+
+#define UPDATE_YUV_BUFFER_SH(yuv,data,x_tm,y_tm,width_tm,height_tm){\
+ int i,k;\
+ for(k=y_tm;k<y_tm+height_tm;k++){\
+ for(i=x_tm;i<x_tm+width_tm;i++){\
+ yuv->y[i+k*yuv->y_width]=min(abs(data[(i+k*yuv->y_width)*4+2] * 2104 + data[(i+k*yuv->y_width)*4+1] * 4130 + data[(i+k*yuv->y_width)*4] * 802 + 4096 + 131072) >> 13, 235);\
+ if((k%2)&&(i%2)){\
+ yuv->u[i/2+k/2*yuv->uv_width]=min(abs(data[(i+k*yuv->y_width)*4+2] * -1214 + data[(i+k*yuv->y_width)*4+1] * -2384 + data[(i+k*yuv->y_width)*4] * 3598 + 4096 + 1048576) >> 13, 240);\
+ yuv->v[i/2+k/2*yuv->uv_width]=min(abs(data[(i+k*yuv->y_width)*4+2] * 3598 + data[(i+k*yuv->y_width)*4+1] * -3013 + data[(i+k*yuv->y_width)*4] * -585 + 4096 + 1048576) >> 13, 240);\
+ }\
+ }\
+ }\
+}
+
+#define UPDATE_YUV_BUFFER_IM(yuv,data,x_tm,y_tm,width_tm,height_tm){\
+ int i,k,j=0;\
+ int x_2=x_tm/2,y_2=y_tm/2,y_width_2=yuv->y_width/2;\
+ for(k=0;k<height_tm;k++){\
+ for(i=0;i<width_tm;i++){\
+ yuv->y[x_tm+i+(k+y_tm)*yuv->y_width]=min(abs(data[(j*4)+2] * 2104 + data[(j*4)+1] * 4130 + data[(j*4)] * 802 + 4096 + 131072) >> 13, 235);\
+ if((k%2)&&(i%2)){\
+ yuv->u[x_2+i/2+(k/2+y_2)*y_width_2]=min(abs(data[(k*width_tm+i)*4+2] * -1214 + data[(k*width_tm+i)*4+1] * -2384 + data[(k*width_tm+i)*4] * 3598 + 4096 + 1048576) >> 13, 240);\
+ yuv->v[x_2+i/2+(k/2+y_2)*y_width_2]=min(abs(data[(k*width_tm+i)*4+2] * 3598 + data[(k*width_tm+i)*4+1] * -3013 + data[(k*width_tm+i)*4] * -585 + 4096 + 1048576) >> 13, 240);\
+ }\
+ \
+ j++;\
+ }\
+ }\
+}
+
+#define DUMMY_POINTER_TO_YUV(yuv,data_tm,x_tm,y_tm,width_tm,height_tm,no_pixel){\
+ int i,k,j=0;\
+ int x_2=x_tm/2,y_2=y_tm/2,y_width_2=(yuv)->y_width/2;\
+ for(k=0;k<height_tm;k++){\
+ for(i=0;i<width_tm;i++){\
+ if(data_tm[(j*4)]!=(no_pixel)){\
+ (yuv)->y[x_tm+i+(k+y_tm)*(yuv)->y_width]=min(abs(data_tm[(j*4)+2] * 2104 + data_tm[(j*4)+1] * 4130 + data_tm[(j*4)] * 802 + 4096 + 131072) >> 13, 235);\
+ if((k%2)&&(i%2)){\
+ yuv->u[x_2+i/2+(k/2+y_2)*y_width_2]=min(abs(data_tm[(k*width_tm+i)*4+2] * -1214 + data_tm[(k*width_tm+i)*4+1] * -2384 + data_tm[(k*width_tm+i)*4] * 3598 + 4096 + 1048576) >> 13, 240);\
+ yuv->v[x_2+i/2+(k/2+y_2)*y_width_2]=min(abs(data_tm[(k*width_tm+i)*4+2] * 3598 + data_tm[(k*width_tm+i)*4+1] * -3013 + data_tm[(k*width_tm+i)*4] * -585 + 4096 + 1048576) >> 13, 240);\
+ }\
+ }\
+ j++;\
+ }\
+ }\
+}
+
+
+/**Function prototypes*/
+
+void *PollDamage(void *pdata);
+void *GetFrame(void *pdata);
+void *EncodeImageBuffer(void *pdata);
+void *FlushToOgg(void *pdata);
+void UpdateYUVBuffer(yuv_buffer *yuv,unsigned char *data,int x,int y,int width,int height);
+void ClearList(RectArea **root);
+int RectInsert(RectArea **root,WGeometry *wgeom);
+int CollideRects(WGeometry *wgeom1,WGeometry *wgeom2,WGeometry **wgeom_return,int *ngeoms);
+void SetExpired(int signum);
+void RegisterCallbacks(ProgArgs *args);
+void UpdateImage(Display * dpy,yuv_buffer *yuv,pthread_mutex_t *yuv_mutex,DisplaySpecs *specs,RectArea **root,BRWindow *brwin,char *datatemp,int noshmem);
+void XImageToYUV(XImage *imgz,yuv_buffer *yuv);
+int GetZPixmap(Display *dpy,Window root,char *data,int x,int y,int width,int height);
+int ParseArgs(int argc,char **argv,ProgArgs *arg_return);
+int QueryExtensions(Display *dpy,ProgArgs *args,int *damage_event,int *damage_error);
+int SetBRWindow(Display *dpy,BRWindow *brwin,DisplaySpecs *specs,ProgArgs *args);
+int ZPixmapToBMP(XImage *imgz,BRWindow *brwin,char *fname,int nbytes,int scale);
+unsigned char *MakeDummyPointer(DisplaySpecs *specs,int size,int color,int type,unsigned char *npxl);
+void UpdateYUVBufferSh(yuv_buffer *yuv,unsigned char *data,int x,int y,int width,int height);
+void UpdateYUVBufferIm(yuv_buffer *yuv,unsigned char *data,int x,int y,int width,int height);
+void *CaptureSound(void *pdata);
+void *EncodeSoundBuffer(void *pdata);
+snd_pcm_t *OpenDev(const char *pcm_dev,unsigned int channels,unsigned int *frequency,snd_pcm_uframes_t *periodsize,unsigned int *periodtime,int *hardpause);
+void InitEncoder(ProgData *pdata,EncData *enc_data_t);
+
+#endif
+
diff --git a/recordmydesktop/src/Makefile.am b/recordmydesktop/src/Makefile.am
new file mode 100644
index 0000000..d3d7a20
--- /dev/null
+++ b/recordmydesktop/src/Makefile.am
@@ -0,0 +1,28 @@
+bin_PROGRAMS = recordmydesktop
+
+
+
+recordmydesktop_SOURCES= recordmydesktop.c\
+ zpixmaptobmp.c\
+ getzpixmap.c\
+ parseargs.c\
+ rectinsert.c\
+ setbrwindow.c\
+ queryextensions.c\
+ register_callbacks.c\
+ get_frame.c\
+ update_image.c\
+ poll_damage.c\
+ encode_image_buffer.c\
+ bgr_to_yuv.c\
+ flush_to_ogg.c\
+ make_dummy_pointer.c\
+ opendev.c\
+ capture_sound.c\
+ encode_sound_buffer.c\
+ init_encoder.c
+
+INCLUDES= $(all_includes) -I../include
+
+recordmydesktop_LDFLAGS = -D_THREAD_SAFE -pthread -Wall -O3
+
diff --git a/recordmydesktop/src/bgr_to_yuv.c b/recordmydesktop/src/bgr_to_yuv.c
new file mode 100644
index 0000000..9441e5d
--- /dev/null
+++ b/recordmydesktop/src/bgr_to_yuv.c
@@ -0,0 +1,74 @@
+/*********************************************************************************
+* recordMyDesktop *
+**********************************************************************************
+* *
+* Copyright (C) 2006 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+* *
+* *
+* *
+* For further information contact me at biocrasher@gmail.com *
+**********************************************************************************/
+
+
+#include <recordmydesktop.h>
+
+void XImageToYUV(XImage *imgz,yuv_buffer *yuv){
+ unsigned char *dtap=(unsigned char *)imgz->data;
+ int i,k,j=0;
+
+ for(k=0;k<(imgz->width*imgz->height);k++){
+ yuv->y[k]=min(abs(dtap[(k*4)+2] * 2104 + dtap[(k*4)+1] * 4130 + dtap[(k*4)] * 802 + 4096 + 131072) >> 13, 235);
+ }
+
+ for(i=0;i<(imgz->height);i+=2){
+ for(k=0;k<(imgz->width);k+=2){
+ yuv->u[j]=min(abs(dtap[i*imgz->bytes_per_line+k*4+2] * -1214 + dtap[i*imgz->bytes_per_line+k*4+1] * -2384 + dtap[i*imgz->bytes_per_line+k*4] * 3598 + 4096 + 1048576) >> 13, 240);
+ yuv->v[j]=min(abs(dtap[i*imgz->bytes_per_line+k*4+2] * 3598 + dtap[i*imgz->bytes_per_line+k*4+1] * -3013 + dtap[i*imgz->bytes_per_line+k*4] * -585 + 4096 + 1048576) >> 13, 240);
+ j++;
+ }
+ }
+}
+
+void UpdateYUVBufferSh(yuv_buffer *yuv,unsigned char *data,int x,int y,int width,int height){
+ int i,k;
+ for(k=y;k<y+height;k++){
+ for(i=x;i<x+width;i++){
+ yuv->y[i+k*yuv->y_width]=min(abs(data[(i+k*yuv->y_width)*4+2] * 2104 + data[(i+k*yuv->y_width)*4+1] * 4130 + data[(i+k*yuv->y_width)*4] * 802 + 4096 + 131072) >> 13, 235);
+ if((k%2)&&(i%2)){
+ yuv->u[i/2+k/2*yuv->uv_width]=min(abs(data[(i+k*yuv->y_width)*4+2] * -1214 + data[(i+k*yuv->y_width)*4+1] * -2384 + data[(i+k*yuv->y_width)*4] * 3598 + 4096 + 1048576) >> 13, 240);
+ yuv->v[i/2+k/2*yuv->uv_width]=min(abs(data[(i+k*yuv->y_width)*4+2] * 3598 + data[(i+k*yuv->y_width)*4+1] * -3013 + data[(i+k*yuv->y_width)*4] * -585 + 4096 + 1048576) >> 13, 240);
+ }
+ }
+ }
+}
+
+void UpdateYUVBufferIm(yuv_buffer *yuv,unsigned char *data,int x,int y,int width,int height){
+ int i,k,j=0;
+ int x_2=x/2,y_2=y/2,y_width_2=yuv->y_width/2;
+ for(k=0;k<height;k++){
+ for(i=0;i<width;i++){
+ yuv->y[x+i+(k+y)*yuv->y_width]=min(abs(data[(j*4)+2] * 2104 + data[(j*4)+1] * 4130 + data[(j*4)] * 802 + 4096 + 131072) >> 13, 235);
+ if((k%2)&&(i%2)){
+ yuv->u[x_2+i/2+(k/2+y_2)*y_width_2]=min(abs(data[(k*width+i)*4+2] * -1214 + data[(k*width+i)*4+1] * -2384 + data[(k*width+i)*4] * 3598 + 4096 + 1048576) >> 13, 240);
+ yuv->v[x_2+i/2+(k/2+y_2)*y_width_2]=min(abs(data[(k*width+i)*4+2] * 3598 + data[(k*width+i)*4+1] * -3013 + data[(k*width+i)*4] * -585 + 4096 + 1048576) >> 13, 240);
+ }
+ j++;
+ }
+ }
+}
+
diff --git a/recordmydesktop/src/capture_sound.c b/recordmydesktop/src/capture_sound.c
new file mode 100644
index 0000000..5dc3839
--- /dev/null
+++ b/recordmydesktop/src/capture_sound.c
@@ -0,0 +1,106 @@
+/*********************************************************************************
+* recordMyDesktop *
+**********************************************************************************
+* *
+* Copyright (C) 2006 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+* *
+* *
+* *
+* For further information contact me at biocrasher@gmail.com *
+**********************************************************************************/
+
+
+#include <recordmydesktop.h>
+
+void *CaptureSound(void *pdata){
+
+ int frames=((ProgData *)pdata)->periodsize>>((ProgData *)pdata)->args.channels;
+// fprintf(stderr,"fr %d ps %d\n",frames,((ProgData *)pdata)->periodsize);fflush(stderr);
+ pthread_mutex_t pmut;
+ pthread_mutex_init(&pmut,NULL);
+ ((ProgData *)pdata)->sound_buffer=NULL;
+
+ while(((ProgData *)pdata)->running){
+ int sret=0;
+ SndBuffer *newbuf,*tmp;
+ if(Paused){
+ if(!((ProgData *)pdata)->hard_pause){
+ snd_pcm_pause(((ProgData *)pdata)->sound_handle,1);
+ pthread_cond_wait(&((ProgData *)pdata)->pause_cond,&pmut);
+ snd_pcm_pause(((ProgData *)pdata)->sound_handle,0);
+ }
+ else{//device doesn't support pause(is this the norm?mine doesn't)
+ snd_pcm_close(((ProgData *)pdata)->sound_handle);
+ pthread_cond_wait(&((ProgData *)pdata)->pause_cond,&pmut);
+
+ ((ProgData *)pdata)->sound_handle=
+ OpenDev(((ProgData *)pdata)->args.device,
+ ((ProgData *)pdata)->args.channels,
+ &((ProgData *)pdata)->args.frequency,
+ NULL,
+ NULL,
+ NULL//let's hope that the device capabilities didn't magically change
+ );
+ if(((ProgData *)pdata)->sound_handle==NULL){
+ fprintf(stderr,"Couldn't reopen sound device.\nThere will be no sound data from this point on.\n");
+ pthread_exit(&errno);
+ }
+ }
+ }
+
+ //create new buffer
+ newbuf=(SndBuffer *)malloc(sizeof(SndBuffer *));
+ newbuf->data=(signed char *)malloc(((ProgData *)pdata)->periodsize);
+ newbuf->next=NULL;
+
+ //read data into new buffer
+ while(sret<frames){
+ int tsret=snd_pcm_readi(((ProgData *)pdata)->sound_handle,
+ newbuf->data+2*((ProgData *)pdata)->args.channels*sret,
+ frames-sret);
+ if(tsret==-EPIPE)
+ snd_pcm_prepare(((ProgData *)pdata)->sound_handle);
+ else if (tsret<0){
+ fprintf(stderr,"An error occured while reading sound data:\n %s\n",snd_strerror(sret));
+ }
+ else
+ sret+=tsret;
+ }
+
+ //queue the new buffer
+ pthread_mutex_lock(&((ProgData *)pdata)->sound_buffer_mutex);
+ tmp=((ProgData *)pdata)->sound_buffer;
+ if(((ProgData *)pdata)->sound_buffer==NULL)
+ ((ProgData *)pdata)->sound_buffer=newbuf;
+ else{
+ while(tmp->next!=NULL)
+ tmp=tmp->next;
+ tmp->next=newbuf;
+ }
+ pthread_mutex_unlock(&((ProgData *)pdata)->sound_buffer_mutex);
+
+
+ //signal that there are data to be proccessed
+ pthread_cond_signal(&((ProgData *)pdata)->sound_data_read);
+ }
+ snd_pcm_close(((ProgData *)pdata)->sound_handle);
+ pthread_exit(&errno);
+}
+
+
+
diff --git a/recordmydesktop/src/encode_image_buffer.c b/recordmydesktop/src/encode_image_buffer.c
new file mode 100644
index 0000000..f4c712a
--- /dev/null
+++ b/recordmydesktop/src/encode_image_buffer.c
@@ -0,0 +1,33 @@
+#include <recordmydesktop.h>
+
+void *EncodeImageBuffer(void *pdata){
+ pthread_mutex_t pmut,imut;
+ pthread_mutex_init(&pmut,NULL);
+ pthread_mutex_init(&imut,NULL);
+
+ while(((ProgData *)pdata)->running){
+ pthread_cond_wait(&((ProgData *)pdata)->image_buffer_ready,&imut);
+ if(Paused)
+ pthread_cond_wait(&((ProgData *)pdata)->pause_cond,&pmut);//this may not be needed
+ pthread_mutex_lock(&((ProgData *)pdata)->yuv_mutex);
+ if(theora_encode_YUVin(&((ProgData *)pdata)->enc_data->m_th_st,&((ProgData *)pdata)->enc_data->yuv)){
+ fprintf(stderr,"Encoder not ready!\n");
+ }
+ pthread_mutex_unlock(&((ProgData *)pdata)->yuv_mutex);
+ theora_encode_packetout(&((ProgData *)pdata)->enc_data->m_th_st,0,&((ProgData *)pdata)->enc_data->m_ogg_pckt1);
+ ogg_stream_packetin(&((ProgData *)pdata)->enc_data->m_ogg_ts,&((ProgData *)pdata)->enc_data->m_ogg_pckt1);
+ avd+=((ProgData *)pdata)->frametime*2*((ProgData *)pdata)->args.channels;
+ }
+ //last packet
+ if(theora_encode_YUVin(&((ProgData *)pdata)->enc_data->m_th_st,&((ProgData *)pdata)->enc_data->yuv)){
+ fprintf(stderr,"Encoder not ready!\n");
+ }
+
+ theora_encode_packetout(&((ProgData *)pdata)->enc_data->m_th_st,1,&((ProgData *)pdata)->enc_data->m_ogg_pckt1);
+
+// ogg_stream_packetin(&((ProgData *)pdata)->enc_data->m_ogg_ts,&((ProgData *)pdata)->enc_data->m_ogg_pckt);
+
+ pthread_exit(&errno);
+}
+
+
diff --git a/recordmydesktop/src/encode_sound_buffer.c b/recordmydesktop/src/encode_sound_buffer.c
new file mode 100644
index 0000000..1c42ae8
--- /dev/null
+++ b/recordmydesktop/src/encode_sound_buffer.c
@@ -0,0 +1,64 @@
+#include <recordmydesktop.h>
+
+void *EncodeSoundBuffer(void *pdata){
+
+ int sampread=((ProgData *)pdata)->periodsize/(2*((ProgData *)pdata)->args.channels);
+ pthread_mutex_t smut;
+ pthread_mutex_init(&smut,NULL);
+ while((((ProgData *)pdata)->running)){
+ float **vorbis_buffer;
+ int count=0,i,j;
+ SndBuffer *buff;
+
+ if(Paused){
+ pthread_mutex_t tmut;
+ pthread_mutex_init(&tmut,NULL);
+ pthread_cond_wait(&((ProgData *)pdata)->pause_cond,&tmut);
+ }
+
+ if(((ProgData *)pdata)->sound_buffer==NULL)
+ pthread_cond_wait(&((ProgData *)pdata)->sound_data_read,&smut);
+
+ pthread_mutex_lock(&((ProgData *)pdata)->sound_buffer_mutex);
+ buff=((ProgData *)pdata)->sound_buffer;
+ //advance the list
+ ((ProgData *)pdata)->sound_buffer=((ProgData *)pdata)->sound_buffer->next;
+ pthread_mutex_unlock(&((ProgData *)pdata)->sound_buffer_mutex);
+
+ if (avd>0){
+ vorbis_buffer=vorbis_analysis_buffer(&((ProgData *)pdata)->enc_data->m_vo_dsp,sampread);
+
+ for(i=0;i<sampread;i++){
+ for(j=0;j<((ProgData *)pdata)->args.channels;j++){
+ vorbis_buffer[j][i]=((buff->data[count+1]<<8)|
+ (0x00ff&(int)buff->data[count]))/32768.f;
+ count+=2;
+ }
+ }
+ vorbis_analysis_wrote(&((ProgData *)pdata)->enc_data->m_vo_dsp,sampread);
+
+ while(vorbis_analysis_blockout(&((ProgData *)pdata)->enc_data->m_vo_dsp,&((ProgData *)pdata)->enc_data->m_vo_block)==1){
+
+ vorbis_analysis(&((ProgData *)pdata)->enc_data->m_vo_block,NULL);
+ vorbis_bitrate_addblock(&((ProgData *)pdata)->enc_data->m_vo_block);
+
+ while(vorbis_bitrate_flushpacket(&((ProgData *)pdata)->enc_data->m_vo_dsp,&((ProgData *)pdata)->enc_data->m_ogg_pckt2))
+ ogg_stream_packetin(&((ProgData *)pdata)->enc_data->m_ogg_vs,&((ProgData *)pdata)->enc_data->m_ogg_pckt2);
+ }
+ avd-=((ProgData *)pdata)->periodtime;
+ }
+ free(buff);
+ }
+
+ vorbis_analysis_wrote(&((ProgData *)pdata)->enc_data->m_vo_dsp,0);
+// while(vorbis_analysis_blockout(&((ProgData *)pdata)->enc_data->m_vo_dsp,&((ProgData *)pdata)->enc_data->m_vo_block)==1){
+// vorbis_analysis(&((ProgData *)pdata)->enc_data->m_vo_block,NULL);
+// vorbis_bitrate_addblock(&((ProgData *)pdata)->enc_data->m_vo_block);
+// while(vorbis_bitrate_flushpacket(&((ProgData *)pdata)->enc_data->m_vo_dsp,&((ProgData *)pdata)->enc_data->m_ogg_pckt2))
+// ogg_stream_packetin(&((ProgData *)pdata)->enc_data->m_ogg_vs,&((ProgData *)pdata)->enc_data->m_ogg_pckt2);
+// }
+
+ pthread_exit(&errno);
+}
+
+
diff --git a/recordmydesktop/src/flush_to_ogg.c b/recordmydesktop/src/flush_to_ogg.c
new file mode 100644
index 0000000..c32302c
--- /dev/null
+++ b/recordmydesktop/src/flush_to_ogg.c
@@ -0,0 +1,64 @@
+#include <recordmydesktop.h>
+
+void *FlushToOgg(void *pdata){
+ int videoflag=0,audioflag=0;
+ double video_bytesout=0,audio_bytesout=0;
+ ogg_page videopage,audiopage;
+ int prev=0;
+ while(((ProgData *)pdata)->running){
+// if(Paused)pthread_cond_wait(&((ProgData *)pdata)->pause_cond,&((ProgData *)pdata)->pause_cond_mutex);
+// if(!prev){
+ videoflag=ogg_stream_pageout(&((ProgData *)pdata)->enc_data->m_ogg_ts,&videopage);
+ if(videoflag){
+ video_bytesout+=fwrite(videopage.header,1,videopage.header_len,((ProgData *)pdata)->enc_data->fp);
+ video_bytesout+=fwrite(videopage.body,1,videopage.body_len,((ProgData *)pdata)->enc_data->fp);
+ videoflag=0;
+// prev=(!((ProgData *)pdata)->args.nosound);
+
+
+// }
+ if(!((ProgData *)pdata)->args.nosound){
+
+ audioflag=ogg_stream_pageout(&((ProgData *)pdata)->enc_data->m_ogg_vs,&audiopage);
+
+ if(audioflag){
+ audio_bytesout+=fwrite(audiopage.header,1,audiopage.header_len,((ProgData *)pdata)->enc_data->fp);
+ audio_bytesout+=fwrite(audiopage.body,1,audiopage.body_len,((ProgData *)pdata)->enc_data->fp);
+ audioflag=0;
+ prev=0;
+ }
+ }
+// else
+// if(!did_one)
+// usleep(10000);
+ }
+ else /*if(((ProgData *)pdata)->args.nosound)*/
+ usleep(10000);
+
+ }
+ //last packages
+ videoflag=ogg_stream_flush(&((ProgData *)pdata)->enc_data->m_ogg_ts,&videopage);
+ if(videoflag){
+ video_bytesout+=fwrite(videopage.header,1,videopage.header_len,((ProgData *)pdata)->enc_data->fp);
+ video_bytesout+=fwrite(videopage.body,1,videopage.body_len,((ProgData *)pdata)->enc_data->fp);
+ videoflag=0;
+ }
+ if(!((ProgData *)pdata)->args.nosound)
+ audioflag=ogg_stream_flush(&((ProgData *)pdata)->enc_data->m_ogg_vs,&audiopage);
+ if(audioflag){
+ audio_bytesout+=fwrite(audiopage.header,1,audiopage.header_len,((ProgData *)pdata)->enc_data->fp);
+ audio_bytesout+=fwrite(audiopage.body,1,audiopage.body_len,((ProgData *)pdata)->enc_data->fp);
+ audioflag=0;
+ }
+
+ ogg_stream_clear(&((ProgData *)pdata)->enc_data->m_ogg_ts);
+ if(!((ProgData *)pdata)->args.nosound)
+ ogg_stream_clear(&((ProgData *)pdata)->enc_data->m_ogg_vs);
+//this always gives me a segfault :(
+// theora_clear(&((ProgData *)pdata)->enc_data->m_th_st);
+
+ if(((ProgData *)pdata)->enc_data->fp)fclose(((ProgData *)pdata)->enc_data->fp);
+
+ fprintf(stderr,"\r \nDone.\nWritten %.0f bytes\n(%.0f of which were video data and %.0f audio data)\n\n",video_bytesout+audio_bytesout,video_bytesout,audio_bytesout);
+ pthread_exit(&errno);
+}
diff --git a/recordmydesktop/src/get_frame.c b/recordmydesktop/src/get_frame.c
new file mode 100644
index 0000000..67c6eb2
--- /dev/null
+++ b/recordmydesktop/src/get_frame.c
@@ -0,0 +1,125 @@
+/*********************************************************************************
+* recordMyDesktop *
+**********************************************************************************
+* *
+* Copyright (C) 2006 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+* *
+* *
+* *
+* For further information contact me at biocrasher@gmail.com *
+**********************************************************************************/
+
+
+#include <recordmydesktop.h>
+
+void *GetFrame(void *pdata){
+ int tlist_sel=0;
+ pthread_mutex_t pmut,tmut;
+ uint msk_ret;
+ WGeometry mouse_pos_abs,mouse_pos_rel,mouse_pos_temp;
+ Window root_ret,child_ret;
+ mouse_pos_abs.x=0;
+ mouse_pos_abs.y=0;
+ mouse_pos_abs.width=((ProgData *)pdata)->dummy_p_size;
+ mouse_pos_abs.height=((ProgData *)pdata)->dummy_p_size;
+ pthread_mutex_init(&pmut,NULL);
+ pthread_mutex_init(&tmut,NULL);
+
+ while(((ProgData *)pdata)->running){
+ pthread_cond_wait(&((ProgData *)pdata)->time_cond,&tmut);
+ if(Paused){
+ pthread_cond_wait(&((ProgData *)pdata)->pause_cond,&pmut);
+ }
+ /*pthread_cond_wait(&((ProgData *)pdata)->pause_cond,&((ProgData *)pdata)->pause_cond_mutex);*/
+ //mutexes and lists with changes are useless when full_shots is enabled
+ if(!((ProgData *)pdata)->args.full_shots){
+ tlist_sel=((ProgData *)pdata)->list_selector;
+ ((ProgData *)pdata)->list_selector=((((ProgData *)pdata)->list_selector+1)%2);
+ pthread_mutex_lock(&((ProgData *)pdata)->list_mutex[tlist_sel]);
+ }
+
+ if(((ProgData *)pdata)->args.have_dummy_cursor){
+ //dummy pointer sequence
+ //update previous_position
+ //(if full_shots is enabled this is skipped since it's pointless)
+ if(!((ProgData *)pdata)->args.full_shots){
+ CLIP_DUMMY_POINTER_AREA(mouse_pos_abs,&((ProgData *)pdata)->brwin,&mouse_pos_temp);
+ if((mouse_pos_temp.x>=0)&&(mouse_pos_temp.y>=0)&&(mouse_pos_temp.width>0)&&(mouse_pos_temp.height>0))
+ RectInsert(&((ProgData *)pdata)->rect_root[tlist_sel],&mouse_pos_temp);
+ }
+ //find new one
+ XQueryPointer(((ProgData *)pdata)->dpy,
+ ((ProgData *)pdata)->specs.root,
+ &root_ret,&child_ret,
+ &mouse_pos_abs.x,&mouse_pos_abs.y,
+ &mouse_pos_rel.x,&mouse_pos_rel.y,&msk_ret);
+ }
+ if(!((ProgData *)pdata)->args.noshared)
+ XShmGetImage(((ProgData *)pdata)->dpy,((ProgData *)pdata)->specs.root,((ProgData *)pdata)->image,(((ProgData *)pdata)->brwin.rgeom.x),(((ProgData *)pdata)->brwin.rgeom.y),AllPlanes);
+ if(!((ProgData *)pdata)->args.full_shots)
+ UpdateImage(((ProgData *)pdata)->dpy,
+ &((ProgData *)pdata)->enc_data->yuv,
+ &((ProgData *)pdata)->yuv_mutex,
+ &((ProgData *)pdata)->specs,
+ &((ProgData *)pdata)->rect_root[tlist_sel],
+ &((ProgData *)pdata)->brwin,
+ ((((ProgData *)pdata)->args.noshared)?(((ProgData *)pdata)->datatemp):((ProgData *)pdata)->image->data),
+ ((ProgData *)pdata)->args.noshared);
+ else{
+ if(((ProgData *)pdata)->args.noshared){
+ GetZPixmap( ((ProgData *)pdata)->dpy,
+ ((ProgData *)pdata)->specs.root,
+ ((ProgData *)pdata)->image->data,
+ ((ProgData *)pdata)->brwin.rgeom.x,
+ ((ProgData *)pdata)->brwin.rgeom.y,
+ ((ProgData *)pdata)->brwin.rgeom.width,
+ ((ProgData *)pdata)->brwin.rgeom.height);
+ pthread_mutex_lock(&((ProgData *)pdata)->yuv_mutex);
+ XImageToYUV(((ProgData *)pdata)->image,&((ProgData *)pdata)->enc_data->yuv);
+ pthread_mutex_unlock(&((ProgData *)pdata)->yuv_mutex);
+ }
+ else{
+ pthread_mutex_lock(&((ProgData *)pdata)->yuv_mutex);
+ XImageToYUV(((ProgData *)pdata)->image,&((ProgData *)pdata)->enc_data->yuv);
+ pthread_mutex_unlock(&((ProgData *)pdata)->yuv_mutex);
+ }
+ }
+ if(((ProgData *)pdata)->args.have_dummy_cursor){
+ //avoid segfaults
+ CLIP_DUMMY_POINTER_AREA(mouse_pos_abs,&((ProgData *)pdata)->brwin,&mouse_pos_temp);
+ //draw the cursor
+ if((mouse_pos_temp.x>=0)&&(mouse_pos_temp.y>=0)&&(mouse_pos_temp.width>0)&&(mouse_pos_temp.height>0)){
+ DUMMY_POINTER_TO_YUV((&((ProgData *)pdata)->enc_data->yuv),
+ ((ProgData *)pdata)->dummy_pointer,
+ (mouse_pos_temp.x-((ProgData *)pdata)->brwin.rgeom.x),
+ (mouse_pos_temp.y-((ProgData *)pdata)->brwin.rgeom.y),
+ mouse_pos_temp.width,
+ mouse_pos_temp.height,
+ ((ProgData *)pdata)->npxl);
+ }
+ }
+ if(!((ProgData *)pdata)->args.full_shots){
+ ClearList(&((ProgData *)pdata)->rect_root[tlist_sel]);
+ pthread_mutex_unlock(&((ProgData *)pdata)->list_mutex[tlist_sel]);
+ }
+ pthread_cond_broadcast(&((ProgData *)pdata)->image_buffer_ready);
+ }
+ pthread_cond_broadcast(&((ProgData *)pdata)->image_buffer_ready);
+ pthread_exit(&errno);
+}
+
diff --git a/recordmydesktop/src/getzpixmap.c b/recordmydesktop/src/getzpixmap.c
new file mode 100644
index 0000000..d1af10b
--- /dev/null
+++ b/recordmydesktop/src/getzpixmap.c
@@ -0,0 +1,55 @@
+/*********************************************************************************
+* recordMyDesktop *
+**********************************************************************************
+* *
+* Copyright (C) 2006 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+* *
+* *
+* *
+* For further information contact me at biocrasher@gmail.com *
+**********************************************************************************/
+
+
+#include <recordmydesktop.h>
+
+int GetZPixmap(Display *dpy,Window root,char *data,int x,int y,int width,int height) {
+ xGetImageReply reply;
+ xGetImageReq *request;
+ long nbytes;
+
+ LockDisplay(dpy);
+ GetReq(GetImage,request);
+ request->drawable=root;
+ request->x=x;
+ request->y=y;
+ request->width=width;
+ request->height=height;
+ request->planeMask=AllPlanes;
+ request->format=ZPixmap;
+ if((!_XReply(dpy,(xReply *)&reply,0,xFalse))||(!reply.length)){
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 1;
+ }
+ nbytes=(long)reply.length<<2;
+ _XReadPad(dpy,data,nbytes);
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 0;
+}
+
diff --git a/recordmydesktop/src/init_encoder.c b/recordmydesktop/src/init_encoder.c
new file mode 100644
index 0000000..35440dc
--- /dev/null
+++ b/recordmydesktop/src/init_encoder.c
@@ -0,0 +1,169 @@
+/*********************************************************************************
+* recordMyDesktop *
+**********************************************************************************
+* *
+* Copyright (C) 2006 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+* *
+* *
+* *
+* For further information contact me at biocrasher@gmail.com *
+**********************************************************************************/
+
+
+#include <recordmydesktop.h>
+
+void InitEncoder(ProgData *pdata,EncData *enc_data_t){
+ int y1,y2;
+ (pdata)->enc_data=enc_data_t;
+ srand(time(NULL));
+ y1=rand();
+ y2=rand();
+ y2+=(y1==y2);
+
+ ogg_stream_init(&(enc_data_t)->m_ogg_ts,y1);
+ if(!pdata->args.nosound)
+ ogg_stream_init(&(enc_data_t)->m_ogg_vs,y2);
+
+ (enc_data_t)->fp=fopen((pdata)->args.filename,"w");
+
+
+ theora_info_init(&(enc_data_t)->m_th_inf);
+ (enc_data_t)->m_th_inf.frame_width=(pdata)->brwin.rgeom.width;
+ (enc_data_t)->m_th_inf.frame_height=(pdata)->brwin.rgeom.height;
+ (enc_data_t)->m_th_inf.width=(((enc_data_t)->m_th_inf.frame_width + 15) >>4)<<4;
+ (enc_data_t)->m_th_inf.height=(((enc_data_t)->m_th_inf.frame_height + 15) >>4)<<4;
+ (enc_data_t)->m_th_inf.offset_x=(((enc_data_t)->m_th_inf.width-(enc_data_t)->m_th_inf.frame_width)/2)&~1;
+ (enc_data_t)->m_th_inf.offset_y=(((enc_data_t)->m_th_inf.height-(enc_data_t)->m_th_inf.frame_height)/2)&~1;
+ (enc_data_t)->m_th_inf.fps_numerator=((pdata)->args.fps*100.0);
+ (enc_data_t)->m_th_inf.fps_denominator=100;
+ (enc_data_t)->m_th_inf.aspect_numerator=(pdata)->brwin.rgeom.width;
+ (enc_data_t)->m_th_inf.aspect_denominator=(pdata)->brwin.rgeom.height;
+ (enc_data_t)->m_th_inf.colorspace=OC_CS_UNSPECIFIED;
+ (enc_data_t)->m_th_inf.pixelformat=OC_PF_420;
+ (enc_data_t)->m_th_inf.target_bitrate=(pdata)->args.v_bitrate;
+ (enc_data_t)->m_th_inf.quality=(pdata)->args.v_quality;
+ (enc_data_t)->m_th_inf.dropframes_p=0;
+ (enc_data_t)->m_th_inf.quick_p=1;
+ (enc_data_t)->m_th_inf.keyframe_auto_p=1;
+ (enc_data_t)->m_th_inf.keyframe_frequency=64;
+ (enc_data_t)->m_th_inf.keyframe_frequency_force=64;
+ (enc_data_t)->m_th_inf.keyframe_data_target_bitrate=(enc_data_t)->m_th_inf.quality*1.5;
+ (enc_data_t)->m_th_inf.keyframe_auto_threshold=80;
+ (enc_data_t)->m_th_inf.keyframe_mindistance=8;
+ (enc_data_t)->m_th_inf.noise_sensitivity=1;
+
+
+ theora_encode_init(&(enc_data_t)->m_th_st,&(enc_data_t)->m_th_inf);
+
+
+
+ if(!pdata->args.nosound){
+ int ret;
+ vorbis_info_init(&(enc_data_t)->m_vo_inf);
+ ret = vorbis_encode_init_vbr(&(enc_data_t)->m_vo_inf,pdata->args.channels,pdata->args.frequency,(float)pdata->args.s_quality*0.1);
+ if(ret){
+ fprintf(stderr,"Error while setting up vorbis stream quality!\n");
+ exit(1);
+ }
+ vorbis_comment_init(&(enc_data_t)->m_vo_cmmnt);
+ vorbis_analysis_init(&(enc_data_t)->m_vo_dsp,&(enc_data_t)->m_vo_inf);
+ vorbis_block_init(&(enc_data_t)->m_vo_dsp,&(enc_data_t)->m_vo_block);
+ }
+
+
+ theora_encode_header(&(enc_data_t)->m_th_st,&(enc_data_t)->m_ogg_pckt1);
+ ogg_stream_packetin(&(enc_data_t)->m_ogg_ts,&(enc_data_t)->m_ogg_pckt1);
+ if(ogg_stream_pageout(&(enc_data_t)->m_ogg_ts,&(enc_data_t)->m_ogg_pg)!=1){
+ fprintf(stderr,"Internal Ogg library error.\n");
+ exit(1);
+ }
+ fwrite((enc_data_t)->m_ogg_pg.header,1,(enc_data_t)->m_ogg_pg.header_len,(enc_data_t)->fp);
+ fwrite((enc_data_t)->m_ogg_pg.body,1,(enc_data_t)->m_ogg_pg.body_len,(enc_data_t)->fp);
+
+ theora_comment_init(&(enc_data_t)->m_th_cmmnt);
+ theora_comment_add_tag(&(enc_data_t)->m_th_cmmnt,"recordMyDesktop",VERSION);
+ theora_encode_comment(&(enc_data_t)->m_th_cmmnt,&(enc_data_t)->m_ogg_pckt1);
+ ogg_stream_packetin(&(enc_data_t)->m_ogg_ts,&(enc_data_t)->m_ogg_pckt1);
+ theora_encode_tables(&(enc_data_t)->m_th_st,&(enc_data_t)->m_ogg_pckt1);
+ ogg_stream_packetin(&(enc_data_t)->m_ogg_ts,&(enc_data_t)->m_ogg_pckt1);
+
+
+ if(!pdata->args.nosound){
+ ogg_packet header;
+ ogg_packet header_comm;
+ ogg_packet header_code;
+
+ vorbis_analysis_headerout(&(enc_data_t)->m_vo_dsp,&(enc_data_t)->m_vo_cmmnt,&header,&header_comm,&header_code);
+ ogg_stream_packetin(&(enc_data_t)->m_ogg_vs,&header);
+ if(ogg_stream_pageout(&(enc_data_t)->m_ogg_vs,&(enc_data_t)->m_ogg_pg)!=1){
+ fprintf(stderr,"Internal Ogg library error.\n");
+ exit(1);
+ }
+ fwrite((enc_data_t)->m_ogg_pg.header,1,(enc_data_t)->m_ogg_pg.header_len,(enc_data_t)->fp);
+ fwrite((enc_data_t)->m_ogg_pg.body,1,(enc_data_t)->m_ogg_pg.body_len,(enc_data_t)->fp);
+
+ ogg_stream_packetin(&(enc_data_t)->m_ogg_vs,&header_comm);
+ ogg_stream_packetin(&(enc_data_t)->m_ogg_vs,&header_code);
+ }
+
+
+
+ while(1){
+ int result = ogg_stream_flush(&(enc_data_t)->m_ogg_ts,&(enc_data_t)->m_ogg_pg);
+ if(result<0){
+ fprintf(stderr,"Internal Ogg library error.\n");
+ exit(1);
+ }
+ if(result==0)break;
+ fwrite((enc_data_t)->m_ogg_pg.header,1,(enc_data_t)->m_ogg_pg.header_len,(enc_data_t)->fp);
+ fwrite((enc_data_t)->m_ogg_pg.body,1,(enc_data_t)->m_ogg_pg.body_len,(enc_data_t)->fp);
+ }
+
+ if(!pdata->args.nosound){
+ while(1){
+ int result=ogg_stream_flush(&(enc_data_t)->m_ogg_vs,&(enc_data_t)->m_ogg_pg);
+ if(result<0){
+ fprintf(stderr,"Internal Ogg library error.\n");
+ exit(1);
+ }
+ if(result==0)break;
+ fwrite((enc_data_t)->m_ogg_pg.header,1,(enc_data_t)->m_ogg_pg.header_len,(enc_data_t)->fp);
+ fwrite((enc_data_t)->m_ogg_pg.body,1,(enc_data_t)->m_ogg_pg.body_len,(enc_data_t)->fp);
+ }
+ }
+
+
+
+ (enc_data_t)->yuv.y=(unsigned char *)malloc((pdata)->image->height*((ProgData *)pdata)->image->width);
+ (enc_data_t)->yuv.u=(unsigned char *)malloc((pdata)->image->height*((ProgData *)pdata)->image->width/4);
+ (enc_data_t)->yuv.v=(unsigned char *)malloc((pdata)->image->height*((ProgData *)pdata)->image->width/4);
+ (enc_data_t)->yuv.y_width=(enc_data_t)->m_th_inf.width;
+ (enc_data_t)->yuv.y_height=(enc_data_t)->m_th_inf.height;
+ (enc_data_t)->yuv.y_stride=(enc_data_t)->m_th_inf.width;
+
+ (enc_data_t)->yuv.uv_width=(enc_data_t)->m_th_inf.width/2;
+ (enc_data_t)->yuv.uv_height=(enc_data_t)->m_th_inf.height/2;
+ (enc_data_t)->yuv.uv_stride=(enc_data_t)->m_th_inf.width/2;
+
+ theora_info_clear(&(enc_data_t)->m_th_inf);
+
+}
+
+
+
+
diff --git a/recordmydesktop/src/make_dummy_pointer.c b/recordmydesktop/src/make_dummy_pointer.c
new file mode 100644
index 0000000..0ab0306
--- /dev/null
+++ b/recordmydesktop/src/make_dummy_pointer.c
@@ -0,0 +1,68 @@
+/*********************************************************************************
+* recordMyDesktop *
+**********************************************************************************
+* *
+* Copyright (C) 2006 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+* *
+* *
+* *
+* For further information contact me at biocrasher@gmail.com *
+**********************************************************************************/
+
+
+#include <recordmydesktop.h>
+
+unsigned char *MakeDummyPointer(DisplaySpecs *specs,int size,int color,int type,unsigned char *npxl){
+ int i,k,o='.';
+ unsigned long w=(color)?1:-1,
+ b=(color)?-1:1;
+ char pmask[1][16][16]={{
+ {w,w,w,w,w,w,o,o,o,o,o,o,o,o,o,o},
+ {w,b,b,w,w,w,w,o,o,o,o,o,o,o,o,o},
+ {w,b,b,b,w,w,w,w,o,o,o,o,o,o,o,o},
+ {w,b,b,b,b,w,w,w,w,o,o,o,o,o,o,o},
+ {w,b,b,b,b,b,w,w,w,w,o,o,o,o,o,o},
+ {w,b,b,b,b,b,b,w,w,w,w,o,o,o,o,o},
+ {w,b,b,b,b,b,b,b,w,w,w,w,o,o,o,o},
+ {w,b,b,b,b,b,b,b,b,w,w,w,w,o,o,o},
+ {w,b,b,b,b,b,b,b,b,b,w,w,w,w,o,o},
+ {w,b,b,b,b,b,b,b,b,b,b,w,w,w,w,o},
+ {w,b,b,b,b,b,b,b,b,w,w,w,w,o,o,o},
+ {w,b,b,b,b,b,b,b,b,w,w,w,w,o,o,o},
+ {w,w,w,w,w,b,b,b,b,b,w,w,w,o,o,o},
+ {w,w,w,w,w,w,b,b,b,b,w,w,w,o,o,o},
+ {o,o,o,o,o,w,w,b,b,b,w,w,w,o,o,o},
+ {o,o,o,o,o,o,w,w,w,w,w,w,w,o,o,o}}
+ };
+
+
+ unsigned char *ret=malloc(size*sizeof(char[size*4]));
+ unsigned char wp[4]={255,255,255,255};
+ unsigned char bp[4]={0,0,0,0};
+ *npxl=((wp[0]-1)!=bp[0])?wp[0]-100:wp[0]-102;
+ for(i=0;i<size;i++){
+ for(k=0;k<size;k++){
+ ret[(i*size+k)*4]=(pmask[type][i][k]==1)?wp[0]:(pmask[type][i][k]==-1)?bp[0]:*npxl;
+ ret[(i*size+k)*4+1]=(pmask[type][i][k]==1)?wp[1]:(pmask[type][i][k]==-1)?bp[1]:*npxl;
+ ret[(i*size+k)*4+2]=(pmask[type][i][k]==1)?wp[2]:(pmask[type][i][k]==-1)?bp[2]:*npxl;
+ ret[(i*size+k)*4+3]=(pmask[type][i][k]==1)?wp[3]:(pmask[type][i][k]==-1)?bp[3]:*npxl;
+ }
+ }
+
+ return ret;
+}
diff --git a/recordmydesktop/src/opendev.c b/recordmydesktop/src/opendev.c
new file mode 100644
index 0000000..d8a4179
--- /dev/null
+++ b/recordmydesktop/src/opendev.c
@@ -0,0 +1,98 @@
+/*********************************************************************************
+* recordMyDesktop *
+**********************************************************************************
+* *
+* Copyright (C) 2006 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+* *
+* *
+* *
+* For further information contact me at biocrasher@gmail.com *
+**********************************************************************************/
+
+
+
+
+#include <recordmydesktop.h>
+
+
+snd_pcm_t *OpenDev(const char *pcm_dev,unsigned int channels,unsigned int *frequency,snd_pcm_uframes_t *periodsize,unsigned int *periodtime,int *hard_pause){
+
+ snd_pcm_t *mhandle;
+ snd_pcm_hw_params_t *hwparams;
+ unsigned int periods=2;
+ unsigned int exactrate = *frequency;
+
+ snd_pcm_hw_params_alloca(&hwparams);
+ snd_pcm_uframes_t buffsize=4096;
+
+ if (snd_pcm_open(&mhandle, pcm_dev, SND_PCM_STREAM_CAPTURE, 0)<0){
+ fprintf(stderr, "Couldn't open PCM device %s\n", pcm_dev);
+ return NULL;
+ }
+ if (snd_pcm_hw_params_any(mhandle, hwparams)<0){
+ fprintf(stderr, "Couldn't configure PCM device.\n");
+ return NULL;
+ }
+ if (snd_pcm_hw_params_set_access(mhandle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)<0) {
+ fprintf(stderr, "Couldn't set access.\n");
+ return NULL;
+ }
+ if (snd_pcm_hw_params_set_format(mhandle, hwparams, SND_PCM_FORMAT_S16_LE)<0){
+ fprintf(stderr, "Couldn't set format.\n");
+ return NULL;
+ }
+ if (snd_pcm_hw_params_set_rate_near(mhandle, hwparams, &exactrate, 0)<0){
+ fprintf(stderr, "Couldn't set frequency.\n");
+ return NULL;
+ }
+ if (*frequency != exactrate){
+ fprintf(stderr, "Playback frequency %dHz is not available...\nUsing %dHz instead.\n",*frequency,exactrate);
+ *frequency=exactrate;
+ }
+ if (snd_pcm_hw_params_set_channels_near(mhandle, hwparams, &channels)<0){
+ fprintf(stderr, "Couldn't set channels number.\n");
+ return NULL;
+ }
+ if (snd_pcm_hw_params_set_periods_near(mhandle, hwparams, &periods,0)<0) {
+ fprintf(stderr, "Couldn't set periods.\n");
+ return NULL;
+ }
+ buffsize=(((exactrate*channels)))>>channels;
+ if (snd_pcm_hw_params_set_buffer_size_near(mhandle, hwparams,&buffsize)<0){
+ fprintf(stderr, "Couldn't set buffer size.\n");
+ return NULL;
+ }
+ if (snd_pcm_hw_params(mhandle, hwparams)<0){
+ fprintf(stderr, "Couldn't set hardware parameters.\n");
+ return NULL;
+ }
+ if(hard_pause!=NULL)
+ if(!snd_pcm_hw_params_can_pause(hwparams)){
+// fprintf(stderr, "Current sound device doesn't seem to support pausing!\nI will attempt to close/reopen device in case you opt to pause during recording.\n");
+ *hard_pause=1;
+ }
+ if(periodsize!=NULL)
+ snd_pcm_hw_params_get_period_size(hwparams,periodsize,0);
+ if(periodtime!=NULL)
+ snd_pcm_hw_params_get_period_time(hwparams,periodtime,0);
+ snd_pcm_prepare(mhandle);
+
+ return mhandle;
+}
+
+
diff --git a/recordmydesktop/src/parseargs.c b/recordmydesktop/src/parseargs.c
new file mode 100644
index 0000000..ea82920
--- /dev/null
+++ b/recordmydesktop/src/parseargs.c
@@ -0,0 +1,380 @@
+/*********************************************************************************
+* recordMyDesktop *
+**********************************************************************************
+* *
+* Copyright (C) 2006 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+* *
+* *
+* *
+* For further information contact me at biocrasher@gmail.com *
+**********************************************************************************/
+
+
+#include <recordmydesktop.h>
+
+
+int ParseArgs(int argc,char **argv,ProgArgs *arg_return){
+ int i;
+ char *usage="\nUsage:\n"
+ "\trecordmydesktop [-h| --help| --version| -delay n[H|h|M|m]| -windowid id_of_window|\n"
+ "\t-display DISPLAY| -x X| -y Y|-width N| -height N| -fps N(number>0)|\n"
+ "\t -v_quality n| -s_quality n| -v_bitrate n| -dummy-cursor color| --no-dummy-cursor|\n"
+ "\t -freq N(number>0)| -channels N(number>0)| -device SOUND_DEVICE| --nosound|\n"
+ "\t --with-shared| --full-shots| --scshot| -scale-shot N| -o filename]^filename\n\n\n"
+
+ "General Options:\n"
+ "\t-h or --help\t\tPrint this help and exit.\n"
+ "\t--version\t\tPrint program version and exit.\n\n"
+
+ "Image Options:\n"
+ "\t-windowid id_of_window\tid of window to be recorded.\n"
+ "\t-display DISPLAY\tDisplay to connect to.\n"
+ "\t-x X\t\t\tOffset in x direction.\n"
+ "\t-y Y\t\t\tOffset in y direction.\n"
+ "\t-width N\t\tWidth of recorded window.\n"
+ "\t-height N\t\tHeight of recorded window.\n\n"
+
+ "\t-dummy-cursor color\tColor of the dummy cursor [black|white](default black)\n"
+ "\t--no-dummy-cursor\tDisable drawing of a dummy cursor.\n"
+ "\t--with-shared\t\tEnable usage of MIT-shared memory extension.\n"
+ "\t--full-shots\t\tTake full screenshot at every frame(Not recomended!).\n"
+ "\t-fps N(number>0.0)\tA positive number denoting desired framerate.\n\n"
+
+ "Sound Options:\n"
+ "\t-channels N(number>0)\tA positive number denoting desired sound channels in recording.\n"
+ "\t-freq N(number>0)\tA positive number denoting desired sound frequency.\n"
+ "\t-device SOUND_DEVICE\tSound device(default hw0:0).\n"
+ "\t--nosound\t\tDo not record sound.\n\n"
+
+ "Encoding Options\n"
+ "\t-v_quality n\t\tA number from 0 to 63 for desired encoded video quality(default 63).\n"
+ "\t-v_bitrate n\t\tA number from 45000 to 2000000 for desired encoded video bitrate(default 45000).\n"
+ "\t-s_quality n\t\tDesired audio quality(-1 to 10).\n\n"
+
+ "Misc Options:\n"
+ "\t-delay n[H|h|M|m]\tNumber of secs(default),minutes or hours before capture starts(number can be float)\n"
+ "\t--scshot\t\tTake a bitmap screenshot(default rmdout.bmp) and exit.\n"
+ "\t-scale-shot N\t\tFactor by which screenshot is scaled down(1<=number<=64,power of 2).\n"
+ "\t-o filename\t\tName of recorded video(default out.ogg).\n"
+ "\n\tIf no other options are specified, filename can be given without the -o switch.\n\n\n";
+
+ if(argc==2){
+ if(argv[1][0]!='-'){
+ realloc(arg_return->filename,strlen(argv[1])+1);
+ strcpy(arg_return->filename,argv[1]);
+ return 0;
+ }
+ }
+ for(i=1;i<argc;i++){
+ if(!strcmp(argv[i],"-delay")){
+ if(i+1<argc){
+ float num=atof(argv[i+1]);
+ if(num>0.0){
+ int k;
+ for(k=0;k<strlen(argv[i+1]);k++){
+ if((argv[i+1][k]=='M')||(argv[i+1][k]=='m')){
+ num*=60.0;
+ break;
+ }
+ else if((argv[i+1][k]=='H')||(argv[i+1][k]=='h')){
+ num*=3600.0;
+ break;
+ }
+ }
+ arg_return->delay=(int)num;
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -delay n[H|h|M|m]\nwhere n is a float number\n");
+ return 1;
+ }
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -delay n[H|h|M|m]\nwhere n is a float number\n");
+ return 1;
+ }
+ i++;
+ }
+ else if(!strcmp(argv[i],"-windowid")){
+ if(i+1<argc){
+ Window num=strtod(argv[i+1],NULL);
+ if(num>0)
+ arg_return->windowid=num;
+ else{
+ fprintf(stderr,"Argument Usage: -windowid id_of_window(number)\n");
+ return 1;
+ }
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -windowid id_of_window(number)\n");
+ return 1;
+ }
+ i++;
+ }
+ else if(!strcmp(argv[i],"-display")){
+ if(i+1<argc){
+ realloc(arg_return->display,strlen(argv[i+1])+1);
+ strcpy(arg_return->display,argv[i+1]);
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -display DISPLAY\n");
+ return 1;
+ }
+ i++;
+ }
+ else if(!strcmp(argv[i],"-x")){
+ if(i+1<argc){
+ int num=atoi(argv[i+1]);
+ if(num>0)
+ arg_return->x=num;
+ else{
+ fprintf(stderr,"Argument Usage: -x X(number>0)\n");
+ return 1;
+ }
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -x X(number>0)\n");
+ return 1;
+ }
+ i++;
+ }
+ else if(!strcmp(argv[i],"-y")){
+ if(i+1<argc){
+ int num=atoi(argv[i+1]);
+ if(num>0)
+ arg_return->y=num;
+ else{
+ fprintf(stderr,"Argument Usage: -y Y(number>0)\n");
+ return 1;
+ }
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -y Y(number>0)\n");
+ return 1;
+ }
+ i++;
+ }
+ else if(!strcmp(argv[i],"-width")){
+ if(i+1<argc){
+ int num=atoi(argv[i+1]);
+ if(num>0)
+ arg_return->width=num;
+ else{
+ fprintf(stderr,"Argument Usage: -width N(number>0)\n");
+ return 1;
+ }
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -width N(number>0)\n");
+ return 1;
+ }
+ i++;
+ }
+ else if(!strcmp(argv[i],"-height")){
+ if(i+1<argc){
+ int num=atoi(argv[i+1]);
+ if(num>0)
+ arg_return->height=num;
+ else{
+ fprintf(stderr,"Argument Usage: -height N(number>0)\n");
+ return 1;
+ }
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -height N(number>0)\n");
+ return 1;
+ }
+ i++;
+ }
+ else if(!strcmp(argv[i],"-o")){
+ if(i+1<argc){
+ realloc(arg_return->filename,strlen(argv[i+1])+1);
+ strcpy(arg_return->filename,argv[i+1]);
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -o filename\n");
+ return 1;
+ }
+ i++;
+ }
+ else if(!strcmp(argv[i],"-fps")){
+ if(i+1<argc){
+ float num=atof(argv[i+1]);
+ if(num>0.0)
+ arg_return->fps=num;
+ else{
+ fprintf(stderr,"Argument Usage: -fps N(number>0)\n");
+ return 1;
+ }
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -fps N(number>0)\n");
+ return 1;
+ }
+ i++;
+ }
+ else if(!strcmp(argv[i],"-v_quality")){
+ if(i+1<argc){
+ int num=atoi(argv[i+1]);
+ if((num>=0)&&(num<64))
+ arg_return->v_quality=num;
+ else{
+ fprintf(stderr,"Argument Usage: -v_quality n(number 0-63)\n");
+ return 1;
+ }
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -v_quality n(number 0-63)\n");
+ return 1;
+ }
+ i++;
+ }
+ else if(!strcmp(argv[i],"-v_bitrate")){
+ if(i+1<argc){
+ int num=atoi(argv[i+1]);
+ if((num>=45000)&&(num<=2000000))
+ arg_return->v_bitrate=num;
+ else{
+ fprintf(stderr,"Argument Usage: -v_bitrate n(number 45000-2000000)\n");
+ return 1;
+ }
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -v_bitrate n(number 45000-2000000)\n");
+ return 1;
+ }
+ i++;
+ }
+ else if(!strcmp(argv[i],"-dummy-cursor")){
+ if(i+1<argc){
+ if(!strcmp(argv[i+1],"white"))
+ arg_return->cursor_color=0;
+ else if(!strcmp(argv[i+1],"black"))
+ arg_return->cursor_color=1;
+ else{
+ fprintf(stderr,"Argument Usage: -dummy-cursor [black|white](default black)\n");
+ return 1;
+ }
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -dummy-cursor [black|white](default black)\n");
+ return 1;
+ }
+ i++;
+ }
+ else if(!strcmp(argv[i],"--no-dummy-cursor"))
+ arg_return->have_dummy_cursor=0;
+ else if(!strcmp(argv[i],"-freq")){
+ if(i+1<argc){
+ int num=atoi(argv[i+1]);
+ if(num>0)
+ arg_return->frequency=num;
+ else{
+ fprintf(stderr,"Argument Usage: -freq N(number>0)\n");
+ return 1;
+ }
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -freq N(number>0)\n");
+ return 1;
+ }
+ i++;
+ }
+ else if(!strcmp(argv[i],"-channels")){
+ if(i+1<argc){
+ int num=atoi(argv[i+1]);
+ if(num>0)
+ arg_return->channels=num;
+ else{
+ fprintf(stderr,"Argument Usage: -channels N(number>0)\n");
+ return 1;
+ }
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -channels N(number>0)\n");
+ return 1;
+ }
+ i++;
+ }
+ else if(!strcmp(argv[i],"-s_quality")){
+ if(i+1<argc){
+ int num=atoi(argv[i+1]);
+ if((num>=-1)&&(num<=10))
+ arg_return->s_quality=num;
+ else{
+ fprintf(stderr,"Argument Usage: -s_quality n(number -1 to 10)\n");
+ return 1;
+ }
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -s_quality n(number -1 to 10)\n");
+ return 1;
+ }
+ i++;
+ }
+ else if(!strcmp(argv[i],"-scale-shot")){
+ if(i+1<argc){
+ int num=atoi(argv[i+1]);
+ if((num==1)||(num==2)||(num==4)||(num==8)
+ ||(num==16)||(num==32)||(num==64)){
+ arg_return->scale_shot=num;
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -scale-shot N(0<number<64,power of 2)\n");
+ return 1;
+ }
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -scale-shot N(0<number<64,power of 2)\n");
+ return 1;
+ }
+ i++;
+ }
+ else if(!strcmp(argv[i],"-device")){
+ if(i+1<argc){
+ realloc(arg_return->device,strlen(argv[i+1])+1);
+ strcpy(arg_return->device,argv[i+1]);
+ }
+ else{
+ fprintf(stderr,"Argument Usage: -device SOUND_DEVICE\n");
+ return 1;
+ }
+ i++;
+ }
+ else if(!strcmp(argv[i],"--nosound"))
+ arg_return->nosound=1;
+ else if(!strcmp(argv[i],"--with-shared"))
+ arg_return->noshared=0;
+ else if(!strcmp(argv[i],"--full-shots"))
+ arg_return->full_shots=1;
+ else if(!strcmp(argv[i],"--scshot"))
+ arg_return->scshot=1;
+ else if(!strcmp(argv[i],"--help")||!strcmp(argv[i],"-h")){
+ fprintf(stderr,"%s",usage);
+ return 1;
+ }
+ else if(!strcmp(argv[i],"--version")){
+ fprintf(stderr,"recordMyDesktop v%s\n\n",VERSION);
+ return 1;
+ }
+ else{
+ fprintf(stderr,"\n\tError parsing arguments.\n\tType --help or -h for usage.\n\n");
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/recordmydesktop/src/poll_damage.c b/recordmydesktop/src/poll_damage.c
new file mode 100644
index 0000000..9daef6b
--- /dev/null
+++ b/recordmydesktop/src/poll_damage.c
@@ -0,0 +1,57 @@
+/*********************************************************************************
+* recordMyDesktop *
+**********************************************************************************
+* *
+* Copyright (C) 2006 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+* *
+* *
+* *
+* For further information contact me at biocrasher@gmail.com *
+**********************************************************************************/
+
+
+#include <recordmydesktop.h>
+
+void *PollDamage(void *pdata){
+
+ Damage damage;
+ XEvent event;
+ int inserts=0;
+
+
+ damage= XDamageCreate( ((ProgData *)pdata)->dpy, ((ProgData *)pdata)->brwin.windowid, XDamageReportRawRectangles);
+ while(((ProgData *)pdata)->running){
+// if(Paused)pthread_cond_wait(&((ProgData *)pdata)->pause_cond,&((ProgData *)pdata)->pause_cond_mutex);
+ //damage polling doesn't stop,eventually full image may be needed
+ XNextEvent(((ProgData *)pdata)->dpy,&event);
+ if(event.type == ((ProgData *)pdata)->damage_event + XDamageNotify ){
+ XDamageNotifyEvent *e =(XDamageNotifyEvent *)( &event );
+ WGeometry wgeom;
+ CLIP_EVENT_AREA(e,&(((ProgData *)pdata)->brwin),&wgeom);
+ if((wgeom.x>=0)&&(wgeom.y>=0)&&(wgeom.width>0)&&(wgeom.height>0))
+ {
+ int tlist_sel=((ProgData *)pdata)->list_selector;
+ pthread_mutex_lock(&((ProgData *)pdata)->list_mutex[tlist_sel]);
+ inserts+=RectInsert(&((ProgData *)pdata)->rect_root[tlist_sel],&wgeom);
+ pthread_mutex_unlock(&((ProgData *)pdata)->list_mutex[tlist_sel]);
+ }
+ }
+ }
+ pthread_exit(&errno);
+}
+
diff --git a/recordmydesktop/src/queryextensions.c b/recordmydesktop/src/queryextensions.c
new file mode 100644
index 0000000..1107fab
--- /dev/null
+++ b/recordmydesktop/src/queryextensions.c
@@ -0,0 +1,40 @@
+/*********************************************************************************
+* recordMyDesktop *
+**********************************************************************************
+* *
+* Copyright (C) 2006 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+* *
+* *
+* *
+* For further information contact me at biocrasher@gmail.com *
+**********************************************************************************/
+
+
+#include <recordmydesktop.h>
+
+int QueryExtensions(Display *dpy,ProgArgs *args,int *damage_event,int *damage_error){
+ if(!XDamageQueryExtension( dpy, damage_event, damage_error)){
+ fprintf(stderr,"XDamage extension not found!!!\n");
+ return 1;
+ }
+ if((!args->noshared)&&(XShmQueryExtension(dpy)==False)){
+ args->noshared=1;
+ fprintf(stderr,"Shared Memory extension not present!\nContinuing without it.\n");
+ }
+ return 0;
+}
diff --git a/recordmydesktop/src/recordmydesktop.c b/recordmydesktop/src/recordmydesktop.c
new file mode 100644
index 0000000..f0f1a3d
--- /dev/null
+++ b/recordmydesktop/src/recordmydesktop.c
@@ -0,0 +1,215 @@
+/*********************************************************************************
+* recordMyDesktop *
+**********************************************************************************
+* *
+* Copyright (C) 2006 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+* *
+* *
+* *
+* For further information contact me at biocrasher@gmail.com *
+**********************************************************************************/
+
+
+#include <recordmydesktop.h>
+
+
+int main(int argc,char **argv){
+ ProgData pdata;
+
+ if(XInitThreads ()==0){
+ fprintf(stderr,"Couldn't initialize thread support!\n");
+ exit(1);
+ }
+ DEFAULT_ARGS(&pdata.args);
+ if(ParseArgs(argc,argv,&pdata.args)){
+ exit(1);
+ }
+ pdata.dpy = XOpenDisplay(pdata.args.display);
+
+ if (pdata.dpy == NULL) {
+ fprintf(stderr, "Cannot connect to X server %s\n",pdata.args.display);
+ exit(1);
+ }
+ else{
+ EncData enc_data;
+ pthread_t poll_damage_t,
+ image_capture_t,
+ image_encode_t,
+ sound_capture_t,
+ sound_encode_t,
+ flush_to_ogg_t;
+ XShmSegmentInfo shminfo;
+
+ QUERY_DISPLAY_SPECS(pdata.dpy,&pdata.specs);
+ if(pdata.specs.depth!=24){
+ fprintf(stderr,"Only 24bpp color depth mode is currently supported.\n");
+ exit(1);
+ }
+ if(SetBRWindow(pdata.dpy,&pdata.brwin,&pdata.specs,&pdata.args))
+ exit(1);
+ if(QueryExtensions(pdata.dpy,&pdata.args,&pdata.damage_event, &pdata.damage_error))
+ exit(1);
+
+ //init data
+
+ if(!pdata.args.scshot){
+ fprintf(stderr,"Initializing...\n");
+
+ if(pdata.args.have_dummy_cursor){
+ pdata.dummy_pointer=MakeDummyPointer(&pdata.specs,16,pdata.args.cursor_color,0,&pdata.npxl);
+ pdata.dummy_p_size=16;
+ }
+ }
+ if((pdata.args.noshared)||(pdata.args.scshot))
+ pdata.datamain=(char *)malloc(pdata.brwin.nbytes);
+ if(!pdata.args.scshot){
+ if(pdata.args.noshared)
+ pdata.datatemp=(char *)malloc(pdata.brwin.nbytes);
+ pdata.rect_root[0]=pdata.rect_root[1]=NULL;
+ pthread_mutex_init(&pdata.list_mutex[0],NULL);
+ pthread_mutex_init(&pdata.list_mutex[1],NULL);
+ pthread_mutex_init(&pdata.sound_buffer_mutex,NULL);
+ pthread_mutex_init(&pdata.yuv_mutex,NULL);
+
+ pthread_cond_init(&pdata.time_cond,NULL);
+ pthread_cond_init(&pdata.pause_cond,NULL);
+ pthread_cond_init(&pdata.image_buffer_ready,NULL);
+ pthread_cond_init(&pdata.sound_buffer_ready,NULL);
+ pthread_cond_init(&pdata.sound_data_read,NULL);
+ pdata.list_selector=Paused=Aborted=avd=0;
+ pdata.running=1;
+ time_cond=&pdata.time_cond;
+ pause_cond=&pdata.pause_cond;
+ Running=&pdata.running;
+ }
+ if((pdata.args.noshared)||(pdata.args.scshot)){
+ pdata.image=XCreateImage(pdata.dpy, pdata.specs.visual, pdata.specs.depth, ZPixmap, 0,pdata.datamain,pdata.brwin.rgeom.width,
+ pdata.brwin.rgeom.height, 8, 0);
+ XInitImage(pdata.image);
+ GetZPixmap(pdata.dpy,pdata.specs.root,pdata.image->data,pdata.brwin.rgeom.x,pdata.brwin.rgeom.y,
+ pdata.brwin.rgeom.width,pdata.brwin.rgeom.height);
+ }
+ else{
+ pdata.image=XShmCreateImage (pdata.dpy,pdata.specs.visual,pdata.specs.depth,ZPixmap,pdata.datamain,
+ &shminfo, pdata.brwin.rgeom.width,pdata.brwin.rgeom.height);
+ shminfo.shmid = shmget (IPC_PRIVATE,
+ pdata.image->bytes_per_line * pdata.image->height,
+ IPC_CREAT|0777);
+ shminfo.shmaddr = pdata.image->data = shmat (shminfo.shmid, 0, 0);
+ shminfo.readOnly = False;
+ if(!XShmAttach(pdata.dpy,&shminfo)){
+ fprintf(stderr,"Failed to attach shared memory to proccess.\n");
+ exit(1);
+ }
+ XShmGetImage(pdata.dpy,pdata.specs.root,pdata.image,0,0,AllPlanes);
+
+ }
+ if(pdata.args.scshot){
+ if(pdata.args.delay>0){
+ fprintf(stderr,"Will sleep for %d seconds now.\n",pdata.args.delay);
+ sleep(pdata.args.delay);
+ }
+ //get a new screenshot
+ GetZPixmap(pdata.dpy,pdata.specs.root,pdata.image->data,pdata.brwin.rgeom.x,pdata.brwin.rgeom.y,
+ pdata.brwin.rgeom.width,pdata.brwin.rgeom.height);
+ ZPixmapToBMP(pdata.image,&pdata.brwin,((!strcmp(pdata.args.filename,"out.ogg"))?"rmdout.bmp":pdata.args.filename),pdata.brwin.nbytes,pdata.args.scale_shot);
+ fprintf(stderr,"done!\n");
+ exit(0);
+ }
+ if(!pdata.args.nosound)
+ pdata.sound_handle=OpenDev(pdata.args.device,pdata.args.channels,&pdata.args.frequency,&pdata.periodsize, &pdata.periodtime,&pdata.hard_pause);
+ if(pdata.sound_handle==NULL){
+ fprintf(stderr,"Error while opening/configuring soundcard %s\nProcceeding with no sound\n",pdata.args.device);
+ pdata.args.nosound=1;
+ }
+ InitEncoder(&pdata,&enc_data);
+ XImageToYUV(pdata.image,&pdata.enc_data->yuv);
+
+ pdata.frametime=(1000000)/pdata.args.fps;
+
+ if(pdata.args.delay>0){
+ fprintf(stderr,"Will sleep for %d seconds now.\n",pdata.args.delay);
+ sleep(pdata.args.delay);
+ }
+
+ /*start threads*/
+ if(!pdata.args.full_shots)
+ pthread_create(&poll_damage_t,NULL,PollDamage,(void *)&pdata);
+ pthread_create(&image_capture_t,NULL,GetFrame,(void *)&pdata);
+ pthread_create(&image_encode_t,NULL,EncodeImageBuffer,(void *)&pdata);
+ if(!pdata.args.nosound){
+ pthread_create(&sound_capture_t,NULL,CaptureSound,(void *)&pdata);
+ pthread_create(&sound_encode_t,NULL,EncodeSoundBuffer,(void *)&pdata);
+ }
+ pthread_create(&flush_to_ogg_t,NULL,FlushToOgg,(void *)&pdata);
+
+
+ RegisterCallbacks(&pdata.args);
+ fprintf(stderr,"Capturing!\n");
+
+ //wait all threads to finish
+
+ pthread_join(image_capture_t,NULL);
+ fprintf(stderr,"Shutting down.");
+ pthread_join(image_encode_t,NULL);
+ fprintf(stderr,".");
+ if(!pdata.args.nosound){
+ pthread_join(sound_capture_t,NULL);
+ fprintf(stderr,".");
+ pthread_join(sound_encode_t,NULL);
+ fprintf(stderr,".");
+ }
+ else
+ fprintf(stderr,"..");
+ pthread_join(flush_to_ogg_t,NULL);
+ fprintf(stderr,".");
+ if(!pdata.args.full_shots)
+ pthread_join(poll_damage_t,NULL);
+ fprintf(stderr,".");
+ fprintf(stderr,"\n");
+ XCloseDisplay(pdata.dpy);
+ if(Aborted){
+ if(remove(pdata.args.filename)){
+ perror("Error while removing file:\n");
+ return 1;
+ }
+ else{
+ fprintf(stderr,"SIGABRT received,file %s removed\n",pdata.args.filename);
+ return 0;
+ }
+ }
+ else
+ fprintf(stderr,"Goodbye!\n");
+ }
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/recordmydesktop/src/rectinsert.c b/recordmydesktop/src/rectinsert.c
new file mode 100644
index 0000000..4caf1b8
--- /dev/null
+++ b/recordmydesktop/src/rectinsert.c
@@ -0,0 +1,469 @@
+/*********************************************************************************
+* recordMyDesktop *
+**********************************************************************************
+* *
+* Copyright (C) 2006 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+* *
+* *
+* *
+* For further information contact me at biocrasher@gmail.com *
+**********************************************************************************/
+
+
+#include <recordmydesktop.h>
+//return 1 and null if geom1 in geom2 ,2 and null if geom2 in geom1,0 if they don't collide
+//-1 and two geoms if they collide and geom1 is broken.//-2 and one or two geoms if they collide and geom2 is broken.
+//-10 if group and replace is possible
+int CollideRects(WGeometry *wgeom1,WGeometry *wgeom2,WGeometry **wgeom_return,int *ngeoms){
+ //1 fits in 2
+ if((wgeom1->x>=wgeom2->x)&&
+ (wgeom1->x+wgeom1->width<=wgeom2->x+wgeom2->width)&&
+ (wgeom1->y>=wgeom2->y)&&
+ (wgeom1->y+wgeom1->height<=wgeom2->y+wgeom2->height)){
+ *ngeoms=0;
+ return 1;
+ }
+ //2 fits in 1
+ else if((wgeom2->x>=wgeom1->x)&&
+ (wgeom2->x+wgeom2->width<=wgeom1->x+wgeom1->width)&&
+ (wgeom2->y>=wgeom1->y)&&
+ (wgeom2->y+wgeom2->height<=wgeom1->y+wgeom1->height)){
+ *ngeoms=0;
+ return 2;
+ }
+ //no collision
+ else if((wgeom1->x+wgeom1->width<wgeom2->x)||
+ (wgeom2->x+wgeom2->width<wgeom1->x)||
+ (wgeom1->y+wgeom1->height<wgeom2->y)||
+ (wgeom2->y+wgeom2->height<wgeom1->y)){
+ *ngeoms=0;
+ return 0;
+ }
+ else{
+//overlapping points are considered enclosed
+//this happens because libxdamage may generate many events for one change
+//and some of them may be in the the exact same region
+//so identical rects would be considered not colliding
+//in order though to avoid endless recursion on the RectInsert
+//function should always start at the next element(which is logical since
+//if any rect makes it to a points none of it's part collides with previous
+//nodes on the list, too)
+ int x1[2]={wgeom1->x,wgeom1->x+wgeom1->width};
+ int y1[2]={wgeom1->y,wgeom1->y+wgeom1->height};
+ int x2[2]={wgeom2->x,wgeom2->x+wgeom2->width};
+ int y2[2]={wgeom2->y,wgeom2->y+wgeom2->height};
+ int enclosed[2][4],tot1,tot2;
+ enclosed[0][0]=(((x1[0]>=x2[0])&&(x1[0]<=x2[1])&&
+ (y1[0]>=y2[0])&&(y1[0]<=y2[1]))?1:0);
+ enclosed[0][1]=(((x1[1]>=x2[0])&&(x1[1]<=x2[1])&&
+ (y1[0]>=y2[0])&&(y1[0]<=y2[1]))?1:0);
+ enclosed[0][2]=(((x1[0]>=x2[0])&&(x1[0]<=x2[1])&&
+ (y1[1]>=y2[0])&&(y1[1]<=y2[1]))?1:0);
+ enclosed[0][3]=(((x1[1]>=x2[0])&&(x1[1]<=x2[1])&&
+ (y1[1]>=y2[0])&&(y1[1]<=y2[1]))?1:0);
+ enclosed[1][0]=(((x2[0]>=x1[0])&&(x2[0]<=x1[1])&&
+ (y2[0]>=y1[0])&&(y2[0]<=y1[1]))?1:0);
+ enclosed[1][1]=(((x2[1]>=x1[0])&&(x2[1]<=x1[1])&&
+ (y2[0]>=y1[0])&&(y2[0]<=y1[1]))?1:0);
+ enclosed[1][2]=(((x2[0]>=x1[0])&&(x2[0]<=x1[1])&&
+ (y2[1]>=y1[0])&&(y2[1]<=y1[1]))?1:0);
+ enclosed[1][3]=(((x2[1]>=x1[0])&&(x2[1]<=x1[1])&&
+ (y2[1]>=y1[0])&&(y2[1]<=y1[1]))?1:0);
+ tot1=enclosed[0][0]+enclosed[0][1]+enclosed[0][2]+enclosed[0][3];
+ tot2=enclosed[1][0]+enclosed[1][1]+enclosed[1][2]+enclosed[1][3];
+ if((tot1==2)&&(tot2==2)){//same width or height, which is the best case
+ //group
+ if((enclosed[1][0]&&enclosed[1][1])&&(wgeom1->width==wgeom2->width)){
+ wgeom_return[0]=(WGeometry *)malloc(sizeof(WGeometry));
+ *ngeoms=1;
+ wgeom_return[0]->x=wgeom1->x;
+ wgeom_return[0]->y=wgeom1->y;
+ wgeom_return[0]->width=wgeom1->width;
+ wgeom_return[0]->height=wgeom2->height+wgeom2->y-wgeom1->y;
+ return -10;
+ }
+ else if((enclosed[1][0]&&enclosed[1][2])&&(wgeom1->height==wgeom2->height)){
+// wgeom_return[0]=(WGeometry *)malloc(sizeof(WGeometry));
+ *ngeoms=1;
+ wgeom_return[0]->x=wgeom1->x;
+ wgeom_return[0]->y=wgeom1->y;
+ wgeom_return[0]->width=wgeom2->width+wgeom2->x-wgeom1->x;
+ wgeom_return[0]->height=wgeom1->height;
+ return -10;
+ }
+ else if((enclosed[1][3]&&enclosed[1][1])&&(wgeom1->height==wgeom2->height)){
+// wgeom_return[0]=(WGeometry *)malloc(sizeof(WGeometry));
+ *ngeoms=1;
+ wgeom_return[0]->x=wgeom2->x;
+ wgeom_return[0]->y=wgeom2->y;
+ wgeom_return[0]->width=wgeom1->width+wgeom1->x-wgeom2->x;
+ wgeom_return[0]->height=wgeom2->height;
+ return -10;
+ }
+ else if((enclosed[1][3]&&enclosed[1][2])&&(wgeom1->width==wgeom2->width)){
+// wgeom_return[0]=(WGeometry *)malloc(sizeof(WGeometry));
+ *ngeoms=1;
+ wgeom_return[0]->x=wgeom2->x;
+ wgeom_return[0]->y=wgeom2->y;
+ wgeom_return[0]->width=wgeom2->width;
+ wgeom_return[0]->height=wgeom1->height+wgeom1->y-wgeom2->y;
+ return -10;
+ }
+ //if control reaches here therewasn't a group and we go on
+ }
+ if(tot2==2){
+ //break geom2
+// wgeom_return[0]=(WGeometry *)malloc(sizeof(WGeometry));
+ wgeom_return[0]->x=wgeom2->x;
+ wgeom_return[0]->y=wgeom2->y;
+ wgeom_return[0]->width=wgeom2->width;
+ wgeom_return[0]->height=wgeom2->height;
+ *ngeoms=1;
+ if(enclosed[1][0]&&enclosed[1][1]){
+ wgeom_return[0]->y=y1[1];
+ wgeom_return[0]->height-=y1[1]-y2[0];
+ }
+ else if(enclosed[1][0]&&enclosed[1][2]){
+ wgeom_return[0]->x=x1[1];
+ wgeom_return[0]->width-=x1[1]-x2[0];
+ }
+ else if(enclosed[1][3]&&enclosed[1][1])
+ wgeom_return[0]->width-=x2[1]-x1[0];
+ else if(enclosed[1][3]&&enclosed[1][2])
+ wgeom_return[0]->height-=y2[1]-y1[0];
+ return -2;
+ }
+ else if(tot1==2){
+ //if the first one breaks(which is already inserted)
+ //then we reenter the part that was left and the one
+ //that was to be inserted
+ wgeom_return[1]=wgeom2;
+// wgeom_return[0]=(WGeometry *)malloc(sizeof(WGeometry));
+ wgeom_return[0]->x=wgeom1->x;
+ wgeom_return[0]->y=wgeom1->y;
+ wgeom_return[0]->width=wgeom1->width;
+ wgeom_return[0]->height=wgeom1->height;
+ *ngeoms=1;
+ if(enclosed[0][0]&&enclosed[0][1]){
+ wgeom_return[0]->y=y2[1];
+ wgeom_return[0]->height-=y2[1]-y1[0];
+ }
+ else if(enclosed[0][0]&&enclosed[0][2]){
+ wgeom_return[0]->x=x2[1];
+ wgeom_return[0]->width-=x2[1]-x1[0];
+ }
+ else if(enclosed[0][3]&&enclosed[0][1])
+ wgeom_return[0]->width-=x1[1]-x2[0];
+ else if(enclosed[0][3]&&enclosed[0][2])
+ wgeom_return[0]->height-=y1[1]-y2[0];
+ return -1;
+
+ }
+ else if(tot2==1){//in which case there is also tot1==1 but we rather not break that
+ //break geom2 in two
+// wgeom_return[0]=(WGeometry *)malloc(sizeof(WGeometry));
+// wgeom_return[1]=(WGeometry *)malloc(sizeof(WGeometry));
+ *ngeoms=2;
+ if(enclosed[1][0]){
+//first
+ wgeom_return[0]->x=x1[1];
+ wgeom_return[0]->y=y2[0];
+ wgeom_return[0]->width=wgeom2->width-x1[1]+x2[0];
+ wgeom_return[0]->height=wgeom2->height;
+//second
+ wgeom_return[1]->x=x2[0];
+ wgeom_return[1]->y=y1[1];
+ wgeom_return[1]->width=x1[1]-x2[0];
+ wgeom_return[1]->height=wgeom2->height-y1[1]+y2[0];
+ }
+ else if(enclosed[1][1]){
+//first
+ wgeom_return[0]->x=x2[0];
+ wgeom_return[0]->y=y2[0];
+ wgeom_return[0]->width=wgeom2->width-x2[1]+x1[0];
+ wgeom_return[0]->height=wgeom2->height;
+//second
+ wgeom_return[1]->x=x1[0];
+ wgeom_return[1]->y=y1[1];
+ wgeom_return[1]->width=x2[1]-x1[0];
+ wgeom_return[1]->height=wgeom2->height-y1[1]+y2[0];
+ }
+ else if(enclosed[1][2]){
+//first(same as [1][0])
+ wgeom_return[0]->x=x1[1];
+ wgeom_return[0]->y=y2[0];
+ wgeom_return[0]->width=wgeom2->width-x1[1]+x2[0];
+ wgeom_return[0]->height=wgeom2->height;
+//second
+ wgeom_return[1]->x=x2[0];
+ wgeom_return[1]->y=y2[0];
+ wgeom_return[1]->width=x1[1]-x2[0];
+ wgeom_return[1]->height=wgeom2->height-y2[1]+y1[0];
+ }
+ else if(enclosed[1][3]){
+//first(same as [1][1])
+ wgeom_return[0]->x=x2[0];
+ wgeom_return[0]->y=y2[0];
+ wgeom_return[0]->width=wgeom2->width-x2[1]+x1[0];
+ wgeom_return[0]->height=wgeom2->height;
+//second
+ wgeom_return[1]->x=x1[0];
+ wgeom_return[1]->y=y2[0];
+ wgeom_return[1]->width=x2[1]-x1[0];
+ wgeom_return[1]->height=wgeom2->height-y2[1]+y1[0];
+ }
+ return -2;
+ }
+ else{//polygons collide but no point of one is in the other
+ //so we just keep the two parts of geom2 that are outside geom1
+
+ //break geom2 in two
+ //two cases:
+ //geom2 crossing vertically geom1
+ //and geom2 crossing horizontally geom1
+ //The proper one can be found by simply checking x,y positions
+// wgeom_return[0]=(WGeometry *)malloc(sizeof(WGeometry));
+// wgeom_return[1]=(WGeometry *)malloc(sizeof(WGeometry));
+ *ngeoms=2;
+ if(wgeom2->y<wgeom1->y){
+ //common
+ wgeom_return[0]->x=wgeom_return[1]->x=x2[0];
+ wgeom_return[0]->width=wgeom_return[1]->width=wgeom2->width;
+
+ wgeom_return[0]->y=y2[0];
+ wgeom_return[0]->height=wgeom2->height-y2[1]+y1[0];
+ wgeom_return[1]->y=y1[1];
+ wgeom_return[1]->height=y2[1]-y1[1];
+ }
+ else{
+ //common
+ wgeom_return[0]->y=wgeom_return[1]->y=y2[0];
+ wgeom_return[0]->height=wgeom_return[1]->height=wgeom2->height;
+
+ wgeom_return[0]->x=x2[0];
+ wgeom_return[0]->width=wgeom2->width-x2[1]+x1[0];
+ wgeom_return[1]->x=x1[1];
+ wgeom_return[1]->width=x2[1]-x1[1];
+ }
+ return -2;
+ }
+ }
+}
+
+int RectInsert(RectArea **root,WGeometry *wgeom){
+
+ int total_insertions=0;
+ RectArea *temp,*newnode=(RectArea *)malloc(sizeof(RectArea));
+ newnode->geom.x=wgeom->x;
+ newnode->geom.y=wgeom->y;
+ newnode->geom.width=wgeom->width;
+ newnode->geom.height=wgeom->height;
+ newnode->prev=newnode->next=NULL;
+ if(*root==NULL){
+ *root=newnode;
+ total_insertions=1;
+ }
+ else{
+ WGeometry *wgeom_return[2];
+ wgeom_return[0]=(WGeometry *)malloc(sizeof(WGeometry));
+ wgeom_return[1]=(WGeometry *)malloc(sizeof(WGeometry));
+
+ int ngeoms=0,insert_ok=1,i=0;
+ temp=*root;
+ while(insert_ok){//if something is broken list does not procceed(except on -1 collres case)
+ int collres/*=0;//*/=CollideRects(&(temp->geom),wgeom,wgeom_return,&ngeoms);
+ if((!collres))
+ insert_ok=1;
+ else{
+ insert_ok=0;
+ switch(collres){
+ case 1://remove current node,reinsert new one
+ total_insertions--;
+ if(temp->prev!=NULL){//no root
+ if(temp->next!=NULL){//
+ temp->prev->next=temp->next;
+ temp->next->prev=temp->prev;
+ temp=temp->next;
+ if((wgeom->width>0)&&(wgeom->height>0))
+ total_insertions+=RectInsert(&temp,wgeom);
+ }
+ else{
+ temp->prev->next=newnode;
+ newnode->prev=temp->prev;
+ total_insertions++;
+ free(temp);
+ }
+ }
+ else{//root
+ if((*root)->next!=NULL){
+ (*root)=(*root)->next;
+ (*root)->prev=NULL;
+ if((wgeom->width>0)&&(wgeom->height>0))
+ total_insertions+=RectInsert(root,wgeom);
+ }
+ else if((wgeom->width>0)&&(wgeom->height>0)){
+ *root=newnode;
+ total_insertions++;
+ }
+ else{
+ *root=NULL;
+ total_insertions++;
+ }
+ free(temp);
+ }
+ break;
+ case 2://done,area is already covered
+ break;
+ case -1://current node is broken and reinserted(in same pos)
+ //newnode is also reinserted
+ if((wgeom_return[0]->width>0)&&(wgeom_return[0]->height>0)){
+ temp->geom.x=wgeom_return[0]->x;
+ temp->geom.y=wgeom_return[0]->y;
+ temp->geom.width=wgeom_return[0]->width;
+ temp->geom.height=wgeom_return[0]->height;
+ if(temp->next==NULL){
+ temp->next=newnode;
+ newnode->prev=temp;
+ total_insertions++;
+ }
+ else{
+ insert_ok=1;
+ }
+ }
+ else{//it might happen that the old and now broken node
+ //is of zero width or height(so it isn't reinserted)
+ /*TODO this may cause lines to be left not updated
+ so maybe it is needed to increase the size by one
+ pixel(zero width or height cause BadValue*/
+ if((temp->prev==NULL)&&(temp->next!=NULL)){
+ *root=(*root)->next;
+ (*root)->prev=NULL;
+ }
+ else if((temp->next==NULL)&&(temp->prev!=NULL)){
+ temp->prev->next=newnode;
+ newnode->prev=temp->prev;
+ }
+ else if((temp->next==NULL)&&(temp->prev==NULL))
+ (*root)=newnode;
+ else{
+ total_insertions--;
+ temp->next->prev=temp->prev;
+ temp->prev->next=temp->next;
+ total_insertions+=RectInsert(&temp->next,wgeom);
+ }
+ }
+ break;
+ case -2://new is broken and reinserted
+ if(temp->next==NULL){
+ total_insertions+=ngeoms;
+ newnode->geom.x=wgeom_return[0]->x;
+ newnode->geom.y=wgeom_return[0]->y;
+ newnode->geom.width=wgeom_return[0]->width;
+ newnode->geom.height=wgeom_return[0]->height;
+ temp->next=newnode;
+ newnode->prev=temp;
+ if(ngeoms>1){
+ RectArea *newnode1=(RectArea *)malloc(sizeof(RectArea));
+ newnode1->geom.x=wgeom_return[1]->x;
+ newnode1->geom.y=wgeom_return[1]->y;
+ newnode1->geom.width=wgeom_return[1]->width;
+ newnode1->geom.height=wgeom_return[1]->height;
+ newnode->next=newnode1;
+ newnode1->prev=newnode;
+ newnode1->next=NULL;
+ }
+ }
+ else{
+ for(i=0;i<ngeoms;i++){
+ if((wgeom_return[i]->width>0)&&(wgeom_return[i]->height>0))
+ total_insertions+=RectInsert(&temp->next,wgeom_return[i]);
+ }
+ }
+ break;
+ case -10://grouped
+ if(temp->prev==NULL){
+ if(temp->next==NULL){//empty list
+ newnode->geom.x=wgeom_return[0]->x;
+ newnode->geom.y=wgeom_return[0]->y;
+ newnode->geom.width=wgeom_return[0]->width;
+ newnode->geom.height=wgeom_return[0]->height;
+ *root=newnode;
+ }
+ else{
+ total_insertions--;
+ *root=temp->next;
+ (*root)->prev=NULL;
+ free(temp);
+ if((wgeom_return[0]->width>0)&&(wgeom_return[0]->height>0))
+ total_insertions+=RectInsert(root,wgeom_return[0]);
+ }
+ }
+ else if(temp->next==NULL){//last, enter anyway
+ newnode->geom.x=wgeom_return[0]->x;
+ newnode->geom.y=wgeom_return[0]->y;
+ newnode->geom.width=wgeom_return[0]->width;
+ newnode->geom.height=wgeom_return[0]->height;
+ temp->prev->next=newnode;
+ newnode->prev=temp->prev;
+ free(temp);
+ }
+ else{//remove node and reinsert, starting where we were
+ total_insertions--;
+ temp->prev->next=temp->next;
+ temp->next->prev=temp->prev;
+ temp=temp->next;
+ if((wgeom_return[0]->width>0)&&(wgeom_return[0]->height>0))
+ total_insertions+=RectInsert(&temp,wgeom_return[0]);
+ }
+ break;
+ }
+ }
+ if(insert_ok){
+ if(temp->next==NULL){
+ temp->next=newnode;
+ newnode->prev=temp;
+ total_insertions++;
+ break;
+ }
+ else{
+ temp=temp->next;
+ }
+ }
+ else{
+ break;
+ }
+ };
+ }
+ return total_insertions;
+}
+
+void ClearList(RectArea **root){
+
+ RectArea *temp;
+ temp=*root;
+ if(temp!=NULL){
+ while(temp->next!=NULL){
+ temp=temp->next;
+ free(temp->prev);
+
+ }
+ free(temp);
+ *root=NULL;
+ }
+}
+
diff --git a/recordmydesktop/src/register_callbacks.c b/recordmydesktop/src/register_callbacks.c
new file mode 100644
index 0000000..1bcffe8
--- /dev/null
+++ b/recordmydesktop/src/register_callbacks.c
@@ -0,0 +1,75 @@
+/*********************************************************************************
+* recordMyDesktop *
+**********************************************************************************
+* *
+* Copyright (C) 2006 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+* *
+* *
+* *
+* For further information contact me at biocrasher@gmail.com *
+**********************************************************************************/
+
+
+#include <recordmydesktop.h>
+void SetExpired(int signum){
+ pthread_cond_broadcast(time_cond);
+}
+
+void SetPaused(int signum){
+ if(!Paused)
+ Paused=1;
+ else{
+// pthread_cond_broadcast(pause_cond);//thsi should work, but it doesn't
+ int i;//this is a bug
+ Paused=0;//normally with the broadcast all the threads should restart, but sound capture thread
+ for(i=0;i<15;i++)//remains dead. If a bunch of signals, restarts all threads, why can't a broadcast do the same?
+ pthread_cond_signal(pause_cond);//if you have any idea please contact me.
+ //(misses the signal?)
+ }
+}
+
+
+void SetRunning(int signum){
+ *Running=0;
+ if(signum==SIGABRT)
+ Aborted=1;
+}
+
+void RegisterCallbacks(ProgArgs *args){
+
+ struct itimerval value;
+ struct sigaction time_act,pause_act,end_act;
+
+
+ value.it_interval.tv_sec=value.it_value.tv_sec=0;
+ value.it_interval.tv_usec=value.it_value.tv_usec=(1000000)/args->fps;
+ setitimer(ITIMER_REAL,&value,NULL);
+ time_act.sa_handler=SetExpired;
+ pause_act.sa_handler=SetPaused;
+ end_act.sa_handler=SetRunning;
+ sigfillset(&(time_act.sa_mask));
+ sigfillset(&(pause_act.sa_mask));
+ sigfillset(&(end_act.sa_mask));
+ time_act.sa_flags=pause_act.sa_flags=end_act.sa_flags=0;
+ sigaction(SIGALRM,&time_act,NULL);
+ sigaction(SIGUSR1,&pause_act,NULL);
+ sigaction(SIGINT,&end_act,NULL);
+ sigaction(SIGTERM,&end_act,NULL);
+ sigaction(SIGABRT,&end_act,NULL);
+}
+
diff --git a/recordmydesktop/src/setbrwindow.c b/recordmydesktop/src/setbrwindow.c
new file mode 100644
index 0000000..13e7de3
--- /dev/null
+++ b/recordmydesktop/src/setbrwindow.c
@@ -0,0 +1,90 @@
+/*********************************************************************************
+* recordMyDesktop *
+**********************************************************************************
+* *
+* Copyright (C) 2006 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+* *
+* *
+* *
+* For further information contact me at biocrasher@gmail.com *
+**********************************************************************************/
+
+
+#include <recordmydesktop.h>
+
+int SetBRWindow(Display *dpy,BRWindow *brwin,DisplaySpecs *specs,ProgArgs *args){
+ //before we start recording we have to make sure the ranges are valid
+ if(args->windowid==0){//root window
+ //first set it up
+ brwin->windowid=specs->root;
+ brwin->geom.x=brwin->geom.y=0;
+ brwin->geom.width=specs->width;
+ brwin->geom.height=specs->height;
+ brwin->rgeom.x=args->x;
+ brwin->rgeom.y=args->y;
+ brwin->rgeom.width=((args->width)?args->width:specs->width-brwin->rgeom.x);
+ brwin->rgeom.height=((args->height)?args->height:specs->height-brwin->rgeom.y);
+// brwin->nbytes=(brwin->rgeom.width*brwin->rgeom.height*4);
+ //and then check validity
+ if((brwin->rgeom.x+brwin->rgeom.width>specs->width)||
+ (brwin->rgeom.y+brwin->rgeom.height>specs->height)){
+ fprintf(stderr,"Window size specification out of bounds!(current resolution:%dx%d)\n",specs->width,specs->height);
+ return 1;
+ }
+ }
+ else{
+ Window wchid;
+ int transl_x,transl_y;
+
+ XWindowAttributes attribs;
+ XGetWindowAttributes(dpy,args->windowid,&attribs);
+ if((attribs.map_state==IsUnviewable)||(attribs.map_state==IsUnmapped)){
+ fprintf(stderr,"Window must be mapped and visible!\n");
+ return 1;
+ }
+ XTranslateCoordinates(dpy,specs->root,args->windowid,attribs.x,attribs.y,&transl_x,&transl_y,&wchid);
+ brwin->windowid=specs->root;
+ brwin->geom.x=attribs.x-transl_x;
+ brwin->geom.y=attribs.y-transl_y;
+ brwin->geom.width=attribs.width;
+ brwin->geom.height=attribs.height;
+ if((brwin->geom.x+brwin->geom.width>specs->width)||
+ (brwin->geom.y+brwin->geom.height>specs->height)){
+ fprintf(stderr,"Window must be on visible screen area!\n");
+ return 1;
+ }
+
+ brwin->rgeom.x=brwin->geom.x+args->x;
+ brwin->rgeom.y=brwin->geom.y+args->y;
+ brwin->rgeom.width=((args->width)?args->width:brwin->geom.width-args->x);
+ brwin->rgeom.height=((args->height)?args->height:brwin->geom.height-args->y);
+ if((args->x+brwin->rgeom.width>brwin->geom.width)||
+ (args->y+brwin->rgeom.height>brwin->geom.height)){
+ fprintf(stderr,"Specified Area is larger than window!\n");
+ return 1;
+ }
+ }
+ //this is needed for theora
+ //+-8 pixels
+ brwin->rgeom.width=((((brwin->rgeom.width+16-(brwin->rgeom.width)%16+brwin->rgeom.x)<=specs->width)&&((brwin->rgeom.width)%16>8))?brwin->rgeom.width+16-(brwin->rgeom.width)%16:brwin->rgeom.width-(brwin->rgeom.width)%16);
+ brwin->rgeom.height=((((brwin->rgeom.height+16-(brwin->rgeom.height)%16+brwin->rgeom.y)<=specs->height)&&((brwin->rgeom.height)%16>8))?brwin->rgeom.height+16-(brwin->rgeom.height)%16:brwin->rgeom.height-(brwin->rgeom.height)%16);
+
+ brwin->nbytes=(brwin->rgeom.width*brwin->rgeom.height*4);
+
+ return 0;
+}
diff --git a/recordmydesktop/src/update_image.c b/recordmydesktop/src/update_image.c
new file mode 100644
index 0000000..04cb16f
--- /dev/null
+++ b/recordmydesktop/src/update_image.c
@@ -0,0 +1,72 @@
+/*********************************************************************************
+* recordMyDesktop *
+**********************************************************************************
+* *
+* Copyright (C) 2006 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+* *
+* *
+* *
+* For further information contact me at biocrasher@gmail.com *
+**********************************************************************************/
+
+
+#include <recordmydesktop.h>
+
+void UpdateImage(Display * dpy,
+ yuv_buffer *yuv,
+ pthread_mutex_t *yuv_mutex,
+ DisplaySpecs *specs,
+ RectArea **root,
+ BRWindow *brwin,
+ char *datatemp,
+ int noshmem){
+ RectArea *temp;
+ unsigned char *dtap=(unsigned char*)datatemp;
+ temp=*root;
+
+ if(temp!=NULL){
+ do{
+ if(noshmem){
+ GetZPixmap( dpy,
+ specs->root,
+ datatemp,
+ temp->geom.x,
+ temp->geom.y,
+ temp->geom.width,
+ temp->geom.height);
+
+ pthread_mutex_lock(yuv_mutex);
+
+ UPDATE_YUV_BUFFER_IM(yuv,dtap,
+ (temp->geom.x-brwin->rgeom.x),(temp->geom.y-brwin->rgeom.y),
+ (temp->geom.width),(temp->geom.height));
+
+ pthread_mutex_unlock(yuv_mutex);
+ }
+ else{
+ UPDATE_YUV_BUFFER_SH(yuv,dtap,
+ (temp->geom.x-brwin->rgeom.x),(temp->geom.y-brwin->rgeom.y),
+ (temp->geom.width),(temp->geom.height));
+
+
+ }
+ temp=temp->next;
+ }while(temp!=NULL);
+ }
+}
+
diff --git a/recordmydesktop/src/zpixmaptobmp.c b/recordmydesktop/src/zpixmaptobmp.c
new file mode 100644
index 0000000..21068c8
--- /dev/null
+++ b/recordmydesktop/src/zpixmaptobmp.c
@@ -0,0 +1,78 @@
+/*********************************************************************************
+* recordMyDesktop *
+**********************************************************************************
+* *
+* Copyright (C) 2006 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+* *
+* *
+* *
+* For further information contact me at biocrasher@gmail.com *
+**********************************************************************************/
+
+
+#include <recordmydesktop.h>
+
+int ZPixmapToBMP(XImage *imgz,BRWindow *brwin,char *fname,int nbytes,int scale){
+ FILE *fpbmp;
+ int i,k;
+ int siz=52+nbytes/(pow(scale,2));
+ int offs=54+1024;
+ short int rsrvd=0;
+ int hsiz=40;
+ int width=brwin->rgeom.width/scale,height=brwin->rgeom.height/scale,nbts=nbytes/(pow(scale,2));
+ unsigned short int planes=1;
+ unsigned short int bpp=24;
+ unsigned int cmpr=0;
+ unsigned int ncols=0;
+ char *dtap=imgz->data;
+
+ /*Write header*/
+ fpbmp=fopen(fname,"wb");
+ fputc('B',fpbmp);
+ fputc('M',fpbmp);
+ fwrite(&siz,4,1,fpbmp);
+ fwrite(&rsrvd,2,1,fpbmp);
+ fwrite(&rsrvd,2,1,fpbmp);
+ fwrite(&offs,4,1,fpbmp);
+ fwrite(&hsiz,4,1,fpbmp);
+ fwrite(&(width),4,1,fpbmp);
+ fwrite(&(height),4,1,fpbmp);
+ fwrite(&planes,2,1,fpbmp);
+ fwrite(&bpp,2,1,fpbmp);
+ fwrite(&cmpr,4,1,fpbmp);
+ fwrite(&nbts,4,1,fpbmp);
+ fwrite(&(width),4,1,fpbmp);
+ fwrite(&(height),4,1,fpbmp);
+ fwrite(&(ncols),4,1,fpbmp);
+ fwrite(&(ncols),4,1,fpbmp);
+ for(i=0;i<1024;i++)
+ fputc(0,fpbmp);
+ /*Data*/
+ for(k=(nbytes/imgz->bytes_per_line)-1;k>=0;k-=scale){
+ for(i=0;i<imgz->bytes_per_line/4;i+=scale){
+ fwrite(&dtap[(i*4)+k*(imgz->bytes_per_line)],1,1,fpbmp);
+ fwrite(&dtap[(i*4)+k*(imgz->bytes_per_line)+1],1,1,fpbmp);
+ fwrite(&dtap[(i*4)+k*(imgz->bytes_per_line)+2],1,1,fpbmp);
+ }
+ }
+
+ fclose(fpbmp);
+ return 0;
+}
+
+
© All Rights Reserved