从 AVAssetWriter 读取实时 H.264 输出时数据损坏

2023-11-22

我正在使用一些技巧来尝试在将 AVAssetWriter 写入磁盘时读取其原始输出。当我通过连接各个文件来重新组装它们时,生成的文件与 AVAssetWriter 的输出文件的字节数完全相同。但是,重新组装的文件将无法在 QuickTime 中播放或被 FFmpeg 解析,因为存在数据损坏。一些字节已被更改,导致生成的文件无法使用。我假设这发生在每次读取的 EOF 边界上,但它不是一致的损坏。

我计划最终使用与此类似的代码从编码器中解析出各个 H.264 NAL 单元,将它们打包并通过 RTP 发送它们,但是如果我不能信任从磁盘读取的数据,我可能不得不使用其他解决方案。

对于此数据损坏有解释/修复吗?您是否找到了有关如何解析 NAL 单元以通过 RTP 进行打包的任何其他资源/链接?

完整代码在这里:AVAppleEncoder.m

// Modified from
// http://www.davidhamrick.com/2011/10/13/Monitoring-Files-With-GCD-Being-Edited-With-A-Text-Editor.html
- (void)watchOutputFileHandle
{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    int fildes = open([[movieURL path] UTF8String], O_EVTONLY);

    source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE,fildes,
                                                              DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_LINK | DISPATCH_VNODE_RENAME | DISPATCH_VNODE_REVOKE,
                                                              queue);
    dispatch_source_set_event_handler(source, ^
                                      {
                                          unsigned long flags = dispatch_source_get_data(source);
                                          if(flags & DISPATCH_VNODE_DELETE)
                                          {
                                              dispatch_source_cancel(source);
                                              //[blockSelf watchStyleSheet:path];
                                          }
                                          if(flags & DISPATCH_VNODE_EXTEND)
                                          {
                                              //NSLog(@"File size changed");
                                              NSError *error = nil;
                                              NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingFromURL:movieURL error:&error];
                                              if (error) {
                                                  [self showError:error];
                                              }
                                              [fileHandle seekToFileOffset:fileOffset];
                                              NSData *newData = [fileHandle readDataToEndOfFile];
                                              if ([newData length] > 0) {
                                                  NSLog(@"newData (%lld): %d bytes", fileOffset, [newData length]);
                                                  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
                                                  NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
                                                  NSString *movieName = [NSString stringWithFormat:@"%d.%lld.%d.mp4", fileNumber, fileOffset, [newData length]];
                                                  NSString *path = [NSString stringWithFormat:@"%@/%@", basePath, movieName];
                                                  [newData writeToFile:path atomically:NO];
                                                  fileNumber++;
                                                  fileOffset = [fileHandle offsetInFile];
                                              }
                                          }
                                      });
    dispatch_source_set_cancel_handler(source, ^(void) 
                                       {
                                           close(fildes);
                                       });
    dispatch_resume(source);
}

以下是我发现的一些类似问题,但不能完全回答我的问题:

  • 从 iOS AVAssetWriter 生成的原始 H264 mdat 中获取 PTS
  • 从 iPhone 传输视频
  • 从 QuickTime MOV 文件解析 h.264 NAL 单元
  • 从 iPhone 到另一台设备(浏览器或 iPhone)的实时音频/视频流

当我最终弄清楚这一点时,我将发布一个开源库来帮助将来尝试这样做的人。

谢谢你!

Update:损坏不会发生在 EOF 边界处。看起来文件的某些部分在之后被重写了finishWriting叫做。第一个文件的分块大小为 4KB,因此更改的区域不在 EOF 边界附近。当新的“moov”元素附近它似乎也被损坏了movieFragmentInterval已启用。

broken file Correct file on the left, broken file on the right.


我最终放弃了“边写边读”的方法,转而采用手动分块方法,我称之为finishWriting每 5 秒在后台线程上执行一次。我能够使用一种方法丢掉可忽略不计的帧数最初描述在这里:

