/**
 * Searches for ADTS 0xfff header.
 * Returns the offset of ADTS frame.
 */
int aacd_adts_sync(unsigned char *buffer, int len)
{
    int pos = 0;
    len -= 3;

    AACD_TRACE( "probe() start len=%d", len );

    while (pos < len)
    {
        if (*buffer != 0xff)
        {
            buffer++;
            pos++;
        }
        else if ((*(++buffer) & 0xf6) == 0xf0)
        {
            AACD_TRACE( "probe() found ADTS start at offset %d", pos );
            return pos;
        }
        else pos++;
    }

    AACD_WARN( "probe() could not find ADTS start" );

    return -1;
}
/**
 * Creates a new ByteIOContext.
 */
static ByteIOContext* aacd_ff_create_byteioctx( AACDFFmpegInfo *ff )
{
    int buffer_size = ff->cinfo->bbsize;
    unsigned char *buffer = av_mallocz( buffer_size );
    ByteIOContext *pb = av_alloc_put_byte( buffer, buffer_size, 0, ff, aacd_ff_io_read_packet, NULL, NULL);

    if (!pb)
    {
        av_free( buffer );
        AACD_WARN( "create_byteioctx(): ByteIOContext could not be created" );
    }

    return pb;
}
Beispiel #3
0
static int aacd_faad_decode( AACDCommonInfo *cinfo, void *ext, unsigned char *buffer, unsigned long buffer_size, jshort *jsamples, jint outLen )
{
    NeAACDecFrameInfo frame;
    jshort *ljsamples = jsamples;

    NeAACDecDecode2( ext, &frame, buffer, buffer_size, (void**)&jsamples, outLen*2 );

    if (ljsamples != jsamples) {
        AACD_WARN( "NeAACDecDecode CHANGE jsamples !!!");
    }

    cinfo->frame_bytesconsumed = frame.bytesconsumed;
    cinfo->frame_samples = frame.samples;

    if (frame.error != 0)
    {
        AACD_ERROR( "NeAACDecDecode bytesleft=%d, error: %s",
                    buffer_size,
                    NeAACDecGetErrorMessage(frame.error));
    }

    return frame.error;
}
/**
 * A wrapper method which reads packets.
 * It only reads them from the internal pre-fetched buffer in AACDCommonInfo.
 */
