Showing posts with label linux. Show all posts
Showing posts with label linux. Show all posts

Friday, 6 February 2015

Making custom versions of packages in Ubuntu/Debian

Had to make some changes in the source code of a couple of packages on my system and decided to document the process for future reference. Surprisingly, it's way easier than I thought it would be.

As an example, suppose we want to make the default graphical viewer Eye of Gnome not jump back to the first picture after the last one in a directory (and, similarly, not jump in the opposite direction, either).

First, we need to get the source code for the program
$ mkdir eog; cd eog; apt-get source eog

Then let's install all the needed dependencies to compile the package:
$ sudo apt-get install build-dep eog

All right, time to make the changes we need. In this case, we need to slightly modify the corresponding part in eog_thumb_view_select_single() in src/eog-thumb-view.c to look like this:

        case EOG_THUMB_VIEW_SELECT_LEFT:
            gtk_tree_path_prev (path);
            break;
        case EOG_THUMB_VIEW_SELECT_RIGHT:
            if (gtk_tree_path_get_indices (path) [0] != n_items - 1)
                gtk_tree_path_next (path);
            break;

Now that we've made the changes, let's make our custom package:
$ dpkg-buildpackage -b

The program has been compiled and assembled in one neat package. All that is left is to install it, replacing the standard version:
$ sudo debi

Hooray, we have our custom version of Eye of Gnome installed and operational!

Now if I only knew a way to apply patches and rebuild the packages automatically every time they get an update..

Sunday, 29 June 2014

Play all songs whose names match a regular expression.


#!/bin/sh
locate -0i --regex "($*).*\.(mp3|mpe?g|avi|mkv|ogg|au|m4a|flac)$" | xargs -0 nohup vlc >/dev/null 2>&1 &

Replace vlc with the player of your choice, save as /usr/local/bin/lplay, make it executable with 'sudo chmod +x /usr/local/bin/lplay' - et voila, you can do pretty complex music queries without amarok or any other bulky and buggy music player, provided there is enough information in their file names.

Since locale uses its own pre-built file database, this will be much faster than using "find" that actually traverses the entire file system.

Examples:
$ lplay music/j-pop
# play your J-Pop collection
$ lplay '風|wind|kaze'
# play everything that has the word or kanji "wind" in it

$ lplay 'bob.*dylan'
# play all Bob Dylan's songs

P.S.
Alternatviely, you can filter out audio/video files by their headers instead of using their extensions. It will give more refined results (you may be surprised how many games keep video and music in standard formats with non-standard extensions!), but will be slower, especially for general queries that have a lot of hits that are not music/video files.
locate -0i --regex "$*" | xargs -0 file -0 | grep -Eia 'audio|video' | cut -d '' -f1 | xargs -d\\n nohup vlc >/dev/null 2>&1 &

Saturday, 3 May 2014

Capturing video in Ubuntu 14.04

(Disclamer: never captured video before, must be missing a whole lot of things and optimizations).

The following line will capture 1920x1080 screen at 30 frames per second and is suitable for taking video game footage.

avconv -f x11grab -r 30 -s hd1080 -i :0.0 -f pulse -name 'screencap -> system audio' -i alsa_output.pci-0000_00_1b.0.analog-stereo.monitor -map 0 -map 1  -codec:v libx264 -pre:v lossless_ultrafast -codec:a libmp3lame -threads auto -y captured.avi

If audio & video are out of sync, chances are you have run into yet another bug in Ubuntu.

http://askubuntu.com/questions/336747/audio-and-video-auto-of-sync-when-streaming
https://github.com/MaartenBaert/ssr/issues/16

To fix that, set the 2 following values in  /etc/pulse/daemon.conf:
does storing
default-sample-rate = 44100
alternate-sample-rate = 44100
To get window geometry if you're capturing a window, you can use xwininfo and then change the resolution (-s WxH) and offset (-i :0.0+x_off,y_off) accordingly.

Expect that 1 minute of stream will hog roughly 1GB with these settings for 1080p.

