Friday, December 21, 2007

Java 1.5 Explained - Varargs

Varargs pretty much does what is sounds like, it adds variable number of arguments support to Java methods. This is very similar to varargs in C and C++, but not exactly the same. Since many Java developers come from C or C++ backgrounds, support for varargs has probably been one of the top most requested features over the years. Along with varargs, Java 1.5 also added support for printf. I really haven't used printf much since I just got used to appending strings together and/or using StringBuffer.

If you read my other blog entry about autoboxing, you'll remember that the Java compiler inserted some extra byte code to autobox and unbox primitive types. Similar things are happing for varargs. Let's look at some code:
public class Varargs
{
public void m(String...args)
{
System.out.println(args[0] + " " + args.length);
}

public static void main(String[] args)
{
Varargs v = new Varargs();
v.m("hi", "there");
}
}
Above you'll see a method that takes a variable number of String objects and within the method you refer to the strings as if they were an array. Well, it turns out they really are an array. So then the call to method m from main must also be doing some array stuff. Let's take a look at the byte code:

public void m(java.lang.String[]);
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: new #3; //class java/lang/StringBuilder
6: dup
7: invokespecial #4; //Method java/lang/StringBuilder."":()V
10: aload_1
11: iconst_0
12: aaload
13: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
16: ldc #6; //String
18: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: aload_1
22: arraylength
23: invokevirtual #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
26: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
29: invokevirtual #9; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
32: return

public static void main(java.lang.String[]);
Code:
0: new #10; //class Varargs
3: dup
4: invokespecial #11; //Method "":()V
7: astore_1
8: aload_1
9: iconst_2
10: anewarray #12; //class java/lang/String
13: dup
14: iconst_0
15: ldc #13; //String hi
17: aastore
18: dup
19: iconst_1
20: ldc #14; //String there
22: aastore
23: invokevirtual #15; //Method m:([Ljava/lang/String;)V
26: return
The first thing to notice is that the method m does take a String[] as an argument. That's what you would have normally used to pass a variable number of strings to a method. Now the compiler is doing this for you.

The next thing to notice is the byte code to call method m from main. You'll see that it's actually creating a String[] of size 2 and assigning the string constants "hi" and "there" to elements 0 and 1 respectively. That's really handy. The compiler writes all the array code for you.

One nice way to get used to programming with varargs is to start using the following:
public static void main(String... args)
instead of:
public static void main(String[] args)
String... and String[] are the same thing.

Thursday, December 20, 2007

Java 1.5 Explained - Autoboxing

Here's the start of a short series on how many of the new language features were added in in Java 1.5. I'm going to start with Autoboxing. Autoboxing is language feature that allows you to write code using primitive types where previously you had to use the object equivalent. For example, the primitive type int not the same as Integer. You can convert between the two manually but that can be cumbersome. There's also extra code required when you're dealing with lists, sets, maps, etc., since you cannot store primitive types in collections.

Let's look at some code:
List list = new ArrayList();
list.add(100); // instead of list.add(new Integer(100));
Adding a primitive int to a list is now super easy.

So how is this actually working? Primitive types are not magically objects in Java 1.5. The 1.5 compiler is doing tricks behind the scenes to make writing code easier. Let's take a look:
List list = new ArrayList();
list.add(100);
list.add(200);
int i = list.get(0);
Integer j = list.get(0);
This code adds two primitive ints to a list and then gets them in two different ways. The compiler generates the following byte code:
0: new #2; //class java/util/ArrayList
3: dup
4: invokespecial #3; //Method java/util/ArrayList."":()V
7: astore_1
8: aload_1
9: bipush 100
11: invokestatic #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
14: invokeinterface #5, 2; //InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
19: pop
20: aload_1
21: sipush 200
24: invokestatic #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
27: invokeinterface #5, 2; //InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
32: pop
33: aload_1
34: iconst_0
35: invokeinterface #8, 2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
40: checkcast #9; //class java/lang/Integer
43: invokevirtual #10; //Method java/lang/Integer.intValue:()I
46: istore_2
47: aload_1
48: iconst_0
49: invokeinterface #8, 2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
54: checkcast #9; //class java/lang/Integer
57: astore_3
Interesting things start on line 11. The compiler added some extra code to call Integer.valueOf(100) so the 100 value can be added to the list. It's the same code you'd normally have to write yourself, but now autoboxing is doing it for you.

Next look at line 35. The generated code is calling the list get method and returning an object. The object is then cast to an Integer and the intValue method is called to obtain the primitive type. Again, it's the same code you'd have to write but you don't have to anymore.

You can compare the byte code for the list.get(0) that returns and Integer. It's the same byte code generated for autoboxing.

You'll see there's some use of generics here since the list.get(0) doesn't have to do any casting to an Integer. I'll cover generics in detail later. That's about it for autoboxing. Go back to enjoying using primitive types and not having to manually create all those Integer and Long objects.

Monday, December 10, 2007

Convert Canon SD600 videos for the Apple TV

The Canon PowerShot SD600 captures video in the following format:

RIFF (little-endian) data, AVI, 640 x 480, 30.00 fps, video: Motion JPEG, audio: uncompressed PCM (mono, 11024 Hz)

Note the fps and resolution can be changed within the camera video settings.

Turns out the SD600 AVI files are not one of the Apple TV supported video formats. I've converted other AVI files to MPEG-4 for the ipod using ffmpeg so I decided to give that a whirl. Some of the files worked while others would display an error in itunes about still not being a supported video format. I read the Apple TV specs page again and noticed the bit about up to 3 Mbps. I guess depending on the video content, ffmpeg was outputting a bitrate higher than 3 Mbps for some videos. The following command is what finally worked for me. You can see the -b option to specify desired bitrate. The actual bitrate in the MPEG-4 files will vary.
ffmpeg -i input.avi -f mp4 -r 30 -b 2Mbps -vcodec mp4 -acodec libfaac ouput.mp4
I've tried this on windows and linux.