1

问题是您如何找到并移动记录在 iOS 设备上的 .mov 文件的 moov 原子,以便您可以通过 http 流式传输它。有一种方法可以做到这一点,但这需要将其导出到文件中,理论上这会使您复制整个文件,然后您就可以流式传输它。

有没有其他方法可以做到这一点?

4

2 回答 2

5
  • 使用 iOS AV Foundation 框架和几行 Objective-C(您也可以从 MOV 转换为 MP4,因为 Android 无法读取 MOV):

    因此,使用没有缓冲区的此代码可以从 Live 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);
         }
     }];
}
于 2016-09-19T06:50:10.923 回答
2

这是我编辑和编写的方法的代码,用于与 iOS 一起查找然后将 moov atom 写入特定位置,因此在您拥有视频文件的这两个部分之后,您只需要访问视频文件的字节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];
}

享受!

于 2012-08-23T15:58:47.770 回答