- (void) segmentRecording:(NSTimer*)timer {
    AVAssetWriter *tempAssetWriter = self.assetWriter;
    AVAssetWriterInput *tempAudioEncoder = self.audioEncoder;
    AVAssetWriterInput *tempVideoEncoder = self.videoEncoder;
    self.assetWriter = queuedAssetWriter;
    self.audioEncoder = queuedAudioEncoder;
    self.videoEncoder = queuedVideoEncoder;
    //NSLog(@"Switching encoders");

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        [tempAudioEncoder markAsFinished];
        [tempVideoEncoder markAsFinished];
        if (tempAssetWriter.status == AVAssetWriterStatusWriting) {
            if(![tempAssetWriter finishWriting]) {
                [self showError:[tempAssetWriter error]];
            }
        }
        if (self.readyToRecordAudio && self.readyToRecordVideo) {
            NSError *error = nil;
            self.queuedAssetWriter = [[AVAssetWriter alloc] initWithURL:[self newMovieURL] fileType:(NSString *)kUTTypeMPEG4 error:&error];
            if (error) {
                [self showError:error];
            }
            self.queuedVideoEncoder = [self setupVideoEncoderWithAssetWriter:self.queuedAssetWriter formatDescription:videoFormatDescription bitsPerSecond:videoBPS];
            self.queuedAudioEncoder = [self setupAudioEncoderWithAssetWriter:self.queuedAssetWriter formatDescription:audioFormatDescription bitsPerSecond:audioBPS];
            //NSLog(@"Encoder switch finished");

        }
    });
}

完整源代码:https://github.com/chrisballinger/FFmpeg-iOS-Encoder/blob/master/AVSegmentingAppleEncoder.m

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从 AVAssetWriter 读取实时 H.264 输出时数据损坏 的相关文章

  • 如何从 iOS 应用程序检测不安全的 wifi 网络

    我想检测我的应用程序中是否存在不安全的 wifi 网络 是否有任何公共 iOS API 可以实现相同的目的 没有记录的 API 可以获取该信息 如果您的应用程序需要通过网络发送和接收敏感数据 您通常应该假设没有安全连接
  • NSOperation 中委托的使用

    我正在尝试利用CLLocationManager in an NSOperation 作为其中的一部分 我需要能够startUpdatingLocation然后等到收到 CLLocation 后才完成操作 目前我已经完成了以下操作 但是委托
  • 如何修复 ReactiveCocoa(带有 CocoaPods)的安装?

    这里是新手 尝试将 ReactiveCocoa 2 2 4 和 CocoaPods 安装到项目中 但在运行时遇到错误 我用过github 上的这个 podspec https github com CocoaPods Specs blob
  • let/var 如何解决可变性? [复制]

    这个问题在这里已经有答案了 我没有任何问题 我只是想对有关可变性的问题进行一些澄清 在 Objective C 中我们会使用例如NSMutableArray得到一个可变数组和NSArray得到一个不可变的 我对两者的内部运作了解不多 但据我
  • 如果加载 dylib,垃圾收集工作队列会崩溃

    我们正在将应用程序从 10 6 移植到 10 8 我正在查看我们在应用程序中加载的 dylib 我面临着非常不寻常的崩溃垃圾收集工作队列并附有以下消息 malloc Thread suspend unable to suspend a th
  • 为具有多个目标和不同平台的项目编写 Podfile

    我正在准备一个支持 OS X 和 iOS 的 Pod 我的 pod 有一些自己的依赖项 这些依赖项在 podspec 文件中定义 因此我使用 Podfile 来管理我用来开发 pod 和运行测试的项目的依赖项 我正在使用 CocoaPods
  • 如何检索 iPhone 的区域设置

    我用谷歌搜索过它 但令我有点惊讶的是我找不到它 我只想访问设备配置的区域设置 我试图找到如何列出所有系统属性 以防我能在那里找到区域设置 但甚至找不到如何做到这一点 我知道 认为 我之前检索过系统属性 但我也记得在谷歌搜索时找到该信息并不容
  • 如何为 Nslocal 通知设置自定义重复间隔......?

    我是 iphone 开发新手 我正在尝试在我的项目中使用 NslocalNotification 我需要每 2 小时或每两天或每两个月等给出提醒 目前我正在使用 NslocalNotification 重复间隔 但它仅适用于使用 Ncale
  • 使用 ZBarSDK 时 iPhone 相机失去自动对焦功能

    我正在开发一个应用程序 用户可以选择是否要扫描条形码或拍摄某物的照片 为了拍照 我正在使用UIImagePickerController照常 为了扫描条形码 我使用 ZbarSDK 1 2ZBarReaderViewController 拍
  • 动画 UICollectionView 单元格大小更改并重新定位周围单元格

    Goal 以动画方式改变单元格的高度并重新定位周围的单元格 设想 集合视图中的某些单元格会加载远程图像 最初 这些单元格的大小是静态的 并显示活动指示器 加载图像后 会将其添加到其单元格中 并且更改单元格的高度以适合照片 Notes 我正在
  • 在成为FirstResponder或resignFirstResponder的情况下将对象保持在键盘顶部?

    我目前在键盘顶部有一个 UITextField 当您点击它时 它应该粘在键盘顶部并平滑地向上移动 我不知道键盘的具体时长和动画类型 所以确实很坎坷 这是我所拥有的 theTextView resignFirstResponder UIVie
  • 在故事板中将 UITableView 的 rowHeight 设置为 UITableViewAutomaticDimension ?

    在 Xcode 6 中创建 iOS 8 应用程序时 如何设置 UITableViewrowHeight to UITableViewAutomaticDimension In WWDC 2014 第 226 场会议 表和集合视图中的新增功能
  • 重叠的装载机圆

    我试图重现苹果为应用程序 活动 制作的重叠圆圈 见下图 如果您使用标准贝塞尔路径 起始 结束位置将仅在 0 到 2PI 之间产生影响 例如 如果您尝试填充 4PI 即使使用一些阴影 则无法模拟重叠加载 如何制作类似于苹果解决方案的东西来创建
  • iPhone/Objective-C - 呈现视图和委托时的 UIDocumentInteractionController 类参考

    我在用UIDocumentInteractionController在我的应用程序中 以便在我的应用程序中呈现 Instagram 过滤器屏幕 如下所述 http instagram com developer iphone hooks h
  • 在文本视图滚动之前无法看到 UITextView 中的文本

    我的应用程序中有一堆文本视图 由于某种原因 无论我以编程方式 来自互联网 还是通过界面生成器 硬编码 设置 UITextView 文本 无论我做什么 当我在测试时转到该文本视图时它都是空白的 但当我滚动它的那一刻 所有文本就突然出现了 只是
  • Objective-C:int值无故改变

    Objective C 我需要帮助保留 int 的值 无需我的命令 它就在我身上发生变化 最初的问题是 如何声明和保留 int 这在另一篇文章中得到了满足 Objective C 如何声明和保留 int https stackoverflo
  • 从命令行调试 iOS 应用程序构建

    我正在通过命令行构建 iOS 应用程序 但在调试它时遇到问题 如果我使用 XCode 进行构建 它会让我在设备上 构建和调试 而不会出现任何问题 但现在 我不知道如何使用 gdb 在设备上启动它并逐步执行它 如果我尝试 添加自定义目标 可执
  • 关于窗口层次结构的警告

    我的调试器中出现这样的警告 这是什么意思 Warning Attempt to present
  • 防止 AlertView 被解雇

    任何人都可以帮助我防止在其按钮单击事件上解雇警报视图吗 我有一个 textview 作为我的alertView 的子视图 如果 textview 值为 nil 我不想关闭它 因为这是一个非常老的问题 但我得到了一个解决方案 并且如果其他开发
  • 来自 iPhone/iPad 的 json Web 服务

    有人可以帮助我解决如何从 iphone 或 ipad 使用 json Web 服务的问题吗 这里我的要求是使用 API 密钥实现 json webservice 如果可能的话发布一些教程或示例链接 谢谢 规范的 JSON 处理库是here

