startag - Decodificación de MP3 en Android
star music tag editor descargar para android (4)
La forma correcta de hacerlo es crear su propio firmware y realizar el descifrado como parte de un códec OpenCORE personalizado. Eso, por supuesto, lo limitará a dispositivos donde pueda instalar ese firmware.
Tenga en cuenta que el resto de esto es algo especulativo. De hecho, tengo la necesidad de hacer algo similar a lo que estás describiendo, pero no tengo tiempo reservado para abordar el problema durante un par de meses. Entonces, describiré esto de la manera en que abordaría el problema.
Una solución es la descrita en la respuesta de twk. No tiene que usar la tarjeta SD, pero es probable que tenga un archivo temporal legible para todo el mundo en su almacén de archivos local de la aplicación ( getFilesDir()
). Descargue el primer fragmento, descifrelo, escríbalo como un archivo MP3 legible para todo el mundo (pero con un directorio / ruta adecuadamente obscuro), y entréguelo a MediaPlayer
través de setDataSource()
. Mientras se reproduce, puede descargar / descifrar y configurar una segunda instancia de MediaPlayer
, que comienza la reproducción tan pronto como finaliza la primera, para una transición tan perfecta como sea posible. Luego, reinicia el primer MediaPlayer
y lo reutiliza con su tercera parte, haciendo ping-pong entre los dos.
Una solución relacionada estaría en el comentario de jleedev. Es casi lo mismo, excepto que proporciona un FileDescriptor
través de un ContentProvider
. Esto tiene una opción para permitirle usar un socket, lo que puede permitirle evitar el archivo temporal. Sin embargo, el ContentProvider
tendrá que ser de acceso público, por lo que el archivo temporal, con un directorio oscuro, podría ser más privado.
Si le preocupa el hecho de que otros procesos puedan leer estas cosas, comprenda que el propio MediaPlayer
(o, más bien, el subsistema OpenCORE) se encuentra en otro proceso. Además, su servidor HTTP propuesto también se puede leer en todo el mundo en el dispositivo. Entonces, la seguridad por oscuridad es su única opción viable si va a dejar que MediaPlayer
haga la decodificación.
AFAIK, el NDK no otorga acceso a OpenCORE, aunque confieso que tiene una experiencia limitada en el NDK, por lo que puedo estar equivocado. Ciertamente hay otros decodificadores de MP3 disponibles ( ffmpeg
/ mplayer
, etc.), aunque no está claro cuán fácilmente se podrían convertir estos en una biblioteca NDK.
Entonces, realmente se reduce a contra quién estás tratando de defenderte. Si está tratando de defenderse contra el usuario, probablemente tendrá que decodificarlo usted mismo, de alguna manera.
Estamos implementando un programa para teléfonos Android que reproduce audio transmitido desde Internet. Esto es aproximadamente lo que hacemos:
- Descarga un formato encriptado personalizado.
- Descifrar para obtener trozos de datos MP3 regulares.
- Decodifique datos MP3 a datos PCM sin procesar en un búfer de memoria.
- Canaliza los datos PCM en bruto a un AudioTrack
Nuestros dispositivos de destino hasta ahora son Droid y Nexus One. Todo funciona muy bien en Nexus One, pero la decodificación de MP3 es demasiado lenta en Droid. La reproducción de audio comienza a saltar si ponemos el Droid bajo carga. No se nos permite decodificar los datos MP3 a la tarjeta SD, pero sé que de todos modos no es nuestro problema.
No escribimos nuestro propio decodificador de MP3, sino que usamos MPADEC ( http://sourceforge.net/projects/mpadec/ ). Es gratis y fue fácil de integrar con nuestro programa. Lo compilamos con el NDK.
Después de un análisis exhaustivo con varias herramientas de creación de perfiles, estamos convencidos de que es este decodificador el que se está quedando atrás.
Aquí están las opciones que estamos pensando:
Encuentra otro decodificador de MP3 que podamos compilar con el Android NDK. Este decodificador de MP3 tendría que estar optimizado para ejecutarse en dispositivos ARM móviles o tal vez usar solo matemáticas de enteros o algunas otras optimizaciones para aumentar el rendimiento.
Debido a que el servicio Android MediaPlayer incorporado llevará URLs, podríamos implementar un pequeño servidor HTTP en nuestro programa y entregar MediaPlayer con los MP3 descifrados. De esa manera podemos aprovechar el decodificador de MP3 incorporado.
Obtenga acceso al decodificador de MP3 incorporado a través del NDK. No sé si esto es posible.
¿Alguien tiene alguna sugerencia sobre qué podemos hacer para acelerar nuestra decodificación de MP3?
- Rob Sz
No he intentado esto, pero creo que puedes darle al reproductor de medios un descriptor de archivo:
public void setDataSource (FileDescriptor fd, long offset, long length)
Tal vez podría escribir el mp3 descifrado en un archivo y reproducirlo usando el descriptor de archivo. Esto podría funcionar incluso para la transmisión, suponiendo que conozca la longitud del archivo antes de tiempo. Si funciona, sería mucho más simple que hacer un servidor web localhost.
Para descifrar un archivo mp3 encriptado antes de reproducirlo. Hay 3 maneras:
1, para usar la api de MediaPlayer:
Después de la versión de Android M:
you can play mp3 data in byte array directly by:
//Read encrypted mp3:
byte[] bytesAudioData = Utils.readFile(path); // or from a url.
final byte[] bytesAudioDataDecrypted = YourUtils.decryptFileToteArray(bytesAudioData);
ByteArrayMediaDataSource bds = new ByteArrayMediaDataSource(bytesAudioDataDecrypted) ;
mediaPlayer.setDataSource(bds);
Antes de la versión M de Android:
//Read encrypted mp3:
byte[] bytesAudioData = Utils.readFile(path); // or from a url.
final byte[] bytesAudioDataDecrypted = YourUtils.decryptFileToteArray(bytesAudioData);
File file =new File(dirofyouraudio.mp3");
FileOutputStream fos = new FileOutputStream(file);
fos.write(bytesAudioDataDecrypted);
Log.d(TAG, "playSound :: file write to temp :: System. nanoTime() ="+System. nanoTime());
fos.close();
FileInputStream fis = new FileInputStream(file);
mediaPlayer.setDataSource(fis.getFD());
2, para la api de AudioTrack si usas:
int minBufferSize = AudioTrack.getMinBufferSize(sampleRate,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT);
AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, minBufferSize,
AudioTrack.MODE_STREAM);
int i = 0;
byte[] tempMinBufferToRead = new byte[minBufferSize];
try {
byte[] bytesAudioData = Utils.readFile( lastRecordedAudiofilePath);
bytesAudioData = yourUtils.decryptYourFileToByteArray(bytesAudioData);
try {
fileInputStremForPlay = new FileInputStream( lastRecordedAudiofilePath);
dataInputStreamForPlay = new DataInputStream(new ByteArrayInputStream(bytesAudioData));
track.play();
while ((i = dataInputStreamForPlay.read(tempMinBufferToRead, 0, minBufferSize)) > -1) {
Log.d(LOG_TAG, "mThreadExitFlag= " + mThreadExitFlag);
if ((mThreadExitFlag == true) || (!audioFilePathInThisThread.equals(lastRecordedAudiofilePath))) {
m_handler.post(new Runnable() {
public void run() {
Log.d(LOG_TAG, "startPlaying: break and reset play button ");
startPlayBtnInToolbar.setEnabled(true);
stopPlayBtnInToolbar.setEnabled(false);
}
});
break;
}
track.write(tempMinBufferToRead, 0, i);
}
Log.d(LOG_TAG, "===== Playing Audio Completed ===== ");
track.stop();
track.release();
dataInputStreamForPlay.close();
fileInputStremForPlay.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
3, Use MediaExtractor, MediaCodec con AudioTrack, puede configurar la fuente de datos con el extractor:
extractor.setDataSource(this.url);
O
extractor.setDataSource(this.Mediadatasource);
ps: la clase ByteArrayMediaDataSource:
import android.annotation.TargetApi;
import android.media.MediaDataSource;
import android.os.Build;
import java.io.IOException;
import android.content.res.AssetFileDescriptor;
import android.media.MediaDataSource;
import android.util.Log;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
@TargetApi(Build.VERSION_CODES.M)
public class ByteArrayMediaDataSource extends MediaDataSource {
private static final String TAG = ByteArrayMediaDataSource.class.getSimpleName();
private byte[] data;
public ByteArrayMediaDataSource(byte []data) {
// assert data != null;
this.data = data;
}
@Override
public int readAt(long position, byte[] buffer, int offset, int size) throws IOException {
if (position >= data.length) {
return -1; // -1 indicates EOF
}
if (position + size > data.length) {
size -= (position + size) - data.length;
}
Log.d(TAG, "MediaDataSource size = "+size);
System.arraycopy(data, (int)position, buffer, offset, size);
return size;
}
@Override
public long getSize() throws IOException {
Log.d(TAG, "MediaDataSource data.length = "+data.length);
return data.length;
}
@Override
public void close() throws IOException {
// Nothing to do here
data =null;
}
}
MAD es una biblioteca de decodificadores de solo aritmética de enteros que parece ser bien considerada.
(¿La decodificación de los datos en la tarjeta SD no lo retrasaría de todos modos?