Decoding only some PCM bytes at a time from an mp3 file - android

How do I decode something on the order of a 1000 bytes of PCM audio from an mp3 file, without decoding the whole thing?
I need to mix together four to six tracks, to one, so that they're played simultaneously on an AudioTrack in the Android app.
This can be done if I can get a stream of PCM samples, and so simple add the decoded tracks together (and maybe adjust for clipping and volume), and then write them to an AudioTrack buffer.
That part is simple.
But how do I decode the individual mp3 files, to inputstreams I can get byte arrays from? I've found something called JLayer, but its not quite clear to me how to do this.
I'd rather avoid doing it in C++ (I'm a bit rusty, and my team doesn't like it), though if that's needed I can do it. Though I'd need a short example of how get say 240 decoded bytes from a file via mpg123, or other such libraries.
Any help is appreciated.

The smallest you can do is 576 samples, which is the smallest MP3 frame size. However, most MP3 streams use the bit reservoir meaning you likely have to decode frames around the frame you want to decode as well.
Complicating things further, bare MP3 streams don't have any internal timestamping, so if you want to drop accurately in the middle of a file, you have to decode up until that point. (MP3 frame headers don't contain byte lengths, so you can't just skim frame headers accurately.) You can try to needle-drop into the middle of the file based on byte length, but this isn't an accurate way of seeking and can be off by several seconds, even for CBR. For VBR, it's all over the place.
It sounds like all you need to do is have a stream decoder, so that the decoding happens as playback is occurring. I'm no Android developer, but it seems you can just use AudioTrack from the framework, in streaming mode. https://developer.android.com/reference/android/media/AudioTrack.html And then the MediaCodec to actually do the decoding. https://developer.android.com/reference/android/media/MediaCodec.html Android devices support MP3, so you don't need to do anything else.

Related

How to loop an audio file in android without any delay?

I have started a android.media.MediaPlayer file with:
mp1.start()
and then trying the looping with:
setLooping(true);
but this is ending up with a delay in playing the file again.
I am trying to run an mp3 file containing a rhythm with a set tempo. Is there any better way of looping it in such a manner that the tempo timing does not get disturbed and the rhythm plays seamlessly without any stutter/delay?
Should I use SoundPool instead?
Most of best practices for this particular case recommend using .ogg format. You can convert you file easily using VNC media player.
Wiki for .ogg file format - http://en.wikipedia.org/wiki/.ogg
Another solution is the SoundPool and the third one - is to use Audacity and cut the quiet/“blanksound” from you audio file.
If your audio is not long, then use SoundPool for low-latency media playback, instead of MediaPlayer. Also convert it to ogg, as others have already pointed it out.
Edit: if it is just a tempo, and not a continous sound, then maybe you can also measure the latency and seek your audio based on that, but I am not sure you will get better results this way.
Mediaplayer solutions:
If you insist on using MediaPlayer, then you can:
either crop the sound at the end of your audio files, so there's no sound gap between two playback loops
or create a custom solution yourself as the one described here.
Soundpool alternative:
Now, from my personal experience, if you want to loop files small in size and duration, not more than 1MB, then Soundpool is more convenient and it seems that not any relevant problems are reported in contrary to the MediaPlayer. There have been many complaints when trying to loop sounds using MediaPlayer, so generally Soundpool is usually preferred for looping.
Soundpool size limit:
If you are concerned about Sounpool's size limit, keep in mind that it has 1Mb buffer size limit per track. But this limit applies not to file size but to decompressed raw PCM data. SoundPool is going to decompress the loaded audio to PCM data so it is ready to play instantly without the latency of decoding. If the audio you are loading is compressed heavily, such as MP3, then that can get blown up quite a bit.
Improve performance:
Also, as suggested in another answer, files of type ".ogg" according to many sources appear to perform better than ".mp3" in general. So, you should try to convert your files for better performance, but I don't think you will see an improvement concerning looping.
To convert your files you can use an online tool such as this. If you convert your files remember to also make these changes:
Change your sound file's sampling rate to 16000 Hz
Change your audio channel to mono, instead of stereo.
Make sure your file after these processes is smaller than 1 mb in size.
Please try to do it this way.
audio = MediaPlayer.create(this, R.raw.pl);
audio.setLooping(true);
audio.start();

