audiolib/audio/audio_demuxer_adts.c

193 lines
7.5 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "audio.h"
#include "audio_internal.h"
#include "audio_demuxer_adts.h"
typedef struct _DemuxerADTSContext {
uint32_t outputBufferPosition;
uint32_t missingBytesInLastPacket;
AudioBuffer *outputBuffer;
uint8_t headerData[7];
uint8_t headerIndex;
} DemuxerADTSContext;
static uint32_t const sampleRateTable[16] = {
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
16000, 12000, 11025, 8000, 7350, 0, 0, 0
};
ADTSHeader demuxer_adts_decode_header(uint8_t data[7]) {
ADTSHeader header = { 0 };
header.valid = true;
header.version = (data[1] >> 3) & 0x01;
header.valid = ((data[1] >> 1) & 0x03) == 0; // layer is always set to 0
header.has_crc = (data[1] & 0x01) == 0;
header.type = ((data[2] >> 6) & 0x03) + 1;
header.sampleRateIndex = (data[2] >> 2) & 0x03;
header.is_private = (data[2] >> 1) & 0x01;
header.channelMode = ((data[2] & 0x01) << 2) + ((data[3] >> 6) & 0x03);
header.is_original = (data[3] >> 5) & 0x01;
header.is_home = (data[3] >> 4) & 0x01;
header.has_copyright = (data[3] >> 3) & 0x01;
header.copyright_start = (data[3] >> 2) & 0x01;
header.packetLength = (data[3] & 0x03) << 11;
header.packetLength += data[4] << 3;
header.packetLength += (data[5] >> 5) & 0x07;
header.numAACFrames = (data[6] & 0x03) + 1;
if (header.valid) {
header.sampleRate = sampleRateTable[header.sampleRateIndex];
header.packetLength -= 7; // Header
} else {
fprintf(stderr, "Invalid header!\n");
}
return header;
}
static inline AudioPipelineStatus demuxer_adts_emit(AudioPipelineElement *self) {
DemuxerADTSContext *context = (DemuxerADTSContext *)self->ctx;
//fprintf(stderr, "INFO: Emitting packet of size %d\n", context->outputBufferPosition);
uint32_t buf_sz = context->outputBuffer->buf_size;
context->outputBuffer->buf_size = context->outputBufferPosition;
AudioPipelineStatus result = self->next->push(self->next, context->outputBuffer);
context->outputBuffer->buf_size = buf_sz;
context->outputBufferPosition = 0;
return result;
}
AudioPipelineStatus demuxer_adts_push(AudioPipelineElement *self, AudioBuffer *buffer) {
DemuxerADTSContext *context = (DemuxerADTSContext *)self->ctx;
uint32_t start = 0;
bool sync = true;
if (context->missingBytesInLastPacket) {
if (buffer->buf_size < context->missingBytesInLastPacket) {
uint32_t remaining_bytes = (context->missingBytesInLastPacket - buffer->buf_size);
//fprintf(stderr, "INFO: Last buffer was too short, copying %d bytes, %d remaining \n", buffer->buf_size, remaining_bytes);
memcpy(context->outputBuffer->data + context->outputBufferPosition, buffer->data, buffer->buf_size);
context->outputBufferPosition += buffer->buf_size;
context->missingBytesInLastPacket = remaining_bytes;
return PipelineBuffering;
}
//fprintf(stderr, "INFO: Last buffer was too short, copying %d bytes\n", context->missingBytesInLastPacket);
memcpy(context->outputBuffer->data + context->outputBufferPosition, buffer->data, context->missingBytesInLastPacket);
context->outputBufferPosition += context->missingBytesInLastPacket;
demuxer_adts_emit(self);
start = context->missingBytesInLastPacket;
context->missingBytesInLastPacket = 0;
}
for (uint32_t i = start; i < buffer->buf_size; i++) {
switch (context->headerIndex) {
case 0:
if (buffer->data[i] != 0xff) {
if (sync) {
fprintf(stderr, "WARN: Sync lost at %d\n", i);
sync = false;
}
continue;
}
context->headerData[context->headerIndex++] = buffer->data[i];
continue;
case 1:
if (buffer->data[i] < 0xf0) {
context->headerIndex = 0;
continue;
}
context->headerData[context->headerIndex++] = buffer->data[i];
continue;
case 2:
case 3:
case 4:
case 5:
case 6:
context->headerData[context->headerIndex++] = buffer->data[i];
continue;
default:
break;
}
context->headerIndex = 0;
// sync marker found, try to decode the header
ADTSHeader header = demuxer_adts_decode_header(context->headerData);
if (!header.valid) {
continue;
}
sync = true;
if (i + header.packetLength < buffer->buf_size) {
// FIXME: realloc output Buffer size if too small
//fprintf(stderr, "INFO: Found frame sync at %d, copying %d bytes\n", i, header.packetLength);
memcpy(context->outputBuffer->data + context->outputBufferPosition, context->headerData, 7);
context->outputBufferPosition += 7;
memcpy(context->outputBuffer->data + context->outputBufferPosition, buffer->data + i, header.packetLength);
i += header.packetLength - 1;
context->outputBufferPosition += header.packetLength;
demuxer_adts_emit(self);
} else {
uint32_t remaining_bytes = (buffer->buf_size - i);
//fprintf(stderr, "INFO: Found frame sync at %d, buffer too short copying %d bytes\n", i, remaining_bytes);
memcpy(context->outputBuffer->data + context->outputBufferPosition, context->headerData, 7);
context->outputBufferPosition += 7;
memcpy(context->outputBuffer->data + context->outputBufferPosition, buffer->data + i, remaining_bytes);
context->outputBufferPosition += remaining_bytes;
context->missingBytesInLastPacket = header.packetLength - remaining_bytes;
return PipelineBuffering;
}
}
return PipelineRunning;
}
AudioPipelineStatus demuxer_adts_link(AudioPipelineElement *self, AudioPipelineElement *source) {
if ((source->sample_rate != 0) || (source->channels != 0) || (source->bits_per_sample != 0) || (source->type != AudioElementSource)) {
fprintf(stderr, "ERROR: ADTS demuxer can only link to a data source, not %s!\n", source->describe(source));
return PipelineError;
}
source->next = self;
return PipelineStopped;
}
char *demuxer_adts_describe(AudioPipelineElement *self) {
return "adts demuxer";
}
void demuxer_adts_destroy(AudioPipelineElement *self) {
DemuxerADTSContext *context = (DemuxerADTSContext *)self->ctx;
if (context->outputBuffer) {
free(context->outputBuffer);
}
free(context);
free(self);
}
AudioPipelineElement *audio_demuxer_adts(void) {
AudioPipelineElement *self = calloc(1, sizeof(AudioPipelineElement));
DemuxerADTSContext *context = calloc(1, sizeof(DemuxerADTSContext));
context->outputBuffer = alloc_audio_buffer(
4 /* max frames per adts packet */
* 768 /* max aac packet size per channel */
* 2 /* channels */
);
self->ctx = context;
self->describe = demuxer_adts_describe;
self->start = filter_start_nop;
self->reset = filter_reset_nop;
self->stop = filter_stop_nop;
self->push = demuxer_adts_push;
self->link = demuxer_adts_link;
self->destroy = demuxer_adts_destroy;
self->type = AudioElementDemuxer;
return self;
}