FFmpeg录屏录音(新版_测试版)

本博客介绍了一个使用Qt和FFmpeg实现的录屏和录音功能,支持开始、暂停和结束操作。通过封装FFmpeg API,实现了音视频的采集、编码和复用,生成多种格式的视频文件。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.youkuaiyun.com/ET_Endeavoring/article/details/88264693
Qt+FFmpeg录屏录音

录屏功能支持:开始,暂停,结束。
使用Qt+C++封装FFmpeg API,没有使用废弃的FFmpeg API。
主线程:Qt GUI线程,以后可接入录屏UI。
MuxThreadProc:复用线程,启动音视频采集线程。打开输入/输出流,然后从fifoBuffer读取帧,编码生成各种格式视频。
ScreenRecordThreadProc:视频采集线程,从输入流采集帧,缩放后写入fifoBuffer。
SoundRecordThreadProc:音频采集线程,从输入流采集样本,重采样后写入fifoBuffer。
ScreenRecordImpl.h
-#pragma once

  1. #include <Windows.h>
  2. #include <atomic>
  3. #include <QObject>
  4. #include <QString>
  5. #include <QMutex>
  6. #include <condition_variable>
  7.  
  8. #ifdef    __cplusplus
  9. extern "C"
  10. {
  11. #endif
  12. struct AVFormatContext;
  13. struct AVCodecContext;
  14. struct AVCodec;
  15. struct AVFifoBuffer;
  16. struct AVAudioFifo;
  17. struct AVFrame;
  18. struct SwsContext;
  19. struct SwrContext;
  20. #ifdef __cplusplus
  21. };
  22. #endif
  23.  
  24. class ScreenRecordImpl : public QObject
  25. {
  26.     Q_OBJECT
  27. private:
  28.     enum RecordState {
  29.         NotStarted,
  30.         Started,
  31.         Paused,
  32.         Stopped,
  33.         Unknown,
  34.     };
  35. public:
  36.     ScreenRecordImpl(QObject * parent = Q_NULLPTR);
  37.     void Init(const QVariantMap& map);
  38.  
  39.     private slots :
  40.     void Start();
  41.     void Pause();
  42.     void Stop();
  43.  
  44. private:
  45.     //从fifobuf读取音视频帧,写入输出流,复用,生成文件
  46.     void MuxThreadProc();
  47.     //从视频输入流读取帧,写入fifobuf
  48.     void ScreenRecordThreadProc();
  49.     //从音频输入流读取帧,写入fifobuf
  50.     void SoundRecordThreadProc();
  51.     int OpenVideo();
  52.     int OpenAudio();
  53.     int OpenOutput();
  54.     QString GetSpeakerDeviceName();
  55.     //获取麦克风设备名称
  56.     QString GetMicrophoneDeviceName();
  57.     AVFrame* AllocAudioFrame(AVCodecContext* c, int nbSamples);
  58.     void InitVideoBuffer();
  59.     void InitAudioBuffer();
  60.     void FlushVideoDecoder();
  61.     void FlushAudioDecoder();
  62.     //void FlushVideoEncoder();
  63.     //void FlushAudioEncoder();
  64.     void FlushEncoders();
  65.     void Release();
  66.  
  67. private:
  68.     QString                m_filePath;
  69.     int                    m_width;
  70.     int                    m_height;
  71.     int                    m_fps;
  72.     int                    m_audioBitrate;
  73.  
  74.     int m_vIndex;        //输入视频流索引
  75.     int m_aIndex;        //输入音频流索引
  76.     int m_vOutIndex;    //输出视频流索引
  77.     int m_aOutIndex;    //输出音频流索引
  78.     AVFormatContext        *m_vFmtCtx;
  79.     AVFormatContext        *m_aFmtCtx;
  80.     AVFormatContext        *m_oFmtCtx;
  81.     AVCodecContext        *m_vDecodeCtx;
  82.     AVCodecContext        *m_aDecodeCtx;
  83.     AVCodecContext        *m_vEncodeCtx;
  84.     AVCodecContext        *m_aEncodeCtx;
  85.     SwsContext            *m_swsCtx;
  86.     SwrContext            *m_swrCtx;
  87.     AVFifoBuffer        *m_vFifoBuf;
  88.     AVAudioFifo            *m_aFifoBuf;
  89.  
  90.     AVFrame                *m_vOutFrame;
  91.     uint8_t                *m_vOutFrameBuf;
  92.     int                    m_vOutFrameSize;
  93.  
  94.     int                    m_nbSamples;
  95.     RecordState            m_state;
  96.     std::condition_variable m_cvNotPause;    //当点击暂停的时候,两个采集线程挂起
  97.     std::mutex                m_mtxPause;
  98.     std::condition_variable m_cvVBufNotFull;
  99.     std::condition_variable m_cvVBufNotEmpty;
  100.     std::mutex                m_mtxVBuf;
  101.     std::condition_variable m_cvABufNotFull;
  102.     std::condition_variable m_cvABufNotEmpty;
  103.     std::mutex                m_mtxABuf;
  104.     int64_t                    m_vCurPts;
  105.     int64_t                    m_aCurPts;
  106. };

