Of course! Using Java to work with AMR audio files via FFmpeg is a common requirement, especially for mobile applications (AMR was widely used for voice recordings on older phones).

Here’s a comprehensive guide covering the "why," "how," and practical code examples.
Why Use AMR and FFmpeg with Java?
- AMR (Adaptive Multi-Rate): An audio codec optimized for speech. It's highly compressed and was the standard for MMS (Multimedia Messaging Service) and voice recordings on many mobile networks and older phones (like pre-smartphone Nokias).
- FFmpeg: The ultimate Swiss Army knife for multimedia. It can decode, encode, transcode, stream, and play almost any audio/video format. It's the perfect tool to handle AMR, as the standard Java Sound API has very limited or no support for it.
- Java: Provides the platform and logic to orchestrate the process, whether it's a web server processing uploads, a desktop app, or an Android service.
Core Concepts: FFmpeg vs. Java
It's crucial to understand the division of labor:
-
Java's Role:
- Manage the application flow.
- Handle file I/O (reading/writing files).
- Construct the FFmpeg command.
- Execute the FFmpeg process.
- Process the output (e.g., get duration, handle errors).
-
FFmpeg's Role:
(图片来源网络,侵删)- Perform the actual audio processing (decoding, encoding, conversion).
- This offloads the heavy lifting and complex codec logic from your Java code.
Step-by-Step Guide with Code Examples
We'll cover the most common tasks: decoding AMR to WAV and encoding WAV to AMR.
Step 1: Get FFmpeg
You need the ffmpeg executable on your system.
- Windows: Download from the official FFmpeg website. Add the
bindirectory to your system'sPATHenvironment variable. - Linux (Debian/Ubuntu):
sudo apt-get update && sudo apt-get install ffmpeg - macOS (with Homebrew):
brew install ffmpeg
Step 2: Java Project Setup
You don't need any special Java libraries for the basic execution. We'll use standard Java classes.
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
public class AmrConverter {
public static void main(String[] args) {
// Define file paths
File amrFile = new File("input.amr");
File wavFile = new File("output.wav");
File amrOutputFile = new File("output_from_wav.amr");
// --- Example 1: Decode AMR to WAV ---
System.out.println("Decoding AMR to WAV...");
boolean decodeSuccess = decodeAmrToWav(amrFile, wavFile);
System.out.println("Decoding " + (decodeSuccess ? "successful" : "failed"));
// --- Example 2: Encode WAV to AMR ---
System.out.println("\nEncoding WAV to AMR...");
boolean encodeSuccess = encodeWavToAmr(wavFile, amrOutputFile);
System.out.println("Encoding " + (encodeSuccess ? "successful" : "failed"));
}
// ... methods will go here ...
}
Step 3: The Conversion Methods (Java + FFmpeg)
We'll create methods to build and execute the FFmpeg commands.

