Make writing a habit together! This is my first day to participate in the “Gold Digging Day New Plan · April More text challenge”, click to see the details of the activity
Welcome to my GitHub
Here classification and summary of xinchen all original (including supporting source code) : github.com/zq2599/blog…
This paper gives an overview of
- In this article, we push the content of the camera to the media server, and then play it successfully with VLC. I believe you must have noticed a flaw: there is no sound
- Although the topic of the JavaCV Camera In Action series is camera processing, audio and video sound is obviously the most common situation, so this article will fill in the previous deficiencies: coding to push the camera and microphone stream, and verify that the remote playback of audio and video can be successful
About the collection and recording of audio
- This code is in the “JavaCV camera actual combat five: push stream” source code based on the increase of audio processing part
- Before coding, let’s analyze how the specific code logic changes with the addition of audio processing
- The operation of saving only video is different from that of saving audio as shown below. The dark block is the new operation:
- In contrast, at the end of the application, there are more audio and video operations when all resources are released than when only video is released, as shown in the figure below. Dark colors are the operation that releases audio related resources:
- To keep the code simple, I’ve put all the audio-related processing in a class called AudioService, which means that the dark code in the two images above is in AudioService.java. The main program uses this class to do the audio processing
- So let’s start coding
Develop the audio processing class AudioService
- The first is audioService.java, which focuses on the functionality of the dark blocks in the previous figure, with a few caveats that will be mentioned later:
@Slf4j
public class AudioService {
/ / sampling rate
private final static int SAMPLE_RATE = 44100;
private final static int CHANNEL_NUM = 2;
// Frame recorder
private FFmpegFrameRecorder recorder;
/ / timer
private ScheduledThreadPoolExecutor sampleTask;
private TargetDataLine line;
byte[] audioBytes;
private volatile boolean isFinish = false;
public void setRecorderParams(FrameRecorder recorder) throws Exception {
this.recorder = (FFmpegFrameRecorder)recorder;
// The bit rate is constant
recorder.setAudioOption("crf"."0");
// Maximum sound quality
recorder.setAudioQuality(0);
// 192 Kbps
recorder.setAudioBitrate(192000);
/ / sampling rate
recorder.setSampleRate(SAMPLE_RATE);
/ / stereo
recorder.setAudioChannels(2);
/ / encoder
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
}
public void initSampleService(a) throws Exception {
AudioFormat audioFormat = new AudioFormat(SAMPLE_RATE, 16, CHANNEL_NUM, true.false);
DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat);
line = (TargetDataLine)AudioSystem.getLine(dataLineInfo);
line.open(audioFormat);
line.start();
final int audioBufferSize = SAMPLE_RATE * CHANNEL_NUM;
audioBytes = new byte[audioBufferSize];
sampleTask = new ScheduledThreadPoolExecutor(1);
}
public void releaseOutputResource(a) {
// The end flag prevents the sampled code from exiting in the whlie loop
isFinish = true;
// End the scheduled task
sampleTask.shutdown();
// Stop the data line
line.stop();
// Close the data line
line.close();
}
public void startSample(double frameRate) {
// Start a scheduled task that executes once per second to collect audio data for the frame recorder
sampleTask.scheduleAtFixedRate((Runnable) new Runnable() {
@Override
public void run(a) {
try
{
int nBytesRead = 0;
while (nBytesRead == 0 && !isFinish) {
nBytesRead = line.read(audioBytes, 0, line.available());
}
if (nBytesRead<1) {
return;
}
int nSamplesRead = nBytesRead / 2;
short[] samples = new short[nSamplesRead];
ByteBuffer.wrap(audioBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(samples);
ShortBuffer sBuff = ShortBuffer.wrap(samples, 0, nSamplesRead);
recorder.recordSamples(SAMPLE_RATE, CHANNEL_NUM, sBuff);
}
catch(FrameRecorder.Exception e) { e.printStackTrace(); }}},0.1000 / (long)frameRate, TimeUnit.MILLISECONDS); }}Copy the code
- In the above code, there are two things to note:
- Focus on recorder. RecordSamples, which stores audio into mp4 files
- The timed task is executed on a new thread, so when the main thread finishes recording, the while loop in the timed task needs to be interrupted. Therefore, the volatile isFinish variable is added to help the code in the timed task determine whether to terminate the while loop immediately
Transform the original push stream only push video code
- Next is “JavaCV camera combat five: Push flow, the article RecordCamera. Java transformation, in order not to affect the chapters on making the code before, here I added a class RecordCameraWithAudio. Java, contents and RecordCamera. Java as like as two peas, So let’s change this RecordCameraWithAudio class
- Add a member variable of type AudioService:
// Audio service class
private AudioService audioService = new AudioService();
Copy the code
- The initOutput method is responsible for initializing the frame recorder, and now it needs to initialize the audio and start a scheduled task to collect and process the audio, as shown in the following.
@Override
protected void initOutput(a) throws Exception {
// instantiate FFmpegFrameRecorder to pass in the SRS push address
recorder = FrameRecorder.createDefault(RECORD_ADDRESS, getCameraImageWidth(), getCameraImageHeight());
recorder.setVideoOption("tune"."zerolatency");
recorder.setVideoOption("preset"."ultrafast");
recorder.setVideoOption("crf"."28");
recorder.setVideoBitrate(2000000);
// Set the encoding format
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
// Set the encapsulation format
recorder.setFormat("flv");
// FPS (frames per second)
// The number of frames per second
recorder.setFrameRate(getFrameRate());
// Key frame interval, in our case every 2 seconds -> 30 (fps) * 2 = 60
// Keyframe interval
recorder.setGopSize((int)getFrameRate()*2);
// Set the audio parameters of the frame recorder
audioService.setRecorderParams(recorder);
// Audio sampling-related initialization operations
audioService.initSampleService();
// The frame recorder starts initialization
recorder.start();
// Start the scheduled task to capture audio frames to the frame recorder
audioService.startSample(getFrameRate());
}
Copy the code
- The output method is saved as is and only handles video frames (audio is handled in a timed task)
@Override
protected void output(Frame frame) throws Exception {
if (0L==startRecordTime) {
startRecordTime = System.currentTimeMillis();
}
/ / timestamp
recorder.setTimestamp(1000 * (System.currentTimeMillis()-startRecordTime));
/ / save
recorder.record(frame);
}
Copy the code
- In the method of releasing resources, added the operation of releasing audio resources:
@Override
protected void releaseOutputResource(a) throws Exception {
// Perform a resource release operation for the audio service
audioService.releaseOutputResource();
// Close the frame recorder
recorder.close();
}
Copy the code
- At this point, the function of pushing camera video and microphone audio to the media server has been developed, and then write the main method to indicate the push stream for ten minutes:
public static void main(String[] args) {
new RecordCameraWithAudio().action(600);
}
Copy the code
- Run the main method and wait until the console outputs the content in the red box below, indicating that it is pushing:
- On another computer with VLC software open just push flow address RTMP: / / 192.168.50.43:21935 / HLS/camera, wait a few seconds later began to normal play, image noise is normal (note can’t use the computer, otherwise the microphone acquisition is VLC player voice) :
- Check the media stream information with the tools of VLC, as shown in the picture below, both video stream and audio stream can be recognized normally:
- Open the monitoring page of the media server itself, as shown below, and you can see all real-time data:
- So far, we have completed the audio and video push stream function, (a little like the appearance of live), thanks to the powerful JavaCV, the whole process is so easy and happy, next please continue to pay attention to Xinchen original, “JavaCV camera actual battle” series will present more rich applications;
Download the source code
- The full source code for JavaCV Camera In Action is available on GitHub at github.com/zq2599/blog…
The name of the | link | note |
---|---|---|
Project home page | Github.com/zq2599/blog… | The project’s home page on GitHub |
Git repository address (HTTPS) | Github.com/zq2599/blog… | The project source warehouse address, HTTPS protocol |
Git repository address (SSH) | [email protected]:zq2599/blog_demos.git | The project source warehouse address, SSH protocol |
- The Git project has multiple folders. The source code for this project is in the Javacv-tutorials folder, as shown in the red box below:
- Javacv-tutorials have many subprojects. The Code for the JavacV Camera Hands-on series was based on the Simply-grab-push project:
Welcome to the Nuggets: programmer Chen Chen
Learning on the road, you are not alone, Xinchen original all the way accompanied by…