首頁>技術>

0.引言

本篇文章主要是講解音訊採集模組的實現,從0到1實現,完整的還原整個過程。也可以參考前面的文章。參考文章列表如下:

1.建立專案工程

2.建立CommonLooper

新建一個c++ class為CommonLooper

CommonLooper.h原始碼如下:

CommonLooper.cpp原始碼如下:

3.建立mediabase

新建一個C++ Header File為mediabase.h,建立引數相關的工作。

mediabase.h原始碼如下:

#ifndef MEDIABASE_H#define MEDIABASE_H#include <map>#include <vector>#include <string>#include <string.h>enum RET_CODE{    RET_ERR_UNKNOWN = -2,                   // 未知錯誤    RET_FAIL = -1,							// 失敗    RET_OK	= 0,							// 正常    RET_ERR_OPEN_FILE,						// 開啟檔案失敗    RET_ERR_NOT_SUPPORT,					// 不支援    RET_ERR_OUTOFMEMORY,					// 沒有記憶體    RET_ERR_STACKOVERFLOW,					// 溢位    RET_ERR_NULLREFERENCE,					// 空參考    RET_ERR_ARGUMENTOUTOFRANGE,				//    RET_ERR_PARAMISMATCH,					//    RET_ERR_MISMATCH_CODE,                  // 沒有匹配的編解碼器    RET_ERR_EAGAIN,    RET_ERR_EOF};class Properties: public std::map<std::string,std::string>{public:    bool HasProperty(const std::string &key) const    {        return find(key)!=end();    }    void SetProperty(const char* key,int intval)    {        SetProperty(std::string(key),std::to_string(intval));    }    void SetProperty(const char* key,uint32_t val)    {        SetProperty(std::string(key),std::to_string(val));    }    void SetProperty(const char* key,uint64_t val)    {        SetProperty(std::string(key),std::to_string(val));    }    void SetProperty(const char* key,const char* val)    {        SetProperty(std::string(key),std::string(val));    }    void SetProperty(const std::string &key,const std::string &val)    {        insert(std::pair<std::string,std::string>(key,val));    }    void GetChildren(const std::string& path,Properties &children) const    {        //Create sarch string        std::string parent(path);        //Add the final .        parent += ".";        //For each property        for (const_iterator it = begin(); it!=end(); ++it)        {            const std::string &key = it->first;            //Check if it is from parent            if (key.compare(0,parent.length(),parent)==0)                //INsert it                children.SetProperty(key.substr(parent.length(),key.length()-parent.length()),it->second);        }    }    void GetChildren(const char* path,Properties &children) const    {        GetChildren(std::string(path),children);    }    Properties GetChildren(const std::string& path) const    {        Properties properties;        //Get them        GetChildren(path,properties);        //Return        return properties;    }    Properties GetChildren(const char* path) const    {        Properties properties;        //Get them        GetChildren(path,properties);        //Return        return properties;    }    void GetChildrenArray(const char* path,std::vector<Properties> &array) const    {        //Create sarch string        std::string parent(path);        //Add the final .        parent += ".";        //Get array length        int length = GetProperty(parent+"length",0);        //For each element        for (int i=0; i<length; ++i)        {            char index[64];            //Print string            snprintf(index,sizeof(index),"%d",i);            //And get children            array.push_back(GetChildren(parent+index));        }    }    const char* GetProperty(const char* key) const    {        return GetProperty(key,"");    }    std::string GetProperty(const char* key,const std::string defaultValue) const    {        //Find item        const_iterator it = find(std::string(key));        //If not found        if (it==end())            //return default            return defaultValue;        //Return value        return it->second;    }    std::string GetProperty(const std::string &key,const std::string defaultValue) const    {        //Find item        const_iterator it = find(key);        //If not found        if (it==end())            //return default            return defaultValue;        //Return value        return it->second;    }    const char* GetProperty(const char* key,const char *defaultValue) const    {        //Find item        const_iterator it = find(std::string(key));        //If not found        if (it==end())            //return default            return defaultValue;        //Return value        return it->second.c_str();    }    const char* GetProperty(const std::string &key,char *defaultValue) const    {        //Find item        const_iterator it = find(key);        //If not found        if (it==end())            //return default            return defaultValue;        //Return value        return it->second.c_str();    }    int GetProperty(const char* key,int defaultValue) const    {        return GetProperty(std::string(key),defaultValue);    }    int GetProperty(const std::string &key,int defaultValue) const    {        //Find item        const_iterator it = find(key);        //If not found        if (it==end())            //return default            return defaultValue;        //Return value        return atoi(it->second.c_str());    }    uint64_t GetProperty(const char* key,uint64_t defaultValue) const    {        return GetProperty(std::string(key),defaultValue);    }    uint64_t GetProperty(const std::string &key,uint64_t defaultValue) const    {        //Find item        const_iterator it = find(key);        //If not found        if (it==end())            //return default            return defaultValue;        //Return value        return atoll(it->second.c_str());    }    bool GetProperty(const char* key,bool defaultValue) const    {        return GetProperty(std::string(key),defaultValue);    }    bool GetProperty(const std::string &key,bool defaultValue) const    {        //Find item        const_iterator it = find(key);        //If not found        if (it==end())            //return default            return defaultValue;        //Get value        char * val = (char *)it->second.c_str();        //Check it        if (strcasecmp(val,(char *)"yes")==0)            return true;        else if (strcasecmp(val,(char *)"true")==0)            return true;        //Return value        return (atoi(val));    }};#endif // MEDIABASE_H

