static gint xmms_faad_read_some (xmms_xform_t *xform, xmms_error_t *err) { xmms_faad_data_t *data; NeAACDecFrameInfo frameInfo; gpointer sample_buffer; guint bytes_read = 0; g_return_val_if_fail (xform, -1); data = xmms_xform_private_data_get (xform); g_return_val_if_fail (data, -1); while (data->outbuf->len == 0) { gboolean need_read; /* MP4 demuxer always gives full packets so we need different handling */ if (data->filetype == FAAD_TYPE_MP4) need_read = (data->buffer_length == 0); else need_read = (data->buffer_length < data->buffer_size); if (need_read) { bytes_read = xmms_xform_read (xform, (gchar *) data->buffer + data->buffer_length, data->buffer_size - data->buffer_length, err); if (bytes_read <= 0 && data->buffer_length == 0) { XMMS_DBG ("EOF"); return 0; } data->buffer_length += bytes_read; } sample_buffer = NeAACDecDecode (data->decoder, &frameInfo, data->buffer, data->buffer_length); g_memmove (data->buffer, data->buffer + frameInfo.bytesconsumed, data->buffer_length - frameInfo.bytesconsumed); data->buffer_length -= frameInfo.bytesconsumed; bytes_read = frameInfo.samples * xmms_sample_size_get (data->sampleformat); if (bytes_read > 0 && frameInfo.error == 0) { if (data->samplerate != frameInfo.samplerate || data->channels != frameInfo.channels) { /* We should inform output to change parameters somehow */ xmms_log_error ("Output format changed in the middle of a read!"); data->samplerate = frameInfo.samplerate; data->channels = frameInfo.channels; } g_string_append_len (data->outbuf, sample_buffer, bytes_read); } else if (frameInfo.error > 0) { xmms_log_error ("ERROR %d in faad decoding: %s", frameInfo.error, NeAACDecGetErrorMessage (frameInfo.error)); return -1; } } return data->outbuf->len; }
AudioStream *AACDecoder::decodeFrame(Common::SeekableReadStream &stream) { // read everything into a buffer uint32 inBufferPos = 0; uint32 inBufferSize = stream.size(); byte *inBuffer = new byte[inBufferSize]; stream.read(inBuffer, inBufferSize); QueuingAudioStream *audioStream = makeQueuingAudioStream(_rate, _channels); // Decode until we have enough samples (or there's no more left) while (inBufferPos < inBufferSize) { NeAACDecFrameInfo frameInfo; void *decodedSamples = NeAACDecDecode(_handle, &frameInfo, inBuffer + inBufferPos, inBufferSize - inBufferPos); if (frameInfo.error != 0) throw Common::Exception("Failed to decode AAC frame: %s", NeAACDecGetErrorMessage(frameInfo.error)); byte *buffer = (byte *)malloc(frameInfo.samples * 2); memcpy(buffer, decodedSamples, frameInfo.samples * 2); byte flags = FLAG_16BITS; #ifdef XOREOS_LITTLE_ENDIAN flags |= FLAG_LITTLE_ENDIAN; #endif audioStream->queueAudioStream(makePCMStream(new Common::MemoryReadStream(buffer, frameInfo.samples * 2), _rate, flags, _channels, true), true); inBufferPos += frameInfo.bytesconsumed; } return audioStream; }
AACDecoder::AACDecoder(Common::SeekableReadStream *extraData, bool disposeExtraData) { // Open the library _handle = NeAACDecOpen(); // Configure the library to our needs NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(_handle); conf->outputFormat = FAAD_FMT_16BIT; // We only support 16bit audio conf->downMatrix = 1; // Convert from 5.1 to stereo if required NeAACDecSetConfiguration(_handle, conf); // Copy the extra data to a buffer extraData->seek(0); byte *extraDataBuf = new byte[extraData->size()]; extraData->read(extraDataBuf, extraData->size()); // Initialize with our extra data // NOTE: This code assumes the extra data is coming from an MPEG-4 file! int err = NeAACDecInit2(_handle, extraDataBuf, extraData->size(), &_rate, &_channels); delete[] extraDataBuf; if (err < 0) throw Common::Exception("Could not initialize AAC decoder: %s", NeAACDecGetErrorMessage(err)); if (disposeExtraData) delete extraData; }
qint64 DecoderAAC::read(unsigned char *audio, qint64 maxSize) { NeAACDecFrameInfo frame_info; qint64 size = 0, to_read, read; bool eof = false; while(m_sample_buf_size <= 0 && !eof) { m_sample_buf_at = 0; if (m_input_at < AAC_BUFFER_SIZE) { to_read = AAC_BUFFER_SIZE - m_input_at; read = input()->read((char *) (m_input_buf + m_input_at), to_read); eof = (read != to_read); m_input_at += read; } m_sample_buf = NeAACDecDecode(data()->handle, &frame_info, (uchar *)m_input_buf, m_input_at); memmove(m_input_buf, m_input_buf + frame_info.bytesconsumed, m_input_at - frame_info.bytesconsumed); m_input_at -= frame_info.bytesconsumed; if (frame_info.error > 0) { m_input_at = 0; qDebug("DecoderAAC: %s", NeAACDecGetErrorMessage(frame_info.error)); return -1; } if(frame_info.samples > 0) m_bitrate = frame_info.bytesconsumed * 8 * frame_info.samplerate * frame_info.channels / frame_info.samples / 1000; m_sample_buf_size = frame_info.samples * 2; } if(m_sample_buf_size > 0) { size = qMin(m_sample_buf_size, maxSize); memcpy(audio, (char *)(m_sample_buf) + m_sample_buf_at, size); m_sample_buf_at += size; m_sample_buf_size -= size; } return size; }
int AACStream::readBuffer(int16 *buffer, const int numSamples) { int samples = 0; assert((numSamples % _channels) == 0); // Dip into our remaining samples pool if it's available if (_remainingSamples) { samples = MIN<int>(numSamples, _remainingSamplesSize - _remainingSamplesPos); memcpy(buffer, _remainingSamples + _remainingSamplesPos, samples * 2); _remainingSamplesPos += samples; if (_remainingSamplesPos == _remainingSamplesSize) { delete[] _remainingSamples; _remainingSamples = 0; } } // Decode until we have enough samples (or there's no more left) while (samples < numSamples && !endOfData()) { NeAACDecFrameInfo frameInfo; uint16 *decodedSamples = (uint16 *)NeAACDecDecode(_handle, &frameInfo, _inBuffer + _inBufferPos, _inBufferSize - _inBufferPos); if (frameInfo.error != 0) error("Failed to decode AAC frame: %s", NeAACDecGetErrorMessage(frameInfo.error)); int decodedSampleSize = frameInfo.samples; int copySamples = (decodedSampleSize > (numSamples - samples)) ? (numSamples - samples) : decodedSampleSize; memcpy(buffer + samples, decodedSamples, copySamples * 2); samples += copySamples; // Copy leftover samples for use in a later readBuffer() call if (copySamples != decodedSampleSize) { _remainingSamplesSize = decodedSampleSize - copySamples; _remainingSamples = new int16[_remainingSamplesSize]; _remainingSamplesPos = 0; memcpy(_remainingSamples, decodedSamples + copySamples, _remainingSamplesSize * 2); } _inBufferPos += frameInfo.bytesconsumed; } return samples; }
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; }
/* play aac stream * @param streamed data * @param received bytes * @param extra data (player data) * @return received bytes or less on error */ static WaitressCbReturn_t BarPlayerAACCb (void *ptr, size_t size, void *stream) { const char *data = ptr; struct audioPlayer *player = stream; QUIT_PAUSE_CHECK; if (!BarPlayerBufferFill (player, data, size)) { return WAITRESS_CB_RET_ERR; } if (player->mode == PLAYER_RECV_DATA) { short int *aacDecoded; NeAACDecFrameInfo frameInfo; size_t i; while ((player->bufferFilled - player->bufferRead) > player->sampleSize[player->sampleSizeCurr]) { /* decode frame */ aacDecoded = NeAACDecDecode(player->aacHandle, &frameInfo, player->buffer + player->bufferRead, player->sampleSize[player->sampleSizeCurr]); if (frameInfo.error != 0) { BarUiMsg (player->settings, MSG_ERR, "Decoding error: %s\n", NeAACDecGetErrorMessage (frameInfo.error)); break; } for (i = 0; i < frameInfo.samples; i++) { aacDecoded[i] = applyReplayGain (aacDecoded[i], player->scale); } /* ao_play needs bytes: 1 sample = 16 bits = 2 bytes */ ao_play (player->audioOutDevice, (char *) aacDecoded, frameInfo.samples * 2); /* add played frame length to played time, explained below */ player->songPlayed += (unsigned long long int) frameInfo.samples * (unsigned long long int) BAR_PLAYER_MS_TO_S_FACTOR / (unsigned long long int) player->samplerate / (unsigned long long int) player->channels; player->bufferRead += frameInfo.bytesconsumed; player->sampleSizeCurr++; /* going through this loop can take up to a few seconds => * allow earlier thread abort */ QUIT_PAUSE_CHECK; } } else { if (player->mode == PLAYER_INITIALIZED) { while (player->bufferRead+4 < player->bufferFilled) { if (memcmp (player->buffer + player->bufferRead, "esds", 4) == 0) { player->mode = PLAYER_FOUND_ESDS; player->bufferRead += 4; break; } player->bufferRead++; } } if (player->mode == PLAYER_FOUND_ESDS) { /* FIXME: is this the correct way? */ /* we're gonna read 10 bytes */ while (player->bufferRead+1+4+5 < player->bufferFilled) { if (memcmp (player->buffer + player->bufferRead, "\x05\x80\x80\x80", 4) == 0) { ao_sample_format format; int audioOutDriver; /* +1+4 needs to be replaced by <something>! */ player->bufferRead += 1+4; char err = NeAACDecInit2 (player->aacHandle, player->buffer + player->bufferRead, 5, &player->samplerate, &player->channels); player->bufferRead += 5; if (err != 0) { BarUiMsg (player->settings, MSG_ERR, "Error while initializing audio decoder " "(%i)\n", err); return WAITRESS_CB_RET_ERR; } audioOutDriver = ao_default_driver_id(); memset (&format, 0, sizeof (format)); format.bits = 16; format.channels = player->channels; format.rate = player->samplerate; format.byte_format = AO_FMT_NATIVE; if ((player->audioOutDevice = ao_open_live (audioOutDriver, &format, NULL)) == NULL) { /* we're not interested in the errno */ player->aoError = 1; BarUiMsg (player->settings, MSG_ERR, "Cannot open audio device\n"); return WAITRESS_CB_RET_ERR; } player->mode = PLAYER_AUDIO_INITIALIZED; break; } player->bufferRead++; } } if (player->mode == PLAYER_AUDIO_INITIALIZED) { while (player->bufferRead+4+8 < player->bufferFilled) { if (memcmp (player->buffer + player->bufferRead, "stsz", 4) == 0) { player->mode = PLAYER_FOUND_STSZ; player->bufferRead += 4; /* skip version and unknown */ player->bufferRead += 8; break; } player->bufferRead++; } } /* get frame sizes */ if (player->mode == PLAYER_FOUND_STSZ) { while (player->bufferRead+4 < player->bufferFilled) { /* how many frames do we have? */ if (player->sampleSizeN == 0) { /* mp4 uses big endian, convert */ player->sampleSizeN = bigToHostEndian32 (*((uint32_t *) (player->buffer + player->bufferRead))); player->sampleSize = malloc (player->sampleSizeN * sizeof (*player->sampleSize)); player->bufferRead += 4; player->sampleSizeCurr = 0; /* set up song duration (assuming one frame always contains * the same number of samples) * calculation: channels * number of frames * samples per * frame / samplerate */ /* FIXME: Hard-coded number of samples per frame */ player->songDuration = (unsigned long long int) player->sampleSizeN * 4096LL * (unsigned long long int) BAR_PLAYER_MS_TO_S_FACTOR / (unsigned long long int) player->samplerate / (unsigned long long int) player->channels; break; } else { player->sampleSize[player->sampleSizeCurr] = bigToHostEndian32 (*((uint32_t *) (player->buffer + player->bufferRead))); player->sampleSizeCurr++; player->bufferRead += 4; } /* all sizes read, nearly ready for data mode */ if (player->sampleSizeCurr >= player->sampleSizeN) { player->mode = PLAYER_SAMPLESIZE_INITIALIZED; break; } } } /* search for data atom and let the show begin... */ if (player->mode == PLAYER_SAMPLESIZE_INITIALIZED) { while (player->bufferRead+4 < player->bufferFilled) { if (memcmp (player->buffer + player->bufferRead, "mdat", 4) == 0) { player->mode = PLAYER_RECV_DATA; player->sampleSizeCurr = 0; player->bufferRead += 4; break; } player->bufferRead++; } } } BarPlayerBufferMove (player); return WAITRESS_CB_RET_OK; }
static int aac_read (DB_fileinfo_t *_info, char *bytes, int size) { aac_info_t *info = (aac_info_t *)_info; if (info->eof) { trace ("aac_read: received call after eof\n"); return 0; } 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 (current=%d, total=%d)\n", info->currentsample, info->endsample); return 0; } } } int initsize = size; 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) { if (info->mp4sample >= info->mp4samples) { break; } 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) { trace ("mp4ff_read_sample failed\n"); info->eof = 1; 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 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); info->remaining += res; trace ("remain: %d\n", info->remaining); if (!info->remaining) { break; } } trace ("NeAACDecDecode %d bytes\n", info->remaining) samples = NeAACDecDecode (info->dec, &info->frame_info, info->buffer, info->remaining); trace ("samples =%p\n", samples); 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++; 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; return initsize-size; }
static void *mp4Decode(void *args) { FILE* mp4file; pthread_mutex_lock(&mutex); seekPosition = -1; bPlaying = TRUE; if(!(mp4file = fopen(args, "rb"))){ g_print("MP4!AAC - Can't open file\n"); g_free(args); bPlaying = FALSE; pthread_mutex_unlock(&mutex); pthread_exit(NULL); } mp4_get_file_type(mp4file); fseek(mp4file, 0, SEEK_SET); if(mp4cfg.file_type == FILE_MP4){// We are reading a MP4 file mp4ff_callback_t* mp4cb; mp4ff_t* infile; gint mp4track; mp4cb = getMP4FF_cb(mp4file); if(!(infile = mp4ff_open_read(mp4cb))){ g_print("MP4 - Can't open file\n"); goto end; } if((mp4track = getAACTrack(infile)) < 0){ /* * TODO: check here for others Audio format..... * */ g_print("Unsupported Audio track type\n"); g_free(args); fclose(mp4file); bPlaying = FALSE; pthread_mutex_unlock(&mutex); pthread_exit(NULL); }else{ NeAACDecHandle decoder; unsigned char *buffer = NULL; guint bufferSize = 0; gulong samplerate; guchar channels; //guint avgBitrate; //MP4Duration duration; int msDuration; int numSamples; int sampleID = 0; unsigned int framesize; mp4AudioSpecificConfig mp4ASC; gchar *xmmstitle; decoder = NeAACDecOpen(); mp4ff_get_decoder_config(infile, mp4track, &buffer, &bufferSize); if(NeAACDecInit2(decoder, buffer, bufferSize, &samplerate, &channels)<0){ goto end; } if(buffer){ framesize = 1024; if(NeAACDecAudioSpecificConfig(buffer, bufferSize, &mp4ASC) >= 0){ if(mp4ASC.frameLengthFlag == 1) framesize = 960; if(mp4ASC.sbr_present_flag == 1) framesize *= 2; } g_free(buffer); } if(channels == 0){ g_print("Number of Channels not supported\n"); goto end; } //duration = MP4GetTrackDuration(mp4file, mp4track); //msDuration = MP4ConvertFromTrackDuration(mp4file, mp4track, // duration,MP4_MSECS_TIME_SCALE); //msDuration = mp4ff_get_track_duration(infile, mp4track); //printf("%d\n", msDuration); //numSamples = MP4GetTrackNumberOfSamples(mp4file, mp4track); numSamples = mp4ff_num_samples(infile, mp4track); { float f = 1024.0; if(mp4ASC.sbr_present_flag == 1) f = f * 2.0; msDuration = ((float)numSamples*(float)(f-1.0)/ (float)samplerate)*1000; } xmmstitle = getMP4title(infile, args); mp4_ip.output->open_audio(FMT_S16_NE, samplerate, channels); mp4_ip.output->flush(0); mp4_ip.set_info(xmmstitle, msDuration, -1, samplerate/1000, channels); g_print("MP4 - %d channels @ %ld Hz\n", channels, samplerate); while(bPlaying){ void* sampleBuffer; faacDecFrameInfo frameInfo; gint rc; if(seekPosition!=-1){ /* duration = MP4ConvertToTrackDuration(mp4file, mp4track, seekPosition*1000, MP4_MSECS_TIME_SCALE); sampleID = MP4GetSampleIdFromTime(mp4file, mp4track, duration, 0); */ float f = 1024.0; if(mp4ASC.sbr_present_flag == 1) f = f * 2.0; sampleID = (float)seekPosition*(float)samplerate/(float)(f-1.0); mp4_ip.output->flush(seekPosition*1000); seekPosition = -1; } buffer=NULL; bufferSize=0; rc = mp4ff_read_sample(infile, mp4track, sampleID++, &buffer, &bufferSize); //g_print("%d/%d\n", sampleID-1, numSamples); if((rc==0) || (buffer== NULL)){ g_print("MP4: read error\n"); sampleBuffer = NULL; sampleID=0; mp4_ip.output->buffer_free(); goto end; }else{ sampleBuffer = NeAACDecDecode(decoder, &frameInfo, buffer, bufferSize); if(frameInfo.error > 0){ g_print("MP4: %s\n", faacDecGetErrorMessage(frameInfo.error)); goto end; } if(buffer){ g_free(buffer); buffer=NULL; bufferSize=0; } while(bPlaying && mp4_ip.output->buffer_free()<frameInfo.samples<<1) xmms_usleep(30000); } mp4_ip.add_vis_pcm(mp4_ip.output->written_time(), FMT_S16_NE, channels, frameInfo.samples<<1, sampleBuffer); mp4_ip.output->write_audio(sampleBuffer, frameInfo.samples<<1); if(sampleID >= numSamples){ break; } } while(bPlaying && mp4_ip.output->buffer_playing() && mp4_ip.output->buffer_free()){ xmms_usleep(10000); } end: mp4_ip.output->close_audio(); g_free(args); NeAACDecClose(decoder); if(infile) mp4ff_close(infile); if(mp4cb) g_free(mp4cb); bPlaying = FALSE; fclose(mp4file); pthread_mutex_unlock(&mutex); pthread_exit(NULL); } }else{ // WE ARE READING AN AAC FILE FILE *file = NULL; NeAACDecHandle decoder = 0; guchar *buffer = 0; gulong bufferconsumed = 0; gulong samplerate = 0; guchar channels; gulong buffervalid = 0; TitleInput* input; gchar *temp = g_strdup(args); gchar *ext = strrchr(temp, '.'); gchar *xmmstitle = NULL; NeAACDecConfigurationPtr config; if((file = fopen(args, "rb")) == 0){ g_print("AAC: can't find file %s\n", args); bPlaying = FALSE; pthread_mutex_unlock(&mutex); pthread_exit(NULL); } if((decoder = NeAACDecOpen()) == NULL){ g_print("AAC: Open Decoder Error\n"); fclose(file); bPlaying = FALSE; pthread_mutex_unlock(&mutex); pthread_exit(NULL); } config = NeAACDecGetCurrentConfiguration(decoder); config->useOldADTSFormat = 0; NeAACDecSetConfiguration(decoder, config); if((buffer = g_malloc(BUFFER_SIZE)) == NULL){ g_print("AAC: error g_malloc\n"); fclose(file); bPlaying = FALSE; NeAACDecClose(decoder); pthread_mutex_unlock(&mutex); pthread_exit(NULL); } if((buffervalid = fread(buffer, 1, BUFFER_SIZE, file))==0){ g_print("AAC: Error reading file\n"); g_free(buffer); fclose(file); bPlaying = FALSE; NeAACDecClose(decoder); pthread_mutex_unlock(&mutex); pthread_exit(NULL); } XMMS_NEW_TITLEINPUT(input); input->file_name = g_basename(temp); input->file_ext = ext ? ext+1 : NULL; input->file_path = temp; if(!strncmp(buffer, "ID3", 3)){ gint size = 0; fseek(file, 0, SEEK_SET); size = (buffer[6]<<21) | (buffer[7]<<14) | (buffer[8]<<7) | buffer[9]; size+=10; fread(buffer, 1, size, file); buffervalid = fread(buffer, 1, BUFFER_SIZE, file); } xmmstitle = xmms_get_titlestring(xmms_get_gentitle_format(), input); if(xmmstitle == NULL) xmmstitle = g_strdup(input->file_name); if(temp) g_free(temp); if(input->performer) g_free(input->performer); if(input->album_name) g_free(input->album_name); if(input->track_name) g_free(input->track_name); if(input->genre) g_free(input->genre); g_free(input); bufferconsumed = NeAACDecInit(decoder, buffer, buffervalid, &samplerate, &channels); if(mp4_ip.output->open_audio(FMT_S16_NE,samplerate,channels) == FALSE){ g_print("AAC: Output Error\n"); g_free(buffer); buffer=0; faacDecClose(decoder); fclose(file); mp4_ip.output->close_audio(); /* if(positionTable){ g_free(positionTable); positionTable=0; } */ g_free(xmmstitle); bPlaying = FALSE; pthread_mutex_unlock(&mutex); pthread_exit(NULL); } //if(bSeek){ //mp4_ip.set_info(xmmstitle, lenght*1000, -1, samplerate, channels); //}else{ mp4_ip.set_info(xmmstitle, -1, -1, samplerate, channels); //} mp4_ip.output->flush(0); while(bPlaying && buffervalid > 0){ NeAACDecFrameInfo finfo; unsigned long samplesdecoded; char* sample_buffer = NULL; /* if(bSeek && seekPosition!=-1){ fseek(file, positionTable[seekPosition], SEEK_SET); bufferconsumed=0; buffervalid = fread(buffer, 1, BUFFER_SIZE, file); aac_ip.output->flush(seekPosition*1000); seekPosition=-1; } */ if(bufferconsumed > 0){ memmove(buffer, &buffer[bufferconsumed], buffervalid-bufferconsumed); buffervalid -= bufferconsumed; buffervalid += fread(&buffer[buffervalid], 1, BUFFER_SIZE-buffervalid, file); bufferconsumed = 0; } sample_buffer = NeAACDecDecode(decoder, &finfo, buffer, buffervalid); if(finfo.error){ config = NeAACDecGetCurrentConfiguration(decoder); if(config->useOldADTSFormat != 1){ NeAACDecClose(decoder); decoder = NeAACDecOpen(); config = NeAACDecGetCurrentConfiguration(decoder); config->useOldADTSFormat = 1; NeAACDecSetConfiguration(decoder, config); finfo.bytesconsumed=0; finfo.samples = 0; NeAACDecInit(decoder, buffer, buffervalid, &samplerate, &channels); }else{ g_print("FAAD2 Warning %s\n", NeAACDecGetErrorMessage(finfo.error)); buffervalid = 0; } } bufferconsumed += finfo.bytesconsumed; samplesdecoded = finfo.samples; if((samplesdecoded<=0) && !sample_buffer){ g_print("AAC: error sample decoding\n"); continue; } while(bPlaying && mp4_ip.output->buffer_free() < (samplesdecoded<<1)){ xmms_usleep(10000); } mp4_ip.add_vis_pcm(mp4_ip.output->written_time(), FMT_S16_LE, channels, samplesdecoded<<1, sample_buffer); mp4_ip.output->write_audio(sample_buffer, samplesdecoded<<1); } while(bPlaying && mp4_ip.output->buffer_playing()){ xmms_usleep(10000); } mp4_ip.output->buffer_free(); mp4_ip.output->close_audio(); bPlaying = FALSE; g_free(buffer); NeAACDecClose(decoder); g_free(xmmstitle); fclose(file); seekPosition = -1; /* if(positionTable){ g_free(positionTable); positionTable=0; } */ bPlaying = FALSE; pthread_mutex_unlock(&mutex); pthread_exit(NULL); } }
/* this is called for each file to process */ enum codec_status codec_run(void) { /* Note that when dealing with QuickTime/MPEG4 files, terminology is * a bit confusing. Files with sound are split up in chunks, where * each chunk contains one or more samples. Each sample in turn * contains a number of "sound samples" (the kind you refer to with * the sampling frequency). */ size_t n; demux_res_t demux_res; stream_t input_stream; uint32_t sound_samples_done; uint32_t elapsed_time; int file_offset; int framelength; int lead_trim = 0; unsigned int frame_samples; unsigned int i; unsigned char* buffer; NeAACDecFrameInfo frame_info; NeAACDecHandle decoder; int err; uint32_t seek_idx = 0; uint32_t s = 0; uint32_t sbr_fac = 1; unsigned char c = 0; void *ret; intptr_t param; bool empty_first_frame = false; /* Clean and initialize decoder structures */ memset(&demux_res , 0, sizeof(demux_res)); if (codec_init()) { LOGF("FAAD: Codec init error\n"); return CODEC_ERROR; } file_offset = ci->id3->offset; ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); codec_set_replaygain(ci->id3); stream_create(&input_stream,ci); ci->seek_buffer(ci->id3->first_frame_offset); /* if qtmovie_read returns successfully, the stream is up to * the movie data, which can be used directly by the decoder */ if (!qtmovie_read(&input_stream, &demux_res)) { LOGF("FAAD: File init error\n"); return CODEC_ERROR; } /* initialise the sound converter */ decoder = NeAACDecOpen(); if (!decoder) { LOGF("FAAD: Decode open error\n"); return CODEC_ERROR; } NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder); conf->outputFormat = FAAD_FMT_24BIT; /* irrelevant, we don't convert */ NeAACDecSetConfiguration(decoder, conf); err = NeAACDecInit2(decoder, demux_res.codecdata, demux_res.codecdata_len, &s, &c); if (err) { LOGF("FAAD: DecInit: %d, %d\n", err, decoder->object_type); return CODEC_ERROR; } #ifdef SBR_DEC /* Check for need of special handling for seek/resume and elapsed time. */ if (ci->id3->needs_upsampling_correction) { sbr_fac = 2; } else { sbr_fac = 1; } #endif i = 0; if (file_offset > 0) { /* Resume the desired (byte) position. Important: When resuming SBR * upsampling files the resulting sound_samples_done must be expanded * by a factor of 2. This is done via using sbr_fac. */ if (m4a_seek_raw(&demux_res, &input_stream, file_offset, &sound_samples_done, (int*) &i)) { sound_samples_done *= sbr_fac; } else { sound_samples_done = 0; } NeAACDecPostSeekReset(decoder, i); } else { sound_samples_done = 0; } elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); ci->set_elapsed(elapsed_time); if (i == 0) { lead_trim = ci->id3->lead_trim; } /* The main decoding loop */ while (i < demux_res.num_sample_byte_sizes) { enum codec_command_action action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; /* Deal with any pending seek requests */ if (action == CODEC_ACTION_SEEK_TIME) { /* Seek to the desired time position. Important: When seeking in SBR * upsampling files the seek_time must be divided by 2 when calling * m4a_seek and the resulting sound_samples_done must be expanded * by a factor 2. This is done via using sbr_fac. */ if (m4a_seek(&demux_res, &input_stream, (param/10/sbr_fac)*(ci->id3->frequency/100), &sound_samples_done, (int*) &i)) { sound_samples_done *= sbr_fac; elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); ci->set_elapsed(elapsed_time); seek_idx = 0; if (i == 0) { lead_trim = ci->id3->lead_trim; } } NeAACDecPostSeekReset(decoder, i); ci->seek_complete(); } /* There can be gaps between chunks, so skip ahead if needed. It * doesn't seem to happen much, but it probably means that a * "proper" file can have chunks out of order. Why one would want * that an good question (but files with gaps do exist, so who * knows?), so we don't support that - for now, at least. */ file_offset = m4a_check_sample_offset(&demux_res, i, &seek_idx); if (file_offset > ci->curpos) { ci->advance_buffer(file_offset - ci->curpos); } else if (file_offset == 0) { LOGF("AAC: get_sample_offset error\n"); return CODEC_ERROR; } /* Request the required number of bytes from the input buffer */ buffer=ci->request_buffer(&n, FAAD_BYTE_BUFFER_SIZE); /* Decode one block - returned samples will be host-endian */ ret = NeAACDecDecode(decoder, &frame_info, buffer, n); /* NeAACDecDecode may sometimes return NULL without setting error. */ if (ret == NULL || frame_info.error > 0) { LOGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error)); return CODEC_ERROR; } /* Advance codec buffer (no need to call set_offset because of this) */ ci->advance_buffer(frame_info.bytesconsumed); /* Output the audio */ ci->yield(); frame_samples = frame_info.samples >> 1; if (empty_first_frame) { /* Remove the first frame from lead_trim, under the assumption * that it had the same size as this frame */ empty_first_frame = false; lead_trim -= frame_samples; if (lead_trim < 0) { lead_trim = 0; } } /* Gather number of samples for the decoded frame. */ framelength = frame_samples - lead_trim; if (i == demux_res.num_sample_byte_sizes - 1) { // Size of the last frame const uint32_t sample_duration = (demux_res.num_time_to_samples > 0) ? demux_res.time_to_sample[demux_res.num_time_to_samples - 1].sample_duration : frame_samples; /* Currently limited to at most one frame of tail_trim. * Seems to be enough. */ if (ci->id3->tail_trim == 0 && sample_duration < frame_samples) { /* Subtract lead_trim just in case we decode a file with only * one audio frame with actual data (lead_trim is usually zero * here). */ framelength = sample_duration - lead_trim; } else { framelength -= ci->id3->tail_trim; } } if (framelength > 0) { ci->pcmbuf_insert(&decoder->time_out[0][lead_trim], &decoder->time_out[1][lead_trim], framelength); sound_samples_done += framelength; /* Update the elapsed-time indicator */ elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); ci->set_elapsed(elapsed_time); } if (lead_trim > 0) { /* frame_info.samples can be 0 for frame 0. We still want to * remove it from lead_trim, so do that during frame 1. */ if (0 == i && 0 == frame_info.samples) { empty_first_frame = true; } lead_trim -= frame_samples; if (lead_trim < 0) { lead_trim = 0; } } ++i; } LOGF("AAC: Decoded %lu samples\n", (unsigned long)sound_samples_done); return CODEC_OK; }
int decodeAACfile(char *sndfile, int def_srate, aac_dec_opt *opt) { int tagsize; unsigned long samplerate; unsigned char channels; void *sample_buffer; FILE *infile; audio_file *aufile; NeAACDecHandle hDecoder; NeAACDecFrameInfo frameInfo; NeAACDecConfigurationPtr config; int first_time = 1; /* declare variables for buffering */ DEC_BUFF_VARS infile = fopen(opt->filename, "rb"); if (infile == NULL) { /* unable to open file */ error_handler("Error opening file: %s\n", opt->filename); return 1; } INIT_BUFF(infile) tagsize = id3v2_tag(buffer); if (tagsize) { UPDATE_BUFF_SKIP(tagsize) } hDecoder = NeAACDecOpen(); /* Set the default object type and samplerate */ /* This is useful for RAW AAC files */ config = NeAACDecGetCurrentConfiguration(hDecoder); if (def_srate) config->defSampleRate = def_srate; config->defObjectType = opt->object_type; config->outputFormat = opt->output_format; NeAACDecSetConfiguration(hDecoder, config); if ((bytesconsumed = NeAACDecInit(hDecoder, buffer, bytes_in_buffer, &samplerate, &channels)) < 0) { /* If some error initializing occured, skip the file */ error_handler("Error initializing decoder library.\n"); END_BUFF NeAACDecClose(hDecoder); fclose(infile); return 1; } buffer_index += bytesconsumed; do { /* update buffer */ UPDATE_BUFF_READ sample_buffer = NeAACDecDecode(hDecoder, &frameInfo, buffer, bytes_in_buffer); /* update buffer indices */ UPDATE_BUFF_IDX(frameInfo) if (frameInfo.error > 0) { error_handler("Error: %s\n", NeAACDecGetErrorMessage(frameInfo.error)); } opt->progress_update((long)fileread, buffer_index); /* open the sound file now that the number of channels are known */ if (first_time && !frameInfo.error) { if(opt->decode_mode == 0) { if (Set_WIN_Params (INVALID_FILEDESC, samplerate, SAMPLE_SIZE, frameInfo.channels) < 0) { error_handler("\nCan't access %s\n", "WAVE OUT"); END_BUFF NeAACDecClose(hDecoder); fclose(infile); return (0); } } else { aufile = open_audio_file(sndfile, samplerate, frameInfo.channels, opt->output_format, opt->file_type, aacChannelConfig2wavexChannelMask(&frameInfo)); if (aufile == NULL) { END_BUFF NeAACDecClose(hDecoder); fclose(infile); return 0; } } first_time = 0; } if ((frameInfo.error == 0) && (frameInfo.samples > 0)) { if(opt->decode_mode == 0) WIN_Play_Samples((short*)sample_buffer, frameInfo.channels*frameInfo.samples); else write_audio_file(aufile, sample_buffer, frameInfo.samples, 0); } if (buffer_index >= fileread) sample_buffer = NULL; /* to make sure it stops now */ if(stop_decoding) break; } while (sample_buffer != NULL); NeAACDecClose(hDecoder); fclose(infile); if(opt->decode_mode == 0) WIN_Audio_close(); else { if (!first_time) close_audio_file(aufile); } END_BUFF return frameInfo.error; }
int audio_dec_decode( #ifndef WIN32 audio_decoder_operations_t *adec_ops, #endif char *outbuf, int *outlen, char *inbuf, int inlen) { unsigned long samplerate; unsigned char channels; void *sample_buffer; NeAACDecFrameInfo frameInfo; int outmaxlen = 0; char *dec_buf; int dec_bufsize; int inbuf_consumed=0; int ret = 0; FaadContext *gFaadCxt = (FaadContext*)adec_ops->pdecoder; dec_bufsize = inlen; dec_buf = inbuf; outmaxlen = *outlen ; *outlen = 0; if(!outbuf ||!inbuf || !inlen){ audio_codec_print("decoder parameter error,check \n"); goto exit; } if(gFaadCxt->init_start_flag == 0){ audio_codec_print("MyFaadDecoder init first in \n"); gFaadCxt->starttime = gettime(); gFaadCxt->init_start_flag = 1; } if (!gFaadCxt->init_flag) { gFaadCxt->error_count= 0; audio_codec_print("begin audio_decoder_init,buf size %d \n",dec_bufsize); ret = audio_decoder_init(adec_ops,outbuf,outlen,dec_buf,dec_bufsize,&inbuf_consumed); if(ret == AAC_ERROR_NO_ENOUGH_DATA){ audio_codec_print("decoder buf size %d,cost %d byte input data ,but initiation failed.^_^ \n",inlen,inbuf_consumed); dec_bufsize -= inbuf_consumed; goto exit; } gFaadCxt->init_flag = 1; dec_buf += inbuf_consumed; dec_bufsize -= inbuf_consumed; gFaadCxt->init_cost += inbuf_consumed; gFaadCxt->endtime = gettime(); audio_codec_print(" MyFaadDecoder decoder init finished total cost %d bytes,consumed time %lld ms \n",gFaadCxt->init_cost,(gFaadCxt->endtime-gFaadCxt->starttime)/1000); gFaadCxt->init_cost = 0; if(dec_bufsize < 0) dec_bufsize = 0; } NeAACDecStruct* hDecoder = (NeAACDecStruct*)(gFaadCxt->hDecoder); //TODO .fix to LATM aac decoder when ffmpeg parser return LATM aac type #if 0 if(adec_ops->nAudioDecoderType == ACODEC_FMT_AAC_LATM) hDecoder->latm_header_present = 1; #endif if(hDecoder->adts_header_present) { int nSeekNum = AACFindADTSSyncWord(dec_buf,dec_bufsize); if(nSeekNum == (dec_bufsize-1)){ audio_codec_print("%d bytes data not found adts sync header \n",nSeekNum); } dec_bufsize = dec_bufsize - nSeekNum; if(dec_bufsize < (get_frame_size(gFaadCxt)+FRAME_SIZE_MARGIN)/*AAC_INPUTBUF_SIZE/2*/){ goto exit; } } if(hDecoder->latm_header_present){ int nSeekNum = AACFindLATMSyncWord(dec_buf,dec_bufsize); if(nSeekNum == (dec_bufsize-2)){ audio_codec_print("%d bytes data not found latm sync header \n",nSeekNum); } dec_bufsize = dec_bufsize - nSeekNum; if(dec_bufsize < (get_frame_size(gFaadCxt)+FRAME_SIZE_MARGIN)/*AAC_INPUTBUF_SIZE/2*/){ goto exit; } } sample_buffer = NeAACDecDecode(gFaadCxt->hDecoder, &frameInfo, dec_buf, dec_bufsize); dec_bufsize -= frameInfo.bytesconsumed; if(frameInfo.error == 0 && sample_buffer == NULL && hDecoder->latm_header_present){ dec_bufsize -= 3; goto exit; } if ((frameInfo.error == 0) && (frameInfo.samples > 0) && sample_buffer!=NULL ) { store_frame_size(gFaadCxt,frameInfo.bytesconsumed); gFaadCxt->gSampleRate=frameInfo.samplerate; gFaadCxt->gChannels=frameInfo.channels; //code to mute first 1 s ??? #define MUTE_S 0.2 if(gFaadCxt->muted_samples == 0){ gFaadCxt->muted_samples = gFaadCxt->gSampleRate*gFaadCxt->gChannels*MUTE_S; } if(gFaadCxt->muted_count < gFaadCxt->muted_samples){ memset(sample_buffer,0,2*frameInfo.samples); gFaadCxt->muted_count += frameInfo.samples; } if( (outmaxlen-(*outlen)) >= (2*frameInfo.samples)){ memcpy(outbuf+(*outlen), sample_buffer, 2*frameInfo.samples); *outlen+=2*frameInfo.samples; gFaadCxt->error_count = 0; }else{ audio_codec_print("[%s %d]WARNING: no enough space used for pcm!\n",__FUNCTION__,__LINE__); } } if (frameInfo.error > 0)//failed seek to the head { if(frameInfo.error != 34 &&frameInfo.error != 35 ){ dec_bufsize -= RSYNC_SKIP_BYTES; audio_codec_print( "Error: %s,inlen %d\n", NeAACDecGetErrorMessage(frameInfo.error),inlen); } // sr/ch changed info happened 5 times always,some times error maybe,skip bytes else if(frameInfo.error == 34 && gFaadCxt->error_count > 5){ dec_bufsize -= RSYNC_SKIP_BYTES; audio_codec_print("%s,,inlen %d\n", NeAACDecGetErrorMessage(frameInfo.error),inlen); } gFaadCxt->error_count++; //err 34,means aac profile changed , PS.SBR,LC ....,normally happens when switch audio source if(gFaadCxt->error_count >= ERROR_RESET_COUNT ||frameInfo.error == 34){ if( gFaadCxt->hDecoder){ NeAACDecClose(gFaadCxt->hDecoder); gFaadCxt->hDecoder=NULL; } gFaadCxt->init_flag = 0; gFaadCxt->init_start_flag = 0; } } exit: if(dec_bufsize < 0) dec_bufsize = 0; if(gFaadCxt->init_flag == 0) gFaadCxt->init_cost += (inlen - dec_bufsize); return inlen - dec_bufsize; }
HRESULT TaudioCodecLibFAAD::decode(TbyteBuffer &src) { NeAACDecFrameInfo frameInfo; unsigned long size = (unsigned long)src.size(); float *outsamples = (float*)NeAACDecDecode(m_decHandle, &frameInfo, size ? &src[0] : NULL, size); src.clear(); if (frameInfo.error) { DPRINTF(_l("AAC: Error %d [%s]\n"), frameInfo.error, (const char_t*)text<char_t>(NeAACDecGetErrorMessage(frameInfo.error))); return S_OK;//S_FALSE } else if (outsamples && frameInfo.samples) { ps = !!frameInfo.ps; sbr = !!frameInfo.sbr; numframes++; bpssum += (lastbps = 8 * fmt.freq * frameInfo.bytesconsumed / (frameInfo.samples / fmt.nchannels) / 1000); if (frameInfo.channels == 2 && frameInfo.channel_position[1] == UNKNOWN_CHANNEL) { frameInfo.channel_position[0] = FRONT_CHANNEL_LEFT; frameInfo.channel_position[1] = FRONT_CHANNEL_RIGHT; } fmt = this->fmt; fmt.channelmask = 0; for (int i = 0; i < frameInfo.channels; i++) { fmt.channelmask |= chmask[frameInfo.channel_position[i]]; } int chmap[countof(frameInfo.channel_position)]; memset(chmap, 0, sizeof(chmap)); for (int i = 0; i < frameInfo.channels; i++) { unsigned int ch = 0; int mask = chmask[frameInfo.channel_position[i]]; for (int j = 0; j < 32; j++) if (fmt.channelmask & (1 << j)) { if ((1 << j) == mask) { chmap[i] = ch; break; } ch++; } } if (frameInfo.channels <= 2) { fmt.channelmask = 0; } float *dst, *dst0; dst = dst0 = (float*)getDst(frameInfo.samples * sizeof(float)); for (unsigned int j = 0; j < frameInfo.samples; j += frameInfo.channels, dst += frameInfo.channels) for (int i = 0; i < frameInfo.channels; i++) { dst[chmap[i]] = *outsamples++; } return sinkA->deliverDecodedSample(dst0, frameInfo.samples / frameInfo.channels, fmt); } else { return S_OK; } }
CAMLprim value ocaml_faad_get_error_message(value err) { return caml_copy_string((char*)NeAACDecGetErrorMessage(Int_val(err))); }
/* this is called for each file to process */ enum codec_status codec_run(void) { size_t n; int32_t bread; unsigned int frame_samples; uint32_t s = 0; unsigned char c = 0; long action = CODEC_ACTION_NULL; intptr_t param; unsigned char* buffer; NeAACDecFrameInfo frame_info; NeAACDecHandle decoder; NeAACDecConfigurationPtr conf; /* Clean and initialize decoder structures */ if (codec_init()) { LOGF("FAAD: Codec init error\n"); return CODEC_ERROR; } ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); codec_set_replaygain(ci->id3); ci->seek_buffer(ci->id3->first_frame_offset); /* initialise the sound converter */ decoder = NeAACDecOpen(); if (!decoder) { LOGF("FAAD: Decode open error\n"); return CODEC_ERROR; } conf = NeAACDecGetCurrentConfiguration(decoder); conf->outputFormat = FAAD_FMT_24BIT; /* irrelevant, we don't convert */ NeAACDecSetConfiguration(decoder, conf); buffer=ci->request_buffer(&n, FAAD_BYTE_BUFFER_SIZE); bread = NeAACDecInit(decoder, buffer, n, &s, &c); if (bread < 0) { LOGF("FAAD: DecInit: %ld, %d\n", bread, decoder->object_type); return CODEC_ERROR; } ci->advance_buffer(bread); if (ci->id3->offset > ci->id3->first_frame_offset) { /* Resume the desired (byte) position. */ ci->seek_buffer(ci->id3->offset); NeAACDecPostSeekReset(decoder, 0); update_playing_time(); } else if (ci->id3->elapsed) { action = CODEC_ACTION_SEEK_TIME; param = ci->id3->elapsed; } else { ci->set_elapsed(0); ci->set_offset(ci->id3->first_frame_offset); } /* The main decoding loop */ while (1) { if (action == CODEC_ACTION_NULL) action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; /* Deal with any pending seek requests */ if (action == CODEC_ACTION_SEEK_TIME) { /* Seek to the desired time position. */ ci->seek_buffer(ci->id3->first_frame_offset + (uint32_t)((uint64_t)param * ci->id3->bitrate / 8)); ci->set_elapsed((unsigned long)param); NeAACDecPostSeekReset(decoder, 0); ci->seek_complete(); } action = CODEC_ACTION_NULL; /* Request the required number of bytes from the input buffer */ buffer=ci->request_buffer(&n, FAAD_BYTE_BUFFER_SIZE); if (n == 0) /* End of Stream */ break; /* Decode one block - returned samples will be host-endian */ if (NeAACDecDecode(decoder, &frame_info, buffer, n) == NULL || frame_info.error > 0) { LOGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error)); return CODEC_ERROR; } /* Advance codec buffer (no need to call set_offset because of this) */ ci->advance_buffer(frame_info.bytesconsumed); /* Output the audio */ ci->yield(); frame_samples = frame_info.samples >> 1; ci->pcmbuf_insert(&decoder->time_out[0][0], &decoder->time_out[1][0], frame_samples); /* Update the elapsed-time indicator */ update_playing_time(); } LOGF("AAC: Decoding complete\n"); return CODEC_OK; }
SINT SoundSourceM4A::readSampleFrames( SINT numberOfFrames, CSAMPLE* sampleBuffer) { DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); const SINT numberOfFramesTotal = math_min( numberOfFrames, getMaxFrameIndex() - m_curFrameIndex); const SINT numberOfSamplesTotal = frames2samples(numberOfFramesTotal); CSAMPLE* pSampleBuffer = sampleBuffer; SINT numberOfSamplesRemaining = numberOfSamplesTotal; while (0 < numberOfSamplesRemaining) { if (!m_sampleBuffer.isEmpty()) { // Consume previously decoded sample data const SampleBuffer::ReadableChunk readableChunk( m_sampleBuffer.readFromHead(numberOfSamplesRemaining)); if (pSampleBuffer) { SampleUtil::copy(pSampleBuffer, readableChunk.data(), readableChunk.size()); pSampleBuffer += readableChunk.size(); } m_curFrameIndex += samples2frames(readableChunk.size()); DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(numberOfSamplesRemaining >= readableChunk.size()); numberOfSamplesRemaining -= readableChunk.size(); if (0 == numberOfSamplesRemaining) { break; // exit loop } } // All previously decoded sample data has been consumed now DEBUG_ASSERT(m_sampleBuffer.isEmpty()); if (0 == m_inputBufferLength) { // Fill input buffer from file if (isValidSampleBlockId(m_curSampleBlockId)) { // Read data for next sample block into input buffer u_int8_t* pInputBuffer = &m_inputBuffer[0]; u_int32_t inputBufferLength = m_inputBuffer.size(); // in/out parameter if (!MP4ReadSample(m_hFile, m_trackId, m_curSampleBlockId, &pInputBuffer, &inputBufferLength, NULL, NULL, NULL, NULL)) { qWarning() << "Failed to read MP4 input data for sample block" << m_curSampleBlockId << "(" << "min =" << kSampleBlockIdMin << "," << "max =" << m_maxSampleBlockId << ")"; break; // abort } ++m_curSampleBlockId; m_inputBufferLength = inputBufferLength; m_inputBufferOffset = 0; } } DEBUG_ASSERT(0 <= m_inputBufferLength); if (0 == m_inputBufferLength) { break; // EOF } // NOTE(uklotzde): The sample buffer for NeAACDecDecode2 has to // be big enough for a whole block of decoded samples, which // contains up to kFramesPerSampleBlock frames. Otherwise // we need to use a temporary buffer. CSAMPLE* pDecodeBuffer; // in/out parameter SINT decodeBufferCapacity; const SINT decodeBufferCapacityMin = frames2samples(kFramesPerSampleBlock); if (pSampleBuffer && (decodeBufferCapacityMin <= numberOfSamplesRemaining)) { // Decode samples directly into sampleBuffer pDecodeBuffer = pSampleBuffer; decodeBufferCapacity = numberOfSamplesRemaining; } else { // Decode next sample block into temporary buffer const SINT writeToTailCount = math_max( numberOfSamplesRemaining, decodeBufferCapacityMin); const SampleBuffer::WritableChunk writableChunk( m_sampleBuffer.writeToTail(writeToTailCount)); pDecodeBuffer = writableChunk.data(); decodeBufferCapacity = writableChunk.size(); } DEBUG_ASSERT(decodeBufferCapacityMin <= decodeBufferCapacity); NeAACDecFrameInfo decFrameInfo; void* pDecodeResult = NeAACDecDecode2( m_hDecoder, &decFrameInfo, &m_inputBuffer[m_inputBufferOffset], m_inputBufferLength, reinterpret_cast<void**>(&pDecodeBuffer), decodeBufferCapacity * sizeof(*pDecodeBuffer)); // Verify the decoding result if (0 != decFrameInfo.error) { qWarning() << "AAC decoding error:" << decFrameInfo.error << NeAACDecGetErrorMessage(decFrameInfo.error) << getUrlString(); break; // abort } DEBUG_ASSERT(pDecodeResult == pDecodeBuffer); // verify the in/out parameter // Verify the decoded sample data for consistency if (getChannelCount() != decFrameInfo.channels) { qWarning() << "Corrupt or unsupported AAC file:" << "Unexpected number of channels" << decFrameInfo.channels << "<>" << getChannelCount(); break; // abort } if (getFrameRate() != SINT(decFrameInfo.samplerate)) { qWarning() << "Corrupt or unsupported AAC file:" << "Unexpected sample rate" << decFrameInfo.samplerate << "<>" << getFrameRate(); break; // abort } // Consume input data m_inputBufferLength -= decFrameInfo.bytesconsumed; m_inputBufferOffset += decFrameInfo.bytesconsumed; // Consume decoded output data const SINT numberOfSamplesDecoded = decFrameInfo.samples; DEBUG_ASSERT(numberOfSamplesDecoded <= decodeBufferCapacity); SINT numberOfSamplesRead; if (pDecodeBuffer == pSampleBuffer) { numberOfSamplesRead = math_min(numberOfSamplesDecoded, numberOfSamplesRemaining); pSampleBuffer += numberOfSamplesRead; } else { m_sampleBuffer.readFromTail(decodeBufferCapacity - numberOfSamplesDecoded); const SampleBuffer::ReadableChunk readableChunk( m_sampleBuffer.readFromHead(numberOfSamplesRemaining)); numberOfSamplesRead = readableChunk.size(); if (pSampleBuffer) { SampleUtil::copy(pSampleBuffer, readableChunk.data(), numberOfSamplesRead); pSampleBuffer += numberOfSamplesRead; } } // The decoder might decode more samples than actually needed // at the end of the file! When the end of the file has been // reached decoding can be restarted by seeking to a new // position. DEBUG_ASSERT(numberOfSamplesDecoded >= numberOfSamplesRead); m_curFrameIndex += samples2frames(numberOfSamplesRead); DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(numberOfSamplesRemaining >= numberOfSamplesRead); numberOfSamplesRemaining -= numberOfSamplesRead; } DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(numberOfSamplesTotal >= numberOfSamplesRemaining); return samples2frames(numberOfSamplesTotal - numberOfSamplesRemaining); }
static gint xmms_faad_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, xmms_error_t *err) { xmms_faad_data_t *data; xmms_error_t error; NeAACDecFrameInfo frameInfo; gpointer sample_buffer; guint size, bytes_read = 0; data = xmms_xform_private_data_get (xform); g_return_val_if_fail (data, -1); size = MIN (data->outbuf->len, len); while (size == 0) { gboolean need_read; /* MP4 demuxer always gives full packets so we need different handling */ if (data->filetype == FAAD_TYPE_MP4) need_read = (data->buffer_length == 0); else need_read = (data->buffer_length < data->buffer_size); if (need_read) { bytes_read = xmms_xform_read (xform, (gchar *) data->buffer + data->buffer_length, data->buffer_size - data->buffer_length, &error); if (bytes_read <= 0 && data->buffer_length == 0) { XMMS_DBG ("EOF"); return 0; } data->buffer_length += bytes_read; } sample_buffer = NeAACDecDecode (data->decoder, &frameInfo, data->buffer, data->buffer_length); g_memmove (data->buffer, data->buffer + frameInfo.bytesconsumed, data->buffer_length - frameInfo.bytesconsumed); data->buffer_length -= frameInfo.bytesconsumed; bytes_read = frameInfo.samples * xmms_sample_size_get (data->sampleformat); if (bytes_read > 0 && frameInfo.error == 0) { gint32 temp, toskip = 0; if (data->samplerate != frameInfo.samplerate || data->channels != frameInfo.channels) { /* We should inform output to change parameters somehow */ XMMS_DBG ("Output format changed in the middle of a read!"); data->samplerate = frameInfo.samplerate; data->channels = frameInfo.channels; } if (xmms_xform_auxdata_get_int (xform, "frame_offset", &temp)) { toskip = (temp * frameInfo.channels * xmms_sample_size_get (data->sampleformat)); } if (xmms_xform_auxdata_get_int (xform, "frame_duration", &temp)) { bytes_read = (temp * frameInfo.channels * xmms_sample_size_get (data->sampleformat)); } g_string_append_len (data->outbuf, sample_buffer + toskip, bytes_read - toskip); } else if (frameInfo.error > 0) { XMMS_DBG ("ERROR %d in faad decoding: %s", frameInfo.error, NeAACDecGetErrorMessage (frameInfo.error)); return -1; } size = MIN (data->outbuf->len, len); } memcpy (buf, data->outbuf->str, size); g_string_erase (data->outbuf, 0, size); return size; }
/***************************************************************************** * DecodeBlock: *****************************************************************************/ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block; if( !pp_block || !*pp_block ) return NULL; p_block = *pp_block; *pp_block = NULL; if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY | BLOCK_FLAG_CORRUPTED) ) { Flush( p_dec ); if( p_block->i_flags & (BLOCK_FLAG_CORRUPTED) ) { block_Release( p_block ); return NULL; } } /* Remove ADTS header if we have decoder specific config */ if( p_dec->fmt_in.i_extra && p_block->i_buffer > 7 ) { if( p_block->p_buffer[0] == 0xff && ( p_block->p_buffer[1] & 0xf0 ) == 0xf0 ) /* syncword */ { /* ADTS header present */ size_t i_header_size; /* 7 bytes (+ 2 bytes for crc) */ i_header_size = 7 + ( ( p_block->p_buffer[1] & 0x01 ) ? 0 : 2 ); /* FIXME: multiple blocks per frame */ if( p_block->i_buffer > i_header_size ) { p_block->p_buffer += i_header_size; p_block->i_buffer -= i_header_size; } } } /* Append the block to the temporary buffer */ if( p_sys->i_buffer_size < p_sys->i_buffer + p_block->i_buffer ) { size_t i_buffer_size = p_sys->i_buffer + p_block->i_buffer; uint8_t *p_buffer = realloc( p_sys->p_buffer, i_buffer_size ); if( p_buffer ) { p_sys->i_buffer_size = i_buffer_size; p_sys->p_buffer = p_buffer; } else { p_block->i_buffer = 0; } } if( p_block->i_buffer > 0 ) { memcpy( &p_sys->p_buffer[p_sys->i_buffer], p_block->p_buffer, p_block->i_buffer ); p_sys->i_buffer += p_block->i_buffer; p_block->i_buffer = 0; } if( p_dec->fmt_out.audio.i_rate == 0 && p_dec->fmt_in.i_extra > 0 ) { /* We have a decoder config so init the handle */ unsigned long i_rate; unsigned char i_channels; if( NeAACDecInit2( p_sys->hfaad, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra, &i_rate, &i_channels ) >= 0 ) { p_dec->fmt_out.audio.i_rate = i_rate; p_dec->fmt_out.audio.i_channels = i_channels; p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_guessed[i_channels]; date_Init( &p_sys->date, i_rate, 1 ); } } if( p_dec->fmt_out.audio.i_rate == 0 && p_sys->i_buffer ) { unsigned long i_rate; unsigned char i_channels; /* Init faad with the first frame */ if( NeAACDecInit( p_sys->hfaad, p_sys->p_buffer, p_sys->i_buffer, &i_rate, &i_channels ) < 0 ) { block_Release( p_block ); return NULL; } p_dec->fmt_out.audio.i_rate = i_rate; p_dec->fmt_out.audio.i_channels = i_channels; p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_guessed[i_channels]; date_Init( &p_sys->date, i_rate, 1 ); } if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != date_Get( &p_sys->date ) ) { date_Set( &p_sys->date, p_block->i_pts ); } else if( !date_Get( &p_sys->date ) ) { /* We've just started the stream, wait for the first PTS. */ block_Release( p_block ); p_sys->i_buffer = 0; return NULL; } /* Decode all data */ if( p_sys->i_buffer > 1) { void *samples; NeAACDecFrameInfo frame; block_t *p_out; samples = NeAACDecDecode( p_sys->hfaad, &frame, p_sys->p_buffer, p_sys->i_buffer ); if( frame.error > 0 ) { msg_Warn( p_dec, "%s", NeAACDecGetErrorMessage( frame.error ) ); if( frame.error == 21 || frame.error == 12 ) { /* * Once an "Unexpected channel configuration change" * or a "Invalid number of channels" error * occurs, it will occurs afterwards, and we got no sound. * Reinitialization of the decoder is required. */ unsigned long i_rate; unsigned char i_channels; NeAACDecHandle *hfaad; NeAACDecConfiguration *cfg,*oldcfg; oldcfg = NeAACDecGetCurrentConfiguration( p_sys->hfaad ); hfaad = NeAACDecOpen(); cfg = NeAACDecGetCurrentConfiguration( hfaad ); if( oldcfg->defSampleRate ) cfg->defSampleRate = oldcfg->defSampleRate; cfg->defObjectType = oldcfg->defObjectType; cfg->outputFormat = oldcfg->outputFormat; NeAACDecSetConfiguration( hfaad, cfg ); if( NeAACDecInit( hfaad, p_sys->p_buffer, p_sys->i_buffer, &i_rate,&i_channels ) < 0 ) { /* reinitialization failed */ NeAACDecClose( hfaad ); NeAACDecSetConfiguration( p_sys->hfaad, oldcfg ); } else { NeAACDecClose( p_sys->hfaad ); p_sys->hfaad = hfaad; p_dec->fmt_out.audio.i_rate = i_rate; p_dec->fmt_out.audio.i_channels = i_channels; p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_guessed[i_channels]; date_Init( &p_sys->date, i_rate, 1 ); } } /* Flush the buffer */ p_sys->i_buffer = 0; block_Release( p_block ); return NULL; } if( frame.channels <= 0 || frame.channels > 8 || frame.channels == 7 ) { msg_Warn( p_dec, "invalid channels count: %i", frame.channels ); /* Flush the buffer */ p_sys->i_buffer -= frame.bytesconsumed; if( p_sys->i_buffer > 0 ) { memmove( p_sys->p_buffer,&p_sys->p_buffer[frame.bytesconsumed], p_sys->i_buffer ); } block_Release( p_block ); return NULL; } if( frame.samples <= 0 ) { msg_Warn( p_dec, "decoded zero sample" ); /* Flush the buffer */ p_sys->i_buffer -= frame.bytesconsumed; if( p_sys->i_buffer > 1 ) { memmove( p_sys->p_buffer,&p_sys->p_buffer[frame.bytesconsumed], p_sys->i_buffer ); } else { /* Drop byte of padding */ p_sys->i_buffer = 0; } block_Release( p_block ); return NULL; } /* We decoded a valid frame */ if( p_dec->fmt_out.audio.i_rate != frame.samplerate ) { date_Init( &p_sys->date, frame.samplerate, 1 ); date_Set( &p_sys->date, p_block->i_pts ); } p_block->i_pts = VLC_TS_INVALID; /* PTS is valid only once */ p_dec->fmt_out.audio.i_rate = frame.samplerate; p_dec->fmt_out.audio.i_channels = frame.channels; /* Adjust stream info when dealing with SBR/PS */ bool b_sbr = (frame.sbr == 1) || (frame.sbr == 2); if( p_sys->b_sbr != b_sbr || p_sys->b_ps != frame.ps ) { const char *psz_ext = (b_sbr && frame.ps) ? "SBR+PS" : b_sbr ? "SBR" : "PS"; msg_Dbg( p_dec, "AAC %s (channels: %u, samplerate: %lu)", psz_ext, frame.channels, frame.samplerate ); if( !p_dec->p_description ) p_dec->p_description = vlc_meta_New(); if( p_dec->p_description ) vlc_meta_AddExtra( p_dec->p_description, _("AAC extension"), psz_ext ); p_sys->b_sbr = b_sbr; p_sys->b_ps = frame.ps; } /* Convert frame.channel_position to our own channel values */ p_dec->fmt_out.audio.i_physical_channels = 0; const uint32_t nbChannels = frame.channels; unsigned j; for( unsigned i = 0; i < nbChannels; i++ ) { /* Find the channel code */ for( j = 0; j < MAX_CHANNEL_POSITIONS; j++ ) { if( frame.channel_position[i] == pi_channels_in[j] ) break; } if( j >= MAX_CHANNEL_POSITIONS ) { msg_Warn( p_dec, "unknown channel ordering" ); /* Invent something */ j = i; } /* */ p_sys->pi_channel_positions[i] = pi_channels_out[j]; if( p_dec->fmt_out.audio.i_physical_channels & pi_channels_out[j] ) frame.channels--; /* We loose a duplicated channel */ else p_dec->fmt_out.audio.i_physical_channels |= pi_channels_out[j]; } if ( nbChannels != frame.channels ) { p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_guessed[nbChannels]; } else { p_dec->fmt_out.audio.i_original_channels = p_dec->fmt_out.audio.i_physical_channels; } p_dec->fmt_out.audio.i_channels = nbChannels; if( decoder_UpdateAudioFormat( p_dec ) ) p_out = NULL; else p_out = decoder_NewAudioBuffer( p_dec, frame.samples / nbChannels ); if( p_out == NULL ) { p_sys->i_buffer = 0; block_Release( p_block ); return NULL; } p_out->i_pts = date_Get( &p_sys->date ); p_out->i_length = date_Increment( &p_sys->date, frame.samples / nbChannels ) - p_out->i_pts; DoReordering( (uint32_t *)p_out->p_buffer, samples, frame.samples / nbChannels, nbChannels, p_sys->pi_channel_positions ); p_sys->i_buffer -= frame.bytesconsumed; if( p_sys->i_buffer > 0 ) { memmove( p_sys->p_buffer, &p_sys->p_buffer[frame.bytesconsumed], p_sys->i_buffer ); } block_Release( p_block ); return p_out; } else { /* Drop byte of padding */ p_sys->i_buffer = 0; } block_Release( p_block ); return NULL; }
int decodeMP4file(char *sndfile, aac_dec_opt *opt) { int track; unsigned long samplerate; unsigned char channels; void *sample_buffer; mp4ff_t *infile; FILE *mp4File; int sampleId, numSamples; audio_file *aufile; NeAACDecHandle hDecoder; NeAACDecFrameInfo frameInfo; unsigned char *buffer; int buffer_size; int first_time = 1; /* initialise the callback structure */ mp4ff_callback_t *mp4cb = malloc(sizeof(mp4ff_callback_t)); mp4File = fopen(opt->filename, "rb"); mp4cb->read = read_callback; mp4cb->seek = seek_callback; mp4cb->user_data = mp4File; infile = mp4ff_open_read(mp4cb); if (!infile) { /* unable to open file */ error_handler("Error opening file: %s\n", opt->filename); return 1; } if ((track = GetAACTrack(infile)) < 0) { error_handler("Unable to find correct AAC sound track in the MP4 file.\n"); mp4ff_close(infile); free(mp4cb); fclose(mp4File); return 1; } buffer = NULL; buffer_size = 0; mp4ff_get_decoder_config(infile, track, &buffer, &buffer_size); hDecoder = NeAACDecOpen(); if(NeAACDecInit2(hDecoder, buffer, buffer_size, &samplerate, &channels) < 0) { /* If some error initializing occured, skip the file */ error_handler("Error initializing decoder library.\n"); NeAACDecClose(hDecoder); mp4ff_close(infile); free(mp4cb); fclose(mp4File); return 1; } if (buffer) free(buffer); numSamples = mp4ff_num_samples(infile, track); for (sampleId = 0; sampleId < numSamples; sampleId++) { int rc; /* get access unit from MP4 file */ buffer = NULL; buffer_size = 0; rc = mp4ff_read_sample(infile, track, sampleId, &buffer, &buffer_size); if (rc == 0) { error_handler("Reading from MP4 file failed.\n"); NeAACDecClose(hDecoder); mp4ff_close(infile); free(mp4cb); fclose(mp4File); return 1; } sample_buffer = NeAACDecDecode(hDecoder, &frameInfo, buffer, buffer_size); if (buffer) free(buffer); opt->progress_update((long)numSamples, sampleId); /* open the sound file now that the number of channels are known */ if (first_time && !frameInfo.error) { if(opt->decode_mode == 0) { if (Set_WIN_Params (INVALID_FILEDESC, samplerate, SAMPLE_SIZE, frameInfo.channels) < 0) { error_handler("\nCan't access %s\n", "WAVE OUT"); NeAACDecClose(hDecoder); mp4ff_close(infile); free(mp4cb); fclose(mp4File); return (0); } } else { aufile = open_audio_file(sndfile, samplerate, frameInfo.channels, opt->output_format, opt->file_type, aacChannelConfig2wavexChannelMask(&frameInfo)); if (aufile == NULL) { NeAACDecClose(hDecoder); mp4ff_close(infile); free(mp4cb); fclose(mp4File); return 0; } } first_time = 0; } if ((frameInfo.error == 0) && (frameInfo.samples > 0)) { if(opt->decode_mode == 0) WIN_Play_Samples((short*)sample_buffer, frameInfo.channels*frameInfo.samples); else write_audio_file(aufile, sample_buffer, frameInfo.samples, 0); } if (frameInfo.error > 0) { error_handler("Error: %s\n", NeAACDecGetErrorMessage(frameInfo.error)); break; } if(stop_decoding) break; } NeAACDecClose(hDecoder); mp4ff_close(infile); free(mp4cb); fclose(mp4File); if(opt->decode_mode == 0) WIN_Audio_close(); else { if (!first_time) close_audio_file(aufile); } return frameInfo.error; }
bool CAacDecoder::DecodeFrame(const CAdtsFrame *pFrame, DecodeFrameInfo *pInfo) { if (m_hDecoder == NULL) { return false; } // 初回フレーム解析 if (m_bInitRequest || pFrame->GetChannelConfig() != m_LastChannelConfig) { if (!m_bInitRequest) { // チャンネル設定が変化した、デコーダリセット if (!ResetDecoder()) return false; } unsigned long SampleRate; unsigned char Channels; if (::NeAACDecInit(m_hDecoder, const_cast<BYTE*>(pFrame->GetData()), pFrame->GetSize(), &SampleRate, &Channels) < 0) { return false; } m_bInitRequest = false; m_LastChannelConfig = pFrame->GetChannelConfig(); } // デコード NeAACDecFrameInfo FrameInfo; //::ZeroMemory(&FrameInfo, sizeof(FrameInfo)); BYTE *pPcmBuffer = pointer_cast<BYTE*>( ::NeAACDecDecode(m_hDecoder, &FrameInfo, const_cast<BYTE*>(pFrame->GetData()), pFrame->GetSize())); bool bOK = false; if (FrameInfo.error == 0) { m_AudioInfo.Frequency = FrameInfo.samplerate; m_AudioInfo.Channels = FrameInfo.channels; // FAADではモノラルが2chにデコードされる if (FrameInfo.channels == 2 && m_LastChannelConfig == 1) m_AudioInfo.OrigChannels = 1; else m_AudioInfo.OrigChannels = FrameInfo.channels; m_AudioInfo.bDualMono = FrameInfo.channels == 2 && m_LastChannelConfig == 0; if (FrameInfo.samples > 0) { pInfo->pData = pPcmBuffer; pInfo->Samples = FrameInfo.samples / FrameInfo.channels; pInfo->Info = m_AudioInfo; pInfo->bDiscontinuity = m_bDecodeError; bOK = true; } } else { // エラー発生 #ifdef _DEBUG ::OutputDebugString(TEXT("CAacDecoder::Decode error - ")); ::OutputDebugStringA(NeAACDecGetErrorMessage(FrameInfo.error)); ::OutputDebugString(TEXT("\n")); #endif // リセットする ResetDecoder(); } return bOK; }