static int aacd_ff_io_read_packet( void *opaque, uint8_t *buf, int buf_size)
{
    AACD_TRACE( "io_read_packet() start" );

    AACDFFmpegInfo *ff = (AACDFFmpegInfo*) opaque;
    AACDCommonInfo *cinfo = ff->cinfo;

    if (cinfo->bytesleft < buf_size)
    {
        // Let's cheat now:
        AACDArrayInfo *ainfo = (AACDArrayInfo*) cinfo;
        if (!aacda_read_buffer( ainfo ))
        {
            AACD_INFO( "io_read_packet() EOF detected" );
        }
    }

    int len = buf_size < cinfo->bytesleft ? buf_size : cinfo->bytesleft;

    if (!len)
    {
        AACD_WARN( "read_packet(): no bytes left, returning 0" );
        return 0;
    }

    memcpy( buf, cinfo->buffer, len );

    cinfo->buffer += len;
    cinfo->bytesleft -= len;

    ff->bytesconsumed += len;

    AACD_TRACE( "io_read_packet() stop" );

    return len;
}
static long aacd_opencore_start( AACDInfo *info, unsigned char *buffer, unsigned long buffer_size)
{
    AACD_TRACE( "start() buffer=%x size=%d", (*(unsigned long*)buffer), buffer_size );

    AACDOpenCore *oc = (AACDOpenCore*) info->ext;
    tPVMP4AudioDecoderExternal *pExt = oc->pExt;

    pExt->remainderBits             = 0;
    pExt->frameLength               = 0;

    // prepare the first samples buffer:
    //pExt->pOutputBuffer             = malloc(4096 * sizeof(int16_t));
    //pExt->pOutputBuffer_plus        = pExt->pOutputBuffer + 2048;
    pExt->pOutputBuffer             = aacd_prepare_samples( info, 4096 );
    pExt->pOutputBuffer_plus        = pExt->pOutputBuffer + 2048;

    int32_t status;
    int frameDecoded = 0;
    int attempts = 16;

    /* pre-init search adts sync */
    while (pExt->frameLength == 0 && attempts--) {
        pExt->pInputBuffer              = buffer;
        pExt->inputBufferMaxLength      = buffer_size;
        pExt->inputBufferCurrentLength  = buffer_size;
        pExt->inputBufferUsedLength     = 0;

        status = PVMP4AudioDecoderConfig(pExt, oc->pMem);
        AACD_DEBUG( "start() Status[0]: %d", status );

        if (status != MP4AUDEC_SUCCESS) {
            status = PVMP4AudioDecodeFrame(pExt, oc->pMem);
            AACD_DEBUG( "start() Status[1]: %d", status );

            buffer -= pExt->inputBufferUsedLength;
            buffer_size -= pExt->inputBufferUsedLength;

            if (MP4AUDEC_SUCCESS == status) {
                AACD_DEBUG( "start() frameLength: %d\n", pExt->frameLength);
                frameDecoded = 1;
                continue;
            }
        }

        if (buffer_size <= PVMP4AUDIODECODER_INBUFSIZE) break;
    }

    if (!frameDecoded)
    {
        AACD_INFO( "start() No stream info available - trying to decode a frame" );

        if (buffer_size >= PVMP4AUDIODECODER_INBUFSIZE) status = PVMP4AudioDecodeFrame(pExt, oc->pMem);
        else AACD_WARN( "start() Input buffer too small" );
    }

    //free( pExt->pOutputBuffer );

    if (status != MP4AUDEC_SUCCESS)
    {
        AACD_ERROR( "start() init failed status=%d", status );
        return -1;
    }

    AACD_DEBUG( "start() bytesconsumed=%d", pExt->inputBufferUsedLength );

    int streamType  = -1;

    if ((pExt->extendedAudioObjectType == MP4AUDIO_AAC_LC) ||
            (pExt->extendedAudioObjectType == MP4AUDIO_LTP))
    {
        streamType = AAC;
    }
    else if (pExt->extendedAudioObjectType == MP4AUDIO_SBR)
    {
        streamType = AACPLUS;
    }
    else if (pExt->extendedAudioObjectType == MP4AUDIO_PS)
    {
        streamType = ENH_AACPLUS;
    }

    AACD_DEBUG( "start() streamType=%d", streamType );

    if ((AAC == streamType) && (2 == pExt->aacPlusUpsamplingFactor))
    {
        AACD_INFO( "start() DisableAacPlus" );
        PVMP4AudioDecoderDisableAacPlus(pExt, oc->pMem);
    }

    info->samplerate = pExt->samplingRate;
    info->channels = pExt->desiredChannels;

    oc->frameSamplesFactor = pExt->desiredChannels;
    if (2 == pExt->aacPlusUpsamplingFactor) oc->frameSamplesFactor *= 2;

    info->frame_bytesconsumed = pExt->inputBufferUsedLength;
    info->frame_samples = pExt->frameLength * oc->frameSamplesFactor;

    return pExt->inputBufferUsedLength;
}
static int aacd_ffwma_decode( AACDCommonInfo *cinfo, void *ext, unsigned char *buffer, unsigned long buffer_size, jshort *jsamples, jint outLen )
{
    AACD_TRACE( "decode() start" );

    AACDFFmpegInfo *ff = (AACDFFmpegInfo*) ext;
    AVFormatContext *ic = ff->avfctx;
    AVPacket *avpkt = ff->avpkt;
    AVPacket *pkt = ff->pkt;

    ff->bytesconsumed = 0;

#ifdef AACD_LOGLEVEL_TRACE
    ic->debug = FF_FDEBUG_TS;
#endif

    while (!pkt->size)
    {
        AACD_TRACE( "decode() calling av_read_frame..." );
        int err = av_read_frame( ic, avpkt );
        AACD_TRACE( "decode() av_read_frame returned: %d", err );

        if (err < 0)
        {
            AACD_ERROR( "decode() cannot read av frame" );

            return AACD_DECODE_EOF;
        }

        if (avpkt->stream_index == ff->audio_stream_index)
        {
            pkt->data = avpkt->data;
            pkt->size = avpkt->size;
            break;
        }

        // TODO: delete packet's buffer ?
        AACD_TRACE( "decode() : freeing packet's data" );
        av_freep( &avpkt->data );
    }

    AACD_TRACE( "decode() packet demuxed, will decode..." );

    AVCodecContext *avctx = ic->streams[ff->audio_stream_index]->codec;
    AVCodec *codec = avctx->codec;

    AACD_DEBUG( "decode() frame_size=%d", avctx->frame_size );

    // aac_decode_frame
    int outSize = outLen * 2;
    int consumed = (*codec->decode)( avctx, jsamples, &outSize, pkt );

    if (consumed <= 0)
    {
        AACD_ERROR( "decode() cannot decode frame pkt->size=%d, outSize=%d, error: %d", pkt->size, outSize, consumed );

        if ( cinfo->frame_samples < outLen * 3 / 2 )
        {
            AACD_WARN( "decode() trying to obtain large output buffer" );

            return AACD_DECODE_OUTPUT_NEEDED;
        }

        pkt->size = 0;

        return AACD_DECODE_OTHER;
    }

    pkt->data += consumed;
    pkt->size -= consumed;

    cinfo->frame_bytesconsumed = consumed;
    //cinfo->frame_samples = avctx->frame_size * avctx->channels;
    cinfo->frame_samples = (outSize >> 1);

    AACD_TRACE( "decode() stop - consumed %d, pkt->size=%d", consumed, pkt->size );

    return AACD_DECODE_OK;
}
/**
 * Decodes the stream - one round until the output buffer is (almost) filled.
 */
