2012-08-23 42 views
0

問題是如何找到並移動iOS設備上記錄的.mov文件的moov原子,以便通過http進行流式處理。有一種方法可以做到這一點,但需要將其導出到文件中,理論上使您可以將整個文件複製過來,然後才能夠對其進行流式處理。移動並修復手機上錄製的視頻的moov原子iOS

有沒有其他方法可以做到這一點?

回答

1

這裏是我編輯和編寫的方法的代碼,以便與iOS一起查找,然後將moov原子寫入特定的位置,然後在您擁有這兩部分視頻文件之後,您只需訪問字節FTYP原子結束處的視頻文件(查看標記爲start_offset和last_offset的變量),並且流將發生。

- (NSString *)fixForFastPlayback:(char*)dest:(ALAsset*)selected 
{ 
    FILE *infile = NULL; 
    FILE *outfile = NULL; 
    uint32_t atom_type = 0; 
    uint64_t atom_size = 0; 
    uint64_t atom_offset = 0; 
    uint64_t last_offset; 
    uint64_t moov_atom_size; 
    uint64_t ftyp_atom_size = 0; 
    uint64_t i, j; 
    uint32_t offset_count; 
    uint64_t current_offset; 
    uint64_t start_offset = 0; 

    ALAssetRepresentation * rep = [[selected defaultRepresentation] retain]; 

    int bufferSize = 8192; // or use 8192 size as read from other posts 

    int read = 0; 
    NSError * err = nil; 

    uint8_t * buffer = calloc(bufferSize, sizeof(*buffer)); 
    uint8_t * ftyp_atom; 
    /* traverse through the atoms in the file to make sure that 'moov' is 
    * at the end */ 
    int asset_offset = 0; 
    while (asset_offset < [rep size]) 
    { 

     read = [rep getBytes:buffer 
        fromOffset:asset_offset 
         length:ATOM_PREAMBLE_SIZE 
         error:&err]; 

     asset_offset += read; 

     if (err != nil) 
     { 
      NSLog(@"Error: %@ %@", err, [err userInfo]); 
     } 


     atom_size = (uint32_t)BE_32(&buffer[0]); 
     atom_type = BE_32(&buffer[4]); 

     /* keep ftyp atom */ 
     if (atom_type == FTYP_ATOM) //no idea what an atom is, maybe a header or some sort of meta data or a file marker 
     { 

      ftyp_atom_size = atom_size; 
      ftyp_atom = calloc(ftyp_atom_size, sizeof(*buffer)); 

      if (!ftyp_atom) 
      { 
       printf ("could not allocate %"PRIu64" byte for ftyp atom\n", 
         atom_size); 

      } 


      asset_offset -= ATOM_PREAMBLE_SIZE; 

      read = [rep getBytes:ftyp_atom 
         fromOffset:asset_offset 
          length:ftyp_atom_size 
          error:&err]; 

      asset_offset += read; 

      start_offset = asset_offset; 

     } 
     else 
     { 

      asset_offset += (atom_size - ATOM_PREAMBLE_SIZE); 

     } 

     printf("%c%c%c%c %10"PRIu64" %"PRIu64"\n", 
       (atom_type >> 24) & 255, 
       (atom_type >> 16) & 255, 
       (atom_type >> 8) & 255, 
       (atom_type >> 0) & 255, 
       atom_offset, 
       atom_size); 
     if ((atom_type != FREE_ATOM) && 
      (atom_type != JUNK_ATOM) && 
      (atom_type != MDAT_ATOM) && 
      (atom_type != MOOV_ATOM) && 
      (atom_type != PNOT_ATOM) && 
      (atom_type != SKIP_ATOM) && 
      (atom_type != WIDE_ATOM) && 
      (atom_type != PICT_ATOM) && 
      (atom_type != UUID_ATOM) && 
      (atom_type != FTYP_ATOM)) 
     { 
      printf ("encountered non-QT top-level atom (is this a Quicktime file?)\n"); 
      break; 
     } 
     atom_offset += atom_size; 

     /* The atom header is 8 (or 16 bytes), if the atom size (which 
     * includes these 8 or 16 bytes) is less than that, we won't be 
     * able to continue scanning sensibly after this atom, so break. */ 
     if (atom_size < 8) 
      break; 
    } 

    if (atom_type != MOOV_ATOM) 
    { 
     printf ("last atom in file was not a moov atom\n"); 
     free(ftyp_atom); 
     fclose(infile); 
     return 0; 
    } 

    asset_offset = [rep size]; 
    asset_offset -= atom_size; 
    last_offset = asset_offset; 



    moov_atom_size = atom_size; 
    uint8_t * moov_atom = calloc(moov_atom_size, sizeof(*buffer)); 

    if (!moov_atom) 
    { 
     printf ("could not allocate %"PRIu64" byte for moov atom\n", 
       atom_size); 

    } 
    read = [rep getBytes:moov_atom 
       fromOffset:asset_offset 
        length:moov_atom_size 
        error:&err]; 

    asset_offset += read; 

    /* this utility does not support compressed atoms yet, so disqualify 
    * files with compressed QT atoms */ 
    if (BE_32(&moov_atom[12]) == CMOV_ATOM) 
    { 
     printf ("this utility does not support compressed moov atoms yet\n"); 

    } 

    /* crawl through the moov chunk in search of stco or co64 atoms */ 
    for (i = 4; i < moov_atom_size - 4; i++) 
    { 
     atom_type = BE_32(&moov_atom[i]); 

     if (atom_type == STCO_ATOM) 
     { 
      printf (" patching stco atom...\n"); 
      atom_size = BE_32(&moov_atom[i - 4]); 
      if (i + atom_size - 4 > moov_atom_size) 
      { 
       printf (" bad atom size\n"); 

      } 
      offset_count = BE_32(&moov_atom[i + 8]); 
      for (j = 0; j < offset_count; j++) 
      { 
       current_offset = BE_32(&moov_atom[i + 12 + j * 4]); 
       current_offset += moov_atom_size; 
       moov_atom[i + 12 + j * 4 + 0] = (current_offset >> 24) & 0xFF; 
       moov_atom[i + 12 + j * 4 + 1] = (current_offset >> 16) & 0xFF; 
       moov_atom[i + 12 + j * 4 + 2] = (current_offset >> 8) & 0xFF; 
       moov_atom[i + 12 + j * 4 + 3] = (current_offset >> 0) & 0xFF; 
      } 
      i += atom_size - 4; 
     } 
     else if (atom_type == CO64_ATOM) 
     { 

      printf (" patching co64 atom...\n"); 
      atom_size = BE_32(&moov_atom[i - 4]); 
      if (i + atom_size - 4 > moov_atom_size) 
      { 
       printf (" bad atom size\n"); 

      } 
      offset_count = BE_32(&moov_atom[i + 8]); 
      for (j = 0; j < offset_count; j++) 
      { 
       current_offset = BE_64(&moov_atom[i + 12 + j * 8]); 
       current_offset += moov_atom_size; 
       moov_atom[i + 12 + j * 8 + 0] = (current_offset >> 56) & 0xFF; 
       moov_atom[i + 12 + j * 8 + 1] = (current_offset >> 48) & 0xFF; 
       moov_atom[i + 12 + j * 8 + 2] = (current_offset >> 40) & 0xFF; 
       moov_atom[i + 12 + j * 8 + 3] = (current_offset >> 32) & 0xFF; 
       moov_atom[i + 12 + j * 8 + 4] = (current_offset >> 24) & 0xFF; 
       moov_atom[i + 12 + j * 8 + 5] = (current_offset >> 16) & 0xFF; 
       moov_atom[i + 12 + j * 8 + 6] = (current_offset >> 8) & 0xFF; 
       moov_atom[i + 12 + j * 8 + 7] = (current_offset >> 0) & 0xFF; 
      } 
      i += atom_size - 4; 
     } 
    } 

    outfile = fopen(dest, "wb"); 
    NSLog(@"%llu",last_offset); 

    //global variables to be used when returning the actual data 
    start_offset_not_c = start_offset; 
    last_offset_not_c = last_offset; 

    if (ftyp_atom_size > 0) 
    { 
     printf ("writing ftyp atom...\n"); 
     if (fwrite(ftyp_atom, ftyp_atom_size, 1, outfile) != 1) 
     { 
      perror(dest); 
     } 
    } 

    printf ("writing moov atom...\n"); 
    if (fwrite(moov_atom, moov_atom_size, 1, outfile) != 1) 
    { 
     perror(dest); 
    } 

    fclose(outfile); 
    free(ftyp_atom); 
    free(moov_atom); 
    ftyp_atom = NULL; 
    moov_atom = NULL; 

    return [NSString stringWithCString:dest encoding:NSStringEncodingConversionAllowLossy]; 
} 

