My Sangsung camera died while shooting the video of my marriage cerimony leaving a 600MB mp4 file which no player could read. The problem is that the codec information and frame indexes where missing at the end of the mp4. The whole moov section actually (as vlc points out and any hex heditor can confirm):
[00000417] mp4 demux error: MP4 plugin discarded (no moov box)
I could not find any software to find the problem, some arcane parameters for mp4box or ffmpeg might work, I was unable to find them
I wrote a small program using QT, ffmpeg and libfaad which rebuilds the index and, given a complete video as an example, recreates the moov atom, thus rendering the file playable again. The code runs under linux, but it should not be difficult to port to windows (or mac).
There is little hope it works for you as it is, but should not be too difficult to modify it
to suit your needs (provided you can code in C++ and use an hexadecimal editor).
In any case you can contact me at ponchio@gmail.com (just not to complain about the code quality :)
The source code (width instructions) is available at the untrunc project in Github.
Older source code (not uptated anymore) is available here. I just recently rewrote the code to something decent.
Right now all you need is libavformat-dev and libavcodec-dev and libavutil-dev straight from the Ubuntu repositories.
The mp4 (mpeg-4, basically a MOV from Apple)format is roughly described on wiki.multimedia.cx and on Atomic Parsley documentation page. Atomic parsley is a software for tagging mp4, but has the nice feature to display the atom structure of an mp4 (option -T). Here is the output of a sane video:
Atom ftyp @ 0 of size: 32, ends @ 32 Atom free @ 32 of size: 32736, ends @ 32768 Atom mdat @ 32768 of size: 6799742, ends @ 6832510 Atom moov @ 6832510 of size: 5901, ends @ 6838411 Atom mvhd @ 6832518 of size: 108, ends @ 6832626 Atom udta @ 6832626 of size: 48, ends @ 6832674 Atom INFO @ 6832634 of size: 40, ends @ 6832674 Atom trak @ 6832674 of size: 3035, ends @ 6835709 Atom tkhd @ 6832682 of size: 92, ends @ 6832774 Atom mdia @ 6832774 of size: 2935, ends @ 6835709 Atom mdhd @ 6832782 of size: 32, ends @ 6832814 Atom hdlr @ 6832814 of size: 64, ends @ 6832878 Atom minf @ 6832878 of size: 2831, ends @ 6835709 Atom vmhd @ 6832886 of size: 20, ends @ 6832906 Atom dinf @ 6832906 of size: 36, ends @ 6832942 Atom dref @ 6832914 of size: 28, ends @ 6832942 Atom stbl @ 6832942 of size: 2767, ends @ 6835709 Atom stsd @ 6832950 of size: 155, ends @ 6833105 Atom avc1 @ 6832966 of size: 139, ends @ 6833105 Atom avcC @ 6833052 of size: 33, ends @ 6833085 Atom btrt @ 6833085 of size: 20, ends @ 6833105 Atom stts @ 6833105 of size: 24, ends @ 6833129 Atom stsc @ 6833129 of size: 28, ends @ 6833157 Atom stsz @ 6833157 of size: 1220, ends @ 6834377 Atom stco @ 6834377 of size: 1216, ends @ 6835593 Atom stss @ 6835593 of size: 116, ends @ 6835709 Atom trak @ 6835709 of size: 2702, ends @ 6838411 Atom tkhd @ 6835717 of size: 92, ends @ 6835809 Atom mdia @ 6835809 of size: 2602, ends @ 6838411 Atom mdhd @ 6835817 of size: 32, ends @ 6835849 Atom hdlr @ 6835849 of size: 64, ends @ 6835913 Atom minf @ 6835913 of size: 2498, ends @ 6838411 Atom smhd @ 6835921 of size: 16, ends @ 6835937 Atom dinf @ 6835937 of size: 36, ends @ 6835973 Atom dref @ 6835945 of size: 28, ends @ 6835973 Atom stbl @ 6835973 of size: 2438, ends @ 6838411 Atom stsd @ 6835981 of size: 102, ends @ 6836083 Atom mp4a @ 6835997 of size: 86, ends @ 6836083 Atom esds @ 6836033 of size: 50, ends @ 6836083 Atom stts @ 6836083 of size: 24, ends @ 6836107 Atom stsc @ 6836107 of size: 28, ends @ 6836135 Atom stsz @ 6836135 of size: 1140, ends @ 6837275 Atom stco @ 6837275 of size: 1136, ends @ 6838411 Atom free @ 6838411 of size: 59635, ends @ 6898046 ------------------------------------------------------ Total size: 6898046 bytes; 43 atoms total. AtomicParsley version: 0.9.0 (utf8) Media data: 6799742 bytes; 98304 bytes all other atoms (1.425% atom overhead). Total free atom space: 92371 bytes; 1.339% waste. ------------------------------------------------------
When the camera is turned of while registering (for whatever reason) the entire moov atom is missing. Fixing size of mdat and replacing the atom with that of another file does not work because
Rebuilding the indices involves guessing start and length of each packed in the mdat atom, and following the instruction in the links above, rebuild stco and stsz [notice how most atoms size needs to be recalculated when doing this]
I tryed some heuristics: AAC audio packets starts with 0x20 and ends with 111 followed by padding zeroes, while h264 video packets starts with 4 bytes indicating the lenght (most convenient) and than 0x41, but for large files there is little hope of never make a mistake.
Using ffmpeg and libfaad we can parse an audio packet:
int consumed = avcodec_decode_audio2(audio_c, outbuf, &outlen, (const uint8_t *)(stream.data() + offset), 0x320);where 0x320 is just big enough that any audio packet will fit, and consumed returns the lenght of the packet. After that is only a matter of saving offsets, and fix durations.
The code is quite horrible but served his purpouse (recover my beloved file in a couple of days). If you need to adapt to your needs there are a few hacks you might want to be aware of:
AVCodec *audio_codec = avcodec_find_decoder(CODEC_ID_AAC); AVCodec *codec = audio_codec->next; while(codec) { if(codec->id == audio_c->codec_id) audio_codec = codec; codec = codec->next; }I am sure there is a better way...
The code is released under GPL (QT, ffmpeg), I hope someone find it useful, drop me an email in case: ponchio@gmail.com