Tôi nhận thấy trong tài liệu iOS cho AVAssetWriterInput
bạn có thể chuyển nil
cho từ điển outputSettings
để xác định rằng dữ liệu đầu vào không được mã hóa lại.Sử dụng AVAssetWriter với các đơn vị NAL thô
Cài đặt được sử dụng để mã hóa phương tiện được nối vào đầu ra. Vượt qua nil để chỉ định rằng các mẫu được thêm vào sẽ không được mã hóa lại.
Tôi muốn tận dụng lợi thế của tính năng này để vượt qua trong một dòng H.264 NALs liệu, nhưng tôi đang gặp khó khăn thích nghi với dòng byte liệu của tôi vào một CMSampleBuffer
mà tôi có thể vượt qua thành phương pháp appendSampleBuffer
AVAssetWriterInput của. Luồng NAL của tôi chỉ chứa SPS/PPS/IDR/P NAL (1, 5, 7, 8). Tôi đã không thể tìm thấy tài liệu hoặc một câu trả lời kết luận về cách sử dụng dữ liệu H264 được mã hóa trước bằng AVAssetWriter. Không thể phát tệp video kết quả.
Làm cách nào để tôi có thể đóng gói đúng các đơn vị NAL vào CMSampleBuffers
? Tôi có cần sử dụng tiền tố mã bắt đầu không? Tiền tố chiều dài? Tôi có cần đảm bảo rằng tôi chỉ đặt một NAL cho mỗi CMSampleBuffer
? Mục tiêu cuối cùng của tôi là tạo vùng chứa MP4 hoặc MOV với H264/AAC.
Dưới đây là đoạn code tôi đã chơi với:
-(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];
});
}
Lưu ý rằng tôi gọi CMSampleBufferSetOutputPresentationTimeStamp
trên đệm mẫu bên trong của phương pháp writeSampleBuffer
với những gì tôi nghĩ là một thời gian hợp lệ trước khi tôi thực sự cố gắng nối thêm.
Mọi trợ giúp đều được đánh giá cao.
Ít nhất một phần vấn đề của tôi là cách tôi xử lý CMSampleTimingInfo.Tôi đã đề cập đến tôi đã sử dụng 'setOutputPresentationTimeStamp' để điền vào một dấu thời gian thực. Bây giờ tôi nhận ra rằng tôi cũng cần phải điền vào các trường khác của CMSampleTimingInfo. Tôi đang thiết lập 'decodeTimeStamp' thành' kCMTimeInvalid' và 'duration' thành' CMTimeMake (1, 30) '. Bây giờ tôi nhận được một thùng chứa video có thể tìm kiếm với tổng thời gian thích hợp, nhưng không có video (thử nghiệm trong VLC). – bsirang