Creating iPhone-compatible movies with PyObjC and QTKit

As part of some general messing around with PyObjC and QTKit, I wrote a short script for converting a movie (anything readable by QuickTime) into an iPhone-compatible format. It's basically a Python version of an Objective-C example from Apple.

The code:

#!/usr/bin/python

import struct

import QTKit


class QuickTimeError(Exception):

    @classmethod
    def from_nserror(cls, nserror):
        return cls(nserror.userInfo()['NSLocalizedDescription'])


def long_from_string(s):
    return struct.unpack('>l', s)[0]


def convert_for_iphone(infile, outfile):
    in_attrs = {
        'QTMovieFileNameAttribute': unicode(infile),
        'QTMovieOpenAsyncOKAttribute': False,
        'QTMovieApertureModeAttribute': QTKit.QTMovieApertureModeClean,
        'QTMovieIsActiveAttribute': True,
        }

    movie, error = QTKit.QTMovie.movieWithAttributes_error_(in_attrs, None)
    if movie is None:
        raise QuickTimeError.from_nserror(error)

    out_attrs = {
        'QTMovieExport': True,
        'QTMovieExportType': long_from_string('M4VP'),
        }

    status, error = movie.writeToFile_withAttributes_error_(unicode(outfile),
                                                            out_attrs,
                                                            None)
    if not status:
        raise QuickTimeError.from_nserror(error)


if __name__ == '__main__':
    import sys

    infile = sys.argv[1]
    outfile = sys.argv[2]

    convert_for_iphone(infile, outfile)

To use it:

$ ./convert_for_iphone infile outfile

I've only tested it with the system Python under Leopard. While the script isn't all that useful in itself, it may serve as a helpful example to someone. Sure the hell beats doing the same job with AppleScript.

Tags: apple, iphone, pyobjc, python, qtkit
Wed, 20 Feb 2008 00:11 UTC

2007 Technology Review

Since this is the season for year-end lists, I thought I'd join the fun and write about a few pieces of new technology (both hardware and software) that have had an impact on my life and work over the past year. Note that "new" here means "new to me". Most of the things I discuss below were around prior to 2007, but I didn't catch on to them until this year.

Apple iPhone

This is the one item where I was, in fact, on the bleeding edge: The iPhone went on sale June 29 at 6pm. I bought mine two hours later.

Part of the motivation behind my uncharacteristic early adoption was that I'd been interested in acquiring a smartphone (and thereby eliminating at least one member of my phone/PDA/iPod trio) since the previous fall. At that time, I had looked at a number of devices (of the BlackBerry, Palm, and Windows Mobile varieties), but all of them had abysmally bad interfaces that rendered them basically unusable.

The other factor in my iPhone eagerness was that I simply got caught up in all the hype around the device. Fortunately, the actual product totally lives up to it. The multitouch interface is very intuitive and genuinely a pleasure to use. Mobile Safari is great; I probably do about two-thirds of my feed reading with it. The iPod functionality puts any other device of that name to shame (excluding the iPod touch, of course). The remaining apps are pretty basic, but they're easy to use and generally get the job done.

True, it isn't perfect: Writing e-mail is kind of a pain (thumb typing and no cut-and-paste), and I really, really wish there were some kind of to-do list application. I've also heard a number of people complain about the phone reception (although I haven't had any problems myself, even in my ground-floor apartment).

But the truth is that, despite its flaws, the iPhone simply beats all of its competitors into bloody, unrecognizable pulp, which it then strains into ziplock bags and mails to their mothers. I'd heartily recommend it to anyone.

Bazaar

One piece of technology that has greatly enhanced my productivity is distributed version control. I frequently hack in coffee shops and other places without internet access. In these situations, if the code I'm working on lives in a remote Subversion (or, god forbid, CVS) repository, then I'm unable to commit changes until I get back online. This seriously limits the number and extent of the changes I'm willing to make, since I like to keep my commits granular and relatively small (meaning they're easy to understand and, if necessary, undo).