4.建立dlog

新增c++ class 為dlog,當做日誌庫使用。

dlog.h原始碼如下:

#ifndef LOG_H#define LOG_H#include <stdio.h>#ifndef NULL#define NULL         (0)#endif#ifndef TRUE#define TRUE         (1)#endif#ifndef FALSE#define FALSE        (0)#endif#ifdef __cplusplusextern "C" {#endiftypedef enum _slog_level {    S_TRACE = 1,    S_DEBUG = 2,    S_INFO = 3,    S_WARN = 4,    S_ERROR = 5} slog_level;int init_logger(const char *log_dir, slog_level level);void write_log(slog_level level, int print_stacktrace, const char *func_name, int line, const char *fmt, ...);#define LogError(fmt, ...) write_log(S_ERROR, FALSE, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)#define LogWarn(fmt, ...) write_log(S_WARN, FALSE, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)#define LogInfo(fmt, ...) write_log(S_INFO, FALSE, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)#define LogDebug(fmt, ...) write_log(S_DEBUG, FALSE, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)#define LogTrace(fmt, ...) write_log(S_TRACE, FALSE, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)#ifdef __cplusplus}#endif#endif // LOG_H

dlog.cpp原始碼如下:

#include "dlog.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <stdarg.h>#include <stdint.h>#if defined(WIN32)#include <io.h>#include <direct.h>#include <Windows.h>#include <DbgHelp.h>#elif defined(linux)#include <unistd.h>#include <pthread.h>#include <sys/stat.h>#include <execinfo.h>#endif#define MAX_LEVEL_STR               (10)#define MAX_DATE_STR                (10)#define DATE_STR_FMT                "%04d%02d%02d"#define MAX_TIME_STR                (20)#define TIME_STR_FMT                "%04d/%02d/%02d %02d:%02d:%02d"#define MAX_FILE_PATH               (260)#define MAX_LOG_LINE                (4096)#define INNER_DEEP                  (2)#define MAX_DEEP                    (24)#define MAX_ST_INFO                 (256)#define MAX_ST_LINE                 (512)#if defined(WIN32)#define snprintf _snprintf#define vsnprintf _vsnprintf#define PROC_HANDLE HANDLE#define SLOG_MUTEX CRITICAL_SECTION#elif defined(linux)#define PROC_HANDLE void *#define SLOG_MUTEX pthread_mutex_t#endiftypedef struct _logger_cfg {    PROC_HANDLE curr_proc;    FILE *log_file;    SLOG_MUTEX mtx;    slog_level filter_levle;    int inited;} logger_cfg;static logger_cfg g_logger_cfg = {    NULL, NULL, {0}, S_INFO, FALSE };static void _slog_init_mutex(SLOG_MUTEX *mtx){#if defined(WIN32)    InitializeCriticalSection(mtx);#elif defined(linux)    pthread_mutex_init(mtx, NULL);#endif}static void _slog_lock(SLOG_MUTEX *mtx){#if defined(WIN32)    EnterCriticalSection(mtx);#elif defined(linux)    pthread_mutex_lock(mtx);#endif}static void _slog_unlock(SLOG_MUTEX *mtx){#if defined(WIN32)    LeaveCriticalSection(mtx);#elif defined(linux)    pthread_mutex_unlock(mtx);#endif}static void _get_curr_date(int datestr_size, char datestr[]){    time_t tt = { 0 };    struct tm *curr_time = NULL;    time(&tt);    curr_time = localtime(&tt);    snprintf(datestr, datestr_size - 1, DATE_STR_FMT,        curr_time->tm_year + 1900, curr_time->tm_mon + 1, curr_time->tm_mday);}static void _get_curr_time(int timestr_size, char timestr[]){    time_t tt = { 0 };    struct tm *curr_time = NULL;    time(&tt);    curr_time = localtime(&tt);    snprintf(timestr, timestr_size - 1, TIME_STR_FMT,        curr_time->tm_year + 1900, curr_time->tm_mon + 1, curr_time->tm_mday,        curr_time->tm_hour, curr_time->tm_min, curr_time->tm_sec);}static inline char *_get_level_str(slog_level level){    switch (level) {    case S_TRACE:        return (char *)"[TRACE]";    case S_DEBUG:        return (char *)"[DEBUG]";    case S_INFO:        return (char *)"[INFO ]";    case S_WARN:        return (char *)"[WARN ]";    case S_ERROR:        return (char *)"[ERROR]";    default:        return (char *)"[     ]";    }}static void _write_stacktrace(){    unsigned int i = 0;    unsigned short frames = 0;    void *stack[MAX_DEEP] = { 0 };    char st_line[MAX_ST_LINE] = { 0 };#if defined(WIN32)#elif defined(linux)    char **st_arr = NULL;    frames = backtrace(stack, MAX_DEEP);    st_arr = backtrace_symbols(stack, frames);    for (i = 0; i < frames; ++i) {        snprintf(st_line, sizeof(st_line) - 1, "    %d: %s\n", frames - i - 1, st_arr[i]);        fwrite(st_line, sizeof(char), strlen(st_line), g_logger_cfg.log_file);    }    free(st_arr);#endif}static int _slog_mkdir(const char *log_dir){#if defined(WIN32)    if (mkdir(log_dir) != 0) {        return FALSE;    }#elif defined(linux)    if (mkdir(log_dir, 0744) != 0) {        return FALSE;    }#endif    return TRUE;}static int _get_curr_proc_handle(){#if defined(WIN32)    g_logger_cfg.curr_proc = NULL;#elif defined(linux)    g_logger_cfg.curr_proc = NULL;#endif    return TRUE;}int init_logger(const char *log_dir, slog_level level){    char log_filepath[MAX_FILE_PATH] = { 0 };    char datestr[MAX_DATE_STR] = { 0 };    if (TRUE == g_logger_cfg.inited) {        return TRUE;    }    if (access(log_dir, 0) != 0) {        if (_slog_mkdir(log_dir) != TRUE) {            return FALSE;        }    }    _slog_init_mutex(&g_logger_cfg.mtx);    _get_curr_proc_handle();    _get_curr_date(sizeof(datestr), datestr);    snprintf(log_filepath, sizeof(log_filepath) - 1, "%s/%s.log", log_dir, datestr);    g_logger_cfg.log_file = fopen(log_filepath, "w+");    if (NULL == g_logger_cfg.log_file) {        return FALSE;    }    g_logger_cfg.filter_levle = level;    g_logger_cfg.inited = TRUE;    return TRUE;}static inline int64_t getTimeMillisecond(){    #ifdef _WIN32        return (int64_t)GetTickCount();    #else        struct timeval tv;        gettimeofday(&tv, NULL);        return ((int64_t)tv.tv_sec * 1000 + (unsigned long long)tv.tv_usec / 1000);    #endif//        return duration_cast<chrono::milliseconds>(high_resolution_clock::now() - m_begin).count();}void write_log(slog_level level, int print_stacktrace, const char *func_name, int line, const char *fmt, ...){    va_list args;    char *level_str = NULL;    char timestr[MAX_TIME_STR] = { 0 };    char log_content[MAX_LOG_LINE] = { 0 };    char log_line[MAX_LOG_LINE] = { 0 };    if (g_logger_cfg.filter_levle > level) {        return;    }    va_start(args, fmt);    vsnprintf(log_content, sizeof(log_content) - 1, fmt, args);    va_end(args);    _get_curr_time(sizeof(timestr), timestr);    level_str = _get_level_str(level);    int64_t cur_time = getTimeMillisecond();    snprintf(log_line, sizeof(log_line) - 1, "[%s %s-%d %s:%d] %s\n",        level_str, timestr, int(cur_time%1000), func_name, line, log_content);//    _slog_lock(&g_logger_cfg.mtx);    fwrite(log_line, sizeof(char), strlen(log_line), g_logger_cfg.log_file);//    if (TRUE == print_stacktrace) {//        _write_stacktrace();//    }    fflush(g_logger_cfg.log_file);    printf("%s", log_line);     // 先列印到終端再說//    _slog_unlock(&g_logger_cfg.mtx);}

