iPhone Life magazine

Tutorial with Source Code: Exporting any Video to the Camera Roll

While I'm still working on the Camera Compatibility bible applicable to, among other applications, iMovie and featuring dozens of current cameras, to reduce the (otherwise, large) size of the final article, I've decided to separate (and publish earlier) two, distinct modules from it:

1. Explaining how you can programmatically export your video files to the Camera Roll of your iDevice and;

2. Explaining the secrets of deinterlacing, which will prove very useful for a lot of iOS users as several cameras (even popular, current ones like the Nikon 1-series or the Sony A65) (can) use interlaced recording and the iDevice (including third-party movie editor apps like iMovie) just can't play them back (or, when it comes to iMovie, edit) without some kind of conversion.
Why the need?

Some applications – for example, the above-mentioned iMovie - can only access videos in the Camera Roll on the iDevice but not anywhere else. That is, you can't synchronize the videos to the database of your built-in Videos application (via the “Movies” tab in iTunes). You can't just copy the movie files you need to work on in iMovies using iTunes File Sharing (in the Apps tab of iTunes) either. The reason for the latter is that iMovie, as with iPhoto, can't access any media file copied to its Documents directory via traditional iTunes File Sharing – these two apps can only access the contents of Camera Roll but nothing else.

Unfortunately, iTunes is severely restricted when it comes to video files it will synchronize to your iDevice. Perfectly playable (and, in iMovie, editable!) video files (for example, 1080p60 ones) can in no way be synchronized via iTunes – and the list go on.

There is another way you can import these files into the Camera Roll: by using Apple's own Camera Connection Kit, making sure your videos are all under a “DCIM” directory in the root and have strictly eight-letter (not seven, not nine!) names without even a hyphen (-) or other special, non-alphanumeric characters. However, this is both slow, requires purchasing a Camera Connection Kit and also requires renaming the files before putting them on a (micro/mini/normal) SD card or a USB stick compatible with the kit. Therefore, it's in most cases preferable to use an approach not utilizing the Camera Connection Kit.

The solution

If you don't want to use third-party, commercial (non-free) and, in many cases, because of the Wi-Fi-only transfer, slow(ish) apps like PhotoSync (more on them in the final article), you might want to use mine I've written for exactly this purpose instead; that is, (mass-)importing videos to the Camera Roll.

The main screen is as follows. It lists all the files you copy to it via iTunes File Sharing:

(As usual, click the image for the original, large one. Incidentally, the list shows the test videos of some of the cameras I'll feature in the final "Camera Compatibility bible" mentioned in the preface of this article. Yes, there'll be info on TONS of cameras - as usual, my article will be really instructive!)

Here, when you tap a video name, it'll be checked whether it's compatible. If it isn't, an error message is displayed:



If it is, after importing, the following message is displayed:



(Incidentally, as has already been stated, iOS doesn't support interlaced videos. The output of Sony A65 is interlaced (1080i60). As I don't actively check for interlacing but just ask iOS whether the file I try to import is compatible, I cannot refuse importing interlaced videos. Neither can the commercial PhotoSync, BTW - it also happily imports interlaced videos.)

If, on the other hand, you tap the “+” icon in the upper right corner, all videos you've transferred to its local Documents folder via iTunes File Sharing will be imported to the roll. You'll need to wait until a “All files saved!” dialog appears after tapping “+”. Don't tap the + twice!

Compatibility

