August 30, 2011

mjpeg

I recently discovered iTunes U where one can listen to lectures on a variety of topics. Most files that I downloaded from there worked fine on my linux box and on my phone but some of the files failed to play correctly. The specific error message said Too many audio packets in the buffer.

Here's a pseudo-solution.

The files were .m4b files. Which is a container format -- a variant of mp4. They are usually encoded using an mjpeg encoder where each frame is basically a jpeg image.

So the first step is to extract the audio track as an mp3:

> ffmpeg -i input_file.m4b -acodec libmp3lame -ab 192000 out.mp3

Which is a good start. We can now listen to the lecture but we're missing the slides. So we need to extract the jpeg images using the following command line:
> ffmpeg -i input_file.m4b -r 1 frame_%05d.jpg

This will result in a slew of images, one for every second of the lecture. To get rid of the duplicates, I use the following ruby script. It's gross but it mostly works:

 1 #!/usr/bin/env ruby
 2 
 3 Dir.new('.').entries.inject(Hash.new) {|hash, f|
 4 
 5   if File.file? f
 6     puts "removing #{f}"; File.delete(f) if hash[File.size? f]
 7     hash[File.size? f] = f
 8   end
 9   hash
10 

Run this in the directory where the frames are and you should be on your way. Careful, that script will delete stuff.

August 5, 2011

ruby warrior

There is a fun little project on github called ruby warrior. It's an interactive way to learn ruby where you guide a warrior through levels by implementing a simple function that gets called at every turn. I didn't try to achieve the secondary objectives or anything fancy but here's my solution:


 1 class Player
 2   @@ALL_DIRECTIONS = [:forward, :left, :right, :backward]
 3 
 4   def play_turn(warrior)
 5     @warrior = warrior
 6 
 7     begin
 8       rest_if_safe_to_do_so
 9       bind_enemies_if_too_many
10       attack_enemies_if_any
11       attack_captives_if_present
12       move_towards_stairs
13     rescue
14       raise if $!.message != "end of turn"
15     end
16   end
17 
18   def rest_if_safe_to_do_so
19     rest if safe_to_rest? and @warrior.health < 20
20   end
21 
22   def bind_enemies_if_too_many
23     directions_with_enemies = @@ALL_DIRECTIONS.select {|d| @warrior.feel(d).enemy? }
24     bind directions_with_enemies.first if directions_with_enemies.size > 1
25   end
26 
27   def safe_to_rest?
28     @@ALL_DIRECTIONS.all? do |direction|
29       !@warrior.feel(direction).enemy?
30     end
31   end
32 
33   def attack_enemies_if_any
34       @@ALL_DIRECTIONS.each do |direction|
35         space = @warrior.feel direction
36         attack(direction) if space.enemy?
37       end
38   end
39 
40   def attack_captives_if_present
41     directions_with_captives = @@ALL_DIRECTIONS.select {|d| @warrior.feel(d).captive? }
42     attack directions_with_captives.first if !directions_with_captives.empty?
43   end
44 
45   def move_towards_stairs
46       walk @warrior.direction_of_stairs
47   end
48 
49   def attack direction
50     @warrior.attack! direction
51     raise "end of turn"
52   end
53 
54   def walk direction
55     @warrior.walk! direction
56     raise "end of turn"
57   end
58 
59   def rest
60     @warrior.rest!
61     raise "end of turn"
62   end
63 
64   def bind direction
65     @warrior.bind! direction
66     raise "end of turn"
67   end
68 
69 end