随机推荐

  • std::allocator 构造/销毁与放置 new/p->~T()

    对于我的一个项目 我正在从头开始编写一些 STL 容器 我有我的理由 由于我如此密切地模仿 STL 的功能和接口 因此我会尽最大努力遵守 如果它与标准结构同名 它将尽可能符合标准 的政策 因此 当然我的容器将分配器作为模板参数 这非常好 因
  • NGINX“Access-Control-Allow-Origin”标头包含多个值

    我有一个带有 PHP 的 NGINX 服务器 假设主机名为http myserver com 我有一个 PHP 脚本 我正在通过 XHR 从本地主机上的网页访问该脚本 我将它用作类似于 freegeoip net 的 GeoIP 服务器 我
  • 将行从一个表复制到另一个表,忽略重复项

    我有 2 个具有相同架构的表 srcTable1 和 destTable 我试图将所有行从 srcTable 复制到 destTable 并忽略重复项 我想我可以添加一个带有子查询的 WHERE 子句 该子查询只会给我不重复的行 然而 它似
  • android.widget.Button 无法转换为 android.widget.EditText

    在开发我的第一个 Android 计算器应用程序时 我通过意图传递答案 成功更新了新活动中的 TextView 但这需要用户按 返回 来执行另一次计算 我试图让 doCalculation 按钮更新 MainActivity 中的简单 Te
  • unix 套接字上的原子写入?

    我正在尝试选择pipes and Unix 套接字对于IPC机制 两者都支持select and epoll 功能很棒 现在 管道具有 4kB 截至今天 的 原子 写入 这是由 Linux 内核保证的 unix 套接字是否存在这样的功能 我
  • OpenCV 中未记录的 groupRectangles 变体

    在OpenCV中的cascadeDetect cpp中 有以下几种变体groupRectangles功能 void groupRectangles std vector
  • 了解 JavaScript 中的事件队列和调用堆栈

    当我解决这个问题时 我对理解 事件队列 和 调用堆栈 概念的好奇心开始了 var list readHugeList var nextListItem function var item list pop if item process t
  • 构建参数化的 EntityFramework 核心表达式

    你好 我正在尝试构建一个表达式来通过主键获取通用实体并获取参数化的 SQL 查询 目前我可以获得正确的 WHERE 查询 但它没有参数化 public async Task
  • 将侦听器添加到通过 XTemplate 创建的 DOM 的正确技术?

    我们使用 XTemplates 很多 XTemplates 它们非常适合显示只读内容 但是您是否曾向通过模板创建的 DOM 添加 Ext JS 侦听器 您愿意分享您创建这些侦听器的首选技术吗 我首选的技术是使用类似的 live来自 jque
  • 有没有办法从 DataContract 导出 XSD 架构

    我正在使用 DataContractSerializer 将我的类序列化为 XML 或从 XML 反序列化 一切工作正常 但在某些时候我想为这些 XML 文件的格式建立一个独立于实际代码的标准架构 这样 如果序列化过程中出现问题 我可以随时
  • HTML 中所有锚点的一般偏移量?

    我有一些锚元素 但它们位于绝对位置 div 并且 div 的内容太大 以至于它在内部滚动 溢出 自动 div 中的所有条目顶部都有一个锚点 但是如果我转到这个锚点 我想要的元素直接位于侧面的顶部 但我希望它位于中心 我需要像偏移这样的东西
  • Java - 类方法可以看到同类参数的私有字段

    我遇到了一个相当奇怪的行为 不确定这是 Java 问题还是 Eclipse 的问题 采取以下代码 class Foo private String text public void doStuff Foo f System out prin
  • 无法创建 PoolableConnectionFactory(用户 ''@'localhost' 的访问被拒绝

    在过去的几天里 我一直在尝试为网络应用程序设置 DatabaseConnectionPool 但没有成功 我已经阅读了 Tomcat 文档的相关部分以及围绕该主题的大量内容 并认为我做的一切都是正确的 但显然不是因为我不断收到以下错误 Ca
  • 在 Docker 容器中运行时,JVM 无法映射保留内存

    我似乎根本无法在服务器上的 Docker 容器中运行 java 即使在发行时java version 我收到以下错误 root 86088d679103 java version OpenJDK 64 Bit Server VM warni
  • C++ 聚合没有虚函数吗?

    在 C 中 聚合是 取自语言规范的 8 5 1p1 一个数组或一个类 第 9 条 没有用户提供的构造函数 12 1 没有私有或 受保护的非静态数据成员 第 11 条 无基类 第 10 条 并且无虚函数 10 3 So 1不是一个聚合 但是
  • 无法使用 mySQL 的 root 密码登录 phpMyAdmin(在 Mac OS X Lion 上)

    因此 我尝试使用 root 密码 用户名 root 密码 登录 phpMyAdmin 但是 我仍然收到错误 2002 无法登录MySQL服务器 我非常确定我知道 root 密码 因为我在 Mac OS X 的终端中输入了以下行 sudo u
  • 警告 请求的配置文件“pom.xml”无法激活,因为它不存在

    我正在尝试运行 Maven goal validation 并不断获取 警告 请求的配置文件 pom xml 无法激活 因为它不存在 在我的 org eclipse m2e core prefs 中 activeProfiles pom x
  • window.onblur 不工作

    我似乎无法让 window onblur 正常工作 window onblur console log blur 当侦听器应用于窗口时 它仅在加载页面时运行 而不是在窗口失去焦点时运行 Ryudice 已经告诉你该怎么做 但没有解释why它
  • java读取DER格式的私钥

    我有以下代码来读取 PKCS 8 格式的私钥 public void encryptHash String hashToEncrypt String pathOfKey String Algorithm FileInputStream fi
  • 从 AVAssetWriter 读取实时 H.264 输出时数据损坏

    我正在使用一些技巧来尝试在将 AVAssetWriter 写入磁盘时读取其原始输出 当我通过连接各个文件来重新组装它们时 生成的文件与 AVAssetWriter 的输出文件的字节数完全相同 但是 重新组装的文件将无法在 QuickTime