Videos you import must be either in the standard MOV / MP4 / M4V or AVI container. (The latter in no way can be synchronized via iTunes, by the way. The usual restrictions apply: AVI's can only contain M-JPEG video etc.)

For MOV / MP4 / M4V files, which must contain H.264 video (but any kind of container-compliant audio: that is, uncompressed PCM is also allowed in addition to the standard AAC), the H.264 level must be 4.1 or below. This means

- several Canon cameras (which record into 1080p30 or 1080p24 but still, absolutely unneededly, use level 5.0), while they do produce MOV files, need to be pre-converted and their H.264 level decreased. Some examples of these, current, incompatible, popular Canon models: S100, SX260 HS, G1 X.

- the H.264 level of files produced by cameras recording into MTS files, after remuxing them into MOV / MP4 / M4V files via iVI [Pro] (please read THIS for more info on all this; make sure you follow the iVI link at the bottom), must also be decreased. All 1080p60 cameras / shots belong to this category; for example, all 1080p60-capable cameras of Sony. After remuxing them via iVI and lowering the H.264 level, you can easily import them via my app – unlike via iTunes, which refuses importing them even with a decreased H.264 level. (Another absolutely unneeded and pretty stupid restriction of iTunes. Or is this “just” a bug?)

Please see THIS for more info on how the H.264 level can be decreased. Note: Subler doesn't recognize many cameras' H.264 level. If you do encounter video files like this, you'll need to re-pack the entire file with avidemux; the output of that tool is already parsable by Subler. It's very easy and will be thoroughly explained in my forthcoming Camera Compatibility bible.

(Actually, if I have the time, I'll implement H.264 level decreasing in my app.)

Availability; sources

As usual, I release the app as an open-source one. The entire project is HERE. Let me know if you have problems compiling / deploying. Feel free to deploy it on your own device. If you don't know how it's done, ask a friend that has an iOS developer license and, therefore, both the right and the tools to do it. I, currently, don't release the app in AppStore. If you absolutely can't find anyone to install the app on your iDevice, let me know and I may create a Cydia version of it (jailbroken devices only, sorry – AppStore publication of such small apps involve too much hassle. Of course, if you compile and deploy the source yourself, you will NOT need jailbreaking.)

And for you (would-be) iOS developers...

The app is very straightforward. As with my previous non-fullscreen video player (see THIS), it's based on a navigation controller. As we don't need detailed view in the project (simple modal dialogs do), I've completely eliminated them and do all the application logic in RootViewController.

In viewDidLoad, I load all the filenames in Documents to the property 'dirContents' and, then, add a “+” button to the nav. controller bar. I pass “addAllFiles” as the method to call back when + is tapped.

Let's start with individual file selection (that is, tapping a filename in the list as opposed to tapping the + button). As usual, didSelectRowAtIndexPath is called back. In there, I index dirContents to get the actual filename tapped and, then, call another, generic (it's called from two methods) utility method, saveVideo, with the filename and an additional false parameter to signal I don't need mass saving.

saveVideo:massSaveNeeded is the longest method as it does all of the work common to both individual and mass file saving. It, first, computes the full path of the file it's passed to. Then, it checks with iOS (see the call to UIVideoAtPathIsCompatibleWithSavedPhotosAlbum) whether the file is compatible. If it isn't, it displays an “Incompatible video!” dialog but, nevertheless, goes on. (I've went for this approach as it was the easiest – otherwise, I would have needed to come up with another, probably much more complicated way of recursion in mass loading mode.)

Now, the standard UISaveVideoAtPathToSavedPhotosAlbum is called to really import the video. If the second argument of our method, massSaveNeeded, is false, then, the completion callback is supplied as “videoSavedCallback:saveResultError:ctx:”; otherwise, as “videoMassSavedCallback:saveResultError:ctx:”.

These two methods are quite different. The first just displays the result of the import (success / false). The second, however, calls saveVideo back. We need to put this callback in this method as, if we didn't wait for the current importing operation to complete (but, for example, called saveVideo from addAllFiles (see below)), we would surely run into “Write busy” errors because of the parallel execution.

If a global variable “callbackCounter” reaches the size of the filename array (dirContents), we stop execution (hence the if (callbackCounter < self.dirContents.count) before the recursive callback call).

Finally, the already-mentioned “addAllFiles” is really simple: first, we set the global “callbackCounter” back to 0 to handle cases of previous mass imports so that the users, if they, for some strange reason, want to mass-import again, can re-run the code. Then, it just passes the first filename in the dirContents array to the already-known saveVideo method – but, now, with “massSaveNeeded” set to true.

That's all – as you can see, with some 20-30 instructions only, such a useful app can easily be coded!

Topics:
Email icon
Want more? Get our weekly newsletter:

Werner Ruotsalainen is an iOS and Java programming lecturer who is well-versed in programming, hacking, operating systems, and programming languages. Werner tries to generate unique articles on subjects not widely discussed. Some of his articles are highly technical and are intended for other programmers and coders.

Werner also is interested in photography and videography. He is a frequent contributor to not only mobile and computing publications, but also photo and video forums. He loves swimming, skiing, going to the gym, and using his iPads. English is one of several languages he speaks.