When the capture is done, compress & (optionally)cut:
avconv -i captured.avi -ss FROM_TIME -t LENGTH -vcodec libx264 -pre:v veryslow -acodec libmp3lame result.avi

So why is GNU/Linux not a popular platform for gaming and streaming? Anyone?

Update as of August 22, 2014 (still needs some polish):

The following line allows for real-time capture AND encoding. The line gives a 50 MB/min output and looks like a full replacement to the old one.
avconv -f x11grab -s hd1080 -i :0.0 -f pulse -name 'screencap -> system audio' -i alsa_output.pci-0000_00_1b.0.analog-stereo.monitor -map 0 -map 1  -codec:v libx264 -pre:v ultrafast -codec:a libmp3lame -af asyncts -threads auto -y captured.mkv

add -filter:v scale=960:-1 (or whatever size you prefer) to record downscaled video. Reduces video size and some CPU power (obviously) at the cost of lower resolution.

Seems like the -r parameter specified earlier may actually cause audio/video desync when the encoder cannot keep up with the input. If there is still desync, try loading the game and THEN starting the capture (still don't know what's causing this).

Update as of May 05, 2015:

OBS now natively supports Linux. The up-to-date version that I tried was a bit buggy, but it was still a great improvement over what I had been dealing with before. One small caveat is that it needs ffmpeg instead of avconv, and those two hate each other with passion. It IS possible to install ffmpeg locally in your home directory (without removing avconv) and make OBS use it from there, though you'll probably need to compile ffmpeg and OBS manually to do that (which is fairly straightforward regardless, I must add).

Friday, 21 February 2014

Convenient keyboard layout switching for 3 or more languages in Linux.

I'm using four different keyboard layouts at a semi-regular basis. Switching between them used to be a headache until I came up with the idea of assigning each language a separate key shorcut consisting of a home row character + the Windows(Meta) key.

Since each layout has a separate shortcut, I no longer need to remember what locale I'm currently using and then count how many times I need to press the universal switch key in order to switch to the desired language. In addition, I don't have to move my fingers from the home row except for the pinky to reach the Windows key.

I implemented my scheme on Linux using ibus as the input method framework, xbindkeys as the keyboard shortcut manager and xbindkeysrc-config for config creation.

After installing these components you need to make a config file for xbindkeys (~/.xbindkeysrc) that would define the keyboard shortcuts and locales. Mine turned out to be as follows:
#Japanese
# The new ibus version does not switch from Cyrillic to Japanese for some reason, so we have to switch to English first.
# Replace "anthy" with "mozc-jp" if you're using Mozc.
"ibus engine xkb:us::eng; ibus engine anthy"
m:0x40 + c:44

#English
"ibus engine xkb:us::eng"
m:0x40 + c:45

#Russian
"ibus engine xkb:ru::rus"
m:0x40 + c:46

#Ukrainian
"ibus engine xkb:ua::ukr"
m:0x40 + c:32

#French
"ibus engine xkb:fr::fra"
m:0x40 + c:47
"ibus engine ..." is the console command that makes ibus switch the current layout. Using keycodes is necessary since the same physical keys may represent different characters in different locales.

<LWin+k>Layout switching became easy!
<LWin+j>入力言語の切り替えは簡単になりました!
<LWin+l>Переключение языков стало простым!
<LWin+;>Changement de langue est devenu très simple!

P.S. I think the same result should be achievable in Windows using the AutoHotkey tool, though I haven't looked into it.

Saturday, 4 January 2014

Running applications so that they wouldn't close when you close the console

Nohup.

But since it litters nohup.outs everywhere let's make a custom shortcut script for launching it:

#!/bin/sh
nohup "$@" >/dev/null 2>&1 &

Just save it as nh into a bin dir and you can use it:

$ nh wine 2hu.exe
$ nh vlc reincarnation.mp3
$ exit

And applications keep on running! Why did I not bother learning about this useful command earlier?

Wednesday, 1 August 2012

Broken encoding in Japanese ZIP files.

After a long and painful road I found a way to properly list file names in the archive using 7z:

> LANG=C 7z l ファイル | iconv -c -f SJIS -t utf8

A little more googling afterwards revealed a blog post with the complete and satisfactory solution, which I modify for more automation (in order to not mess up the other files, the archive should be extracted in an empty directory):

> LANG=C 7z x ファイル ; find -exec convmv --notest -f shift-jis -t utf8 {} \;

Finally, there exists a patch called unzip-iconv which is supposed to add the option that specifies what encoding the archive uses. Too bad it's not in Squeeze.


Wednesday, 20 April 2011

Accessing a deleted file which is still open in Linux.

As you may know, Linux does not actually delete a file from a disk until
1) all the (hard) links to it are deleted in the file system
2) no programs still use that file (i.e. there are no open file descriptors)

For example, if you delete a video file from a disk but still have an open media player with it, the file won't be deleted until you close the app or open a new movie instead of it. To access the file you've got to know the PID of the program using it (you can get it with "ps") and its file descriptor in it. Linux provides a simple interface to access open files through the /proc pseudo-file system: /proc/<pid>/fd/<fd>.

How can this be useful?

Apart from the case shown above, the last versions of the Flash plugin seem to use this trick to prevent the user from easily copying video files from the /tmp directory. In fact, the videos are still created, but they are deleted as soon as Flash opens them. This trick makes it possible to save the "deleted" .flv files nevertheless.

Finally, the very way Linux makes access through file descriptors possible for a user just looks like a very neat and simple solution of a rather complex issue. ♥

P.S. Seems to be a popular issue with many howtos and step-by-step tutorials, but oh well.

Saturday, 2 April 2011

No such file or directory after ld.

I was toying with the Linux development tools trying to figure out the whole compilation process of a program (something I should have done a loooong time ago) and ran into this interesting error. Or, rather, quite a boring one, but with a baffling manifestation for a permanent newbie like me.

What I wanted to do was to go through the whole source->compiler->assembler->linker->binary tool invocation chain manually instead of relying on GCC. I made a typical C program:
#include <stdio.h>

main()
{
printf ("Le ha-ha.\n");
}
Ran a typical compiler with the -S option to get a typical assembly source rather than a typical ready-to-go binary:
gcc -S hello.c -o hello.S
Assembled it into a typical ELF object file:
as hello.S -o hello.o
And, finally linked it with libc containing printf() and the crt* wrappers.
ld hello.o /usr/lib/crt* /usr/lib/libc.so -o hello
I say, that was quite simple! Let's run the bastard!
$ ./hello
bash: ./hello: No such file or directory
Huh? I guess there WAS an error, but the stupid tools didn't report it. Let's see which file is missing:
$ ls
hello hello.c hello.o hello.S
Err, what? The binary is present? What about the permissions?
$ ls -lh ./hello
-rwxr-xr-x 1 * * 4.3K 2011-04-03 03:43 hello
WTF?
$ file hello
hello: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped
So the file actually EXISTS and it IS executale. However, when I run it, the system says it's absent.

Guess what? Linux actually doesn't find one file when I invoke my program, however, it is not my binary.

