Reputation: 5975
I'm trying decode an audio file into PCM to use with AudioTrack. The audio is squeeky, squelchy, and just plain jibberish and for a random second sounds like it should but mainly is completely muddled. I'm not sure where my mistake is, is it in how the array is passed back to playSound?
Thank you in advance, I would really appreciate help on this matter as it's been kicking my ass for a while.
This is my java code:
public void init() {
int bufSize = AudioTrack.getMinBufferSize(44100,
AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT);
track = new AudioTrack(AudioManager.STREAM_MUSIC,
44100,
AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT,
bufSize,
AudioTrack.MODE_STREAM);
log("STARTING!!! _________________________ <--");
byte[] array = new byte[bufSize];
try {
fos = new FileOutputStream("/sdcard/acdc.bin");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
decoder("/sdcard/acdc.ogg", array);
}
void playSound(byte[] buf, int size) {
try {
fos.write(buf, 0, size);
} catch (IOException e) {
e.printStackTrace();
}
if(track.getPlayState()!=AudioTrack.PLAYSTATE_PLAYING) {
track.play();
}
int wrote = track.write(buf, 0, size);
if (wrote != size)
log("WRITING: " + wrote + " but size was: " + size);
}
This is my c function:
void Java_com_example_ffmpegsample_MainActivity_decoder(JNIEnv* env, jobject obj,jstring file,jbyteArray array)
{
jboolean isfilenameCopy;
const char * filename = (*env)->GetStringUTFChars(env, file, &isfilenameCopy);
AVCodec *codec;
AVCodecContext *c= NULL;
AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx;
int out_size, len;
FILE *f, *outfile;
uint8_t *outbuf;
uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
AVPacket avpkt;
LOGI("HERE");
jclass cls = (*env)->GetObjectClass(env, obj);
LOGI(cls);
jmethodID play = (*env)->GetMethodID(env, cls, "playSound", "([BI)V");//At the begining of your main function
av_init_packet(&avpkt);
av_register_all();
LOGI("AUDIO DECODER");
printf("Audio decoding\n");
int err;
err = av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL);
if (err!=0) {
LOGI("COULD NOT AV_OPEN file");
return;
}
if(av_find_stream_info(pFormatCtx)<0) {
LOGE("Unable to get stream info");
return;
}
int audioStream = -1;
int i;
for (i=0; i<pFormatCtx->nb_streams; i++) {
if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO) {
audioStream = i;
break;
}
}
if(audioStream==-1) {
LOGE("Unable to find audio stream");
return;
}
LOGI("Audio stream is [%d]", audioStream);
pCodecCtx=pFormatCtx->streams[audioStream]->codec;
codec = avcodec_find_decoder(pCodecCtx->codec_id);
/* find the mpeg audio decoder */
// codec = avcodec_find_decoder(CODEC_ID_AAC);
if (!codec) {
LOGI("NO CODEC");
fprintf(stderr, "codec not found\n");
return;
}
//c= avcodec_alloc_context();
c = pCodecCtx;
/* open it */
if (avcodec_open(c, codec) < 0) {
fprintf(stderr, "could not open codec\n");
LOGI("NOT LOADING CODEC");
return;
}
outbuf = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "could not open %s\n", filename);
LOGI("COULD NOT OPEN FILE");
return;
}
/* decode until eof */
avpkt.data = inbuf;
avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
while (avpkt.size > 0) {
LOGI("............................." + avpkt.size);
out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
len = avcodec_decode_audio3(c, (short *)outbuf, &out_size, &avpkt);
if (len < 0) {
fprintf(stderr, "Error while decoding\n");
LOGI("ERROR DECODING, error: %d", len);
return;
}
if (out_size > 0) {
/* if a frame has been decoded, output it */
jbyte *bytes = (*env)->GetByteArrayElements(env, array, NULL);
memcpy(bytes, outbuf, out_size); //
(*env)->ReleaseByteArrayElements(env, array, bytes, 0);
(*env)->CallVoidMethod(env, obj, play, array, out_size);
}
avpkt.size -= len;
avpkt.data += len;
if (avpkt.size < AUDIO_REFILL_THRESH) {
/* Refill the input buffer, to avoid trying to decode
* incomplete frames. Instead of this, one could also use
* a parser, or use a proper container format through
* libavformat. */
memmove(inbuf, avpkt.data, avpkt.size);
avpkt.data = inbuf;
len = fread(avpkt.data + avpkt.size, 1,
AUDIO_INBUF_SIZE - avpkt.size, f);
if (len > 0)
avpkt.size += len;
}
}
fclose(f);
free(outbuf);
avcodec_close(c);
av_free(c);
}
Upvotes: 0
Views: 465
Reputation: 2520
You create an AudioTrack in Streaming mode with a min size buffer. It may be that if it is converting some data, then writing some data that gaps are happening in the audio playback. This would be especially true if the conversion has to keep reading from the SDcard. You could increase the size of the AudioTrack buffer to see if this is a factor.
Also, I'm not sure but I think avcodec_decode_audio3 may set &out_size as size in shorts, but this is then sent to AudioTrack as size in bytes.(No just checked API and its bytes).
Upvotes: 1
Reputation: 6289
have u tried using plain CLI interface in android like this project? You could use a simple fileProcesssor interface: IN=ogg OUT=raw-pcm
see below on CLI for conversion of .ogg to PCM format. Then do whatever with the output
rob@ Downloads$ ffmpeg -i Example.ogg -f s16le -acodec pcm_s16le output.raw
ffmpeg version N-35901-g27a3415 Copyright (c) 2000-2012 the FFmpeg developers
built on Oct 7 2012 12:06:43 with gcc 4.6 (Ubuntu/Linaro 4.6.3-1ubuntu5)
configuration: --enable-gpl --enable-libfaac --enable-libfdk-aac --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-librtmp --enable-libtheora --enable-libvorbis --enable-libvpx --enable-x11grab --enable-libx264 --enable-nonfree --enable-version3
libavutil 51. 73.102 / 51. 73.102
libavcodec 54. 64.100 / 54. 64.100
libavformat 54. 29.105 / 54. 29.105
libavdevice 54. 3.100 / 54. 3.100
libavfilter 3. 19.102 / 3. 19.102
libswscale 2. 1.101 / 2. 1.101
libswresample 0. 16.100 / 0. 16.100
libpostproc 52. 1.100 / 52. 1.100
[NULL @ 0x186b840] Invalid packet
Input #0, ogg, from 'Example.ogg':
Duration: 00:00:06.10, start: 0.000000, bitrate: 137 kb/s
Stream #0:0: Audio: vorbis, 44100 Hz, stereo, s16, 160 kb/s
Output #0, s16le, to 'output.raw':
Metadata:
encoder : Lavf54.29.105
Stream #0:0: Audio: pcm_s16le, 44100 Hz, stereo, s16, 1411 kb/s
Stream mapping:
Stream #0:0 -> #0:0 (vorbis -> pcm_s16le)
Press [q] to stop, [?] for help
size= 1054kB time=00:00:06.11 bitrate=1411.2kbits/s
video:0kB audio:1054kB subtitle:0 global headers:0kB muxing overhead 0.000000%
This assumes you can config/make ffmpeg for android with OGG LIB dependencies , which may be a tricky process...
Upvotes: 1