With distributed version control, this isn't a problem. I can commit to my local branch as often as I like and have full access to the complete repository, including all previous revisions. When I'm back online and want to transfer my updates to another machine, all that's required is a simple push or pull. (If I'm sharing updates with another person who's been working on the same code, then there will be a merge step as well, but that's no more complicated than it would be with a centralized VCS.)

There are a number of distributed version control systems to choose from, and I looked at several. One of the strongest contenders was Git, which is impressive mainly because it's used in the development of the Linux kernel (which I'd imagine is an ideal project for stress-testing any VCS). However, I found Git's command set less than intuitive, and installing it under Mac OS X is a pain. (Yes, I could get it from MacPorts, but MacPorts seems to fail in random ways every time I try to install or upgrade something, so I'm not willing to depend on it for an essential development tool.)

In contrast, Bazaar is simple to build and install (even under Windows), and its command set is easy to use and very natural for someone who's accustomed to Subversion. It's also implemented in Python, which I'll appreciate if I ever need to dive into the source or write a plugin. Overall, I'm extremely happy with it, and I use it daily to manage the source for a number of projects (including the code and entries for this blog).

Google Reader

I was very, very late to the feed reader party. But now that I'm here, I find it hard to believe that I actually used to browse the web. It's just so much simpler to have a machine do it for me.

Since I started using Google Reader, the amount of content (news, blogs, etc.) that I consume daily has probably increased by at least a factor of 10. There's just no way I could ingest that much information if I had to manually poll every site for updates. A feed reader is also a great way to keep track of high-quality but infrequently-updated sites (like Joel on Software); you just subscribe once and then wait to be notified of updates, whenever they arrive.

Of course, I'd get those same benefits from any feed reader. Why choose Google Reader specifically? Here are the main reasons:

  • It's free.
  • It's a web app, which means
    1. I can use it from any machine without the need to synchronize read items or other application data, and
    2. it runs in my normal web browser (Camino), which means I don't have to switch applications when moving between the reader and the sites I'm reading.
  • It works well on mobile devices (and even has a skin tailored specifically to the iPhone).

The only potential downside is that, by using it, I surrender a little more of my privacy to the Googleplex. Meh.

Nintendo DS Lite

Up until a bit over a month ago, the last video game system I owned had been a Sega Game Gear. (Prior to that, I had a first-gen Game Boy, and before that, an Atari 7800. Sadly, I was NES-deprived as a child.) Although I gamed a lot during my first two years of junior high, my interest waned during 8th grade and had totally disappeared by the time I entered high school. Despite a brief relapse during my junior year of college (during which I enjoyed Final Fantasy VII and was seriously baffled by Riven), I thought my gaming days were long past.

