https://github.com/jcodec/jcodec
This tutorial series covers how to make a recording software using Java Technology.
For this tutorial (Part 3), we are going to implement the audio support for our screen recording program. We will be getting audio input from the system microphone and then merge it with the audio-less video frames we created.
The following steps will guide us into integrating the audio feature on our software:
To achieve audio recording, we are going to make use of the Java Sound API. Since audio capturing and recording will take some time to process completely thus blocking the current thread, we are going implement the operations in a separate thread outside the UI thread.
public class AudioRecorder extends Thread {
...
private void initRecording() {
System.out.println("begin sound test...");
try {
//define audio format
AudioFormat audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 4, 44100, false);
//build line info with audio format
DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat);
mic = (TargetDataLine) AudioSystem.getLine(info); // initialize the mic line
mic.open(); //open the line for recording
System.out.println("recording initialized...");
} catch (LineUnavailableException ex) {
ex.printStackTrace();
}
}
...
}
Code explanation
mic = (TargetDataLine) AudioSystem.getLine(info);mic.open(); allocate the system resource to the lineStart Recording
public class AudioRecorder extends Thread {
...
private void statRecording() {
try {
mic.start(); // start reading from line
//get audio input streams from the line
AudioInputStream audioInputStream = new AudioInputStream(mic);
File f = new File("audio_output.wav"); // craete a wav file
//write to file
AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, f);
System.out.println("done writing to file");
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public void run() {
initRecording();
statRecording();
}
...
}
Code explanation
mic.start(); to start reading from the line.initRecording(); and statRecording(); to start recording in this threadStop Recording
public void stopRecording() {
mic.stop();
mic.close();
System.out.println("Recording ended");
}
Code explanation
mic.stop(); the line stops reading audio inputsmic.close(); the mic closes the line and releases system resourcesWhat is FFmpeg?
FFmpeg is a complete, cross-platform solution to record, convert and stream audio and video. At its core is the FFmpeg program itself, designed for command-line-based processing of video and audio files, widely used for format trans-coding, basic editing (trimming and concatenation), video scaling, and video post-production effects source
Before we proceed , lets first get the FFmpeg set on the PC
This Recording software is built on linux (Elementary OS) so i decide to show installation of FFmpeg on this distro. Open the command terminal and put the following commands
Add the PPA repository sudo add-apt-repository ppa:kirillshkrogalev/ffmpeg-next
output image
Update local repository index sudo apt-get update
Install ffmpeg sudo apt-get install ffmpeg
output image
Windows users should follow this link for guide on how to install FFmpeg on their PC
https://www.wikihow.com/Install-FFmpeg-on-Windows
1. Getting audio/video file information
To display your media file details, run:
$ ffmpeg -i mp4_video_output.mp4 -hide_banner
output image
2. Converting video files to different formats
FFmpeg is a powerful audio and video converter, we can convert media files between different formats. To convert mp4 file to avi file, run:
$ ffmpeg -i mp4_video_output.mp4 avi_video_output.avi
3. Merge Video and Audio File
With FFmpeg, we can with ease merge an audio-less video file with an audio file. This Functionality interest us more as this is exactly what we need in our Screen recording Software to merge the audio tracks from the microphone and the video frames.
ffmpeg -i mp4_video_output.mp4 -i audio_output.wav -c:v copy -c:a aac -strict experimental output.mp4
You may be wandering how this will work from our program interface owing to the fact that the above commands are run from the command terminal. Well luckily for us we can access the terminal runtime environment from Java directly. With this we can execute raw FFmpeg commands directly. Another way to do this is to use a Java FFmpeg Wrapper Library.
Another question may be why are we converting our initial MP4 output to AVI ? The answer is this:
The initial Mp4 was encoded by the JCodec encoder and trying to merge the audio and video always give a faulty output. After much research and experimenting, i discovered that the Fault was from the JCodec encoder. The Video frames are always on hold till the audio tracks are done playing.
Trick I applied
I converted the initial Mp4 output having a Jcodec Encoder to AVI format
The code below output the properties of the Mp4 showing its Codec
$ ffmpeg -i mp4_video_output.mp4 -hide_banner
output image with jcodec encoder
Merge the video output in AVI format with the audio in ACC , giving it an Mp4 output
The command below does this conversion. See the output image below to see the new codec use to encode the final output in Mp4 format. See red rectangle area.
ffmpeg -i mp4_video_output.mp4 -i audio_output.wav -c:v copy -c:a aac -strict experimental output.mp4
output image with Lavf56.40.101 encoder
This method will be used to execute any FFmpeg commands.
public static void executeFfMpeg(String exec) {
Runtime runtime = Runtime.getRuntime();
try {
Process process = runtime.exec(exec);
int exitVal = process.waitFor();
System.out.println("Exited with error code " + exitVal);
} catch (IOException ex) {
ex.printStackTrace();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
Code explanation
Runtime.getRuntime();With this we get access to the program runtime environment.runtime.exec(exec); This returns a process object which could be used to gain information of that particular process and also control it .process.waitFor(); this line of code causes the current thread to wait until the process is terminated. It returns an integer value showing the termination status. 0 usually represent normal termination.For the conversion from Mp4 to AVI the String below will be used at any time
String execConvertToAVI = "ffmpeg -i mp4_video_output.mp4 -q:v 0 avi_video_output.avi";
Basically the merging of these two formats will still be done by the executeFfMpeg method shown above. The Only difference with the conversion implementation is the FFmpeg command passed into the method. Below is the command passed into the method.
String execMuxAudioVideo = "ffmpeg -i avi_video_output.avi -i audio_output.wav -c:v copy -c:a aac -strict experimental video_output.mp4";
After implementing Audio sound recording, Video Format conversion and Audio and Video Merging in separate classes, we have to integrate it into our existing program.
Update buttonStartRecordingActionPerformed method of the MainScreenRecorderFrame
This method is executed when the start recording button is click
private void buttonStartRecordingActionPerformed(java.awt.event.ActionEvent evt) {
initScreenRecorderObjects("mp4_video_output");
scheduleTimerTasks();
audioRecorder = new AudioRecorder();
audioRecorder.start();
}
Code explanation
This method is triggered when the stop button is clicked
private void buttonStopRecordingActionPerformed(java.awt.event.ActionEvent evt) {
if (isRecording) {
stopScreenRecording();
audioRecorder.stopRecording();
ExecFfmpeg.executeFfMpeg(execConvertToAVI);
ExecFfmpeg.executeFfMpeg(execMuxAudioVideo);
}
isRecording = false;
}
complete source code
Code explanation
stopScreenRecording(); is called to stop screen recording while audioRecorder.stopRecording(); is called to stop the audio recording.ExecFfmpeg.executeFfMpeg(execConvertToAVI); this line of code takes the saved video file in mp4 format and converts to AVI format as avi_video_output.aviExecFfmpeg.executeFfMpeg(execMuxAudioVideo); this line of code does the actual merging of the audio_ouput.wav and the avi_video_output.avi , saving it as video_ouput.mp4With steps one to 5 completed, we can now proceed to testing of the software.
Testing the software gives the output video below
Curriculum
Proof of Work
The complete source code can be found on gitHub
https://github.com/enyason/DesktopScreenRecorder