Java fronty, Pole a JNI

hlasů
1

Myslím, že to je obecný Java otázka, ale to vyžaduje trochu Android věci.

Takže tady je řešení: Mám JNI zabalený verzi mpg123 pro Android, a mohu stáhnout data PCM ze souboru MP3 na sdcard. Rád bych vytáhnout kus tato data, provést analýzu na něm používat jinou třídu jsem napsal, a pak ji zatlačte do fronty. V ideálním případě bych rád zvuk přehrávat pomocí čtyř sekundovým zpožděním. dosáhl jsem to bez zpoždění pomocí tohoto kódu:

public void run() 
{
  // The actual thread where the PCM data gets processed and analyzed
 short[] pcm = new short[ 4096 ];
 short[] zero = new short[ 4096 ];
 Queue<short[]> buffer = new LinkedList<short[]>();

 // Fill the zero buffer
 for( int i = 0; i < 4096; i++ )
  zero[i] = 0;

 // Push back 4 seconds of silence - Note this commented section
 //for( int i = 0; i < 43; i++ )
 // buffer.add( zero );

 // Analyze the whole file 
 while( !isInterrupted() )
 {
  // Grab and analyze data, add events
  int ret = audio.GetPCM( pcm );
  //Log.d( AudioThread, GetPCM returns:  + ret );
  if( ret != MPG123.MPG123_DONE )
  {
   // Process the PCM data
   if( bd.Process( pcm ) != BeatDetection.AUDALYSIS_OK )
    Log.v( AudioThread, Beat Detection Error! );

   // Add the data to the PCM buffer
   buffer.add( pcm );
  }

  // Play the audio
  short[] data = buffer.poll();
  if( data != null ) // If we have data left in the buffer
   at.write( data, 0, 4096 ); // Write it to the audio track
  else
   break; // Otherwise we need to exit the loop

  Log.d( AudioThread, BufferSize=  + buffer.size() );
 }

 // Debug message
 Log.d( AudioThread, Exiting Thread. );

 // Clean stuff up
 bd.Cleanup();
 audio.Cleanup();
 at.stop();
 at.release(); 
 }

To znamená, že když se snažím představit zpoždění do mé fronty přidáním „4 sekundy“ v hodnotě 0 let do fronty ( poznámka komentovaný blok ), moje hudba hraje hned, ale začne 4 sekundy do písně a hraje v reálném čase, dokud fronty začne vyprazdňovat, kde se hraje stejnou kus dokola až do porušení ze smyčky. Skoro se zdá, jako by se fronta se chová jako „First In Last Out“ frontě spíše než „First In First Out“ frontě.

Možná nejsem pomocí Java fronty správně? Možná, že to je nějaká podivná chyba s android AudioTrack?

Dík!

-Griff

EDIT - jsem vyřešil problém. Zdá se to být problém s mým realizaci JNI z GetPCM. Zdá se, že když jsem se zkopíruje data do PCM z úrovně JNI je nastavena stejná data pro každou instanci PCM tlačil zpět do fronty, nastavit každý vstup PCM ve frontě na stejném rámu PCM dat. Jsem vyřešil tento problém změnou:

buffer.add( pcm );

na

buffer.add( pcm.clone() );

New Otázka: Je to normální chování Java? Už jsem implementovat funkce JNI nesprávně?

JNIEXPORT jint JNICALL Java_com_motalenbubble_projectlucid_MPG123_GetPCM(
    JNIEnv* env,
    jobject obj,
    jshortArray data ) // jshortarray already has a size attribute
{
    // Call mpg123_read
    jint  err  = MPG123_OK, length;
    jshort *pcm;
    jsize len = (*env)->GetArrayLength( env, data );

    pcm = (*env)->GetShortArrayElements( env, data, NULL );
    err = mpg123_read( mh, (unsigned char*)pcm, len * sizeof( short ), &length ); // Read length is in bytes - we need in shorts. 
    (*env)->ReleaseShortArrayElements( env, data, pcm, 0 );
    // Annoying logging
    //dprintf(0, read(%d): %s\n, length, err == MPG123_ERR ? mpg123_strerror(mh) : mpg123_plain_strerror(err)); 
    return err;
}
Položena 26/07/2010 v 02:44
zdroj uživatelem
V jiných jazycích...                            


1 odpovědí

hlasů
2

Vypadá to, že role vaší funkce JNI je:

Přihrej inicializované vyrovnávací paměti (tj java krátký objekt pole), a to bude naplněna další kus vzorků z mp3 dekodéru.

Pro účely dělá tento úkol se zdá být provedena správně. Funkce nikdy instance objektu krátká pole java, a já si nemyslím, že by se dalo očekávat na.

Dám popis problému, i když se zdá, že již pochopil, co se děje.

Ve metodu run () pro pcmproměnnou instanci krátkou pole najednou. Pokaždé, když budete volat audio.GetPCM( pcm ), budete dávat to stejný objekt pole. A pak, když říkáte buffer.add( pcm ), že vždy enqueues s odkazem na stejném poli . Takže, pokud zavoláte GetPCM, a pak volat GetPCM znovu před psali rámeček na zvukové zařízení, GetPCM bude katastrofálně přepsat pole.

Vyřešil jste problém buffer.add( pcm.clone() ), protože to vždy alokuje nové pole, a doplňuje odkaz na toto nové pole do fronty. GetPCM stále přepíše stejné pole ( pcm) pokaždé, ale to není problém, protože fronta obsahuje odkazy na nepříbuzných polí, které byly vytvořeny jako kopie minulých obsahu pcmpole.

Problém není ve skutečnosti souvisí s Android nebo JNI; GetPCM mohly být stejně tak realizovány v čisté Javě a stejný problém by vznikl.


Používání pcm.clone () je bezpečné řešení, ale to nemusí být nejúčinnější, protože vyžaduje nové pole, které mají být instance na každém snímku.

Pokud si nemusíte dekódovat data mp3 v předstihu, pak byste měli být schopni navrhnout mechanismus, který zabraňuje GetPCM od volána, dokud fronta je prázdná, a můžete dostat s jedním nebo dvěma předem přidělené vyrovnávací paměti.

Na druhou stranu, pokud jste absolutně nutné dekódovat data MP3 čtyř sekund dopředu, určitě se vám bude nevyhnutelně potřebovat hodně vyrovnávací paměti. Ale obecně, výkon je lepší, pokud je paměti přidělené jednou na začátku, a znovu použít, a nikoli opakovaně dynamicky přidělena.

Odpovězeno 12/08/2010 v 18:37
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more