static void aacd_decode( AACDInfo *info, jshort *samples, jint outLen )
{
    AACD_DEBUG( "decode() start" );

    info->round_frames = 0;
    info->round_bytesconsumed = 0;
    info->round_samples = 0;

    do
    {
        // check if input buffer is filled:
        if (info->bytesleft <= info->frame_max_bytesconsumed)
        {
	     AACD_TRACE( "decode() reading input buffer" );
            aacd_read_buffer( info );

            if (info->bytesleft <= info->frame_max_bytesconsumed)
            {
                AACD_INFO( "decode() detected end-of-file" );
                break;
            }
        }

        AACD_TRACE( "decode() frame - frames=%d, consumed=%d, samples=%d, bytesleft=%d, frame_maxconsumed=%d, frame_samples=%d, outLen=%d", info->round_frames, info->round_bytesconsumed, info->round_samples, info->bytesleft, info->frame_max_bytesconsumed, info->frame_samples, outLen);

        int attempts = 10;

        do
        {
            if (!info->decoder->decode( info, info->buffer, info->bytesleft, samples, outLen )) break;

            AACD_WARN( "decode() failed to decode a frame" );
            AACD_DEBUG( "decode() failed to decode a frame - frames=%d, consumed=%d, samples=%d, bytesleft=%d, frame_maxconsumed=%d, frame_samples=%d, outLen=%d", info->round_frames, info->round_bytesconsumed, info->round_samples, info->bytesleft, info->frame_max_bytesconsumed, info->frame_samples, outLen);

            if (info->bytesleft <= info->frame_max_bytesconsumed)
            {
                aacd_read_buffer( info );

                if (info->bytesleft <= info->frame_max_bytesconsumed)
                {
                    AACD_INFO( "decode() detected end-of-file after partial frame error" );
                    attempts = 0;
                    break;
                }
            }

            int pos = info->decoder->sync( info, info->buffer+1, info->bytesleft-1 );

            if (pos >= 0) {
                info->buffer += pos+1;
                info->bytesleft -= pos+1;
            }
            else {
                int move = info->bytesleft < 2048 ? (info->bytesleft >> 1) : 1024;
                info->buffer += move;
                info->bytesleft -= move;
            }
        }
        while (--attempts > 0);

        if ( !attempts )
        {
            AACD_WARN( "decode() failed after several attempts");
            break;
        }

        info->round_frames++;
        info->round_bytesconsumed += info->frame_bytesconsumed;
        info->bytesleft -= info->frame_bytesconsumed;
        info->buffer += info->frame_bytesconsumed;

        if (info->frame_bytesconsumed > info->frame_max_bytesconsumed)
        {
            info->frame_max_bytesconsumed_exact = info->frame_bytesconsumed;
            info->frame_max_bytesconsumed = info->frame_bytesconsumed * 3 / 2;
        }

        samples += info->frame_samples;
        outLen -= info->frame_samples;
        info->round_samples += info->frame_samples;
    } 
    while (outLen >= info->frame_samples );

    AACD_DEBUG( "decode() round - frames=%d, consumed=%d, samples=%d, bytesleft=%d, frame_maxconsumed=%d, frame_samples=%d, outLen=%d", info->round_frames, info->round_bytesconsumed, info->round_samples, info->bytesleft, info->frame_max_bytesconsumed, info->frame_samples, outLen);
}