[FFmpeg-user] Correct way to use FFmpeg filters in a real time context
Ronak
ronak2121 at yahoo.com
Thu Jan 31 01:49:25 EET 2019
Hi all,
I'm trying to embed some ffmpeg filters, such as loudnorm and silenceremove in a real time context: meaning I have an audio speaker connected at the end of it.
I saw that loudnorm supports single pass mode; where it doesn't require me to pass all the audio in the file through it, before it can start normalizing to a given LUFS value.
I also saw silenceremove is also similar.
However, what I can't seem to figure out is that if I just plug in those filters into my filter chain during playback, I hear a bunch of silence, audio artifacts and random noise, rather than my audio.
I'm thinking this might be an issue due to how I'm inputting data into those filters perhaps?
Here's the code I use to push data into my filter chain. This is code in the Swift language on iOS. Would someone be able to help look over this code and give me any pointers on what I'm doing wrong?
Thanks,
Ronak
private func filterBuffer(_ inputBufferList: UnsafeMutableAudioBufferListPointer, frameCount: UInt32, outputBufferList: UnsafeMutableAudioBufferListPointer) throws -> UInt32 {
guard let inputAudioFrame = inputAudioFrame, let outputAudioFrame = outputAudioFrame else { throw PlayerError.filterFailure([:]) }
// copy the pointers to the audio buffer into the frame for manipulation
// each buffer represents the audio per channel. copy data from the inputBuffer into the input frame.
for index in 0..<inputBufferList.count {
let bufferSize = Int(inputBufferList[index].mDataByteSize)
let buffer = inputBufferList[index].mData?.bindMemory(to: UInt8.self, capacity: bufferSize)
inputAudioFrame.pointee.nb_samples = Int32(frameCount)
inputAudioFrame.pointee.extended_data[index] = buffer
inputAudioFrame.pointee.linesize.0 = Int32(bufferSize)
}
// write the audio frame into the audioInputContext so it can be filtered
let writeResult = av_buffersrc_write_frame(audioInputContext, inputAudioFrame)
if writeResult == 0 {
// pull the filtered audio out of the audioOutputContext
let pullResult = av_buffersink_get_frame(audioOutputContext, outputAudioFrame)
// if we were able to read the filtered audio without any issue, lets use it
if pullResult >= 0 {
// copy the pointers to the filtered audio into the output buffers
for index in 0..<outputBufferList.count {
outputBufferList[index].mData = UnsafeMutableRawPointer(outputAudioFrame.pointee.extended_data[index])
outputBufferList[index].mDataByteSize = UInt32(outputAudioFrame.pointee.linesize.0)
outputBufferList[index].mNumberChannels = 1
}
return UInt32(outputAudioFrame.pointee.nb_samples)
} else if pullResult == -EAGAIN {
// if the result was -EAGAIN, it means we need to write additional data into the filter graph to pull data out of it..
return UInt32(outputAudioFrame.pointee.nb_samples)
} else {
let rawErrorString = UnsafeMutablePointer<Int8>.allocate(capacity: 64)
av_make_error_string(rawErrorString, 64, pullResult)
ARCLogError("Failed to read audio out of the filter due to error code: \(pullResult): \(String(cString: rawErrorString))")
// the audio couldn't be filtered properly, throw an error
throw PlayerError.filterFailure([:])
}
} else {
let rawErrorString = UnsafeMutablePointer<Int8>.allocate(capacity: 64)
av_make_error_string(rawErrorString, 64, writeResult)
ARCLogError("Failed to write audio into the filter due to error code: \(writeResult): \(String(cString: rawErrorString))")
// the audio couldn't be filtered properly, throw an error
throw PlayerError.filterFailure([:])
}
More information about the ffmpeg-user
mailing list