2015-05-13 2 views
1

Я использую библиотеку Bento4 для мультиплексирования файла TS TS (MPEG-2 транспортного потока) приложения B с видео h264 и аудиопотоками AAC, которые генерируются из VideoToolbox и AVFoundation соответственно, в качестве исходных данных для HLS (HTTP Live Streaming). Этот вопрос не обязательно специфичен для Bento4: я пытаюсь понять базовые понятия, чтобы выполнить задачу, желательно используя Apple libs.Звуковой эквивалент SPS и PPS при мультиплексировании Приложение B MPEG-TS? Что такое «DecoderInfo»?

До сих пор я понял, как создать AP4_AvcSampleDescription путем получать различные виды данных из моего CMVideoFormatDescriptionRef, а самое главное генерируя SPS и PPS с использованием индекса 0 и 1 соответственно CMVideoFormatDescriptionGetH264ParameterSetAtIndex, что я могу просто придерживаться как байтовые буферы в Bento4. Отлично, это вся информация заголовка, в которой я нуждаюсь, чтобы я мог запросить Bento4 мультиплексирование видео в ts-файл!

Теперь я пытаюсь отключить звук в одном файле. Я использую свой CMAudioFormatDescriptionRef, чтобы получить необходимую информацию для построения моего AP4_MpegAudioSampleDescription, который Bento4 использует для создания необходимых QT-атомов и заголовков. Однако, если поля являются байтовым буфером «декодер информации», без объяснения того, что это такое, или код для генерации одного из данных. Я бы надеялся иметь CMAudioFormatDescriptionGetDecoderInfo или что-то в этом роде, но я не могу найти ничего подобного. Есть ли такая функция в любой библиотеке Apple? Или есть хорошая спецификация, которую я не нашел о том, как сгенерировать эти данные?

Или, наоборот, я иду по неправильному пути? Есть ли более простой способ для mux ts-файлов с базы данных Mac/iOS?

ответ

1

Мультимедийный звук в MPEG-TS на удивление прост и не требует сложного заголовка, подобного потоку видео! Для каждого буфера выборки требуется только 7-байтовый заголовок ADTS, прежде чем писать его как PES.

Bento4 использует буфер «DecoderInfo» для того, чтобы разобрать его на экземпляр AP4_Mp4AudioDecoderConfig, чтобы он мог извлечь информацию, необходимую для заголовка ADTS. Вместо того, чтобы обходить эту информацию, я сделал копию-вставку AP4_Mpeg2TsAudioSampleStream::WriteSample, которая пишет CMSampleBufferRef. Это легко может быть обобщена для других аудио рамок, но я просто вставить его как-здесь для справки:

// These two functions are copy-pasted from Ap4Mpeg2Ts.cpp 
static unsigned int GetSamplingFrequencyIndex(unsigned int sampling_frequency) { ... } 
static void 
MakeAdtsHeader(unsigned char *bits, 
       size_t frame_size, 
       unsigned int sampling_frequency_index, 
       unsigned int channel_configuration) { ... } 

static const size_t kAdtsHeaderLength = 7; 

- (void)appendAudioSampleBuffer2:(CMSampleBufferRef)sampleBuffer 
{ 
    // Get the actual audio data from the block buffer. 
    CMBlockBufferRef blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer); 
    size_t blockBufferLength = CMBlockBufferGetDataLength(blockBuffer); 

    // Get the audio meta-data from its AudioFormatDescRef 
    CMAudioFormatDescriptionRef audioFormat = CMSampleBufferGetFormatDescription(sampleBuffer); 
    const AudioStreamBasicDescription *asbd = CMAudioFormatDescriptionGetStreamBasicDescription(audioFormat); 

    // These are the values we will need to build our ADTS header 
    unsigned int sample_rate = asbd->mSampleRate; 
    unsigned int channel_count = asbd->mChannelsPerFrame; 
    unsigned int sampling_frequency_index = GetSamplingFrequencyIndex(sample_rate); 
    unsigned int channel_configuration = channel_count; 

    // Create a byte buffer with first the header, and then the sample data. 
    NSMutableData *buffer = [NSMutableData dataWithLength:kAdtsHeaderLength + blockBufferLength]; 
    MakeAdtsHeader((unsigned char*)[buffer mutableBytes], blockBufferLength, sampling_frequency_index, channel_configuration); 
    CMBlockBufferCopyDataBytes(blockBuffer, 0, blockBufferLength, ((char*)[buffer mutableBytes])+kAdtsHeaderLength); 

    // Calculate a timestamp int64 that Bento4 can use, by converting our CMTime into an Int64 in the timescale of the audio stream. 
    CMTime presentationTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer); 
    AP4_UI64 ts = CMTimeConvertScale(presentationTime, _audioStream->m_TimeScale, kCMTimeRoundingMethod_Default).value; 

    _audioStream->WritePES(
     (const unsigned char*)[buffer bytes], 
     (unsigned int)[buffer length], 
     ts, 
     false, // don't need a decode timestamp for audio 
     ts, 
     true, // do write a presentation timestamp so we can sync a/v 
     *_output 
    ); 
} 
0

Байт-буфер «декодера», необходимый Bento4 для создания экземпляра AP4_MpegAudioSampleDescription, представляет собой данные инициализации кодека, специфичные для кодека. Для аудио AAC-LC обычно это 2 байта данных (для HE-AAC вы получите еще несколько байтов), детали которых указаны в спецификации AAC. Например, потоки 44,1 кГц, стерео, AAC-LC будут иметь [0x12,0x10] в качестве данных инициализации. В большинстве API Apple этот тип данных инициализации кодека передается через то, что они называют «Magic Cookies». Вероятно, функция CMAudioFormatDescriptionGetMagicCookie вернет вам то, что вам нужно.

+0

OOH, думал, что вы могли бы показать с, с правильными тегами: D Спасибо !! Могу ли я предположить, что AP4_SampleDescription вместо этого использует экземпляр AP4_Mp4AudioDecoderConfig, чтобы пользователям API не приходилось иметь дело с этой деталью реализации? :) Я закончил тем, что скопировал WriteSample с версией, которая берет только то, что у меня есть и что мне нужно для моих данных; Я отправлю ответ, когда я его заработаю ... (edit: MagicCookie возвращает NULL:/не то, что мне это нужно, но просто fyi) – nevyn