5.建立音訊採集

新增c++ class 為AudioCapturer,當做音訊採集使用。

AudioCapturer.h原始碼如下:

#ifndef AUDIOCAPTURER_H#define AUDIOCAPTURER_H#include <functional>#include "commonlooper.h"#include "mediabase.h"using std::function;class AudioCapturer:public CommonLooper{public:    AudioCapturer();    virtual ~AudioCapturer();    RET_CODE Init(const Properties properties);    virtual void Loop();    void AddCallback(function<void(uint8_t *, int32_t)> callback);private:    // PCM file只是用來測試, 寫死為s16格式 2通道 取樣率48Khz    // 1幀1024取樣點持續的時間21.333333333333333333333333333333ms    int openPcmFile(const char *file_name);    int readPcmFile(uint8_t *pcm_buf, int32_t pcm_buf_size);    int closePcmFile();    int audio_test_ = 0;    std::string input_pcm_name_; //輸入的pcm測試檔名字    FILE *pcm_fp_ = NULL;    int64_t pcm_start_time_ = 0; //起始時間    double pcm_total_duration_ = 0; //推流時長的統計    double frame_duration_ = 23.2;    std::function<void(uint8_t *, int32_t)> callback_get_pcm_;    //const int PCM_BUF_MAX_SIZE = 8196;    bool is_first_time_ = false;    int sample_rate_ = 48000;    int nb_samples_ = 1024;    int format_ = 1;//目前固定s16    int channels_ = 2;    int32_t pcm_buf_size_;    uint8_t *pcm_buf_;};#endif // AUDIOCAPTURER_H

