{"id":268,"date":"2014-01-26T17:34:42","date_gmt":"2014-01-26T17:34:42","guid":{"rendered":"http:\/\/olofee.wordpress.com\/?p=268"},"modified":"2014-01-26T17:34:42","modified_gmt":"2014-01-26T17:34:42","slug":"fix-a-broken-gopro-video","status":"publish","type":"post","link":"http:\/\/malemuk.com\/olofee\/fix-a-broken-gopro-video\/","title":{"rendered":"Fix a broken GoPro video file"},"content":{"rendered":"<p>Run <a href=\"http:\/\/curx.free.fr\/market\/fixfrV2.zip\">this Perl script<\/a> (link found here: <a href=\"http:\/\/goprohacks.blogspot.no\/2010\/11\/recuperer-un-fichier-mp4-de-gopro.html\">http:\/\/goprohacks.blogspot.no\/2010\/11\/recuperer-un-fichier-mp4-de-gopro.html)<\/a><\/p>\n<p>Syntax: $ perl fix.pl videofile -reso 1080p30<\/p>\n<p>default resolution is 720p25, so if the resolution of your broken file is different, you have to use the -reso option.<\/p>\n<p>Here is the content of the script:<\/p>\n<blockquote><p>my $infile = shift(@ARGV);<br \/>\nmy $outfile = $infile . &#8220;.restore.mp4&#8221;;<\/p>\n<p>my $ctts_offset=0;<br \/>\nmy $width = 1280;<br \/>\nmy $height = 720;<br \/>\nmy $framerate = 25;<br \/>\nmy $i, $val;<\/p>\n<p>#<br \/>\n# Parse command line options for options<br \/>\n#<br \/>\nfor($i=0; $i&lt;@ARGV; $i++) {<br \/>\nif ($ARGV[$i] =~ \/-ctts\/) {<br \/>\n$ctts_offset = $ARGV[++$i];<br \/>\n}<br \/>\nif ($ARGV[$i] =~ \/-reso\/){<br \/>\n$val = $ARGV[++$i];<br \/>\nif ($val eq &#8216;720p30&#8217; || $val eq &#8216;ntscr2&#8217;) {<br \/>\n$width = 1280;<br \/>\n$height = 720;<br \/>\n$framerate = 30;<br \/>\n} elsif ($val eq &#8216;720p60&#8217; || $val eq &#8216;ntscr3&#8217;) {<br \/>\n$width = 1280;<br \/>\n$height = 720;<br \/>\n$framerate = 60;<br \/>\n} elsif ($val eq &#8216;960p30&#8217; || $val eq &#8216;ntscr4&#8217;) {<br \/>\n$width = 1280;<br \/>\n$height = 960;<br \/>\n$framerate = 30;<br \/>\n} elsif ($val eq &#8216;1080p30&#8217; || $val eq &#8216;ntscr5&#8217;) {<br \/>\n$width = 1920;<br \/>\n$height = 1080;<br \/>\n$framerate = 30;<br \/>\n} elsif ($val eq &#8216;480p60&#8217; || $val eq &#8216;ntscr1&#8217;) {<br \/>\n$width = 848;<br \/>\n$height = 480;<br \/>\n$framerate = 60;<br \/>\n} elsif ($val eq &#8216;720p60&#8217; || $val eq &#8216;palr3&#8217;) {<br \/>\n$width = 1280;<br \/>\n$height = 720;<br \/>\n$framerate = 50;<br \/>\n} elsif ($val eq &#8216;960p30&#8217; || $val eq &#8216;palr4&#8217;) {<br \/>\n$width = 1280;<br \/>\n$height = 960;<br \/>\n$framerate = 25;<br \/>\n} elsif ($val eq &#8216;1080p30&#8217; || $val eq &#8216;palr5&#8217;) {<br \/>\n$width = 1920;<br \/>\n$height = 1080;<br \/>\n$framerate = 25;<br \/>\n} elsif ($val eq &#8216;480p60&#8217; || $val eq &#8216;palr1&#8217;) {<br \/>\n$width = 848;<br \/>\n$height = 480;<br \/>\n$framerate = 50;<br \/>\n} elsif ($val eq &#8216;720p30&#8217; || $val eq &#8216;palr2&#8217;) {<br \/>\n$width = 1280;<br \/>\n$height = 720;<br \/>\n$framerate = 25;<br \/>\n} elsif ($val eq &#8216;960p48&#8217; || $val eq &#8216;96048HD2&#8242;) {<br \/>\n$width = 1280;<br \/>\n$height = 960;<br \/>\n$framerate = 48;<br \/>\n} else {<br \/>\nprintf(&#8220;Error &#8211; resolution $val not supported. Trying default &#8220;.$height.&#8221;p&#8221;.&#8221;$frameraten&#8221;);<br \/>\n}<br \/>\n}<\/p>\n<p>}<\/p>\n<p>open INFILE, &#8220;&lt;&#8220;, $infile or die(&#8220;Cannot open $infile for readingn&#8221;);<br \/>\nbinmode INFILE;<\/p>\n<p>print (&#8220;nAttempting to fix $infilenn&#8221;);<\/p>\n<p>#disable screen buffering<br \/>\n$|=1;<\/p>\n<p>#<br \/>\n# read data section, find video frames<br \/>\n#<\/p>\n<p>my $n, $size, $type, $buff, $framecount, @ptrs, @szs, $offset, $pmdat;<\/p>\n<p>#<br \/>\n# Skip looking for mdat, find frames by brute force<br \/>\n#<\/p>\n<p>$framecount = 0;<\/p>\n<p>#set delimiter to look for 6-byte value indicating AVC frame start<br \/>\n$\/ = pack (&#8220;C*&#8221;, (0x00, 0x00, 0x00, 0x02, 0x09));<\/p>\n<p>printf(&#8220;Found frame\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 at\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &#8220;);<br \/>\nwhile ($buff = &lt;INFILE&gt;)\u00a0 {<br \/>\nprintf(&#8220;bbbbbbbbbbbbbbbbbb%06d at %08x&#8221;, $framecount, (tell INFILE) &#8211; 5);<br \/>\n$ptrs[$framecount] = (tell INFILE)-5; #adjust to start of code<br \/>\nif ($framecount &gt; 0) {<br \/>\n$szs[$framecount-1] = $ptrs[$framecount] &#8211; $ptrs[$framecount-1];<br \/>\n#print (&#8220;size:\u00a0 &#8220;.$szs[$framecount-1].&#8221;\u00a0 n&#8221;);<br \/>\n}<br \/>\n$framecount++;<br \/>\n}<\/p>\n<p># throw away last one since it triggered on EOF<br \/>\n$framecount&#8211;;<br \/>\npop(@ptrs);<\/p>\n<p>#set beginning of mdat pointer based on 1st found frame<br \/>\n$pmdat=$ptrs[0]-8;<\/p>\n<p>if ($framecount == 0){<br \/>\nprintf(&#8220;bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&#8221;);<br \/>\nprintf(&#8220;No frames found. Quitting.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 n&#8221;);<br \/>\nclose INFILE;<br \/>\nexit;<br \/>\n} else {<br \/>\nprint (&#8220;n&#8221;);<br \/>\n}<\/p>\n<p>open OUTFILE, &#8220;&gt;&#8221;, $outfile or die(&#8220;Cannot open $outfile for writingn&#8221;);<br \/>\nbinmode OUTFILE;<br \/>\nprint (&#8220;Opened file $outfile for writingnn&#8221;);<\/p>\n<p>$min=0xffffffff;<br \/>\n$max=0x0;<br \/>\nforeach(@szs){<br \/>\nif ($_&gt; $max) {$max = $_}<br \/>\nif ($_&lt; $min) {$min = $_}<br \/>\n}<\/p>\n<p>printf(&#8220;Found %d (%x) frames, or approx %ds of video at %dfpsn&#8221;, $framecount, $framecount, $framecount \/ $framerate, $framerate);<br \/>\nprintf(&#8221;\u00a0\u00a0 min size %x, max size %xn&#8221;, $min, $max);<br \/>\nprintf(&#8221;\u00a0\u00a0 from %x, to %xn&#8221;, $ptrs[0], $ptrs[$framecount-1]);<\/p>\n<p>#<br \/>\n# Rebuild Header<br \/>\n#<\/p>\n<p>my $hdrsize, $i, $moov, $stbl ;<\/p>\n<p>#calculate size<br \/>\n#17 B per frame V, 17 Bpf A, plus overhead<br \/>\n$hdrsize = (34 * $framecount) + 2500;<br \/>\n$hdrsize = int ($hdrsize \/ 0x8000) + 1;<br \/>\nif ($hdrsize % 2 == 0) {<br \/>\n$hdrsize ++; # always make header size an odd multiple of 0x8000<br \/>\n}<br \/>\n$hdrsize = $hdrsize * 0x8000;<\/p>\n<p># calculate adjustment for new header size<br \/>\n$offset = $hdrsize &#8211; $pmdat ;<\/p>\n<p>printf(&#8220;Calculated header size of 0x%x n&#8221;,$hdrsize);<br \/>\nprintf(&#8220;Using ctts offset of $ctts_offsetn&#8221;);<br \/>\nprintf(&#8220;Using $width x $height @ $framerate fpsn&#8221;);<\/p>\n<p># ftyp<br \/>\nprint OUTFILE pack(&#8220;NA4A4NA4A4NN&#8221;,0x20,&#8217;ftyp&#8217;,&#8217;avc1&#8242;,0,&#8217;avc1&#8242;,&#8217;isom&#8217;,0,0);<\/p>\n<p>#stbl<br \/>\n$stbl = pack (&#8220;NA4NN&#8221;,0xf9,&#8217;stsd&#8217;,0,0&#215;01);<br \/>\n$stbl .= pack (&#8220;NA4NNNNNNnnNNNCCCA21C11CCC&#8221;,0xe9,&#8217;avc1&#8242;,0,1,0,0,0,0,$width,$height,0x480000,0x480000,0,0,1,0&#215;15,&#8217;Ambarella AVC encoder&#8217;,0,0,0,0,0,0,0,0,0,0,0,0&#215;18,0xff,0xff);<br \/>\n$stbl .= pack (&#8220;NA4NN&#8221;,0x10,&#8217;pasp&#8217;,0,0);<br \/>\n$stbl .= pack (&#8220;NA4N8&#8221;,0x28,&#8217;clap&#8217;,$width,1,$height,1,0,1,0,1);<br \/>\nif ($height == 1080) {<br \/>\n$stbl .= pack (&#8220;NA4N15C3&#8221;,0x47,&#8217;avcC&#8217;,0x014d0028,0xffe10030,0x274d0028,0x9a6280f0,0x044fcb80,0x8800001f,0x48000753,0x07430005, 0xb8e00019,0xbfd5de5c,0x686000b7,0x1c000337,0xfabbcb87,0xc2211458,0x01000428,0xee,0x3c,0x80);<br \/>\n} elsif ($height == 480) {<br \/>\n$stbl .= pack (&#8220;NA4N15C3&#8221;,0x47,&#8217;avcC&#8217;,0x014d401e,0xffe10030,0x274d401e,0x9a6281a8,0x7b602200,0x7d200,0x03a981d0,0x8007a180, 0x0044aa57,0x7971a100,0x0f430000,0x8954aef2,0xe1f08845,0x16000000,0x01000428,0xee,0x3c,0x80);<br \/>\n} elsif ($height == 960) {<br \/>\n$stbl .= pack (&#8220;NA4N15C3&#8221;,0x47,&#8217;avcC&#8217;,0x014d0028,0xffe10030,0x274d0028,0x9a6280a0,0x0f360220,0x7d20,0x1d4c1d,0x0c0016e3, 0x800066ff,0x577971a1,0x8002dc70,0x000cdfea,0xef2e1f08,0x84516000,0x01000428,0xee,0x3c,0x80);<br \/>\n}\u00a0 else {<br \/>\n$stbl .= pack (&#8220;NA4N15C3&#8221;,0x47,&#8217;avcC&#8217;,0x014d0028,0xffe10030,0x274d0028,0x9a6280a0,0x0b760220,0x7d20,0x1d4c1d,0x0c003d0a, 0x0112a9,0x5de5c686,0x1e8500,0x8954ae,0xf2e1f088,0x451e0000,0x01000428,0xee,0x3c,0x80);<br \/>\n}<br \/>\n$stbl .= pack (&#8220;NA4N3&#8221;,0x14,&#8217;btrt&#8217;,0,0,0);<br \/>\n$stbl .= pack (&#8220;NA4N4&#8221;,0x18,&#8217;stts&#8217;,0,1,$framecount,90090\/$framerate);<br \/>\n$stbl .= pack (&#8220;NA4NN&#8221;,8*$framecount\u00a0 + 0x10, &#8216;ctts&#8217;, 0, $framecount);<br \/>\nif ($height == 1080) {<br \/>\nfor ($i=0;$i &lt; $framecount;$i++){<br \/>\n$stbl .= pack (&#8220;NN&#8221;,1,0x0bbb);<br \/>\n}<br \/>\n} elsif ( $framerate == 60) {<br \/>\nfor ($i=$ctts_offset;$i &lt; $framecount + $ctts_offset;$i++){<br \/>\nif (($i\u00a0 %6 == 0) || ($i %6 == 3)) {<br \/>\n$stbl .= pack (&#8220;NN&#8221;,1,0&#215;1199);<br \/>\n} elsif (($i\u00a0 %6 == 1) || ($i %6 == 5)) {<br \/>\n$stbl .= pack (&#8220;NN&#8221;,1,1);<br \/>\n} else {<br \/>\n$stbl .= pack (&#8220;NN&#8221;,1,0);<br \/>\n}<br \/>\n}<br \/>\n} else {<br \/>\nfor ($i=$ctts_offset;$i &lt; $framecount + $ctts_offset;$i++){<br \/>\nif ($i % 3 == 0) {<br \/>\n$stbl .= pack (&#8220;NN&#8221;,1,0&#215;2331);<br \/>\n} else {<br \/>\n$stbl .= pack (&#8220;NN&#8221;,1,0);<br \/>\n}<br \/>\n}<br \/>\n}<br \/>\n$stbl .= pack (&#8220;NA4N5&#8221;,0x1c,&#8217;stsc&#8217;,0,1,1,1,1);<br \/>\n$stbl .= pack (&#8220;NA4N3&#8221;,4*$framecount + 0x14, &#8216;stsz&#8217;,0,0,$framecount);<br \/>\nfor ($i=0;$i &lt; $framecount;$i++){<br \/>\n$stbl .= pack (&#8220;N&#8221;,$szs[$i]);<br \/>\n}<br \/>\n$stbl .= pack (&#8220;NA4N2&#8221;,4*$framecount + 0x10, &#8216;stco&#8217;,0,$framecount);<br \/>\nfor ($i=0;$i &lt; $framecount;$i++){<br \/>\n$stbl .= pack (&#8220;N&#8221;,$ptrs[$i] + $offset);<br \/>\n}<br \/>\n#fake stss because I don&#8217;t know how to re-calculate it<br \/>\n$stbl .= pack (&#8220;NA4N3&#8221;,0x14,&#8217;stss&#8217;,0,1,1);<br \/>\n$stbl .= pack (&#8220;NA4N&#8221;,$framecount + 0xc,&#8217;sdtp&#8217;,0);<br \/>\nif ($height == 1080) {<br \/>\nfor ($i=0;$i &lt; $framecount;$i++){<br \/>\n$stbl .= pack (&#8220;C&#8221;,0);<br \/>\n}<br \/>\n} else {<br \/>\nfor ($i=0;$i &lt; $framecount;$i++){<br \/>\nif ($i % 3 == 0) {<br \/>\n$stbl .= pack (&#8220;C&#8221;,0);<br \/>\n} else {<br \/>\n$stbl .= pack (&#8220;C&#8221;,0x08);<br \/>\n}<br \/>\n}<br \/>\n}<br \/>\n#moov<br \/>\nprint OUTFILE pack(&#8220;NA4&#8221;,$hdrsize-0x20,&#8217;moov&#8217;);<br \/>\nprint OUTFILE pack (&#8220;NA4N25&#8221;,0x6c,&#8217;mvhd&#8217;,0,0,0,0x015f90,2700000 \/ $framerate \/ 0x1d * $framecount, 0x010000, 0x01000000, 0, 0, 0x010000,0,0,0,0&#215;010000,0,0,0,0x40000000,0,0,0,0,0,0,3);<br \/>\nprint OUTFILE pack (&#8220;NA4&#8221;,0x180,&#8217;udta&#8217;);<br \/>\nif ($height == 960) {<br \/>\nprint OUTFILE pack (&#8220;NA4N30&#8221;,0x80,&#8217;AMBA&#8217;,0x040003,0x01030f00,0x04,0x1776,0x02bf20,0xb71b00,0xb71b00,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0&#215;0100);<br \/>\n} elsif ($height == 1080) {<br \/>\nprint OUTFILE pack (&#8220;NA4N30&#8221;,0x80,&#8217;AMBA&#8217;,0x100009,0x01010800,0x04,0x0bbb * (3-($framerate\/30)),0x02bf20,0xb71b00,0xb71b00,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0&#215;0100);<br \/>\n} else {<br \/>\nprint OUTFILE pack (&#8220;NA4N30&#8221;,0x80,&#8217;AMBA&#8217;,0x100009,0x01030f00,0x04,0x0bbb * (3-($framerate\/30)),0x02bf20,0x7a1200,0x7a1200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0&#215;0100);<br \/>\n}<br \/>\nprint OUTFILE pack (&#8220;NA4N60&#8221;,0xf8,&#8217;free&#8217;,(0)x60);<br \/>\nprint OUTFILE pack (&#8220;NA4&#8221;,0x16a + length($stbl), &#8216;trak&#8217;);<br \/>\nprint OUTFILE pack (&#8220;NA4N19n4&#8221;,0x5c,&#8217;tkhd&#8217;,0x07,0,0,1,0,2700000 \/ $framerate \/ 0x1d * $framecount,0,0,0,0,0&#215;10000,0,0,0,0x10000,0,0,0,0&#215;40000000,$width,0,$height,0);<br \/>\nprint OUTFILE pack (&#8220;NA4&#8221;,0x24,&#8217;edts&#8217;);<br \/>\nprint OUTFILE pack (&#8220;NA4N5&#8221;,0x1c,&#8217;elst&#8217;,0,1,0x015f90 \/ 0x1d * $framecount, 90090\/$framerate,0x10000);<br \/>\nprint OUTFILE pack (&#8220;NA4&#8221;,0x44, &#8216;tapt&#8217;);<br \/>\nprint OUTFILE pack (&#8220;NA4Nn4&#8221;,0x14,&#8217;clef&#8217;,0,$width,0,$height,0);<br \/>\nprint OUTFILE pack (&#8220;NA4Nn4&#8221;,0x14,&#8217;prof&#8217;,0,$width,0,$height,0);<br \/>\nprint OUTFILE pack (&#8220;NA4Nn4&#8221;,0x14,&#8217;enof&#8217;,0,$width,0,$height,0);<br \/>\nprint OUTFILE pack (&#8220;NA4&#8221;, 0x9e + length($stbl), &#8216;mdia&#8217;);<br \/>\nprint OUTFILE pack (&#8220;NA4N6&#8221;, 0x20, &#8216;mdhd&#8217;, 0,0,0,0x015f90,0x015f90 \/ 0x1d * $framecount,0);<br \/>\nprint OUTFILE pack (&#8220;NA4N2A4N3CA13&#8221;, 0x2e, &#8216;hdlr&#8217;, 0,0, &#8216;vide&#8217;,0,0,0,0xd,&#8217;Ambarella AVC&#8217;);<br \/>\nprint OUTFILE pack (&#8220;NA4&#8221;,0x48 + length ($stbl), &#8216;minf&#8217;);<br \/>\nprint OUTFILE pack (&#8220;NA4N3&#8221;, 0x14, &#8216;vmhd&#8217;, 1,0,0,);<br \/>\nprint OUTFILE pack (&#8220;NA4&#8221;,0x24,&#8217;dinf&#8217;);<br \/>\nprint OUTFILE pack (&#8220;NA4N2&#8221;,0x1c,&#8217;dref&#8217;,0,1);<br \/>\nprint OUTFILE pack (&#8220;NA4N&#8221;,0xc,&#8217;url &#8216;,1);<br \/>\nprint OUTFILE pack (&#8220;NA4&#8221;, 0x8+length($stbl),&#8217;stbl&#8217;);<br \/>\nprint OUTFILE $stbl;<\/p>\n<p>print OUTFILE pack (&#8220;NA4&#8221;,$hdrsize &#8211; tell OUTFILE, &#8216;free&#8217;);<\/p>\n<p>for ($i=$hdrsize &#8211; tell OUTFILE; $i&gt;0; $i&#8211;) {<br \/>\nprint OUTFILE pack (&#8220;C&#8221;,0);<br \/>\n}<\/p>\n<p>#<br \/>\n# Copy data over<br \/>\n#<\/p>\n<p>print OUTFILE pack (&#8220;NA4&#8221;,unpack (&#8220;%123d*&#8221; , pack( &#8220;d*&#8221;, @szs)) + 13,&#8217;mdat&#8217;);<br \/>\nseek INFILE, $pmdat + 8, 0;<br \/>\n$framecount=0;<br \/>\nprintf(&#8220;Copying\u00a0 frame\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &#8230;&#8221;);<br \/>\nwhile ($buff = &lt;INFILE&gt;)\u00a0 {<br \/>\nprintf(&#8220;bbbbbbbbb%06d&#8230;&#8221;, $framecount++);<br \/>\nprint OUTFILE $buff;<br \/>\n}<br \/>\nprint(&#8220;nDone.n&#8221;);<\/p>\n<p>close OUTFILE;<br \/>\nclose INFILE;<\/p><\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>Run this Perl script (link found here: http:\/\/goprohacks.blogspot.no\/2010\/11\/recuperer-un-fichier-mp4-de-gopro.html) Syntax: $ perl fix.pl videofile -reso 1080p30 default resolution is 720p25, so if the resolution of your broken file is different, you have to use the -reso option. Here is the content of the script: my $infile = shift(@ARGV); my $outfile = $infile . &#8220;.restore.mp4&#8221;; my $ctts_offset=0; [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[14],"tags":[],"class_list":["post-268","post","type-post","status-publish","format-standard","hentry","category-computer-stuff"],"jetpack-related-posts":[],"_links":{"self":[{"href":"http:\/\/malemuk.com\/olofee\/wp-json\/wp\/v2\/posts\/268","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/malemuk.com\/olofee\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/malemuk.com\/olofee\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/malemuk.com\/olofee\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/malemuk.com\/olofee\/wp-json\/wp\/v2\/comments?post=268"}],"version-history":[{"count":0,"href":"http:\/\/malemuk.com\/olofee\/wp-json\/wp\/v2\/posts\/268\/revisions"}],"wp:attachment":[{"href":"http:\/\/malemuk.com\/olofee\/wp-json\/wp\/v2\/media?parent=268"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/malemuk.com\/olofee\/wp-json\/wp\/v2\/categories?post=268"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/malemuk.com\/olofee\/wp-json\/wp\/v2\/tags?post=268"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}