Let's dive into the details. If you run GCC with the -v option, it prints all the commands it executes. You can find the linking stage there too, although it's performed through a wrapper called collect2. My line was the following:
"/usr/lib/gcc/i486-linux-gnu/4.4.1/collect2" "--build-id" "--eh-frame-hdr" "-m" "elf_i386" "--hash-style=both" "-dynamic-linker" "/lib/ld-linux.so.2" "-z" "relro" "/usr/lib/gcc/i486-linux-gnu/4.4.1/../../../../lib/crt1.o" "/usr/lib/gcc/i486-linux-gnu/4.4.1/../../../../lib/crti.o" "/usr/lib/gcc/i486-linux-gnu/4.4.1/crtbegin.o" "-L/usr/lib/gcc/i486-linux-gnu/4.4.1" "-L/usr/lib/gcc/i486-linux-gnu/4.4.1" "-L/usr/lib/gcc/i486-linux-gnu/4.4.1/../../../../lib" "-L/lib/../lib" "-L/usr/lib/../lib" "-L/usr/lib/gcc/i486-linux-gnu/4.4.1/../../.." "-L/usr/lib/i486-linux-gnu" "/tmp/ccWw7lET.o" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "/usr/lib/gcc/i486-linux-gnu/4.4.1/crtend.o" "/usr/lib/gcc/i486-linux-gnu/4.4.1/../../../../lib/crtn.o"
After some trial and error I found out that the option I needed was this:
"-dynamic-linker" "/lib/ld-linux.so.2"
It specifies the name of the dynamic linker that will be used on program invocation. But how on earth was I supposed to know that the default dynamic linker wasn't good if the manpage for ld says:
The default dynamic linker is normally correct; don't use this unless you know what you are doing.
Liars. Let's find out what the default linker is:
$ ld hello.o /usr/lib/crt* /usr/lib/libc.so -o hello.without.explicit.dl
$ ./hello.without.explicit.dl
bash: ./hello.without.explicit.dl: No such file or directory
$ ld --dynamic-linker=/lib/ld-linux.so.2 hello.o /usr/lib/crt* /usr/lib/libc.so -o hello.with.explicit.dl
$ ./hello.with.explicit.dl
Le ha-ha.
$ objdump -s hello.without.explicit.dl > hello.without.explicit.dl.objdump
$ objdump -s hello.with.explicit.dl > hello.with.explicit.dl.objdump
$ diff -C1 hello.with.explicit.dl.objdump hello.without.explicit.dl.objdump
*** hello.with.explicit.dl.objdump 2011-04-03 04:14:11.000000000 +0400
--- hello.without.explicit.dl.objdump 2011-04-03 04:14:00.000000000 +0400
***************
*** 1,7 ****

! hello.with.explicit.dl: file format elf32-i386

Contents of section .interp:
! 8048114 2f6c6962 2f6c642d 6c696e75 782e736f /lib/ld-linux.so
! 8048124 2e3200 .2.
Contents of section .note.ABI-tag:
--- 1,7 ----

! hello.without.explicit.dl: file format elf32-i386

Contents of section .interp:
! 8048114 2f757372 2f6c6962 2f6c6962 632e736f /usr/lib/libc.so
! 8048124 2e3100 .1.
Contents of section .note.ABI-tag:
The only difference was the string value in the .interp section (which apparently specifies the path to the dynamic loader). And instead of /usr/lib/libc.so.1 what I needed was /lib/ld-linux.so.2. So... What does libc.so.1 look like?
$ ls /usr/lib/libc.so.1
ls: cannot access /usr/lib/libc.so.1: No such file or directory
There we have it. So the error we saw was the error about a missing dynamic loader, not the binary itself! But how was I supposed to know that from that message without stepping on this rake once? Beats me.

A query to Google shows that /usr/lib/libc.so.1 is used on SCO UnixWare systems, not Linux. Why ld doesn't put the proper linker name on an i386 Ubuntu system and, on top of that, confuses the user by saying not to touch the --dynamic-linker option is another question I can't answer.

Finally, it seems that the older Linux systems used to complain about a "bad ELF interpreter" which was kind of right. I wonder if the modern behaviour can be considered a bug.

Lesson learned? Even robust tools used for many years on a multitude of platforms may try to trick you. Especially robust tools used for many years on a multitude of platforms.

Tuesday, 16 November 2010

No English text in Symphonic Rain

Note to self: don't forget to add (and probably modify first) SR.reg (located in the game's directory) to your registry before wondering why you cannot see any English text. Indeed, sometimes the issue may lie not in the "alternative" OS (works fine in Wine, woohoo!), but somewhere in between the keyboard and the chair.

P.S. The songs are charming and the game mechanics looks really fun, mind you, I've never played Guitar Hero or other rhytm games. The only one thing that's bothering me is that after 5 attempts I managed to get only 4 stars for the intro song. My years of piano practice went for nothing.