AudioCapturer.cpp原始碼如下:

#include "audiocapturer.h"#include "dlog.h"#include "timesutil.h"AudioCapturer::AudioCapturer(){}AudioCapturer::~AudioCapturer(){}RET_CODE AudioCapturer::Init(const Properties properties){    audio_test_ = properties.GetProperty("audio_test", 0);    input_pcm_name_ = properties.GetProperty("input_pcm_name", "buweishui_48000_2_s16le.pcm");    sample_rate_ = properties.GetProperty("sample_rate", 48000);    channels_ = properties.GetProperty("channels",2);    nb_samples_ = properties.GetProperty("nb_samples", 1024);    pcm_buf_size_ = 2*channels_*nb_samples_;    pcm_buf_ = new uint8_t[pcm_buf_size_];//分配buff    if(!pcm_buf_)    {        return RET_ERR_OUTOFMEMORY;    }    if(openPcmFile(input_pcm_name_.c_str()) < 0)    {        LogError("openPcmFile %s failed", input_pcm_name_.c_str());        return RET_FAIL;    }    frame_duration_ = 1.0*nb_samples_/sample_rate_*1000;//單位就是ms,得到一幀的毫秒時間    return RET_OK;}void AudioCapturer::Loop(){    LogInfo("into loop");    pcm_total_duration_ = 0;    pcm_start_time_ = TimesUtil::GetTimeMillisecond();//初始化時間基    while (true) {        if(request_abort_)        {            break;//請求退出        }        if(readPcmFile(pcm_buf_, pcm_buf_size_) == 0)        {            //如果是第一幀資料            if(is_first_time_)            {                is_first_time_ = true;                LogInfo("is_first_time_");            }            if(callback_get_pcm_)            {                //透過回撥把資料傳送出去給使用者去處理,對接的就是使用者的PushWork::PcmCallback                callback_get_pcm_(pcm_buf_,pcm_buf_size_);            }        }        //如果讀取的返回值不為0,就休眠2ms        std::this_thread::sleep_for(std::chrono::milliseconds(2));    }    request_abort_ = false;    closePcmFile();}void AudioCapturer::AddCallback(function<void (uint8_t *, int32_t)> callback){    callback_get_pcm_ = callback;}int AudioCapturer::openPcmFile(const char *file_name){    pcm_fp_ = fopen(file_name, "rb");    if(!pcm_fp_)    {        return -1;    }    return 0;}int AudioCapturer::readPcmFile(uint8_t *pcm_buf, int32_t pcm_buf_size){    int64_t cur_time = TimesUtil::GetTimeMillisecond(); //單位毫秒    int64_t dif = cur_time - pcm_start_time_;//目前經過的時間    if(((int64_t)pcm_total_duration_) > dif)    {        return 1; //還沒有到讀取新一幀的時間    }//讀取資料    size_t ret = fread(pcm_buf, 1, pcm_buf_size, pcm_fp_);    if(ret != pcm_buf_size)    {        //重新開始        ret = fseek(pcm_fp_,0, SEEK_SET);        ret = fread(pcm_buf, 1, pcm_buf_size, pcm_fp_);        if(ret != pcm_buf_size)        {            return -1;//出錯        }    }    //累計讀取幀時間    pcm_total_duration_ += frame_duration_;    return 0;}int AudioCapturer::closePcmFile(){    if(pcm_fp_)    {        fclose(pcm_fp_);    }    return 0;}

