Moving and fixing atom moov video recorded on iOS phone

The question is how do you find and move the moov atom of the .mov file, which is recorded on the iOS device so that you can transfer it via http. There is one way to do this, but for this you need to export it to a file, which theoretically forces you to copy the entire file, and then you can transfer it.

Is there any other way to do this?

0
source share
2 answers

Here is the code for the method that I edited and wrote for working with iOS to find and then write the moov atom to a specific place, so right after you have these two parts of the video file, you just need to access the bytes of the video file, with which ends with the FTYP atom (look at the variables labeled start_offset and last_offset), and streaming will happen.

- (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 it!

+1
source
  • Using the IOS AV Foundation framework and a few lines of Objective-C (you can also convert from MOV to MP4, since Android cannot read MOV):

    therefore, using this code without a buffer, play smooth video from the Live URL, its operation, but before you upload the video to your server, use this code and convert your video after downloading it. therefore the video plays the video like snapchat without load.

    Remember to add this structure below to your project.

 #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); } }]; } 
+2
source

Source: https://habr.com/ru/post/1263845/


All Articles