--An example way to compile this is like  gnatmake -O3 unload_mdat.adb -cargs -Ofast

with Ada.Sequential_Io;

with Ada.Command_Line;

with Ada.Text_Io;

procedure Unload_Mdat is
   
   type Octet is new Standard.Character;
   --A GNAT bug crashes this program if Input's length is not a multiple of 32 bits by saying  "raised ADA.IO_EXCEPTIONS.DATA_ERROR : System.File_IO.Read_Buf: not enough data read"  if Octet is reified as  type Octet is new Integer range 0 .. 255;
   
   package Octet_Io is new Ada.Sequential_Io (Element_Type => Octet);
   Input, Output : Octet_Io.File_Type;
   Payload_Datum, Either_bogus_Header_Or_valid_Datum : Octet;
begin
   Ada.Text_Io.Put_Line ("unload_mdat by Nicholas Collin Paul de Gloucester copies a (probably defective) MPEG-4 audio file's contents excluding its (unneeded, probably defective) mdat header to raw.m4a. This is useful e.g. as a step for making an MP4 file (by an incompatible recorder) playable by many popular MP4 players. unload_mdat is fast unlike slow alternatives. Cf. HTTP://Gloucester.Insomnia247.NL/FFMPEG_etc/Overcoming_MPEG-4_incompatibility.HTM");
   Ada.Text_Io.Put_Line ("Example usage:");
   Ada.Text_Io.Put_Line ("unload_mdat input.M4A");
   Ada.Text_Io.Put_Line ("faad -a newname.m4a raw.m4a");
   Ada.Text_Io.Put_Line ("ffmpeg -i newname.m4a -c:a aac Playable_audio_MPEG-4_final_output.M4A");
   
   if Ada.Command_Line.Argument_Count /= 0 then
      Octet_Io.Open(File => Input, Mode => Octet_Io.In_file, Name => Ada.Command_Line.Argument (1));
      Octet_Io.create(File => Output, Mode => Octet_Io.Out_file, Name => "raw.m4a");
      while not Octet_Io.End_Of_File (Input) loop
	 Octet_Io.read(File => input, Item => Either_bogus_Header_Or_valid_Datum);
	 if Either_Bogus_Header_Or_Valid_Datum = 'm' then -- mdat marks the end of a bogus MPEG4 header
	    Octet_Io.read(File => input, Item => Either_bogus_Header_Or_valid_Datum);
	    if Either_Bogus_Header_Or_Valid_Datum = 'd' then
	       Octet_Io.read(File => input, Item => Either_bogus_Header_Or_valid_Datum);
	       if Either_Bogus_Header_Or_Valid_Datum = 'a' then
		  Octet_Io.read(File => input, Item => Either_bogus_Header_Or_valid_Datum);
		  if Either_Bogus_Header_Or_Valid_Datum = 't' then
		     while not Octet_Io.End_Of_File (Input) loop
			Octet_Io.read(File => input, Item => Payload_Datum);
			Octet_Io.write(File => Output, Item => Payload_Datum);
		     end loop;
		  end if;
	       end if;
	    end if;
	 end if;
      end loop;
   end if;
end Unload_Mdat;