6.建立時間基

新建一個C++ Header File為TimesUtil,當做時間類使用。

TimesUtil.h原始碼如下:

#ifndef TIMESUTIL_H#define TIMESUTIL_H#include <stdint.h>#ifdef _WIN32#include <winsock2.h>#include <ws2tcpip.h>#ifdef _MSC_VER	/* MSVC *///#define snprintf _snprintf#define strcasecmp stricmp#define strncasecmp strnicmp//#define vsnprintf _vsnprintf#endif#define GetSockError()	WSAGetLastError()#define SetSockError(e)	WSASetLastError(e)#define setsockopt(a,b,c,d,e)	(setsockopt)(a,b,c,(const char *)d,(int)e)#define EWOULDBLOCK	WSAETIMEDOUT	/* we don't use nonblocking, but we do use timeouts */#define sleep(n)	Sleep(n*1000)#define msleep(n)	Sleep(n)#define SET_RCVTIMEO(tv,s)	int tv = s*1000#else /* !_WIN32 */#include <sys/types.h>#include <sys/socket.h>#include <sys/times.h>#include <netdb.h>#include <unistd.h>#include <netinet/in.h>#include <netinet/tcp.h>#include <arpa/inet.h>#define GetSockError()	errno#define SetSockError(e)	errno = e#undef closesocket#define closesocket(s)	close(s)#define msleep(n)	usleep(n*1000)#define SET_RCVTIMEO(tv,s)	struct timeval tv = {s,0}#endif#include<chrono>using namespace std;using namespace std::chrono;#ifdef _WIN32#pragma comment(lib, "ws2_32.lib")#endifclass TimesUtil{public:    static inline int64_t GetTimeMillisecond()    {        #ifdef _WIN32            return (int64_t)GetTickCount();        #else            struct timeval tv;            gettimeofday(&tv, NULL);            return ((int64_t)tv.tv_sec * 1000 + (unsigned long long)tv.tv_usec / 1000);        #endif//        return duration_cast<chrono::milliseconds>(high_resolution_clock::now() - m_begin).count();    }//private://    static time_point<high_resolution_clock> m_begin;};#endif // TIMESUTIL_H

怎麼按照播放速率讀取時間?

當前時間減去時間基準,幀累計時間計算

7.建立使用者管理推流模組

新增c++ class 為push_work,實現一個push_work,當做一個總的模組,開放出去使用。

pushwork.h原始碼如下:

