我想将fMP4片段转换为TS段(用于HLS),因为片段是在iOS设备上使用FFmpeg编写的.
我正在尝试在iOS上实现实时上传,同时在本地保持无缝的高清副本.
滚动AVAssetWriters,每次写入8秒,然后通过FFmpeg连接MP4.
出了什么问题 - 音频和视频有时会出现问题.我已经确定了3个原因.
1)为AAC编码器写入的音频启动帧,从而产生间隙.
2)由于视频帧长33.33ms,音频帧长0.022ms,因此它们可能不在文件末尾排队.
3)Mac OS上缺少帧精确编码,但iOS 详细信息不适用于此
FFmpeg将具有原始音频的大视频MP4文件复用到TS段中.这项工作基于Kickflip SDK
什么是错的 - 每隔一段时间,只有一个音频文件会上传,没有任何视频.永远不能在内部重现它,但当他们没有记录他们认为他们做的事情时,它对我们的用户来说非常令人沮丧.在最后一段上也存在准确搜索的问题,几乎就像TS段的时间戳错误一样.
苹果公司今年(2016年)正在WWDC推动fMP4,在此之前我还没有对它进行太多调查.由于fMP4文件可以在写入时读取和播放,我认为FFmpeg也可以在写入时对文件进行转码,只要我们阻止将字节发送到FFmpeg直到每个片段内文件完成了.
但是,我对FFmpeg C API并不熟悉,我只是在尝试#2中简单地使用它.
AVFoundation已经完成在文件中写一个片段,以便我可以将它管道输入FFmpeg?我在使用Kotlin和RxJava的Android应用中遇到了一个问题.它如下所示.
import rx.Observable
data class TestUser(val name: String)
fun getTestUser(): Observable<TestUser> {
return Observable.just(TestUser("Brian")).flatMap { getUser() } // this compiles
}
fun getTestUser2(): Observable<TestUser> {
val observable = Observable.just(TestUser("Brian")).flatMap { getUser() }
return observable // this does not compile
}
fun getUser(): Observable<TestUser?> {
return Observable.just(null)
}
Run Code Online (Sandbox Code Playgroud)
在getTestUser2,编译器推断最终返回类型为Observable<TestUser?>和不编译.然而,getTestUser在代码中进行编译,并且当它运行时,该可观察对象的任何订阅者可能会在TestUser回来时感到意外null.
我猜这与在Kotlin和Java之间来回走动有关.但是,编译器可以看到差异的事实getTestUser2使我认为这可以解决.
编辑
这是在昨天(2016年2月15日)发布的最终版Kotlin 1.0上.
我知道这是一个常见问题,但是这个堆栈跟踪显示其他错误.你可以看到即使setDisplay(holder)被称为内部surfaceCreated仍然会抛出IllegalArgumentException.这也不是一个罕见的例外,昨天在~3,000,000个剪辑视图中发生了~125,000次.我可以向你保证,mCurrentPlayer也可以正确初始化.
surfaceCreated:
@Override
public void surfaceCreated(SurfaceHolder holder) {
mIsSurfaceCreated = true;
mCurrentPlayer.setDisplay(holder);
}
Run Code Online (Sandbox Code Playgroud)
surfaceDestroy:
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mIsSurfaceCreated = false;
// Could be called after player was released in onDestroy.
if (mCurrentPlayer != null) {
mCurrentPlayer.setDisplay(null);
}
}
Run Code Online (Sandbox Code Playgroud)
堆栈跟踪:
java.lang.IllegalArgumentException: The surface has been released
at android.media.MediaPlayer._setVideoSurface(Native Method)
at android.media.MediaPlayer.setDisplay(MediaPlayer.java:660)
at com.xxx.xxx.view.VideoPlayerView.surfaceCreated(VideoPlayerView.java:464)
at android.view.SurfaceView.updateWindow(SurfaceView.java:543)
at android.view.SurfaceView.access$000(SurfaceView.java:81)
at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:169)
at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:590)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1644)
at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2505)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:154)
at …Run Code Online (Sandbox Code Playgroud) 我最近一直在试验GCD优先事项.这是我一直在使用的代码片段.
for _ in 1...1000 {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
for _ in 1...10000000 {
let _ = sin(0.64739812)
}
print("Finished a default")
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
for _ in 1...10000 {
let _ = sin(0.64739812)
}
print("Finished a high")
}
}
}
Run Code Online (Sandbox Code Playgroud)
我希望它能打印出来
Finished a default
Finished a high
// Repeat default and high alternating back and forth 1000 times (because there are 1000 loops)
Run Code Online (Sandbox Code Playgroud)
但实际发生的是打印的日志
Finished a default
Finished a high
Finished a default x 21
Finished a high
Finished …Run Code Online (Sandbox Code Playgroud) 我有一个UITableView,我的单元格处理所有的触摸而不是tableview本身.细胞需要瞬间响应单击和双击.(是的,这确实意味着单击被调用然后双击,我希望它们都被调用).
单击动作是放入敲击单元格下方的另一个单元格(该单元格是上述单元格的菜单).我为此使用insertRowsAtIndexPaths.然而,在该动画期间,用户交互似乎完全失败,因此我无法在第二次点击时启动该操作.
使用2个UITapGestureRecognizers(单击和双击)并将单个设置为等待双击失败,但会导致单击操作中出现明显的延迟.
我知道在UIView动画中你可以标记它UIViewAnimationOptionAllowUserInteraction并且它会正常工作,但是这不是UITableView中的一个选项.
有关如何在tablview动画期间继续接听触摸事件的任何想法?
我尝试过使用UITapGestureRecognizers,使用touchesEnded和touchesBegan,没有人在动画期间注册过触摸.
TL;DR -AVAudioSession将AVAudioSessionMediaServicesWereLostNotification在指定蓝牙端口时触发,AVAudioSession.setPreferredInput并且该设备在使用AVCaptureSession或主动读取输入时断开连接AVAudioEngine。示例项目在这里。
https://openradar.appspot.com/FB8921592
通过我认为的“快乐路径”,或者至少应该得到 Apple 支持的路径,我可以始终如一AVAudioSession地触发它AVAudioSessionMediaServicesWereLostNotification和AVAudioSessionMediaServicesWereResetNotification通知。
在这两个通知之间,您的应用无法执行任何音频或视频 I/O 或处理(编码或解码)。这是一个总的媒体服务关闭 1 到 2 秒。
这仅在使用时发生AVAudioSession.setPreferredInput,其中您设置的端口是蓝牙设备。从该端口主动录制时,您关闭蓝牙设备。
发生这种情况时,在服务丢失之前不会触发来自AVAudioSession、AVAudioEngine或 的其他通知AVCaptureSession,因此无法抢先处理这种情况。用户可以随时关闭耳机,导致服务全面失败。
首先我设置了音频会话
try! AVAudioSession.sharedInstance().setCategory(.record, mode: .videoRecording, options: .allowBluetooth)
try! AVAudioSession.sharedInstance().setActive(true)
Run Code Online (Sandbox Code Playgroud)
然后指定正确的端口
let bluetoothPort = AVAudioSession.sharedInstance().availableInputs?
.first(where: { $0.portType == .bluetoothHFP })
guard let validPort = newPort else {
print("Couldn't find a valid bluetooth port")
return
} …Run Code Online (Sandbox Code Playgroud) core-audio ios avcapturesession avaudiosession avaudioengine
ios ×4
android ×1
animation ×1
avfoundation ×1
core-audio ×1
ffmpeg ×1
fmp4 ×1
kotlin ×1
objective-c ×1
rx-java ×1
swift ×1
touch ×1
uitableview ×1