Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix an issue in Audio transcoding where target-sample-rate is less than the source-sample-rate #111

Merged

Conversation

Ma7moudHatem
Copy link
Contributor

Fix an issue in Audio transcoding, where the target sample-rate is less than the source sample-rate, so here we need to do a down-sampling, and I found this fix by another third party, but I did some changes.

…less than the source sample-rate, so here we need to do a down-sampling, and I found this fix by another third party, but I did some changes.
*/
void renderFrame(@Nullable Frame frame, long presentationTimeNs);
void renderFrame(@Nullable Frame inputFrame, long presentationTimeNs, MediaFormat sourceMediaFormat,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have to break a public API? Source and target formats are passed in init method, can't we just hold on to them in the renderer? They don't usually change during transcoding.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we don't need to break the renderFrame() method, but yes, they change after init method, so I'll add a new method onMediaFormatChanged() to Renderer interface, and will call it each time the MediaCodec.INFO_OUTPUT_FORMAT_CHANGED is returned

public void resample(@NonNull ByteBuffer inputBuffer, int inputSampleRate, @NonNull ByteBuffer outputBuffer,
int outputSampleRate, int channels) {
super.resample(inputBuffer, inputSampleRate, outputBuffer, outputSampleRate, channels);
// TODO currently up-sampling not supported because it's need some enhancements, so fallback to PASSTHROUGH approach
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably don't want to do this here. I think we can remove this entire class for now and bring it in later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

/**
* An {@link AudioResampler} that downsamples from a higher sample rate to a lower sample rate.
*/
public class DownsampleAudioResampler implements AudioResampler {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this adapted code from a different open source project? In that case we have to keep their copyright notice and add a note that we made modifications (feel free to add your name as author of modifications)

* @param outputSampleRate the output sample rate
* @param channels the number of channels
*/
void resample(@NonNull final ByteBuffer inputBuffer, int inputSampleRate, @NonNull final ByteBuffer outputBuffer, int outputSampleRate, int channels);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, factory pattern would work better here to create correct resampler implementation for given source/target formats. We would need instantiate only one class.

* Resamples audio data. See {@link UpsampleAudioResampler} or
* {@link DownsampleAudioResampler} for concrete implementations.
*/
public interface AudioResampler {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For all new classes that are not modified classes from other project please add LinkedIn copyright notice

- Add a copyright notice fot new classes
- Changed the logic of getting an updated sourceMediaFormat and targetAudioFormat
private final AudioResampler audioResampler = new DefaultAudioResampler();

@VisibleForTesting
static int getSampleRate(MediaFormat format) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this static?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed to non-static method

}

@VisibleForTesting
static int getChannels(MediaFormat format) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed from here

* @param outputSampleRate the output sample rate
* @param channels the number of channels
*/
void resample(@NonNull final ByteBuffer inputBuffer, int inputSampleRate, @NonNull final ByteBuffer outputBuffer, int outputSampleRate, int channels);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be more flexible to pass MediaFormat for source and target. Resampler implementation would know how to extract information it needs from it. And we would not need to change method signature (breaking change) if we needed to pass in more parameters than we do now.

*/
void resample(@NonNull final ByteBuffer inputBuffer, int inputSampleRate, @NonNull final ByteBuffer outputBuffer, int outputSampleRate, int channels);

AudioResampler DOWNSAMPLE = new DownsampleAudioResampler();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interface being aware of two of its implementations does not sounds right. We should use factory pattern to instantiate a correct resampler implementation in onMediaFormatChanged method. By default, it should be PassthroughResampler, of course.


@Override
public void resample(@NonNull ByteBuffer inputBuffer, int inputSampleRate, @NonNull ByteBuffer outputBuffer, int outputSampleRate, int channels) {
if (inputSampleRate > outputSampleRate) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic can move into onMediaFormatChanged method. That way we would remove this entire class and only one instance of resampler would be created. This would also remove those two constants with implementations from AudioResampler interface.

*/
public class DownsampleAudioResampler implements AudioResampler {

private static float ratio(int remaining, int all) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this was original static and got copied there? Can we make this not static?

@@ -42,8 +50,35 @@ public PassthroughSoftwareRenderer(@NonNull Encoder encoder, long frameWaitTimeo
this.frameWaitTimeoutUs = frameWaitTimeoutUs;
}

private int getSampleRate(MediaFormat format) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not anymore

if (sourceAudioFormat == null || targetAudioFormat == null) {
return;
}
int inputSampleRate = getSampleRate(sourceAudioFormat);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we use AudioResampler method here? It seems to be doing the same thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@izzytwosheds izzytwosheds merged commit cfb9cb8 into linkedin:main Apr 2, 2021
@Ma7moudHatem Ma7moudHatem deleted the fix-audio-transcoding-issue branch April 3, 2021 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants