【发布时间】:2013-12-09 21:32:29
【问题描述】:
我正在尝试在 iPhone 5 上捕捉视频以进行实时上传和 HLS 流式传输。我正处于在设备上生成视频的阶段(尚未上传到服务器)。就像 SO 建议的这些链接一样,我已经编写了一些代码,每五秒钟切换一次 AssetWriter。
- Upload live streaming video from iPhone like Ustream or Qik
- streaming video FROM an iPhone
- Data corruption when reading realtime H.264 output from AVAssetWriter
现在在开发期间,我只是将文件保存到本地设备并通过 XCode Organizer 将它们拉出。然后我运行 Apple 的 mediafilesegmenter 将它们简单地转换为 MPEG2-TS(它们已经低于 10 秒,因此没有发生实际的分段 - 我假设它们只是被转换为 TS)。我通过编辑在此过程中创建的各种索引文件(目前也是手动)来构建 m3u8。
当我将资产放在服务器上进行测试时,它们大部分都可以正确流式传输,但我可以判断何时有分段切换,因为音频短暂下降(可能还有视频,但我无法确定 -看起来不错)。对于从单个输入文件分段的典型 HLS 流,这显然不会发生。我不知道是什么原因造成的。
您可以在此处在您的 iPhone 上打开我的 HLS 流(您可以在 5 秒后听到音频下降,然后在 10 秒左右再次听到)
在我的创作过程中(无论是在设备上还是在后期处理中)是否发生了导致短暂音频丢失的事情?我认为我在 AssetWriter 切换期间不会丢弃任何 sampleBuffer(参见代码)。
- (void)writeSampleBuffer:(CMSampleBufferRef)sampleBuffer ofType:(NSString *)mediaType
{
if (!self.isStarted) {
return;
}
@synchronized(self) {
if (mediaType == AVMediaTypeVideo && !assetWriterVideoIn) {
videoFormat = CMSampleBufferGetFormatDescription(sampleBuffer);
CFRetain(videoFormat);
assetWriterVideoIn = [self addAssetWriterVideoInput:assetWriter withFormatDesc:videoFormat];
[tracks addObject:AVMediaTypeVideo];
return;
}
if (mediaType == AVMediaTypeAudio && !assetWriterAudioIn) {
audioFormat = CMSampleBufferGetFormatDescription(sampleBuffer);
CFRetain(audioFormat);
assetWriterAudioIn = [self addAssetWriterAudioInput:assetWriter withFormatDesc:audioFormat];
[tracks addObject:AVMediaTypeAudio];
return;
}
if (assetWriterAudioIn && assetWriterVideoIn) {
recording = YES;
if (assetWriter.status == AVAssetWriterStatusUnknown) {
if ([assetWriter startWriting]) {
[assetWriter startSessionAtSourceTime:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)];
if (segmentationTimer) {
[self setupQueuedAssetWriter];
[self startSegmentationTimer];
}
} else {
[self showError:[assetWriter error]];
}
}
if (assetWriter.status == AVAssetWriterStatusWriting) {
if (mediaType == AVMediaTypeVideo) {
if (assetWriterVideoIn.readyForMoreMediaData) {
if (![assetWriterVideoIn appendSampleBuffer:sampleBuffer]) {
[self showError:[assetWriter error]];
}
}
}
else if (mediaType == AVMediaTypeAudio) {
if (assetWriterAudioIn.readyForMoreMediaData) {
if (![assetWriterAudioIn appendSampleBuffer:sampleBuffer]) {
[self showError:[assetWriter error]];
}
}
}
}
}
}
}
- (void)setupQueuedAssetWriter
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSLog(@"Setting up queued asset writer...");
queuedFileURL = [self nextFileURL];
queuedAssetWriter = [[AVAssetWriter alloc] initWithURL:queuedFileURL fileType:AVFileTypeMPEG4 error:nil];
if ([tracks objectAtIndex:0] == AVMediaTypeVideo) {
queuedAssetWriterVideoIn = [self addAssetWriterVideoInput:queuedAssetWriter withFormatDesc:videoFormat];
queuedAssetWriterAudioIn = [self addAssetWriterAudioInput:queuedAssetWriter withFormatDesc:audioFormat];
} else {
queuedAssetWriterAudioIn = [self addAssetWriterAudioInput:queuedAssetWriter withFormatDesc:audioFormat];
queuedAssetWriterVideoIn = [self addAssetWriterVideoInput:queuedAssetWriter withFormatDesc:videoFormat];
}
});
}
- (void)doSegmentation
{
NSLog(@"Segmenting...");
AVAssetWriter *writer = assetWriter;
AVAssetWriterInput *audioIn = assetWriterAudioIn;
AVAssetWriterInput *videoIn = assetWriterVideoIn;
NSURL *fileURL = currentFileURL;
//[avCaptureSession beginConfiguration];
@synchronized(self) {
assetWriter = queuedAssetWriter;
assetWriterAudioIn = queuedAssetWriterAudioIn;
assetWriterVideoIn = queuedAssetWriterVideoIn;
}
//[avCaptureSession commitConfiguration];
currentFileURL = queuedFileURL;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
[audioIn markAsFinished];
[videoIn markAsFinished];
[writer finishWritingWithCompletionHandler:^{
if (writer.status == AVAssetWriterStatusCompleted ) {
[fileURLs addObject:fileURL];
} else {
NSLog(@"...WARNING: could not close segment");
}
}];
});
}
【问题讨论】:
标签: ios video-streaming http-live-streaming