Monday, 11 October 2010

Running Tsukihime on Ubuntu Linux.

Late yesterday evening, when I was heading home, pondering whatever people usually ponder in cold dark evenings, I saw the moon. It is quite rare to see it so clear in the town where I live, but there it was, big, incredibly beautiful, with a tinge of blue. Long story short, that hit the trigger in my head and I got a strong urge to play the Moon Princess again.

There is one problem, though: my desktop PC is running Linux. Actually, the problem is not that big, because the English translation of Tsukihime uses the ONScripter engine, which is open source and multi-platform. And although Mirror Moon, the folks who translated Tsukihime, did not release a separate set of binaries for Linux, they were very kind to provide their patch for Onscripter-en to make things work.
http://mirrormoon.org/news/2007-01-15-tsukihime_english_for_linux_and_osx

Just as it is always happening, the actual process is harder than it is supposed to be and has a couple of unexpected caveats. To begin with, you may have discovered that the Ubuntu repo actually has the Onscripter package. Well, surprise! It won't work with the game, because it does not have the patch! So let's compile the game from the source instead.

Let's get these two files:
$ ls
onscripter-20060724-insani.src.zip  onscripter-20060724-insani-zalas.patch2

Then unzip onscripter:
$ unzip onscripter-20060724-insani.src.zip ; cd onscripter-20060724-insani

Now let's apply the patch:
$ patch -p1 < ../onscripter-20060724-insani-zalas.patch2

After that, install all the dependences mentioned in the README file. You will know you're missing something if the compilation fails saying there is no header file.

Now, after these steps we WERE supposed to get a working binary by just running:
$ make -f Makefile.Linux.insani


However, there is a problem:


...
ONScripterLabel_command.cpp: In member function ‘int ONScripterLabel::savescreenshotCommand()’:
ONScripterLabel_command.cpp:861: error: invalid conversion from ‘const char*’ to ‘char*’
ONScripterLabel_command.cpp: In member function ‘int ONScripterLabel::exbtnCommand()’:
ONScripterLabel_command.cpp:2225: warning: suggest parentheses around ‘&&’ within ‘||’
make: *** [ONScripterLabel_command.o] Error 1



This is simple. GCC has become more strict since the time this code was written, so we need to re-declare *ext on line 861 from char * to const char *. Now, can we have the working program?

$ make -f Makefile.Linux.insani
...
/usr/bin/ld: cannot find -lartsc
collect2: ld returned 1 exit status
make: *** [onscripter] Error 1



Not yet! The Arts sound library which we are missing here is outdated, and it's not available in the modern Ubuntu distros. Instead, a compatible sound interface is provided through PulseAudio, which is default nowadays. After a lot of googling, I finally figured out the solution: you should substitute -lartsc with -lpulse inside Makefile.Linux.insani in the uncommented "LIBS = ..." string. In addition, you must get rid of "-static", because there is no static version of libpulse-simple which you will need. (Actually, I have no idea why static linking was enabled in the first place). After these changes, LIBS should look like this:

LIBS = -z muldefs -Wl,--start-group `sdl-config --static-libs` `smpeg-config --libs` -lSDL_ttf -lfreetype -lSDL_image -ltiff -lpng -lSDL_mixer -lbz2 -lz -ljpeg -lm -lvorbis -lvorbisenc -lvorbisfile -logg -lgpm -lncurses -lslang -ldirectfb -lfusion -ldirect -lvga -ldl -lesd -lpulse -lasound -lX11 -laa -Wl,--end-group

$ make -f Makefile.Linux.insani

Finally, the binary is ready! After copying it to the game dir (or vice versa), all the preparations have been made, and we can enjoy the game:

$ ./onscripter
ONScripter version 20060724-insani(2.55)
Autodetect: insanity spirit detected!
Display: 640 x 480 (32 bpp)
Audio: 44100 Hz 16 bit stereo


P.S. The steps above were valid for Ubuntu 9.10 Karmic Koala. Chances are very high that the steps for 10.04 and 10.10 will be exactly the same.