static int control(sh_audio_t *sh,int cmd,void* arg, ...) { switch(cmd) { case ADCTRL_RESYNC_STREAM: aac_sync(sh); AACFlushCodec(hAACDecoder); return CONTROL_TRUE; } return CONTROL_UNKNOWN; }
// returns -1 on error, 0 on success int seek_raw_aac (aac_info_t *info, int sample) { uint8_t buf[ADTS_HEADER_SIZE*8]; int nsamples = 0; int stream_sr = 0; int stream_ch = 0; int eof = 0; int bufsize = 0; int remaining = 0; int frame = 0; int frame_samples = 0; int curr_sample = 0; do { curr_sample += frame_samples; int size = sizeof (buf) - bufsize; if (deadbeef->fread (buf + bufsize, 1, size, info->file) != size) { trace ("seek_raw_aac: eof\n"); break; } bufsize = sizeof (buf); int channels, samplerate, bitrate; size = aac_sync (buf, &channels, &samplerate, &bitrate, &frame_samples); if (size == 0) { memmove (buf, buf+1, sizeof (buf)-1); bufsize--; continue; } else { //trace ("aac: frame #%d(%d/%d) sync: %d %d %d %d %d\n", frame, curr_sample, sample, channels, samplerate, bitrate, frame_samples, size); frame++; if (deadbeef->fseek (info->file, size-(int)sizeof(buf), SEEK_CUR) == -1) { trace ("seek_raw_aac: invalid seek %d\n", size-sizeof(buf)); break; } bufsize = 0; } if (samplerate <= 24000) { frame_samples *= 2; } } while (curr_sample + frame_samples < sample); if (curr_sample + frame_samples < sample) { return -1; } return sample - curr_sample; }
static int control(sh_audio_t *sh,int cmd,void* arg, ...) { switch(cmd) { case ADCTRL_RESYNC_STREAM: aac_sync(sh); return CONTROL_TRUE; #if 0 case ADCTRL_SKIP_FRAME: return CONTROL_TRUE; #endif } return CONTROL_UNKNOWN; }
static int decode_audio(sh_audio_t *sh,unsigned char *buf,int minlen,int maxlen) { int j = 0, len = 0, last_dec_len = 1, errors = 0; void *faac_sample_buffer; while(len < minlen && last_dec_len > 0 && errors < MAX_FAAD_ERRORS) { /* update buffer for raw aac streams: */ if(!sh->codecdata_len) if(sh->a_in_buffer_len < sh->a_in_buffer_size){ sh->a_in_buffer_len += demux_read_data(sh->ds,&sh->a_in_buffer[sh->a_in_buffer_len], sh->a_in_buffer_size - sh->a_in_buffer_len); } #ifdef DUMP_AAC_COMPRESSED {int i; for (i = 0; i < 16; i++) printf ("%02X ", sh->a_in_buffer[i]); printf ("\n");} #endif if(!sh->codecdata_len){ // raw aac stream: do { faac_sample_buffer = faacDecDecode(faac_hdec, &faac_finfo, sh->a_in_buffer, sh->a_in_buffer_len); /* update buffer index after faacDecDecode */ if(faac_finfo.bytesconsumed >= sh->a_in_buffer_len) { sh->a_in_buffer_len=0; } else { sh->a_in_buffer_len-=faac_finfo.bytesconsumed; memmove(sh->a_in_buffer,&sh->a_in_buffer[faac_finfo.bytesconsumed],sh->a_in_buffer_len); } if(faac_finfo.error > 0) { mp_msg(MSGT_DECAUDIO,MSGL_WARN,"FAAD: error: %s, trying to resync!\n", faacDecGetErrorMessage(faac_finfo.error)); if (sh->a_in_buffer_len <= 0) { errors = MAX_FAAD_ERRORS; break; } sh->a_in_buffer_len--; memmove(sh->a_in_buffer,&sh->a_in_buffer[1],sh->a_in_buffer_len); aac_sync(sh); errors++; } else break; } while(errors < MAX_FAAD_ERRORS); } else { // packetized (.mp4) aac stream: unsigned char* bufptr=NULL; double pts; int buflen=ds_get_packet_pts(sh->ds, &bufptr, &pts); if(buflen<=0) break; if (pts != MP_NOPTS_VALUE) { sh->pts = pts; sh->pts_bytes = 0; } faac_sample_buffer = faacDecDecode(faac_hdec, &faac_finfo, bufptr, buflen); } //for (j=0;j<faac_finfo.channels;j++) printf("%d:%d\n", j, faac_finfo.channel_position[j]); if(faac_finfo.error > 0) { mp_msg(MSGT_DECAUDIO,MSGL_WARN,"FAAD: Failed to decode frame: %s \n", faacDecGetErrorMessage(faac_finfo.error)); } else if (faac_finfo.samples == 0) { mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"FAAD: Decoded zero samples!\n"); } else { /* XXX: samples already multiplied by channels! */ mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"FAAD: Successfully decoded frame (%ld Bytes)!\n", sh->samplesize*faac_finfo.samples); memcpy(buf+len,faac_sample_buffer, sh->samplesize*faac_finfo.samples); last_dec_len = sh->samplesize*faac_finfo.samples; len += last_dec_len; sh->pts_bytes += last_dec_len; //printf("FAAD: buffer: %d bytes consumed: %d \n", k, faac_finfo.bytesconsumed); } } return len; }
static int parse_aac_stream(DB_FILE *fp, int *psamplerate, int *pchannels, float *pduration, int *ptotalsamples) { size_t framepos = deadbeef->ftell (fp); size_t initfpos = framepos; int firstframepos = -1; int fsize = -1; int offs = 0; if (!fp->vfs->is_streaming ()) { int skip = deadbeef->junk_get_leading_size (fp); if (skip >= 0) { deadbeef->fseek (fp, skip, SEEK_SET); } int offs = deadbeef->ftell (fp); fsize = deadbeef->fgetlength (fp); if (skip > 0) { fsize -= skip; } } uint8_t buf[ADTS_HEADER_SIZE*8]; int nsamples = 0; int stream_sr = 0; int stream_ch = 0; int eof = 0; int bufsize = 0; int remaining = 0; int frame = 0; int scanframes = 1000; if (fp->vfs->is_streaming ()) { scanframes = 1; } do { int size = sizeof (buf) - bufsize; if (deadbeef->fread (buf + bufsize, 1, size, fp) != size) { trace ("parse_aac_stream: eof\n"); break; } bufsize = sizeof (buf); int channels, samplerate, bitrate, samples; size = aac_sync (buf, &channels, &samplerate, &bitrate, &samples); if (size == 0) { memmove (buf, buf+1, sizeof (buf)-1); bufsize--; // trace ("aac_sync fail, framepos: %d\n", framepos); if (deadbeef->ftell (fp) - initfpos > 2000) { // how many is enough to make sure? break; } framepos++; continue; } else { trace ("aac: frame #%d sync: %dch %d %d %d %d\n", frame, channels, samplerate, bitrate, samples, size); frame++; nsamples += samples; if (!stream_sr) { stream_sr = samplerate; } if (!stream_ch) { stream_ch = channels; } if (firstframepos == -1) { firstframepos = framepos; } // if (fp->vfs->streaming) { // *psamplerate = stream_sr; // *pchannels = stream_ch; // } framepos += size; if (deadbeef->fseek (fp, size-(int)sizeof(buf), SEEK_CUR) == -1) { trace ("parse_aac_stream: invalid seek %d\n", size-sizeof(buf)); break; } bufsize = 0; } } while (ptotalsamples || frame < scanframes); if (!frame || !stream_sr || !nsamples) { return -1; } *psamplerate = stream_sr; *pchannels = stream_ch; if (ptotalsamples) { *ptotalsamples = nsamples; *pduration = nsamples / (float)stream_sr; trace ("aac: duration=%f (%d samples @ %d Hz), fsize=%d, nframes=%d\n", *pduration, *ptotalsamples, stream_sr, fsize, frame); } else { int pos = deadbeef->ftell (fp); int totalsamples = (double)fsize / (pos-offs) * nsamples; *pduration = totalsamples / (float)stream_sr; trace ("aac: duration=%f (%d samples @ %d Hz), fsize=%d\n", *pduration, totalsamples, stream_sr, fsize); } if (*psamplerate <= 24000) { *psamplerate *= 2; if (ptotalsamples) { *ptotalsamples *= 2; } } return firstframepos; }
static int decode_audio(sh_audio_t *sh,unsigned char *buf,int minlen,int maxlen){ int len = 0, last_dec_len = 1, err = 0, in_len; int outOfData = 0, errors=0;; uint8_t *inBuf; while(len < minlen && last_dec_len > 0 ) { /* update buffer for raw aac streams: */ if(!sh->codecdata_len){ if(sh->a_in_buffer_len < sh->a_in_buffer_size){ sh->a_in_buffer_len += demux_read_data(sh->ds,&sh->a_in_buffer[sh->a_in_buffer_len], sh->a_in_buffer_size - sh->a_in_buffer_len); } //#define DUMP_AAC_COMPRESSED #ifdef DUMP_AAC_COMPRESSED {int i; inBuf = sh->a_in_buffer; for (i = 0; i < 16; i++) printf ("%02x ", inBuf[i]); printf ("\n");} #endif inBuf = sh->a_in_buffer; in_len = sh->a_in_buffer_len; // raw aac stream: err = AACDecode(hAACDecoder, &(inBuf), &(in_len), buf+len); if(in_len > 0) { memmove(sh->a_in_buffer,inBuf,in_len); } sh->a_in_buffer_len = in_len; if (err == ERR_AAC_NONE) { AACGetLastFrameInfo(hAACDecoder, frameInfo); reorder_ch_pcm(buf+len, frameInfo->outputSamps, frameInfo->nChans); last_dec_len = sh->samplesize*frameInfo->outputSamps*sh->channels/frameInfo->nChans; len += last_dec_len; sh->pts_bytes += last_dec_len; if(errors) errors=0; }else if(err == ERR_AAC_INDATA_UNDERFLOW){ errors++; }else if(sh->a_in_buffer_len > 0){ sh->a_in_buffer_len--; memmove(sh->a_in_buffer,&sh->a_in_buffer[1],sh->a_in_buffer_len); aac_sync(sh); errors++; } if(errors > 10){ break; } }else{ /* update buffer for raw aac streams: */ // packetized (.mp4) aac stream: unsigned char* bufptr=NULL; double pts; int buflen=ds_get_packet_pts(sh->ds, &bufptr, &pts); if(buflen<=0) break; if (pts != MP_NOPTS_VALUE) { sh->pts = pts; sh->pts_bytes = 0; } err = AACDecode(hAACDecoder, &bufptr, &buflen, buf+len); if (err == ERR_AAC_NONE) { AACGetLastFrameInfo(hAACDecoder, frameInfo); reorder_ch_pcm(buf+len, frameInfo->outputSamps, frameInfo->nChans); last_dec_len = sh->samplesize*frameInfo->outputSamps*sh->channels/frameInfo->nChans; len += last_dec_len; sh->pts_bytes += last_dec_len; } } } return len; }
static int aac_read (DB_fileinfo_t *_info, char *bytes, int size) { aac_info_t *info = (aac_info_t *)_info; int samplesize = _info->fmt.channels * _info->fmt.bps / 8; if (!info->file->vfs->is_streaming ()) { if (info->currentsample + size / samplesize > info->endsample) { size = (info->endsample - info->currentsample + 1) * samplesize; if (size <= 0) { trace ("aac_read: eof"); return 0; } } } int initsize = size; int eof = 0; while (size > 0) { if (info->skipsamples > 0 && info->out_remaining > 0) { int skip = min (info->out_remaining, info->skipsamples); if (skip < info->out_remaining) { memmove (info->out_buffer, info->out_buffer + skip * samplesize, (info->out_remaining - skip) * samplesize); } info->out_remaining -= skip; info->skipsamples -= skip; } if (info->out_remaining > 0) { int n = size / samplesize; n = min (info->out_remaining, n); char *src = info->out_buffer; if (info->noremap) { memcpy (bytes, src, n * samplesize); bytes += n * samplesize; src += n * samplesize; } else { int i, j; if (info->remap[0] == -1) { // build remap mtx // FIXME: should build channelmask 1st; then remap based on channelmask for (i = 0; i < _info->fmt.channels; i++) { switch (info->frame_info.channel_position[i]) { case FRONT_CHANNEL_CENTER: trace ("FC->%d\n", i); info->remap[2] = i; break; case FRONT_CHANNEL_LEFT: trace ("FL->%d\n", i); info->remap[0] = i; break; case FRONT_CHANNEL_RIGHT: trace ("FR->%d\n", i); info->remap[1] = i; break; case SIDE_CHANNEL_LEFT: trace ("SL->%d\n", i); info->remap[6] = i; break; case SIDE_CHANNEL_RIGHT: trace ("SR->%d\n", i); info->remap[7] = i; break; case BACK_CHANNEL_LEFT: trace ("RL->%d\n", i); info->remap[4] = i; break; case BACK_CHANNEL_RIGHT: trace ("RR->%d\n", i); info->remap[5] = i; break; case BACK_CHANNEL_CENTER: trace ("BC->%d\n", i); info->remap[8] = i; break; case LFE_CHANNEL: trace ("LFE->%d\n", i); info->remap[3] = i; break; default: trace ("aac: unknown ch(%d)->%d\n", info->frame_info.channel_position[i], i); break; } } for (i = 0; i < _info->fmt.channels; i++) { trace ("%d ", info->remap[i]); } trace ("\n"); if (info->remap[0] == -1) { info->remap[0] = 0; } if ((_info->fmt.channels == 1 && info->remap[0] == FRONT_CHANNEL_CENTER) || (_info->fmt.channels == 2 && info->remap[0] == FRONT_CHANNEL_LEFT && info->remap[1] == FRONT_CHANNEL_RIGHT)) { info->noremap = 1; } } for (i = 0; i < n; i++) { for (j = 0; j < _info->fmt.channels; j++) { ((int16_t *)bytes)[j] = ((int16_t *)src)[info->remap[j]]; } src += samplesize; bytes += samplesize; } } size -= n * samplesize; if (n == info->out_remaining) { info->out_remaining = 0; } else { memmove (info->out_buffer, src, (info->out_remaining - n) * samplesize); info->out_remaining -= n; } continue; } char *samples = NULL; if (info->mp4file) { unsigned char *buffer = NULL; int buffer_size = 0; #ifdef USE_MP4FF int rc = mp4ff_read_sample (info->mp4file, info->mp4track, info->mp4sample, &buffer, &buffer_size); if (rc == 0) { break; } #else buffer = info->samplebuffer; buffer_size = info->maxSampleSize; MP4Timestamp sampleTime; MP4Duration sampleDuration; MP4Duration sampleRenderingOffset; bool isSyncSample; MP4ReadSample (info->mp4file, info->mp4track, info->mp4sample, &buffer, &buffer_size, &sampleTime, &sampleDuration, &sampleRenderingOffset, &isSyncSample); // convert timestamp and duration from track time to milliseconds u_int64_t myTime = MP4ConvertFromTrackTimestamp (info->mp4file, info->mp4track, sampleTime, MP4_MSECS_TIME_SCALE); u_int64_t myDuration = MP4ConvertFromTrackDuration (info->mp4file, info->mp4track, sampleDuration, MP4_MSECS_TIME_SCALE); #endif if (info->mp4sample >= info->mp4samples) { if (buffer) { free (buffer); } break; } info->mp4sample++; samples = NeAACDecDecode(info->dec, &info->frame_info, buffer, buffer_size); if (buffer) { free (buffer); } if (!samples) { break; } } else { if (info->remaining < AAC_BUFFER_SIZE) { trace ("fread from offs %lld\n", deadbeef->ftell (info->file)); size_t res = deadbeef->fread (info->buffer + info->remaining, 1, AAC_BUFFER_SIZE-info->remaining, info->file); if (res == 0) { eof = 1; } info->remaining += res; if (!info->remaining) { break; } } trace ("NeAACDecDecode %d bytes\n", info->remaining) samples = NeAACDecDecode (info->dec, &info->frame_info, info->buffer, info->remaining); if (!samples) { trace ("NeAACDecDecode failed with error %s (%d), consumed=%d\n", NeAACDecGetErrorMessage(info->frame_info.error), (int)info->frame_info.error, info->frame_info.bytesconsumed); if (info->num_errors > 10) { trace ("NeAACDecDecode failed %d times, interrupting\n", info->num_errors); break; } info->num_errors++; int s = 0; while (!s && info->remaining > 0) { int ch, sr, br, sm; s = aac_sync (info->buffer, &ch, &sr, &br, &sm); if (s == 0) { memmove (info->buffer, info->buffer+1, info->remaining-1); info->remaining--; } } // info->remaining = 0; continue; } info->num_errors=0; int consumed = info->frame_info.bytesconsumed; if (consumed > info->remaining) { trace ("NeAACDecDecode consumed more than available! wtf?\n"); break; } if (consumed == info->remaining) { info->remaining = 0; } else if (consumed > 0) { memmove (info->buffer, info->buffer + consumed, info->remaining - consumed); info->remaining -= consumed; } } if (info->frame_info.samples > 0) { memcpy (info->out_buffer, samples, info->frame_info.samples * 2); info->out_remaining = info->frame_info.samples / info->frame_info.channels; } } info->currentsample += (initsize-size) / samplesize; trace ("aac_read return: %d\n", initsize-size); return initsize-size; }