Thursday, December 10, 2009

Fixing resolution of C-770 MPEG4 videos

My Olympus C-770 Ultra Zoom camera is supposed to record 640x480 MPEG4 videos. However, some applications instead play the videos at 320x240. For example, QuickTime 6.x and Xvid play the video at 640x480, while QuickTime 7.x and ffdshow play it at 320x240.

My solution up to now was to play the videos using Haali Media Splitter for the .MP4 container and Xvid for decoding. That resolved all the problems for me, but if I sent a file to someone else, they could still end up viewing the video at 320x240. Now I've finally figured out what is wrong with the files themselves.

I started out by compiling mp4v2 in Cygwin. This resulted in some errors, but just re-running make was enough to get the executables compiled. Then I used "mp4file --dump" to examine the contents of the MP4 container. It showed a 320x240 size in two places: the tkhd header for the video track and the stsd atom. QuickTime 7.6.5 uses the tkhd size, and Mplayer 1.0rc1-3.4.2 uses the stsd size. Changing both sizes to 640x480 should make the video always play at 640x480.

After seeing 320x240 at two places in the file and not seeing 640x480, I was left wondering what was the actual resolution of the video. It seems to be 640x480 based on several pieces of supporting evidence:
  • The videos are clearer when decoded at 640x480 than when decoded at 320x240 and scaled up.
  • Even when decoding at 320x240, Mplayer allocates a 640 wide YUV buffer with 320x240 chroma (which should be at half resolution).
  • If I extract the video stream using mp4creator, Mplayer plays the resulting MPEG4 ES stream at 640x480. This is even true if extracting from an unaltered .MP4 file which plays at 320x240.
At this point, I was wondering how to change the tkhd and stsd resolution values. The tkhd values may be changed via mp4track (from mp4v2), but I don't know what program can change the stsd values. After finding that the values aren't protected by any sort of checksum and they occur at the same place in all of my videos, I decided to directly alter all the values without using a tool specifically designed for MP4 container files. The changes which need to be made are:
000000F0: 01 02
000000F1: 40 80
000000F4: 00 01
000000F5: F0 E0
000001B9: 01 02
000001BA: 40 80
000001BB: 00 01
000001BC: F0 E0
This is the output of "fc /b". The first four are lines are tkhd and last four are stsd. Note that the patch is simply changing obvious big endian values.

Now the only problem was how to automatically change these values. I thought I would be able to find a utility which takes "fc /b" or "cmp -l" output, verifies the original bytes and applies the changes. However, I didn't find any simple utilities so I decided to create my own. For fun, I created a sed script which transforms "fc /b" output into a C program which performs the patch. You can download it and the resulting Windows executable.

3 comments:

djenkinsca said...

I have been struggling with that strange playback of my videos from my C-770 for years. Thanks for figuring it out.
I have downloaded the patch but I don't know how to use it. Can you tell me a step by step.
Thanks for your time.
Dwayne

djenkinsca said...

Hi again and thanks again.
I placed c770mp4.exe on the desktop.
Moved the MP4 files to the desktop.
Dragged the MP4 files and dropped them into the c770mp4 and quicker than you could see it, they were fixed. Amazing.
Dwayne

Boris Gjenero said...

Yeah, dropping MP4 files onto the EXE works. I had a lot of videos to fix, so I used the -exec feature of the Unix-type find utility.