2012-05-27 6 views
32

Chciałbym uzyskać bufor bajtowy z zasobu audio za pomocą obiektu OpenSL ES FileDescriptor, więc mogę go wielokrotnie zamieniać w kolejkę do SimpleBufferQueue, zamiast używać interfejsów SL do odtwarzania/zatrzymywania/wyszukiwania pliku.Czy można uzyskać bufor bajtów bezpośrednio z zasobu audio w OpenSL ES (dla systemu Android)?

Istnieją trzy główne powody, dla których chciałbym bezpośrednio zarządzać bajtów przykładowe:

  1. OpenSL wykorzystuje warstwę AudioTrack do PLAY/STOP/etc na odtwarzacz obiektów. To nie tylko wprowadza niepożądane obciążenie, ale także ma kilka błędów, a szybkie uruchamianie/zatrzymywanie odtwarzacza powoduje wiele problemów.
  2. Potrzebuję manipulować bezpośrednio buforem bajtowym dla niestandardowych efektów DSP.
  3. Klipy, które będę odtwarzać, są małe i wszystkie mogą być załadowane do pamięci, aby uniknąć narzutu we/wy pliku. Dodatkowo, zapisywanie własnych buforów pozwoli mi zmniejszyć opóźnienie, pisząc 0 do wyjściowego zlewu, i po prostu przełączając się na bajty przykładowe podczas odtwarzania, zamiast ZATRZYMYĆ, WSTRZYMAĆ i ODTWARZAĆ ścieżkę dźwiękową.

porządku, więc uzasadnienia Complete - oto co próbowałem - Mam Sample struct, który zawiera w istocie ścieżkę wejścia i wyjścia oraz tablicę bajtów do przechowywania próbek. Wejście to mój odtwarzacz FileDescriptor, a wyjście to obiekt SimpleBufferQueue. Oto mój struct:

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; 

po uruchomieniu odtwarzacza plików fdPlayerObject i malloc-ing pamięci dla mojego bufora bajtów z

sample->buffer = malloc(sizeof(short)*sample->totalSamples); 

Dostaję jego interfejs BufferQueue z

// get the buffer queue interface 
result = (*(sample->fdPlayerObject))->GetInterface(sample->fdPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &(sample->fdBufferQueue)); 

Następnie tworzę egzemplarz wyjściowy :

// 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); 

Gdy chcę odtworzyć próbkę, używam:

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)); 

Jednak to powoduje mój app zamrozić i zamknięty. Coś tu nie gra. Również, Wolałbym nie pobierać próbek z bufora bufora deskryptorów plików za każdym razem. Zamiast tego chciałbym na stałe zapisać go w tablicy bajtów i dodać go do wyjścia, kiedy tylko zechcę.

+2

Witaj khiner, czy pomogłoby Ci odczytać pliki .wav z folderu zasobów w bajcie Java lub krótkiej tablicy, a następnie przetworzyć to dalej? –

+0

Nie jestem pewien, ile mogę pomóc, ale tylko dla nagrania - czy używasz NDK? Czy to dlatego Twój kod jest w C++? – Erhannis

+2

Tak, używam NDK, a to jest rzeczywiście czysty C. To pytanie jest coraz dłuższe w ząb. Dokonałem wielu postępów w tej sprawie i otrzymam porządną odpowiedź. – khiner

Odpowiedz

5

Dekodowanie do PCM jest dostępne na poziomie API 14 i wyższym.

Podczas tworzenia odtwarzacza dekodera czego potrzebujesz ustawić Android prostą kolejkę bufora jako dane umywalką:

// 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); 

Dla kolejce dekodera trzeba enqueue zestaw pustych buforów do Android prosty kolejce bufora, który zostanie wypełniony z danymi PCM.

Potrzebujesz też zarejestrować program obsługi wywołania zwrotnego w kolejce dekodera, który zostanie wywołany, gdy dane PCM będą gotowe. Program obsługi wywołania zwrotnego powinien przetwarzać dane PCM, ponownie zamon- tować pusty bufor, a następnie powrócić.Aplikacja jest odpowiedzialna za śledzenie zdekodowanych buforów; lista parametrów wywołania zwrotnego nie zawiera wystarczających informacji wskazujących, który bufor został wypełniony lub który bufor ma zostać następny.

Dekodowanie na PCM obsługuje pauzę i początkowe wyszukiwanie. Regulacja głośności, efekty, zapętlanie i szybkość odtwarzania nie są obsługiwane.

Przeczytaj Odszyfruj dźwięk do PCM od OpenSL ES for Android, aby uzyskać więcej informacji.