Trim aac-mp4 audio in android (mediaCodec/extractor)

I want to trim an existing aac-mp4 audio file. For the first time I want to "trim" 0 bytes, basically just to copy the file using MediaCodec/MediaExtractor.
Questions:
The header is fixed size and I can just copy it from the old file? Or it has some infos about the track duration and I need to update it? If it has fixed size which is that (in order to know how many bytes should I copy from the old file)?
Should I only use the extractor's getSampleData(ByteBuffer, offset) and advance() or I should also use the MediaCodec and extract the samples(decode) and then encode them again with an encoder - and write the encoded values?
If you use MediaExtractor, you probably aren't going to read the raw file yourself, so I don't see what header you're proposing to copy. This is probably easiest to do with MediaExtractor + MediaMuxer; just copy the MediaFormat and the packets you get from MediaExtractor to MediaMuxer.
This depends on how you want to do the trimming. It's absolutely simplest to not involve MediaCodec at all, but just copy packets from MediaExtractor to MediaMuxer, and skip the packets at the start that you want to omit (or use seekTo() for seeking to the right start position).
But keep in mind that audio frames have a certain length; for AAC-LC it's usually 1024 samples, which for 48 kHz audio is 21 milliseconds. So if you only copy individual packets, you can't get any closer trimming granularity than 21 milliseconds, for 48 kHz. This probably is fine for most cases, but if the audio has a lower sample rate, say 8 kHZ, the granularity ends up as high as 128 ms.
If you want to trim to a more exact position than the individual packets allow you, you need to decode using MediaCodec, skip the right amount of samples, repackage output frames from the decoder into new full frames for the encoder, and encode this.

Transcode video to lower bitrate and stream

I have a working app that streams video to Chromecast(using nannoHttpd) and everything is working fine. Now my problem is: videos recorded using new devices are too large in size to stream, so I want to re-encode videos to some lower bitrate.
I tried ffmpeg but the results are not satisfactory and it will increase the apk size by 14 MB.
Now I am trying the MediaCodec api. It is faster than ffmpeg, but it takes the input file and writes it to the output file and I want to re-encode byte data that is to be served by nannohttpd.
Now a solution comes to my mind, that is to transcode the video and stream the output file but its has two drawbacks;
What if the file is too large and the user doesn't see the whole video? Much of CPU, battery resource is wasted.
What if the user fast forwards a long video to a time which is not re-encoded yet?
1 MediaCodec just do one thing decode encode! and you will get raw bytes of new encoded data. So it is up to the programmer to choose to either dump that into a container (.mp4 file) using a muxer. So no need here to rewrite everything back into a file.
2 Seek to the proper chunk of data and restart MediaCodec.

Drawing an audio waveform from a decoded sound file in Android

I'm trying to draw a custom waveform view from a decoded audio file. The problem is that when I use the MediaCodec class to decode an m4a sound file to pcm, the decoding process may take a long time.
I followed this CTS test to get the decoded array.
Is there any way to minimize the decoding process or to get relevant information about the audio file frames without decoding the whole file each time.
You don't need to wait for the whole file to be decoded, you can use the decoded data from each frame once it is available.
In the CTS test you linked, have a look at lines 223-234 - here a buffer of decoded data has been received from the decoder, which is copied into an output buffer. If you change this to do the processing of the data right there, you can do your handling of the decoded data immediately without waiting for the whole file. (This is how playback of a file would be done as well.)
Keep in mind that you can't really assume the size of the output frames, it depends on the frame size of the codec used in the file. (For the most common versions of AAC, it is 1024 samples.) So depending on how you want to process your output data, you might want to buffer it up into slightly larger chunks if necessary.

3GP/AMR mix/merge tracks

Is there an easy way to merge 2 3gp (amr) audio files into a single audio file?
I need them to be synchronous/over top of each other not one after the other. I am using android to do this. I have heard somewhere that for some audio formats you can simply add the bytes (being careful that you dont get a too high or too low result). Is this true with the 3gp/amr format on android?
Android only allows playback/recording of 3GP/AMR files. To mix audio you will need the decoded PCM data. This means you have to decode both streams mix (this is indeed adding + normalizing) and then playback.
The bad side - there no way to get access to the build in AMR decoder which allows you to decode without playback.
So ... no easy way.

Categories

Resources