summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--recordmydesktop/ChangeLog40
-rw-r--r--recordmydesktop/README5
-rw-r--r--recordmydesktop/TODO5
-rw-r--r--recordmydesktop/configure.ac23
-rw-r--r--recordmydesktop/doc/recordmydesktop.196
-rw-r--r--recordmydesktop/include/recordmydesktop.h397
-rw-r--r--recordmydesktop/src/Makefile.am14
-rw-r--r--recordmydesktop/src/cache_audio.c (renamed from recordmydesktop/src/zpixmaptobmp.c)81
-rw-r--r--recordmydesktop/src/cache_frame.c193
-rw-r--r--recordmydesktop/src/encode_image_buffer.c20
-rw-r--r--recordmydesktop/src/encode_sound_buffer.c30
-rw-r--r--recordmydesktop/src/init_encoder.c70
-rw-r--r--recordmydesktop/src/load_cache.c187
-rw-r--r--recordmydesktop/src/parseargs.c64
-rw-r--r--recordmydesktop/src/poll_damage.c47
-rw-r--r--recordmydesktop/src/recordmydesktop.c211
-rw-r--r--recordmydesktop/src/register_callbacks.c10
-rw-r--r--recordmydesktop/src/rmd_cache.c102
-rw-r--r--recordmydesktop/src/wm_check.c68
19 files changed, 1353 insertions, 310 deletions
diff --git a/recordmydesktop/ChangeLog b/recordmydesktop/ChangeLog
index 3f5dc1e..bdd5f6f 100644
--- a/recordmydesktop/ChangeLog
+++ b/recordmydesktop/ChangeLog
@@ -1,14 +1,14 @@
/*VERSION 0.2.1*/
*Unupdated lines bug fixed.
*Fuzzy cursor at border bug fixed.
-*Incorrect display of windows that
+*Incorrect display of windows that
extended beyond recording height fixed.
-*Size adjustement that resulted in extra
+*Size adjustement that resulted in extra
or missing pixels at borders has been corrected.
New adjustment is 8 pixels max,split evenly if possible.
*The option to drop frames has been added.
*The option to do better subsampling has been added.
-*Default behavior now is to use shared memory when
+*Default behavior now is to use shared memory when
size of image gets over 75% of total (or a user set threshold).
*Many other minor bugfixes.
@@ -18,18 +18,18 @@ size of image gets over 75% of total (or a user set threshold).
*BGR to YUV convertion corrected.
/*VERSION 0.2.3*/
-*Problems on big-endian architectures, corrected
+*Problems on big-endian architectures, corrected
(thanks to Marcel Unbehaun for bringing up the problem
and providing the neccessary feedback to resolve it).
-*Failure to respect change in channels number, while
+*Failure to respect change in channels number, while
opening soundcard, which resulted in crashes, segfaults
and repeated error-messages has been fixed.
*other minor bugfixes
/*VERSION 0.2.4*/
-*Behavior on lack of $DISPLAY evironment
+*Behavior on lack of $DISPLAY evironment
variable has been corrected.
-*Size adjustment is now quantized at 16 pixels,
+*Size adjustment is now quantized at 16 pixels,
in order to avoid complete image distortion,
present at certain resolutions, when using shared memory
(conditional or not).
@@ -39,12 +39,12 @@ values of options.
/*VERSION 0.2.5*/
*Drawing of the correct cursor is now supported through
the Xfixes extension.
-*Change of behavior on lack of any Xserver extension and
+*Change of behavior on lack of any Xserver extension and
failure to open sound device. The program now exits and informs
instead of continuing with a different configuration.
*Exit status also indicates the nature of any error that occured.
*Documentation has been updated with exit status explanations.
-*Subsampling of the chroma planes is made by averaging, while
+*Subsampling of the chroma planes is made by averaging, while
pixel discarding is an option(used to be otherwise).
@@ -54,21 +54,27 @@ Now, instead of dropping sound buffers, image
capturing speeds up. That is, waiting for timer to
expire is disabled until sync is achieved.
When not recording sound, this does not apply.
-*Theora return values are now properly checked,
+*Theora return values are now properly checked,
to avoid inserting corrupt packages into the stream.
*Major memory leaks have been fixed. These were related
to the rectangle insertion algorithm and discarding of
used sound buffers,
-*Segmentation fault on seemingly random occasions has been
+*Segmentation fault on seemingly random occasions has been
found and is now fixed. Reason was lack of thread safety over
libogg calls.
-/*VERSION 0.2.7*/
-*Opening of the sound device no longer hangs, if it isn't available.
-Instead the program exits with the appropriate error code.
-The same applies when reopening after a pause.
-
-
+/*VERSION 0.3.0*/
+*Implemented cache functionality
+(Encoding by default happens right after the recording)
+*Corrected damage event handling.
+*Saving under the same file-name,no longer deletes the previous one,
+instead it saves under a number postfixed file.
+*Opening the sound device doesn't block anymore.
+*A few new options were added related to caching.
+*Program now checks if it is run uder a known 3d compositing window manager
+and set behavior accordingly, to reduce the need for extra options at launch.
+*Updated documentation.
+*Removed uneeded bitmap screenshot function.
diff --git a/recordmydesktop/README b/recordmydesktop/README
index 625990c..a64d5a5 100644
--- a/recordmydesktop/README
+++ b/recordmydesktop/README
@@ -1,3 +1,6 @@
-To see examples of usage and explanation of the options check the manpage in the doc directory.
+This is the experimental branch of recordMyDesktop. Changes that will
+take place here might render the program unusuable and/or unstable.
+Any stable changes that influence the program positively and bugfixes
+will be merged back into the main tree.
diff --git a/recordmydesktop/TODO b/recordmydesktop/TODO
index 139597f..62a2465 100644
--- a/recordmydesktop/TODO
+++ b/recordmydesktop/TODO
@@ -1,2 +1,3 @@
-
-
+1)write a TODO
+2)?
+3)Profit!
diff --git a/recordmydesktop/configure.ac b/recordmydesktop/configure.ac
index 4c6ae69..c8dae65 100644
--- a/recordmydesktop/configure.ac
+++ b/recordmydesktop/configure.ac
@@ -3,7 +3,7 @@
AC_PREREQ(2.59)
AC_INIT(src/recordmydesktop.c)
-AM_INIT_AUTOMAKE(recordmydesktop,0.2.7,)
+AM_INIT_AUTOMAKE(recordmydesktop,0.3.0,)
AC_CONFIG_SRCDIR([src/recordmydesktop.c])
AM_CONFIG_HEADER(config.h)
@@ -22,22 +22,27 @@ AC_HEADER_STDC
AC_PATH_X
AC_PATH_XTRA
-AC_CHECK_HEADER([png.h])
-AC_CHECK_HEADER([alsa/asoundlib.h])
-AC_CHECK_HEADERS([sys/time.h unistd.h vorbis/vorbisfile.h ])
+if test "x$x_libraries" != "x" && test "x$x_libraries" != xNONE ; then
+ echo "X libraries are found in $x_libraries"
+ LIBS="-L$x_libraries $LIBS";
+fi
-LDFLAGS="$LD_FLAGS -L$x_libraries $X_LIBS $X_EXTRA_LIBS $X_PRE_LIBS"
-
-#no-O3s-thx.patch ;)
-CFLAGS="${CFLAGS} -Wall -D_THREAD_SAFE -pthread"
+if test "x$x_includes" != "x" && test "x$x_includes" != xNONE ; then
+ echo "X includes are found in $x_includes"
+ CFLAGS="-I$x_includes $CFLAGS";
+fi
+AC_CHECK_HEADER([alsa/asoundlib.h])
+AC_CHECK_HEADERS([sys/time.h unistd.h vorbis/vorbisfile.h ])
# Checks for libraries.
AC_CHECK_LIB([m],[isnan],,)
AC_CHECK_LIB([z],[deflate],,)
+AC_CHECK_LIB([ICE],[IceOpenConnection],,AC_MSG_ERROR([Can't find libICE]),)
+AC_CHECK_LIB([SM],[SmcOpenConnection],,AC_MSG_ERROR([Can't find libSM]),)
AC_CHECK_LIB([X11],[XOpenDisplay],,AC_MSG_ERROR([Can't find libX11]),
-L$x_libraries $X_PRE_LIBS)
AC_CHECK_LIB([Xext],[XShmQueryVersion],,AC_MSG_ERROR([Can't find libXext]))
@@ -49,10 +54,10 @@ AC_CHECK_LIB([vorbisenc],[vorbis_encode_init],,AC_MSG_ERROR([Can't find libvorbi
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.
diff --git a/recordmydesktop/doc/recordmydesktop.1 b/recordmydesktop/doc/recordmydesktop.1
index e8cbb6a..6fa7da5 100644
--- a/recordmydesktop/doc/recordmydesktop.1
+++ b/recordmydesktop/doc/recordmydesktop.1
@@ -7,7 +7,7 @@ recordMyDesktop \- record desktop sessions to an Ogg\-Theora\-Vorbis file.
.SH SYNOPSIS
-.B recordmydesktop
+.B recordmydesktop
[
.B
Options
@@ -22,14 +22,14 @@ filename
.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
+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)
+or capture windows that do not generate events on change(windows with accelerated 3d context)
.br
-but this will notably increase the workload. In this case, enabling the
+but this will notably increase the workload. In this case, enabling the
.B
\-\-with\-shared
option is recommended
@@ -71,9 +71,15 @@ while a command like:
.br
.B
~$ recordmydesktop foo.ogg
-.br
+.br
will write output to foo.ogg
.br
+.br
+Since version 0.3, encoding will happen right after the recording finishes.
+.br
+While this behavior saves a lot of CPU, you can revert to the old one by entering the \-\-on\-the\-fly\-encoding switch.
+.br
+.br
To specify a region for recording you can type this:
.br
.B
@@ -87,6 +93,8 @@ If the area extends beyond your current resolution, you will be notified appropr
.br
Notice also, that if any option is entered you have to specify the output file with the \-o switch.
.br
+If you try to save under a filename that already exists, the name will be post-fixed with a number (incremented if that name exists already)
+.br
.br
.B
To normally end a recording you can press ctl-c.
@@ -97,15 +105,15 @@ SIGINT
to the program).
.br
.br
-For further manipulation of the end result look at the
+For further manipulation of the end result look at the
.B
OPTIONS
-and
+and
.B
NOTES
sections.
.br
-.br
+.br
.br
.SH EXIT STATUS
0 is success
@@ -129,7 +137,7 @@ The following error codes indicate the nature of the error:
.br
7 XInitThreads failed.
.br
-8 No $DISPLAY environment variable and none specified as argument.
+8 No $DISPLAY environment variable and none specified as argument.
.br
9 Cannot connect to Xserver.
.br
@@ -140,8 +148,8 @@ The following error codes indicate the nature of the error:
12 Cannot attach shared memory to proccess.
.br
13 Cannot open file for writting.
-.br
-.br
+.br
+.br
.SH OPTIONS
.PP
.B
@@ -149,7 +157,7 @@ Generic Options:
.br
.TP
.B
- \-h or \-\-help
+ \-h or \-\-help
Print help summary and exit.
.br
.TP
@@ -258,7 +266,7 @@ Sound Options:
.br
.TP
.B
- \-\-nosound
+ \-\-no\-sound
Do not record sound.
.br
.PP
@@ -268,6 +276,11 @@ Encoding Options:
.br
.TP
.B
+ \-\-on\-the\-fly\-encoding
+ Encode the audio-video data, while recording.
+.br
+.TP
+.B
\-v_quality n
A number from 0 to 63 for desired encoded video quality(default 63).
.br
@@ -293,18 +306,34 @@ 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).
+ \-\-no\-wm\-check
+ When a 3d compositing window manager is detected the program will function as if the
+ \-\-full\-shots and \-\-with\-shared options have been specified. This option disables that
+ behavior alltogether.
.br
.TP
.B
- \-\-scshot
- Take a bitmap screenshot(default rmdout.bmp) and exit.
+ \-\-zero\-compression
+ Image data are always cached uncompressed.
.br
.TP
.B
- \-scale\-shot N
- Factor by which screenshot is scaled down(1<=number<=64,power of 2).
+ \-workdir DIR
+ Location where a temporary directory will be created to hold project files(default $HOME).
+.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
+ \-\-overwrite
+ If there is already a file with the same name, delete it.
+ Default action is to add a number postfix to the new file.
+ For example when not specifying a name, if out.ogg exists,
+ the new file will be out.ogg.1 and if that exists too, out.ogg.2
+ and so on (no ad-infinitum though, more like ad-short-integer...)
.br
.TP
.B
@@ -320,19 +349,20 @@ If no other option is specified, filename can be given without the \-o switch.
.br
.SH USAGE
.TP
-.B recordmydesktop
+.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)|
+\-display DISPLAY| \-x X| \-y Y|\-width N| \-height N| \-fps N(number>0)| \-\-on\-the\-fly\-encoding|
.br
\-v_quality n| \-s_quality n| \-v_bitrate n| \-\-no\-framedrop| \-dummy\-cursor color|
.br
\-\-no\-cursor| \-freq N(number>0)| \-channels N(number>0)| \-device SOUND_DEVICE|
.br
-\-\-nosound| \-\-with\-shared| \-\-no\-cond\-shared| \-shared\-threshold n| \-\-full\-shots|
+\-\-no\-sound| \-\-with\-shared| \-\-no\-cond\-shared| \-shared\-threshold n| \-\-full\-shots|
+.br
+\-\-quick\-subsampling| \-workdir DIR| \-\-zero\-compression| \-\-no\-wm\-check| \-\-overwrite| \-o filename]^filename
.br
-\-\-quick\-subsampling| \-\-scshot| \-scale\-shot N| \-o filename]^filename
.br
.br
.br
@@ -349,7 +379,7 @@ Display environment variable, specifying X server to connect to.
.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
+An easy way to find out the id of a window, is by using the
.B
xwininfo
program.
@@ -357,14 +387,14 @@ program.
Running a command like :
.br
.B
-xwininfo |grep "Window id:"|sed \-e "s/xwininfo\\:\\ Window id:\\ // ;s/\\ \.*//"
+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/\\ \.*//" )
+~$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 (
@@ -372,7 +402,11 @@ More conviniently you can put all that in the command that launches recordMyDesk
-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.
+So
+.B
+if you are doing the encoding on the fly
+,it's better to start with default values and manipulate
+the end\-result with another program.
.br
An excellent converter is
.B
@@ -382,13 +416,17 @@ ffmpeg2theora
Changing the quality of a recordng with it,can be as simple as :
.br
.B
-ffmpeg2theora infile.ogg -v 3 -a 4 -o outfile.ogg
+ffmpeg2theora infile.ogg \-v 3 \-a 4 \-o outfile.ogg
.br
It can even perform resizing on the size of the recording, or change the overall duration.
.br
.br
.SH BUGS
-Too resource intensive.
+Does not record 3d windows, if \-\-full\-shots isn't specified.
+.br
+Saving 65536 files with the same name, will result in upredictable behavior,
+.br
+which might manifest as an endless loop, or a segmentation fault.
.br
.SH AUTHORS
John Varouhakis(johnvarouhakis@gmail.com)
diff --git a/recordmydesktop/include/recordmydesktop.h b/recordmydesktop/include/recordmydesktop.h
index 4533b87..4c3ad18 100644
--- a/recordmydesktop/include/recordmydesktop.h
+++ b/recordmydesktop/include/recordmydesktop.h
@@ -37,7 +37,7 @@
#include <string.h>
#include <errno.h>
#include <math.h>
-#include <unistd.h>
+#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <signal.h>
@@ -49,8 +49,10 @@
#include <sys/ipc.h>
#include <sys/shm.h>
#include <pthread.h>
+#include <zlib.h>
#include <X11/Xlib.h>
#include <X11/Xlibint.h>
+#include <X11/Xatom.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/Xdamage.h>
#include <X11/extensions/XShm.h>
@@ -67,18 +69,29 @@
#define __RBYTE 2
#define __GBYTE 1
#define __BBYTE 0
+
+#define __RVALUE(tmp_val) (((tmp_val)&0x00ff0000)>>16)
+#define __GVALUE(tmp_val) (((tmp_val)&0x0000ff00)>>8)
+#define __BVALUE(tmp_val) (((tmp_val)&0x000000ff))
+
#elif __BYTE_ORDER == __BIG_ENDIAN
+
#define __ABYTE 0
#define __RBYTE 1
#define __GBYTE 2
#define __BBYTE 3
+
+#define __RVALUE(tmp_val) (((tmp_val)&0x0000ff00)>>8)
+#define __GVALUE(tmp_val) (((tmp_val)&0x00ff0000)>>16)
+#define __BVALUE(tmp_val) (((tmp_val)&0xff000000)>>24)
+
#else
#error Only little-endian and big-endian systems are supported
#endif
//do not be confused
-//this is useless and obsolete.
+//this is useless and obsolete.
//There are no plans for other fotmats
enum {UNSPECIFIED,OGG_THEORA_VORBIS};
@@ -86,7 +99,7 @@ enum {UNSPECIFIED,OGG_THEORA_VORBIS};
/**Structs*/
typedef struct _DisplaySpecs{ //this struct holds some basic information
- int screen; //about the display,needed mostly for
+ int screen; //about the display,needed mostly for
uint width; //validity checks at startup
uint height;
Window root;
@@ -102,7 +115,7 @@ typedef struct _WGeometry{ //basic geometry of a window or area
int y;
int width;
int height;
-}WGeometry;
+}WGeometry;
typedef struct _RectArea{ //an area that has been damaged gets stored
WGeometry geom; //in a list comprised of structs of this type
@@ -129,7 +142,7 @@ typedef struct _ProgArgs{
int encoding; //encoding(default OGG_THEORA_VORBIS)
int cursor_color; //black or white=>1 or 0
int have_dummy_cursor;//disable/enable drawing of the dummy cursor
- int xfixes_cursor; //disable/enable drawing of a cursor obtained
+ int xfixes_cursor; //disable/enable drawing of a cursor obtained
//through the xfixes extension
float fps; //desired framerate(default 15)
unsigned int frequency; //desired frequency (default 22050)
@@ -137,23 +150,27 @@ typedef struct _ProgArgs{
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 1)
- int nocondshared; //de not use shared memory on large image aquititions
+ int nocondshared; //do not use shared memory on large image aquititions
+ int nowmcheck; //do not check if there's a 3d comp window manager
+ //(which changes full-shots and with-shared to 1)
int shared_thres; //threshold to use shared memory
int full_shots; //do not poll damage, take full screenshots
int no_quick_subsample;//average pixels in chroma planes
- 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
int dropframes; //option for theora encoder
+ int encOnTheFly; //encode while recording, no caching(default 0)
+ char *workdir; //directory to be used for cache files(default $HOME)
+ int zerocompression;//image data are always flushed uncompressed
+ int overwrite;//overwite a previously existing file(do not add a .number postfix)
}ProgArgs;
-//this struct holds anything related to encoding AND
-//writting out to file.
+//this struct holds anything related to encoding AND
+//writting out to file.
typedef struct _EncData{
ogg_stream_state m_ogg_ts;//theora
ogg_stream_state m_ogg_vs;//vorbis
- ogg_page m_ogg_pg;//this could be avoided since
+ ogg_page m_ogg_pg;//this could be avoided since
// it is used only while initializing
ogg_packet m_ogg_pckt1;//theora stream
ogg_packet m_ogg_pckt2;//vorbis stream
@@ -165,7 +182,7 @@ typedef struct _EncData{
//vorbis data
vorbis_info m_vo_inf;
vorbis_comment m_vo_cmmnt;
- vorbis_dsp_state m_vo_dsp;
+ vorbis_dsp_state m_vo_dsp;
vorbis_block m_vo_block;
//these should be 0, since area is quantized
//before input
@@ -175,8 +192,27 @@ typedef struct _EncData{
FILE *fp;
}EncData;
+//this struct will hold a few basic
+//information, needed for caching the frames.
+typedef struct _CacheData{
+ char *workdir, //The directory were the project will be stored, while recording.
+ //Since this will take a lot of space, the user must be
+ //able to change the location.
+ *projname, //This is the name of the folder that will hold the project.
+ //It is rMD-session-%d where %d is the pid of the current proccess.
+ //This way, running two instances will not create problems
+ //and also, a frontend can identify leftovers from a possible crash
+ //and delete them
+ *imgdata, //workdir+projname+img.out.gz
+ *audiodata; //workdir+projname+audio.pcm
+
+ gzFile *ifp; //image data file pointer
+ FILE *afp; //audio data file pointer
+
+}CacheData;
+
//sound buffer
-//sound keeps coming so we que it in this list
+//sound keeps coming so we que it in this list
//which we then traverse
typedef struct _SndBuffer{
signed char *data;
@@ -184,23 +220,24 @@ typedef struct _SndBuffer{
}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.
+//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
+ char *window_manager;//name of the window manager at program launch
XImage *image;//the image that holds the current full screenshot
XImage *shimage;//the image that holds the current full screenshot(shared memory)
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 image
+ char *datamain,//the data of image
*datash,//the data of shimage
- *datatemp;//buffer for the temporary image,which will be
+ *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
@@ -209,6 +246,7 @@ typedef struct _ProgData{
running;
SndBuffer *sound_buffer;
EncData *enc_data;
+ CacheData *cache_data;
int hard_pause;//if sound device doesn't support pause
//we have to close and reopen
int avd;//syncronization among audio and video
@@ -217,7 +255,7 @@ typedef struct _ProgData{
pthread_mutex_t list_mutex[2],//mutexes for concurrency protection of the lists
sound_buffer_mutex,
libogg_mutex,//libogg is not thread safe
- yuv_mutex;//this might not be needed since we only have
+ yuv_mutex;//this might not be needed since we only have
//one read-only and one write-only thread
//also on previous versions, y component was looped separately
//and then u and v so this was needed to avoid wrong coloring to render
@@ -231,6 +269,48 @@ typedef struct _ProgData{
snd_pcm_uframes_t periodsize;
}ProgData;
+
+//This is the header of every frame.
+//Reconstruction will be correct only if made on
+//the same platform.
+
+//We need the total number of blocks
+//for each plane.
+
+//The number of the frame compared to the
+//number of time expirations at the time of
+//caching, will enable us to make up for lost frames.
+
+//default 4+4+2+2+2=14!bad!
+//me add pad, make god of 2 happy!
+typedef struct _FrameHeader{
+ char frame_prefix[4];//always FRAM
+ u_int32_t frameno,//number of frame(cached frames)
+ current_total;//number of frames that should have been
+ //taken at time of caching this one
+ u_int16_t Ynum,//number of changed blocks in the Y plane
+ Unum,//number of changed blocks in the U plane
+ Vnum;//number of changed blocks in the V plane
+ u_int16_t pad;//always zero
+
+}FrameHeader;
+
+//The frame after retrieval.
+//Based on the Header information
+//we can read the correct amount of bytes.
+
+
+typedef struct _CachedFrame{
+ FrameHeader *header;
+ unsigned char *YBlocks;//identifying number on the grid, starting at top left
+ unsigned char *UBlocks;// >> >>
+ unsigned char *VBlocks;// >> >>
+ unsigned char *YData;//pointer to data for the blocks that have changed,
+ unsigned char *UData;//which have to be remapped on the buffer when reading
+ unsigned char *VData;
+}CachedFrame;
+
+
/**Globals*/
//I've read somewhere that I'll go to hell for using globals...
@@ -241,9 +321,9 @@ unsigned char Yr[256],Yg[256],Yb[256],
Vr[256],Vg[256],Vb[256];
//the following values are of no effect
//but they might be usefull later for profiling
-unsigned int frames_total,//frames calculated by total time expirations
- frames_lost;//the value of shame
-//used to determine frame drop which can
+unsigned int frames_total,//frames calculated by total time expirations
+ frames_lost;//the value of shame
+//used to determine frame drop which can
//happen on failure to receive a signal over a condition variable
int capture_busy,
encoder_busy;
@@ -318,8 +398,10 @@ int capture_busy,
(args)->display=NULL;\
(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)->nosound=(args)->full_shots=(args)->encOnTheFly\
+ =(args)->zerocompression=(args)->nowmcheck\
+ =(args)->overwrite=0;\
+ (args)->noshared=1;\
(args)->dropframes=(args)->nocondshared=0;\
(args)->no_quick_subsample=1;\
(args)->filename=(char *)malloc(8);\
@@ -337,6 +419,8 @@ int capture_busy,
(args)->v_bitrate=45000;\
(args)->v_quality=63;\
(args)->s_quality=10;\
+ (args)->workdir=(char *)malloc(strlen(getenv("HOME"))+1);\
+ strcpy((args)->workdir,getenv("HOME"));\
}
#define QUERY_DISPLAY_SPECS(display,specstruct){\
@@ -356,83 +440,193 @@ int capture_busy,
+data_array[(k_tm*width_img+i_tm-1)*4+offset]+data_array[((k_tm-1)*width_img+i_tm-1)*4+offset])/4)
#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]=Yr[data[(i+k*yuv->y_width)*4+__RBYTE]] + Yg[data[(i+k*yuv->y_width)*4+__GBYTE]] + Yb[data[(i+k*yuv->y_width)*4+__BBYTE]];\
- if((k%2)&&(i%2)){\
- yuv->u[i/2+k/2*yuv->uv_width]=Ur[data[(i+k*yuv->y_width)*4+__RBYTE]] + Ug[data[(i+k*yuv->y_width)*4+__GBYTE]] + Ub[data[(i+k*yuv->y_width)*4+__BBYTE]] ;\
- yuv->v[i/2+k/2*yuv->uv_width]=Vr[data[(i+k*yuv->y_width)*4+__RBYTE]] + Vg[data[(i+k*yuv->y_width)*4+__GBYTE]] + Vb[data[(i+k*yuv->y_width)*4+__BBYTE]] ;\
- }\
+ int k,i;\
+ register unsigned int t_val;\
+ register unsigned int *datapi=(unsigned int*)data+x_tm+y_tm*yuv->y_width;\
+ register unsigned char *yuv_y=yuv->y+x_tm+y_tm*yuv->y_width,\
+ *yuv_u=yuv->u+x_tm/2+(y_tm*yuv->uv_width)/2,\
+ *yuv_v=yuv->v+x_tm/2+(y_tm*yuv->uv_width)/2,\
+ *_yr=Yr,*_yg=Yg,*_yb=Yb,\
+ *_ur=Ur,*_ug=Ug,*_ub=Ub,\
+ *_vr=Vr,*_vg=Vg,*_vb=Vb;\
+\
+ for(k=0;k<height_tm;k++){\
+ for(i=0;i<width_tm;i++){\
+ t_val=*datapi;\
+ *yuv_y=_yr[__RVALUE(t_val)] + _yg[__GVALUE(t_val)] + _yb[__BVALUE(t_val)] ;\
+ datapi++;\
+ yuv_y++;\
+ }\
+ yuv_y+=yuv->y_width-width_tm;\
+ datapi+=yuv->y_width-width_tm;\
+ }\
+ datapi=(unsigned int*)data+x_tm+y_tm*yuv->y_width;\
+ for(k=0;k<height_tm;k+=2){\
+ for(i=0;i<width_tm;i+=2){\
+ t_val=*datapi;\
+ *yuv_u=\
+ _ur[__RVALUE(t_val)] + _ug[__GVALUE(t_val)] + _ub[__BVALUE(t_val)];\
+ *yuv_v=\
+ _vr[__RVALUE(t_val)] + _vg[__GVALUE(t_val)] + _vb[__BVALUE(t_val)];\
+ datapi+=2;\
+ yuv_u++;\
+ yuv_v++;\
}\
+ yuv_u+=(yuv->y_width-width_tm)/2;\
+ yuv_v+=(yuv->y_width-width_tm)/2;\
+ datapi+=(2*yuv->y_width-width_tm);\
}\
}
#define UPDATE_YUV_BUFFER_SH_AVG(yuv,data,x_tm,y_tm,width_tm,height_tm){\
- int i,k;\
- unsigned char avg0,avg1,avg2;\
- 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]=Yr[data[(i+k*yuv->y_width)*4+__RBYTE]] + Yg[data[(i+k*yuv->y_width)*4+__GBYTE]] + Yb[data[(i+k*yuv->y_width)*4+__BBYTE]];\
- if((k%2)&&(i%2)){\
- avg2=AVG_4_PIXELS(data,(yuv->y_width),k,i,__RBYTE);\
- avg1=AVG_4_PIXELS(data,(yuv->y_width),k,i,__GBYTE);\
- avg0=AVG_4_PIXELS(data,(yuv->y_width),k,i,__BBYTE);\
- yuv->u[i/2+k/2*yuv->uv_width]=Ur[avg2] +\
- Ug[avg1] +\
- Ub[avg0] ;\
- yuv->v[i/2+k/2*yuv->uv_width]=Vr[avg2] +\
- Vg[avg1] +\
- Vb[avg0] ;\
- }\
+ int k,i;\
+ register unsigned int t_val,t1,t2,t3,t4;\
+ register unsigned int *datapi=(unsigned int*)data+x_tm+y_tm*yuv->y_width,\
+ *datapi_next=(unsigned int*)data+x_tm+(y_tm+1)*yuv->y_width;\
+ register unsigned char *yuv_y=yuv->y+x_tm+y_tm*yuv->y_width,\
+ *yuv_u=yuv->u+x_tm/2+(y_tm*yuv->uv_width)/2,\
+ *yuv_v=yuv->v+x_tm/2+(y_tm*yuv->uv_width)/2,\
+ *_yr=Yr,*_yg=Yg,*_yb=Yb,\
+ *_ur=Ur,*_ug=Ug,*_ub=Ub,\
+ *_vr=Vr,*_vg=Vg,*_vb=Vb;\
+\
+ for(k=0;k<height_tm;k++){\
+ for(i=0;i<width_tm;i++){\
+ t_val=*datapi;\
+ *yuv_y=_yr[__RVALUE(t_val)] + _yg[__GVALUE(t_val)] + _yb[__BVALUE(t_val)] ;\
+ datapi++;\
+ yuv_y++;\
+ }\
+ yuv_y+=yuv->y_width-width_tm;\
+ datapi+=yuv->y_width-width_tm;\
+ }\
+ datapi=(unsigned int*)data+x_tm+y_tm*yuv->y_width;\
+ for(k=0;k<height_tm;k+=2){\
+ for(i=0;i<width_tm;i+=2){\
+ t1=*datapi;\
+ t2=*(datapi+1);\
+ t3=*datapi_next;\
+ t4=*(datapi_next+1);\
+ t_val=((((t1&0xff000000) +(t2&0xff000000)+\
+ (t3&0xff000000)+(t4&0xff000000))/4)&0xff000000) \
+ +((((t1&0x00ff0000) +(t2&0x00ff0000)+\
+ (t3&0x00ff0000)+(t4&0x00ff0000))/4)&0x00ff0000)\
+ +((((t1&0x0000ff00) +(t2&0x0000ff00)+\
+ (t3&0x0000ff00)+(t4&0x0000ff00))/4)&0x0000ff00)\
+ +((((t1&0x000000ff) +(t2&0x000000ff)+\
+ (t3&0x000000ff)+(t4&0x000000ff))/4)&0x000000ff);\
+\
+ *yuv_u=\
+ _ur[__RVALUE(t_val)] + _ug[__GVALUE(t_val)] + _ub[__BVALUE(t_val)];\
+ *yuv_v=\
+ _vr[__RVALUE(t_val)] + _vg[__GVALUE(t_val)] + _vb[__BVALUE(t_val)];\
+ datapi+=2;\
+ datapi_next+=2;\
+ yuv_u++;\
+ yuv_v++;\
}\
+ yuv_u+=(yuv->y_width-width_tm)/2;\
+ yuv_v+=(yuv->y_width-width_tm)/2;\
+ datapi+=(2*yuv->y_width-width_tm);\
+ datapi_next+=(2*yuv->y_width-width_tm);\
}\
}
+
+
#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;\
+ int k,i;\
+ register unsigned int t_val;\
+ register unsigned int *datapi=(unsigned int*)data;\
+ register unsigned char *yuv_y=yuv->y+x_tm+y_tm*yuv->y_width,\
+ *yuv_u=yuv->u+x_tm/2+(y_tm*yuv->uv_width)/2,\
+ *yuv_v=yuv->v+x_tm/2+(y_tm*yuv->uv_width)/2,\
+ *_yr=Yr,*_yg=Yg,*_yb=Yb,\
+ *_ur=Ur,*_ug=Ug,*_ub=Ub,\
+ *_vr=Vr,*_vg=Vg,*_vb=Vb;\
+\
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]=Yr[data[(j*4)+__RBYTE]] + Yg[data[(j*4)+__GBYTE]] + Yb[data[(j*4)+__BBYTE]] ;\
- if((k%2)&&(i%2)){\
- yuv->u[x_2+i/2+(k/2+y_2)*yuv->uv_width]=\
- Ur[data[(k*width_tm+i)*4+__RBYTE]] + Ug[data[(k*width_tm+i)*4+__GBYTE]] + Ub[data[(k*width_tm+i)*4+__BBYTE]];\
- yuv->v[x_2+i/2+(k/2+y_2)*yuv->uv_width]=\
- Vr[data[(k*width_tm+i)*4+__RBYTE]] + Vg[data[(k*width_tm+i)*4+__GBYTE]] + Vb[data[(k*width_tm+i)*4+__BBYTE]];\
- }\
- \
- j++;\
+ t_val=*datapi;\
+ *yuv_y=_yr[__RVALUE(t_val)] + _yg[__GVALUE(t_val)] + _yb[__BVALUE(t_val)] ;\
+ datapi++;\
+ yuv_y++;\
}\
+ yuv_y+=yuv->y_width-width_tm;\
+ }\
+ datapi=(unsigned int*)data;\
+ for(k=0;k<height_tm;k+=2){\
+ for(i=0;i<width_tm;i+=2){\
+ t_val=*datapi;\
+ *yuv_u=\
+ _ur[__RVALUE(t_val)] + _ug[__GVALUE(t_val)] + _ub[__BVALUE(t_val)];\
+ *yuv_v=\
+ _vr[__RVALUE(t_val)] + _vg[__GVALUE(t_val)] + _vb[__BVALUE(t_val)];\
+ datapi+=2;\
+ yuv_u++;\
+ yuv_v++;\
+ }\
+ yuv_u+=(yuv->y_width-width_tm)/2;\
+ yuv_v+=(yuv->y_width-width_tm)/2;\
+ datapi+=width_tm;\
}\
}
-
-
#define UPDATE_YUV_BUFFER_IM_AVG(yuv,data,x_tm,y_tm,width_tm,height_tm){\
- int i,k,j=0;\
- unsigned char avg0,avg1,avg2;\
- int x_2=x_tm/2,y_2=y_tm/2;\
+ int k,i;\
+ register unsigned int t_val,t1,t2,t3,t4;\
+ register unsigned int *datapi=(unsigned int*)data,\
+ *datapi_next=(unsigned int*)data+width_tm;\
+ register unsigned char *yuv_y=yuv->y+x_tm+y_tm*yuv->y_width,\
+ *yuv_u=yuv->u+x_tm/2+(y_tm*yuv->uv_width)/2,\
+ *yuv_v=yuv->v+x_tm/2+(y_tm*yuv->uv_width)/2,\
+ *_yr=Yr,*_yg=Yg,*_yb=Yb,\
+ *_ur=Ur,*_ug=Ug,*_ub=Ub,\
+ *_vr=Vr,*_vg=Vg,*_vb=Vb;\
+\
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]=Yr[data[(j*4)+__RBYTE]] + Yg[data[(j*4)+__GBYTE]] + Yb[data[(j*4)+__BBYTE]] ;\
- if((k%2)&&(i%2)){\
- avg2=AVG_4_PIXELS(data,width_tm,k,i,__RBYTE);\
- avg1=AVG_4_PIXELS(data,width_tm,k,i,__GBYTE);\
- avg0=AVG_4_PIXELS(data,width_tm,k,i,__BBYTE);\
- yuv->u[x_2+i/2+(k/2+y_2)*yuv->uv_width]=\
- Ur[avg2] + Ug[avg1] +\
- Ub[avg0];\
- yuv->v[x_2+i/2+(k/2+y_2)*yuv->uv_width]=\
- Vr[avg2] + Vg[avg1] +\
- Vb[avg0];\
- }\
- \
- j++;\
+ t_val=*datapi;\
+ *yuv_y=_yr[__RVALUE(t_val)] + _yg[__GVALUE(t_val)] + _yb[__BVALUE(t_val)] ;\
+ datapi++;\
+ yuv_y++;\
}\
+ yuv_y+=yuv->y_width-width_tm;\
+ }\
+ datapi=(unsigned int*)data;\
+ for(k=0;k<height_tm;k+=2){\
+ for(i=0;i<width_tm;i+=2){\
+ t1=*datapi;\
+ t2=*(datapi+1);\
+ t3=*datapi_next;\
+ t4=*(datapi_next+1);\
+ t_val=((((t1&0xff000000) +(t2&0xff000000)+\
+ (t3&0xff000000)+(t4&0xff000000))/4)&0xff000000) \
+ +((((t1&0x00ff0000) +(t2&0x00ff0000)+\
+ (t3&0x00ff0000)+(t4&0x00ff0000))/4)&0x00ff0000)\
+ +((((t1&0x0000ff00) +(t2&0x0000ff00)+\
+ (t3&0x0000ff00)+(t4&0x0000ff00))/4)&0x0000ff00)\
+ +((((t1&0x000000ff) +(t2&0x000000ff)+\
+ (t3&0x000000ff)+(t4&0x000000ff))/4)&0x000000ff);\
+\
+ *yuv_u=\
+ _ur[__RVALUE(t_val)] + _ug[__GVALUE(t_val)] + _ub[__BVALUE(t_val)];\
+ *yuv_v=\
+ _vr[__RVALUE(t_val)] + _vg[__GVALUE(t_val)] + _vb[__BVALUE(t_val)];\
+ datapi+=2;\
+ datapi_next+=2;\
+ yuv_u++;\
+ yuv_v++;\
+ }\
+ yuv_u+=(yuv->y_width-width_tm)/2;\
+ yuv_v+=(yuv->y_width-width_tm)/2;\
+ datapi+=width_tm;\
+ datapi_next+=width_tm;\
}\
}
+
+
#define XFIXES_POINTER_TO_YUV(yuv,data,x_tm,y_tm,width_tm,height_tm,column_discard_stride){\
int i,k,j=0;\
unsigned char avg0,avg1,avg2,avg3;\
@@ -479,6 +673,42 @@ int capture_busy,
}
+#define I16TOA(number,buffer){\
+ int t_num=(number),k=0,i=0;\
+ char *t_buf=malloc(8);\
+ t_num=t_num&((2<<15)-1);\
+ while(t_num>0){\
+ int digit=t_num%10;\
+ t_buf[k]=digit+48;\
+ t_num-=digit;\
+ t_num/=10;\
+ k++;\
+ }\
+ while(k>0)\
+ (buffer)[i++]=t_buf[--k];\
+ (buffer)[i]='\0';\
+ free(t_buf);\
+};\
+
+#define INIT_FRAME(frame_t,fheader_t,yuv_t){\
+ (frame_t)->header=(fheader_t);\
+ (frame_t)->YBlocks=malloc(256);\
+ (frame_t)->UBlocks=malloc(64);\
+ (frame_t)->VBlocks=malloc(64);\
+ (frame_t)->YData=malloc((yuv_t)->y_width*(yuv_t)->y_height);\
+ (frame_t)->UData=malloc((yuv_t)->uv_width*(yuv_t)->uv_height);\
+ (frame_t)->VData=malloc((yuv_t)->uv_width*(yuv_t)->uv_height);\
+};
+
+#define CLEAR_FRAME(frame_t){\
+ free((frame_t)->YBlocks);\
+ free((frame_t)->UBlocks);\
+ free((frame_t)->VBlocks);\
+ free((frame_t)->YData);\
+ free((frame_t)->UData);\
+ free((frame_t)->VData);\
+};
+
/**Function prototypes*/
void *PollDamage(void *pdata);
@@ -496,13 +726,20 @@ int GetZPixmap(Display *dpy,Window root,char *data,int x,int y,int width,int hei
int ParseArgs(int argc,char **argv,ProgArgs *arg_return);
void 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 *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);
+void InitEncoder(ProgData *pdata,EncData *enc_data_t,int buffer_ready);
void MakeMatrices();
void SizePack2_8_16(int *start,int *size,int limit);
+void *CacheImageBuffer(void *pdata);
+void InitCacheData(ProgData *pdata,EncData *enc_data_t,CacheData *cache_data_t);
+void *CacheSoundBuffer(void *pdata);
+void *LoadCache(void *pdata);
+void SyncEncodeImageBuffer(ProgData *pdata);
+void CancelTimer(void);
+void SyncEncodeSoundBuffer(ProgData *pdata,signed char *buff);
+char *rmdWMCheck(Display *dpy,Window root);
#endif
diff --git a/recordmydesktop/src/Makefile.am b/recordmydesktop/src/Makefile.am
index e56b856..d5fa847 100644
--- a/recordmydesktop/src/Makefile.am
+++ b/recordmydesktop/src/Makefile.am
@@ -3,7 +3,6 @@ bin_PROGRAMS = recordmydesktop
recordmydesktop_SOURCES= recordmydesktop.c\
- zpixmaptobmp.c\
getzpixmap.c\
parseargs.c\
rectinsert.c\
@@ -20,9 +19,14 @@ recordmydesktop_SOURCES= recordmydesktop.c\
opendev.c\
capture_sound.c\
encode_sound_buffer.c\
- init_encoder.c
+ init_encoder.c\
+ cache_frame.c\
+ cache_audio.c\
+ rmd_cache.c\
+ load_cache.c\
+ wm_check.c
-INCLUDES= $(all_includes) -I../include -I$x_includes
-
-recordmydesktop_LDFLAGS = -D_THREAD_SAFE -pthread -Wall
+INCLUDES= $(all_includes) -I../include
+recordmydesktop_LDFLAGS = @X_LIBS@ @X_EXTRA_LIBS@ @X_PRE_LIBS@
+recordmydesktop_CFLAGS = -D_THREAD_SAFE -pthread -Wall
diff --git a/recordmydesktop/src/zpixmaptobmp.c b/recordmydesktop/src/cache_audio.c
index 0aa9477..7b17d7b 100644
--- a/recordmydesktop/src/zpixmaptobmp.c
+++ b/recordmydesktop/src/cache_audio.c
@@ -24,55 +24,44 @@
* For further information contact me at johnvarouhakis@gmail.com *
**********************************************************************************/
-
#include <recordmydesktop.h>
+void *CacheSoundBuffer(void *pdata){
+//We are simply going to throw sound on the disk.
+//It's sound is tiny compared to that of image, so
+//compressing would reducethe overall size by only an
+//insignificant fraction.
+ pthread_mutex_t smut;
+ pthread_mutex_init(&smut,NULL);
+ while((((ProgData *)pdata)->running)){
+ SndBuffer *buff;
-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);
- }
+ if(Paused){
+ pthread_mutex_t tmut;
+ pthread_mutex_init(&tmut,NULL);
+ pthread_cond_wait(&((ProgData *)pdata)->pause_cond,&tmut);
}
-
- fclose(fpbmp);
- return 0;
+
+ 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);
+
+ fwrite(buff->data,((ProgData *)pdata)->periodsize,1,((ProgData *)pdata)->cache_data->afp);
+
+
+
+ ((ProgData *)pdata)->avd-=((ProgData *)pdata)->periodtime;
+
+ free(buff->data);
+ free(buff);
+ }
+
+ fclose(((ProgData *)pdata)->cache_data->afp);
+ pthread_exit(&errno);
}
diff --git a/recordmydesktop/src/cache_frame.c b/recordmydesktop/src/cache_frame.c
new file mode 100644
index 0000000..c100505
--- /dev/null
+++ b/recordmydesktop/src/cache_frame.c
@@ -0,0 +1,193 @@
+/*********************************************************************************
+* 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 johnvarouhakis@gmail.com *
+**********************************************************************************/
+
+#include <recordmydesktop.h>
+
+
+int CompareBlocks(unsigned char *incoming,unsigned char *old,int blockno,int width, int height,int divisor){
+ int j,i,
+ block_i=blockno/divisor,//place on the grid
+ block_k=blockno%divisor;
+ register unsigned char *incoming_reg=&(incoming[block_i*(width*height/divisor)+block_k*width/divisor]),
+ *old_reg=&(old[block_i*(width*height/divisor)+block_k*width/divisor]);
+
+ for(j=0;j<height/divisor;j++){
+ for(i=0;i<width/divisor;i++){
+ if((*(incoming_reg++))!=(*(old_reg++)))
+ return 1;
+ }
+ incoming_reg+=(width-width/divisor);
+ old_reg+=(width-width/divisor);
+ }
+
+ return 0;
+}
+
+void FlushBlock(unsigned char *buf,int blockno,int width, int height,int divisor,gzFile *fp){
+ int j,
+ block_i=blockno/divisor,//place on the grid
+ block_k=blockno%divisor;
+ register unsigned char *buf_reg=(&buf[block_i*(width*height/divisor)+block_k*width/divisor]);
+ for(j=0;j<height/divisor;j++){//we flush in rows
+ gzwrite(fp,(void *)buf_reg,width/divisor);
+ buf_reg+=width;
+ }
+}
+
+void *CacheImageBuffer(void *pdata){
+ pthread_mutex_t pmut,imut;
+ pthread_mutex_init(&pmut,NULL);
+ pthread_mutex_init(&imut,NULL);
+ yuv_buffer yuv[2];
+ gzFile *fp=((ProgData *)pdata)->cache_data->ifp;
+
+ if(fp==NULL)exit(13);
+
+ int i,current=0,divisor=16,firstrun=1,frameno=0;
+
+ for(i=0;i<2;i++){
+ yuv[i].y_width=((ProgData *)pdata)->enc_data->yuv.y_width;
+ yuv[i].y_height=((ProgData *)pdata)->enc_data->yuv.y_height;
+ yuv[i].uv_width=((ProgData *)pdata)->enc_data->yuv.uv_width;
+ yuv[i].uv_height=((ProgData *)pdata)->enc_data->yuv.uv_height;
+
+ yuv[i].y=(unsigned char *)malloc(yuv[i].y_width*yuv[i].y_height);
+ yuv[i].u=(unsigned char *)malloc(yuv[i].uv_width*yuv[i].uv_height);
+ yuv[i].v=(unsigned char *)malloc(yuv[i].uv_width*yuv[i].uv_height);
+ }
+
+
+ while(((ProgData *)pdata)->running){
+ int prev;
+ int j;
+ unsigned short ynum,unum,vnum;
+ unsigned char yblocks[256],ublocks[64],vblocks[64];
+ FrameHeader fheader;
+ ynum=unum=vnum=0;
+
+ pthread_cond_wait(&((ProgData *)pdata)->image_buffer_ready,&imut);
+ if(Paused)
+ pthread_cond_wait(&((ProgData *)pdata)->pause_cond,&pmut);
+ pthread_mutex_lock(&((ProgData *)pdata)->yuv_mutex);
+
+ //rotate buffers
+ prev=current;
+ current=(current)?0:1;
+ //copy incoming
+ memcpy(yuv[current].y,((ProgData *)pdata)->enc_data->yuv.y,yuv[current].y_width*yuv[current].y_height);
+ memcpy(yuv[current].u,((ProgData *)pdata)->enc_data->yuv.u,yuv[current].uv_width*yuv[current].uv_height);
+ memcpy(yuv[current].v,((ProgData *)pdata)->enc_data->yuv.v,yuv[current].uv_width*yuv[current].uv_height);
+ //release main buffer
+ pthread_mutex_unlock(&((ProgData *)pdata)->yuv_mutex);
+ //get checksums for new
+
+ //find and flush different blocks
+ if(firstrun){
+ firstrun=0;
+ for(j=0;j<pow(divisor,2);j++){
+ ynum++;
+ yblocks[ynum-1]=j;
+ }
+ for(j=0;j<pow(divisor/2,2);j++){
+ unum++;
+ ublocks[unum-1]=j;
+ }
+ for(j=0;j<pow(divisor/2,2);j++){
+ vnum++;
+ vblocks[vnum-1]=j;
+ }
+
+ }
+ else{
+ for(j=0;j<pow(divisor,2);j++){
+ if(CompareBlocks(yuv[current].y,yuv[prev].y,j,yuv[current].y_width,yuv[current].y_height,divisor)){
+ ynum++;
+ yblocks[ynum-1]=j;
+ }
+ }
+ for(j=0;j<pow(divisor/2,2);j++){
+ if(CompareBlocks(yuv[current].u,yuv[prev].u,j,yuv[current].uv_width,yuv[current].uv_height,divisor/2)){
+ unum++;
+ ublocks[unum-1]=j;
+ }
+ }
+ for(j=0;j<pow(divisor/2,2);j++){
+ if(CompareBlocks(yuv[current].v,yuv[prev].v,j,yuv[current].uv_width,yuv[current].uv_height,divisor/2)){
+ vnum++;
+ vblocks[vnum-1]=j;
+ }
+ }
+
+ }
+ /**WRITE FRAME TO DISK*/
+ if(!((ProgData *)pdata)->args.zerocompression){
+ if(ynum+unum+vnum>(pow(divisor,2)+pow(divisor/2,2)*2)/10)
+ gzsetparams (fp,1,Z_FILTERED);
+ else
+ gzsetparams (fp,0,Z_FILTERED);
+ }
+
+ strncpy(fheader.frame_prefix,"FRAM",4);
+ fheader.frameno=++frameno;
+ fheader.current_total=frames_total;
+ fheader.Ynum=ynum;
+ fheader.Unum=unum;
+ fheader.Vnum=vnum;
+ fheader.pad=0;
+ gzwrite(fp,(void*)&fheader,sizeof(FrameHeader));
+ //flush indexes
+ if(ynum)gzwrite(fp,yblocks,ynum);
+ if(unum)gzwrite(fp,ublocks,unum);
+ if(vnum)gzwrite(fp,vblocks,vnum);
+
+
+ //flush the blocks for each buffer
+ if(ynum)
+ for(j=0;j<ynum;j++)
+ FlushBlock(yuv[current].y,yblocks[j],yuv[current].y_width,yuv[current].y_height,divisor,fp);
+ if(unum)
+ for(j=0;j<unum;j++)
+ FlushBlock(yuv[current].u,ublocks[j],yuv[current].uv_width,yuv[current].uv_height,divisor/2,fp);
+ if(vnum)
+ for(j=0;j<vnum;j++)
+ FlushBlock(yuv[current].v,vblocks[j],yuv[current].uv_width,yuv[current].uv_height,divisor/2,fp);
+
+
+ /**@________________@**/
+ ((ProgData *)pdata)->avd+=((ProgData *)pdata)->frametime*2*((ProgData *)pdata)->args.channels;
+
+ }
+
+ //clean up since we're not finished
+ for(i=0;i<2;i++){
+ free(yuv[i].y);
+ free(yuv[i].u);
+ free(yuv[i].v);
+ }
+ fprintf(stderr,"Saved %d frames in a total of %d requests\n",frameno,frames_total);
+ gzclose(fp);
+ pthread_exit(&errno);
+}
diff --git a/recordmydesktop/src/encode_image_buffer.c b/recordmydesktop/src/encode_image_buffer.c
index 38a1d77..8ff9629 100644
--- a/recordmydesktop/src/encode_image_buffer.c
+++ b/recordmydesktop/src/encode_image_buffer.c
@@ -30,8 +30,8 @@ void *EncodeImageBuffer(void *pdata){
pthread_mutex_init(&pmut,NULL);
pthread_mutex_init(&imut,NULL);
while(((ProgData *)pdata)->running){
- encoder_busy=1;
pthread_cond_wait(&((ProgData *)pdata)->image_buffer_ready,&imut);
+ encoder_busy=1;
if(Paused)
pthread_cond_wait(&((ProgData *)pdata)->pause_cond,&pmut);//this may not be needed
pthread_mutex_lock(&((ProgData *)pdata)->yuv_mutex);
@@ -62,4 +62,22 @@ void *EncodeImageBuffer(void *pdata){
pthread_exit(&errno);
}
+//this function is meant to be called normally
+//not through a thread of it's own
+void SyncEncodeImageBuffer(ProgData *pdata){
+ if(theora_encode_YUVin(&pdata->enc_data->m_th_st,
+ &pdata->enc_data->yuv)){
+ fprintf(stderr,"Encoder not ready!\n");
+ }
+ else{
+ if(theora_encode_packetout(&pdata->enc_data->m_th_st,0,
+ &pdata->enc_data->m_ogg_pckt1)==1){
+ pthread_mutex_lock(&pdata->libogg_mutex);
+ ogg_stream_packetin(&pdata->enc_data->m_ogg_ts,
+ &pdata->enc_data->m_ogg_pckt1);
+ pthread_mutex_unlock(&pdata->libogg_mutex);
+ pdata->avd+=pdata->frametime*2*pdata->args.channels;
+ }
+ }
+}
diff --git a/recordmydesktop/src/encode_sound_buffer.c b/recordmydesktop/src/encode_sound_buffer.c
index 85e277d..73f6d48 100644
--- a/recordmydesktop/src/encode_sound_buffer.c
+++ b/recordmydesktop/src/encode_sound_buffer.c
@@ -90,4 +90,32 @@ void *EncodeSoundBuffer(void *pdata){
pthread_exit(&errno);
}
-
+void SyncEncodeSoundBuffer(ProgData *pdata,signed char *buff){
+ float **vorbis_buffer;
+ int count=0,i,j;
+ int sampread=pdata->periodsize/(2*pdata->args.channels);
+ vorbis_buffer=vorbis_analysis_buffer(&pdata->enc_data->m_vo_dsp,sampread);
+ for(i=0;i<sampread;i++){
+ for(j=0;j<pdata->args.channels;j++){
+ vorbis_buffer[j][i]=((buff[count+1]<<8)|
+ (0x00ff&(int)buff[count]))/32768.f;
+ count+=2;
+ }
+ }
+
+ vorbis_analysis_wrote(&pdata->enc_data->m_vo_dsp,sampread);
+
+ while(vorbis_analysis_blockout(&pdata->enc_data->m_vo_dsp,&pdata->enc_data->m_vo_block)==1){
+
+ vorbis_analysis(&pdata->enc_data->m_vo_block,NULL);
+ vorbis_bitrate_addblock(&pdata->enc_data->m_vo_block);
+
+ while(vorbis_bitrate_flushpacket(&pdata->enc_data->m_vo_dsp,&pdata->enc_data->m_ogg_pckt2)){
+ pthread_mutex_lock(&pdata->libogg_mutex);
+ ogg_stream_packetin(&pdata->enc_data->m_ogg_vs,&pdata->enc_data->m_ogg_pckt2);
+ pthread_mutex_unlock(&pdata->libogg_mutex);
+ }
+ }
+ pdata->avd-=pdata->periodtime;
+}
+
diff --git a/recordmydesktop/src/init_encoder.c b/recordmydesktop/src/init_encoder.c
index ed1ad53..84d36aa 100644
--- a/recordmydesktop/src/init_encoder.c
+++ b/recordmydesktop/src/init_encoder.c
@@ -27,7 +27,35 @@
#include <recordmydesktop.h>
-void InitEncoder(ProgData *pdata,EncData *enc_data_t){
+int IncrementalNaming(char **name){
+ struct stat buff;
+ char *base_name;
+ int i=0;
+ base_name=malloc(strlen(*name));
+ strcpy(base_name,*name);
+
+ //this will go on an endless loop if you have 65536? files with the same name
+ //or it will crash and die.anyone interested in trying ?
+ while (stat(*name,&buff)==0){
+ //create new name
+ char *tname=malloc(strlen(*name)+10);
+ char numbuf[8];
+
+ strcpy(tname,base_name);
+ strcat(tname,".");
+ I16TOA((++i),numbuf)
+ strcat(tname,numbuf);
+ //save new name
+ free(*name);
+ *name=malloc(strlen(tname)+1);
+ strcpy(*name,tname);
+ free(tname);
+ }
+ free(base_name);
+ return 0;
+}
+
+void InitEncoder(ProgData *pdata,EncData *enc_data_t,int buffer_ready){
int y1,y2;
(pdata)->enc_data=enc_data_t;
srand(time(NULL));
@@ -38,12 +66,13 @@ void InitEncoder(ProgData *pdata,EncData *enc_data_t){
ogg_stream_init(&(enc_data_t)->m_ogg_ts,y1);
if(!pdata->args.nosound)
ogg_stream_init(&(enc_data_t)->m_ogg_vs,y2);
-
+ if(!pdata->args.overwrite)
+ IncrementalNaming(&(pdata)->args.filename);
(enc_data_t)->fp=fopen((pdata)->args.filename,"w");
if((enc_data_t)->fp==NULL){
fprintf(stderr,"Cannot open file %s for writting!\n",(pdata)->args.filename);
exit(13);
- }
+ }
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;
@@ -87,7 +116,7 @@ void InitEncoder(ProgData *pdata,EncData *enc_data_t){
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){
@@ -109,16 +138,16 @@ void InitEncoder(ProgData *pdata,EncData *enc_data_t){
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);
+ 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(2);
}
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);
}
@@ -150,23 +179,24 @@ void InitEncoder(ProgData *pdata,EncData *enc_data_t){
}
+ if(!buffer_ready){
+ (enc_data_t)->yuv.y=(unsigned char *)malloc((enc_data_t)->m_th_inf.height*(enc_data_t)->m_th_inf.width);
+ (enc_data_t)->yuv.u=(unsigned char *)malloc((enc_data_t)->m_th_inf.height*(enc_data_t)->m_th_inf.width/4);
+ (enc_data_t)->yuv.v=(unsigned char *)malloc((enc_data_t)->m_th_inf.height*(enc_data_t)->m_th_inf.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.y=(unsigned char *)malloc((enc_data_t)->m_th_inf.height*(enc_data_t)->m_th_inf.width);
- (enc_data_t)->yuv.u=(unsigned char *)malloc((enc_data_t)->m_th_inf.height*(enc_data_t)->m_th_inf.width/4);
- (enc_data_t)->yuv.v=(unsigned char *)malloc((enc_data_t)->m_th_inf.height*(enc_data_t)->m_th_inf.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;
- (enc_data_t)->x_offset=(enc_data_t)->m_th_inf.offset_x;
- (enc_data_t)->y_offset=(enc_data_t)->m_th_inf.offset_y;
+ (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;
+ (enc_data_t)->x_offset=(enc_data_t)->m_th_inf.offset_x;
+ (enc_data_t)->y_offset=(enc_data_t)->m_th_inf.offset_y;
+ }
theora_info_clear(&(enc_data_t)->m_th_inf);
}
-
+
diff --git a/recordmydesktop/src/load_cache.c b/recordmydesktop/src/load_cache.c
new file mode 100644
index 0000000..cd09956
--- /dev/null
+++ b/recordmydesktop/src/load_cache.c
@@ -0,0 +1,187 @@
+/*********************************************************************************
+* 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 johnvarouhakis@gmail.com *
+**********************************************************************************/
+
+
+#include <recordmydesktop.h>
+
+void LoadBlock(unsigned char *dest,unsigned char *source,int blockno,int width, int height,int divisor){
+ int j,
+ block_i=blockno/divisor,//place on the grid
+ block_k=blockno%divisor;
+
+ for(j=0;j<height/divisor;j++)//we copy rows
+ memcpy( &dest[block_i*(width*height/divisor)+j*width+block_k*width/divisor],
+ &source[j*width/divisor],
+ width/divisor);
+}
+
+
+
+void *LoadCache(void *pdata){
+
+ yuv_buffer *yuv=&((ProgData *)pdata)->enc_data->yuv;
+ gzFile *ifp=((ProgData *)pdata)->cache_data->ifp;
+ FILE *afp=((ProgData *)pdata)->cache_data->afp;
+ FrameHeader fheader;
+ CachedFrame frame;
+ signed char *sound_data=(signed char *)malloc(((ProgData *)pdata)->periodsize);
+
+ int j=0,
+ audio_end=0,
+ extra_frames=0,//total number of duplicated frames
+ missing_frames=0,//if this is found >0 current run will not load
+ //a frame but it will proccess the previous
+ thread_exit=0,//0 success, -1 couldn't find files,1 couldn't remove
+ divisor=16,
+ blockszy=0,//size of y plane block in bytes
+ blockszuv=0;//size of u,v plane blocks in bytes
+ //we allocate the frame that we will use
+ INIT_FRAME(&frame,&fheader,yuv)
+ //and the we open our files
+ ifp=gzopen(((ProgData *)pdata)->cache_data->imgdata,"rb");
+ if(ifp==NULL){
+ thread_exit=-1;
+ pthread_exit(&thread_exit);
+ }
+
+ if(!((ProgData *)pdata)->args.nosound){
+ afp=fopen(((ProgData *)pdata)->cache_data->audiodata,"rb");
+ if(afp==NULL){
+ thread_exit=-1;
+ pthread_exit(&thread_exit);
+ }
+ }
+ //these two are likely to be the same, but not guaranteed, especially on
+ //low resolutions
+ blockszy=(yuv->y_width*yuv->y_height )/pow(divisor,2);
+ blockszuv=(yuv->uv_width*yuv->uv_height)/pow(divisor/2,2);
+
+ //this will be used now to define if we proccess audio or video
+ //on any given loop.
+ ((ProgData *)pdata)->avd=0;
+ //If sound finishes first,we go on with the video.
+ //If video ends we will do one more run to flush audio in the ogg file
+
+ while(((ProgData *)pdata)->running){
+ //video load and encoding
+ if(((ProgData *)pdata)->avd<=0 || ((ProgData *)pdata)->args.nosound || audio_end){
+ if(missing_frames>0){
+ extra_frames++;
+ missing_frames--;
+ SyncEncodeImageBuffer((ProgData *)pdata);
+ }
+ else if(gzread(ifp,frame.header,sizeof(FrameHeader))==sizeof(FrameHeader)){
+ //sync
+ missing_frames+=frame.header->current_total-(extra_frames+frame.header->frameno);
+ fprintf(stdout,"\r[%d%%] ",
+ ((frame.header->frameno+extra_frames)*100)/frames_total);
+
+ fflush(stdout);
+ if( (frame.header->Ynum<=pow(divisor,2)) &&
+ (frame.header->Unum<=pow(divisor/2,2)) &&
+ (frame.header->Vnum<=pow(divisor/2,2)) &&
+ (gzread(ifp,frame.YBlocks,frame.header->Ynum)==frame.header->Ynum) &&
+ (gzread(ifp,frame.UBlocks,frame.header->Unum)==frame.header->Unum) &&
+ (gzread(ifp,frame.VBlocks,frame.header->Vnum)==frame.header->Vnum) &&
+ (gzread(ifp,frame.YData,blockszy*frame.header->Ynum)==blockszy*frame.header->Ynum) &&
+ (gzread(ifp,frame.UData,(blockszuv*frame.header->Unum))==(blockszuv*frame.header->Unum)) &&
+ (gzread(ifp,frame.VData,(blockszuv*frame.header->Vnum))==(blockszuv*frame.header->Vnum))){
+ //load the blocks for each buffer
+ if(frame.header->Ynum)
+ for(j=0;j<frame.header->Ynum;j++)
+ LoadBlock( yuv->y,
+ &frame.YData[j*blockszy],
+ frame.YBlocks[j],
+ yuv->y_width,
+ yuv->y_height,
+ divisor);
+ if(frame.header->Unum)
+ for(j=0;j<frame.header->Unum;j++)
+ LoadBlock( yuv->u,
+ &frame.UData[j*blockszuv],
+ frame.UBlocks[j],
+ yuv->uv_width,
+ yuv->uv_height,
+ divisor/2);
+ if(frame.header->Vnum)
+ for(j=0;j<frame.header->Vnum;j++)
+ LoadBlock( yuv->v,
+ &frame.VData[j*blockszuv],
+ frame.VBlocks[j],
+ yuv->uv_width,
+ yuv->uv_height,
+ divisor/2);
+ //encode. This is not made in a thread since now blocking is not a problem
+ //and this way sync problems can be avoided more easily.
+ SyncEncodeImageBuffer((ProgData *)pdata);
+ }
+ else{
+ raise(SIGINT);
+ continue;
+ }
+ }
+ else{
+ raise(SIGINT);
+ continue;
+ }
+ }
+ //audio load and encoding
+ else{
+ if(!audio_end){
+ int nbytes=fread(sound_data,((ProgData *)pdata)->periodsize,1,afp);
+ if(nbytes<=0)
+ audio_end=1;
+ else
+ SyncEncodeSoundBuffer((ProgData *)pdata,sound_data);
+ }
+ }
+ }
+ fprintf(stdout,"\n");
+ CLEAR_FRAME(&frame)
+ free(sound_data);
+ gzclose(ifp);
+
+ if(remove(((ProgData *)pdata)->cache_data->imgdata)){
+ fprintf(stderr,"Couldn't remove temporary file %s",((ProgData *)pdata)->cache_data->imgdata);
+ thread_exit=1;
+ }
+ if(!((ProgData *)pdata)->args.nosound){
+ fclose(afp);
+ if(remove(((ProgData *)pdata)->cache_data->audiodata)){
+ fprintf(stderr,"Couldn't remove temporary file %s",((ProgData *)pdata)->cache_data->audiodata);
+ thread_exit=1;
+ }
+ }
+ if(remove(((ProgData *)pdata)->cache_data->projname)){
+ fprintf(stderr,"Couldn't remove temporary directory %s",((ProgData *)pdata)->cache_data->projname);
+ thread_exit=1;
+ }
+
+ pthread_exit(&thread_exit);
+
+
+}
+
diff --git a/recordmydesktop/src/parseargs.c b/recordmydesktop/src/parseargs.c
index 5280cf2..c7d20fd 100644
--- a/recordmydesktop/src/parseargs.c
+++ b/recordmydesktop/src/parseargs.c
@@ -32,11 +32,11 @@ 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-display DISPLAY| -x X| -y Y|-width N| -height N| -fps N(number>0)| --on-the-fly-encoding|\n"
"\t -v_quality n| -s_quality n| -v_bitrate n| --no-framedrop| -dummy-cursor color|\n"
"\t --no-cursor| -freq N(number>0)| -channels N(number>0)| -device SOUND_DEVICE|\n"
- "\t --nosound| --with-shared| --no-cond-shared| -shared-threshold n| --full-shots|\n"
- "\t --quick-subsampling| --scshot| -scale-shot N| -o filename]^filename\n\n\n"
+ "\t --no-sound| --with-shared| --no-cond-shared| -shared-threshold n| --full-shots|\n"
+ "\t --quick-subsampling| -workdir DIR| --zero-compression| --no-wm-check| --overwite| -o filename]^filename\n\n\n"
"General Options:\n"
"\t-h or --help\t\tPrint this help and exit.\n"
@@ -51,7 +51,7 @@ int ParseArgs(int argc,char **argv,ProgArgs *arg_return){
"\t-height N\t\tHeight of recorded window.\n\n"
"\t-dummy-cursor color\tColor of the dummy cursor [black|white]\n"
- "\t--no-cursor\tDisable drawing of the cursor.\n"
+ "\t--no-cursor\t\tDisable drawing of the cursor.\n"
"\t--with-shared\t\tEnable usage of MIT-shared memory extension at all times.\n"
"\t--no-cond-shared\tDo not use the MIT-shared memory extension when aquiring large areas.\n"
"\t-shared-threshold n\tThreshold over which shared memory is used(default 75).\n"
@@ -63,18 +63,22 @@ int ParseArgs(int argc,char **argv,ProgArgs *arg_return){
"\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"
+ "\t--no-sound\t\tDo not record sound.\n\n"
"Encoding Options\n"
+ "\t--on-the-fly-encoding\tEncode the audio-video data, while recording.\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--drop-frames\t\tAllow theora encoder to drop frames.\n"
"\t-s_quality n\t\tDesired audio quality(-1 to 10).\n\n"
"Misc Options:\n"
+ "\t--no-wm-check\tDo not try to detect the window manager(and set options according to it)\n"
+ "\t--zero-compression\tImage data are always cached uncompressed.\n"
+ "\t-workdir DIR\t\tLocation where a temporary directory will be created to hold project files(default $HOME).\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--overwrite\t\tIf there is already a file with the same name, delete it\n"
+ "\t\t\t\t(default is to add a number postfix to the new one).\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";
@@ -279,7 +283,7 @@ int ParseArgs(int argc,char **argv,ProgArgs *arg_return){
return 1;
}
arg_return->have_dummy_cursor=1;
- arg_return->xfixes_cursor=0;
+ arg_return->xfixes_cursor=0;
}
else{
fprintf(stderr,"Argument Usage: -dummy-cursor [black|white]\n");
@@ -353,37 +357,31 @@ int ParseArgs(int argc,char **argv,ProgArgs *arg_return){
}
i++;
}
- else if(!strcmp(argv[i],"-scale-shot")){
+ else if(!strcmp(argv[i],"-device")){
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;
- }
+ free(arg_return->device);
+ arg_return->device=malloc(strlen(argv[i+1])+1);
+ strcpy(arg_return->device,argv[i+1]);
}
else{
- fprintf(stderr,"Argument Usage: -scale-shot N(0<number<64,power of 2)\n");
+ fprintf(stderr,"Argument Usage: -device SOUND_DEVICE\n");
return 1;
}
i++;
}
- else if(!strcmp(argv[i],"-device")){
+ else if(!strcmp(argv[i],"-workdir")){
if(i+1<argc){
- free(arg_return->device);
- arg_return->device=malloc(strlen(argv[i+1])+1);
- strcpy(arg_return->device,argv[i+1]);
+ free(arg_return->workdir);
+ arg_return->workdir=malloc(strlen(argv[i+1])+1);
+ strcpy(arg_return->workdir,argv[i+1]);
}
else{
- fprintf(stderr,"Argument Usage: -device SOUND_DEVICE\n");
+ fprintf(stderr,"Argument Usage: -workdir DIR\n");
return 1;
}
i++;
}
- else if(!strcmp(argv[i],"--nosound"))
+ else if(!strcmp(argv[i],"--no-sound"))
arg_return->nosound=1;
else if(!strcmp(argv[i],"--drop-frames"))
arg_return->dropframes=1;
@@ -397,13 +395,19 @@ int ParseArgs(int argc,char **argv,ProgArgs *arg_return){
arg_return->full_shots=1;
arg_return->nocondshared=1;
}
- else if(!strcmp(argv[i],"--scshot")){
- arg_return->scshot=1;
- arg_return->nocondshared=1;
- }
else if(!strcmp(argv[i],"--quick-subsampling")){
arg_return->no_quick_subsample=0;
}
+ else if(!strcmp(argv[i],"--on-the-fly-encoding")){
+ arg_return->encOnTheFly=1;
+ }
+ else if(!strcmp(argv[i],"--overwrite"))
+ arg_return->overwrite=1;
+ else if(!strcmp(argv[i],"--no-wm-check"))
+ arg_return->nowmcheck=1;
+ else if(!strcmp(argv[i],"--zero-compression")){
+ arg_return->zerocompression=1;
+ }
else if(!strcmp(argv[i],"--help")||!strcmp(argv[i],"-h")){
fprintf(stderr,"%s",usage);
return 1;
@@ -415,7 +419,7 @@ int ParseArgs(int argc,char **argv,ProgArgs *arg_return){
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
index 5433bbc..9bf7ee2 100644
--- a/recordmydesktop/src/poll_damage.c
+++ b/recordmydesktop/src/poll_damage.c
@@ -28,18 +28,48 @@
#include <recordmydesktop.h>
void *PollDamage(void *pdata){
-
- Damage damage;
+ Window root_return,
+ parent_return,
+ *children;
+ unsigned int i,
+ nchildren,
+ inserts=0;
XEvent event;
- int inserts=0;
-
-
- damage= XDamageCreate( ((ProgData *)pdata)->dpy, ((ProgData *)pdata)->brwin.windowid, XDamageReportRawRectangles);
+
+ XSelectInput (((ProgData *)pdata)->dpy,((ProgData *)pdata)->specs.root, SubstructureNotifyMask);
+
+ XQueryTree (((ProgData *)pdata)->dpy,
+ ((ProgData *)pdata)->specs.root,
+ &root_return,
+ &parent_return,
+ &children,
+ &nchildren);
+
+ for (i = 0; i < nchildren; i++){
+ XWindowAttributes attribs;
+ if (XGetWindowAttributes (((ProgData *)pdata)->dpy,children[i],&attribs)){
+ if (!attribs.override_redirect && attribs.depth==((ProgData *)pdata)->specs.depth)
+ XDamageCreate (((ProgData *)pdata)->dpy, children[i],XDamageReportRawRectangles);
+ }
+ }
+
+ 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
+ //30/10/2006 : when and why did I write the above line? what did I mean?
XNextEvent(((ProgData *)pdata)->dpy,&event);
- if(event.type == ((ProgData *)pdata)->damage_event + XDamageNotify ){
+ if (event.type == MapNotify ){
+ XWindowAttributes attribs;
+ if (!((XMapEvent *)(&event))->override_redirect && XGetWindowAttributes (((ProgData *)pdata)->dpy,
+ event.xcreatewindow.window,
+ &attribs)){
+ if (!attribs.override_redirect && attribs.depth==((ProgData *)pdata)->specs.depth)
+ XDamageCreate (((ProgData *)pdata)->dpy,event.xcreatewindow.window,XDamageReportRawRectangles);
+ }
+ }
+ else if(event.type == ((ProgData *)pdata)->damage_event + XDamageNotify ){
XDamageNotifyEvent *e =(XDamageNotifyEvent *)( &event );
WGeometry wgeom;
CLIP_EVENT_AREA(e,&(((ProgData *)pdata)->brwin),&wgeom);
@@ -51,6 +81,7 @@ void *PollDamage(void *pdata){
pthread_mutex_unlock(&((ProgData *)pdata)->list_mutex[tlist_sel]);
}
}
+
}
pthread_exit(&errno);
}
diff --git a/recordmydesktop/src/recordmydesktop.c b/recordmydesktop/src/recordmydesktop.c
index 6b9e003..77c08ce 100644
--- a/recordmydesktop/src/recordmydesktop.c
+++ b/recordmydesktop/src/recordmydesktop.c
@@ -51,12 +51,16 @@ int main(int argc,char **argv){
}
else{
EncData enc_data;
+ CacheData cache_data;
pthread_t poll_damage_t,
image_capture_t,
image_encode_t,
+ image_cache_t,
sound_capture_t,
sound_encode_t,
- flush_to_ogg_t;
+ sound_cache_t,
+ flush_to_ogg_t,
+ load_cache_t;
XShmSegmentInfo shminfo;
int i;
@@ -67,47 +71,68 @@ int main(int argc,char **argv){
}
if(SetBRWindow(pdata.dpy,&pdata.brwin,&pdata.specs,&pdata.args))
exit(11);
-
+
+
+ //check if we are under compiz or beryl,in which case we must enable full-shots
+ //and with it use of shared memory.User can override this
+ pdata.window_manager=((pdata.args.nowmcheck)?NULL:rmdWMCheck(pdata.dpy,pdata.specs.root));
+ if(pdata.window_manager==NULL){
+ fprintf(stderr,"Not taking window manager into account.\n");
+ }
+ //Right now only wm's that I know of performing 3d compositing are beryl and compiz.
+ //No, the blue screen in metacity doesn't count :)
+ //names can be compiz for compiz and beryl/beryl-co/beryl-core for beryl(so it's strncmp )
+ else if(!strcmp(pdata.window_manager,"compiz") || !strncmp(pdata.window_manager,"beryl",5)){
+ fprintf(stderr,"\nDetected 3d compositing window manager.\n"
+ "Reverting to full screen capture at every frame.\n"
+ "To disable this check run with --no-wm-check\n"
+ "(though that is not advised, since it will probably produce faulty results).\n\n");
+ pdata.args.full_shots=1;
+ pdata.args.noshared=0;
+ pdata.args.nocondshared=1;
+ }
+
QueryExtensions(pdata.dpy,&pdata.args,&pdata.damage_event, &pdata.damage_error);
- //init data
+
+ //init data
+
//these are globals, look for them at the header
frames_total=frames_lost=encoder_busy=capture_busy=0;
- if(!pdata.args.scshot){
- fprintf(stderr,"Initializing...\n");
- MakeMatrices();
- 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;
- }
+ fprintf(stderr,"Initializing...\n");
+ MakeMatrices();
+ 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))
+
+ if((pdata.args.noshared))
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.libogg_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=pdata.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)){
+
+ 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.libogg_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=pdata.avd=0;
+ pdata.running=1;
+ time_cond=&pdata.time_cond;
+ pause_cond=&pdata.pause_cond;
+ Running=&pdata.running;
+
+ if((pdata.args.noshared)){
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);
@@ -115,7 +140,7 @@ int main(int argc,char **argv){
pdata.brwin.rgeom.width,pdata.brwin.rgeom.height);
}
if((!pdata.args.noshared)||(!pdata.args.nocondshared)){
- pdata.shimage=XShmCreateImage (pdata.dpy,pdata.specs.visual,pdata.specs.depth,ZPixmap,pdata.datash,
+ pdata.shimage=XShmCreateImage (pdata.dpy,pdata.specs.visual,pdata.specs.depth,ZPixmap,pdata.datash,
&shminfo, pdata.brwin.rgeom.width,pdata.brwin.rgeom.height);
shminfo.shmid = shmget (IPC_PRIVATE,
pdata.shimage->bytes_per_line * pdata.shimage->height,
@@ -128,18 +153,6 @@ int main(int argc,char **argv){
}
XShmGetImage(pdata.dpy,pdata.specs.root,pdata.shimage,pdata.brwin.rgeom.x,pdata.brwin.rgeom.y,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){
@@ -147,12 +160,18 @@ int main(int argc,char **argv){
exit(3);
}
}
- InitEncoder(&pdata,&enc_data);
+
+ if(pdata.args.encOnTheFly)
+ InitEncoder(&pdata,&enc_data,0);
+ else
+ InitCacheData(&pdata,&enc_data,&cache_data);
+
for(i=0;i<(pdata.enc_data->yuv.y_width*pdata.enc_data->yuv.y_height);i++)
pdata.enc_data->yuv.y[i]=0;
for(i=0;i<(pdata.enc_data->yuv.uv_width*pdata.enc_data->yuv.uv_height);i++){
pdata.enc_data->yuv.v[i]=pdata.enc_data->yuv.u[i]=127;
}
+
if((pdata.args.nocondshared)&&(!pdata.args.noshared)){
if(pdata.args.no_quick_subsample){
UPDATE_YUV_BUFFER_IM_AVG((&pdata.enc_data->yuv),((unsigned char*)pdata.shimage->data),
@@ -189,50 +208,120 @@ int main(int argc,char **argv){
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.encOnTheFly)
+ pthread_create(&image_encode_t,NULL,EncodeImageBuffer,(void *)&pdata);
+ else
+ pthread_create(&image_cache_t,NULL,CacheImageBuffer,(void *)&pdata);
+
if(!pdata.args.nosound){
pthread_create(&sound_capture_t,NULL,CaptureSound,(void *)&pdata);
- pthread_create(&sound_encode_t,NULL,EncodeSoundBuffer,(void *)&pdata);
+ if(pdata.args.encOnTheFly)
+ pthread_create(&sound_encode_t,NULL,EncodeSoundBuffer,(void *)&pdata);
+ else
+ pthread_create(&sound_cache_t,NULL,CacheSoundBuffer,(void *)&pdata);
}
- pthread_create(&flush_to_ogg_t,NULL,FlushToOgg,(void *)&pdata);
-
+ if(pdata.args.encOnTheFly)
+ 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);
+ //if no damage events have been received the thread will get stuck
+ pthread_cond_broadcast(&pdata.image_buffer_ready);
+ if(pdata.args.encOnTheFly)
+ pthread_join(image_encode_t,NULL);
+ else
+ pthread_join(image_cache_t,NULL);
+
+
fprintf(stderr,".");
if(!pdata.args.nosound){
int *snd_exit;
- pthread_join(sound_capture_t,(&snd_exit));
+ pthread_join(sound_capture_t,(void *)(&snd_exit));
fprintf(stderr,".");
- if(!(*snd_exit))
- pthread_join(sound_encode_t,NULL);
+
+ if(pdata.args.encOnTheFly){
+ if(!(*snd_exit))
+ pthread_join(sound_encode_t,NULL);
+ else{
+ pthread_cancel(sound_encode_t);
+ exit_status=*snd_exit;
+ }
+ }
else{
- pthread_cancel(sound_encode_t);
- exit_status=*snd_exit;
+ if(!(*snd_exit))
+ pthread_join(sound_cache_t,NULL);
+ else{
+ pthread_cancel(sound_cache_t);
+ exit_status=*snd_exit;
+ }
}
- fprintf(stderr,".");
}
else
fprintf(stderr,"..");
- pthread_join(flush_to_ogg_t,NULL);
+
+ if(pdata.args.encOnTheFly)
+ pthread_join(flush_to_ogg_t,NULL);
fprintf(stderr,".");
+
if(!pdata.args.full_shots)
pthread_join(poll_damage_t,NULL);
+
+
fprintf(stderr,".");
if((!pdata.args.noshared)||(!pdata.args.nocondshared)){
XShmDetach (pdata.dpy, &shminfo);
-// XDestroyImage (pdata.image);
shmdt (&shminfo.shmaddr);
shmctl (shminfo.shmid, IPC_RMID, 0);
}
fprintf(stderr,"\n");
+
+
+ //Now that we are done with recording we cancel the timer
+ CancelTimer();
+
+/** Encoding */
+ if(!pdata.args.encOnTheFly){
+ if(!Aborted){
+ fprintf(stderr,"Encoding started!\nThis may take several minutes.\n"
+ "Pressing Ctrl-C will cancel the procedure (resuming will not be possible, but\n"
+ "any portion of the video, which is already encoded won't be deleted).\n"
+ "Please wait...\n");
+ pdata.running=1;
+ InitEncoder(&pdata,&enc_data,1);
+ //load encoding and flushing threads
+ if(!pdata.args.nosound){
+ //before we start loading again
+ //we need to free any left-overs
+ while(pdata.sound_buffer!=NULL){
+ free(pdata.sound_buffer->data);
+ pdata.sound_buffer=pdata.sound_buffer->next;
+ }
+ }
+ pthread_create(&flush_to_ogg_t,NULL,FlushToOgg,(void *)&pdata);
+
+
+ //start loading image and audio
+ pthread_create(&load_cache_t,NULL,LoadCache,(void *)&pdata);
+
+ //join and finish
+ pthread_join(load_cache_t,NULL);
+ fprintf(stderr,"Encoding finished!\nWait a moment please...\n");
+ pthread_join(flush_to_ogg_t,NULL);
+ fprintf(stderr,"Done!!!\n");
+ }
+ }
+/**@_______________________________________________@*/
+
+ //This can happen earlier, but in some cases it might get stuck.
+ //So we must make sure the recording is not wasted.
XCloseDisplay(pdata.dpy);
+
if(Aborted){
if(remove(pdata.args.filename)){
perror("Error while removing file:\n");
diff --git a/recordmydesktop/src/register_callbacks.c b/recordmydesktop/src/register_callbacks.c
index 677fc75..08c528f 100644
--- a/recordmydesktop/src/register_callbacks.c
+++ b/recordmydesktop/src/register_callbacks.c
@@ -56,6 +56,16 @@ void SetRunning(int signum){
Aborted=1;
}
+void CancelTimer(void){
+ struct itimerval value;
+ value.it_interval.tv_sec=
+ value.it_value.tv_sec=
+ value.it_interval.tv_usec=
+ value.it_value.tv_usec=0;
+
+ setitimer(ITIMER_REAL,&value,NULL);
+}
+
void RegisterCallbacks(ProgArgs *args){
struct itimerval value;
diff --git a/recordmydesktop/src/rmd_cache.c b/recordmydesktop/src/rmd_cache.c
new file mode 100644
index 0000000..9cb76d5
--- /dev/null
+++ b/recordmydesktop/src/rmd_cache.c
@@ -0,0 +1,102 @@
+/*********************************************************************************
+* 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 johnvarouhakis@gmail.com *
+**********************************************************************************/
+
+#include <recordmydesktop.h>
+
+void InitCacheData(ProgData *pdata,EncData *enc_data_t,CacheData *cache_data_t){
+ int width,height,offset_x,offset_y,pid;
+ char pidbuf[8];
+
+ //we set the buffer only since there's
+ //no need to initialize the encoder from now.
+ width=((pdata->brwin.rgeom.width + 15) >>4)<<4;
+ height=((pdata->brwin.rgeom.height + 15) >>4)<<4;
+ offset_x=((width-pdata->brwin.rgeom.width)/2)&~1;
+ offset_y=((height-pdata->brwin.rgeom.height)/2)&~1;
+
+ (pdata)->enc_data=enc_data_t;
+
+ enc_data_t->yuv.y=(unsigned char *)malloc(height*width);
+ enc_data_t->yuv.u=(unsigned char *)malloc(height*width/4);
+ enc_data_t->yuv.v=(unsigned char *)malloc(height*width/4);
+ enc_data_t->yuv.y_width=width;
+ enc_data_t->yuv.y_height=height;
+ enc_data_t->yuv.y_stride=width;
+
+ enc_data_t->yuv.uv_width=width/2;
+ enc_data_t->yuv.uv_height=height/2;
+ enc_data_t->yuv.uv_stride=width/2;
+ enc_data_t->x_offset=offset_x;
+ enc_data_t->y_offset=offset_y;
+
+
+ //now we set the cache files
+ (pdata)->cache_data=cache_data_t;
+
+ cache_data_t->workdir=(pdata->args).workdir;
+ pid=getpid();
+
+ I16TOA(pid,pidbuf)
+ //names are stored relatively to current dir(i.e. no chdir)
+ cache_data_t->projname=malloc(strlen(cache_data_t->workdir)+12+strlen(pidbuf)+3);
+ //projname
+ strcpy(cache_data_t->projname,cache_data_t->workdir);
+ strcat(cache_data_t->projname,"/");
+ strcat(cache_data_t->projname,"rMD-session-");
+ strcat(cache_data_t->projname,pidbuf);
+ strcat(cache_data_t->projname,"/");
+ //image data
+ cache_data_t->imgdata=malloc(strlen(cache_data_t->projname)+11);
+ strcpy(cache_data_t->imgdata,cache_data_t->projname);
+ strcat(cache_data_t->imgdata,"img.out.gz");
+ //audio data
+ cache_data_t->audiodata=malloc(strlen(cache_data_t->projname)+10);
+ strcpy(cache_data_t->audiodata,cache_data_t->projname);
+ strcat(cache_data_t->audiodata,"audio.pcm");
+
+ //now that've got out buffers and our filenames we start
+ //creating the needed files
+
+ if(mkdir(cache_data_t->projname,0777)){
+ fprintf(stderr,"Could not create temporary directory %s !!!\n",cache_data_t->projname);
+ exit(13);
+ }
+ cache_data_t->ifp=gzopen(cache_data_t->imgdata,"wb0f");
+ if(cache_data_t->ifp==NULL){
+ fprintf(stderr,"Could not create temporary file %s !!!\n",cache_data_t->imgdata);
+ exit(13);
+ }
+ if(!pdata->args.nosound){
+ cache_data_t->afp=fopen(cache_data_t->audiodata,"wb");
+ if(cache_data_t->afp==NULL){
+ fprintf(stderr,"Could not create temporary file %s !!!\n",cache_data_t->audiodata);
+ exit(13);
+ }
+ }
+
+}
+
+
diff --git a/recordmydesktop/src/wm_check.c b/recordmydesktop/src/wm_check.c
new file mode 100644
index 0000000..ee6b0ba
--- /dev/null
+++ b/recordmydesktop/src/wm_check.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 johnvarouhakis@gmail.com *
+**********************************************************************************/
+
+
+#include <recordmydesktop.h>
+
+char *rmdWMCheck(Display *dpy,Window root){
+
+ Window *wm_child;
+ Atom nwm_atom,
+ utf8_string,
+ wm_name_atom,
+ rt;
+ unsigned long nbytes,
+ nitems;
+
+ char *wm_name_str=NULL;
+ int fmt;
+
+ utf8_string = XInternAtom(dpy, "UTF8_STRING", False);
+
+ nwm_atom =XInternAtom(dpy,"_NET_SUPPORTING_WM_CHECK",True);
+ wm_name_atom =XInternAtom(dpy,"_NET_WM_NAME",True);
+
+ if(nwm_atom!=None && wm_name_atom!=None){
+ if(!((XGetWindowProperty( dpy,root,nwm_atom,0,100,
+ False,XA_WINDOW,
+ &rt,&fmt,&nitems, &nbytes,
+ (unsigned char **)((void*)&wm_child))
+ ==Success ) &&
+ (XGetWindowProperty( dpy,*wm_child,wm_name_atom,0,100,
+ False,utf8_string,&rt,
+ &fmt,&nitems, &nbytes,
+ (unsigned char **)((void*)&wm_name_str))
+ ==Success ))){
+ fprintf(stderr,"Warning!!!\nYour window manager appears to be non-compliant!\n");
+ }
+ }
+ fprintf(stderr,"Your window manager appears to be %s\n\n",
+ ((wm_name_str!=NULL)?wm_name_str:"Uknown"));
+
+
+ return wm_name_str;
+}
+
© All Rights Reserved