iphone - 将 AVAssetWriter 与原始 NAL 单元一起使用

标签 iphone ios h.264 avassetwriter cmsamplebufferref

我在 iOS 文档中注意到 AVAssetWriterInput你可以通过nil对于 outputSettings字典来指定不应重新编码输入数据。

The settings used for encoding the media appended to the output. Pass nil to specify that appended samples should not be re-encoded.

我想利用此功能传入原始 H.264 NAL 流,但我无法将原始字节流调整为 CMSampleBuffer我可以传递给 AVAssetWriterInput 的 appendSampleBuffer方法。我的 NAL 流仅包含 SPS/PPS/IDR/P NAL(1、5、7、8)。我一直无法找到有关如何将预编码的 H264 数据与 AVAssetWriter 一起使用的文档或结论性答案。生成的视频文件无法播放。

如何将 NAL 单元正确打包到 CMSampleBuffers 中?我需要使用起始代码前缀吗?长度前缀?我是否需要确保每个 CMSampleBuffer 只放一个 NAL? ?我的最终目标是使用 H264/AAC 创建 MP4 或 MOV 容器。

这是我一直在玩的代码:

-(void)addH264NAL:(NSData *)nal
{
    dispatch_async(recordingQueue, ^{
        //Adapting the raw NAL into a CMSampleBuffer
        CMSampleBufferRef sampleBuffer = NULL;
        CMBlockBufferRef blockBuffer = NULL;
        CMFormatDescriptionRef formatDescription = NULL;
        CMItemCount numberOfSampleTimeEntries = 1;
        CMItemCount numberOfSamples = 1;


        CMVideoFormatDescriptionCreate(kCFAllocatorDefault, kCMVideoCodecType_H264, 480, 360, nil, &formatDescription);
        OSStatus result = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, NULL, [nal length], kCFAllocatorDefault, NULL, 0, [nal length], kCMBlockBufferAssureMemoryNowFlag, &blockBuffer);
        if(result != noErr)
        {
            NSLog(@"Error creating CMBlockBuffer");
            return;
        }
        result = CMBlockBufferReplaceDataBytes([nal bytes], blockBuffer, 0, [nal length]);
        if(result != noErr)
        {
            NSLog(@"Error filling CMBlockBuffer");
            return;
        }
        const size_t sampleSizes = [nal length];
        CMSampleTimingInfo timing = { 0 };
        result = CMSampleBufferCreate(kCFAllocatorDefault, blockBuffer, YES, NULL, NULL, formatDescription, numberOfSamples, numberOfSampleTimeEntries, &timing, 1, &sampleSizes, &sampleBuffer);

        if(result != noErr)
        {
            NSLog(@"Error creating CMSampleBuffer");
        }
        [self writeSampleBuffer:sampleBuffer ofType:AVMediaTypeVideo];
    });
}

请注意,我正在调用 CMSampleBufferSetOutputPresentationTimeStampwriteSampleBuffer 内的样本缓冲区上在我实际尝试追加它之前,我认为它是有效时间的方法。

感谢任何帮助。

最佳答案

我设法在 VLC 而非 QuickTime 中播放视频。我使用与我在上面发布的代码类似的代码将 H.264 NAL 导入 CMSampleBuffers。

我有两个主要问题:

  1. 我没有正确设置 CMSampleTimingInfo(如我上面的评论所述)。
  2. 我没有正确打包原始 NAL 数据(不确定记录在何处,如果有的话)。

为了解决 #1,我设置了 timing.duration = CMTimeMake(1, fps);,其中 fps 是预期的帧速率。然后我设置 timing.decodeTimeStamp = kCMTimeInvalid; 意味着样本将按解码顺序给出。最后,我通过计算绝对时间来设置 timing.presentationTimeStamp,我也将其与 startSessionAtSourceTime 一起使用。

为了解决 #2,通过反复试验,我发现以下列形式提供我的 NAL 单元是有效的:

[7 8 5] [1] [1] [1]..... [7 8 5] [1] [1] [1]..... (repeating)

其中每个 NAL 单元都以等于 0x00000001 的 32 位起始代码为前缀。

可能出于同样的原因,它不能在 QuickTime 中播放,我仍然无法将生成的 .mov 文件移动到相册(ALAssetLibrary 方法 videoAtPathIsCompatibleWithSavedPhotosAlbum 是未能说明“无法播放电影”。希望知道发生了什么的人可以发表评论。谢谢!

关于iphone - 将 AVAssetWriter 与原始 NAL 单元一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15629117/

相关文章:

opencv - Windows 上的 FFMPEG(用于 H.264 RTSP 解码)

iphone - 类中两个独立的委托(delegate)方法

iphone - 从 Master 到 Detail UITableView,其中第二个具有分组样式

java - H264 字节流到图像文件

iphone - 无法在单元测试中设置 NSMutableDictionary 中的值

ios - 如何调整图像大小以适应包含的 ImageView

c - 在 C 中对 OpenGL 捕获的缓冲区进行编码

iphone - TouchXML (Sudzc) 并正确使用这些数据

iphone - mobileNetworkCode 返回 "VZW"而不是数字移动网络代码

ios - iAd 正在关闭。我应该从我的所有应用程序中删除 iAd 框架吗?