Search code examples
adobe

How to convert F4F file to MP4?


We know F4F is Adobe's fragmented MP4 file format for HTTP Dynamic Streaming. A tool called F4F Packager could convert an F4V file to several F4F files and a manifest file(F4M).

My question is, how to convert such F4F files back to an F4V or MP4 file?


Solution

  • We finally found a simple method to merge & convert .f4f files -> .flv file, in which only 'mdat' box is usefull. Here is a the php code:

    <?php
      function ReadInt24($str, $pos)
        {
          return intval(bin2hex(substr($str, $pos, 3)), 16);
        }
    
      function ReadInt32($str, $pos)
        {
          return unpack("N", substr($str, $pos, 4))[1];
        }
    
      echo "\nKSV Adobe HDS Downloader\n\n";
      $flvHeader        = hex2bin("464c5601050000000900000000");
      $firstVideoPacket = true;
      $prevTagSize      = 4;
      $fragCount        = 0;
    
      isset($argv[1]) ? $baseFilename = $argv[1] : $baseFilename = "";
      $baseFilename ? $outputFile = "$baseFilename.flv" : $outputFile = "Joined.flv";
      while (true)
        {
          if (file_exists("$baseFilename" . $fragCount + 1 . ".f4f"))
              $fragCount++;
          else
              break;
        }
      echo "Found $fragCount fragments\n";
      $flv = fopen("$outputFile", "wb");
      fwrite($flv, $flvHeader, 13);
    
      for ($i = 1; $i <= $fragCount; $i++)
        {
          $frag = file_get_contents("$baseFilename$i.f4f");
          preg_match('/(.{4})mdat[\x08\x09\x12]/i', $frag, $mdat, PREG_OFFSET_CAPTURE);
          $fragLen = ReadInt32($mdat[1][0], 0) - 8;
          $frag    = substr($frag, $mdat[1][1] + 8, $fragLen);
          $pos     = 0;
          while ($pos < $fragLen)
            {
              $packetType  = $frag[$pos];
              $packetSize  = ReadInt24($frag, $pos + 1);
              $packetTS    = ReadInt24($frag, $pos + 4);
              $totalTagLen = 11 + $packetSize + $prevTagSize;
              if (($packetType == "\x08" && $packetSize > 4) or ($packetType == "\x09" && $packetSize > 40) or ($packetType == "\x09" && $firstVideoPacket))
                {
                  if ($packetType == "\x09" && $firstVideoPacket)
                      $firstVideoPacket = false;
                  fwrite($flv, substr($frag, $pos, $totalTagLen), $totalTagLen);
                }
              $pos += $totalTagLen;
            }
        }
    
      fclose($flv);
      echo "Finished\n";
    ?>