ScreenRecordImpl.cpp

  1. #ifdef    __cplusplus
  2. extern "C"
  3. {
  4. #endif
  5. #include "libavcodec/avcodec.h"
  6. #include "libavformat/avformat.h"
  7. #include "libswscale/swscale.h"
  8. #include "libavdevice/avdevice.h"
  9. #include "libavutil/audio_fifo.h"
  10. #include "libavutil/imgutils.h"
  11. #include "libswresample/swresample.h"
  12. #include <libavutil\avassert.h>
  13. #ifdef __cplusplus
  14. };
  15. #endif
  16.  
  17. #include "ScreenRecordImpl.h"
  18. #include <QDebug>
  19. #include <QAudioDeviceInfo>
  20. #include <thread>
  21. #include <fstream>
  22.  
  23. #include <dshow.h>
  24.  
  25. using namespace std;
  26.  
  27. int g_vCollectFrameCnt = 0;    //视频采集帧数
  28. int g_vEncodeFrameCnt = 0;    //视频编码帧数
  29. int g_aCollectFrameCnt = 0;    //音频采集帧数
  30. int g_aEncodeFrameCnt = 0;    //音频编码帧数
  31.  
  32. ScreenRecordImpl::ScreenRecordImpl(QObject * parent) :
  33.     QObject(parent)
  34.     , m_fps(30)
  35.     , m_vIndex(-1), m_aIndex(-1)
  36.     , m_vFmtCtx(nullptr), m_aFmtCtx(nullptr), m_oFmtCtx(nullptr)
  37.     , m_vDecodeCtx(nullptr), m_aDecodeCtx(nullptr)
  38.     , m_vEncodeCtx(nullptr), m_aEncodeCtx(nullptr)
  39.     , m_vFifoBuf(nullptr), m_aFifoBuf(nullptr)
  40.     , m_swsCtx(nullptr)
  41.     , m_swrCtx(nullptr)
  42.     , m_state(RecordState::NotStarted)
  43.     , m_vCurPts(0), m_aCurPts(0)
  44. {
  45. }
  46.  
  47. void ScreenRecordImpl::Init(const QVariantMap& map)
  48. {
  49.     m_filePath = map["filePath"].toString();
  50.     m_width = map["width"].toInt();
  51.     m_height = map["height"].toInt();
  52.     m_fps = map["fps"].toInt();
  53.     m_audioBitrate = map["audioBitrate"].toInt();
  54. }
  55.  
  56. void ScreenRecordImpl::Start()
  57. {
  58.     if (m_state == RecordState::NotStarted)
  59.     {
  60.         qDebug() << "start record";
  61.         m_state = RecordState::Started;
  62.         std::thread muxThread(&ScreenRecordImpl::MuxThreadProc, this);
  63.         muxThread.detach();
  64.     }
  65.     else if (m_state == RecordState::Paused)
  66.     {
  67.         qDebug() << "continue record";
  68.         m_state = RecordState::Started;
  69.         m_cvNotPause.notify_one();
  70.     }
  71. }
  72.  
  73. void ScreenRecordImpl::Pause()
  74. {
  75.     qDebug() << "pause record";
  76.     m_state = RecordState::Paused;
  77. }
  78.  
  79. void ScreenRecordImpl::Stop()
  80. {
  81.     qDebug() << "stop record";
  82.     RecordState state = m_state;
  83.     m_state = RecordState::Stopped;
  84.     if (state == RecordState::Paused)
  85.         m_cvNotPause.notify_one();
  86. }
  87.  
  88. int ScreenRecordImpl::OpenVideo()
  89. {
  90.     int ret = -1;
  91.     AVInputFormat *ifmt = av_find_input_format("gdigrab");
  92.     AVDictionary *options = nullptr;
  93.     AVCodec *decoder = nullptr;
  94.     av_dict_set(&options, "framerate", QString::number(m_fps).toStdString().c_str(), NULL);
  95.  
  96.     if (avformat_open_input(&m_vFmtCtx, "desktop", ifmt, &options) != 0)
  97.     {
  98.         qDebug() << "Cant not open video input stream";
  99.         return -1;
  100.     }
  101.     if (avformat_find_stream_info(m_vFmtCtx, nullptr) < 0)
  102.     {
  103.         printf("Couldn't find stream information.(无法获取视频流信息)\n");
  104.         return -1;
  105.     }
  106.     for (int i = 0; i < m_vFmtCtx->nb_streams; ++i)
  107.     {
  108.         AVStream *stream = m_vFmtCtx->streams[i];
  109.         if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
  110.         {
  111.             decoder = avcodec_find_decoder(stream->codecpar->codec_id);
  112.             if (decoder == nullptr)
  113.             {
  114.                 printf("Codec not found.(没有找到解码器)\n");
  115.                 return -1;
  116.             }
  117.             //从视频流中拷贝参数到codecCtx
  118.             m_vDecodeCtx = avcodec_alloc_context3(decoder);
  119.             if ((ret = avcodec_parameters_to_context(m_vDecodeCtx, stream->codecpar)) < 0)
  120.             {
  121.                 qDebug() << "Video avcodec_parameters_to_context failed,error code: " << ret;
  122.                 return -1;
  123.             }
  124.             m_vIndex = i;
  125.             break;
  126.         }
  127.     }
  128.     if (avcodec_open2(m_vDecodeCtx, decoder, nullptr) < 0)
  129.     {
  130.         printf("Could not open codec.(无法打开解码器)\n");
  131.         return -1;
  132.     }
  133.  
  134.     m_swsCtx = sws_getContext(m_vDecodeCtx->width, m_vDecodeCtx->height, m_vDecodeCtx->pix_fmt,
  135.         m_width, m_height, AV_PIX_FMT_YUV420P, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
  136.     return 0;
  137. }
  138.  
  139. static char *dup_wchar_to_utf8(wchar_t *w)
  140. {
  141.     char *s = NULL;
  142.     int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
  143.     s = (char *)av_malloc(l);
  144.     if (s)
  145.         WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
  146.     return s;
  147. }
  148.  
  149. static int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt)
  150. {
  151.     const enum AVSampleFormat *p = codec->sample_fmts;
  152.  
  153.     while (*p != AV_SAMPLE_FMT_NONE) {
  154.         if (*p == sample_fmt)
  155.             return 1;
  156.         p++;
  157.     }
  158.     return 0;
  159. }
  160.  
  161. int ScreenRecordImpl::OpenAudio()
  162. {
  163.     int ret = -1;
  164.     AVCodec *decoder = nullptr;
  165.     qDebug() << GetMicrophoneDeviceName();
  166.  
  167.     AVInputFormat *ifmt = av_find_input_format("dshow");
  168.     QString audioDeviceName = "audio=" + GetMicrophoneDeviceName();
  169.  
  170.     if (avformat_open_input(&m_aFmtCtx, audioDeviceName.toStdString().c_str(), ifmt, nullptr) < 0)
  171.     {
  172.         qDebug() << "Can not open audio input stream";
  173.         return -1;
  174.     }
  175.     if (avformat_find_stream_info(m_aFmtCtx, nullptr) < 0)
  176.         return -1;
  177.  
  178.     for (int i = 0; i < m_aFmtCtx->nb_streams; ++i)
  179.     {
  180.         AVStream * stream = m_aFmtCtx->streams[i];
  181.         if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
  182.         {
  183.             decoder = avcodec_find_decoder(stream->codecpar->codec_id);
  184.             if (decoder == nullptr)
  185.             {
  186.                 printf("Codec not found.(没有找到解码器)\n");
  187.                 return -1;
  188.             }
  189.             //从视频流中拷贝参数到codecCtx
  190.             m_aDecodeCtx = avcodec_alloc_context3(decoder);
  191.             if ((ret = avcodec_parameters_to_context(m_aDecodeCtx, stream->codecpar)) < 0)
  192.             {
  193.                 qDebug() << "Audio avcodec_parameters_to_context failed,error code: " << ret;
  194.                 return -1;
  195.             }
  196.             m_aIndex = i;
  197.             break;
  198.         }
  199.     }
  200.     if (0 > avcodec_open2(m_aDecodeCtx, decoder, NULL))
  201.     {
  202.         printf("can not find or open audio decoder!\n");
  203.         return -1;
  204.     }
  205.     return 0;
  206. }
  207.  
  208. int ScreenRecordImpl::OpenOutput()
  209. {
  210.     int ret = -1;
  211.     AVStream *vStream = nullptr, *aStream = nullptr;
  212.     const char *outFileName = "test.mp4";
  213.     ret = avformat_alloc_output_context2(&m_oFmtCtx, nullptr, nullptr, outFileName);
  214.     if (ret < 0)
  215.     {
  216.         qDebug() << "avformat_alloc_output_context2 failed";
  217.         return -1;
  218.     }
  219.  
  220.     if (m_vFmtCtx->streams[m_vIndex]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
  221.     {
  222.         vStream = avformat_new_stream(m_oFmtCtx, nullptr);
  223.         if (!vStream)
  224.         {
  225.             printf("can not new stream for output!\n");
  226.             return -1;
  227.         }
  228.         //AVFormatContext第一个创建的流索引是0,第二个创建的流索引是1
  229.         m_vOutIndex = vStream->index;
  230.         vStream->time_base = AVRational{ 1, m_fps };
  231.  
  232.         m_vEncodeCtx = avcodec_alloc_context3(NULL);
  233.         if (nullptr == m_vEncodeCtx)
  234.         {
  235.             qDebug() << "avcodec_alloc_context3 failed";
  236.             return -1;
  237.         }
  238.         m_vEncodeCtx->width = m_width;
  239.         m_vEncodeCtx->height = m_height;
  240.         m_vEncodeCtx->codec_type = AVMEDIA_TYPE_VIDEO;
  241.         m_vEncodeCtx->time_base.num = 1;
  242.         m_vEncodeCtx->time_base.den = m_fps;
  243.         m_vEncodeCtx->pix_fmt = AV_PIX_FMT_YUV420P;
  244.         m_vEncodeCtx->codec_id = AV_CODEC_ID_H264;
  245.         m_vEncodeCtx->bit_rate = 800 * 1000;
  246.         m_vEncodeCtx->rc_max_rate = 800 * 1000;
  247.         m_vEncodeCtx->rc_buffer_size = 500 * 1000;
  248.         //设置图像组层的大小, gop_size越大,文件越小 
  249.         m_vEncodeCtx->gop_size = 30;
  250.         m_vEncodeCtx->max_b_frames = 3;
  251.          //设置h264中相关的参数,不设置avcodec_open2会失败
  252.         m_vEncodeCtx->qmin = 10;    //2
  253.         m_vEncodeCtx->qmax = 31;    //31
  254.         m_vEncodeCtx->max_qdiff = 4;
  255.         m_vEncodeCtx->me_range = 16;    //0    
  256.         m_vEncodeCtx->max_qdiff = 4;    //3    
  257.         m_vEncodeCtx->qcompress = 0.6;    //0.5
  258.  
  259.         //查找视频编码器
  260.         AVCodec *encoder;
  261.         encoder = avcodec_find_encoder(m_vEncodeCtx->codec_id);
  262.         if (!encoder)
  263.         {
  264.             qDebug() << "Can not find the encoder, id: " << m_vEncodeCtx->codec_id;
  265.             return -1;
  266.         }
  267.         m_vEncodeCtx->codec_tag = 0;
  268.         //正确设置sps/pps
  269.         m_vEncodeCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
  270.         //打开视频编码器
  271.         ret = avcodec_open2(m_vEncodeCtx, encoder, nullptr);
  272.         if (ret < 0)
  273.         {
  274.             qDebug() << "Can not open encoder id: " << encoder->id << "error code: " << ret;
  275.             return -1;
  276.         }
  277.         //将codecCtx中的参数传给输出流
  278.         ret = avcodec_parameters_from_context(vStream->codecpar, m_vEncodeCtx);
  279.         if (ret < 0)
  280.         {
  281.             qDebug() << "Output avcodec_parameters_from_context,error code:" << ret;
  282.             return -1;
  283.         }
  284.     }
  285.     if (m_aFmtCtx->streams[m_aIndex]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
  286.     {
  287.         aStream = avformat_new_stream(m_oFmtCtx, NULL);
  288.         if (!aStream)
  289.         {
  290.             printf("can not new audio stream for output!\n");
  291.             return -1;
  292.         }
  293.         m_aOutIndex = aStream->index;
  294.  
  295.         AVCodec *encoder = avcodec_find_encoder(m_oFmtCtx->oformat->audio_codec);
  296.         if (!encoder)
  297.         {
  298.             qDebug() << "Can not find audio encoder, id: " << m_oFmtCtx->oformat->audio_codec;
  299.             return -1;
  300.         }
  301.         m_aEncodeCtx = avcodec_alloc_context3(encoder);
  302.         if (nullptr == m_vEncodeCtx)
  303.         {
  304.             qDebug() << "audio avcodec_alloc_context3 failed";
  305.             return -1;
  306.         }
  307.         m_aEncodeCtx->sample_fmt = encoder->sample_fmts ? encoder->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;
  308.         m_aEncodeCtx->bit_rate = m_audioBitrate;
  309.         m_aEncodeCtx->sample_rate = 44100;
  310.         if (encoder->supported_samplerates) 
  311.         {
  312.             m_aEncodeCtx->sample_rate = encoder->supported_samplerates[0];
  313.             for (int i = 0; encoder->supported_samplerates[i]; ++i)
  314.             {
  315.                 if (encoder->supported_samplerates[i] == 44100)
  316.                     m_aEncodeCtx->sample_rate = 44100;
  317.             }
  318.         }
  319.         m_aEncodeCtx->channels = av_get_channel_layout_nb_channels(m_aEncodeCtx->channel_layout);
  320.         m_aEncodeCtx->channel_layout = AV_CH_LAYOUT_STEREO;
  321.         if (encoder->channel_layouts) 
  322.         {
  323.             m_aEncodeCtx->channel_layout = encoder->channel_layouts[0];
  324.             for (int i = 0; encoder->channel_layouts[i]; ++i) 
  325.             {
  326.                 if (encoder->channel_layouts[i] == AV_CH_LAYOUT_STEREO)
  327.                     m_aEncodeCtx->channel_layout = AV_CH_LAYOUT_STEREO;
  328.             }
  329.         }
  330.         m_aEncodeCtx->channels = av_get_channel_layout_nb_channels(m_aEncodeCtx->channel_layout);
  331.         aStream->time_base = AVRational{ 1, m_aEncodeCtx->sample_rate };
  332.  
  333.         m_aEncodeCtx->codec_tag = 0;
  334.         m_aEncodeCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
  335.  
  336.         if (!check_sample_fmt(encoder, m_aEncodeCtx->sample_fmt)) 
  337.         {
  338.             qDebug() << "Encoder does not support sample format " << av_get_sample_fmt_name(m_aEncodeCtx->sample_fmt);
  339.             return -1;
  340.         }
  341.  
  342.         //打开音频编码器,打开后frame_size被设置
  343.         ret = avcodec_open2(m_aEncodeCtx, encoder, 0);
  344.         if (ret < 0)
  345.         {
  346.             qDebug() << "Can not open the audio encoder, id: " << encoder->id << "error code: " << ret;
  347.             return -1;
  348.         }
  349.         //将codecCtx中的参数传给音频输出流
  350.         ret = avcodec_parameters_from_context(aStream->codecpar, m_aEncodeCtx);
  351.         if (ret < 0)
  352.         {
  353.             qDebug() << "Output audio avcodec_parameters_from_context,error code:" << ret;
  354.             return -1;
  355.         }
  356.  
  357.         m_swrCtx = swr_alloc();
  358.         if (!m_swrCtx)
  359.         {
  360.             qDebug() << "swr_alloc failed";
  361.             return -1;
  362.         }
  363.         av_opt_set_int(m_swrCtx, "in_channel_count", m_aDecodeCtx->channels, 0);    //2
  364.         av_opt_set_int(m_swrCtx, "in_sample_rate", m_aDecodeCtx->sample_rate, 0);    //44100
  365.         av_opt_set_sample_fmt(m_swrCtx, "in_sample_fmt", m_aDecodeCtx->sample_fmt, 0);    //AV_SAMPLE_FMT_S16
  366.         av_opt_set_int(m_swrCtx, "out_channel_count", m_aEncodeCtx->channels, 0);    //2
  367.         av_opt_set_int(m_swrCtx, "out_sample_rate", m_aEncodeCtx->sample_rate, 0);    //44100
  368.         av_opt_set_sample_fmt(m_swrCtx, "out_sample_fmt", m_aEncodeCtx->sample_fmt, 0);    //AV_SAMPLE_FMT_FLTP
  369.  
  370.         if ((ret = swr_init(m_swrCtx)) < 0) 
  371.         {
  372.             qDebug() << "swr_init failed";
  373.             return -1;
  374.         }
  375.     }
  376.  
  377.     //打开输出文件
  378.     if (!(m_oFmtCtx->oformat->flags & AVFMT_NOFILE))
  379.     {
  380.         if (avio_open(&m_oFmtCtx->pb, outFileName, AVIO_FLAG_WRITE) < 0)
  381.         {
  382.             printf("can not open output file handle!\n");
  383.             return -1;
  384.         }
  385.     }
  386.     //写文件头
  387.     if (avformat_write_header(m_oFmtCtx, nullptr) < 0)
  388.     {
  389.         printf("can not write the header of the output file!\n");
  390.         return -1;
  391.     }
  392.     return 0;
  393. }
  394.  
  395. QString ScreenRecordImpl::GetSpeakerDeviceName()
  396. {
  397.     char sName[256] = { 0 };
  398.     QString speaker = "";
  399.     bool bRet = false;
  400.     ::CoInitialize(NULL);
  401.  
  402.     ICreateDevEnum* pCreateDevEnum;//enumrate all speaker devices
  403.     HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum,
  404.         NULL,
  405.         CLSCTX_INPROC_SERVER,
  406.         IID_ICreateDevEnum,
  407.         (void**)&pCreateDevEnum);
  408.  
  409.     IEnumMoniker* pEm;
  410.     hr = pCreateDevEnum->CreateClassEnumerator(CLSID_AudioRendererCategory, &pEm, 0);
  411.     if (hr != NOERROR)
  412.     {
  413.         ::CoUninitialize();
  414.         return "";
  415.     }
  416.  
  417.     pEm->Reset();
  418.     ULONG cFetched;
  419.     IMoniker *pM;
  420.     while (hr = pEm->Next(1, &pM, &cFetched), hr == S_OK)
  421.     {
  422.  
  423.         IPropertyBag* pBag = NULL;
  424.         hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pBag);
  425.         if (SUCCEEDED(hr))
  426.         {
  427.             VARIANT var;
  428.             var.vt = VT_BSTR;
  429.             hr = pBag->Read(L"FriendlyName", &var, NULL);//还有其他属性,像描述信息等等
  430.             if (hr == NOERROR)
  431.             {
  432.                 //获取设备名称
  433.                 WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, sName, 256, "", NULL);
  434.                 speaker = QString::fromLocal8Bit(sName);
  435.                 SysFreeString(var.bstrVal);
  436.             }
  437.             pBag->Release();
  438.         }
  439.         pM->Release();
  440.         bRet = true;
  441.     }
  442.     pCreateDevEnum = NULL;
  443.     pEm = NULL;
  444.     ::CoUninitialize();
  445.     return speaker;
  446. }
  447.  
  448. QString ScreenRecordImpl::GetMicrophoneDeviceName()
  449. {
  450.     char sName[256] = { 0 };
  451.     QString capture = "";
  452.     bool bRet = false;
  453.     ::CoInitialize(NULL);
  454.  
  455.     ICreateDevEnum* pCreateDevEnum;//enumrate all audio capture devices
  456.     HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum,
  457.         NULL,
  458.         CLSCTX_INPROC_SERVER,
  459.         IID_ICreateDevEnum,
  460.         (void**)&pCreateDevEnum);
  461.  
  462.     IEnumMoniker* pEm;
  463.     hr = pCreateDevEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory, &pEm, 0);
  464.     if (hr != NOERROR)
  465.     {
  466.         ::CoUninitialize();
  467.         return "";
  468.     }
  469.  
  470.     pEm->Reset();
  471.     ULONG cFetched;
  472.     IMoniker *pM;
  473.     while (hr = pEm->Next(1, &pM, &cFetched), hr == S_OK)
  474.     {
  475.  
  476.         IPropertyBag* pBag = NULL;
  477.         hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pBag);
  478.         if (SUCCEEDED(hr))
  479.         {
  480.             VARIANT var;
  481.             var.vt = VT_BSTR;
  482.             hr = pBag->Read(L"FriendlyName", &var, NULL);//还有其他属性,像描述信息等等
  483.             if (hr == NOERROR)
  484.             {
  485.                 //获取设备名称
  486.                 WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, sName, 256, "", NULL);
  487.                 capture = QString::fromLocal8Bit(sName);
  488.                 SysFreeString(var.bstrVal);
  489.             }
  490.             pBag->Release();
  491.         }
  492.         pM->Release();
  493.         bRet = true;
  494.     }
  495.     pCreateDevEnum = NULL;
  496.     pEm = NULL;
  497.     ::CoUninitialize();
  498.     return capture;
  499. }
  500.  
  501. AVFrame* ScreenRecordImpl::AllocAudioFrame(AVCodecContext* c, int nbSamples)
  502. {
  503.     AVFrame *frame = av_frame_alloc();
  504.     int ret;
  505.  
  506.     frame->format = c->sample_fmt;
  507.     frame->channel_layout = c->channel_layout ? c->channel_layout: AV_CH_LAYOUT_STEREO;
  508.     frame->sample_rate = c->sample_rate;
  509.     frame->nb_samples = nbSamples;
  510.  
  511.     if (nbSamples)
  512.     {
  513.         ret = av_frame_get_buffer(frame, 0);
  514.         if (ret < 0) 
  515.         {
  516.             qDebug() << "av_frame_get_buffer failed";
  517.             return nullptr;
  518.         }
  519.     }
  520.     return frame;
  521. }
  522.  
  523. void ScreenRecordImpl::InitVideoBuffer()
  524. {
  525.     m_vOutFrameSize = av_image_get_buffer_size(m_vEncodeCtx->pix_fmt, m_width, m_height, 1);
  526.     m_vOutFrameBuf = (uint8_t *)av_malloc(m_vOutFrameSize);
  527.     m_vOutFrame = av_frame_alloc();
  528.     //先让AVFrame指针指向buf,后面再写入数据到buf
  529.     av_image_fill_arrays(m_vOutFrame->data, m_vOutFrame->linesize, m_vOutFrameBuf, m_vEncodeCtx->pix_fmt, m_width, m_height, 1);
  530.     //申请30帧缓存
  531.     if (!(m_vFifoBuf = av_fifo_alloc_array(30, m_vOutFrameSize)))
  532.     {
  533.         qDebug() << "av_fifo_alloc_array failed";
  534.         return;
  535.     }
  536. }
  537.  
  538. void ScreenRecordImpl::InitAudioBuffer()
  539. {
  540.     m_nbSamples = m_aEncodeCtx->frame_size;
  541.     if (!m_nbSamples)
  542.     {
  543.         qDebug() << "m_nbSamples==0";
  544.         m_nbSamples = 1024;
  545.     }
  546.     m_aFifoBuf = av_audio_fifo_alloc(m_aEncodeCtx->sample_fmt, m_aEncodeCtx->channels, 30 * m_nbSamples);
  547.     if (!m_aFifoBuf)
  548.     {
  549.         qDebug() << "av_audio_fifo_alloc failed";
  550.         return;
  551.     }
  552. }
  553.  
  554. void ScreenRecordImpl::FlushVideoDecoder()
  555. {
  556.     int ret = -1;
  557.     int y_size = m_width * m_height;
  558.     AVFrame    *oldFrame = av_frame_alloc();
  559.     AVFrame *newFrame = av_frame_alloc();
  560.  
  561.     ret = avcodec_send_packet(m_vDecodeCtx, nullptr);
  562.     if (ret != 0)
  563.     {
  564.         qDebug() << "flush video avcodec_send_packet failed, ret: " << ret;
  565.         return;
  566.     }
  567.     while (ret >= 0)
  568.     {
  569.         ret = avcodec_receive_frame(m_vDecodeCtx, oldFrame);
  570.         if (ret < 0)
  571.         {
  572.             if (ret == AVERROR(EAGAIN))
  573.             {
  574.                 qDebug() << "flush EAGAIN avcodec_receive_frame";
  575.                 ret = 1;
  576.                 continue;
  577.             }
  578.             else if (ret == AVERROR_EOF)
  579.             {
  580.                 qDebug() << "flush video decoder finished";
  581.                 break;
  582.             }
  583.             qDebug() << "flush video avcodec_receive_frame error, ret: " << ret;
  584.             return;
  585.         }
  586.         ++g_vCollectFrameCnt;
  587.         sws_scale(m_swsCtx, (const uint8_t* const*)oldFrame->data, oldFrame->linesize, 0,
  588.             m_vEncodeCtx->height, newFrame->data, newFrame->linesize);
  589.  
  590.         {
  591.             unique_lock<mutex> lk(m_mtxVBuf);
  592.             m_cvVBufNotFull.wait(lk, [this] { return av_fifo_space(m_vFifoBuf) >= m_vOutFrameSize; });
  593.         }
  594.         av_fifo_generic_write(m_vFifoBuf, newFrame->data[0], y_size, NULL);
  595.         av_fifo_generic_write(m_vFifoBuf, newFrame->data[1], y_size / 4, NULL);
  596.         av_fifo_generic_write(m_vFifoBuf, newFrame->data[2], y_size / 4, NULL);
  597.         m_cvVBufNotEmpty.notify_one();
  598.     }
  599.     qDebug() << "video collect frame count: " << g_vCollectFrameCnt;
  600. }
  601.  
  602. //void ScreenRecordImpl::FlushVideoEncoder()
  603. //{
  604. //    int ret = -1;
  605. //    AVPacket pkt = { 0 };
  606. //    av_init_packet(&pkt);
  607. //    ret = avcodec_send_frame(m_vEncodeCtx, nullptr);
  608. //    qDebug() << "avcodec_send_frame ret:" << ret;
  609. //    while (ret >= 0)
  610. //    {
  611. //        ret = avcodec_receive_packet(m_vEncodeCtx, &pkt);
  612. //        if (ret < 0)
  613. //        {
  614. //            av_packet_unref(&pkt);
  615. //            if (ret == AVERROR(EAGAIN))
  616. //            {
  617. //                qDebug() << "flush EAGAIN avcodec_receive_packet";
  618. //                ret = 1;
  619. //                continue;
  620. //            }
  621. //            else if (ret == AVERROR_EOF)
  622. //            {
  623. //                qDebug() << "flush video encoder finished";
  624. //                break;
  625. //            }
  626. //            qDebug() << "flush video avcodec_receive_packet failed, ret: " << ret;
  627. //            return;
  628. //        }
  629. //        pkt.stream_index = m_vOutIndex;
  630. //        av_packet_rescale_ts(&pkt, m_vEncodeCtx->time_base, m_oFmtCtx->streams[m_vOutIndex]->time_base);
  631. //
  632. //        ret = av_interleaved_write_frame(m_oFmtCtx, &pkt);
  633. //        if (ret == 0)
  634. //            qDebug() << "flush Write video packet id: " << ++g_vEncodeFrameCnt;
  635. //        else
  636. //            qDebug() << "video av_interleaved_write_frame failed, ret:" << ret;
  637. //        av_free_packet(&pkt);
  638. //    }
  639. //}
  640.  
  641. void ScreenRecordImpl::FlushAudioDecoder()
  642. {
  643.     int ret = -1;
  644.     AVPacket pkt = { 0 };
  645.     av_init_packet(&pkt);
  646.     int dstNbSamples, maxDstNbSamples;
  647.     AVFrame *rawFrame = av_frame_alloc();
  648.     AVFrame *newFrame = AllocAudioFrame(m_aEncodeCtx, m_nbSamples);
  649.     maxDstNbSamples = dstNbSamples = av_rescale_rnd(m_nbSamples,
  650.         m_aEncodeCtx->sample_rate, m_aDecodeCtx->sample_rate, AV_ROUND_UP);
  651.  
  652.     ret = avcodec_send_packet(m_aDecodeCtx, nullptr);
  653.     if (ret != 0)
  654.     {
  655.         qDebug() << "flush audio avcodec_send_packet  failed, ret: " << ret;
  656.         return;
  657.     }
  658.     while (ret >= 0)
  659.     {
  660.         ret = avcodec_receive_frame(m_aDecodeCtx, rawFrame);
  661.         if (ret < 0)
  662.         {
  663.             if (ret == AVERROR(EAGAIN))
  664.             {
  665.                 qDebug() << "flush audio EAGAIN avcodec_receive_frame";
  666.                 ret = 1;
  667.                 continue;
  668.             }
  669.             else if (ret == AVERROR_EOF)
  670.             {
  671.                 qDebug() << "flush audio decoder finished";
  672.                 break;
  673.             }
  674.             qDebug() << "flush audio avcodec_receive_frame error, ret: " << ret;
  675.             return;
  676.         }
  677.         ++g_aCollectFrameCnt;
  678.  
  679.         dstNbSamples = av_rescale_rnd(swr_get_delay(m_swrCtx, m_aDecodeCtx->sample_rate) + rawFrame->nb_samples,
  680.             m_aEncodeCtx->sample_rate, m_aDecodeCtx->sample_rate, AV_ROUND_UP);
  681.         if (dstNbSamples > maxDstNbSamples)
  682.         {
  683.             qDebug() << "flush audio newFrame realloc";
  684.             av_freep(&newFrame->data[0]);
  685.             ret = av_samples_alloc(newFrame->data, newFrame->linesize, m_aEncodeCtx->channels,
  686.                 dstNbSamples, m_aEncodeCtx->sample_fmt, 1);
  687.             if (ret < 0)
  688.             {
  689.                 qDebug() << "flush av_samples_alloc failed";
  690.                 return;
  691.             }
  692.             maxDstNbSamples = dstNbSamples;
  693.             m_aEncodeCtx->frame_size = dstNbSamples;
  694.             m_nbSamples = newFrame->nb_samples;
  695.         }
  696.         newFrame->nb_samples = swr_convert(m_swrCtx, newFrame->data, dstNbSamples,
  697.             (const uint8_t **)rawFrame->data, rawFrame->nb_samples);
  698.         if (newFrame->nb_samples < 0)
  699.         {
  700.             qDebug() << "flush swr_convert failed";
  701.             return;
  702.         }
  703.  
  704.         {
  705.             unique_lock<mutex> lk(m_mtxABuf);
  706.             m_cvABufNotFull.wait(lk, [newFrame, this] { return av_audio_fifo_space(m_aFifoBuf) >= newFrame->nb_samples; });
  707.         }
  708.         if (av_audio_fifo_write(m_aFifoBuf, (void **)newFrame->data, newFrame->nb_samples) < newFrame->nb_samples)
  709.         {
  710.             qDebug() << "av_audio_fifo_write";
  711.             return;
  712.         }
  713.         m_cvABufNotEmpty.notify_one();
  714.     }
  715.     qDebug() << "audio collect frame count: " << g_aCollectFrameCnt;
  716. }
  717.  
  718. //void ScreenRecordImpl::FlushAudioEncoder()
  719. //{
  720. //}
  721.  
  722. void ScreenRecordImpl::FlushEncoders()
  723. {
  724.     int ret = -1;
  725.     bool vBeginFlush = false;
  726.     bool aBeginFlush = false;
  727.  
  728.     m_vCurPts = m_aCurPts = 0;
  729.  
  730.     int nFlush = 2;
  731.  
  732.     while (1)
  733.     {
  734.         AVPacket pkt = { 0 };
  735.         av_init_packet(&pkt);
  736.         if (av_compare_ts(m_vCurPts, m_oFmtCtx->streams[m_vOutIndex]->time_base,
  737.             m_aCurPts, m_oFmtCtx->streams[m_aOutIndex]->time_base) <= 0)
  738.         {
  739.             if (!vBeginFlush)
  740.             {
  741.                 vBeginFlush = true;
  742.                 ret = avcodec_send_frame(m_vEncodeCtx, nullptr);
  743.                 if (ret != 0)
  744.                 {
  745.                     qDebug() << "flush video avcodec_send_frame failed, ret: " << ret;
  746.                     return;
  747.                 }
  748.             }
  749.             ret = avcodec_receive_packet(m_vEncodeCtx, &pkt);
  750.             if (ret < 0)
  751.             {
  752.                 av_packet_unref(&pkt);
  753.                 if (ret == AVERROR(EAGAIN))
  754.                 {
  755.                     qDebug() << "flush video EAGAIN avcodec_receive_packet";
  756.                     ret = 1;
  757.                     continue;
  758.                 }
  759.                 else if (ret == AVERROR_EOF)
  760.                 {
  761.                     qDebug() << "flush video encoder finished";
  762.                     //break;
  763.                     if (!(--nFlush))
  764.                         break;
  765.                     m_vCurPts = INT_MAX;
  766.                     continue;
  767.                 }
  768.                 qDebug() << "flush video avcodec_receive_packet failed, ret: " << ret;
  769.                 return;
  770.             }
  771.             pkt.stream_index = m_vOutIndex;
  772.             //将pts从编码层的timebase转成复用层的timebase
  773.             av_packet_rescale_ts(&pkt, m_vEncodeCtx->time_base, m_oFmtCtx->streams[m_vOutIndex]->time_base);
  774.             m_vCurPts = pkt.pts;
  775.             qDebug() << "m_vCurPts: " << m_vCurPts;
  776.  
  777.             ret = av_interleaved_write_frame(m_oFmtCtx, &pkt);
  778.             if (ret == 0)
  779.                 qDebug() << "flush Write video packet id: " << ++g_vEncodeFrameCnt;
  780.             else
  781.                 qDebug() << "flush video av_interleaved_write_frame failed, ret:" << ret;
  782.             av_free_packet(&pkt);
  783.         }
  784.         else
  785.         {
  786.             if (!aBeginFlush)
  787.             {
  788.                 aBeginFlush = true;
  789.                 ret = avcodec_send_frame(m_aEncodeCtx, nullptr);
  790.                 if (ret != 0)
  791.                 {
  792.                     qDebug() << "flush audio avcodec_send_frame failed, ret: " << ret;
  793.                     return;
  794.                 }
  795.             }
  796.             ret = avcodec_receive_packet(m_aEncodeCtx, &pkt);
  797.             if (ret < 0)
  798.             {
  799.                 av_packet_unref(&pkt);
  800.                 if (ret == AVERROR(EAGAIN))
  801.                 {
  802.                     qDebug() << "flush EAGAIN avcodec_receive_packet";
  803.                     ret = 1;
  804.                     continue;
  805.                 }
  806.                 else if (ret == AVERROR_EOF)
  807.                 {
  808.                     qDebug() << "flush audio encoder finished";
  809.                     /*break;*/
  810.                     if (!(--nFlush))
  811.                         break;
  812.                     m_aCurPts = INT_MAX;
  813.                     continue;
  814.                 }
  815.                 qDebug() << "flush audio avcodec_receive_packet failed, ret: " << ret;
  816.                 return;
  817.             }
  818.             pkt.stream_index = m_aOutIndex;
  819.             //将pts从编码层的timebase转成复用层的timebase
  820.             av_packet_rescale_ts(&pkt, m_aEncodeCtx->time_base, m_oFmtCtx->streams[m_aOutIndex]->time_base);
  821.             m_aCurPts = pkt.pts;
  822.             qDebug() << "m_aCurPts: " << m_aCurPts;
  823.             ret = av_interleaved_write_frame(m_oFmtCtx, &pkt);
  824.             if (ret == 0)
  825.                 qDebug() << "flush write audio packet id: " << ++g_aEncodeFrameCnt;
  826.             else
  827.                 qDebug() << "flush audio av_interleaved_write_frame failed, ret: " << ret;
  828.             av_free_packet(&pkt);
  829.         }
  830.     }
  831. }
  832.  
  833. void ScreenRecordImpl::Release()
  834. {
  835.     if (m_vOutFrame)
  836.     {
  837.         av_frame_free(&m_vOutFrame);
  838.         m_vOutFrame = nullptr;
  839.     }
  840.     if (m_vOutFrameBuf)
  841.     {
  842.         av_free(m_vOutFrameBuf);
  843.         m_vOutFrameBuf = nullptr;
  844.     }
  845.     if (m_oFmtCtx)
  846.     {
  847.         avio_close(m_oFmtCtx->pb);
  848.         avformat_free_context(m_oFmtCtx);
  849.         m_oFmtCtx = nullptr;
  850.     }
  851.     if (m_vDecodeCtx)
  852.     {
  853.         avcodec_free_context(&m_vDecodeCtx);
  854.         m_vDecodeCtx = nullptr;
  855.     }
  856.     if (m_aDecodeCtx)
  857.     {
  858.         avcodec_free_context(&m_aDecodeCtx);
  859.         m_aDecodeCtx = nullptr;
  860.     }
  861.     if (m_vEncodeCtx)
  862.     {
  863.         avcodec_free_context(&m_vEncodeCtx);
  864.         m_vEncodeCtx = nullptr;
  865.     }
  866.     if (m_aEncodeCtx)
  867.     {
  868.         avcodec_free_context(&m_aEncodeCtx);
  869.         m_aEncodeCtx = nullptr;
  870.     }
  871.     if (m_vFifoBuf)
  872.     {
  873.         av_fifo_freep(&m_vFifoBuf);
  874.         m_vFifoBuf = nullptr;
  875.     }
  876.     if (m_aFifoBuf)
  877.     {
  878.         av_audio_fifo_free(m_aFifoBuf);
  879.         m_aFifoBuf = nullptr;
  880.     }
  881.     if (m_vFmtCtx)
  882.     {
  883.         avformat_close_input(&m_vFmtCtx);
  884.         m_vFmtCtx = nullptr;
  885.     }
  886.     if (m_aFmtCtx)
  887.     {
  888.         avformat_close_input(&m_aFmtCtx);
  889.         m_aFmtCtx = nullptr;
  890.     }
  891. }
  892.  
  893. void ScreenRecordImpl::MuxThreadProc()
  894. {
  895.     int ret = -1;
  896.     bool done = false;
  897.     int vFrameIndex = 0, aFrameIndex = 0;
  898.  
  899.     av_register_all();
  900.     avdevice_register_all();
  901.     avcodec_register_all();
  902.  
  903.     if (OpenVideo() < 0)
  904.         return;
  905.     if (OpenAudio() < 0)
  906.         return;
  907.     if (OpenOutput() < 0)
  908.         return;
  909.  
  910.     InitVideoBuffer();
  911.     InitAudioBuffer();
  912.  
  913.     //启动音视频数据采集线程
  914.     std::thread screenRecord(&ScreenRecordImpl::ScreenRecordThreadProc, this);
  915.     std::thread soundRecord(&ScreenRecordImpl::SoundRecordThreadProc, this);
  916.     screenRecord.detach();
  917.     soundRecord.detach();
  918.  
  919.     while (1)
  920.     {
  921.         if (m_state == RecordState::Stopped && !done)
  922.             done = true;
  923.         if (done)
  924.         {
  925.             unique_lock<mutex> vBufLock(m_mtxVBuf, std::defer_lock);
  926.             unique_lock<mutex> aBufLock(m_mtxABuf, std::defer_lock);
  927.             std::lock(vBufLock, aBufLock);
  928.             if (av_fifo_size(m_vFifoBuf) < m_vOutFrameSize &&
  929.                 av_audio_fifo_size(m_aFifoBuf) < m_nbSamples)
  930.             {
  931.                 qDebug() << "both video and audio fifo buf are empty, break";
  932.                 break;
  933.             }
  934.         }
  935.         if (av_compare_ts(m_vCurPts, m_oFmtCtx->streams[m_vOutIndex]->time_base,
  936.             m_aCurPts, m_oFmtCtx->streams[m_aOutIndex]->time_base) <= 0)
  937.     /*    if (av_compare_ts(vCurPts, m_vEncodeCtx->time_base,
  938.             aCurPts, m_aEncodeCtx->time_base) <= 0)*/
  939.         {
  940.             if (done)
  941.             {
  942.                 lock_guard<mutex> lk(m_mtxVBuf);
  943.                 if (av_fifo_size(m_vFifoBuf) < m_vOutFrameSize)
  944.                 {
  945.                     qDebug() << "video wirte done";
  946.                     //break;
  947.                     //m_vCurPts = 0x7ffffffffffffffe;    //int64_t最大有符号整数
  948.                     m_vCurPts = INT_MAX;
  949.                     continue;
  950.                 }
  951.             }
  952.             else 
  953.             {
  954.                 unique_lock<mutex> lk(m_mtxVBuf);
  955.                 m_cvVBufNotEmpty.wait(lk, [this] { return av_fifo_size(m_vFifoBuf) >= m_vOutFrameSize; });
  956.             }
  957.             av_fifo_generic_read(m_vFifoBuf, m_vOutFrameBuf, m_vOutFrameSize, NULL);
  958.             m_cvVBufNotFull.notify_one();
  959.  
  960.             //设置视频帧参数
  961.             //m_vOutFrame->pts = vFrameIndex * ((m_oFmtCtx->streams[m_vOutIndex]->time_base.den / m_oFmtCtx->streams[m_vOutIndex]->time_base.num) / m_fps);
  962.             m_vOutFrame->pts = vFrameIndex++;
  963.             m_vOutFrame->format = m_vEncodeCtx->pix_fmt;
  964.             m_vOutFrame->width = m_vEncodeCtx->width;
  965.             m_vOutFrame->height = m_vEncodeCtx->height;
  966.  
  967.             AVPacket pkt = { 0 };
  968.             av_init_packet(&pkt);
  969.             ret = avcodec_send_frame(m_vEncodeCtx, m_vOutFrame);
  970.             if (ret != 0)
  971.             {
  972.                 qDebug() << "video avcodec_send_frame failed, ret: " << ret;
  973.                 av_packet_unref(&pkt);
  974.                 continue;
  975.             }
  976.             ret = avcodec_receive_packet(m_vEncodeCtx, &pkt);
  977.             if (ret != 0)
  978.             {
  979.                 qDebug() << "video avcodec_receive_packet failed, ret: " << ret;
  980.                 av_packet_unref(&pkt);
  981.                 continue;
  982.             }
  983.             pkt.stream_index = m_vOutIndex;
  984.             //将pts从编码层的timebase转成复用层的timebase
  985.             av_packet_rescale_ts(&pkt, m_vEncodeCtx->time_base, m_oFmtCtx->streams[m_vOutIndex]->time_base);
  986.  
  987.             m_vCurPts = pkt.pts;
  988.             qDebug() << "m_vCurPts: " << m_vCurPts;
  989.  
  990.             ret = av_interleaved_write_frame(m_oFmtCtx, &pkt);
  991.             if (ret == 0)
  992.                 qDebug() << "Write video packet id: " << ++g_vEncodeFrameCnt;
  993.             else
  994.                 qDebug() << "video av_interleaved_write_frame failed, ret:" << ret;
  995.             av_free_packet(&pkt);
  996.         }
  997.         else
  998.         {
  999.             if (done)
  1000.             {
  1001.                 lock_guard<mutex> lk(m_mtxABuf);
  1002.                 if (av_audio_fifo_size(m_aFifoBuf) < m_nbSamples)
  1003.                 {
  1004.                     qDebug() << "audio write done";
  1005.                     //m_aCurPts = 0x7fffffffffffffff;
  1006.                     m_aCurPts = INT_MAX;
  1007.                     continue;
  1008.                 }
  1009.             }
  1010.             else
  1011.             {
  1012.                 unique_lock<mutex> lk(m_mtxABuf);
  1013.                 m_cvABufNotEmpty.wait(lk, [this] { return av_audio_fifo_size(m_aFifoBuf) >= m_nbSamples; });
  1014.             }
  1015.  
  1016.             int ret = -1;
  1017.             AVFrame *aFrame = av_frame_alloc();
  1018.             aFrame->nb_samples = m_nbSamples;
  1019.             aFrame->channel_layout = m_aEncodeCtx->channel_layout;
  1020.             aFrame->format = m_aEncodeCtx->sample_fmt;
  1021.             aFrame->sample_rate = m_aEncodeCtx->sample_rate;
  1022.             aFrame->pts = m_nbSamples * aFrameIndex++;
  1023.             //分配data buf
  1024.             ret = av_frame_get_buffer(aFrame, 0);
  1025.             av_audio_fifo_read(m_aFifoBuf, (void **)aFrame->data, m_nbSamples);
  1026.             m_cvABufNotFull.notify_one();
  1027.  
  1028.             AVPacket pkt = { 0 };
  1029.             av_init_packet(&pkt);
  1030.             ret = avcodec_send_frame(m_aEncodeCtx, aFrame);
  1031.             if (ret != 0)
  1032.             {
  1033.                 qDebug() << "audio avcodec_send_frame failed, ret: " << ret;
  1034.                 av_frame_free(&aFrame);
  1035.                 av_packet_unref(&pkt);
  1036.                 continue;
  1037.             }
  1038.             ret = avcodec_receive_packet(m_aEncodeCtx, &pkt);
  1039.             if (ret != 0)
  1040.             {
  1041.                 qDebug() << "audio avcodec_receive_packet failed, ret: " << ret;
  1042.                 av_frame_free(&aFrame);
  1043.                 av_packet_unref(&pkt);
  1044.                 continue;
  1045.             }
  1046.             pkt.stream_index = m_aOutIndex;
  1047.  
  1048.             av_packet_rescale_ts(&pkt, m_aEncodeCtx->time_base, m_oFmtCtx->streams[m_aOutIndex]->time_base);
  1049.  
  1050.             m_aCurPts = pkt.pts;
  1051.             qDebug() << "aCurPts: " << m_aCurPts;
  1052.  
  1053.             ret = av_interleaved_write_frame(m_oFmtCtx, &pkt);
  1054.             if (ret == 0)
  1055.                 qDebug() << "Write audio packet id: " << ++g_aEncodeFrameCnt;
  1056.             else
  1057.                 qDebug() << "audio av_interleaved_write_frame failed, ret: " << ret;
  1058.  
  1059.             av_frame_free(&aFrame);
  1060.             av_free_packet(&pkt);
  1061.         }
  1062.     }
  1063.     FlushEncoders();
  1064.     av_write_trailer(m_oFmtCtx);
  1065.     Release();
  1066.     qDebug() << "parent thread exit";
  1067. }
  1068.  
  1069. void ScreenRecordImpl::ScreenRecordThreadProc()
  1070. {
  1071.     int ret = -1;
  1072.     AVPacket pkt = { 0 };
  1073.     av_init_packet(&pkt);
  1074.     int y_size = m_width * m_height;
  1075.     AVFrame    *oldFrame = av_frame_alloc();
  1076.     AVFrame *newFrame = av_frame_alloc();
  1077.  
  1078.     int newFrameBufSize = av_image_get_buffer_size(m_vEncodeCtx->pix_fmt, m_width, m_height, 1);
  1079.     uint8_t *newFrameBuf = (uint8_t*)av_malloc(newFrameBufSize);
  1080.     av_image_fill_arrays(newFrame->data, newFrame->linesize, newFrameBuf,
  1081.         m_vEncodeCtx->pix_fmt, m_width, m_height, 1);
  1082.  
  1083.     while (m_state != RecordState::Stopped)
  1084.     {
  1085.         if (m_state == RecordState::Paused)
  1086.         {
  1087.             unique_lock<mutex> lk(m_mtxPause);
  1088.             m_cvNotPause.wait(lk, [this] { return m_state != RecordState::Paused; });
  1089.         }
  1090.         if (av_read_frame(m_vFmtCtx, &pkt) < 0)
  1091.         {
  1092.             qDebug() << "video av_read_frame < 0";
  1093.             continue;
  1094.         }
  1095.         if (pkt.stream_index != m_vIndex)
  1096.         {
  1097.             qDebug() << "not a video packet from video input";
  1098.             av_packet_unref(&pkt);
  1099.         }
  1100.         ret = avcodec_send_packet(m_vDecodeCtx, &pkt);
  1101.         if (ret != 0)
  1102.         {
  1103.             qDebug() << "video avcodec_send_packet failed, ret:" << ret;
  1104.             av_packet_unref(&pkt);
  1105.             continue;
  1106.         }
  1107.         ret = avcodec_receive_frame(m_vDecodeCtx, oldFrame);
  1108.         if (ret != 0)
  1109.         {
  1110.             qDebug() << "video avcodec_receive_frame failed, ret:" << ret;
  1111.             av_packet_unref(&pkt);
  1112.             continue;
  1113.         }
  1114.         ++g_vCollectFrameCnt;
  1115.         sws_scale(m_swsCtx, (const uint8_t* const*)oldFrame->data, oldFrame->linesize, 0,
  1116.             m_vEncodeCtx->height, newFrame->data, newFrame->linesize);
  1117.  
  1118.         {
  1119.             unique_lock<mutex> lk(m_mtxVBuf);
  1120.             m_cvVBufNotFull.wait(lk, [this] { return av_fifo_space(m_vFifoBuf) >= m_vOutFrameSize; });
  1121.         }
  1122.         av_fifo_generic_write(m_vFifoBuf, newFrame->data[0], y_size, NULL);
  1123.         av_fifo_generic_write(m_vFifoBuf, newFrame->data[1], y_size / 4, NULL);
  1124.         av_fifo_generic_write(m_vFifoBuf, newFrame->data[2], y_size / 4, NULL);
  1125.         m_cvVBufNotEmpty.notify_one();
  1126.  
  1127.         av_packet_unref(&pkt);
  1128.     }
  1129.     FlushVideoDecoder();
  1130.  
  1131.     av_free(newFrameBuf);
  1132.     av_frame_free(&oldFrame);
  1133.     av_frame_free(&newFrame);
  1134.     qDebug() << "screen record thread exit";
  1135. }
  1136.  
  1137. void ScreenRecordImpl::SoundRecordThreadProc()
  1138. {
  1139.     int ret = -1;
  1140.     AVPacket pkt = { 0 };
  1141.     av_init_packet(&pkt);
  1142.     int nbSamples = m_nbSamples;
  1143.     int dstNbSamples, maxDstNbSamples;
  1144.     AVFrame *rawFrame = av_frame_alloc();
  1145.     AVFrame *newFrame = AllocAudioFrame(m_aEncodeCtx, nbSamples);
  1146.  
  1147.     maxDstNbSamples = dstNbSamples = av_rescale_rnd(nbSamples, 
  1148.         m_aEncodeCtx->sample_rate, m_aDecodeCtx->sample_rate, AV_ROUND_UP);
  1149.  
  1150.     while (m_state != RecordState::Stopped)
  1151.     {
  1152.         if (m_state == RecordState::Paused)
  1153.         {
  1154.             unique_lock<mutex> lk(m_mtxPause);
  1155.             m_cvNotPause.wait(lk, [this] { return m_state != RecordState::Paused; });
  1156.         }
  1157.         if (av_read_frame(m_aFmtCtx, &pkt) < 0)
  1158.         {
  1159.             qDebug() << "audio av_read_frame < 0";
  1160.             continue;
  1161.         }
  1162.         if (pkt.stream_index != m_aIndex)
  1163.         {
  1164.             qDebug() << "not a audio packet";
  1165.             av_packet_unref(&pkt);
  1166.             continue;
  1167.         }
  1168.         ret = avcodec_send_packet(m_aDecodeCtx, &pkt);
  1169.         if (ret != 0)
  1170.         {
  1171.             qDebug() << "audio avcodec_send_packet failed, ret: " << ret;
  1172.             av_packet_unref(&pkt);
  1173.             continue;
  1174.         }
  1175.         ret = avcodec_receive_frame(m_aDecodeCtx, rawFrame);
  1176.         if (ret != 0)
  1177.         {
  1178.             qDebug() << "audio avcodec_receive_frame failed, ret: " << ret;
  1179.             av_packet_unref(&pkt);
  1180.             continue;
  1181.         }
  1182.         ++g_aCollectFrameCnt;
  1183.  
  1184.         dstNbSamples = av_rescale_rnd(swr_get_delay(m_swrCtx, m_aDecodeCtx->sample_rate) + rawFrame->nb_samples,
  1185.             m_aEncodeCtx->sample_rate, m_aDecodeCtx->sample_rate, AV_ROUND_UP);
  1186.         if (dstNbSamples > maxDstNbSamples) 
  1187.         {
  1188.             qDebug() << "audio newFrame realloc";
  1189.             av_freep(&newFrame->data[0]);
  1190.             //nb_samples*nb_channels*Bytes_sample_fmt
  1191.             ret = av_samples_alloc(newFrame->data, newFrame->linesize, m_aEncodeCtx->channels,
  1192.                 dstNbSamples, m_aEncodeCtx->sample_fmt, 1);
  1193.             if (ret < 0)
  1194.             {
  1195.                 qDebug() << "av_samples_alloc failed";
  1196.                 return;
  1197.             }
  1198.  
  1199.             maxDstNbSamples = dstNbSamples;
  1200.             m_aEncodeCtx->frame_size = dstNbSamples;
  1201.             m_nbSamples = newFrame->nb_samples;    //1024
  1202.             /*
  1203.              * m_nbSamples = dstNbSamples;        //22050
  1204.              * 如果改为m_nbSamples = dstNbSamples;则av_audio_fifo_write会异常,不明白为什么?
  1205.              * 我觉得应该改为22050,不然编码线程一次编码的帧sample太少了,
  1206.              * 但是用1024生成的音频好像没问题?
  1207.              * 音频是否应该根据采集的nb_samples而重新分配fifo?
  1208.             */
  1209.         }
  1210.  
  1211.         newFrame->nb_samples = swr_convert(m_swrCtx, newFrame->data, dstNbSamples,
  1212.             (const uint8_t **)rawFrame->data, rawFrame->nb_samples);
  1213.         if (newFrame->nb_samples < 0)
  1214.         {
  1215.             qDebug() << "swr_convert error";
  1216.             return;
  1217.         }
  1218.         {
  1219.             unique_lock<mutex> lk(m_mtxABuf);
  1220.             m_cvABufNotFull.wait(lk, [newFrame, this] { return av_audio_fifo_space(m_aFifoBuf) >= newFrame->nb_samples; });
  1221.         }
  1222.         if (av_audio_fifo_write(m_aFifoBuf, (void **)newFrame->data, newFrame->nb_samples) < newFrame->nb_samples)
  1223.         {
  1224.             qDebug() << "av_audio_fifo_write";
  1225.             return;
  1226.         }
  1227.         m_cvABufNotEmpty.notify_one();
  1228.     }
  1229.     FlushAudioDecoder();
  1230.     av_frame_free(&rawFrame);
  1231.     av_frame_free(&newFrame);
  1232.     qDebug() << "sound record thread exit";
  1233. }

 

 

