Я пытаюсь записать видео на iPhone 5 для загрузки в реальном времени и потоковой передачи HLS. Я нахожусь на этапе создания видео на устройстве (еще не загружающего на сервер). Как и предполагают эти ссылки на SO, я собрал код, который отключает AssetWriters каждые пять секунд.
- Загружайте потоковое видео в реальном времени с iPhone, например Ustream или Qik а>
- потоковое видео с iPhone
- Повреждение данных при чтении вывода H.264 в реальном времени из AVAssetWriter < / а>
Прямо сейчас во время разработки я просто сохраняю файлы на устройство локально и вытаскиваю их через XCode Organizer. Затем я запускаю Mediafilesegmenter от Apple, чтобы просто преобразовать их в MPEG2-TS (они уже менее 10 секунд, поэтому фактического сегментирования не происходит - я предполагаю, что они просто конвертируются в TS). Я создаю m3u8, редактируя вместе различные индексные файлы, созданные во время этого процесса (в настоящее время также вручную).
Когда я помещаю ресурсы на сервер для тестирования, они в основном транслируются правильно, но я могу сказать, когда происходит переключение сегмента, потому что звук на короткое время падает (возможно, видео тоже, но я не могу сказать наверняка - выглядит нормально ). Очевидно, этого не происходит для типичных потоков HLS, сегментированных из одного входного файла. Я не понимаю, что вызывает это.
Вы можете открыть мой поток HLS на своем iPhone здесь (вы можете услышать пропадание звука через 5 секунд и снова около 10)
Может ли что-то происходить в процессе моего создания (на устройстве или при постобработке), что вызывает кратковременные пропадания звука? Я не думаю, что отбрасываю какой-либо sampleBuffer во время переключения AssetWriter (см. Код).
- (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");
}
}];
});
}