#include "pushwork.h"#include "dlog.h"#include <functional>PushWork::PushWork(){}RET_CODE PushWork::Init(const Properties &properties){    // 音訊test模式    audio_test_ = properties.GetProperty("audio_test", 0);    input_pcm_name_ = properties.GetProperty("input_pcm_name", "input_48k_2ch_s16.pcm");    // 麥克風取樣屬性    mic_sample_rate_ = properties.GetProperty("mic_sample_rate", 48000);    mic_sample_fmt_ = properties.GetProperty("mic_sample_fmt", AV_SAMPLE_FMT_S16);    mic_channels_ = properties.GetProperty("mic_channels", 2);    //設定音訊捕獲    audio_capturer_ = new AudioCapturer();    Properties aud_cap_properties;    aud_cap_properties.SetProperty("audio_test", 1);    aud_cap_properties.SetProperty("input_pcm_name", input_pcm_name_);    aud_cap_properties.SetProperty("nb_channels", mic_channels_);    //aud_cap_properties.SetProperty("nb_samples",1024);    if(audio_capturer_->Init(aud_cap_properties) != RET_OK)    {        LogError("AudioCapturer Init failed");        return RET_FAIL;    }    //呼叫回撥函式    audio_capturer_->AddCallback(std::bind(&PushWork::PcmCallback, this, std::placeholders::_1,                                 std::placeholders::_2));    if(audio_capturer_->Start() != RET_OK)    {         LogError("AudioCapturer Start failed");        return RET_FAIL;    }    return RET_OK;}RET_CODE PushWork::DeInit(){    if(audio_capturer_)    {        audio_capturer_->Stop();        delete audio_capturer_;        audio_capturer_ = NULL;    }}//使用者的回撥函式實現void PushWork::PcmCallback(uint8_t *pcm, int32_t size){    LogInfo("size:%d",size);}

pushwork.cpp原始碼如下:

#include "pushwork.h"#include "dlog.h"#include <functional>PushWork::PushWork(){}RET_CODE PushWork::Init(const Properties &properties){    // 音訊test模式    audio_test_ = properties.GetProperty("audio_test", 0);    input_pcm_name_ = properties.GetProperty("input_pcm_name", "input_48k_2ch_s16.pcm");    // 麥克風取樣屬性    mic_sample_rate_ = properties.GetProperty("mic_sample_rate", 48000);    mic_sample_fmt_ = properties.GetProperty("mic_sample_fmt", AV_SAMPLE_FMT_S16);    mic_channels_ = properties.GetProperty("mic_channels", 2);    //設定音訊捕獲    audio_capturer_ = new AudioCapturer();    Properties aud_cap_properties;    aud_cap_properties.SetProperty("audio_test", 1);    aud_cap_properties.SetProperty("input_pcm_name", input_pcm_name_);    aud_cap_properties.SetProperty("nb_channels", mic_channels_);    //aud_cap_properties.SetProperty("nb_samples",1024);    if(audio_capturer_->Init(aud_cap_properties) != RET_OK)    {        LogError("AudioCapturer Init failed");        return RET_FAIL;    }    //呼叫回撥函式    audio_capturer_->AddCallback(std::bind(&PushWork::PcmCallback, this, std::placeholders::_1,                                 std::placeholders::_2));    if(audio_capturer_->Start() != RET_OK)    {         LogError("AudioCapturer Start failed");        return RET_FAIL;    }    return RET_OK;}RET_CODE PushWork::DeInit(){    if(audio_capturer_)    {        audio_capturer_->Stop();        delete audio_capturer_;        audio_capturer_ = NULL;    }}//使用者的回撥函式實現void PushWork::PcmCallback(uint8_t *pcm, int32_t size){    LogInfo("size:%d",size);}

8.建立main函式

主函式main.cpp原始碼如下:

#include <iostream>#include "dlog.h"#include "pushwork.h"using namespace std;extern "C" {#include <libavcodec/avcodec.h>#include <libswresample/swresample.h>#include <libavutil/opt.h>#include <libavutil/audio_fifo.h>}//第一版的音訊採集,已實現int main(){    cout << "Hello World!" << endl;    init_logger("rtsp_push.log", S_INFO);    {        PushWork push_work;        Properties properties;        // 音訊test模式        properties.SetProperty("audio_test", 1);    // 音訊測試模式        properties.SetProperty("input_pcm_name", "buweishui_48000_2_s16le.pcm");        // 麥克風取樣屬性        properties.SetProperty("mic_sample_fmt", AV_SAMPLE_FMT_S16);        properties.SetProperty("mic_sample_rate", 48000);        properties.SetProperty("mic_channels", 2);        if(push_work.Init(properties) != RET_OK)        {            LogError("PushWork init failed");            return -1;        }                int count = 0;                while (true) {                    std::this_thread::sleep_for(std::chrono::milliseconds(1000));//10s鍾退出                     if(count++ > 5)                        break;                }    }    LogInfo("main finish");    return 0;}

9.測試

音訊採集除錯完成,可以讀到資料。

注意:需要提前準備好音訊pcm檔案。

10.總結

11
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • Python 寫一個檔案分發小程式