How to confirm opus encode buffer size? - android

Function opus_encode need frame size as parameter. in api doc it says buffer size is number of samples per channel.
But how to determine which size should i use?
I use opus in android. sample rate 16k, buffer size 1280. when i set frame size to 640 in encode and decode, the length of decoded file is half of raw pcm. when i set to 960, decoded file is 2/3 of raw pcm. but set to 1280, encode will return -1 as arg error.
When i use cool edit to play decoded, it is faster than raw pcm.
there must be something about my parameters.
Is anyone using opus can help me.
Thanks a lot.

Opus encode definition:
opus_int32 opus_encode ( OpusEncoder * st,
const opus_int16 * pcm,
int frame_size,
unsigned char * data,
opus_int32 max_data_bytes )
When you specify frame_size you need to set it to number of samples per one channel available in pcm buffer.
OPUS codec supports stereo and mono signals and corresponding configuration of encoder is channels parameter that you specify when you call opus_encoder_create function.
Also you need to know about supported frame sizes by OPUS codec. It supports frames with: 2.5, 5, 10, 20, 40 or 60 ms of audio data.
One millisecond of audio with 16kHz is 16 samples (16000/1000). So for mono you can specify frame_size set to:
16 * 2.5 = 40 (very rare)
16 * 5 = 80 (rare)
16 * 10 = 160
16 * 20 = 320
16 * 40 = 640
16 * 60 = 960
OPUS codec will not accept another sizes. The best way to deal with buffer size of 1280 samples is to split on four 20ms packets or two 40ms packets.
So you encode two or four packets from one buffer received from buffer.

Related

MediaCodec output bitrate decrees to 10% when update bitrate

I want to compare the difference between "bitrate-mode" of Android MediaCodec, my test workflow is:
Use MediaExtractor to extract H.264 video frames from a mp4 file (a 100 seconds clip from video), it's in 1280*720 size;
Use MediaCodec decoder to decode those video frames;
Render the decoded frame into MediaCodec encoder's input Surface, the output size is 360*640;
Collect encoder output frame size, calculate the output bitrate of every second;
During the test process, I'll change encoder's output bitrate, and see how does it change in different "bitrate-mode", CQ, VBR, and CBR.
My problem is, in VBR and CBR mode, once I change the encoder output bitrate, e.g. from 500 kbps to 600 kbps or 400 kbps, the collected output bitrate decreases into only 50kbps, and never get up again!
I've created a python script to plot the result, the result of CBR is below:
The red line is calculated output bitrate of each second, the blue dots are bitrate update actions, 500 -> 1100 -> 400 -> 1000. We can see that at the first time I update bitrate, it decreases into only about 50 kbps.
Any idea of what happened?
More info:
When I change encoder's output size into 1280*720, the plot is like below:
And here is the source code of my test project: https://github.com/Piasy/MediaCodecRcTest
Please help me, thanks!
Your issue seems to be that you have the variable mCurrentBr in the unit kbps, while the API expects it in the unit bps. You handle this correctly at init:
encodeFormat.setInteger(MediaFormat.KEY_BIT_RATE, mConfig.initBr() * 1000);
mCurrentBr = mConfig.initBr();
But fail to do the same when updating the bitrate:
mParams.putInt(MediaCodec.PARAMETER_KEY_VIDEO_BITRATE, mCurrentBr);
If you add a * 1000 at the second spot, I would expect it to behave much better.

Android SuperPowered SDK Audio - Frequency Domain example - memset frequency manipulation