ScreenRecordTest.h

 

  1. #pragma once
  2. #include <QObject>
  3. #include <QVariant>
  4.  
  5. class ScreenRecord : public QObject
  6. {
  7.     Q_OBJECT
  8. public:
  9.     ScreenRecord(QObject *parent = Q_NULLPTR);
  10.  
  11. private:
  12.     QVariantMap m_args;
  13. };

 

 

ScreenRecordTest.cpp

 

  1. #include "ScreenRecordTest.h"
  2. #include "ScreenRecordImpl.h"
  3. #include <QTimer>
  4.  
  5. ScreenRecord::ScreenRecord(QObject *parent) :
  6.     QObject(parent)
  7. {
  8.     ScreenRecordImpl *sr = new ScreenRecordImpl(this);
  9.     QVariantMap args;
  10.     args["filePath"] = "test.mp4";
  11.     //args["width"] = 1920;
  12.     //args["height"] = 1080;
  13.     args["width"] = 1440;
  14.     args["height"] = 900;
  15.     args["fps"] = 30;
  16.     args["audioBitrate"] = 128000;
  17.  
  18.     sr->Init(args);
  19.  
  20.     QTimer::singleShot(1000, sr, SLOT(Start()));
  21.     //QTimer::singleShot(5000, sr, SLOT(Pause()));
  22.     QTimer::singleShot(11000, sr, SLOT(Stop()));
  23. }

 

main.cpp

 

  1. #include <QApplication>

  2. #include "ScreenRecordImpl.h"

  3. #include "ScreenRecordTest.h"

  4.  

  5. int main(int argc, char *argv[])

  6. {

  7.     QApplication a(argc, argv);

  8.  

  9.     ScreenRecord sr;

  10.  

  11.     return a.exec();

  12. }

 

参考文献:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值