Search code examples
iosaudioavfoundationlibvlc

How do I add ADTS header when reading m4a raw data from iPod library?


Objective

Reading m4a file bought from iTunes Store via AVAssetReader. Stream via HTTP and consumed by MobileVLCKit.

What I've tried

As far as I know, AVAssetReader only generates audio raw data, so I guess I should add ADTS header in front of every sample.

NSError *error = nil;
AVAssetReader* reader = [[AVAssetReader alloc] initWithAsset:asset error:&error];
if (error != nil) {
    NSLog(@"%@", [error localizedDescription]);
    return -1;
}

AVAssetTrack* track = [asset.tracks objectAtIndex:0];
AVAssetReaderTrackOutput *readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:track
                                                                                        outputSettings:nil];
[reader addOutput:readerOutput];
    [reader startReading];
    while (reader.status == AVAssetReaderStatusReading){
        AVAssetReaderTrackOutput * trackOutput = (AVAssetReaderTrackOutput *)[reader.outputs objectAtIndex:0];
        CMSampleBufferRef sampleBufferRef;
        @synchronized(self) {
            sampleBufferRef = [trackOutput copyNextSampleBuffer];
        }
        CMItemCount = CMSampleBufferGetNumSamples(sampleBufferRef);
        ...
    }

So, my question is, how do I loop every sample and add ADTS header?


Solution

  • First, you don't need trackOutput, it's the same as readerOutput that you already have.

    UPDATE
    My mistake, you're absolutely right. I thought the usual 0xFFF sync words were part of AAC, instead they're ADTS headers. So you must add an ADTS header to each of your AAC packets to stream them as ADTS or "aac". I think you have two choices:

    1. Use AudioFileInitializeWithCallbacks + kAudioFileAAC_ADTSType to get the AudioFile API to add the headers for you. You write AAC packets to the AudioFileID and it will call your write callback from where you can stream AAC in ADTS.

    2. Add the headers to the packets yourself. They're only 7 fiddly bytes (9 with checksums, but who uses them?). Some readable implementations here and here

    Either way you need to call either CMSampleBufferGetAudioStreamPacketDescriptions or CMSampleBufferCallBlockForEachSample to get the individual AAC packets from a CMSampleBufferRef.