I'm trying to understand the Superpowered SDK, but new to both Android and C++, as well as audio signals. I have Frequency Domain example from here:
https://github.com/superpoweredSDK/Low-Latency-Android-Audio-iOS-Audio-Engine/tree/master/Examples_Android/FrequencyDomain
running on my Nexus 5X. In the FrequencyDomain.cpp file:
static SuperpoweredFrequencyDomain *frequencyDomain;
static float *magnitudeLeft, *magnitudeRight, *phaseLeft, *phaseRight, *fifoOutput, *inputBufferFloat;
static int fifoOutputFirstSample, fifoOutputLastSample, stepSize, fifoCapacity;
#define FFT_LOG_SIZE 11 // 2^11 = 2048
static bool audioProcessing(void * __unused clientdata, short int *audioInputOutput, int numberOfSamples, int __unused samplerate) {
SuperpoweredShortIntToFloat(audioInputOutput, inputBufferFloat, (unsigned int)numberOfSamples); // Converting the 16-bit integer samples to 32-bit floating point.
frequencyDomain->addInput(inputBufferFloat, numberOfSamples); // Input goes to the frequency domain.
// In the frequency domain we are working with 1024 magnitudes and phases for every channel (left, right), if the fft size is 2048.
while (frequencyDomain->timeDomainToFrequencyDomain(magnitudeLeft, magnitudeRight, phaseLeft, phaseRight)) {
// You can work with frequency domain data from this point.
// This is just a quick example: we remove the magnitude of the first 20 bins, meaning total bass cut between 0-430 Hz.
memset(magnitudeLeft, 0, 80);
memset(magnitudeRight, 0, 80);
I understand how the first 20 bins is 0-430 Hz from here:
How do I obtain the frequencies of each value in an FFT?
but I don't understand the value of 80 in memset... being 4*20, is it 4 bytes for a float * 20 bins? Does magnitudeLeft hold data for all the frequencies? How would I then remove, for example, 10 bins of frequencies from the middle or the highest from the end? Thank you!
Every value in magnitudeLeft and magnitudeRight is a float, which is 32-bits, 4 bytes.
memset takes a number of bytes parameter, so 20 bins * 4 bytes = 80 bytes.
memset clears the first 20 bins this way.
Both magnitudeLeft and magnitudeRight represents the full frequency range with 1024 floats. Their size is always FFT size divided by two, so 2048 / 2 in the example.
Removing from the middle and the top looks something like:
memset(&magnitudeLeft[index_of_first_bin_to_remove], 0, number_of_bins * sizeof(float));
Note that the first parameter is not multiplied with sizeof(float), because the compiler knows that magnitudeLeft is a float, so it will automatically input the correct address.

How to record a pcm mp4 with FFmpegFrameRecorder on Android?

How can i get a pcm mp4 with FFmpegFrameRecorder?I see it suppout pcm format.I try like below:
mFrameRecorder = new FFmpegFrameRecorder(mVideo, videoWidth, videoHeight, 1);
mFrameRecorder.setFormat("mp4");
mFrameRecorder.setSampleRate(sampleAudioRateInHz);
mFrameRecorder.setFrameRate(frameRate);
// Use H264
mFrameRecorder.setVideoCodec(avcodec.AV_CODEC_ID_MPEG4);
mFrameRecorder.setAudioCodec(avcodec.AV_CODEC_ID_PCM_S16LE);
// See: https://trac.ffmpeg.org/wiki/Encode/H.264#crf
/*
* The range of the quantizer scale is 0-51: where 0 is lossless, 23 is default, and 51 is worst possible. A lower value is a higher quality and a subjectively sane range is 18-28. Consider 18 to be visually lossless or nearly so: it should look the same or nearly the same as the input but it isn't technically lossless.
* The range is exponential, so increasing the CRF value +6 is roughly half the bitrate while -6 is roughly twice the bitrate. General usage is to choose the highest CRF value that still provides an acceptable quality. If the output looks good, then try a higher value and if it looks bad then choose a lower value.
*/
mFrameRecorder.setVideoOption("crf", "28");
mFrameRecorder.setVideoOption("preset", "superfast");
mFrameRecorder.setVideoOption("tune", "zerolatency");
but it crashed with error msg :
library "/system/lib/libdl.so" ("/system/lib/libdl.so") needed or dlopened by "/system/lib/libnativeloader.so" is not accessible for the namespace: [name="classloader-namespace", ld_library_paths="", default_library_paths="/data/app/com.github.crazyorr.ffmpegrecorder-2/lib/arm:/data/app/com.github.crazyorr.ffmpegrecorder-2/base.apk!/lib/armeabi", permitted_paths="/data:/mnt/expand:/data/data/com.github.crazyorr.ffmpegrecorder"]

getMinBufferSize() when recording more than 1 sec with AudioRecord

I´m a bit confused using getMinBufferSize() and AudioRecord.read() while recording from the MIC of the phone.
I understand that getMinBufferSize() gives you the minimun amount of bytes required to create the audiorecord object (in 1 sec?).
bufferSize= AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE,
RECORDER_CHANNELS,
RECORDER_AUDIO_ENCODING);
Then, when they call AudioRecord.read(), they have as an argument for the size of the bytes read "bufferSize".
read = recorder.read(data, 0, bufferSize);
Here are my questions:
1- Why bufferSize returns me 8192? I guess it´s making 8*1024 but I would like to know exactly what is the calculation that it is making (I´m using 8000 Hz sample rate, channel MONO and 16-bit PCM)
2- I suppose that bufferSize is the amount of data that I can store in 1 sec of duration but, what if I want to read more than 1 sec? Should I multiply this value to the number of seconds?
I guess you have a size of an array 8192
Since you encode your file in 16bit-PCM, the array size will be 16bit * 8192 which is around 130000
data capacity made in a second is 128000 ( = 8000 * 1 * 16)
so it becomes your min buffer size

Buffer calculation in AudioHardwareALSA::getInputBufferSize(...)

I'm looking at getInputBufferSize(...) function in AudioHardwareALSA.cpp and it returns hardcoded the value of 320. My question is: How is this value calculated?
I've done some pre-cals but still there are some questions.
sample_rate = 8000
format = S16_LE = 2 bytes/sample
period_time = 10000 us (guessing)
buffer_size = 2 * period_size
period_size = period_time * bytes/sec
buffer_size = 2 * (0.01 * sample_rate * 2) = 320 bytes.
I can't find the period_time in the code, so one question is: where is it defined or is just a rough calculation?
I'm also trying to add some more sample rates i.e 16000 and 32000 (later maybe more). How to calculate the right minimum buffer size? Is the delay always 10 ms for all the sample rates?
Any help is appreciated.
I believe Google implemented NB-AMR encode to start with. later they added support for AAC. In the case of NB-AMR, the frame size is 320 bytes.
You may be aware that for NB-AMR:
sampling rate = 8000 samples / sec
frame duration = 20ms
sample size = 2 bytes
channels = mono
So, each frame contains
8000 samples / sec * 0.02 sec * 2 bytes / sample / channel * 1 channels = 320 bytes
For AAC, these parameters are different and hence the framesize

Categories

Resources