Ho notato nella documentazione di iOS per AVAssetWriterInput
è possibile passare nil
per il dizionario outputSettings
per specificare che i dati di input non devono essere ricodificati.Utilizzo di AVAssetWriter con unità NAL raw
Le impostazioni utilizzate per la codifica del supporto aggiunto all'output. Passare a zero per specificare che i campioni aggiunti non devono essere ricodificati.
voglio approfittare di questa caratteristica per passare in un flusso di H.264 Nalles prime, ma sto avendo difficoltà ad adattarsi ai miei flussi di byte grezzi in un CMSampleBuffer
che posso passare nel metodo di AVAssetWriterInput appendSampleBuffer
. Il mio flusso di NAL contiene solo NAL SPS/PPS/IDR/P (1, 5, 7, 8). Non sono stato in grado di trovare documentazione o una risposta definitiva su come utilizzare i dati H264 pre-codificati con AVAssetWriter. Il file video risultante non può essere riprodotto.
Come posso impacchettare correttamente le unità NAL in CMSampleBuffers
? Devo usare un prefisso del codice di avviamento? Un prefisso di lunghezza? Devo assicurarmi di inserire solo un valore NAL per CMSampleBuffer
? Il mio obiettivo finale è creare un contenitore MP4 o MOV con H264/AAC.
Ecco il codice che ho giocato con:
-(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];
});
}
Si noti che sto chiamando CMSampleBufferSetOutputPresentationTimeStamp
sul tampone campione all'interno del metodo writeSampleBuffer
con quello che credo sia un tempo valido prima che io sono in realtà cercando di aggiungerlo.
Qualsiasi aiuto è apprezzato.
Almeno una parte del mio problema era come avevo a che fare con CMSampleTimingInfo.Ho detto che stavo usando 'setOutputPresentationTimeStamp' per riempire un timestamp reale. Ora mi rendo conto che ho bisogno di compilare anche gli altri campi di CMSampleTimingInfo. Sto impostando 'decodeTimeStamp' su' kCMTimeInvalid' e 'duration' su' CMTimeMake (1, 30) '. Ora ho un contenitore video ricercabile con un tempo totale adeguato, ma non c'è video (test in VLC). – bsirang