我想使用OpenSL ES FileDescriptor对象从音频资产中获取字节缓冲区,因此我可以将其重复排列到SimpleBufferQueue,而不是使用SL接口来播放/停止/搜索文件。
我想直接管理样本字节有三个主要原因:
好的,所以理由完成 - 这就是我尝试过的 - 我有一个 Sample 结构,其中包含一个输入和输出轨道,以及一个用于保存样本的字节数组。输入是我的FileDescriptor播放器,输出是SimpleBufferQueue对象。这是我的结构:
typedef struct Sample_ {
// buffer to hold all samples
short *buffer;
int totalSamples;
SLObjectItf fdPlayerObject;
// file descriptor player interfaces
SLPlayItf fdPlayerPlay;
SLSeekItf fdPlayerSeek;
SLMuteSoloItf fdPlayerMuteSolo;
SLVolumeItf fdPlayerVolume;
SLAndroidSimpleBufferQueueItf fdBufferQueue;
SLObjectItf outputPlayerObject;
SLPlayItf outputPlayerPlay;
// output buffer interfaces
SLAndroidSimpleBufferQueueItf outputBufferQueue;
} Sample;
初始化文件播放器 fdPlayerObject 后,使用
为我的字节缓冲区内存存储器sample->buffer = malloc(sizeof(short)*sample->totalSamples);
我正在使用
获取其BufferQueue接口// get the buffer queue interface
result = (*(sample->fdPlayerObject))->GetInterface(sample->fdPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &(sample->fdBufferQueue));
然后我实例化输出播放器:
// create audio player for output buffer queue
const SLInterfaceID ids1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
const SLboolean req1[] = {SL_BOOLEAN_TRUE};
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &(sample->outputPlayerObject), &outputAudioSrc, &audioSnk,
1, ids1, req1);
// realize the output player
result = (*(sample->outputPlayerObject))->Realize(sample->outputPlayerObject, SL_BOOLEAN_FALSE);
assert(result == SL_RESULT_SUCCESS);
// get the play interface
result = (*(sample->outputPlayerObject))->GetInterface(sample->outputPlayerObject, SL_IID_PLAY, &(sample->outputPlayerPlay));
assert(result == SL_RESULT_SUCCESS);
// get the buffer queue interface for output
result = (*(sample->outputPlayerObject))->GetInterface(sample->outputPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
&(sample->outputBufferQueue));
assert(result == SL_RESULT_SUCCESS);
// set the player's state to playing
result = (*(sample->outputPlayerPlay))->SetPlayState(sample->outputPlayerPlay, SL_PLAYSTATE_PLAYING);
assert(result == SL_RESULT_SUCCESS);
当我想播放样本时,我正在使用:
Sample *sample = &samples[sampleNum];
// THIS WORKS FOR SIMPLY PLAYING THE SAMPLE, BUT I WANT THE BUFFER DIRECTLY
// if (sample->fdPlayerPlay != NULL) {
// // set the player's state to playing
// (*(sample->fdPlayerPlay))->SetPlayState(sample->fdPlayerPlay, SL_PLAYSTATE_PLAYING);
// }
// fill buffer with the samples from the file descriptor
(*(sample->fdBufferQueue))->Enqueue(sample->fdBufferQueue, sample->buffer,sample->totalSamples*sizeof(short));
// write the buffer to the outputBufferQueue, which is already playing
(*(sample->outputBufferQueue))->Enqueue(sample->outputBufferQueue, sample->buffer, sample->totalSamples*sizeof(short));
但是,这会导致我的应用冻结并关闭。这里不对劲。 同样,我宁愿每次都不从文件描述符的BufferQueue中获取样本。相反,我想永久地将它存储在一个字节数组中,并在我喜欢的时候将它排入输出。
答案 0 :(得分:6)
可在API级别14及更高版本处解码到PCM。
创建解码器播放器时,需要将Android简单缓冲区队列设置为数据接收器:
// For init use something like this:
SLDataLocator_AndroidFD locatorIn = {SL_DATALOCATOR_ANDROIDFD, decriptor, start, length};
SLDataFormat_MIME dataFormat = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
SLDataSource audioSrc = {&locatorIn, &dataFormat};
SLDataLocator_AndroidSimpleBufferQueue loc_bq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
SLDataSink audioSnk = { &loc_bq, NULL };
const SLInterfaceID ids[2] = {SL_IID_PLAY, SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
SLresult result = (*engineEngine)->CreateAudioPlayer(engineEngine, &(sample->fdPlayerObject), &outputAudioSrc, &audioSnk, 2, ids1, req1);
对于解码器队列,您需要将一组空缓冲区排入Android简单缓冲区队列,该队列将填充PCM数据。
此外,您需要在解码器队列中注册一个回调处理程序,当PCM数据准备就绪时将调用该解码器队列。回调处理程序应处理PCM数据,重新排队现在为空的缓冲区,然后返回。该应用程序负责跟踪已解码的缓冲区;回调参数列表不包含足够的信息来指示填充了哪个缓冲区或下一个要排队的缓冲区。
解码为PCM支持暂停和初始搜索。不支持音量控制,效果,循环和播放速率。
从OpenSL ES for Android读取将音频解码为PCM 以获取更多详细信息。