Method 1: Decode AMR to WAV
This command tells FFmpeg to read the input.amr file and save it as a output.wav file.
/**
* Decodes an AMR file to a WAV file using FFmpeg.
*
* @param amrFile The input AMR file.
* @param wavFile The output WAV file.
* @return true if conversion was successful, false otherwise.
*/
public static boolean decodeAmrToWav(File amrFile, File wavFile) {
// The command: ffmpeg -i input.amr -ar 8000 output.wav
// -i: input file
// -ar 8000: Set audio sampling rate to 8000 Hz (standard for AMR)
String[] command = {
"ffmpeg",
"-i", amrFile.getAbsolutePath(),
"-ar", "8000",
wavFile.getAbsolutePath()
};
return executeCommand(command, "Decoding AMR to WAV");
}
Method 2: Encode WAV to AMR
This command tells FFmpeg to read the input.wav file and save it as an output.amr file using the AMR-NB codec.
/**
* Encodes a WAV file to an AMR file using FFmpeg.
*
* @param wavFile The input WAV file.
* @param amrFile The output AMR file.
* @return true if conversion was successful, false otherwise.
*/
public static boolean encodeWavToAmr(File wavFile, File amrFile) {
// The command: ffmpeg -i input.wav -c:a libamr_nb -b:a 12200 output.amr
// -i: input file
// -c:a libamr_nb: Use the AMR-NB audio codec
// -b:a 12200: Set audio bitrate to 12.2 kbps (one of the standard AMR rates)
String[] command = {
"ffmpeg",
"-i", wavFile.getAbsolutePath(),
"-c:a", "libamr_nb",
"-b:a", "12200",
amrFile.getAbsolutePath()
};
return executeCommand(command, "Encoding WAV to AMR");
}
Method 3: The Command Executor (Helper Method)
This is the core logic that runs the FFmpeg process and captures its output. It's vital for checking for errors.
/**
* Executes a command-line process and streams the output.
*
* @param command The command and its arguments.
* @param taskDescription A description of the task for logging purposes.
* @return true if the process exits with code 0, false otherwise.
*/
private static boolean executeCommand(String[] command, String taskDescription) {
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.redirectErrorStream(true); // Merge stderr into stdout
try {
Process process = processBuilder.start();
// Read the output (and error) stream
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println("[FFmpeg] " + line);
}
}
// Wait for the process to finish
int exitCode = process.waitFor();
if (exitCode == 0) {
System.out.println(taskDescription + " completed successfully.");
return true;
} else {
System.err.println(taskDescription + " failed with exit code: " + exitCode);
return false;
}
} catch (IOException | InterruptedException e) {
System.err.println("Error executing FFmpeg command: " + e.getMessage());
Thread.currentThread().interrupt(); // Restore the interrupted status
return false;
}
}
Complete Runnable Example
Here is the full, self-contained Java file. Just save it as AmrConverter.java, place an input.amr file in the same directory, and run it.
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
public class AmrConverter {
public static void main(String[] args) {
// Define file paths
File amrFile = new File("input.amr");
File wavFile = new File("output.wav");
File amrOutputFile = new File("output_from_wav.amr");
if (!amrFile.exists()) {
System.err.println("Error: 'input.amr' not found. Please create it.");
return;
}
// --- Example 1: Decode AMR to WAV ---
System.out.println("Decoding AMR to WAV...");
boolean decodeSuccess = decodeAmrToWav(amrFile, wavFile);
System.out.println("Decoding " + (decodeSuccess ? "successful" : "failed"));
if (decodeSuccess && wavFile.exists()) {
// --- Example 2: Encode WAV to AMR ---
System.out.println("\nEncoding WAV to AMR...");
boolean encodeSuccess = encodeWavToAmr(wavFile, amrOutputFile);
System.out.println("Encoding " + (encodeSuccess ? "successful" : "failed"));
}
}
/**
* Decodes an AMR file to a WAV file using FFmpeg.
*
* @param amrFile The input AMR file.
* @param wavFile The output WAV file.
* @return true if conversion was successful, false otherwise.
*/
public static boolean decodeAmrToWav(File amrFile, File wavFile) {
String[] command = {
"ffmpeg",
"-i", amrFile.getAbsolutePath(),
"-ar", "8000", // Set sample rate to 8kHz, standard for AMR
wavFile.getAbsolutePath()
};
return executeCommand(command, "Decoding AMR to WAV");
}
/**
* Encodes a WAV file to an AMR file using FFmpeg.
*
* @param wavFile The input WAV file.
* @param amrFile The output AMR file.
* @return true if conversion was successful, false otherwise.
*/
public static boolean encodeWavToAmr(File wavFile, File amrFile) {
String[] command = {
"ffmpeg",
"-i", wavFile.getAbsolutePath(),
"-c:a", "libamr_nb", // Use the AMR-NB codec
"-b:a", "12200", // Set bitrate to 12.2 kbps (a standard AMR rate)
"-y", // Overwrite output file if it exists
amrFile.getAbsolutePath()
};
return executeCommand(command, "Encoding WAV to AMR");
}
/**
* Executes a command-line process and streams the output.
*
* @param command The command and its arguments.
* @param taskDescription A description of the task for logging purposes.
* @return true if the process exits with code 0, false otherwise.
*/
private static boolean executeCommand(String[] command, String taskDescription) {
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.redirectErrorStream(true); // Merge stderr into stdout
try {
Process process = processBuilder.start();
// Read the output (and error) stream
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
// FFmpeg logs to stderr, but we redirected it.
// We can filter out verbose logs if needed.
if (!line.startsWith("frame=")) {
System.out.println("[FFmpeg] " + line);
}
}
}
// Wait for the process to finish
int exitCode = process.waitFor();
if (exitCode == 0) {
System.out.println(taskDescription + " completed successfully.");
return true;
} else {
System.err.println(taskDescription + " failed with exit code: " + exitCode);
return false;
}
} catch (IOException | InterruptedException e) {
System.err.println("Error executing FFmpeg command: " + e.getMessage());
Thread.currentThread().interrupt(); // Restore the interrupted status
return false;
}
}
}
Important Considerations
FFmpeg Version
The codec name might vary slightly between FFmpeg versions. libamr_nb is the most common for AMR-NB (the original, narrowband version). If you have issues, you can list available codecs with this command:
ffmpeg -codecs | grep amr
Performance
- Overhead: Spawning a new process for every conversion has a performance cost. For high-throughput systems (e.g., processing thousands of files per second), this approach might be too slow.
- Alternatives: For better performance, consider:
- JNI (Java Native Interface): Write a C wrapper around FFmpeg and call it directly from Java. This is complex but very fast.
- Pure Java Libraries: Libraries like JAVE (Java Audio Video Encoder) use native binaries under the hood and can simplify the process, but they still rely on an external process.
Android
On Android, you cannot rely on a system-wide ffmpeg. You must package it with your app.
- Download: Get the
ffmpegARMv7 or ARMv8 static builds from a trusted source (e.g., Bambuser's FFmpeg builds). - Package: Place the
ffmpegexecutable in your app'sassetsorjniLibsdirectory. - Run: You need to make the file executable and call it from your Java/Kotlin code using
Runtime.exec(). You'll also need to handle the Android-specific file paths.
This example provides a solid foundation for working with AMR files in a standard Java environment.
