Recording by programming
The main steps to develop the recording function are:
- Register device
- Get input format object
- Open device
- Collect data
- Release resources
There are 3 FFmpeg libraries that need to be used.
extern "C" {
// Device related API
#include
// Format related API
#include
// tool related API (such as error handling)
#include
}
Register device
During the running of the entire program, you only need to execute the code for registering the device once.
// Initialize libavdevice and register all input and output devices
avdevice_register_all();
Get input format object
Macro definition
The format name and device name of Windows and Mac environments are both are different, so use conditional compilation to achieve cross-platform.
//The format name and device name are temporarily fixed by macro definitions
#ifdef Q_OS_WIN
//The format name
#define FMT_NAME "dshow"
// device name
#define DEVICE_NAME "audio=microphone array (Realtek(R) Audio)"
#else
#define FMT_NAME "avfoundation"
#define DEVICE_NAME " :0"
#endif
Core Code
Get the input format object according to the format name, you need to Open the device with an input format object.
AVInputFormat *fmt = av_find_input_format(FMT_NAME);
if (!fmt) {
// if the input format cannot be found
qDebug () <<"Input format not found" <<FMT_NAME;
return;
}
Open device
// format context (later operate device through format context)
AVFormatContext *ctx = nullptr;
// open device
int ret = avformat_open_input(&ctx, DEVICE_NAME, fmt, nullptr);
// If the device fails to open
if (ret <0) {
char errbuf[1024] = {0};
// According to the function The returned error code gets the error message
av_strerror(code, errbuf, sizeof (errbuf));
qDebug() <<"Failed to open the device" <<errbuf;
return;
}
Collect data
Macro definition
#ifdef Q_OS_WIN
// The file name of the PCM file
#define FILENAME "F:/out.pcm"
#else
#define FILENAME "/ Users/mj/Desktop/out.pcm"
#endif
core code
#include
// file
QFile file(FILENAME);
// WriteOnly: write-only mode. If the file does not exist, create the file; if the file exists, delete the file content
if (!file.open(QFile::WriteOnly)) {
qDebug() <<"Failed to open the file" <<FILENAME ;
// Close the device
avformat_close_input(&ctx);
return;
}
// Temporarily assume that only 50 data packets are collected
int count = 50;
/ / Data packet
AVPacket pkt;
// Collect data from the device
// The return value of av_read_frame is 0, which means the data collection is successful
while (count-- > 0 && av_read_frame(ctx, &pkt ) == 0) {
// write data
file.write((const char *) pkt.data, pkt.size);
}
Release resources
//Close the file
file.close();
//Close Device
avformat_close_input(&ctx);
To understand the specific role of each function, you can query: official API documentation.
Multithreading
Recording is a time-consuming operation. In order to avoid blocking the main thread, it is best to perform recording operations in sub-threads. A thread class inherited from QThread is created here. Once the thread starts (start), it will automatically call the run function.
.h
#include
class AudioThread : public QThread {
Q_OBJECT
private:
void run();
public:
explicit AudioThread(QObject *parent = nullptr);
~AudioThread();
};
.cpp
AudioThread::AudioThread(QObject * parent,
AVInputFormat *fmt,
const char *deviceName)
: QThread(parent), _fmt(fmt), _deviceName(deviceName) {
// Automatically reclaim the memory of the thread when the thread ends
connect(this, &AudioThread::finished,
this, &AudioThread::deleteLater);
}
AudioThread::~AudioThread() {
// When the memory of the thread object is recycled, End the thread normally
requestInterruption();
quit();
wait();
}
void AudioThread::run() {
// recording operation
/ / ...
}
Open Thread
AudioThread *audioThread = new AudioThread(this);
audioThread- >start();
end thread
//external Call the requestInterruption of the thread and request to end the thread
audioThread->requestInterruption();
//The logic inside the thread
void AudioThread::run() {
//You can judge whether to end by isInterruptionRequested Thread
// When the requestInterruption of the thread is called, the return value of isInterruptionRequested is true, otherwise it is false
while (!isInterruptionRequested()) {
// ...
}
}
[Second understand audio and video development] 09_ audio recording 02_ programming