Then, after a week on the couch with mono convinced me that I needed more at-home entertainment options, I bought a DS Lite — and I totally love it! The hardware is innovative (dual displays, stylus and touchscreen control, and a microphone that's used in quirky ways), the games are fun and encompass a wide range of genres and styles, and (unlike some other systems) you can actually just go out and buy one. I can see why Nintendo is selling a ridiculous number of them.

Currently, my game library includes Brain Age, Final Fantasy III, Mario Kart DS, and New Super Mario Bros., all of which are high-quality titles. At the moment, I'm in the middle of the excellent Legend of Zelda: Phantom Hourglass, after which I'll probably move on to Final Fantasy XII: Revenant Wings. And now I can't help wondering: Why haven't I been gaming for the past 15 years?

Looking forward …

I'll finish up by mentioning a few things I'm looking forward to in 2008:

Python 3.0
My favorite programming language gets a new major version. Eat your heart out, Perl 6.
iPhone SDK
I'd love to be able to hack on my iPhone (that is, without having to crack it first or use reverse-engineered APIs). Let's just hope that the upcoming SDK is free and open to all and not some pay-to-play bullshit.
iPhone support for CalDAV
I haven't heard any rumors or announcements about this, but I really hope it's coming, since lack of support on the iPhone is the only reason I'm not using CalDAV already.
Apple subnotebook
My 12-inch PowerBook is three years old, and I'd like to replace it with an Intel Mac, but the 15-inch MacBook Pro just seems too big. I hope these rumors materialize into a compelling replacement.

Happy new year, everyone!

Tags: apple, bazaar, gaming, iphone, python
Fri, 28 Dec 2007 21:04 UTC

Setting window and tab names in the Leopard Terminal

Since I'm a Unix person at heart, I spend a lot of time working in terminal windows. Most modern terminal applications (such as those provided by GNOME and KDE) support web-browser-like tabs, which allow you to have multiple interactive shell sessions running in a single window. However, prior to Mac OS X 10.5, Apple's Terminal application didn't have tabs, which rendered it essentially useless for a heavy terminal user like me. (Fortunately, iTerm provided a tab-enabled alternative.)

For the Leopard release, Apple upgraded Terminal to include support for tabs. This is a very welcome (and long overdue) enhancement that puts the stock Mac OS X terminal on par with the previously-superior iTerm … almost. Unfortunately, the support for tabs in Leopard's Terminal has one serious flaw: The title of a tab is always set to the name of the currently-running process, and there's no preference option for overriding it.

In order to keep track of the various tabs I have open, I want the title of each tab to always be the name of the current working directory (not the full path — just the last component). With iTerm, all I had to do to accomplish this was to add the following line to my .bash_profile:

PROMPT_COMMAND='echo -n -e "\e]0;${PWD##*/}\a"'

In brief, this causes bash to set the title of the terminal window to the name of the current directory every time it prints the shell prompt. (For a more detailed explanation, see "How to change the title of an xterm".) In iTerm, this also sets the tab title. Sadly, such is not the case in Terminal; the window title changes, but the tab title is still the name of the current process.

I googled around a bit, hoping someone had already solved this problem for me, but I didn't find anything (although a post by Mike Rodriquez suggested the trick of using hard links to change the tab title). So I was forced to put on my bash-hacker hat and come up with my own solution.

And here it is:

function set_window_and_tab_title
{
    local title="$1"
    if [[ -z "$title" ]]; then
        title="root"
    fi

    local tmpdir=~/Library/Caches/${FUNCNAME}_temp
    local cmdfile="$tmpdir/$title"

    # Set window title
    echo -n -e "\e]0;${title}\a"

    # Set tab title
    if [[ -n ${CURRENT_TAB_TITLE_PID:+1} ]]; then
        kill $CURRENT_TAB_TITLE_PID
    fi
    mkdir -p $tmpdir
    ln /bin/sleep "$cmdfile"
    "$cmdfile" 10 &
    CURRENT_TAB_TITLE_PID=$(jobs -x echo %+)
    disown %+
    kill -STOP $CURRENT_TAB_TITLE_PID
    command rm -f "$cmdfile"
}

PROMPT_COMMAND='set_window_and_tab_title "${PWD##*/}"'

It's not pretty, but it does the job. To use it, just add the above code to your .bash_profile. Since the code works by creating a dummy process with the name of the current directory, you should also change Terminal's "Preferences … → Settings → Shell → Prompt before closing" setting to "Never". Otherwise, whenever you try to close a tab, Terminal will warn you about killing the dummy process, which gets old fast.

Hopefully, Apple will fix the issue with tab titles soon, making my little hack unnecessary. Until then, this will allow me to be as productive in the new Terminal as I was with iTerm.

(Note that iTerm supports a number of other features that aren't present in the new Terminal, so it's definitely worth a look if you use the command line frequently. Personally, the only iTerm feature I ever cared about was tabs, and now that Terminal supports them, I can simplify my life a little by relying on one less piece of third-party software.)

Update: The initial version of my code failed when the working directory was /. I've updated it to set the window and tab title to "root" in that case.

Tags: apple
Sat, 08 Dec 2007 00:42 UTC

« Next    Previous »