|  | @@ -0,0 +1,466 @@
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * 叶海辉
 | 
	
		
			
				|  |  | + * QQ群121376426
 | 
	
		
			
				|  |  | + * http://blog.yundiantech.com/
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include "AppConfig.h"
 | 
	
		
			
				|  |  | +#include "GetAudioThread.h"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include <thread>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#if defined __linux
 | 
	
		
			
				|  |  | +#include <xcb/xcb.h>
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//Show Dshow Device
 | 
	
		
			
				|  |  | +void show_dshow_device()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    AVFormatContext *pFormatCtx = avformat_alloc_context();
 | 
	
		
			
				|  |  | +    AVDictionary* options = nullptr;
 | 
	
		
			
				|  |  | +    av_dict_set(&options,"list_devices","true",0);
 | 
	
		
			
				|  |  | +    AVInputFormat *iformat = av_find_input_format("dshow");
 | 
	
		
			
				|  |  | +    printf("========Device Info=============\n");
 | 
	
		
			
				|  |  | +    avformat_open_input(&pFormatCtx,"video=dummy",iformat,&options);
 | 
	
		
			
				|  |  | +    printf("================================\n");
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +GetAudioThread::GetAudioThread()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    m_isRun = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    pFormatCtx = nullptr;
 | 
	
		
			
				|  |  | +    aCodecCtx = nullptr;
 | 
	
		
			
				|  |  | +    aFrame = nullptr;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    m_pause = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    aFrame = nullptr;
 | 
	
		
			
				|  |  | +    aFrame_ReSample = nullptr;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    mCallBackFunc = nullptr;
 | 
	
		
			
				|  |  | +    mFuncIndex = -1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    audio_buf_size_L = 0;
 | 
	
		
			
				|  |  | +    audio_buf_size_R = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    mONEFrameSize = 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +GetAudioThread::~GetAudioThread()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +bool GetAudioThread::init(const char * const deviceName)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +//    show_dshow_device();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    AVCodec			*pCodec = nullptr;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    pFormatCtx = avformat_alloc_context();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#if defined(WIN32)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    AVInputFormat *ifmt = av_find_input_format("dshow"); //使用dshow
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    char deviceNameStr[512] = {0};
 | 
	
		
			
				|  |  | +    sprintf(deviceNameStr, "audio=%s", deviceName);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//    if(avformat_open_input(&pFormatCtx, "audio=virtual-audio-capturer", ifmt, nullptr)!=0)
 | 
	
		
			
				|  |  | +    if(avformat_open_input(&pFormatCtx, deviceNameStr, ifmt, nullptr)!=0)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        fprintf(stderr, "Couldn't open input stream video.(无法打开输入流)\n");
 | 
	
		
			
				|  |  | +        return false;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#elif defined __linux
 | 
	
		
			
				|  |  | +//Linux
 | 
	
		
			
				|  |  | +    //Linux
 | 
	
		
			
				|  |  | +    AVInputFormat *ifmt = av_find_input_format("alsa");
 | 
	
		
			
				|  |  | +    if(avformat_open_input(&pFormatCtx, deviceName, ifmt, NULL)!=0)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        printf("Couldn't open input stream. default\n");
 | 
	
		
			
				|  |  | +        return false;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +    show_avfoundation_device();
 | 
	
		
			
				|  |  | +    //Mac
 | 
	
		
			
				|  |  | +    AVInputFormat *ifmt=av_find_input_format("avfoundation");
 | 
	
		
			
				|  |  | +    //Avfoundation
 | 
	
		
			
				|  |  | +    //[video]:[audio]
 | 
	
		
			
				|  |  | +    if(avformat_open_input(&pFormatCtx,"0",ifmt,nullptr)!=0)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        fprintf(stderr, "Couldn't open input stream.\n");
 | 
	
		
			
				|  |  | +        return VideoOpenFailed;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    audioStream = -1;
 | 
	
		
			
				|  |  | +    aCodecCtx   = nullptr;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    for(unsigned int i=0; i < pFormatCtx->nb_streams; i++)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        if(pFormatCtx->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_AUDIO)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            audioStream = static_cast<int>(i);
 | 
	
		
			
				|  |  | +            break;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if(audioStream == -1)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        printf("Didn't find a audio stream.(没有找到音频流)\n");
 | 
	
		
			
				|  |  | +        return false;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    //find the decoder
 | 
	
		
			
				|  |  | +    aCodecCtx = avcodec_alloc_context3(nullptr);
 | 
	
		
			
				|  |  | +    avcodec_parameters_to_context(aCodecCtx, pFormatCtx->streams[audioStream]->codecpar);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    pCodec = avcodec_find_decoder(aCodecCtx->codec_id);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if(pCodec == nullptr)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        printf("audio Codec not found.\n");
 | 
	
		
			
				|  |  | +        return false;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if(avcodec_open2(aCodecCtx, pCodec, nullptr)<0)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        printf("Could not open audio codec.\n");
 | 
	
		
			
				|  |  | +        return false;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    ///解码音频相关
 | 
	
		
			
				|  |  | +    aFrame = av_frame_alloc();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    initResample();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void GetAudioThread::deInit()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +//    if (outBufferYuv)
 | 
	
		
			
				|  |  | +//    {
 | 
	
		
			
				|  |  | +//        av_free(outBufferYuv);
 | 
	
		
			
				|  |  | +//        outBufferYuv = nullptr;
 | 
	
		
			
				|  |  | +//    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//    if (pFrame)
 | 
	
		
			
				|  |  | +//    {
 | 
	
		
			
				|  |  | +//        av_free(pFrame);
 | 
	
		
			
				|  |  | +//        pFrame = nullptr;
 | 
	
		
			
				|  |  | +//    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//    if (pFrameYUV)
 | 
	
		
			
				|  |  | +//    {
 | 
	
		
			
				|  |  | +//        av_free(pFrameYUV);
 | 
	
		
			
				|  |  | +//        pFrameYUV = nullptr;
 | 
	
		
			
				|  |  | +//    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//    if (pCodecCtx)
 | 
	
		
			
				|  |  | +//        avcodec_close(pCodecCtx);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//    avformat_close_input(&pFormatCtx);
 | 
	
		
			
				|  |  | +//    avformat_free_context(pFormatCtx);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void GetAudioThread::startRecord(int outOneFrameSize, std::function<void (PCMFramePtr pcmFrame, int index)> func, int funcIndex)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    m_isRun = true;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    mONEFrameSize = outOneFrameSize;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    mCallBackFunc = func;
 | 
	
		
			
				|  |  | +    mFuncIndex = funcIndex;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    //启动新的线程
 | 
	
		
			
				|  |  | +    std::thread([&](GetAudioThread *pointer)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        pointer->run();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    }, this).detach();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void GetAudioThread::pauseRecord()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    m_pause = true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void GetAudioThread::restoreRecord()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    m_getFirst = false;
 | 
	
		
			
				|  |  | +    m_pause = false;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void GetAudioThread::stopRecord()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    m_isRun = false;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +bool GetAudioThread::initResample()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    //重采样设置选项-----------------------------------------------------------start
 | 
	
		
			
				|  |  | +    aFrame_ReSample = nullptr;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    //frame->16bit 44100 PCM 统一音频采样格式与采样率
 | 
	
		
			
				|  |  | +    swrCtx = nullptr;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    //输入的声道布局
 | 
	
		
			
				|  |  | +    int in_ch_layout;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// 由于ffmpeg编码aac需要输入FLTP格式的数据。
 | 
	
		
			
				|  |  | +    /// 因此这里将音频重采样成44100 双声道  AV_SAMPLE_FMT_FLTP
 | 
	
		
			
				|  |  | +    //重采样设置选项----------------
 | 
	
		
			
				|  |  | +    //输入的采样格式
 | 
	
		
			
				|  |  | +    in_sample_fmt = aCodecCtx->sample_fmt;
 | 
	
		
			
				|  |  | +    //输出的采样格式 32bit PCM
 | 
	
		
			
				|  |  | +    out_sample_fmt = AV_SAMPLE_FMT_FLTP;
 | 
	
		
			
				|  |  | +    //输入的采样率
 | 
	
		
			
				|  |  | +    in_sample_rate = aCodecCtx->sample_rate;
 | 
	
		
			
				|  |  | +    //输入的声道布局
 | 
	
		
			
				|  |  | +    in_ch_layout = aCodecCtx->channel_layout;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    //输出的采样率
 | 
	
		
			
				|  |  | +    out_sample_rate = 44100;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    //输出的声道布局
 | 
	
		
			
				|  |  | +    out_ch_layout = AV_CH_LAYOUT_STEREO;
 | 
	
		
			
				|  |  | +    audio_tgt_channels = av_get_channel_layout_nb_channels(out_ch_layout);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//        //输出的声道布局
 | 
	
		
			
				|  |  | +//        out_ch_layout = av_get_default_channel_layout(audio_tgt_channels); ///AV_CH_LAYOUT_STEREO
 | 
	
		
			
				|  |  | +//        out_ch_layout &= ~AV_CH_LAYOUT_STEREO;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (in_ch_layout <= 0)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        if (aCodecCtx->channels == 2)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            in_ch_layout = AV_CH_LAYOUT_STEREO;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        else
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            in_ch_layout = AV_CH_LAYOUT_MONO;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    swrCtx = swr_alloc_set_opts(nullptr, out_ch_layout, out_sample_fmt, out_sample_rate,
 | 
	
		
			
				|  |  | +                                         in_ch_layout, in_sample_fmt, in_sample_rate, 0, nullptr);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /** Open the resampler with the specified parameters. */
 | 
	
		
			
				|  |  | +    int ret = swr_init(swrCtx);
 | 
	
		
			
				|  |  | +    if (ret < 0)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        char buff[128]={0};
 | 
	
		
			
				|  |  | +        av_strerror(ret, buff, 128);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        fprintf(stderr, "Could not open resample context %s\n", buff);
 | 
	
		
			
				|  |  | +        swr_free(&swrCtx);
 | 
	
		
			
				|  |  | +        swrCtx = nullptr;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        return false;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void GetAudioThread::run()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    struct SwsContext *img_convert_ctx = nullptr;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    AVPacket packet;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    int64_t firstTime = AppConfig::getTimeStamp_MilliSecond();
 | 
	
		
			
				|  |  | +    m_getFirst = false;
 | 
	
		
			
				|  |  | +    int64_t timeIndex = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    while(m_isRun)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        if (av_read_frame(pFormatCtx, &packet)<0)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            fprintf(stderr, "read failed! \n");
 | 
	
		
			
				|  |  | +            AppConfig::mSleep(10);
 | 
	
		
			
				|  |  | +            continue;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if (m_pause)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            av_packet_unref(&packet);
 | 
	
		
			
				|  |  | +            AppConfig::mSleep(10);
 | 
	
		
			
				|  |  | +            continue;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if(packet.stream_index == audioStream)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            int64_t time = 0;
 | 
	
		
			
				|  |  | +//            if (m_saveVideoFileThread)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                if (m_getFirst)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    int64_t secondTime = AppConfig::getTimeStamp_MilliSecond();
 | 
	
		
			
				|  |  | +                    time = secondTime - firstTime + timeIndex;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                else
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    firstTime = AppConfig::getTimeStamp_MilliSecond();
 | 
	
		
			
				|  |  | +                    timeIndex = 0;
 | 
	
		
			
				|  |  | +                    m_getFirst = true;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (int ret = avcodec_send_packet(aCodecCtx, &packet) && ret != 0)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +               char buffer[1024] = {0};
 | 
	
		
			
				|  |  | +               av_strerror(ret, buffer, 1024);
 | 
	
		
			
				|  |  | +               fprintf(stderr, "input AVPacket to decoder failed! ret = %d %s\n", ret, buffer);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            else
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +            //    while (0 == avcodec_receive_frame(pCodecCtx, pFrame))
 | 
	
		
			
				|  |  | +                while(1)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    int ret = avcodec_receive_frame(aCodecCtx, aFrame);
 | 
	
		
			
				|  |  | +                    if (ret != 0)
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +            //            char buffer[1024] = {0};
 | 
	
		
			
				|  |  | +            //            av_strerror(ret, buffer, 1024);
 | 
	
		
			
				|  |  | +            //            fprintf(stderr, "avcodec_receive_frame = %d %s\n", ret, buffer);
 | 
	
		
			
				|  |  | +                        break;
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    ///解码一帧后才能获取到采样率等信息,因此将初始化放到这里
 | 
	
		
			
				|  |  | +                    if (aFrame_ReSample == nullptr)
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +                        aFrame_ReSample = av_frame_alloc();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        int nb_samples = av_rescale_rnd(swr_get_delay(swrCtx, out_sample_rate) + aFrame->nb_samples, out_sample_rate, in_sample_rate, AV_ROUND_UP);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    //                    av_samples_fill_arrays(aFrame_ReSample->data, aFrame_ReSample->linesize, audio_buf_resample, audio_tgt_channels, aFrame_ReSample->nb_samples, out_sample_fmt, 0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        aFrame_ReSample->format = out_sample_fmt;
 | 
	
		
			
				|  |  | +                        aFrame_ReSample->channel_layout = out_ch_layout;
 | 
	
		
			
				|  |  | +                        aFrame_ReSample->sample_rate = out_sample_rate;
 | 
	
		
			
				|  |  | +                        aFrame_ReSample->nb_samples = nb_samples;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        ret = av_frame_get_buffer(aFrame_ReSample, 0);
 | 
	
		
			
				|  |  | +                        if (ret < 0)
 | 
	
		
			
				|  |  | +                        {
 | 
	
		
			
				|  |  | +                            fprintf(stderr, "Error allocating an audio buffer\n");
 | 
	
		
			
				|  |  | +                            exit(1);
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    ///执行重采样
 | 
	
		
			
				|  |  | +                    int len2 = swr_convert(swrCtx, aFrame_ReSample->data, aFrame_ReSample->nb_samples, (const uint8_t**)aFrame->data, aFrame->nb_samples);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    ///下面这两种方法计算的大小是一样的
 | 
	
		
			
				|  |  | +    #if 0
 | 
	
		
			
				|  |  | +                    int resampled_data_size = len2 * audio_tgt_channels * av_get_bytes_per_sample(out_sample_fmt);
 | 
	
		
			
				|  |  | +    #else
 | 
	
		
			
				|  |  | +                    int resampled_data_size = av_samples_get_buffer_size(NULL, audio_tgt_channels, aFrame_ReSample->nb_samples, out_sample_fmt, 1);
 | 
	
		
			
				|  |  | +    #endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    int OneChannelDataSize = resampled_data_size / audio_tgt_channels;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//fprintf(stderr, "OneChannelDataSize=%d %d %d\n", OneChannelDataSize, mAudioEncoder->getONEFrameSize(), aFrame->nb_samples);
 | 
	
		
			
				|  |  | +/// 由于平面模式的pcm存储方式为:LLLLLLLLLLLLLLLLLLLLLRRRRRRRRRRRRRRRRRRRRR,
 | 
	
		
			
				|  |  | +/// 因此这里需要将左右声道数据分开存入文件才可以正常播放。
 | 
	
		
			
				|  |  | +/// 使用播放器单独播放左右 声道数据测试即可(以单声道 44100 32bit打开播放)。
 | 
	
		
			
				|  |  | +//static FILE *fp1 = fopen("out-L.pcm", "wb");
 | 
	
		
			
				|  |  | +//fwrite(aFrame_ReSample->data[0], 1, OneChannelDataSize, fp1);
 | 
	
		
			
				|  |  | +//if (audio_tgt_channels >= 2)
 | 
	
		
			
				|  |  | +//{
 | 
	
		
			
				|  |  | +//    static FILE *fp2 = fopen("out-R.pcm", "wb");
 | 
	
		
			
				|  |  | +//    fwrite(aFrame_ReSample->data[1], 1, OneChannelDataSize, fp2);
 | 
	
		
			
				|  |  | +//}
 | 
	
		
			
				|  |  | +                    dealWithAudioFrame(OneChannelDataSize);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        else
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            fprintf(stderr, "other %d \n", packet.stream_index);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        av_packet_unref(&packet);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    sws_freeContext(img_convert_ctx);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    fprintf(stderr, "record stopping... \n");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    m_pause = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    deInit();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    fprintf(stderr, "record finished! \n");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void GetAudioThread::dealWithAudioFrame(const int &OneChannelDataSize)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    ///编码器一帧的采样为1024,而这里一次获取到的不是1024,因此需要放入队列,然后每次从队里取1024次采样交给编码器。
 | 
	
		
			
				|  |  | +    ///PS:平面模式的pcm存储方式为:LLLLLLLLLLLLLLLLLLLLLRRRRRRRRRRRRRRRRRRRRR,需要了解这句话的含义。
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    memcpy(audio_buf_L + audio_buf_size_L, aFrame_ReSample->data[0], OneChannelDataSize);
 | 
	
		
			
				|  |  | +    audio_buf_size_L += OneChannelDataSize;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (audio_tgt_channels >= 2)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        memcpy(audio_buf_R + audio_buf_size_R, aFrame_ReSample->data[1], OneChannelDataSize);
 | 
	
		
			
				|  |  | +        audio_buf_size_R += OneChannelDataSize;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    int index = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    int leftSize  = audio_buf_size_L;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    int ONEChannelAudioSize = mONEFrameSize / audio_tgt_channels;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    ///由于采集到的数据很大,而编码器一次只需要很少的数据。
 | 
	
		
			
				|  |  | +    ///因此将采集到的数据分成多次传给编码器。
 | 
	
		
			
				|  |  | +    /// 由于平面模式的pcm存储方式为:LLLLLLLLLLLLLLLLLLLLLRRRRRRRRRRRRRRRRRRRRR,因此这里合并完传给编码器就行了
 | 
	
		
			
				|  |  | +    while(1)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        if (leftSize >= ONEChannelAudioSize)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            uint8_t * buffer = (uint8_t *)malloc(ONEChannelAudioSize * audio_tgt_channels);
 | 
	
		
			
				|  |  | +            memcpy(buffer, audio_buf_L+index, ONEChannelAudioSize);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (audio_tgt_channels >= 2)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                memcpy(buffer+ONEChannelAudioSize, audio_buf_R+index, ONEChannelAudioSize);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            PCMFramePtr framePtr = std::make_shared<PCMFrame>();
 | 
	
		
			
				|  |  | +            framePtr->setFrameBuffer(buffer, ONEChannelAudioSize * audio_tgt_channels);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            free(buffer);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (mCallBackFunc != nullptr)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                mCallBackFunc(framePtr, mFuncIndex);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            index    += ONEChannelAudioSize;
 | 
	
		
			
				|  |  | +            leftSize -= ONEChannelAudioSize;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        else
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            if (leftSize > 0)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                memcpy(audio_buf_L, audio_buf_L+index, leftSize);
 | 
	
		
			
				|  |  | +                memcpy(audio_buf_R, audio_buf_R+index, leftSize);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            audio_buf_size_L = leftSize;
 | 
	
		
			
				|  |  | +            audio_buf_size_R = leftSize;
 | 
	
		
			
				|  |  | +            break;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 |