Enjoy!

2
  • 使用的是iOS AV Foundation框架和Objective-C的幾行(你 也可以從MOV到MP4轉換由於Android無法讀取MOV):

    ,因此使用此代碼,而無需緩衝播放流暢的視頻從實時URL的作品,但在上傳視頻到您的服務器之前使用此代碼和 轉換您的視頻,並在上傳後。所以視頻播放視頻就像沒有任何負載的 snapchat。

    不要忘了將下面的框架添加到您的項目中。

#import <AVFoundation/AVAsset.h> 
#import <AVFoundation/AVAssetExportSession.h> 
#import <AVFoundation/AVMediaFormat.h> 
+ (void) convertVideoToMP4AndFixMooV: (NSString*)filename toPath:(NSString*)outputPath { 

    NSURL *url = [NSURL fileURLWithPath:filename]; 
    AVAsset *avAsset = [AVURLAsset URLAssetWithURL:url options:nil]; 
    AVAssetExportSession *exportSession = [AVAssetExportSession 
              exportSessionWithAsset:avAsset 
              presetName:AVAssetExportPresetPassthrough]; 

    exportSession.outputURL = [NSURL fileURLWithPath:outputPath]; 
    exportSession.outputFileType = AVFileTypeAppleM4V; 

    // This should move the moov atom before the mdat atom, 
    // hence allow playback before the entire file is downloaded 
    exportSession.shouldOptimizeForNetworkUse = YES; 

    [exportSession exportAsynchronouslyWithCompletionHandler: 
    ^{ 

     if (AVAssetExportSessionStatusCompleted == exportSession.status) {} 
     else if (AVAssetExportSessionStatusFailed == exportSession.status) { 
      NSLog(@"AVAssetExportSessionStatusFailed"); 
     } 
     else 
     { 
      NSLog(@"Export Session Status: %d", exportSession.status); 
     } 
    }]; 
} 
+0

這工作,但如果你有一個4分鐘長的視頻?這可能需要30秒以上的時間來轉換然後流式傳輸。 – Krzemienski